UNPKG

@openui5/sap.ui.core

Version:

OpenUI5 Core Library sap.ui.core

802 lines (696 loc) 30 kB
/*! * OpenUI5 * (c) Copyright 2009-2023 SAP SE or an SAP affiliate company. * Licensed under the Apache License, Version 2.0 - see LICENSE.txt. */ // Provides class sap.ui.core.theming.ThemeManager sap.ui.define([ 'sap/ui/Global', "sap/ui/core/Element", "sap/ui/core/Configuration", "sap/ui/Device", "sap/ui/base/EventProvider", "sap/base/Log", "sap/base/assert", "sap/base/util/each", 'sap/base/util/LoaderExtensions', "sap/ui/util/ActivityDetection", "sap/ui/dom/includeStylesheet", "./ThemeHelper" ], function(Global, Element, Configuration, Device, EventProvider, Log, assert, each, LoaderExtensions, ActivityDetection, includeStylesheet, ThemeHelper) { "use strict"; var oThemeManager; var maxThemeCheckCycles = 150; var mAllLoadedLibraries = {}; var CUSTOMCSSCHECK = /\.sapUiThemeDesignerCustomCss/i; /** * Creates a new ThemeManager object. * * @class Helper class used by the UI5 Core to check whether the themes are applied correctly. * * It could happen that e.g. in onAfterRendering not all themes are available. In these cases the * check waits until the CSS is applied and fires an onThemeChanged event. * * @extends sap.ui.base.EventProvider * @since 1.10.0 * @author SAP SE * @private * @alias sap.ui.core.theming.ThemeManager */ var ThemeManager = EventProvider.extend("sap.ui.core.theming.ThemeManager", /** @lends sap.ui.core.theming.ThemeManager.prototype */ { constructor : function() { EventProvider.apply(this, arguments); this._iCount = 0; // Prevent endless loop this._CUSTOMID = "sap-ui-core-customcss"; this._customCSSAdded = false; this._themeCheckedForCustom = null; this._sFallbackTheme = null; this._mThemeFallback = {}; setupThemes(this); this.themeLoaded = true; }, metadata: { events: { "ThemeChanged": {} } }, /** * Trigger ThemeManager * * @private * @ui5-restricted sap.ui.core */ checkThemeChanged : function() { this.reset(); delayedCheckTheme(true); if (!this._sThemeCheckId) { this.fireThemeChanged(); } } }); ThemeManager.prototype.themeLoaded = false; /** * Resets the internal bookkeeping * * @private * @ui5-restricted sap.ui.core.Core */ ThemeManager.prototype.reset = function() { this.themeLoaded = false; if (this._sThemeCheckId) { clearTimeout(this._sThemeCheckId); this._sThemeCheckId = null; this._iCount = 0; this._sFallbackTheme = null; this._mThemeFallback = {}; } }; function checkTheme() { var sThemeName = Configuration.getTheme(); var sPath = oThemeManager._getThemePath("sap.ui.core", sThemeName) + "custom.css"; var bIsStandardTheme = sThemeName.indexOf("sap_") === 0 || sThemeName === "base"; var res = true; var aFailedLibs = []; if (oThemeManager._customCSSAdded && oThemeManager._themeCheckedForCustom === sThemeName) { // include custom style sheet here because it has already been added using sap/ui/dom/includeStyleSheet // hence, needs to be checked for successful inclusion, too mAllLoadedLibraries[oThemeManager._CUSTOMID] = {}; } function checkLib(lib) { var sStyleId = "sap-ui-theme-" + lib; var currentRes = ThemeHelper.checkAndRemoveStyle({ prefix: "sap-ui-theme-", id: lib }); if (currentRes && document.getElementById("sap-ui-themeskeleton-" + lib)) { // remove also the skeleton if present in the DOM currentRes = ThemeHelper.checkAndRemoveStyle({ prefix: "sap-ui-themeskeleton-", id: lib }); } res = res && currentRes; if (res) { /* as soon as css has been loaded, look if there is a flag for custom css inclusion inside, but only * if this has not been checked successfully before for the same theme */ if (oThemeManager._themeCheckedForCustom != sThemeName) { // custom css is supported for custom themes, so this check is skipped for standard themes if (!bIsStandardTheme && checkCustom(lib)) { // load custom css available at sap/ui/core/themename/custom.css var sCustomCssPath = sPath; // check for configured query parameters and add them if available var sLibCssQueryParams = getLibraryCssQueryParams(mAllLoadedLibraries["sap.ui.core"]); if (sLibCssQueryParams) { sCustomCssPath += sLibCssQueryParams; } includeStylesheet(sCustomCssPath, oThemeManager._CUSTOMID); oThemeManager._customCSSAdded = true; Log.debug("ThemeManager: delivered custom CSS needs to be loaded, Theme not yet applied"); oThemeManager._themeCheckedForCustom = sThemeName; res = false; return false; } else { // remove stylesheet once the particular class is not available (e.g. after theme switch) /*check for custom theme was not successful, so we need to make sure there are no custom style sheets attached*/ var oCustomCssLink = document.querySelector("LINK[id='" + oThemeManager._CUSTOMID + "']"); if (oCustomCssLink) { oCustomCssLink.remove(); Log.debug("ThemeManager: Custom CSS removed"); } oThemeManager._customCSSAdded = false; } } } // Collect all libs that failed to load and no fallback has been applied, yet. // The fallback relies on custom theme metadata, so it is not done for standard themes if (!bIsStandardTheme && currentRes && !oThemeManager._mThemeFallback[lib]) { var oStyle = document.getElementById(sStyleId); // Check for error marker (data-sap-ui-ready=false) and that there are no rules // to be sure the stylesheet couldn't be loaded at all. // E.g. in case an @import within the stylesheet fails, the error marker will // also be set, but in this case no fallback should be done as there is a (broken) theme if (oStyle && oStyle.getAttribute("data-sap-ui-ready") === "false" && !(oStyle.sheet && ThemeHelper.hasSheetCssRules(oStyle.sheet)) ) { aFailedLibs.push(lib); } } } each(mAllLoadedLibraries, checkLib); // Try to load a fallback theme for all libs that couldn't be loaded if (aFailedLibs.length > 0) { // Only retrieve the fallback theme once per ThemeManager cycle if (!oThemeManager._sFallbackTheme) { for (var sLib in mAllLoadedLibraries) { var oThemeMetaData = ThemeHelper.getMetadata(sLib); if (oThemeMetaData && oThemeMetaData.Extends && oThemeMetaData.Extends[0]) { oThemeManager._sFallbackTheme = oThemeMetaData.Extends[0]; break; } } } if (oThemeManager._sFallbackTheme) { aFailedLibs.forEach(function(lib) { var sStyleId = "sap-ui-theme-" + lib; var oStyle = document.getElementById(sStyleId); Log.warning( "ThemeManager: Custom theme '" + sThemeName + "' could not be loaded for library '" + lib + "'. " + "Falling back to its base theme '" + oThemeManager._sFallbackTheme + "'." ); // Change the URL to load the fallback theme updateThemeUrl(oStyle, oThemeManager._sFallbackTheme); // remember the lib to prevent doing the fallback multiple times // (if the fallback also can't be loaded) oThemeManager._mThemeFallback[lib] = true; }); // Make sure to wait for the fallback themes to be loaded res = false; } } if (!res) { Log.debug("ThemeManager: Theme not yet applied."); } else { oThemeManager._themeCheckedForCustom = sThemeName; } return res; } /* checks if a particular class is available */ function checkCustom(lib) { var cssFile = window.document.getElementById("sap-ui-theme-" + lib); if (!cssFile) { return false; } /* Check if custom.css indication rule is applied to <link> element The rule looks like this: link[id^="sap-ui-theme-"]::after, .sapUiThemeDesignerCustomCss { content: '{"customcss" : true}'; } First selector is to apply it to the <link> elements, the second one for the Safari workaround (see below). */ var style = window.getComputedStyle(cssFile, ':after'); var content = style ? style.getPropertyValue('content') : null; if (!content && Device.browser.safari) { // Safari has a bug which prevents reading properties of hidden pseudo elements // As a workaround: Add "sapUiThemeDesignerCustomCss" class on html element // in order to get the computed "content" value and remove it again. var html = document.documentElement; html.classList.add("sapUiThemeDesignerCustomCss"); content = window.getComputedStyle(html, ":after").getPropertyValue("content"); html.classList.remove("sapUiThemeDesignerCustomCss"); } if (content && content !== "none") { try { // Strip surrounding quotes (single or double depending on browser) if (content[0] === "'" || content[0] === '"') { content = content.substring(1, content.length - 1); } // Cast to boolean (returns true if string equals "true", otherwise false) return content === "true"; } catch (e) { // parsing error Log.error("Custom check: Error parsing JSON string for custom.css indication.", e); } } //*********************************** // Fallback legacy customcss check //*********************************** /* * checks if a particular class is available at the beginning of the stylesheet */ var aRules = cssFile.sheet ? ThemeHelper.safeAccessSheetCssRules(cssFile.sheet) : null; if (!aRules || aRules.length === 0) { Log.warning("Custom check: Failed retrieving a CSS rule from stylesheet " + lib); return false; } // we should now have some rule name ==> try to match against custom check for (var i = 0; (i < 2 && i < aRules.length) ; i++) { if (CUSTOMCSSCHECK.test(aRules[i].selectorText)) { return true; } } return false; } function delayedCheckTheme(bFirst) { oThemeManager._iCount++; var bEmergencyExit = oThemeManager._iCount > maxThemeCheckCycles; if (!checkTheme() && !bEmergencyExit) { // Use dynamic delay to have a fast check for most use cases // but not cause too much CPU usage for long running css requests var iDelay; if (oThemeManager._iCount <= 100) { iDelay = 2; // 1. Initial interval } else if (oThemeManager._iCount <= 110) { iDelay = 500; // 2. After 100 cycles } else { iDelay = 1000; // 3. After another 10 cycles (about 5 seconds) } oThemeManager._sThemeCheckId = setTimeout(delayedCheckTheme, iDelay); } else if (!bFirst) { oThemeManager.reset(); oThemeManager.themeLoaded = true; oThemeManager.fireThemeChanged(); if (bEmergencyExit) { Log.error("ThemeManager: max. check cycles reached."); } } else { oThemeManager.themeLoaded = true; } } // helper to add the FOUC marker to the CSS for the given id function fnAddFoucmarker(sLinkId) { var oLink = document.getElementById(sLinkId); if (oLink) { oLink.dataset.sapUiFoucmarker = sLinkId; } } /** * Includes a library theme into the current page (if a variant is specified it * will include the variant library theme) and ensure theme root * @param {object} [oLibThemingInfo] to be used only by the Core * @since 1.108 * @private * @ui5-restricted sap.ui.core */ ThemeManager.prototype._includeLibraryThemeAndEnsureThemeRoot = function(oLibThemingInfo) { var sLibName = oLibThemingInfo.name; // ensure to register correct library theme module path even when "preloadLibCss" prevents // including the library theme as controls might use it to calculate theme-specific URLs _ensureThemeRoot(sLibName, Configuration.getTheme()); // also ensure correct theme root for the library's base theme which might be relevant in some cases // (e.g. IconPool which includes font files from sap.ui.core base theme) _ensureThemeRoot(sLibName, "base"); mAllLoadedLibraries[sLibName] = oLibThemingInfo; if (Configuration.getValue('preloadLibCss').indexOf(sLibName) < 0) { this.includeLibraryTheme(sLibName, oLibThemingInfo.variant, oLibThemingInfo); } }; /** * Includes a library theme into the current page (if a variant is specified it * will include the variant library theme) * @param {string} sLibName the name of the UI library * @param {string} [sVariant] the variant to include (optional) * @param {string|object} [vQueryOrLibInfo] to be used only by the Core * @since 1.108 * @private * @ui5-restricted sap.ui.core */ ThemeManager.prototype.includeLibraryTheme = function(sLibName, sVariant, vQueryOrLibInfo) { assert(typeof sLibName === "string", "sLibName must be a string"); assert(sVariant === undefined || typeof sVariant === "string", "sVariant must be a string or undefined"); var sQuery = vQueryOrLibInfo; if (typeof sQuery === "object") { // check for configured query parameters and use them sQuery = getLibraryCssQueryParams(vQueryOrLibInfo); } /* * by specifying a library name containing a colon (":") you can specify * the file name of the CSS file to include (ignoring RTL) */ // include the stylesheet for the library (except for "classic" and "legacy" lib) if ((sLibName != "sap.ui.legacy") && (sLibName != "sap.ui.classic")) { // no variant? if (!sVariant) { sVariant = ""; } // determine CSS Variables / RTL var sCssVars = (/^(true|x)$/i.test(Configuration.getValue('xx-cssVariables')) ? "_skeleton" : ""); var sRtl = (Configuration.getRTL() ? "-RTL" : ""); // create the library file name var sLibFileName, sLibId = sLibName + (sVariant.length > 0 ? "-[" + sVariant + "]" : sVariant); if (sLibName && sLibName.indexOf(":") == -1) { sLibFileName = "library" + sVariant + sCssVars + sRtl; } else { sLibFileName = sLibName.substring(sLibName.indexOf(":") + 1) + sVariant; sLibName = sLibName.substring(0, sLibName.indexOf(":")); } var sLinkId = "sap-ui-theme-" + sLibId; var sOldCssUri = document.getElementById(sLinkId) && document.getElementById(sLinkId).href; var sCssBasePath = new URL(this._getThemePath(sLibName, this.sTheme), document.baseURI).toString(); var sCssPathAndName = sCssBasePath + sLibFileName + ".css" + (sQuery ? sQuery : ""); var sCssVariablesPathAndName = sCssBasePath + "css_variables.css" + (sQuery ? sQuery : ""); // includeStylesheet takes care of adding link tag for library only once but we need to take care to skip // checkThemeChanged in case the link tag does not change in order to avoid fireThemeChanged if (!(sCssPathAndName === sOldCssUri || sCssVariablesPathAndName === sOldCssUri)) { // use the special FOUC handling for initially existing stylesheets // to ensure that they are not just replaced when using the // includeStyleSheet API and to be removed later fnAddFoucmarker(sLinkId); // include the css variables if (/^(true|x|additional)$/i.test(Configuration.getValue('xx-cssVariables'))) { Log.info("Including " + sCssVariablesPathAndName + " - sap.ui.core.theming.ThemeManager.includeLibraryTheme()"); includeStylesheet(sCssVariablesPathAndName, sLinkId); // include the skeleton css next to the css variables sLinkId = "sap-ui-themeskeleton-" + sLibId; fnAddFoucmarker(sLinkId); } // log and include Log.info("Including " + sCssPathAndName + " - sap.ui.core.theming.ThemeManager.includeLibraryTheme()"); includeStylesheet(sCssPathAndName, sLinkId); // if parameters have been used, update them with the new style sheet var Parameters = sap.ui.require("sap/ui/core/theming/Parameters"); if (Parameters) { Parameters._addLibraryTheme(sLibId); } this.checkThemeChanged(); } } }; /** * Returns the URL of the folder in which the CSS file for the given theme and the given library is located. * * @param {string} sLibName Library name (dot separated) * @param {string} sThemeName Theme name * @returns {string} module path URL (ends with a slash) * @since 1.108 * @private * @ui5-restricted sap.ui.core,sap.ui.support.supportRules.report.DataCollector */ ThemeManager.prototype._getThemePath = function(sLibName, sThemeName) { // make sure to register correct theme module path in case themeRoots are defined _ensureThemeRoot(sLibName, sThemeName); // use the library location as theme location return sap.ui.require.toUrl((sLibName + ".themes." + sThemeName).replace(/\./g, "/") + "/"); }; /** * Makes sure to register the correct module path for the given library and theme * in case a themeRoot has been defined. * * @param {string} sLibName Library name (dot separated) * @param {string} sThemeName Theme name * @private */ function _ensureThemeRoot(sLibName, sThemeName) { if (oThemeManager._mThemeRoots) { var path = oThemeManager._mThemeRoots[sThemeName + " " + sLibName] || oThemeManager._mThemeRoots[sThemeName]; // check whether for this combination (theme+lib) a URL is registered or for this theme a default location is registered if (path) { path = path + sLibName.replace(/\./g, "/") + "/themes/" + sThemeName + "/"; LoaderExtensions.registerResourcePath((sLibName + ".themes." + sThemeName).replace(/\./g, "/"), path); } } } /** * Defines the root directory from below which UI5 should load the theme with the given name. * Optionally allows restricting the setting to parts of a theme covering specific control libraries. * * Example: * <pre> * sap.ui.getCore().setThemeRoot("my_theme", "https://mythemeserver.com/allThemes"); * sap.ui.getCore().applyTheme("my_theme"); * </pre> * * will cause the following file to be loaded (assuming that the bootstrap is configured to load * libraries <code>sap.m</code> and <code>sap.ui.layout</code>): * <pre> * https://mythemeserver.com/allThemes/sap/ui/core/themes/my_theme/library.css * https://mythemeserver.com/allThemes/sap/ui/layout/themes/my_theme/library.css * https://mythemeserver.com/allThemes/sap/m/themes/my_theme/library.css * </pre> * * If parts of the theme are at different locations (e.g. because you provide a standard theme * like "sap_belize" for a custom control library and this self-made part of the standard theme is at a * different location than the UI5 resources), you can also specify for which control libraries the setting * should be used, by giving an array with the names of the respective control libraries as second parameter: * <pre> * sap.ui.getCore().setThemeRoot("sap_belize", ["my.own.library"], "https://mythemeserver.com/allThemes"); * </pre> * * This will cause the Belize theme to be loaded from the UI5 location for all standard libraries. * Resources for styling the <code>my.own.library</code> controls will be loaded from the configured * location: * <pre> * https://openui5.hana.ondemand.com/resources/sap/ui/core/themes/sap_belize/library.css * https://openui5.hana.ondemand.com/resources/sap/ui/layout/themes/sap_belize/library.css * https://openui5.hana.ondemand.com/resources/sap/m/themes/sap_belize/library.css * https://mythemeserver.com/allThemes/my/own/library/themes/sap_belize/library.css * </pre> * * If the custom theme should be loaded initially (via bootstrap attribute), the <code>themeRoots</code> * property of the <code>window["sap-ui-config"]</code> object must be used instead of calling * <code>sap.ui.getCore().setThemeRoot(...)</code> in order to configure the theme location early enough. * * @param {string} sThemeName Name of the theme for which to configure the location * @param {string[]} [aLibraryNames] Optional library names to which the configuration should be restricted * @param {string} sThemeBaseUrl Base URL below which the CSS file(s) will be loaded from * @param {boolean} [bForceUpdate=false] Force updating URLs of currently loaded theme * @since 1.108 * @private * @ui5-restricted sap.ui.core.Core */ ThemeManager.prototype.setThemeRoot = function(sThemeName, aLibraryNames, sThemeBaseUrl, bForceUpdate) { assert(typeof sThemeName === "string", "sThemeName must be a string"); assert((Array.isArray(aLibraryNames) && typeof sThemeBaseUrl === "string") || (typeof aLibraryNames === "string" && sThemeBaseUrl === undefined), "either the second parameter must be a string (and the third is undefined), or it must be an array and the third parameter is a string"); if (!this._mThemeRoots) { this._mThemeRoots = {}; } // normalize parameters if (typeof aLibraryNames === "string") { bForceUpdate = sThemeBaseUrl; sThemeBaseUrl = aLibraryNames; aLibraryNames = undefined; } sThemeBaseUrl = sThemeBaseUrl + (sThemeBaseUrl.slice( -1) == "/" ? "" : "/"); if (aLibraryNames) { // registration of URL for several libraries for (var i = 0; i < aLibraryNames.length; i++) { var lib = aLibraryNames[i]; this._mThemeRoots[sThemeName + " " + lib] = sThemeBaseUrl; } } else { // registration of theme default base URL this._mThemeRoots[sThemeName] = sThemeBaseUrl; } // Update theme urls when theme roots of currently loaded theme have changed if (bForceUpdate && sThemeName === this.sTheme) { this._updateThemeUrls(this.sTheme); } }; /** * Modify style sheet URLs to point to the given theme, using the current RTL mode * * @param {string} sThemeName The name of the theme to update * @param {boolean} bSuppressFOUC If FOUC-Marker should be added or not * @since 1.108 * @private * @ui5-restricted sap.ui.core.Core */ ThemeManager.prototype._updateThemeUrls = function(sThemeName, bSuppressFOUC) { // select "our" stylesheets var oQueryResult = document.querySelectorAll("link[id^=sap-ui-theme-],link[id^=sap-ui-themeskeleton-]"); Array.prototype.forEach.call(oQueryResult, function(oHTMLElement) { updateThemeUrl(oHTMLElement, sThemeName, bSuppressFOUC); }); }; // this function is also used by "sap.ui.core.theming.ThemeManager" to load a fallback theme for a single library function updateThemeUrl(oLink, sThemeName, bSuppressFOUC) { var sLibName, iQueryIndex = oLink.href.search(/[?#]/), sLibFileName, sQuery, sStandardLibFilePrefix = "library", sRTL = Configuration.getRTL() ? "-RTL" : "", sHref, pos; // derive lib name from id via regex var mLinkId = /^sap-ui-theme(?:skeleton)?-(.*)$/i.exec(oLink.id); if (Array.isArray(mLinkId)) { sLibName = mLinkId[1]; } else { // fallback to legacy logic sLibName = oLink.id.slice(13); // length of "sap-ui-theme-" } mAllLoadedLibraries[sLibName] = mAllLoadedLibraries[sLibName] || {}; if (iQueryIndex > -1) { // Split href on query and/or fragment to check for the standard lib file prefix sLibFileName = oLink.href.substring(0, iQueryIndex); sQuery = oLink.href.substring(iQueryIndex); } else { sLibFileName = oLink.href; sQuery = ""; } // Get basename of stylesheet (e.g. "library.css") sLibFileName = sLibFileName.substring(sLibFileName.lastIndexOf("/") + 1); // handle 'variants' if ((pos = sLibName.indexOf("-[")) > 0) { // assumes that "-[" does not occur as part of a library name sStandardLibFilePrefix += sLibName.slice(pos + 2, -1); // 2=length of "-]" sLibName = sLibName.slice(0, pos); } // try to distinguish "our" library css from custom css included with the ':' notation in includeLibraryTheme if ( sLibFileName === (sStandardLibFilePrefix + ".css") || sLibFileName === (sStandardLibFilePrefix + "-RTL.css") ) { sLibFileName = sStandardLibFilePrefix + sRTL + ".css"; } sHref = oThemeManager._getThemePath(sLibName, sThemeName) + sLibFileName + sQuery; if ( sHref != oLink.href ) { // sap/ui/dom/includeStylesheet has a special FOUC handling // which is activated once the attribute data-sap-ui-foucmarker is // present on the link to be replaced (usage of the Promise // API is not sufficient as it will change the sync behavior) if (bSuppressFOUC) { oLink.dataset.sapUiFoucmarker = oLink.id; } // Replace the current <link> tag with a new one. // Changing "oLink.href" would also trigger loading the new stylesheet but // the load/error handlers would not get called which causes issues with the ThemeManager // as the "data-sap-ui-ready" attribute won't be set. includeStylesheet(sHref, oLink.id); } } /** * Applies the theme with the given name (by loading the respective style sheets, which does not disrupt the application). * * By default, the theme files are expected to be located at path relative to the respective control library ([libraryLocation]/themes/[themeName]). * Different locations can be configured by using the method setThemePath() or by using the second parameter "sThemeBaseUrl" of applyTheme(). * Usage of this second parameter is a shorthand for setThemePath and internally calls setThemePath, so the theme location is then known. * * sThemeBaseUrl is a single URL to specify the default location of all theme files. This URL is the base folder below which the control library folders * are located. E.g. if the CSS files are not located relative to the root location of UI5, but instead they are at locations like * http://my.server/myapp/resources/sap/ui/core/themes/my_theme/library.css * then the URL that needs to be given is: * http://my.server/myapp/resources * All theme resources are then loaded from below this folder - except if for a certain library a different location has been registered. * * If the theme resources are not all either below this base location or with their respective libraries, then setThemePath must be * used to configure individual locations. * * @param {string} sThemeName The name of the theme to be loaded * @param {string} [sThemeBaseUrl] The (optional) base location of the theme * @param {boolean} [bForce] Apply theme even if theme hasn't changed. * <code>sap.ui.core.Core</code> does a lazy require of * ThemeManager. Loading could be already done, but no change * was fired. * @since 1.108 * @private */ ThemeManager.prototype.applyTheme = function(sThemeName, sThemeBaseUrl, bForce) { assert(typeof sThemeName === "string", "sThemeName must be a string"); assert(typeof sThemeBaseUrl === "string" || typeof sThemeBaseUrl === "undefined", "sThemeBaseUrl must be a string or undefined"); sThemeName = Configuration.normalizeTheme(sThemeName, sThemeBaseUrl); if (sThemeBaseUrl) { this.setThemeRoot(sThemeName, sThemeBaseUrl); } // only apply the theme if it is different from the active one if ((sThemeName && this.sTheme != sThemeName) || bForce) { var sCurrentTheme = this.sTheme; var html = document.documentElement; this._updateThemeUrls(sThemeName, /* bSuppressFOUC */ true); this.sTheme = sThemeName; Configuration.setTheme(sThemeName); // modify the <html> tag's CSS class with the theme name html.classList.remove("sapUiTheme-" + sCurrentTheme); html.classList.add("sapUiTheme-" + sThemeName); // notify the listeners this.checkThemeChanged(); } }; /** * Returns a string containing query parameters for theme specific files. * * Used in Core#initLibrary and ThemeManager#checkStyle. * * @param {object} oLibInfo Library info object (containing a "version" property) * @returns {string|undefined} query parameters or undefined if "versionedLibCss" config is "false" * @private */ function getLibraryCssQueryParams(oLibInfo) { var sQuery; if (Configuration.getValue("versionedLibCss") && oLibInfo) { sQuery = "?version=" + oLibInfo.version; // distribution version may not be available (will be loaded in Core constructor syncpoint2) if (Global.versioninfo) { sQuery += "&sap-ui-dist-version=" + Global.versioninfo.version; } } return sQuery; } /** * Initializes the window "sap-ui-config" property, sets theme roots, initializes sTheme, sets theme CSS classes * @private */ function setupThemes(oThemeManager) { var mThemeRoots = Configuration.getValue("themeRoots"); // read themeRoots configuration if (mThemeRoots) { for (var themeName in mThemeRoots) { var themeRoot = mThemeRoots[themeName]; if (typeof themeRoot === "string") { oThemeManager.setThemeRoot(themeName, themeRoot); } else { for (var lib in themeRoot) { if (lib.length > 0) { oThemeManager.setThemeRoot(themeName, [lib], themeRoot[lib]); } else { oThemeManager.setThemeRoot(themeName, themeRoot[lib]); } } } } } // set CSS class for the theme name oThemeManager.sTheme = Configuration.getTheme(); document.documentElement.classList.add("sapUiTheme-" + oThemeManager.sTheme); Log.info("Declared theme " + oThemeManager.sTheme,null); } /** * Notify content density changes * * @since 1.108 * @private * @ui5-restricted sap.ui.core.Core */ ThemeManager.prototype.notifyContentDensityChanged = function () { this.fireThemeChanged(); }; /** * Notify theme change * * @param {object} oParameters The event parameters * @since 1.108 * @private * @ui5-restricted sap.ui.core.Core */ ThemeManager.prototype.fireThemeChanged = function (oParameters) { // special hook for resetting theming parameters before the controls get // notified (lightweight coupling to static Parameters module) var ThemeParameters = sap.ui.require("sap/ui/core/theming/Parameters"); if (ThemeParameters) { ThemeParameters._reset(/* bOnlyWhenNecessary= */ true); } oParameters = oParameters || {}; // set the current theme name as default if omitted if (!oParameters.theme) { oParameters.theme = Configuration.getTheme(); } // notify all elements/controls via a pseudo browser event var sEventId = "ThemeChanged"; var oEvent = jQuery.Event(sEventId); oEvent.theme = oParameters.theme; Element.registry.forEach(function(oElement) { oElement._handleEvent(oEvent); }); ActivityDetection.refresh(); this.fireEvent(sEventId, oParameters); }; oThemeManager = new ThemeManager(); return oThemeManager; });