UNPKG

@openui5/sap.m

Version:

OpenUI5 UI Library sap.m

940 lines (769 loc) 26.6 kB
/*! * OpenUI5 * (c) Copyright 2026 SAP SE or an SAP affiliate company. * Licensed under the Apache License, Version 2.0 - see LICENSE.txt. */ sap.ui.define([ 'sap/m/semantic/SegmentedContainer', 'sap/m/semantic/SemanticConfiguration', 'sap/m/Button', 'sap/m/Title', 'sap/m/Page', 'sap/m/OverflowToolbar', 'sap/m/ToolbarSpacer', 'sap/m/Bar', 'sap/ui/core/CustomData', 'sap/ui/base/ManagedObject', 'sap/m/PageAccessibleLandmarkInfo', 'sap/ui/base/ManagedObjectObserver', 'sap/ui/core/Control', "sap/ui/core/Lib", 'sap/ui/core/library', "sap/ui/core/InvisibleText", 'sap/m/library', "./SemanticPageRenderer", "sap/base/Log", "sap/ui/thirdparty/jquery" ], function( SegmentedContainer, SemanticConfiguration, Button, Title, Page, OverflowToolbar, ToolbarSpacer, Bar, CustomData, ManagedObject, PageAccessibleLandmarkInfo, ManagedObjectObserver, Control, Library, coreLibrary, InvisibleText, library, SemanticPageRenderer, Log, jQuery ) { "use strict"; // shortcut for sap.m.ButtonType var ButtonType = library.ButtonType; // shortcut for sap.m.PageBackgroundDesign var PageBackgroundDesign = library.PageBackgroundDesign; // shortcut for sap.m.semantic.SemanticRuleSetType var SemanticRuleSetType = library.semantic.SemanticRuleSetType; // shortcut for sap.ui.core.TitleLevel var TitleLevel = coreLibrary.TitleLevel; /** * Constructor for a new <code>SemanticPage</code>. * @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 * An enhanced {@link sap.m.Page}, that can contain controls with semantic meaning, * see {@link sap.m.semantic.SemanticControl}. * * <b>Note:</b> This control implements the SAP Fiori 1.0 design guidelines. * For SAP Fiori 2.0, see the {@link sap.f.semantic.SemanticPage}. * * <h3>Overview</h3> * * The main functionality of the <code>SemanticPage</code> is to predefine the placement, * behavior and styles of the page elements. * * Content specified in the semantic aggregations will be automatically positioned in * dedicated sections of the footer or the header of the page. * * <h3>Structure</h3> * * The semantics of the content are the following: * <ul> * <li>Visual properties (for example, <code>AddAction</code> will be styled as an icon button)</li> * <li>Position in the page (UX guidelines specify that some buttons should be in the header only, * while others are in the footer or the "share" menu, so we do the correct positioning)</li> * <li>Sequence order (UX guidelines define a specific sequence order of semantic controls with * respect to each other)</li> * <li>Default localized tooltip for icon-only buttons</li> * <li>Overflow behavior (UX guidelines define which buttons are allowed to go to the overflow of * the toolbar when the screen gets narrower). For icon buttons, we ensure that the text label of * the button appears when the button is in overflow, as specified by UX.</li> * <li>Screen reader support (invisible text for reading the semantic type)</li> * </ul> * * In addition to the predefined semantic controls, the <code>SemanticPage</code> can host also * custom app controls. It preserves most of the API of the {@link sap.m.Page} for specifying page content. * * <h3>Usage</h3> * * The app developer only has to specify the action type, and the required styling and * positioning are automatically added. * * @see {@link topic:4a97a07ec8f5441d901994d82eaab1f5 Semantic Page} * @see {@link topic:84f3d52f492648d5b594e4f45dca7727 Semantic Pages} * * @extends sap.ui.core.Control * @abstract * * @author SAP SE * @version 1.146.0 * * @constructor * @public * @since 1.30.0 * @alias sap.m.semantic.SemanticPage */ var SemanticPage = Control.extend("sap.m.semantic.SemanticPage", /** @lends sap.m.semantic.SemanticPage.prototype */ { metadata: { library: "sap.m", properties: { /** * See {@link sap.m.Page#title} */ title: { type: "string", group: "Misc", defaultValue: null }, /** * See {@link sap.m.Page#titleLevel} */ titleLevel: { type: "sap.ui.core.TitleLevel", group: "Appearance", defaultValue: TitleLevel.Auto }, /** * See {@link sap.m.Page#showNavButton} */ showNavButton: { type: "boolean", group: "Appearance", defaultValue: false }, /** * See {@link sap.m.Page#showSubHeader} */ showSubHeader: { type: "boolean", group: "Appearance", defaultValue: true }, /** * See {@link sap.m.Page#enableScrolling} */ enableScrolling: { type: "boolean", group: "Behavior", defaultValue: true }, /** * Hides or shows the page footer */ showFooter: { type: "boolean", group: "Appearance", defaultValue: true }, /** * Determines whether the floating footer behavior is enabled. * If set to <code>true</code>, the content is visible when it's underneath the footer. * @since 1.40.1 */ floatingFooter: { type: "boolean", group:"Appearance", defaultValue: false }, /** * Declares the type of semantic ruleset that will govern the styling and positioning of semantic content. * @since 1.44 */ semanticRuleSet: { type: "sap.m.semantic.SemanticRuleSetType", group: "Misc", defaultValue: SemanticRuleSetType.Classic }, /** * Determines the backgound color of the page. For more * information, see {@link sap.m.Page#backgroundDesign}. * @since 1.52 */ backgroundDesign: { type: "sap.m.PageBackgroundDesign", group: "Appearance", defaultValue: PageBackgroundDesign.Standard } }, defaultAggregation: "content", aggregations: { /** * See {@link sap.m.Page#subHeader} */ subHeader: { type: "sap.m.IBar", multiple: false }, /** * See {@link sap.m.Page#content} */ content: { type: "sap.ui.core.Control", multiple: true, singularName: "content", forwarding: { getter: "_getPage", aggregation: "content" } }, /** * Custom header buttons */ customHeaderContent: { type: "sap.m.Button", multiple: true, singularName: "customHeaderContent" }, /** * Custom footer buttons */ customFooterContent: { type: "sap.m.Button", multiple: true, singularName: "customFooterContent" }, /** * Accessible landmark settings to be applied to the containers of the <code>sap.m.Page</code> control. * * If not set, no landmarks will be written. */ landmarkInfo : {type : "sap.m.PageAccessibleLandmarkInfo", multiple : false, forwarding: {getter: "_getPage", aggregation: "landmarkInfo"}}, /** * Wrapped instance of {@link sap.m.Page} */ _page: { type: "sap.m.Page", multiple: false, visibility: "hidden" } }, events: { /** * See {@link sap.m.Page#navButtonPress} */ navButtonPress: {} }, dnd: { draggable: false, droppable: true }, designtime: "sap/m/designtime/semantic/SemanticPage.designtime" }, renderer: SemanticPageRenderer }); // Static members SemanticPage._getResourceBundle = function () { return Library.getResourceBundleFor("sap.m"); }; SemanticPage.ARIA = { TOOLBAR_HEADER_ACTIONS: SemanticPage._getResourceBundle().getText('ARIA_LABEL_TOOLBAR_HEADER_ACTIONS'), TOOLBAR_FOOTER_ACTIONS: SemanticPage._getResourceBundle().getText('ARIA_LABEL_TOOLBAR_FOOTER_ACTIONS') }; // Lifecycle methods SemanticPage.prototype.init = function () { this._aCachedInvisibleTexts = []; this._oHeaderObserver = new ManagedObjectObserver(SemanticPage.prototype._updateHeaderVisibility.bind(this)); this._currentMode = SemanticConfiguration._PageMode.display; this._getPage().setCustomHeader(this._getInternalHeader()); this._getPage().setFooter(this._getInternalOverflowToolbar()); this.setLandmarkInfo(new PageAccessibleLandmarkInfo()); this._getPage().setShowHeader(false); }; /** * Function is called when exiting the control. * * @private */ SemanticPage.prototype.exit = function () { if (this._oInternalHeader) { this._oInternalHeader.destroy(); this._oInternalHeader = null; } if (this._oWrappedFooter) { this._oWrappedFooter.destroy(); this._oWrappedFooter = null; } if (this._oTitle) { this._oTitle.destroy(); this._oTitle = null; } if (this._oNavButton) { this._oNavButton.destroy(); this._oNavButton = null; } if ( this._oHeaderObserver ) { this._oHeaderObserver.disconnect(); this._oHeaderObserver = null; } this._destroyInvisibleTexts(); this._oPositionsMap = null; }; SemanticPage.prototype.setSubHeader = function (oSubHeader, bSuppressInvalidate) { this._getPage().setSubHeader(oSubHeader, bSuppressInvalidate); return this; }; SemanticPage.prototype.getSubHeader = function () { return this._getPage().getSubHeader(); }; SemanticPage.prototype.destroySubHeader = function (bSuppressInvalidate) { this._getPage().destroySubHeader(bSuppressInvalidate); return this; }; SemanticPage.prototype.getShowSubHeader = function () { return this._getPage().getShowSubHeader(); }; SemanticPage.prototype.setShowSubHeader = function (bShowSubHeader, bSuppressInvalidate) { this._getPage().setShowSubHeader(bShowSubHeader, bSuppressInvalidate); this.setProperty("showSubHeader", bShowSubHeader, true); return this; }; SemanticPage.prototype.getShowFooter = function () { return this._getPage().getShowFooter(); }; SemanticPage.prototype.setShowFooter = function (bShowFooter, bSuppressInvalidate) { this._getPage().setShowFooter(bShowFooter, bSuppressInvalidate); this.setProperty("showFooter", bShowFooter, true); return this; }; SemanticPage.prototype.setFloatingFooter = function (bFloatingFooter, bSuppressInvalidate) { this._getPage().setFloatingFooter(bFloatingFooter, bSuppressInvalidate); this.setProperty("floatingFooter", bFloatingFooter, true); return this; }; SemanticPage.prototype.setTitle = function (sTitle) { var oTitle = this._getTitle(); if (oTitle) { oTitle.setText(sTitle); if (!oTitle.getParent()) { this._getInternalHeader().addContentMiddle(oTitle); } } this.setProperty("title", sTitle, true); return this; }; SemanticPage.prototype.setTitleLevel = function (sTitleLevel) { this.setProperty("titleLevel", sTitleLevel, true); this._getTitle().setLevel(sTitleLevel); return this; }; SemanticPage.prototype.setShowNavButton = function (bShow) { var oButton = this._getNavButton(); if (oButton) { oButton.setVisible(bShow); if (!oButton.getParent()) { this._getInternalHeader().addContentLeft(oButton); } } this.setProperty("showNavButton", bShow, true); return this; }; SemanticPage.prototype.setEnableScrolling = function (bEnable) { this._getPage().setEnableScrolling(bEnable); this.setProperty("enableScrolling", bEnable, true); return this; }; SemanticPage.prototype.setBackgroundDesign = function (sBgDesign) { this.setProperty("backgroundDesign", sBgDesign, true); this._getPage().setBackgroundDesign(sBgDesign); return this; }; /* FOOTER RIGHT (CUSTOM CONTENT) */ SemanticPage.prototype.getCustomFooterContent = function () { return this._getSegmentedFooter().getSection("customRight").getContent(); }; SemanticPage.prototype.addCustomFooterContent = function (oControl, bSuppressInvalidate) { this._getSegmentedFooter().getSection("customRight").addContent(oControl, bSuppressInvalidate); return this; }; SemanticPage.prototype.indexOfCustomFooterContent = function (oControl) { return this._getSegmentedFooter().getSection("customRight").indexOfContent(oControl); }; SemanticPage.prototype.insertCustomFooterContent = function (oControl, iIndex, bSuppressInvalidate) { this._getSegmentedFooter().getSection("customRight").insertContent(oControl, iIndex, bSuppressInvalidate); return this; }; SemanticPage.prototype.removeCustomFooterContent = function (oControl, bSuppressInvalidate) { return this._getSegmentedFooter().getSection("customRight").removeContent(oControl, bSuppressInvalidate); }; SemanticPage.prototype.removeAllCustomFooterContent = function (bSuppressInvalidate) { return this._getSegmentedFooter().getSection("customRight").removeAllContent(bSuppressInvalidate); }; SemanticPage.prototype.destroyCustomFooterContent = function (bSuppressInvalidate) { var aChildren = this.getCustomFooterContent(); if (!aChildren) { return this; } // set suppress invalidate flag if (bSuppressInvalidate) { this.iSuppressInvalidate++; } this._getSegmentedFooter().getSection("customRight").destroy(bSuppressInvalidate); if (!this.isInvalidateSuppressed()) { this.invalidate(); } // reset suppress invalidate flag if (bSuppressInvalidate) { this.iSuppressInvalidate--; } return this; }; /* HEADER RIGHT (CUSTOM CONTENT) */ SemanticPage.prototype.getCustomHeaderContent = function () { return this._getSegmentedHeader().getSection("customRight").getContent(); }; SemanticPage.prototype.addCustomHeaderContent = function (oControl, bSuppressInvalidate) { this._getSegmentedHeader().getSection("customRight").addContent(oControl, bSuppressInvalidate); return this; }; SemanticPage.prototype.indexOfCustomHeaderContent = function (oControl) { return this._getSegmentedHeader().getSection("customRight").indexOfContent(oControl); }; SemanticPage.prototype.insertCustomHeaderContent = function (oControl, iIndex, bSuppressInvalidate) { this._getSegmentedHeader().getSection("customRight").insertContent(oControl, iIndex, bSuppressInvalidate); return this; }; SemanticPage.prototype.removeCustomHeaderContent = function (oControl, bSuppressInvalidate) { return this._getSegmentedHeader().getSection("customRight").removeContent(oControl, bSuppressInvalidate); }; SemanticPage.prototype.removeAllCustomHeaderContent = function (bSuppressInvalidate) { return this._getSegmentedHeader().getSection("customRight").removeAllContent(bSuppressInvalidate); }; SemanticPage.prototype.destroyCustomHeaderContent = function (bSuppressInvalidate) { var aChildren = this.getCustomHeaderContent(); if (!aChildren) { return this; } // set suppress invalidate flag if (bSuppressInvalidate) { this.iSuppressInvalidate++; } this._getSegmentedHeader().getSection("customRight").destroy(bSuppressInvalidate); if (!this.isInvalidateSuppressed()) { this.invalidate(); } // reset suppress invalidate flag if (bSuppressInvalidate) { this.iSuppressInvalidate--; } return this; }; SemanticPage.prototype.setAggregation = function(sAggregationName, oObject, bSuppressInvalidate) { var oOldChild = this.mAggregations[sAggregationName]; if (oOldChild === oObject) { return this; } // no change oObject = this.validateAggregation(sAggregationName, oObject, /* multiple */ false); var sType = this.getMetadata().getManagedAggregation(sAggregationName).type; if (SemanticConfiguration.isKnownSemanticType(sType)) { if (oOldChild) { this._stopMonitor(oOldChild); this._removeFromInnerAggregation(oOldChild._getControl(), SemanticConfiguration.getPositionInPage(sType), bSuppressInvalidate); } if (oObject) { this._initMonitor(oObject); this._addToInnerAggregation(oObject._getControl(), SemanticConfiguration.getPositionInPage(sType), SemanticConfiguration.getSequenceOrderIndex(sType), bSuppressInvalidate); } return ManagedObject.prototype.setAggregation.call(this, sAggregationName, oObject, true);// no need to invalidate entire page since the change only affects custom footer/header of page } return ManagedObject.prototype.setAggregation.call(this, sAggregationName, oObject, bSuppressInvalidate); }; SemanticPage.prototype.destroyAggregation = function(sAggregationName, bSuppressInvalidate) { var oAggregationInfo = this.getMetadata().getAggregations()[sAggregationName]; if (oAggregationInfo && SemanticConfiguration.isKnownSemanticType(oAggregationInfo.type)) { var oObject = ManagedObject.prototype.getAggregation.call(this, sAggregationName); if (oObject) { this._stopMonitor(oObject); if (!oObject._getControl().bIsDestroyed) { this._removeFromInnerAggregation(oObject._getControl(), SemanticConfiguration.getPositionInPage(oAggregationInfo.type), bSuppressInvalidate); } } } return ManagedObject.prototype.destroyAggregation.call(this, sAggregationName, oObject, bSuppressInvalidate); }; SemanticPage.prototype._updateHeaderVisibility = function () { var oHeader = this._getInternalHeader(); var bEmpty = (oHeader.getContentLeft().length === 0) && (oHeader.getContentMiddle().length === 0) && (oHeader.getContentRight().length === 0); this._getPage().setShowHeader(!bEmpty); }; SemanticPage.prototype._getTitle = function () { if (!this._oTitle) { this._oTitle = new Title(this.getId() + "-title", {text: this.getTitle()}); } return this._oTitle; }; SemanticPage.prototype._getNavButton = function () { if (!this._oNavButton) { this._oNavButton = new Button(this.getId() + "-navButton", { type: ButtonType.Up, tooltip: SemanticPage._getResourceBundle().getText("PAGE_NAVBUTTON_TEXT"), press: jQuery.proxy(this.fireNavButtonPress, this) }); } return this._oNavButton; }; SemanticPage.prototype._initMonitor = function (oSemanticControl) { var oConfig = oSemanticControl._getConfiguration(); if (oConfig.triggers) { // control is defined to trigger a PageMode upon press oSemanticControl.attachEvent("press", this._updateCurrentMode, this); } var oStates = oConfig.states, that = this; if (oStates) { jQuery.each(SemanticConfiguration._PageMode, function (key, value) { if (oStates[key]) { that.attachEvent(key, oSemanticControl._onPageStateChanged, oSemanticControl); } }); } }; SemanticPage.prototype._stopMonitor = function (oSemanticControl) { oSemanticControl.detachEvent("press", this._updateCurrentMode, this); var oConfig = oSemanticControl._getConfiguration(); var oStates = oConfig.states, that = this; if (oStates) { jQuery.each(SemanticConfiguration._PageMode, function (key, value) { if (oStates[key]) { that.detachEvent(key, oSemanticControl._onPageStateChanged, oSemanticControl); } }); } }; SemanticPage.prototype._updateCurrentMode = function (oEvent) { var oConfig = oEvent.oSource._getConfiguration(); // update global state if (typeof oConfig.triggers === 'string') { this._currentMode = oConfig.triggers; } else { var iLength = oConfig.triggers.length; // control triggers more than one global state, // depending on current state (e.g. if toggle button) if (iLength && iLength > 0) { for (var iIndex = 0; iIndex < iLength; iIndex++) { var oTriggerConfig = oConfig.triggers[iIndex]; if (oTriggerConfig && (oTriggerConfig.inState === this._currentMode)) { this._currentMode = oTriggerConfig.triggers; break; } } } } this.fireEvent(this._currentMode); }; SemanticPage.prototype._removeFromInnerAggregation = function (oControl, sPosition, bSuppressInvalidate) { var oPositionInPage = this._getSemanticPositionsMap()[sPosition]; if (oPositionInPage && oPositionInPage.oContainer && oPositionInPage.sAggregation) { oPositionInPage.oContainer["remove" + fnCapitalize(oPositionInPage.sAggregation)](oControl, bSuppressInvalidate); } }; SemanticPage.prototype._addToInnerAggregation = function (oControl, sPosition, iOrder, bSuppressInvalidate) { if (!oControl || !sPosition) { return; } var oPositionInPage = this._getSemanticPositionsMap()[sPosition]; if (!oPositionInPage || !oPositionInPage.oContainer || !oPositionInPage.sAggregation) { return; } if (typeof iOrder !== 'undefined') { oControl.addCustomData(new CustomData({key: "sortIndex", value: iOrder})); } return oPositionInPage.oContainer["add" + fnCapitalize(oPositionInPage.sAggregation)](oControl, bSuppressInvalidate); }; SemanticPage.prototype._getSemanticPositionsMap = function (oControl, oConfig) { if (!this._oPositionsMap) { this._oPositionsMap = {}; this._oPositionsMap[SemanticConfiguration.prototype._PositionInPage.headerLeft] = { oContainer: this._getInternalHeader(), sAggregation: "contentLeft" }; this._oPositionsMap[SemanticConfiguration.prototype._PositionInPage.headerRight] = { oContainer: this._getSegmentedHeader().getSection("semanticRight"), sAggregation: "content" }; this._oPositionsMap[SemanticConfiguration.prototype._PositionInPage.headerMiddle] = { oContainer: this._getInternalHeader(), sAggregation: "contentMiddle" }; this._oPositionsMap[SemanticConfiguration.prototype._PositionInPage.footerLeft] = { oContainer: this._getSegmentedFooter().getSection("semanticLeft"), sAggregation: "content" }; this._oPositionsMap[SemanticConfiguration.prototype._PositionInPage.footerRight_IconOnly] = { oContainer: this._getSegmentedFooter().getSection("semanticRight_IconOnly"), sAggregation: "content" }; this._oPositionsMap[SemanticConfiguration.prototype._PositionInPage.footerRight_TextOnly] = { oContainer: this._getSegmentedFooter().getSection("semanticRight_TextOnly"), sAggregation: "content" }; } return this._oPositionsMap; }; /** * Create internal page * @returns {sap.m.Page} * @private */ SemanticPage.prototype._getPage = function () { var oPage = this.getAggregation("_page"); if (!oPage && !this._bIsBeingDestroyed) { this.setAggregation("_page", new Page(this.getId() + "-page")); oPage = this.getAggregation("_page"); } return oPage; }; /** * Create internal header * @returns {sap.m.IBar} * @private */ SemanticPage.prototype._getInternalHeader = function () { if (!this._oInternalHeader) { var sId = this.getId() + "-intHeader"; this._oInternalHeader = new Bar({ id: sId, ariaLabelledBy: this._getInvisibleText(sId, SemanticPage.ARIA.TOOLBAR_HEADER_ACTIONS) }); if (this._oHeaderObserver) { this._oHeaderObserver.observe(this._oInternalHeader, { aggregations: [ "contentLeft", "contentMiddle", "contentRight" ] }); } } return this._oInternalHeader; }; /** * @returns {sap.m.OverflowToolbar} The internal overflow toolbar. * @private */ SemanticPage.prototype._getInternalOverflowToolbar = function () { var sId = this.getId() + "-footer"; return new OverflowToolbar({ id: sId, ariaLabelledBy: this._getInvisibleText(sId, SemanticPage.ARIA.TOOLBAR_FOOTER_ACTIONS) }); }; /** * Returns the custom or internal header * @private * @returns {sap.m.IBar} */ SemanticPage.prototype._getAnyHeader = function () { return this._getInternalHeader(); }; /** * Returns the internal footer * @private * @returns {sap.m.semantic.SegmentedContainer} */ SemanticPage.prototype._getSegmentedHeader = function() { if (!this._oWrappedHeader) { var oHeader = this._getInternalHeader(); if (!oHeader) { Log.error("missing page header", this); return null; } this._oWrappedHeader = new SegmentedContainer(oHeader, "contentRight"); this._oWrappedHeader.addSection({sTag: "customRight"}); this._oWrappedHeader.addSection({sTag: "semanticRight"}); } return this._oWrappedHeader; }; /** * Returns the internal footer * @private * @returns {sap.m.semantic.SegmentedContainer} */ SemanticPage.prototype._getSegmentedFooter = function() { if (!this._oWrappedFooter) { var oFooter = this._getPage().getFooter(); if (!oFooter) { Log.error("missing page footer", this); return null; } this._oWrappedFooter = new SegmentedContainer(oFooter); //add section for SEMANTIC content that should go on the left this._oWrappedFooter.addSection({sTag: "semanticLeft"}); //add spacer to separate left from right this._oWrappedFooter.addSection({ sTag: "spacer", aContent: [new ToolbarSpacer()] }); //add section for SEMANTIC content that should go on the right; // REQUIREMENT: only TEXT-BUTTONS allowed in this section this._oWrappedFooter.addSection({ sTag: "semanticRight_TextOnly", fnSortFunction: fnSortSemanticContent }); //add section for CUSTOM content that should go on the right; this._oWrappedFooter.addSection({sTag: "customRight"}); //add section for SEMANTIC content that should go on the right; // REQUIREMENT: only ICON-BUTTONS/ICON-SELECT allowed in this section this._oWrappedFooter.addSection({ sTag: "semanticRight_IconOnly", fnSortFunction: fnSortSemanticContent }); } return this._oWrappedFooter; }; /** * Creates and caches an instance of the {@link sap.ui.core.InvisibleText} control for the specified aria label. * @param {string} sId The ID for the invisible text control. * @param {string} sAriaLabel The aria label to set for the invisible text control. * @returns {sap.ui.core.InvisibleText} The created invisible text control. * @private */ SemanticPage.prototype._getInvisibleText = function(sId, sAriaLabel) { var oInvisibleText = new InvisibleText({ id: sId + "-InvisibleText", text: sAriaLabel }).toStatic(); this._aCachedInvisibleTexts.push(oInvisibleText); return oInvisibleText; }; /** * Destroys all cached instances of the {@link sap.ui.core.InvisibleText} control. * @private */ SemanticPage.prototype._destroyInvisibleTexts = function () { this._aCachedInvisibleTexts.forEach(function (oInvisibleText) { oInvisibleText.destroy(); }); this._aCachedInvisibleTexts = []; }; /* helper functions */ function fnCapitalize(sName) { return sName.substring(0, 1).toUpperCase() + sName.substring(1); } function fnSortSemanticContent(oControl1, oControl2) { var iSortIndex1 = oControl1.data("sortIndex"); var iSortIndex2 = oControl2.data("sortIndex"); if ((typeof iSortIndex1 === 'undefined') || (typeof iSortIndex2 === 'undefined')) { Log.warning("sortIndex missing", this); return null; } return (iSortIndex1 - iSortIndex2); } return SemanticPage; });