@openui5/sap.ui.core
Version:
OpenUI5 Core Library sap.ui.core
380 lines (348 loc) • 12.9 kB
JavaScript
/*!
* OpenUI5
* (c) Copyright 2026 SAP SE or an SAP affiliate company.
* Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
*/
// Provides control sap.ui.core.mvc.HTMLView.
sap.ui.define([
'./View',
'./HTMLViewRenderer',
'./ViewType',
'sap/base/util/merge',
'sap/ui/base/ManagedObject',
'sap/ui/base/OwnStatics',
'sap/ui/core/DeclarativeSupport',
'sap/ui/model/resource/ResourceModel',
'sap/base/util/LoaderExtensions'
],
function(
View,
HTMLViewRenderer,
ViewType,
merge,
ManagedObject,
OwnStatics,
DeclarativeSupport,
ResourceModel,
LoaderExtensions
) {
"use strict";
const { runWithPreprocessors } = OwnStatics.get(ManagedObject);
/**
* Constructor for a new <code>HTMLView</code>.
*
* <strong>Note:</strong> Application code shouldn't call the constructor directly, but rather use the factory
* {@link sap.ui.core.mvc.HTMLView.create HTMLView.create} or {@link sap.ui.core.mvc.View.create View.create}
* with type {@link sap.ui.core.mvc.ViewType.HTML HTML}. 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/constructed by declarative HTML.
* @extends sap.ui.core.mvc.View
*
* @author SAP SE
* @version 1.147.0
*
* @public
* @since 1.9.2
* @alias sap.ui.core.mvc.HTMLView
* @deprecated Since version 1.108, as there are no more known usages of <code>HTMLViews</code>,
* and as the use of HTML as syntax does not bring any advantages over XML. The HTML necessary for
* the <code>HTMLView</code> is not re-used for the HTML of the controls, but is fully replaced.
*
* Consider using {@link sap.ui.core.mvc.XMLView XMLViews} or "typed views" (view classes
* written in JavaScript) instead. For more information, see the documentation on
* {@link topic:91f27e3e6f4d1014b6dd926db0e91070 View types}.
*/
var HTMLView = View.extend("sap.ui.core.mvc.HTMLView", /** @lends sap.ui.core.mvc.HTMLView.prototype */ {
metadata : {
library : "sap.ui.core",
deprecated: true
},
renderer: HTMLViewRenderer
});
/**
* Creates an instance of a declarative HTML view.
*
* @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] Name of the view resource in module name notation (without suffix)
* @param {string} [oOptions.definition] The view definition.
* @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
* @since 1.56.0
* @return {Promise<sap.ui.core.mvc.HTMLView>} A promise which resolves with the created <code>HTMLView</code> instance
*/
HTMLView.create = function(oOptions) {
var mParameters = merge({}, oOptions);
mParameters.type = ViewType.HTML;
return View.create(mParameters);
};
/**
* Defines or creates an instance of a declarative HTML view.
*
* The behavior of this method depends on the signature of the call and on the current context.
*
* <ul>
* <li>View Definition <code>sap.ui.htmlview(sId, vView)</code>: Defines a view of the given name with the given
* implementation. sId must be the views name, vView must be an object and can contain
* implementations for any of the hooks provided by HTMLView</li>
* <li>View Instantiation <code>sap.ui.htmlview(sId?, vView)</code>: Creates an instance of the view with the given name (and id)</li>.
* </ul>
*
* Any other call signature will lead to a runtime error. If the id is omitted in the second variant, an id will
* be created automatically.
*
* @param {string} [sId] id of the newly created view, only allowed for instance creation
* @param {string | object} vView name or implementation of the view.
* @param {boolean} [vView.async] whether the view source is loaded asynchronously
* @public
* @static
* @deprecated Since 1.56. Use {@link sap.ui.core.mvc.HTMLView.create HTMLView.create} to create view instances
* @return {sap.ui.core.mvc.HTMLView | undefined} the created HTMLView instance in the creation case, otherwise undefined
* @ui5-global-only
*/
sap.ui.htmlview = function(sId, vView) {
return sap.ui.view(sId, vView, ViewType.HTML); // legacy-relevant
};
/**
* 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
*/
HTMLView._sType = ViewType.HTML;
/**
* Flag for feature detection of asynchronous loading/rendering
* @public
* @readonly
* @type {boolean}
* @since 1.30
*/
HTMLView.asyncSupport = true;
/**
* The template cache. Templates are only loaded once.
*
* @private
* @static
*/
HTMLView._mTemplates = {};
/**
* A map with the allowed settings for the view.
*
* @private
* @static
*/
HTMLView._mAllowedSettings = {
"viewName" : true,
"controller" : true,
"viewContent" : true,
"definition" : true,
"controllerName" : true,
"resourceBundleName" : true,
"resourceBundleUrl" : true,
"resourceBundleLocale" : true,
"resourceBundleAlias" : true
};
/**
* Loads and returns a template for the given template name. Templates are only loaded once {@link sap.ui.core.mvc.HTMLView._mTemplates}.
*
* @param {string} sTemplateName The name of the template
* @param {object} mOptions configuration options
* @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
* @static
*/
HTMLView._getTemplate = function(sTemplateName, mOptions) {
var sUrl = this._getViewUrl(sTemplateName);
var sHTML = this._mTemplates[sUrl];
if (!sHTML) {
sHTML = this._loadTemplate(sTemplateName, mOptions);
// TODO discuss
// a) why caching at all (more precise: why for HTMLView although we refused to do it for other view types - risk of a memory leak!)
// b) why cached via URL instead of via name? Any special scenario in mind?
if (mOptions && mOptions.async) {
var that = this;
return sHTML.then(function(_sHTML) {
that._mTemplates[sUrl] = _sHTML;
return Promise.resolve(_sHTML);
});
} else {
this._mTemplates[sUrl] = sHTML;
}
}
return mOptions.async ? Promise.resolve(sHTML) : sHTML;
};
/**
* Abstract method implementation. Returns the name of the controller.
* @return {string} the name of the set controller. Returns undefined when no controller is set.
* @private
*/
HTMLView.prototype.getControllerName = function() {
return this._controllerName;
};
/**
* Returns the view URL for a given template name in respect of the module path.
*
* @param {string} sTemplateName The name of the template
* @return {string} the view url
* @private
* @static
*/
HTMLView._getViewUrl = function(sTemplateName) {
return sap.ui.require.toUrl(sTemplateName.replace(/\./g, "/")) + ".view.html";
};
/**
* Loads and returns the template from a given URL.
*
* @param {string} sTemplateName The name of the template
* @param {object} [mOptions] configuration options
* @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
* @static
*/
HTMLView._loadTemplate = function(sTemplateName, mOptions) {
var sResourceName = sTemplateName.replace(/\./g, "/") + ".view.html";
return LoaderExtensions.loadResource(sResourceName, mOptions);
};
/**
* Abstract method implementation.
*
* @see sap.ui.core.mvc.View#initViewSettings
*
* @private
*/
HTMLView.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;
function fnInitViewSettings() {
that._oTemplate = document.createElement("div");
if (typeof vHTML === "string") {
that._oTemplate.innerHTML = vHTML;
} else {
var oNodeList = vHTML;
var oFragment = document.createDocumentFragment();
for (var i = 0; i < oNodeList.length;i++) {
oFragment.appendChild(oNodeList.item(i));
}
that._oTemplate.appendChild(oFragment);
}
var oMetaElement = that._oTemplate.getElementsByTagName("template")[0];
var oProperties = that.getMetadata().getAllProperties();
if (oMetaElement) {
var aAttributes = oMetaElement.getAttributeNames();
for (var j = 0; j < aAttributes.length; j++) {
var sAttributeName = aAttributes[j];
var sSettingName = DeclarativeSupport.convertAttributeToSettingName(sAttributeName, that.getId());
var sValue = oMetaElement.getAttribute(sAttributeName);
var oProperty = oProperties[sSettingName];
if (!mSettings[sSettingName]) {
if (oProperty) {
mSettings[sSettingName] = DeclarativeSupport.convertValueToType(DeclarativeSupport.getPropertyDataType(oProperty),sValue);
} else if (HTMLView._mAllowedSettings[sSettingName]) {
mSettings[sSettingName] = sValue;
}
}
}
that._oTemplate = oMetaElement;
}
// that is a fix for browsers that support web components
if (that._oTemplate.content) {
var oFragment = that._oTemplate.content;
// Create a new template, as innerHTML would be empty for TemplateElements when the fragment is appended directly
that._oTemplate = document.createElement("div");
// Make the shadow DOM available in the DOM
that._oTemplate.appendChild(oFragment);
}
if (mSettings.controllerName) {
that._controllerName = mSettings.controllerName;
}
if ((mSettings.resourceBundleName || mSettings.resourceBundleUrl) && (!mSettings.models || !mSettings.models[mSettings.resourceBundleAlias])) {
var oModel = new ResourceModel({
bundleName: mSettings.resourceBundleName,
bundleUrl: mSettings.resourceBundleUrl,
bundleLocale: mSettings.resourceBundleLocale,
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, mSettings.resourceBundleAlias);
});
}
that.setModel(oModel, mSettings.resourceBundleAlias);
}
}
var vHTML = mSettings.viewContent;
if (!vHTML) {
// vHTML could be a promise if {async: true}
vHTML = HTMLView._getTemplate(mSettings.viewName, {async: mSettings.async});
}
if (mSettings.async) {
// return the promise
return vHTML.then(function(_vHTML) {
vHTML = _vHTML;
return fnInitViewSettings();
});
}
fnInitViewSettings();
};
/**
* Abstract method implementation.
*
* @see sap.ui.core.mvc.View#onControllerConnected
*
* @private
*/
HTMLView.prototype.onControllerConnected = function(oController) {
// unset any preprocessors (e.g. from an enclosing HTML view)
var that = this;
runWithPreprocessors(function() {
DeclarativeSupport.compile(that._oTemplate, that);
}, {
settings: this._fnSettingsPreprocessor
});
};
/**
* Called when the control is destroyed. Use this one to free resources and finalize activities.
*/
HTMLView.prototype.exit = function() {
this._oTemplate = null;
View.prototype.exit.call(this);
// Destroy all unassociated controls that are connected with the view
if (this._connectedControls) {
for (var i = 0; i < this._connectedControls.length; i++) {
this._connectedControls[i].destroy();
}
this._connectedControls = null;
}
};
/**
* Internal method to connect unassociated controls to the view. All controls will be destroyed when the view is destroyed.
*
* @param {sap.ui.core.Control} oControl reference to a Control
* @private
*/
HTMLView.prototype.connectControl = function(oControl) {
this._connectedControls = this._connectedControls || [];
this._connectedControls.push(oControl);
};
return HTMLView;
});