UNPKG

@openui5/sap.m

Version:

OpenUI5 UI Library sap.m

332 lines (280 loc) 9.69 kB
/*! * OpenUI5 * (c) Copyright 2009-2023 SAP SE or an SAP affiliate company. * Licensed under the Apache License, Version 2.0 - see LICENSE.txt. */ sap.ui.define([ 'sap/ui/Device', 'sap/ui/base/Object', 'sap/ui/core/Core', 'sap/ui/core/ValueStateSupport', 'sap/ui/core/Popup', 'sap/ui/core/library', "sap/ui/thirdparty/jquery", "sap/ui/dom/jquery/Aria" // jQuery Plugin "addAriaDescribedBy", "removeAriaDescribedBy" ], function( Device, BaseObject, Core, ValueStateSupport, Popup, coreLibrary, jQuery ) { "use strict"; // shortcut for sap.ui.core.ValueState var ValueState = coreLibrary.ValueState; /** * Creates a <code>sap.m.delegate.ValueState</code> delegate that can be attached to controls that require * a value state message popup. * * @example <caption>Example of usage:</caption> * * <pre> * MyControl.prototype.init = function() { * this._oValueStateMessage = new ValueStateMessage(this); * }; * * MyControl.prototype.onfocusin = function(oEvent) { * this._oValueStateMessage.open(); * }; * * MyControl.prototype.onfocusout = function(oEvent) { * this._oValueStateMessage.close(); * }; * * MyControl.prototype.exit = function() { * * if (this._oValueStateMessage) { * this._oValueStateMessage.destroy(); * } * * this._oValueStateMessage = null; * }; * </pre> * * <b>Preconditions:</b> * The given control must implement the following interface: * * <code> * .getValueState() * .getValueStateText() * .getFocusDomRef() * .getDomRefForValueStateMessage() * </code> * * @extends sap.ui.base.Object * @param {sap.ui.core.Control} oControl The control for which this value state message is the delegate * @constructor * @private * @alias sap.m.delegate.ValueState * @version 1.42 * @author SAP SE */ var ValueStateMessage = BaseObject.extend("sap.m.delegate.ValueState", /** @lends sap.m.delegate.ValueState.prototype */ { constructor: function(oControl) { BaseObject.apply(this, arguments); this._oControl = oControl; this._oPopup = null; } }); /** * Opens value state message popup. * * @protected */ ValueStateMessage.prototype.open = function() { var oControl = this._oControl, oPopup = this.getPopup(), oMessageDomRef = this.createDom(), mDock = Popup.Dock, $Control; if (!oControl || !oControl.getDomRef() || !oPopup || !oMessageDomRef) { return; } var sValueState = oControl.getValueState(); var vValueStateMessageText = this._getValueStateText(oControl, sValueState); $Control = jQuery(oControl.getDomRefForValueStateMessage()); oPopup.setContent(oMessageDomRef); oPopup.close(0); if (oPopup.getContent()) { oPopup.getContent().style.maxWidth = oControl.getDomRef().offsetWidth + "px"; } else { oPopup.getContent().style.maxWidth = ""; } oPopup.open( this.getOpenDuration(), mDock.BeginTop, mDock.BeginBottom, oControl.getDomRefForValueStateMessage(), null, null, null, Device.system.phone ? true : Popup.CLOSE_ON_SCROLL ); this.createFormattedTextDOM(vValueStateMessageText, oMessageDomRef); var $DomRef = jQuery(oMessageDomRef); // check whether popup is below or above the input if ($Control.offset().top < $DomRef.offset().top) { $DomRef.addClass("sapMValueStateMessageBottom"); } else { $DomRef.addClass("sapMValueStateMessageTop"); } }; /** * Closes value state message popup. * * @protected */ ValueStateMessage.prototype.close = function() { if (this._oPopup) { this._oPopup.close(0); } }; ValueStateMessage.prototype.getId = function() { var oControl = this._oControl; if (!oControl) { return ""; } return (typeof oControl.getValueStateMessageId === "function") ? oControl.getValueStateMessageId() : oControl.getId() + "-message"; }; ValueStateMessage.prototype.getOpenDuration = function() { var oControl = this._oControl; if (!oControl) { return 0; } return (oControl.iOpenMessagePopupDuration === undefined) ? 0 : oControl.iOpenMessagePopupDuration; }; /** * Creates the value state message popup. * * @param {string} [sID] ID for the new message popup; generated automatically if no ID is given * @returns {sap.ui.core.Popup} The popup instance object */ ValueStateMessage.prototype.createPopup = function(sID) { sID = sID || this.getId(); if (this._oPopup) { return this._oPopup; } this._oPopup = new Popup(document.createElement("span"), false, false, false); this._oPopup.attachClosed(function() { jQuery(document.getElementById(sID)).remove(); }); this._oPopup.attachOpened(function () { var content = this._oPopup.getContent(); /* z-index of the popup is not calculated correctly by this._getCorrectZIndex() in IE, causing it to be "under" the "blind layer" and links to be unreachable (unclickable) in IE */ if (content) { content.style.zIndex = this._getCorrectZIndex(); } }.bind(this)); return this._oPopup; }; /** * Gets the value state message popup, creating it if necessary by calling * the <code>createPopup()</code> method. * * @returns {sap.ui.core.Popup} The popup instance object */ ValueStateMessage.prototype.getPopup = function() { if (!this._oControl) { return null; } return this.createPopup(); }; /** * Determines and extracts the correct value state text depending on the value state * If <code>formattedValueStateText</code> aggregation of type <code>sap.m.FormattedText</code> is set * it has priority over the plain text (string) <code>valueStateText</code> value state property. * * @param {sap.ui.core.Control} oControl The control for which this value state message is attached. * @param {string} sValueState The value state type of the control. * @returns {(string|object)} Value state message text of the control. * * @private */ ValueStateMessage.prototype._getValueStateText = function(oControl, sValueState) { // Don't return text for value state "success" or "none" if (sValueState === ValueState.Success || sValueState === ValueState.None) { return ""; } var oValueStateFormattedText = oControl.getFormattedValueStateText && oControl.getFormattedValueStateText(); var oValueStateFormattedTextContent = oValueStateFormattedText && oValueStateFormattedText.getHtmlText(); var sValueStatePlainText = oControl.getValueStateText() || ValueStateSupport.getAdditionalText(oControl); // Return sap.m.FormattedText aggregation only if there is an actual formatted text set to it // Otherwise return the plain text value state message set in the control or the default one return oValueStateFormattedTextContent ? oValueStateFormattedText : sValueStatePlainText; }; /** * Creates the value state message HTML elements. * * @returns {object} The value state message root HTML element */ ValueStateMessage.prototype.createDom = function() { var oControl = this._oControl; if (!oControl) { return null; } var sID = this.getId(), oTextDomRef, oMessageDomRef = document.createElement("div"), sValueState = oControl.getValueState(), vValueStateMessageText = this._getValueStateText(oControl, sValueState); if (sValueState === ValueState.Success || sValueState === ValueState.None) { oMessageDomRef.className = "sapUiInvisibleText"; } else { oMessageDomRef.className = "sapMValueStateMessage sapMValueStateMessage" + sValueState; } // If value state message is plain text create the required DOM // otherwise it's of type sap.m.FormattedText - render it and add ID if (typeof vValueStateMessageText === "string") { oTextDomRef = document.createElement("span"); oTextDomRef.id = sID + "-text"; oTextDomRef.appendChild(document.createTextNode(vValueStateMessageText)); oMessageDomRef.appendChild(oTextDomRef); } // This element should be hidden from the accessibility tree, since it has only presentation role // The value state announcement is present via hidden span, referenced via aria-describedby/aria-errormessage oMessageDomRef.setAttribute("role", "presentation"); oMessageDomRef.setAttribute("aria-hidden", "true"); oMessageDomRef.id = sID; return oMessageDomRef; }; ValueStateMessage.prototype.createFormattedTextDOM = function(vValueStateMessageText, oMessageDomRef) { if (typeof vValueStateMessageText === "string") { return; } Core.createRenderManager().render(vValueStateMessageText, oMessageDomRef); oMessageDomRef.lastElementChild.setAttribute("id", this.getId() + "-text"); }; ValueStateMessage.prototype.destroy = function() { if (this._oPopup) { this._oPopup.destroy(); this._oPopup = null; } this._oControl = null; }; /** * Gets the z-index of the popup, so it won't be shown above some other popups. * @return {int} The correct z-index * @private */ ValueStateMessage.prototype._getCorrectZIndex = function() { var aParents = this._oControl.$().parents().filter(function() { var sZIndex = jQuery(this).css('z-index'); return sZIndex && sZIndex !== 'auto' && sZIndex !== '0'; }); if (!aParents.length) { return 1; } var iHighestZIndex = 0; aParents.each(function () { var iZIndex = parseInt(jQuery(this).css('z-index')); if (iZIndex > iHighestZIndex) { iHighestZIndex = iZIndex; } }); return iHighestZIndex + 1; }; return ValueStateMessage; });