UNPKG

@openui5/sap.ui.core

Version:

OpenUI5 Core Library sap.ui.core

276 lines (254 loc) 10.7 kB
/*! * OpenUI5 * (c) Copyright 2026 SAP SE or an SAP affiliate company. * Licensed under the Apache License, Version 2.0 - see LICENSE.txt. */ sap.ui.define(["sap/base/future", "sap/ui/core/Component"], function(future, Component) { "use strict"; // contains all external ExtensionProvider instances, mapped by their class-name var mExtensionProvider = {}; /** * Static controller extensions provider. * Reads the extension information from the Manifest of the owner-component. * Additionally relays the resolution to an ExternalProvider. * * @since 1.88.0 * @alias sap.ui.core.mvc.ControllerExtensionProvider * @static * @namespace * @private * @ui5-restricted sap.ui.core.mvc.Controller */ var ControllerExtensionProvider = {}; /** * Global extension provider name which will be used to create the * instance of the extension provider. * * @private */ ControllerExtensionProvider._sExtensionProvider = null; /** * Registers a callback module, which provides code enhancements for the * lifecycle and event handler functions of a specific controller. The code * enhancements are returned either in sync or async mode. * * The extension provider module provides the <code>getControllerExtensions</code> function * which returns either directly an array of objects or a Promise that returns an array * of objects when it resolves. These objects are object literals defining the * methods and properties of the controller in a similar way as for {@link sap.ui.core.mvc.Controller Controller} subclasses. * * * <b>Example for a callback module definition (sync):</b> * <pre> * sap.ui.define("my/custom/sync/ExtensionProvider", [], function() { * var ExtensionProvider = function() {}; * ExtensionProvider.prototype.getControllerExtensions = function(sControllerName, sComponentId, bAsync) { * if (!bAsync && sControllerName == "my.own.Controller") { * // IMPORTANT: only return extensions for a specific controller * return [{ * onInit: function() { * // Do something here... * }, * onAfterRendering: function() { * // Do something here... * }, * onButtonClick: function(oEvent) { * // Handle the button click event * } * } * }]; * }; * return ExtensionProvider; * }); * </pre> * * * <b>Example for a callback module definition (async):</b> * <pre> * sap.ui.define("my/custom/async/ExtensionProvider", [], function() { * var ExtensionProvider = function() {}; * ExtensionProvider.prototype.getControllerExtensions = function(sControllerName, sComponentId, bAsync) { * if (bAsync && sControllerName == "my.own.Controller") { * // IMPORTANT: * // only return a Promise for a specific controller since it * // requires the View/Controller and its parents to run in async * // mode! * return new Promise(function(fnResolve, fnReject) { * fnResolve([{ * onInit: function() { * // Do something here... * }, * onAfterRendering: function() { * // Do something here... * }, * onButtonClick: function(oEvent) { * // Handle the button click event * } * }]); * } * }; * }; * return ExtensionProvider; * }); * </pre> * * * The lifecycle functions <code>onInit</code>, <code>onExit</code>, * <code>onBeforeRendering</code> and <code>onAfterRendering</code> * are added before or after the lifecycle functions of the original * controller. The event handler functions, such as <code>onButtonClick</code>, * are replacing the original controller's function. * * When using an async extension provider, you need to ensure that the * view is loaded in async mode. * * In both cases, return <code>undefined</code> if no controller extension shall be applied. * * @param {string} sExtensionProvider the module name of the extension provider * * See {@link sap.ui.core.mvc.Controller} for an overview of the available functions for controllers. * * @alias sap.ui.core.mvc.ControllerExtensionProvider.registerExtensionProvider * @static * @private * @ui5-restricted sap/ui/fl */ ControllerExtensionProvider.registerExtensionProvider = function(sExtensionProvider) { ControllerExtensionProvider._sExtensionProvider = sExtensionProvider; }; /** * Retrieves the controller extensions. * * @param {string} sControllerName the name of the controller which should be extended * @param {string} sComponentId the ID of the controller's owner-component * @param {string} sViewId the view-id which is used to distinguish instance-specific controller extensions * @param {boolean} bAsync whether the provider should act asynchronously * @returns {object} an object containing all controller-extensions * split into two parts: * 1. extensions from the customizing configuration in the manifest (<return>.customizingControllerNames) * 2. extensions from the external provider (<return>.providerControllers) * * @private * @ui5-restricted sap.ui.core.mvc.Controller * @ui5-transform-hint replace-param bAsync true */ ControllerExtensionProvider.getControllerExtensions = function(sControllerName, sComponentId, sViewId, bAsync) { var mControllerExtensions = { customizingControllerNames: [], // extensions defined in the manifest via customizing config providerControllers: [] // extensions loaded via external provider }; var oComponent = Component.getComponentById(sComponentId); // the view ID used in the customizing definition in the manifest.json // must not contain a reference to the runtime ID of the component itself if (oComponent && oComponent.getLocalId) { // if view ID is not prefixed getLocalId returns null sViewId = oComponent.getLocalId(sViewId) || sViewId; } // 1. Read customizing config from manifest var aManifestExtensions = readManifestExtensionConfiguration(sControllerName, oComponent, sViewId); mControllerExtensions.customizingControllerNames = aManifestExtensions; if (bAsync) { // 2. Read extensions from externally defined ExtensionProvider (if registered) if (ControllerExtensionProvider._sExtensionProvider) { return loadExtensionProvider(bAsync).then(function (oExternalProvider) { return oExternalProvider.getControllerExtensions(sControllerName, sComponentId, bAsync, sViewId); }).then(function(aExternalExtensions) { // add provider-extensions mControllerExtensions.providerControllers = aExternalExtensions || []; return mControllerExtensions; }); } else { return Promise.resolve(mControllerExtensions); } } else { // 2. Read extensions from externally defined ExtensionProvider (if registered) if (ControllerExtensionProvider._sExtensionProvider) { var oExternalProvider = loadExtensionProvider(); if (oExternalProvider) { var aExternalExtensions = oExternalProvider.getControllerExtensions(sControllerName, sComponentId, bAsync, sViewId); if (aExternalExtensions && Array.isArray(aExternalExtensions)) { // add provider-extensions mControllerExtensions.providerControllers = aExternalExtensions; } else { future.errorThrows("Controller Extension Provider: Error in ExtensionProvider.getControllerExtensions: " + ControllerExtensionProvider._sExtensionProvider + " - no valid extensions returned. Return value must be an array of ControllerExtensions."); } } } return mControllerExtensions; } }; function readManifestExtensionConfiguration(sControllerName, oComponent, sViewId) { var aControllerNames = []; // lookup config of "sap.ui.controllerExtensions" in Manifest var mInstanceSpecificConfig = Component.getCustomizing(oComponent, { type: "sap.ui.controllerExtensions", name: sControllerName + "#" + sViewId }); // First check for instance-specific extension, if none exists look for base extension var aControllerExtConfigs = []; if (mInstanceSpecificConfig) { aControllerExtConfigs.push(mInstanceSpecificConfig); } else { var mDefaultConfig = Component.getCustomizing(oComponent, { type: "sap.ui.controllerExtensions", name: sControllerName }); if (mDefaultConfig) { aControllerExtConfigs.push(mDefaultConfig); } } for (var i = 0; i < aControllerExtConfigs.length; i++) { var vControllerExtensions = aControllerExtConfigs[i]; if (vControllerExtensions) { // Normalize the different legacy extension definitions, either: // - a string -> "my.ctrl.name" // - an object containing a controllerName:string property and/or a controllerNames:string[] property, e.g. // { controllerName: "my.ctrl.name0", controllerNames: ["my.ctrl.name1", "my.ctrl.name2"] } var sExtControllerName = typeof vControllerExtensions === "string" ? vControllerExtensions : vControllerExtensions.controllerName; aControllerNames = aControllerNames.concat(vControllerExtensions.controllerNames || []); if (sExtControllerName) { aControllerNames.unshift(sExtControllerName); } } } return aControllerNames; } /** * Load the registered ExtensionProvider. * * @param {boolean} bAsync Load async or not * @return {ExtensionProvider|Promise|undefined} ExtensionProvider <code>Promise</code> in case of asynchronous loading * or the <code>ExtensionProvider</code> in case of synchronous loading or undefined in case no provider exists * @ui5-transform-hint replace-param bAsync true */ function loadExtensionProvider(bAsync) { var sProviderName = ControllerExtensionProvider._sExtensionProvider.replace(/\./g, "/"), oProvider = mExtensionProvider[sProviderName]; // provider already available if (oProvider) { return bAsync ? Promise.resolve(oProvider) : oProvider; } // provider must be loaded if (sProviderName) { if (bAsync) { return new Promise(function(resolve, reject) { sap.ui.require([sProviderName], function(ExtensionProvider) { oProvider = new ExtensionProvider(); mExtensionProvider[sProviderName] = oProvider; resolve(oProvider); }, reject); }); } else { var ExtensionProviderClass = sap.ui.requireSync(sProviderName); // legacy-relevant: Sync path oProvider = new ExtensionProviderClass(); mExtensionProvider[sProviderName] = oProvider; return oProvider; } } else { // no provider registered return bAsync ? Promise.resolve() : undefined; } } return ControllerExtensionProvider; });