@openui5/sap.ui.core
Version:
OpenUI5 Core Library sap.ui.core
927 lines (863 loc) • 37.2 kB
JavaScript
/*!
* OpenUI5
* (c) Copyright 2009-2021 SAP SE or an SAP affiliate company.
* Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
*/
// Provides base class for controllers (part of MVC concept)
sap.ui.define([
'sap/base/util/ObjectPath',
'sap/base/util/extend',
'sap/ui/base/EventProvider',
'sap/ui/base/ManagedObject',
'sap/ui/core/mvc/ControllerMetadata',
'sap/ui/core/mvc/ControllerExtension',
'sap/ui/core/mvc/OverrideExecution',
"sap/base/Log"
], function(
ObjectPath,
extend,
EventProvider,
ManagedObject,
ControllerMetadata,
ControllerExtension,
OverrideExecution,
Log
) {
"use strict";
var mRegistry = {};
var mExtensionProvider = {};
/**
* Instantiates a (MVC-style) controller. Consumers should call the constructor only in the
* typed controller scenario. In the generic controller use case, they should use
* {@link sap.ui.controller} instead.
*
* @class A generic controller implementation for the UI5 Model-View-Controller concept.
*
* Can either be used as a generic controller which is enriched on the fly with methods
* and properties (see {@link sap.ui.controller}) or as a base class for typed controllers.
*
* @param {string|object[]} sName The name of the controller to instantiate. If a controller is defined as real sub-class,
* the "arguments" of the sub-class constructor should be given instead.
*
* @public
* @alias sap.ui.core.mvc.Controller
* @extends sap.ui.base.EventProvider
*/
var Controller = EventProvider.extend("sap.ui.core.mvc.Controller", /** @lends sap.ui.core.mvc.Controller.prototype */ {
metadata: {
stereotype: "controller",
methods: {
"byId": {"public": true, "final": true},
"getView" : {"public": true, "final": true},
"getInterface" : {"public": false, "final": true},
"onInit": {"public": false, "final": false, "overrideExecution": OverrideExecution.After},
"onExit": {"public": false, "final": false, "overrideExecution": OverrideExecution.Before},
"onBeforeRendering": {"public": false, "final": false, "overrideExecution": OverrideExecution.Before},
"onAfterRendering": {"public": false, "final": false, "overrideExecution": OverrideExecution.After}
}
},
constructor : function(sName) {
var oToExtend = null;
if (typeof (sName) == "string") {
if (!mRegistry[sName]) {
Log.warning("Do not call sap.ui.core.mvc.Controller constructor for non typed scenario!");
}
oToExtend = mRegistry[sName];
}
EventProvider.apply(this,arguments);
if (oToExtend) {
extend(this, mRegistry[sName]);
}
if (this.extension) {
throw new Error("The keyword 'extension' cannot be used as a member of a controller");
}
this["_sapui_Extensions"] = {};
Controller.extendByMember(this, false);
this._sapui_isExtended = false;
},
/**
* Wether a controller is extended or not
* @private
* @returns {boolean} Whether controller is extended or not
*/
_isExtended: function() {
return this._sapui_isExtended;
},
/**
* Returns the public interface for this controller
*
* @returns {object} The public interface for this extension
* @private
*/
getInterface: function() {
var mMethods = {};
var oMetadata = this.getMetadata();
var aPublicMethods = oMetadata.getAllPublicMethods();
aPublicMethods.forEach(function(sMethod) {
var fnFunction = this[sMethod];
if (typeof fnFunction === 'function') {
mMethods[sMethod] = function() {
var tmp = fnFunction.apply(this, arguments);
return (tmp instanceof Controller) ? tmp.getInterface() : tmp;
}.bind(this);
}
}.bind(this));
this.getInterface = function() {
return mMethods;
};
return mMethods;
}
}, ControllerMetadata);
/**
* Apply extension to controller
*
* @param {sap.ui.core.mvc.Controller} oController The controller to extend
* @param {sap.ui.core.mvc.ControllerExtension|object} oCustomControllerDef The controller extension
* @param {string} [sLocalNamespace] Extensions could be applied to a local namespace. Do so if passed
* @private
*/
function applyExtension(oController, oExtension, sLocalNamespace) {
//create the controller extension object
var sNamespace = oExtension.getMetadata().getName();
var oControllerMetadata = oController.getMetadata();
var oExtensions = oController["_sapui_Extensions"];
var oInterface = oController.getInterface();
var mLifecycleConfig = ControllerExtension.getMetadata().getLifecycleConfiguration();
var oExtensionInfo = {
namespace: sNamespace,
extension: oExtension,
reloadNeeded: false
};
oExtension._setController(oInterface); //only allow access to public methods of the main controller
if (oExtension.getMetadata().hasOverrides()) {
//override the original controller methods for the entries in the "override" setting of the controller extension
var sExtensionOverride, oOrigExtensionInfo, oOrigExtensionMetadata, sOverrideMember,
oOverrides = oExtension.getMetadata().getOverrides(),
oStaticOverrides = oExtension.getMetadata().getStaticOverrides();
//handle 'inline' overrides first
for (sOverrideMember in oStaticOverrides) {
oOrigExtensionMetadata = oExtension.getMetadata();
if (!oOrigExtensionMetadata.isMethodFinal(sOverrideMember)) {
ControllerExtension.overrideMethod(sOverrideMember, oExtension, oStaticOverrides, oExtension, oOrigExtensionMetadata.getOverrideExecution(sOverrideMember));
} else {
Log.error("Method '" + sOverrideMember + "' of extension '" + sNamespace + "' is flagged final and cannot be overridden by calling 'override'");
}
}
//handle 'normal' overrides
for (sOverrideMember in oOverrides) {
if (sOverrideMember !== 'extension') {
//handle overrides on controller and member extensions
if (sOverrideMember in oExtension.base) {
Log.debug("Overriding member '" + sOverrideMember + "' of original controller.");
var vMember = oOverrides[sOverrideMember];
var fnOriginal = oController[sOverrideMember];
//check for member extension
if (typeof fnOriginal == "object" && typeof vMember == "object") {
oOrigExtensionInfo = oExtensions[sOverrideMember];
oOrigExtensionMetadata = oOrigExtensionInfo.extension.getMetadata();
for (sExtensionOverride in vMember) {
if (!oOrigExtensionMetadata.isMethodFinal(sExtensionOverride)) {
ControllerExtension.overrideMethod(sExtensionOverride, fnOriginal, vMember, oExtension, oOrigExtensionMetadata.getOverrideExecution(sExtensionOverride));
} else {
Log.error("Method '" + sExtensionOverride + "' of extension '" + oOrigExtensionInfo.namespace + "' is flagged final and cannot be overridden by extension '" + sNamespace + "'");
}
}
} else if (!oControllerMetadata.isMethodFinal(sOverrideMember)) {
ControllerExtension.overrideMethod(sOverrideMember, oController, oOverrides, oExtension, oControllerMetadata.getOverrideExecution(sOverrideMember));
} else {
Log.error("Method '" + sOverrideMember + "' of controller '" + oController.getMetadata().getName() + "' is flagged final and cannot be overridden by extension '" + sNamespace + "'");
}
} else if (sOverrideMember in mLifecycleConfig) {
//apply lifecycle hooks even if they don't exist on controller
ControllerExtension.overrideMethod(sOverrideMember, oController, oOverrides, oExtension, oControllerMetadata.getOverrideExecution(sOverrideMember));
} else {
Log.error("Method '" + sOverrideMember + "' does not exist in controller " + oController.getMetadata().getName() + " and cannot be overridden");
}
}
oExtensionInfo.reloadNeeded = true;
}
//handle non member extension overrides
if (oOverrides && oOverrides.extension) {
//allow to override methods of other controller extensions
for (var sExtensionNamespace in oOverrides.extension) {
oOrigExtensionMetadata = oExtensions[sExtensionNamespace].extension.getMetadata();
var oOrigExtensionInterface = ObjectPath.create(sExtensionNamespace, oController.extension);
var oOrigExtension = oExtensions[sExtensionNamespace].extension;
var oExtensionOverrides = oOverrides.extension[sExtensionNamespace];
for (sExtensionOverride in oExtensionOverrides) {
if (!oOrigExtensionMetadata.isMethodFinal(sExtensionOverride)) {
//override interface
ControllerExtension.overrideMethod(sExtensionOverride, oOrigExtensionInterface, oExtensionOverrides, oExtension, oOrigExtensionMetadata.getOverrideExecution(sExtensionOverride));
//override Extension so 'this' is working for overrides
ControllerExtension.overrideMethod(sExtensionOverride, oOrigExtension, oExtensionOverrides, oExtension, oOrigExtensionMetadata.getOverrideExecution(sExtensionOverride));
} else {
Log.error("Method '" + sExtensionOverride + "' of extension '" + sExtensionNamespace + "' is flagged final and cannot be overridden by extension '" + sNamespace + "'");
}
}
}
}
}
var oExtensionInterface = oExtension.getInterface();
if (sLocalNamespace) {
oExtensions[sLocalNamespace] = oExtensionInfo;
oExtensionInfo.location = sLocalNamespace;
oController[sLocalNamespace] = oExtensionInterface;
oInterface[sLocalNamespace] = oExtensionInterface;
} else {
oExtensions[sNamespace] = oExtensionInfo;
oExtensionInfo.location = "extension." + sNamespace;
ObjectPath.set("extension." + sNamespace, oExtensionInterface, oController);
ObjectPath.set("extension." + sNamespace, oExtensionInterface, oInterface);
}
}
/*
* Mixin controller extensions
* @param {sap.ui.core.mvc.Controller} oController The controller to apply the extensions
* @param {object} oCustomControllerDef The controller extension definition
* @private
*/
function mixinControllerDefinition(oController, CustomControllerDef, sLocalNameSpace) {
if (CustomControllerDef instanceof ControllerExtension) {
applyExtension(oController, CustomControllerDef, sLocalNameSpace);
} else if (CustomControllerDef.getMetadata && CustomControllerDef.getMetadata().getStereotype() == "controllerextension") {
//create ControllerExtension instance
var oControllerExtension = new CustomControllerDef();
applyExtension(oController, oControllerExtension, sLocalNameSpace);
} else {
//apply 'legacy' extension
var mLifecycleConfig = ControllerExtension.getMetadata().getLifecycleConfiguration();
for (var sMemberName in CustomControllerDef) {
if (sMemberName in mLifecycleConfig) {
ControllerExtension.overrideMethod(sMemberName, oController, CustomControllerDef, oController, mLifecycleConfig[sMemberName].overrideExecution);
} else {
//default extension behavior
ControllerExtension.overrideMethod(sMemberName, oController, CustomControllerDef);
}
}
}
}
/* load controller class
*
* @param {string} sName the controller name
* @param {boolean} bAsync Load async or not
* @return {{sap.ui.core.mvc.Controller | Promise} oController <code>Promise</code> in case of asynchronous loading
* or <code>undefined</code> in case of synchronous loading
*/
function loadControllerClass(sName, bAsync) {
if (!sName) {
throw new Error("Controller name ('sName' parameter) is required");
}
var sControllerName = sName.replace(/\./g, "/") + ".controller",
ControllerClass = resolveClass(sap.ui.require(sControllerName));
function resolveClass(ControllerClass) {
if (ControllerClass) {
return ControllerClass;
} else if (mRegistry[sName]) {
return Controller;
} else {
//legacy controller
return ObjectPath.get(sName);
}
}
if (bAsync) {
return new Promise(function(resolve, reject) {
if (!ControllerClass) {
sap.ui.require([sControllerName], function (ControllerClass) {
resolve(resolveClass(ControllerClass));
}, reject);
} else {
resolve(ControllerClass);
}
});
} else if (!ControllerClass) {
ControllerClass = sap.ui.requireSync(sControllerName);
return resolveClass(ControllerClass);
} else {
return ControllerClass;
}
}
/* load extension provider
*
* @param {sap.ui.core.mvc.Controller} oController The controller instance
* @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
*/
function loadExtensionProvider(oController, bAsync) {
var sProviderName = Controller._sExtensionProvider.replace(/\./g, "/"),
oProvider = mExtensionProvider[sProviderName];
if (bAsync) {
return new Promise(function(resolve, reject) {
if (sProviderName) {
if (oProvider){
resolve(oProvider);
} else {
sap.ui.require([sProviderName], function(ExtensionProvider) {
oProvider = new ExtensionProvider();
mExtensionProvider[sProviderName] = oProvider;
resolve(oProvider);
}, reject);
}
} else {
resolve();
}
});
} else if (sProviderName) {
if (oProvider) {
return oProvider;
} else {
var ExtensionProvider = sap.ui.requireSync(sProviderName);
oProvider = new ExtensionProvider();
mExtensionProvider[sProviderName] = oProvider;
return oProvider;
}
}
}
/*
* Instantiation of a controller
*
* @param {function} ControllerClass The controller constructor
* @param {string} sName the controller name
* @param {boolean} bAsync Load async or not
* @return {sap.ui.core.mvc.Controller|Promise} A <code>Promise</code> in case of asynchronous extend
* or the <code>controller</code> in case of synchronous extend
*
*/
function instantiateController(ControllerClass, sName) {
var oController;
if (mRegistry[sName]) {
oController = new ControllerClass(sName);
} else {
oController = new ControllerClass();
}
if (!oController) {
throw new Error("Controller " + sName + " couldn't be instantiated");
}
return oController;
}
/**
* apply extension if passed as a member of the controller
* @param {sap.ui.core.mvc.Controller} oController The controller instance
* @param {boolean} bAsync Wether extend async or not
* @private
*/
Controller.extendByMember = function(oController, bAsync) {
var sMember;
//create all member extension instances first
for (sMember in oController) {
if (oController[sMember] &&
oController[sMember].getMetadata &&
oController[sMember].getMetadata().getStereotype() == "controllerextension") {
oController[sMember] = new oController[sMember]();
}
}
//apply the extensions
for (sMember in oController) {
if (oController[sMember] &&
oController[sMember].getMetadata &&
oController[sMember].getMetadata().getStereotype() == "controllerextension") {
mixinControllerDefinition(oController, oController[sMember], sMember);
}
}
if (bAsync) {
return Promise.resolve(oController);
} else {
return oController;
}
};
/*
* This function can be used to extend a controller with controller
* extensions defined in the Customizing configuration.
*
* @param {object|sap.ui.core.mvc.Controller} oController Controller to extend
* @param {string} sName Name of the controller
* @param {sap.ui.core.ID|undefined} sOwnerId the ID of the owner component to which this controller belongs,
* or undefined if the controller is not associated to a component
* @param {boolean} bAsync If set to true, extension will be run in async mode
* @returns {sap.ui.core.mvc.Controller|Promise} A <code>Promise</code> in case of asynchronous extend
* or the <code>controller</code> in case of synchronous extend
*
* @private
*/
Controller.extendByCustomizing = function(oController, sName, sOwnerId, bAsync) {
var CustomizingConfiguration = sap.ui.require('sap/ui/core/CustomizingConfiguration');
if (!CustomizingConfiguration) {
return bAsync ? Promise.resolve(oController) : oController;
}
function extendAsync(sCustomControllerName, oController) {
return loadControllerClass(sCustomControllerName, bAsync)
.then(function(oCustomControllerDef) {
// loadControllerClass resolves with the base sap/ui/core/mvc/Controller class,
// in case 'sCustomControllerName' is not a module but was defined with sap.ui.controller("...", {})
oCustomControllerDef = mRegistry[sCustomControllerName] || oCustomControllerDef;
if (oCustomControllerDef !== undefined) {
if (oCustomControllerDef.getMetadata && oCustomControllerDef.getMetadata().isA("sap.ui.core.mvc.Controller")) {
Log.warning("Attempt to load Extension Controller " + sCustomControllerName + " was not successful", "Controller extension should be a plain object.", null, function() {
return {
type: "ControllerExtension",
name: sCustomControllerName
};
});
} else {
mixinControllerDefinition(oController, oCustomControllerDef);
}
return oController;
}
}, function(err) {
Log.error("Attempt to load Extension Controller " + sCustomControllerName + " was not successful - is the Controller correctly defined in its file?");
});
}
var oCustomControllerDef,
aControllerNames = [],
sExtControllerName,
vController = bAsync ? Promise.resolve(oController) : oController,
controllerExtensionConfig = CustomizingConfiguration.getControllerExtension(sName, sOwnerId);
if (controllerExtensionConfig) {
sExtControllerName = typeof controllerExtensionConfig === "string" ? controllerExtensionConfig : controllerExtensionConfig.controllerName;
// create a list of controller names which will be used to extend this controller
aControllerNames = controllerExtensionConfig.controllerNames || [];
if (sExtControllerName) {
aControllerNames.unshift(sExtControllerName);
}
}
for (var i = 0, l = aControllerNames.length; i < l; i++) {
var sControllerName = aControllerNames[i];
// avoid null values for controllers to be handled here!
if (typeof sControllerName === "string") {
Log.info("Customizing: Controller '" + sName + "' is now extended by '" + sControllerName + "'");
if (bAsync) {
//chain controllers as the order of processing is relevant
vController = vController.then(extendAsync.bind(null, sControllerName, oController));
} else {
//load Controller extension
if (!mRegistry[sControllerName] && !sap.ui.require(sControllerName)) {
loadControllerClass(sControllerName);
}
if ((oCustomControllerDef = mRegistry[sControllerName]) !== undefined) { //variable init, not comparison!
mixinControllerDefinition(oController, oCustomControllerDef);
} else {
/* eslint-disable no-loop-func */
Log.error("Attempt to load Extension Controller " + sControllerName + " was not successful - is the Controller correctly defined in its file?", null, function() {
return {
type: "ControllerExtension",
name: sControllerName
};
});
/* eslint-enable no-loop-func */
}
}
}
}
return vController;
};
/*
* This function can be used to extend a controller with controller
* extensions returned by controller extension provider.
*
* @param {object|sap.ui.core.mvc.Controller} oController Controller to extend
* @param {string} sName Name of the controller
* @param {sap.ui.core.ID|undefined} sOwnerId the ID of the owner component to which this controller belongs,
* or undefined if the controller is not associated to a component
* @param {boolean} bAsync If set to true, extension will be run in async mode
* @return {sap.ui.core.mvc.Controller|Promise} A <code>Promise</code> in case of asynchronous extend
* or the <code>controller</code> in case of synchronous extend
* @private
*/
Controller.extendByProvider = function(oController, sName, sOwnerId, bAsync) {
if (!Controller._sExtensionProvider) {
return bAsync ? Promise.resolve(oController) : oController;
}
Log.info("Customizing: Controller '" + sName + "' is now extended by Controller Extension Provider '" + Controller._sExtensionProvider + "'");
var oExtensions,
oExtensionProvider;
if (bAsync) {
return loadExtensionProvider(oController, bAsync)
.then(function (oExtensionProvider) {
return oExtensionProvider.getControllerExtensions(sName /* controller name */, sOwnerId /* component ID / clarfiy if this is needed? */, bAsync);
})
.then(function (aControllerExtensions) {
if (aControllerExtensions && aControllerExtensions.length) {
for (var i = 0, l = aControllerExtensions.length; i < l; i++) {
mixinControllerDefinition(oController, aControllerExtensions[i]);
}
}
return oController;
}, function(err){
Log.error("Controller Extension Provider: Error '" + err + "' thrown in " + Controller._sExtensionProvider + "; extension provider ignored.");
return oController;
});
} else {
oExtensionProvider = loadExtensionProvider(oController, bAsync);
oExtensions = oExtensionProvider.getControllerExtensions(sName /* controller name */, sOwnerId /* component ID / clarfiy if this is needed? */, bAsync);
if (oExtensions && Array.isArray(oExtensions)) {
// in sync mode, oExtensions is an array of controller extensions
for (var i = 0, l = oExtensions.length; i < l; i++) {
mixinControllerDefinition(oController, oExtensions[i]);
}
} else {
Log.error("Controller Extension Provider: Error in ExtensionProvider.getControllerExtensions: " + Controller._sExtensionProvider + " - no valid extensions returned");
}
}
return oController;
};
/**
* Creates an instance of controller class.
*
* @param {object} mOptions A map containing the controller configuration options.
* @param {string} mOptions.name The controller name that corresponds to a JS module that can be loaded
* via the module system (mOptions.name + suffix ".controller.js")
* @return {Promise} the Promise resolves with a new instance of the controller
* @public
* @static
* @since 1.56.0
*/
Controller.create = function (mOptions) {
return controllerFactory(mOptions.name, undefined, true);
};
/**
* Defines a controller class or creates an instance of an already defined controller class.
*
* When a name and a controller implementation object is given, a new controller class
* of the given name is created. The members of the implementation object will be copied
* into each new instance of that controller class (shallow copy).
* <b>Note</b>: as the members are shallow copied, controller instances will share all object values.
* This might or might not be what applications expect.
*
* If only a name is given, a new instance of the named controller class is returned.
*
* @param {string} sName The controller name
* @param {object} [oControllerImpl] An object literal defining the methods and properties of the controller
* @param {boolean} [bAsync=false] Decides whether the controller gets loaded asynchronously or not
* @return {void | sap.ui.core.mvc.Controller | Promise} void, the new controller instance or a Promise
* resolving with the controller in async case
* @static
* @deprecated Since 1.56, use {@link sap.ui.core.mvc.Controller.create Controller.create} or
* {@link sap.ui.core.mvc.Controller.extend Controller.extend} instead.
* @public
* @ui5-global-only
*/
sap.ui.controller = function (sName, oControllerImpl, bAsync) {
if (bAsync) {
Log.info("Do not use deprecated factory function 'sap.ui.controller(" + sName + ")'. Use 'sap.ui.core.mvc.Controller.create(...)' instead.", "sap.ui.controller", null, function () {
return {
type: "sap.ui.controller",
name: sName
};
});
} else {
Log.warning("Do not use synchronous controller creation for controller '" + sName + "'! Use the new asynchronous factory 'sap.ui.core.mvc.Controller.create(...)' instead.", "sap.ui.controller", null, function () {
return {
type: "sap.ui.controller",
name: sName
};
});
}
return controllerFactory.apply(this, arguments);
};
/*
* Old controller factory implementation
*/
function controllerFactory(sName, oControllerImpl, bAsync) {
var oController,
ControllerClass,
sOwnerId = ManagedObject._sOwnerId;
if (typeof oControllerImpl === "boolean") {
oControllerImpl = undefined;
}
if (!oControllerImpl) {
// controller *instantiation*
if (bAsync) {
return loadControllerClass(sName, bAsync)
.then(function(ControllerClass) {
return instantiateController(ControllerClass, sName);
})
.then(function(oController) {
return Controller.extendByCustomizing(oController, sName, sOwnerId, bAsync);
})
.then(function(oController) {
return Controller.extendByProvider(oController, sName, sOwnerId, bAsync);
}).then(function(oController) {
oController._sapui_isExtended = true;
return oController;
});
} else {
ControllerClass = loadControllerClass(sName, bAsync);
oController = instantiateController(ControllerClass, sName);
oController = Controller.extendByCustomizing(oController, sName, sOwnerId, bAsync);
oController = Controller.extendByProvider(oController, sName, sOwnerId, bAsync);
//if controller is created via the factory all extensions are already mixed in
oController._sapui_isExtended = true;
}
return oController;
} else {
// controller *definition*
mRegistry[sName] = oControllerImpl;
Log.info("For defining controllers use Controller.extend instead");
}
}
/**
* Returns a list of public methods of the controller. If <code>bWithExtensions</code> is
* set to true the public methods of the extensions are also returned
*
* @private
*/
Controller.prototype.getPublicMethods = function() {
var mPublicFunctions = {},
oControllerMetadata = this.getMetadata(),
oControllerMethods = oControllerMetadata.getAllMethods(),
oLifeCycleConfig = oControllerMetadata.getLifecycleConfiguration();
Object.keys(oControllerMethods).forEach(function(sMethod) {
if (oControllerMetadata.isMethodPublic(sMethod)) {
mPublicFunctions[sMethod] = oControllerMethods[sMethod];
mPublicFunctions[sMethod].reloadNeeded = !!(sMethod in oLifeCycleConfig);
}
});
//extensions member should not be exposed
delete mPublicFunctions.extension;
var oExtensions = this["_sapui_Extensions"];
Object.keys(oExtensions).forEach(function(sNamespace) {
var oExtensionInfo = oExtensions[sNamespace];
var oExtensionInterface = oExtensionInfo.extension.getInterface();
var mAllMethods = oExtensionInfo.extension.getMetadata().getAllMethods();
Object.keys(oExtensionInterface).forEach(function(sMethod) {
//extension member should not be exposed
delete mPublicFunctions[oExtensionInfo.location];
var oMethodMetadata = extend({}, mAllMethods[sMethod], {reloadNeeded: oExtensionInfo.reloadNeeded});
mPublicFunctions[oExtensionInfo.location + "." + sMethod] = oMethodMetadata;
});
});
return mPublicFunctions;
};
/**
* Fire event when destroying a controller to cleanup extensions
* @private
*/
Controller.prototype.destroy = function() {
Object.keys(this["_sapui_Extensions"]).forEach(function(oExtensionInfo) {
ObjectPath.set(oExtensionInfo.location, null, this);
}.bind(this));
delete this["_sapui_Extensions"];
delete this["_sapui_Interface"];
EventProvider.prototype.destroy.apply(this, arguments);
};
/**
* Returns the view associated with this controller or undefined.
* @return {sap.ui.core.mvc.View} View connected to this controller.
* @public
*/
Controller.prototype.getView = function() {
return this.oView;
};
/**
* Returns an Element of the connected view with the given local ID.
*
* Views automatically prepend their own ID as a prefix to created Elements
* to make the IDs unique even in the case of multiple view instances.
* This method helps to find an element by its local ID only.
*
* If no view is connected or if the view doesn't contain an element with
* the given local ID, undefined is returned.
*
* @param {string} sId View-local ID
* @return {sap.ui.core.Element} Element by its (view local) ID
* @public
*/
Controller.prototype.byId = function(sId) {
return this.oView ? this.oView.byId(sId) : undefined;
};
/**
* Converts a view local ID to a globally unique one by prepending
* the view ID.
*
* If no view is connected, undefined is returned.
*
* @param {string} sId View-local ID
* @return {string} Prefixed ID
* @public
*/
Controller.prototype.createId = function(sId) {
return this.oView ? this.oView.createId(sId) : undefined;
};
/**
* Gets the component of the controller's view
*
* If there is no Component connected to the view or the view is not connected to the controller,
* undefined is returned.
*
* @return {sap.ui.core.Component} Component instance
* @since 1.23.0
* @public
*/
Controller.prototype.getOwnerComponent = function () {
var Component = sap.ui.requireSync("sap/ui/core/Component");
return Component.getOwnerComponentFor(this.getView());
};
Controller.prototype.connectToView = function(oView) {
this.oView = oView;
if (this.onInit) {
oView.attachAfterInit(this.onInit, this);
}
if (this.onExit) {
oView.attachBeforeExit(this.onExit, this);
}
if (this.onAfterRendering) {
oView.attachAfterRendering(this.onAfterRendering, this);
}
if (this.onBeforeRendering) {
oView.attachBeforeRendering(this.onBeforeRendering, this);
}
//oView.addDelegate(this);
};
/**
* Global extension provider name which will be used to create the
* instance of the extension provider.
*
* @private
*/
Controller._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 {@link sap.ui.controller}.
*
*
* <b>Example for a callback module definition (sync):</b>
* <pre>
* sap.ui.define("my/custom/sync/ExtensionProvider", ['jquery.sap.global'], function(jQuery) {
* 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;
* }, true);
* </pre>
*
*
* <b>Example for a callback module definition (async):</b>
* <pre>
* sap.ui.define("my/custom/async/ExtensionProvider", ['jquery.sap.global'], function(jQuery) {
* 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;
* }, true);
* </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.controller} for an overview of the available functions for controllers.
* @since 1.34.0
* @public
*/
Controller.registerExtensionProvider = function(sExtensionProvider) {
Controller._sExtensionProvider = sExtensionProvider;
};
/**
* This method is called upon initialization of the View. The controller can perform its internal setup in
* this hook. It is only called once per View instance, unlike the onBeforeRendering and onAfterRendering
* hooks.
* (Even though this method is declared as "abstract", it does not need to be defined in controllers, if the
* method does not exist, it will simply not be called.)
*
* <b>Note:</b> In component-based apps <code>this.getOwnerComponent().getModel()</code> should be used
* inside <code>onInit()</code> to get a model assigned to the component instead of using
* <code>this.getView().getModel()</code>. The latter call might return <code>undefined</code> because
* the view might not have been attached to a parent yet (i.e. the component), and thus the view
* can't inherit a model from that parent.
* You could also attach to the <code>modelContextChange</code> event. The event is fired when either
* the context or the model changes for the control.
*
* @function
* @name sap.ui.core.mvc.Controller.prototype.onInit
* @abstract
* @protected
*/
/**
* This method is called upon desctuction of the View. The controller should perform its internal destruction in
* this hook. It is only called once per View instance, unlike the onBeforeRendering and onAfterRendering
* hooks.
* (Even though this method is declared as "abstract", it does not need to be defined in controllers, if the
* method does not exist, it will simply not be called.)
*
* @function
* @name sap.ui.core.mvc.Controller.prototype.onExit
* @abstract
* @protected
*/
/**
* This method is called every time the View is rendered, before the Renderer is called and the HTML is placed in
* the DOM-Tree. It can be used to perform clean-up-tasks before re-rendering.
* (Even though this method is declared as "abstract", it does not need to be defined in controllers, if the
* method does not exist, it will simply not be called.)
*
* @see sap.ui.core.Control.prototype.onBeforeRendering
*
* @function
* @name sap.ui.core.mvc.Controller.prototype.onBeforeRendering
* @abstract
* @protected
*/
/**
* This method is called every time the View is rendered, after the HTML is placed in the DOM-Tree. It can be
* used to apply additional changes to the DOM after the Renderer has finished.
* (Even though this method is declared as "abstract", it does not need to be defined in controllers, if the
* method does not exist, it will simply not be called.)
*
* @see sap.ui.core.Control.prototype.onAfterRendering
*
* @function
* @name sap.ui.core.mvc.Controller.prototype.onAfterRendering
* @abstract
* @protected
*/
return Controller;
});