Skip to content

Commit

Permalink
feat(framework): OpenUI5 integration (#1138)
Browse files Browse the repository at this point in the history
  • Loading branch information
vladitasev committed Feb 11, 2020
1 parent b1459ce commit 5527990
Show file tree
Hide file tree
Showing 49 changed files with 267 additions and 121 deletions.
23 changes: 23 additions & 0 deletions docs/Public Module Imports.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,3 +340,26 @@ You can pass the parameters directly, as an object, or as a URL:
3) Pass a URL to a JSON file, containing the CSS Vars in its "_" property. Will be fetched on demand, not upon registration.

`registerThemeProperties("my-package", "my_theme", "http://url/to/my/theme.json");`

### 7. OpenUI5 integration

```js
import "@ui5/webcomponents-base/dist/features/OpenUI5Support.js";
```

If your app uses both OpenUI5 and UI5 Web Components, UI5 Web Components can benefit
from OpenUI5 configuration and resources.

When you import the above module:
1. OpenUI5 configuration takes precedence over UI5 Web Components configuration
for all common entities (theme, language, RTL, etc...). In addition, changing the theme
in OpenUI5 will also change the theme in UI5 Web Components.
2. Fonts will not be loaded twice (just once by OpenUI5, and reused).
3. Locale Data assets will not be fetched twice (just once by OpenUI5, and reused).

Therefore, if you intend to run both frameworks in the same browser window,
it is highly recommended to enable OpenUI5 support and benefit from these optimizations.

*Note:* In general the order in which OpenUI5 and UI5 Web Components are loaded does not matter.
However, if your app needs to support Internet Explorer 11, either load OpenUI5 first, or load
UI5 Web Components deferred.
8 changes: 3 additions & 5 deletions docs/dev/Developing Web Components.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,8 @@ class Demo extends UI5Element {
return DemoCss;
}

static async define(...params) {
static async onDefine() {
await fetchI18nBundle("my-ui5-web-components");
super.define(...params);
}
}

Expand Down Expand Up @@ -374,9 +373,8 @@ class Demo extends UI5Element {
return DemoCss;
}

static async define(...params) {
static async onDefine() {
await fetchI18nBundle("my-ui5-web-components");
super.define(...params);
}
}

Expand All @@ -385,7 +383,7 @@ Demo.define();
export default Demo;
```

Please note that here we override the `define` method of `UI5Element` in order to ensure that i18n resources have been fetched
Please note that here we use the `onDefine` method of `UI5Element` in order to ensure that i18n resources have been fetched
before the web component has been defined. The used namespace for resource registration (in this example `my-ui5-web-components`)
is the `name` property of your `package.json` file.

Expand Down
1 change: 1 addition & 0 deletions packages/base/bundle.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import "./dist/features/calendar/Persian.js";

// ESM bundle targets Edge + browsers with native support
import "./dist/features/browsersupport/Edge.js";
import "./dist/features/OpenUI5Support.js";

// Test components
import "./dist/test-resources/elements/Generic.js";
Expand Down
7 changes: 7 additions & 0 deletions packages/base/src/FontFace.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* CSS font face used for the texts provided by SAP.
*/
import createStyleInHead from "./util/createStyleInHead.js";
import { getFeature } from "./FeaturesRegistry.js";

/* CDN Locations */
const font72RegularWoff = `https://ui5.sap.com/sdk/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Regular.woff?ui5-webcomponents`;
Expand Down Expand Up @@ -60,6 +61,12 @@ const insertFontFace = () => {
return;
}

// If OpenUI5 is found, let it set the font
const OpenUI5Support = getFeature("OpenUI5Support");
if (OpenUI5Support && OpenUI5Support.isLoaded()) {
return;
}

createStyleInHead(fontFaceCSS, { "data-ui5-font-face": "" });
};

Expand Down
31 changes: 21 additions & 10 deletions packages/base/src/InitialConfiguration.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import merge from "@ui5/webcomponents-utils/dist/sap/base/util/merge.js";
import { getFeature } from "./FeaturesRegistry.js";

let initialized = false;

