UNPKG

@openui5/sap.ui.core

Version:

OpenUI5 Core Library sap.ui.core

280 lines (258 loc) 10.7 kB
/*! * OpenUI5 * (c) Copyright 2009-2021 SAP SE or an SAP affiliate company. * Licensed under the Apache License, Version 2.0 - see LICENSE.txt. */ // Provides control sap.ui.core.mvc.JSONView. sap.ui.define([ './View', './JSONViewRenderer', './EventHandlerResolver', 'sap/base/util/merge', 'sap/ui/base/ManagedObject', 'sap/ui/core/library', 'sap/ui/model/resource/ResourceModel', 'sap/base/Log', 'sap/base/util/LoaderExtensions' ], function( View, JSONViewRenderer, EventHandlerResolver, merge, ManagedObject, library, ResourceModel, Log, LoaderExtensions ) { "use strict"; // shortcut for enum(s) var ViewType = library.mvc.ViewType; /** * Constructor for a new mvc/JSONView. * * <strong>Note:</strong> Application code shouldn't call the constructor directly, but rather use the factory * {@link sap.ui.core.mvc.JSONView.create JSONView.create} or {@link sap.ui.core.mvc.View.create View.create} * with type {@link sap.ui.core.mvc.ViewType.JSON JSON}. The factory simplifies asynchronous loading of a view * and future features might be added to the factory only. * * @param {string} [sId] id for the new control, generated automatically if no id is given * @param {object} [mSettings] initial settings for the new control * * @class * A View defined using JSON. * @extends sap.ui.core.mvc.View * @version 1.87.1 * * @public * @alias sap.ui.core.mvc.JSONView * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel */ var JSONView = View.extend("sap.ui.core.mvc.JSONView", /** @lends sap.ui.core.mvc.JSONView.prototype */ { metadata : { library : "sap.ui.core" }, renderer: JSONViewRenderer }); /** * Creates a JSON view of the given configuration. * * @param {object} oOptions An object containing the view configuration options. * @param {string} [oOptions.id] Specifies an ID for the view instance. If no ID is given, an ID will be generated. * @param {string} [oOptions.viewName] The view name (in dot-notation) that corresponds to a JSON resource that can * be loaded via the module system (viewName + suffix ".view.json"). * @param {string|object} [oOptions.definition] view definition as a JSON string or an object literal * @param {sap.ui.core.mvc.Controller} [oOptions.controller] Controller instance to be used for this view. * The given controller instance overrides the controller defined in the view definition. Sharing a controller instance * between multiple views is not supported. * @public * @static * @returns {Promise<sap.ui.core.mvc.JSONView>} A promise which resolves with the created <code>JSONView</code> instance. */ JSONView.create = function(oOptions) { var mParameters = merge({}, oOptions); //remove unsupported options: for (var sOption in mParameters) { if (sOption === 'preprocessors') { delete mParameters['preprocessors']; Log.warning("JSView.create does not support the option preprocessors!"); } } mParameters.type = ViewType.JSON; return View.create(mParameters); }; /** * Creates a JSON view of the given name and id. * * The <code>viewName</code> must either correspond to a JSON module that can be loaded * via the module system (viewName + suffix ".view.json") and which defines the view or it must * be a configuration object for a view. * The configuration object can have a viewName, viewContent and a controller property. The viewName * behaves as described above, viewContent can hold the view description as JSON string or as object literal. * * <strong>Note</strong>: when an object literal is given, it might be modified during view construction. * * The controller property can hold a controller instance. If a controller instance is given, * it overrides the controller defined in the view. * * When property <code>async</code> is set to true, the view definition and the controller class (and its * dependencies) will be loaded asynchronously. Any controls used in the view might be loaded sync or * async, depending on the view configuration. Even when the view definition is provided as string or object tree, * controller or controls might be loaded * asynchronously. In any case, a view instance will be returned synchronously by this factory API, but its * content (control tree) might appear only later. Also see {@link sap.ui.core.mvc.View#loaded}. * * Like with any other control, an id is optional and will be created when missing. * * @param {string} [sId] id of the newly created view * @param {string | object} vView name of a view resource or view configuration as described above. * @param {string} [vView.viewName] name of a view resource in module name notation (without suffix) * @param {string|object} [vView.viewContent] view definition as a JSON string or an object literal * @param {boolean} [vView.async] defines how the view source is loaded and rendered later on * @param {sap.ui.core.mvc.Controller} [vView.controller] controller to be used for this view instance * @public * @static * @deprecated since 1.56: Use {@link sap.ui.core.mvc.JSONView.create JSONView.create} instead. * @return {sap.ui.core.mvc.JSONView} the created JSONView instance * @ui5-global-only */ sap.ui.jsonview = function(sId, vView) { return sap.ui.view(sId, vView, ViewType.JSON); }; /** * The type of the view used for the <code>sap.ui.view</code> factory * function. This property is used by the parsers to define the specific * view type. * @private */ JSONView._sType = ViewType.JSON; /** * Flag for feature detection of asynchronous loading/rendering * @public * @since 1.30 */ JSONView.asyncSupport = true; JSONView.prototype.initViewSettings = function(mSettings) { if (!mSettings) { throw new Error("mSettings must be given"); } // View template handling - no JSON template given if (mSettings.viewName && mSettings.viewContent) { throw new Error("View name and view content are given. There is no point in doing this, so please decide."); } else if (!mSettings.viewName && !mSettings.viewContent) { throw new Error("Neither view name nor view content is given. One of them is required."); } var that = this; var fnInitModel = function() { if ((that._oJSONView.resourceBundleName || that._oJSONView.resourceBundleUrl) && (!mSettings.models || !mSettings.models[that._oJSONView.resourceBundleAlias])) { var oModel = new ResourceModel({ bundleName: that._oJSONView.resourceBundleName, bundleUrl: that._oJSONView.resourceBundleUrl, async: mSettings.async }); var vBundle = oModel.getResourceBundle(); // if ResourceBundle was created with async flag vBundle will be a Promise if (vBundle instanceof Promise) { return vBundle.then(function() { that.setModel(oModel, that._oJSONView.resourceBundleAlias); }); } that.setModel(oModel, that._oJSONView.resourceBundleAlias); } }; if (mSettings.viewName) { if (mSettings.async) { return this._loadTemplate(mSettings.viewName, {async: true}).then(fnInitModel); } else { this._loadTemplate(mSettings.viewName); fnInitModel(); } } else if (mSettings.viewContent) { // keep the content as a pseudo property to make cloning work but without supporting mutation // TODO model this as a property as soon as write-once-during-init properties become available this.mProperties["viewContent"] = mSettings.viewContent; if (typeof mSettings.viewContent === "string") { this._oJSONView = JSON.parse(mSettings.viewContent); if (!this._oJSONView) { // would lead to errors later on throw new Error("error when parsing viewContent: " + mSettings.viewContent); } } else if (typeof mSettings.viewContent === "object") { this._oJSONView = mSettings.viewContent; } else { throw new Error("viewContent must be a JSON string or object, but is a " + (typeof mSettings.viewContent)); } if (mSettings.async) { return Promise.resolve().then(fnInitModel); } else { fnInitModel(); } } // else does not happen, already checked }; JSONView.prototype.onControllerConnected = function(oController) { var that = this; // use preprocessors to fix IDs, associations and event handler references ManagedObject.runWithPreprocessors(function() { // parse that.applySettings({ content : that._oJSONView.content}, oController); }, { // preprocessors id : function(sId) { // prefix only if prefix doesn't exist already. Avoids double prefixes // for composite components (now done in createId) return that.createId(sId); }, // preprocess 'mSettings' for setting the controller as Listener for defined events // => make sure to store old preprocessor in case of nested views settings : function(oSettings) { var oMetadata = this.getMetadata(), aValidKeys = oMetadata.getJSONKeys(), // UID names required, they're part of the documented contract sKey, oValue, oKeyInfo; for (sKey in oSettings) { // get info object for the key if ( (oKeyInfo = aValidKeys[sKey]) !== undefined ) { oValue = oSettings[sKey]; switch (oKeyInfo._iKind) { case 3: // SINGLE ASSOCIATIONS // prefix the association ids with the view id if ( typeof oValue === "string" ) { oSettings[sKey] = that.createId(oValue); } break; case 5: // EVENTS if ( typeof oValue === "string" ) { oSettings[sKey] = EventHandlerResolver.resolveEventHandler(oValue, oController); } break; } } } } }); }; /** * Loads and returns the template from a given URL. * * @param {string} sTemplateName The name of the template * @param {object} [mOptions] with view settings * @param {boolean} [mOptions.async=false] whether the action should be performed asynchronously * @return {string|Promise} the template data, or a Promise resolving with it when async * @private */ JSONView.prototype._loadTemplate = function(sTemplateName, mOptions) { var sResourceName = sTemplateName.replace(/\./g, "/") + ".view.json"; if (!mOptions || !mOptions.async) { this._oJSONView = LoaderExtensions.loadResource(sResourceName); } else { var that = this; return LoaderExtensions.loadResource(sResourceName, mOptions).then(function(oJSONView) { that._oJSONView = oJSONView; }); } }; JSONView.prototype.getControllerName = function() { return this._oJSONView.controllerName; }; return JSONView; });