@openui5/sap.ui.core
Version:
OpenUI5 Core Library sap.ui.core
937 lines (855 loc) • 37.5 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.XMLView.
sap.ui.define([
"./View",
"./ViewType",
"./XMLViewRenderer",
"sap/base/config",
"sap/base/future",
"sap/base/Log",
"sap/base/i18n/Localization",
"sap/base/strings/hash",
"sap/base/util/LoaderExtensions",
"sap/base/util/merge",
"sap/ui/base/ManagedObject",
"sap/ui/base/OwnStatics",
"sap/ui/core/Core",
"sap/ui/core/Control",
"sap/ui/core/RenderManager",
"sap/ui/core/XMLTemplateProcessor",
"sap/ui/core/cache/CacheManager",
"sap/ui/model/resource/ResourceModel",
"sap/ui/util/XMLHelper",
"sap/ui/VersionInfo",
"sap/ui/performance/trace/Interaction",
"sap/ui/thirdparty/jquery"
],
function(
View,
ViewType,
XMLViewRenderer,
BaseConfig,
future,
Log,
Localization,
hash,
LoaderExtensions,
merge,
ManagedObject,
OwnStatics,
Core,
Control,
RenderManager,
XMLTemplateProcessor,
Cache,
ResourceModel,
XMLHelper,
VersionInfo,
Interaction,
jQuery
) {
"use strict";
const { runWithPreprocessors } = OwnStatics.get(ManagedObject);
// actual constants
var RenderPrefixes = RenderManager.RenderPrefixes,
sXMLViewCacheError = "XMLViewCacheError",
notCacheRelevant = {};
/**
* Dummy control for after rendering notification before onAfterRendering of
* child controls of the XMLView is called
*
* @extends sap.ui.core.Control
* @alias sap.ui.core.mvc.XMLAfterRenderingNotifier
* @private
* @deprecated since 1.120 because the support of HTML and SVG tags is deprecated
*/
var XMLAfterRenderingNotifier = Control.extend("sap.ui.core.mvc.XMLAfterRenderingNotifier", {
metadata: {
library: "sap.ui.core"
},
renderer: {
apiVersion: 2,
render: function(oRM, oControl) {
oRM.text(""); // onAfterRendering is only called if control produces output
}
}
});
/**
* Constructor for a new <code>XMLView</code>.
*
* <strong>Note:</strong> Application code shouldn't call the constructor directly, but rather use the factory
* {@link sap.ui.core.mvc.XMLView.create XMLView.create} or {@link sap.ui.core.mvc.View.create View.create}
* with type {@link sap.ui.core.mvc.ViewType.XML XML}. The factory provides more features than the
* constructor (e.g. caching and preprocessing) and simplifies asynchronous loading of a view.
* Future features might only be available when using the factory.
*
* @param {string} [sId] ID for the new view, generated automatically if no ID is given
* @param {object} [mSettings] Initial settings for the new view
*
* @class
* A View defined using XML and, optionally, pure HTML markup.
*
* <strong>Note:</strong><br>
* Be aware that modifications of the content aggregation of this control are not supported due to technical reasons.
* This includes calls to all content modifying methods like <code>addContent></code> etc., but also the implicit
* removal of controls contained by the content aggregation. For example the destruction of a Control via the <code>
* destroy</code> method. All functions can be called but may not work properly or lead to unexpected side effects.
*
* <strong>Note:</strong><br>
* The XML view offers special handling for context binding and style classes.
* You can specify them via the <code>binding</code> and <code>class</code> attributes on a control's XML node.
* Please be aware that these attributes are not properties of the respective controls and thus
* are not supported by a control's constructor.
* For more information, see {@link topic:91f05e8b6f4d1014b6dd926db0e91070 Context Binding (Element Binding)}
* and {@link topic:b564935324f449209354c7e2f9903f22 Using CSS Style Sheets in XML Views}.
*
* <strong>Note:</strong><br>
* When the content aggregation of this control is bound, no HTML markup is allowed in the binding template of the
* bound content aggregation. An error will be thrown when the above combination is detected.
*
* @extends sap.ui.core.mvc.View
* @version 1.147.0
*
* @public
* @alias sap.ui.core.mvc.XMLView
*/
var XMLView = View.extend("sap.ui.core.mvc.XMLView", /** @lends sap.ui.core.mvc.XMLView.prototype */ {
metadata : {
library : "sap.ui.core",
specialSettings : {
/**
* If an XMLView instance is used to represent an HTML subtree of another XMLView,
* then that other XMLView is provided with this setting to be able to delegate
* View functionality (createId, getController) to that 'real' view.
*/
containingView : { type: 'sap.ui.core.mvc.XMLView', visibility: 'hidden' },
/**
* If an XMLView instance is used to represent an HTML subtree of another XMLView,
* that subtree is provided with this setting.
*/
xmlNode : { type: 'Element', visibility: 'hidden' },
/**
* Configuration for the XMLView caching.
*/
cache : 'Object',
/**
* @deprecated because the 'Sequential' Mode is used by default and it's the only mode that will be supported
* in the next major release
*
* The processing mode of the XMLView.
*/
processingMode: { type: "sap.ui.core.mvc.XMLProcessingMode", visibility: "hidden" },
/**
* legacy-relevant:
*
* A map containing references to modules loaded via a 'core:require' statement
* in an XMLView.
*
* Only used for HTML embedded in an XMLView. This kind of HTML is processed synchronously only
* and needs access to 'core:require' modules from outside.
* Normally 'core:require' modules are NOT passed into nested Views and Fragments.
*
* The visibility is set to hidden because this is set only in internal code to propagate the
* 'core:require' context into the nested XMLView which is created for the HTML or SVG node and
* its sub-nodes. This isn't needed for nested Views/Fragments because 'core:require' context
* isn't propagated across View/Fragment borders.
*
* @deprecated since 1.120 because the support of HTML and SVG in XMLView is deprecated
*/
requireContext: { type: 'Object', visibility: "hidden" }
},
designtime: "sap/ui/core/designtime/mvc/XMLView.designtime"
},
renderer: XMLViewRenderer
});
/**
* Instantiates an XMLView of the given name and with the given ID.
*
* The <code>vView</code> can either be the name of the module that contains the view definition
* or it can be a configuration object with properties <code>viewName</code>, <code>viewContent</code>
* and a <code>controller</code> property (more properties are described in the parameters section below).
*
* If a <code>viewName</code> is given, it behaves the same as when <code>vView</code> is a string:
* the named resource will be loaded and parsed as XML. Alternatively, an already loaded view definition
* can be provided as <code>viewContent</code>, either as XML string or as an already parsed XML document.
* Exactly one of <code>viewName</code> and <code>viewContent</code> must be given, if none or both are given,
* an error will be reported. The <code>controller</code> property is optional and can hold a controller instance.
* When given, it overrides the controller class defined in the view definition.
*
* 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 processingMode. Even when
* the view definition is provided as string or XML Document, 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}.
*
* <strong>Note</strong>: If an XML document is given, it might be modified during view construction.
*
* <strong>Note</strong>: On root level, you can only define content for the default aggregation, e.g.
* without adding the <code><content></code> tag. If you want to specify content for another aggregation
* of a view like <code>dependents</code>, place it in a child control's dependents aggregation or add it by
* using {@link sap.ui.core.mvc.XMLView#addDependent}.
*
* <strong>Note</strong>: If you enable caching, you need to take care of the invalidation via keys. Automatic
* invalidation takes only place if the UI5 version or the component descriptor (manifest.json) change. This is
* still an experimental feature and may experience slight changes of the invalidation parameters or the cache
* key format.
*
* Like with any other control, <code>sId</code> is optional and an ID will be created automatically.
*
* @param {string} [sId] ID of the newly created view
* @param {string | object} vView Name of the view or a view configuration object as described above
* @param {string} [vView.viewName] Name of the view resource in module name notation (without suffix)
* @param {string|Document} [vView.viewContent] XML string or XML document that defines the view
* @param {boolean} [vView.async] whether the view source is loaded asynchronously
* @param {object} [vView.cache] Cache configuration, only for <code>async</code> views; caching gets active
* when this object is provided with vView.cache.keys array; keys are used to store data in the cache and for
* invalidation of the cache
* @param {Array<(string|Promise<string>)>} [vView.cache.keys] Array with strings or Promises resolving with strings
* @param {object} [vView.preprocessors] Preprocessors configuration, see {@link sap.ui.core.mvc.View}
* @param {sap.ui.core.mvc.Controller} [vView.controller] Controller instance to be used for this view
* @public
* @static
* @deprecated Since 1.56. Use {@link sap.ui.core.mvc.XMLView.create XMLView.create} to create view instances
* @returns {sap.ui.core.mvc.XMLView} the created XMLView instance
* @ui5-global-only
*/
sap.ui.xmlview = function(sId, vView) {
return sap.ui.view(sId, vView, ViewType.XML); // legacy-relevant
};
/**
* Instantiates an XMLView from the given configuration options.
*
* If a <code>viewName</code> is given, it must be a dot-separated name of an XML view resource (without
* the mandatory suffix ".view.xml"). The resource will be loaded asynchronously via the module system
* (preload caches might apply) and will be parsed as XML. Alternatively, an already loaded view <code>definition</code>
* can be provided, either as XML string or as an already parsed XML document. Exactly one of <code>viewName</code>
* or <code>definition</code> must be given, if none or both are given, an error will be reported.
*
* The <code>controller</code> property is optional and can hold a controller instance. When given, it overrides
* the controller class defined in the view definition.
*
* <strong>Note</strong>: On root level, you can only define content for the default aggregation, e.g. without
* adding the <code><content></code> tag. If you want to specify content for another aggregation of a view
* like <code>dependents</code>, place it in a child control's <code>dependents</code> aggregation or add it
* by using {@link sap.ui.core.mvc.XMLView#addDependent}.
*
* <strong>Note</strong>: If you enable caching, you need to take care of the invalidation via keys. Automatic
* invalidation takes only place if the UI5 version or the component descriptor (manifest.json) change. This is
* still an experimental feature and may experience slight changes of the invalidation parameters or the cache
* key format.
*
* @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] - Corresponds to an XML module that can be loaded via the module system
* (oOptions.viewName + suffix ".view.xml")
* @param {string|Document} [oOptions.definition] - XML string or XML document that defines the view.
* Exactly one of <code>viewName</code> or <code>definition</code> must be given.
* @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 one controller instance between multiple views is not possible.
* @param {object} [oOptions.cache] - Cache configuration; caching gets active when this object is provided
* with vView.cache.keys array; keys are used to store data in the cache and for invalidation
* of the cache.
* @param {Array<(string|Promise<string>)>} [oOptions.cache.keys] - Array with strings or Promises resolving with strings
* @param {object} [oOptions.preprocessors] Preprocessors configuration, see {@link sap.ui.core.mvc.View}
* <strong>Note</strong>: These preprocessors are only available to this instance.
* For global or on-demand availability use {@link sap.ui.core.mvc.XMLView.registerPreprocessor}.
* @public
* @since 1.56.0
* @static
* @returns {Promise<sap.ui.core.mvc.XMLView>} A Promise that resolves with the view instance or rejects with any thrown error.
*/
XMLView.create = function (oOptions) {
var mParameters = merge({}, oOptions);
// mapping renamed parameters
mParameters.viewContent = mParameters.definition;
// defaults for the async API
mParameters.async = true;
mParameters.type = ViewType.XML;
return View.create(mParameters);
};
/**
* 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
*/
XMLView._sType = ViewType.XML;
/**
* Flag for feature detection of asynchronous loading/rendering
* @public
* @readonly
* @type {boolean}
* @since 1.30
*/
XMLView.asyncSupport = true;
/**
* Flag indicating whether to use the cache
* @private
* @since 1.44
*/
XMLView._bUseCache = BaseConfig.get({
name: "sapUiXxViewCache",
type: BaseConfig.Type.Boolean,
defaultValue: true,
external: true
}) && Cache._isSupportedEnvironment();
function validatexContent(xContent) {
if (xContent.parseError.errorCode !== 0) {
var oParseError = xContent.parseError;
throw new Error(
"The following problem occurred: XML parse Error for " + oParseError.url +
" code: " + oParseError.errorCode +
" reason: " + oParseError.reason +
" src: " + oParseError.srcText +
" line: " + oParseError.line +
" linepos: " + oParseError.linepos +
" filepos: " + oParseError.filepos
);
}
}
function validateViewSettings(oView, mSettings) {
if (!mSettings) {
throw new Error("mSettings must be given");
} else 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) && mSettings.xmlNode) {
throw new Error("View name/content AND an XML node are given. There is no point in doing this, so please decide.");
} else if (!(mSettings.viewName || mSettings.viewContent) && !mSettings.xmlNode) {
throw new Error("Neither view name/content nor an XML node is given. One of them is required.");
} else if (mSettings.cache && !(mSettings.cache.keys && mSettings.cache.keys.length)) {
throw new Error("No cache keys provided. At least one is required.");
}
}
function getxContent(oView, mSettings) {
// 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
oView.mProperties["viewContent"] = mSettings.viewContent;
var xContent = XMLHelper.parse(mSettings.viewContent);
validatexContent(xContent);
return xContent.documentElement;
}
/**
* Sets the resource model to the given <code>oView</code>
*
* @param {sap.ui.core.mvc.XMLView} oView The view instance
* @param {map} mSettings The view settings
* @returns {undefined|Promise} will return a Promise if ResourceModel is instantiated asynchronously, otherwise undefined
*/
function setResourceModel(oView, mSettings) {
if ((oView._resourceBundleName || oView._resourceBundleUrl) && (!mSettings.models || !mSettings.models[oView._resourceBundleAlias])) {
var oModel = new ResourceModel({
bundleName: oView._resourceBundleName,
bundleUrl: oView._resourceBundleUrl,
bundleLocale: oView._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() {
oView.setModel(oModel, oView._resourceBundleAlias);
});
}
oView.setModel(oModel, oView._resourceBundleAlias);
}
}
/**
* Set the notifier for reacting to setAfterRendering
*
* @param {sap.ui.core.mvc.XMLView} oView The view itself
* @deprecated since 1.120 because the support of HTML and SVG tags is deprecated
*/
function setAfterRenderingNotifier(oView) {
// Delegate for after rendering notification before onAfterRendering of child controls
oView.oAfterRenderingNotifier = new XMLAfterRenderingNotifier();
oView.oAfterRenderingNotifier.addDelegate({
onAfterRendering: function() {
oView.onAfterRenderingBeforeChildren();
}
});
}
function getRootComponent(oSrcElement) {
var Component = sap.ui.require("sap/ui/core/Component"),
oComponent;
if (Component) {
while (oSrcElement) {
var oCandidateComponent = Component.getOwnerComponentFor(oSrcElement);
if (oCandidateComponent) {
oSrcElement = oComponent = oCandidateComponent;
} else {
if (oSrcElement instanceof Component) {
oComponent = oSrcElement;
}
oSrcElement = oSrcElement.getParent && oSrcElement.getParent();
}
}
}
return oComponent;
}
function getCacheInput(oView, mCacheSettings) {
var oRootComponent = getRootComponent(oView),
sManifest = oRootComponent ? JSON.stringify(oRootComponent.getManifest()) : null,
aFutureKeyParts = [];
aFutureKeyParts = aFutureKeyParts.concat(
getCacheKeyPrefixes(oView, oRootComponent),
getVersionInfo(), getCacheKeyProviders(oView),
mCacheSettings.keys
);
return validateCacheKey(oView, aFutureKeyParts).then(function(sKey) {
return {
key: sKey + "(" + hash(sManifest || "") + ")",
componentManifest: sManifest,
additionalData: mCacheSettings.additionalData
};
});
}
function isValidKey(sKey) {
return sKey;
}
function validateCacheKey(oView, aFutureKeyParts) {
return Promise.all(aFutureKeyParts).then(function(aKeys) {
aKeys = aKeys.filter(function(oElement) {
return oElement !== notCacheRelevant;
});
if (aKeys.every(isValidKey)) {
return aKeys.join('_');
} else {
var e = new Error("Provided cache keys may not be empty or undefined.");
e.name = sXMLViewCacheError;
return Promise.reject(e);
}
});
}
function getCacheKeyPrefixes(oView, oRootComponent) {
var sComponentName = oRootComponent && oRootComponent.getMetadata().getName();
return [
sComponentName || window.location.host + window.location.pathname,
oView.getId(),
Localization.getLanguageTag().toString()
].concat(oRootComponent && oRootComponent.getActiveTerminologies() || []);
}
function getCacheKeyProviders(oView) {
var mPreprocessors = oView.getPreprocessors(),
oPreprocessorInfo = oView.getPreprocessorInfo(/*bSync =*/false),
aFutureCacheKeys = [];
function pushFutureKey(o) {
aFutureCacheKeys.push(o.preprocessor
.then(function(oPreprocessorImpl) {
if (oPreprocessorImpl.getCacheKey) {
return oPreprocessorImpl.getCacheKey(oPreprocessorInfo);
} else {
/* We cannot check for the getCacheKey function synchronous, but we later need
* to differentiate whether the result of getCacheKey returns an invalid result
* (null/undefined) or the function simply does not exist.
* Therefore we use the 'notCacheRelevant' token to mark preProcessors that does
* not provide a getCacheKey function and so are not relevant for caching.
* See validateCacheKey function.
*/
return notCacheRelevant;
}
})
);
}
for (var sType in mPreprocessors) {
mPreprocessors[sType].forEach(pushFutureKey);
}
return aFutureCacheKeys;
}
function getVersionInfo() {
return VersionInfo.load().then(function(oInfo) {
var sTimestamp = "";
if (!oInfo.libraries) {
sTimestamp = Core.buildinfo.buildtime;
} else {
oInfo.libraries.forEach(function(oLibrary) {
sTimestamp += oLibrary.buildTimestamp;
});
}
return sTimestamp;
}).catch(function(error) {
// Do not populate the cache if the version info could not be retrieved.
Log.warning("version info could not be retrieved", "sap.ui.core.mvc.XMLView");
Log.debug(error);
return "";
});
}
function writeCache(mCacheInput, xContent) {
// we don't want to write the key into the cache
var sKey = mCacheInput.key;
delete mCacheInput.key;
var vAdditionalData = mCacheInput.additionalData;
mCacheInput.xml = XMLHelper.serialize(xContent);
if (vAdditionalData && vAdditionalData.setAdditionalCacheData && vAdditionalData.getAdditionalCacheData) {
mCacheInput.additionalData = vAdditionalData.getAdditionalCacheData();
}
return Cache.set(sKey, mCacheInput);
}
function readCache(mCacheInput) {
return Cache.get(mCacheInput.key).then(function(mCacheOutput) {
// double check manifest to eliminate issues with hash collisions
if (mCacheOutput && mCacheOutput.componentManifest == mCacheInput.componentManifest) {
mCacheOutput.xml = XMLHelper.parse(mCacheOutput.xml, "application/xml").documentElement;
if (mCacheOutput.additionalData) {
var vAdditionalData = mCacheInput.additionalData;
if (vAdditionalData && vAdditionalData.setAdditionalCacheData && vAdditionalData.getAdditionalCacheData) {
vAdditionalData.setAdditionalCacheData(mCacheOutput.additionalData);
} else {
// extend the additionalData which was passed into cache configuration dynamically
/**
* @deprecated
*/
Log.error("Deprecated: Don't use an object reference for caching additional Data! Use a CacheDataProvider instead!");
/**
* @deprecated
*/
merge(mCacheInput.additionalData, mCacheOutput.additionalData);
}
}
return mCacheOutput;
}
});
}
/**
* This function initialized the view settings.
*
* @param {object} mSettings with view settings
* @returns {Promise|null} will be returned if running in async mode
* @ui5-transform-hint replace-param mSettings.async true
*/
XMLView.prototype.initViewSettings = function(mSettings) {
var that = this, _xContent;
function processView(xContent) {
that._xContent = xContent;
/** @deprecated since 1.120.0 */
if (View._supportInfo) {
View._supportInfo({context: that._xContent, env: {caller:"view", viewinfo: merge({}, that), settings: merge({}, mSettings || {}), type: "xmlview"}});
}
// extract the properties of the view from the XML element
if (!that.isSubView()) {
// extract the internal settings from the XML and set on the view. The standard properties, event
// handler, aggregation and association will be extracted during parsing the content and applied to the
// view instance by calling "applySettings"
XMLTemplateProcessor.parseViewAttributes(xContent, that);
} else {
// when used as fragment: prevent connection to controller, only top level XMLView must connect
delete mSettings.controller;
}
/**
* @ui5-transform-hint replace-local false
*/
const bSupportHTMLAndSVG = true;
// vSetResourceModel is a promise if ResourceModel is created async
var vSetResourceModel = setResourceModel(that, mSettings);
if (vSetResourceModel instanceof Promise) {
if (bSupportHTMLAndSVG) {
return vSetResourceModel.then(function() {
setAfterRenderingNotifier(that);
});
} else {
return vSetResourceModel;
}
}
if (bSupportHTMLAndSVG) {
setAfterRenderingNotifier(that);
}
}
function runViewxmlPreprocessor(xContent, bAsync) {
if (that.hasPreprocessor("viewxml")) {
// for the viewxml preprocessor fully qualified ids are provided on the xml source
return XMLTemplateProcessor.enrichTemplateIdsPromise(xContent, that, bAsync).then(function() {
return that.runPreprocessor("viewxml", xContent, !bAsync);
});
}
return xContent;
}
function runPreprocessorsAsync(xContent) {
var fnDone = Interaction.notifyAsyncStep("VIEW PREPROCESSING");
return that.runPreprocessor("xml", xContent).then(function(xContent) {
return runViewxmlPreprocessor(xContent, /*bAsync=*/true);
})
.finally(fnDone);
}
function loadResourceAsync(sResourceName) {
return LoaderExtensions.loadResource(sResourceName, {async: true}).then(function(oData) {
return oData.documentElement; // result is the document node
});
}
function processResource(sResourceName, mCacheInput) {
return loadResourceAsync(sResourceName).then(runPreprocessorsAsync).then(function(xContent) {
if (mCacheInput) {
writeCache(mCacheInput, xContent);
}
return xContent;
});
}
function processCache(sResourceName, mCacheSettings) {
return getCacheInput(that, mCacheSettings).then(function(mCacheInput) {
return readCache(mCacheInput).then(function(mCacheOutput) {
if (!mCacheOutput) {
return processResource(sResourceName, mCacheInput);
} else {
return mCacheOutput.xml;
}
});
}).catch(function(error) {
if (error.name === sXMLViewCacheError) {
// no sufficient cache keys, processing can continue
Log.error(error.message, error.name, "sap.ui.core.mvc.XMLView");
Log.error("Processing the View without caching.", "sap.ui.core.mvc.XMLView");
return processResource(sResourceName);
} else {
// an unknown error occured and should be exposed
return Promise.reject(error);
}
});
}
this._oContainingView = mSettings.containingView || this;
/**
* @deprecated because the 'Sequential' Mode is used by default and it's the only mode that will be supported
* in the next major release
*/
this._sProcessingMode = mSettings.processingMode;
if (this.oAsyncState) {
// suppress rendering of preserve content
this.oAsyncState.suppressPreserve = true;
}
validateViewSettings(this, mSettings);
// either template name or XML node is given
if (mSettings.viewName) {
var sResourceName = mSettings.viewName.replace(/\./g, "/") + ".view.xml";
if (mSettings.async) {
// in async mode we need to return here as processing takes place in Promise callbacks
if (mSettings.cache && XMLView._bUseCache) {
return processCache(sResourceName, mSettings.cache).then(processView);
} else {
return loadResourceAsync(sResourceName).then(runPreprocessorsAsync).then(processView);
}
} else {
_xContent = LoaderExtensions.loadResource(sResourceName).documentElement;
}
} else if (mSettings.viewContent) {
if (mSettings.viewContent.nodeType === window.Node.DOCUMENT_NODE) { // Check for XML Document
_xContent = mSettings.viewContent.documentElement;
} else {
_xContent = getxContent(this, mSettings);
}
} else if (mSettings.xmlNode) {
_xContent = mSettings.xmlNode;
}
if (mSettings.async) {
// a normal Promise:
return runPreprocessorsAsync(_xContent).then(processView);
} else {
// a SyncPromise
_xContent = this.runPreprocessor("xml", _xContent, true);
_xContent = runViewxmlPreprocessor(_xContent, false);
// if the _xContent is a SyncPromise we have to extract the _xContent
// and make sure we throw any occurring errors further
if (_xContent && typeof _xContent.getResult === 'function') {
if (_xContent.isRejected()) {
// sync promises store the error within the result if they are rejected
throw _xContent.getResult();
}
_xContent = _xContent.getResult();
}
processView(_xContent);
}
};
XMLView.prototype.onBeforeRendering = function() {
// make sure to preserve the content if not preserved yet
var oDomRef = this.getDomRef();
if (oDomRef && !RenderManager.isPreservedContent(oDomRef)) {
RenderManager.preserveContent(oDomRef, /* bPreserveRoot= */ true);
}
View.prototype.onBeforeRendering.apply(this, arguments);
};
XMLView.prototype.exit = function() {
if (this.oAfterRenderingNotifier) {
this.oAfterRenderingNotifier.destroy();
}
View.prototype.exit.apply(this, arguments);
};
XMLView.prototype.onControllerConnected = function(oController, mSettings) {
var that = this;
// unset any preprocessors (e.g. from an enclosing JSON view)
// create a function, which scopes the instance creation of a class with the corresponding owner ID
// XMLView special logic for asynchronous template parsing, when component loading is async but
// instance creation is sync.
function fnRunWithPreprocessor(fn) {
return runWithPreprocessors(fn, {
settings: that._fnSettingsPreprocessor
});
}
/**
* @ui5-transform-hint replace-local false
*/
const bSync = !this.oAsyncState;
if (bSync) {
this._aParsedContent = fnRunWithPreprocessor(XMLTemplateProcessor.parseTemplate.bind(null, this._xContent, this, mSettings));
} else {
// parse the XML tree
var fnDone = Interaction.notifyAsyncStep("VIEW PROCESSING");
return XMLTemplateProcessor.parseTemplatePromise(this._xContent, this, true, {
fnRunWithPreprocessor: fnRunWithPreprocessor
}).then(function(aParsedContent) {
that._aParsedContent = aParsedContent;
// allow rendering of preserve content
delete that.oAsyncState.suppressPreserve;
}).finally(fnDone);
}
};
XMLView.prototype.getControllerName = function() {
if (this._controllerModuleName) {
Log.error(`Controller name is specified using module syntax: '${this._controllerModule}'. Use #getControllerModuleName() instead.`);
return undefined;
}
return this._controllerName;
};
XMLView.prototype._getControllerName = function() {
return this._controllerName;
};
XMLView.prototype.getControllerModuleName = function() {
if (typeof this._controllerName === "string") {
return this._controllerName.replace(/\./g, "/") + ".controller";
}
return typeof this._controllerModuleName === "string" ? this._controllerModuleName.substring("module:".length) : "";
};
XMLView.prototype._getControllerModuleName = function() {
return this._controllerModuleName;
};
XMLView.prototype.isSubView = function() {
return this._oContainingView != this;
};
/**
* If the HTML doesn't contain own content, it tries to reproduce existing content
* This is executed before the onAfterRendering of the child controls, to ensure that
* the HTML is already at its final position, before additional operations are executed.
*
* @deprecated since 1.120 because the support of HTML and SVG tags is deprecated
*/
XMLView.prototype.onAfterRenderingBeforeChildren = function() {
if ( this._$oldContent.length !== 0 ) {
// Log.debug("after rendering for " + this);
// move DOM of children into correct place in preserved DOM
var aChildren = this.getAggregation("content");
if ( aChildren ) {
for (var i = 0; i < aChildren.length; i++) {
// Get current DOM of the child or the invisible placeholder for it.
// For children that do DOM preservation on their own, use the temporary DOM,
// they'll move their old DOM themselves
var oNewChildDOM =
document.getElementById(RenderPrefixes.Temporary + aChildren[i].getId())
|| aChildren[i].getDomRef()
|| document.getElementById(RenderPrefixes.Invisible + aChildren[i].getId());
// if such DOM exists, replace the placeholder in the view's DOM with it
if ( oNewChildDOM ) {
jQuery(document.getElementById(RenderPrefixes.Dummy + aChildren[i].getId())).replaceWith(oNewChildDOM);
} // otherwise keep the dummy placeholder
}
}
// move preserved DOM into place
// Log.debug("moving preserved dom into place for " + this);
jQuery(document.getElementById(RenderPrefixes.Temporary + this.getId())).replaceWith(this._$oldContent);
}
this._$oldContent = undefined;
};
XMLView.prototype._onChildRerenderedEmpty = function(oControl, oElement) {
// when the render manager notifies us about an empty child rendering, we replace the old DOM with a dummy
jQuery(oElement).replaceWith('<div id="' + RenderPrefixes.Dummy + oControl.getId() + '" class="sapUiHidden"></div>');
return true; // indicates that we have taken care
};
/**
* Register a preprocessor for all views of a specific type.
*
* The preprocessor can be registered for several stages of view initialization, for xml views these are
* either the plain "xml" or the already initialized "controls" , see {@link sap.ui.core.mvc.XMLView.PreprocessorType}.
* For each type one preprocessor is executed. If there is a preprocessor passed to or activated at the
* view instance already, that one is used. When several preprocessors are registered for one hook, it has to be made
* sure, that they do not conflict when being processed serially.
*
* It can be either a module name as string of an implementation of {@link sap.ui.core.mvc.View.Preprocessor} or a
* function with a signature according to {@link sap.ui.core.mvc.View.Preprocessor.process}.
*
* <strong>Note</strong>: Preprocessors work only in async views and will be ignored when the view is instantiated
* in sync mode by default, as this could have unexpected side effects. You may override this behaviour by setting the
* bSyncSupport flag to true.
*
* @public
* @since 1.30
* @static
* @param {string|sap.ui.core.mvc.XMLView.PreprocessorType} sType
* the type of content to be processed
* @param {string|function(Object, sap.ui.core.mvc.View.Preprocessor.ViewInfo, object)} vPreprocessor
* module path of the preprocessor implementation or a preprocessor function
* @param {string} [sViewType="XML"]
* Since 1.89, added for signature compatibility with {@link sap.ui.core.mvc.View#registerPreprocessor
* View#registerPreprocessor}. Only supported value is "XML".
* @param {boolean} bSyncSupport
* Deprecated as of version 1.145, because this parameter is only applicable to sync views and is no longer used.
* Declares if the vPreprocessor ensures safe sync processing. This means the preprocessor will be executed
* also for sync views. Please be aware that any kind of async processing (like Promises, XHR, etc) may
* break the view initialization and lead to unexpected results.
* @param {boolean} [bOnDemand]
* ondemand preprocessor which enables developers to quickly activate the preprocessor for a view,
* by setting <code>preprocessors : { xml }</code>, for example.
* @param {object} [mSettings]
* optional configuration for preprocessor
*/
XMLView.registerPreprocessor = function(sType, vPreprocessor, sViewType, bSyncSupport, bOnDemand, mSettings) {
var sOwnViewType = this.getMetadata().getClass()._sType;
if (typeof sViewType === "string") {
if (sViewType !== sOwnViewType) {
throw new TypeError("View types other than " + sOwnViewType
+ " are not supported by XMLView.registerPreprocessor,"
+ " check View.registerPreprocessor instead");
}
} else {
mSettings = bOnDemand;
bOnDemand = bSyncSupport;
bSyncSupport = sViewType;
}
sType = sType.toUpperCase();
if (XMLView.PreprocessorType[sType]) {
View.registerPreprocessor(XMLView.PreprocessorType[sType], vPreprocessor, sOwnViewType, bSyncSupport, bOnDemand, mSettings);
} else {
future.errorThrows(`${this.getMetadata().getName()}: Preprocessor could not be registered due to unknown sType "${sType}"`);
}
};
/**
* Specifies the available preprocessor types for XMLViews
*
* @see sap.ui.core.mvc.XMLView
* @see sap.ui.core.mvc.View.Preprocessor
* @enum {string}
* @since 1.34
* @public
*/
XMLView.PreprocessorType = {
/**
* This preprocessor receives the plain xml source of the view and should also return a valid
* xml ready for view creation
* @public
*/
XML : "xml",
/**
* This preprocessor receives a valid xml source for View creation without any template tags but with control
* declarations. These include their full IDs by which they can also be queried during runtime.
* @public
*/
VIEWXML : "viewxml",
/**
* This preprocessor receives the control tree produced through the view source
* @public
*/
CONTROLS : "controls"
};
// Register OpenUI5 default preprocessor for templating
XMLView.registerPreprocessor("xml", "sap.ui.core.util.XMLPreprocessor", true, true);
return XMLView;
});