UNPKG

@openui5/sap.m

Version:

OpenUI5 UI Library sap.m

397 lines (347 loc) 13.3 kB
/*! * OpenUI5 * (c) Copyright 2009-2023 SAP SE or an SAP affiliate company. * Licensed under the Apache License, Version 2.0 - see LICENSE.txt. */ sap.ui.define([ "sap/base/Log", "./library", 'sap/ui/core/Core', "sap/ui/thirdparty/jquery", "sap/ui/core/StaticArea" ], function(Log, mLibrary, Core, jQuery, StaticArea) { "use strict"; /** * STATIC MEMBERS */ var SAP_ILLUSTRATION_POOL_ID = 'sap-ui-illustration-pool', SAP_ILLUSTRATION_PATTERNS_NAME = '-Patterns', SAP_ILLUSTRATION_SET_NAME = 'sapIllus', SAP_ILLUSTRATION_SET_PATH = sap.ui.require.toUrl("sap/m/themes/base/illustrations/"), SAP_ILLUSTRATION_SET_SYMBOLS = Object.keys(mLibrary.IllustratedMessageType); /* * A map of registered sets * key: set name * value: configuration object containing * key: sPath * value: string path of the illustration set * key: aSymbols * value: array of the symbols names which the illustration set supports * key: bIsPending * value: boolean of whether or not the Illustration Set is loading */ var oSetRegistry = Object.create(null); oSetRegistry[SAP_ILLUSTRATION_SET_NAME] = { sPath: SAP_ILLUSTRATION_SET_PATH, aSymbols: SAP_ILLUSTRATION_SET_SYMBOLS, bIsPending: false }; var aSymbolsInDOM = [], // Array with IDs of the symbols which are already in the DOM oAssetRegistry = Object.create(null), // Object with IDs of the assets which are loaded or being loaded oLoadedSymbols = Object.create(null), // Object which stores the loaded HTML raw data for a given asset for future reuse (might not be in the DOM yet) oRequiredAssets = Object.create(null); // Object which stores the last required asset ID for a given instance /** * <code>IllustrationPool</code> loads the illustration assets (SVGs) via XMLHttpRequest requests. * * The successfully loaded data is kept in the DOM (div with ID <code>sap-illustration-pool</code>) * in the <code>sap-ui-static</code> DOM element. * * To load a given asset, register its illustration set through the * {@link sap.m.IllustrationPool.registerIllustrationSet registerIllustrationSet} API of <code>IllustrationPool</code>. * The exception being the <code>sapIllus</code>, which is the default illustration set * that is registered by default. * * The default behavior of <code>IllustrationPool</code> is to load/require an asset only * when it's needed by using the {@link sap.m.IllustrationPool.loadAsset} API. * When registering the new illustration set, you are given the option to load all of its assets. * * If some of the assets are not loaded initially, you can load the rest of them on * a later state with the {@link sap.m.IllustrationPool.loadRestOfTheAssets} API. * * @namespace * @since 1.98 * @public * @alias sap.m.IllustrationPool */ var IllustrationPool = {}; /** * PUBLIC METHODS */ /** * Loads an SVG asset depending on the input asset ID. * * @param {string} sAssetId The string ID of the asset being loaded * @param {string} sInstanceId the ID of the Illustration instance which is requiring the asset * @static * @public */ IllustrationPool.loadAsset = function (sAssetId, sInstanceId) { var sSet; if (sAssetId === "") { Log.error("ID of the asset can not be blank/empty."); return; } // if the the asset is required by an instance - cache its ID if (sInstanceId) { oRequiredAssets[sInstanceId] = sAssetId; } if (oAssetRegistry[sAssetId]) { Log.info("The asset with ID '" + sAssetId + "' is either loaded or being loaded."); // if the the asset is required by an instance and it's loaded - update the DOM pool if (sInstanceId && oLoadedSymbols[sAssetId]) { IllustrationPool._updateDOMPool(); } return; } sSet = sAssetId.split("-")[0]; if (!oSetRegistry[sSet]) { Log.error("The illustration set '" + sSet + "' is not registered. Please register it before requiring one of its assets."); return; } oAssetRegistry[sAssetId] = true; IllustrationPool._requireSVG(sSet, sAssetId, sInstanceId); }; /** * Loads the rest of the SVG assets for a given illustration set. * * @param {string} sIllustrationSet The illustration set, the rest of the assets should be loaded for * @static * @public */ IllustrationPool.loadRestOfTheAssets = function(sIllustrationSet) { var aSymbols; if (!oSetRegistry[sIllustrationSet]) { throw new Error("The illustration set '" + sIllustrationSet + "' is not registered. Please register it before requiring rest of its assets."); } aSymbols = oSetRegistry[sIllustrationSet].aSymbols; if (Array.isArray(aSymbols)) { aSymbols.forEach(function(sSymbol) { IllustrationPool.loadAsset(sIllustrationSet + "-Dot-" + sSymbol); IllustrationPool.loadAsset(sIllustrationSet + "-Spot-" + sSymbol); IllustrationPool.loadAsset(sIllustrationSet + "-Dialog-" + sSymbol); IllustrationPool.loadAsset(sIllustrationSet + "-Scene-" + sSymbol); }); } }; /** * Registers an illustration set, which is needed before loading any of its assets. * * @param {object} oConfig object containing the name and the path of the Illustration Set * @param {string} oConfig.setFamily Name of the Illustration Set * @param {string} oConfig.setURI URL Path of the Illustration Set * @param {boolean} bLoadAllResources whether or not all of the assets for the Illustration Set * should be loaded once the metadata is loaded * @static * @public */ IllustrationPool.registerIllustrationSet = function(oConfig, bLoadAllResources) { var sName = oConfig.setFamily, sPath = oConfig.setURI; if (oSetRegistry[sName]) { if (oSetRegistry[sName].bIsPending) { Log.warning("Illustration Set is currently being loaded."); } else { Log.warning("Illustration Set already registered."); } return; } // add trailing slash if necessary for more convenience if (sPath.substr(sPath.length - 1) !== "/") { sPath += "/"; } oSetRegistry[sName] = Object.create(null); oSetRegistry[sName].sPath = sPath; oSetRegistry[sName].bIsPending = true; IllustrationPool._loadMetadata(sName, sPath, bLoadAllResources); }; /** * PRIVATE METHODS */ /** * Adds an asset to the Illustration Pool's DOM element inner HTML. * * @param {string} sHTML string containing the raw HTML of an asset * @param {string} sId string containing the ID of an asset * @static * @private */ IllustrationPool._addAssetToDOMPool = function(sHTML, sId) { IllustrationPool._getDOMPool().insertAdjacentHTML("beforeend", sHTML); if (sId) { aSymbolsInDOM.push(sId); } }; /** * Returns the DOM for the Illustration Pool. * It also loads the mandatory patterns for the default Illustration Set once the DOM is created. * * @return {Object} DOM reference of the Illustration Pool * @static * @private */ IllustrationPool._getDOMPool = function() { var oDOMPool = document.getElementById(SAP_ILLUSTRATION_POOL_ID); if (oDOMPool === null) { oDOMPool = document.createElement("div"); oDOMPool.id = SAP_ILLUSTRATION_POOL_ID; oDOMPool.setAttribute("aria-hidden", "true"); StaticArea.getDomRef().appendChild(oDOMPool); // Load the patterns for the default illustration set after the DOM Pool is created IllustrationPool.loadAsset(SAP_ILLUSTRATION_SET_NAME + SAP_ILLUSTRATION_PATTERNS_NAME); } return oDOMPool; }; /** * Loads the metadata of an Illustration Set. * * @param {string} sName the name of the Illustration Set for which the metadata is being loaded * @param {string} sPath the path of the Illustration Set for which the metadata is being loaded * @param {boolean} bLoadAllResources whether or not all of the assets for the Illustration Set should be loaded * @return {Promise} Promise which resolves when the metadata is loaded * @static * @private */ IllustrationPool._loadMetadata = function(sName, sPath, bLoadAllResources) { var sMetadataPath = sPath + "metadata.json"; return new Promise(function (fnResolve) { jQuery.ajax(sMetadataPath, { type: "GET", dataType: "json", success: function (oMetadataJSON) { Log.info("Metadata for illustration set (" + sName + ") successfully loaded"); IllustrationPool._metadataLoaded(sName, oMetadataJSON, bLoadAllResources); fnResolve(oMetadataJSON); // passing the json in the resolve for testing purposes }, error: function (jqXHR, sStatus) { if (sStatus !== "abort") { // log an error if it isn't aborted Log.error("Metadata from: " + sMetadataPath + " file path could not be loaded"); delete oSetRegistry[sName]; fnResolve(); } } }); }); }; /** * Hook which is triggered when the metadata for an Illustration Set is loaded. * * @param {string} sName the name of the Illustration Set for which the metadata is loaded * @param {object} oMetadataJSON the loaded metadata object * @param {boolean} bLoadAllResources whether or not all of the assets for the Illustration Set should be loaded * @static * @private */ IllustrationPool._metadataLoaded = function(sName, oMetadataJSON, bLoadAllResources) { var aSymbols = oMetadataJSON.symbols, bHasPatterns = oMetadataJSON.requireCustomPatterns; oSetRegistry[sName].aSymbols = aSymbols; // Load the patterns (if available) as soon as possible, since they can be used in any of the symbols. if (bHasPatterns) { IllustrationPool.loadAsset(sName + SAP_ILLUSTRATION_PATTERNS_NAME); } if (bLoadAllResources) { IllustrationPool.loadRestOfTheAssets(sName); } oSetRegistry[sName].bIsPending = false; }; /** * Removes an asset from the Illustration Pool's DOM element inner HTML. * * @param {string} sId string containing the ID of the asset which should be removed from the Illustration Pool's DOM * @static * @private */ IllustrationPool._removeAssetFromDOMPool = function(sId) { var oDOMPool = document.getElementById(SAP_ILLUSTRATION_POOL_ID), oAssetDOM; if (oDOMPool !== null) { oAssetDOM = document.getElementById(sId); if (oAssetDOM !== null) { oDOMPool.removeChild(oAssetDOM); aSymbolsInDOM.splice(aSymbolsInDOM.indexOf(sId), 1); } } }; /** * Loads an SVG asset. * * @param {string} sSet the name of the Illustration Set for which the asset is being loaded * @param {string} sId the ID of the asset being loaded * @param {string} sInstanceId the ID of the Illustration instance which is requiring the asset * @return {Promise} Promise which resolves when the SVG asset is loaded * @static * @private */ IllustrationPool._requireSVG = function(sSet, sId, sInstanceId) { return new Promise(function (fnResolve) { jQuery.ajax(oSetRegistry[sSet].sPath + sId + ".svg", { type: "GET", dataType: "html", success: function (sHTML) { // if asset is a symbol, and not a pattern if (sId.indexOf(SAP_ILLUSTRATION_PATTERNS_NAME) === -1) { // cache the loaded symbol oLoadedSymbols[sId] = sHTML; // update the DOM if the asset is required by an instance if (sInstanceId) { IllustrationPool._updateDOMPool(); } } else { // add the pattern immediately IllustrationPool._addAssetToDOMPool(sHTML); } fnResolve(sHTML); }, error: function (jqXHR, sStatus) { if (sStatus !== "abort") { // log an error if it isn't aborted delete oAssetRegistry[sId]; Core.getEventBus().publish("sapMIllusPool-assetLdgFailed"); Log.error(sId + " asset could not be loaded"); fnResolve(); } } }); }); }; /** * Updates the IllustrationPool's DOM node. Adds the currently required assets (if they are * not already there) and removes the ones which are not needed. * * @static * @private */ IllustrationPool._updateDOMPool = function() { var oAssetsToKeep = Object.create(null), oAssetsToAdd = Object.create(null), sCurrAsset, iCurrIndexInDOM; for (var sCurrInstance in oRequiredAssets) { sCurrAsset = oRequiredAssets[sCurrInstance]; iCurrIndexInDOM = aSymbolsInDOM.indexOf(sCurrAsset); // if the asset is not already in the DOM, remember its ID and add it later, if it's loaded if (iCurrIndexInDOM === -1) { oAssetsToAdd[sCurrAsset] = true; } else { // if the asset is already in the DOM, remember its ID to help remove the not needed ones later oAssetsToKeep[sCurrAsset] = true; } } // remove the symbols which are not used and are not required for (var i = 0; i < aSymbolsInDOM.length; i++) { sCurrAsset = aSymbolsInDOM[i]; if (!oAssetsToKeep[sCurrAsset]) { IllustrationPool._removeAssetFromDOMPool(sCurrAsset); i--; } } for (var sId in oAssetsToAdd) { sCurrAsset = oLoadedSymbols[sId]; // add the missing required asset to the DOM only if it's loaded if (sCurrAsset) { IllustrationPool._addAssetToDOMPool(sCurrAsset, sId); } } }; return IllustrationPool; }, /* bExport= */ true);