UNPKG

@openui5/sap.ui.core

Version:

OpenUI5 Core Library sap.ui.core

204 lines (188 loc) 8.13 kB
/*! * OpenUI5 * (c) Copyright 2026 SAP SE or an SAP affiliate company. * Licensed under the Apache License, Version 2.0 - see LICENSE.txt. */ // Provides default renderer for XMLView sap.ui.define([ './ViewRenderer', '../RenderManager', "sap/ui/thirdparty/jquery" ], function(ViewRenderer, RenderManager, jQuery) { "use strict"; // shortcut var PREFIX_DUMMY = RenderManager.RenderPrefixes.Dummy, PREFIX_INVISIBLE = RenderManager.RenderPrefixes.Invisible, PREFIX_TEMPORARY = RenderManager.RenderPrefixes.Temporary; /** * Renderer for an XMLView. * * XMLViews implement <i>DOM preservation</i>. Any DOM that is not created by rendering a UI5 control * will be preserved (re-used) during re-rendering of the XMLView. Child UI5 controls will be re-rendered * as usual, their old DOM will be replaced with newly rendered DOM. So the only preserved parts are the * native HTML or SVG parts in an XMLView. * * <h3>Initial Rendering</h3> * * The XMLView parses its XML representation into a sequence of strings and controls, where the strings * represent any static HTML/SVG. The individual strings in the sequence are not well-formed HTML/SVG but usually * only represent a prefix or postfix of a bigger DOM tree. * * During string based rendering, the sequence is rendered into the RenderManager's buffer step by step. * Strings are rendered 1:1 whereas controls are rendered by {@link sap.ui.core.RenderManager#renderControl RenderManager#renderControl}. * The output is wrapped with an additional &lt;div&gt; element which is marked as 'to-be-preserved' by adding * the <code>data-sap-ui-preserve</code> attribute. * * The resulting string is converted to a tree of DOM elements as usual and injected into the desired location. * * <b>Note:</b> The support of using HTML and SVG tags in XML Views is deprecated since version 1.120. There * will be no preserved content anymore without HTML and SVG tags. * * <h3>Re-rendering</h3> * Before the DOM of any UI5 control is removed from the page, it will be scanned for 'to-be-preserved' subtrees. * If any are found, they are moved to the <code>sap-ui-preserve</code> area for later re-use. Because of the marker * attribute, this is also done for the complete DOM of an XMLView. * * If such an XMLView is (string-)rendered again, it will not render the parsed fragment sequence as in the initial * rendering. Instead, in a first step it only renders a dummy &lt;div&gt; and all its child controls. Before a child * control is (string-)rendered, any old DOM for the child (which might exist in the preserved DOM of the XMLView) * is replaced by a dummy placeholder. That placeholder identifies the location in the preserved DOM where the newly * rendered DOM for the child must be injected. If a child control was or is invisible, the invisible placeholders * must be taken into account the same way as normal DOM. * * In the onAfterRendering phase, the newly rendered DOM for all the children is injected into the preserved DOM * of the XMLView by replacing the dummy placeholders with the new DOM. Here as well, newly rendered invisible * placeholders must be treated the same way as normal DOM. Finally, the preserved DOM replaces the newly rendered * dummy wrapper for the XMLView. * * @namespace * @alias sap.ui.core.mvc.XMLViewRenderer * @private */ var XMLViewRenderer = { apiVersion: 2 }; /** * Renders the HTML for the given control, using the provided {@link sap.ui.core.RenderManager}. * * @param {sap.ui.core.RenderManager} rm the RenderManager that can be used for writing to the Render-Output-Buffer * @param {sap.ui.core.mvc.XMLView} oControl an object representation of the control that should be rendered */ XMLViewRenderer.render = function(rm, oControl) { /** * Create the root open tag. * * @param {boolean} bPreserve Whether the DOM should be preserved * @ui5-transform-hint replace-param bPreserve false */ function writeRootOpenTag(bPreserve) { rm.openStart("div", oControl); rm.class("sapUiView"); rm.class("sapUiXMLView"); ViewRenderer.addDisplayClass(rm, oControl); if (bPreserve) { rm.attr("data-sap-ui-preserve", oControl.getId()); } rm.style("width", oControl.getWidth()); rm.style("height", oControl.getHeight()); rm.openEnd(); } function writeRootCloseTag() { rm.close("div"); } // write the HTML into the render manager var aParsedContent = oControl._aParsedContent, i; if (oControl.isBound("content")) { writeRootOpenTag(); var aContent = oControl.getContent(); for (i = 0; i < aContent.length; i++) { rm.renderControl(aContent[i]); } writeRootCloseTag(); } else { /** * Because HTML and SVG support is deprecated, this line of code can also be deprecated * @deprecated since 1.120 */ oControl._$oldContent = RenderManager.findPreservedContent(oControl.getId()); /** * @ui5-transform-hint replace-local true */ const bNoPreserveContent = (oControl._$oldContent.length === 0); if (bNoPreserveContent) { // Log.debug("rendering " + oControl + " anew"); var bSubView = oControl.isSubView(); if (!bSubView) { /** * @ui5-transform-hint replace-local false */ const bUsePreserveParam = true; if (bUsePreserveParam) { // do not preserve when rendering initially in async mode writeRootOpenTag(!oControl.oAsyncState || !oControl.oAsyncState.suppressPreserve /* bPreserve */); } else { writeRootOpenTag(); } } if (aParsedContent) { for (i = 0; i < aParsedContent.length; i++) { var vRmInfo = aParsedContent[i]; /** * @ui5-transform-hint replace-local false */ const bRenderManagerAPICall = Array.isArray(vRmInfo); // apply RenderManagerAPI calls which might have been recorded during XML processing for all encountered HTML elements in an XMLView if (bRenderManagerAPICall) { rm[vRmInfo[0]].apply(rm, vRmInfo[1]); } else if (!vRmInfo._isExtensionPoint) { // XMLView ExtensionPoint placeholder // we need to ignore these placeholders during rendering, they will be resolved asynchronously later by the flexibility provider // plain UI5 Control rm.renderControl(vRmInfo); /** * @deprecated because it's not needed anymore after the HTML and SVG support is deprecated * * when the child control did not render anything, we add a placeholder to know where to render the child later */ if ( !vRmInfo.bOutput ) { rm.openStart("div", PREFIX_DUMMY + vRmInfo.getId()); rm.class("sapUiHidden"); rm.openEnd(); rm.close("div"); } } } } if (!bSubView) { writeRootCloseTag(); } } else { // render dummy control for early after rendering notification rm.renderControl(oControl.oAfterRenderingNotifier); // preserve mode: render a temporary element and all child controls rm.openStart("div", PREFIX_TEMPORARY + oControl.getId()); rm.class("sapUiHidden"); rm.openEnd(); for (i = 0; i < aParsedContent.length; i++) { var vFragment = aParsedContent[i]; // if the parsed content does not have a corresponding _renderManagerAPICall, it's a control if (!Array.isArray(vFragment) && !vFragment._isExtensionPoint) { // render DOM string for child control rm.renderControl(vFragment); // replace any old DOM (or invisible placeholder) for a child control with a dummy placeholder var sFragmentId = vFragment.getId(), $fragment = jQuery(document.getElementById(sFragmentId)); if ($fragment.length == 0) { $fragment = jQuery(document.getElementById(PREFIX_INVISIBLE + sFragmentId)); } if ( !RenderManager.isPreservedContent($fragment[0]) ) { $fragment.replaceWith('<div id="' + PREFIX_DUMMY + sFragmentId + '" class="sapUiHidden"></div>'); } } } rm.close("div"); } } }; return XMLViewRenderer; }, /* bExport= */ true);