@openui5/sap.m
Version:
OpenUI5 UI Library sap.m
332 lines (280 loc) • 9.69 kB
JavaScript
/*!
* 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;
});