const initialConfig = {
let initialConfig = {
animationMode: "full",
theme: "sap_fiori_3",
rtl: null,
Expand Down Expand Up @@ -50,8 +53,6 @@ const booleanMapping = new Map();
booleanMapping.set("true", true);
booleanMapping.set("false", false);

let runtimeConfig = {};

const parseConfigurationScript = () => {
const configScript = document.querySelector("[data-ui5-config]") || document.querySelector("[data-id='sap-ui-config']"); // for backward compatibility

Expand All @@ -65,7 +66,7 @@ const parseConfigurationScript = () => {
}

if (configJSON) {
runtimeConfig = Object.assign({}, configJSON);
initialConfig = merge(initialConfig, configJSON);
}
}
};
Expand All @@ -86,24 +87,34 @@ const parseURLParameters = () => {
value = booleanMapping.get(lowerCaseValue);
}

runtimeConfig[param] = value;
initialConfig[param] = value;
});
};

const applyConfigurations = () => {
Object.keys(runtimeConfig).forEach(key => {
initialConfig[key] = runtimeConfig[key];
});
const applyOpenUI5Configuration = () => {
const OpenUI5Support = getFeature("OpenUI5Support");
if (!OpenUI5Support || !OpenUI5Support.isLoaded()) {
return;
}

const OpenUI5Config = OpenUI5Support.getConfigurationSettingsObject();
initialConfig = merge(initialConfig, OpenUI5Config);
};


const initConfiguration = () => {
if (initialized) {
return;
}

// 1. Lowest priority - configuration script
parseConfigurationScript();

// 2. URL parameters overwrite configuration script parameters
parseURLParameters();
applyConfigurations();

// 3. If OpenUI5 is detected, it has the highest priority
applyOpenUI5Configuration();

initialized = true;
};
Expand Down
5 changes: 5 additions & 0 deletions packages/base/src/UI5Element.js
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,11 @@ class UI5Element extends HTMLElement {
*/
static async define() {
await boot();

if (this.onDefine) {
await this.onDefine();
}

const tag = this.getMetadata().getTag();

const definedLocally = DefinitionsSet.has(tag);
Expand Down
7 changes: 7 additions & 0 deletions packages/base/src/boot.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,24 @@ import insertFontFace from "./FontFace.js";
import { getTheme } from "./config/Theme.js";
import { _applyTheme } from "./Theming.js";
import whenPolyfillLoaded from "./compatibility/whenPolyfillLoaded.js";
import { getFeature } from "./FeaturesRegistry.js";

let bootPromise;
const OpenUI5Support = getFeature("OpenUI5Support");

const boot = () => {
if (bootPromise) {
return bootPromise;
}

bootPromise = new Promise(async resolve => {
if (OpenUI5Support) {
await OpenUI5Support.init();
}

await whenDOMReady();
await _applyTheme(getTheme());
OpenUI5Support && OpenUI5Support.attachListeners();
insertFontFace();
await whenPolyfillLoaded();
resolve();
Expand Down
6 changes: 5 additions & 1 deletion packages/base/src/config/AnimationMode.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { getAnimationMode as getConfiguredAnimationMode } from "../InitialConfiguration.js";

const animationMode = getConfiguredAnimationMode();
let animationMode;

const getAnimationMode = () => {
if (animationMode === undefined) {
animationMode = getConfiguredAnimationMode();
}

return animationMode;
};

Expand Down
6 changes: 5 additions & 1 deletion packages/base/src/config/CalendarType.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import CalendarType from "@ui5/webcomponents-utils/dist/sap/ui/core/CalendarType.js";
import { getCalendarType as getConfiguredCalendarType } from "../InitialConfiguration.js";

const calendarType = getConfiguredCalendarType();
let calendarType;

const getCalendarType = () => {
if (calendarType === undefined) {
calendarType = getConfiguredCalendarType();
}

if (calendarType) {
const type = Object.keys(CalendarType).find(calType => calType === calendarType);

Expand Down
6 changes: 5 additions & 1 deletion packages/base/src/config/FormatSettings.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { getFormatSettings } from "../InitialConfiguration.js";

const formatSettings = getFormatSettings();
let formatSettings;

const getFirstDayOfWeek = () => {
if (formatSettings === undefined) {
formatSettings = getFormatSettings();
}

return formatSettings.firstDayOfWeek;
};

Expand Down
5 changes: 4 additions & 1 deletion packages/base/src/config/Language.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { getLanguage as getConfiguredLanguage } from "../InitialConfiguration.js";

const language = getConfiguredLanguage();
let language;

const getLanguage = () => {
if (language === undefined) {
language = getConfiguredLanguage();
}
return language;
};

Expand Down
13 changes: 10 additions & 3 deletions packages/base/src/config/NoConflict.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,31 @@ const shouldFireOriginalEvent = eventName => {
return excludeList.includes(eventName);
};

let noConflict = getConfiguredNoConflict();
let noConflict;

const shouldNotFireOriginalEvent = eventName => {
return !(noConflict.events && noConflict.events.includes && noConflict.events.includes(eventName));
const nc = getNoConflict();
return !(nc.events && nc.events.includes && nc.events.includes(eventName));
};

const getNoConflict = () => {
if (noConflict === undefined) {
noConflict = getConfiguredNoConflict();
}

return noConflict;
};

const skipOriginalEvent = eventName => {
const nc = getNoConflict();

// Always fire these events
if (shouldFireOriginalEvent(eventName)) {
return false;
}

// Read from the configuration
if (noConflict === true) {
if (nc === true) {
return true;
}

Expand Down
6 changes: 5 additions & 1 deletion packages/base/src/config/Theme.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { getTheme as getConfiguredTheme } from "../InitialConfiguration.js";
import { _applyTheme } from "../Theming.js";

let theme = getConfiguredTheme();
let theme;

const getTheme = () => {
if (theme === undefined) {
theme = getConfiguredTheme();
}

return theme;
};

Expand Down
76 changes: 76 additions & 0 deletions packages/base/src/features/OpenUI5Support.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { registerFeature } from "../FeaturesRegistry.js";
import { setTheme } from "../config/Theme.js";

const sap = window.sap;
const core = sap && sap.ui && typeof sap.ui.getCore === "function" && sap.ui.getCore();

const isLoaded = () => {
return !!core;
};

const init = () => {
if (!core) {
return Promise.resolve();
}

return new Promise(resolve => {
core.attachInit(() => {
sap.ui.require(["sap/ui/core/LocaleData"], resolve);
});
});
};

const getConfigurationSettingsObject = () => {
if (!core) {
return;
}

const config = core.getConfiguration();
const LocaleData = sap.ui.require("sap/ui/core/LocaleData");

return {
animationMode: config.getAnimationMode(),
language: config.getLanguage(),
theme: config.getTheme(),
rtl: config.getRTL(),
calendarType: config.getCalendarType(),
formatSettings: {
firstDayOfWeek: LocaleData.getInstance(config.getLocale()).getFirstDayOfWeek(),
},
};
};

const getLocaleDataObject = () => {
if (!core) {
return;
}

const config = core.getConfiguration();
const LocaleData = sap.ui.require("sap/ui/core/LocaleData");
return LocaleData.getInstance(config.getLocale()).mData;
};

const listenForThemeChange = () => {
const config = core.getConfiguration();
core.attachThemeChanged(async () => {
await setTheme(config.getTheme());
});
};

const attachListeners = () => {
if (!core) {
return;
}

listenForThemeChange();
};

const OpenUI5Support = {
isLoaded,
init,
getConfigurationSettingsObject,
getLocaleDataObject,
attachListeners,
};

registerFeature("OpenUI5Support", OpenUI5Support);
4 changes: 1 addition & 3 deletions packages/fiori/src/ShellBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -867,15 +867,13 @@ class ShellBar extends UI5Element {
return getRTL() ? "rtl" : undefined;
}

static async define(...params) {
static async onDefine() {
await Promise.all([
Icon.define(),
List.define(),
Popover.define(),
StandardListItem.define(),
]);

super.define(...params);
}
}

Expand Down
Loading

0 comments on commit 5527990

Please sign in to comment.