UNPKG

@openui5/sap.m

Version:

OpenUI5 UI Library sap.m

563 lines (498 loc) 17 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(["./PluginBase", "sap/ui/base/ManagedObjectObserver", "sap/ui/core/Lib", "sap/ui/core/Messaging"], function(PluginBase, ManagedObjectObserver, Library, Messaging) { "use strict"; /** * Constructor for a new DataStateIndicator plugin. * * @param {string} [sId] ID for the new <code>DataStateIndicator</code>, generated automatically if no ID is given * @param {object} [mSettings] Initial settings for the <code>DataStateIndicator</code> * * @class * This plugin implements a message strip used to show binding-related messages. * * @extends sap.ui.core.Element * @author SAP SE * @version 1.146.0 * * @public * @since 1.73 * @alias sap.m.plugins.DataStateIndicator * @borrows sap.m.plugins.PluginBase.findOn as findOn */ var DataStateIndicator = PluginBase.extend("sap.m.plugins.DataStateIndicator", /** @lends sap.m.plugins.DataStateIndicator.prototype */ { metadata: { library: "sap.m", properties: { /** * Defines a predicate to test each message of the data state. * * This callback gets called using the {@link sap.ui.core.message.Message message} and {@link sap.ui.core.Control related control} parameters. * Return <code>true</code> to keep the message, <code>false</code> otherwise. */ filter: {type: "function", invalidate: false}, /** * Enables filtering for data state messages if this property is set to <code>true</code>. A link is provided to the user that allows them to filter. * After the binding-related messages have been filtered by the user, all the existing filters are only taken into account once the message filter has been cleared again. * * <b>Note:</b> This feature must be enabled for OData models only. * @since 1.89 */ enableFiltering: { type: "boolean", defaultValue: false, invalidate: false } }, events: { /** * This event is fired when the {@link sap.ui.model.DataState data state} of the plugin parent is changed. */ dataStateChange: { allowPreventDefault: true, parameters: { /** * The data state object. */ dataState: {type: "sap.ui.model.DataState"}, /** * The messages ({@link sap.ui.core.message.Message}) from the current <code>dataState</code> object filtered by the given <code>filter</code> function. */ filteredMessages: {type: "object[]"} } }, /** * This event is fired when the user filters data state messages and if the <code>enableFiltering</code> property is set to <code>true</code>. * * @since 1.89 */ applyFilter: { allowPreventDefault: true, parameters: { /** * The filter object representing the entries with messages. */ filter: {type: "sap.ui.model.Filter"} } }, /** * This event is fired when the user clears the data state message filter and if the <code>enableFiltering</code> property is set to <code>true</code>. * * @since 1.89 */ clearFilter: { allowPreventDefault: true }, /** * This event is fired when the user presses the <code>Close</code> button of the <code>MessageStrip</code> control which is managed by this plugin. * * @since 1.103 */ close: {} } }}); DataStateIndicator.findOn = PluginBase.findOn; DataStateIndicator.prototype.init = function() { this._fnOnAggregatedDataStateChange = this._onAggregatedDataStateChange.bind(this); }; DataStateIndicator.prototype.onActivate = function(oControl) { this._bFiltering = false; var sBindingName = this._getBindingName(); var oBinding = oControl.getBinding(sBindingName); if (oBinding) { oBinding.attachAggregatedDataStateChange(this._fnOnAggregatedDataStateChange); this._processDataState(oBinding.getDataState()); } this._oObserver = new ManagedObjectObserver(this._observeChanges.bind(this)); this._oObserver.observe(oControl, { bindings: [sBindingName] }); }; DataStateIndicator.prototype.onDeactivate = function(oControl) { var sBindingName = this._getBindingName(); var oBinding = oControl.getBinding(sBindingName); if (oBinding) { oBinding.detachAggregatedDataStateChange(this._fnOnAggregatedDataStateChange); oBinding.getDataState().getMessages().forEach(function(oMessage) { oMessage.removeControlId(oControl.getId()); }); } if (this._bFiltering) { this._clearFilter(); } if (this._oMessageStrip) { oControl.removeAriaLabelledBy(this._oMessageStrip); this._oMessageStrip.destroy(); this._oMessageStrip = null; } if (this._oLink) { this._oLink.destroy(); this._oLink = null; } if (this._oInfoToolbar) { this._oInfoToolbar.destroy(); this._oInfoToolbar = this._oInfoText = null; } this._oObserver.unobserve(oControl, { bindings: [sBindingName] }); this._oObserver.destroy(); this._oObserver = null; }; DataStateIndicator.prototype._setLinkText = function(sLinkText) { this._sLinkText = sLinkText; this._updateLinkControl(); }; DataStateIndicator.prototype.setEnableFiltering = function(bEnableFiltering) { if ((bEnableFiltering = !!bEnableFiltering) == this.getEnableFiltering()) { return this; } this.setProperty("enableFiltering", bEnableFiltering, true); if (this.isActive()) { if (bEnableFiltering) { this.refresh(); } else { this._clearFilter(true); } } }; /** * Shows a message. * * @param {string} [sText] The message text, if empty, the message is hidden * @param {sap.ui.core.ValueState} [sType] The message type * @public */ DataStateIndicator.prototype.showMessage = function(sText, sType) { if (!this.getEnabled() || !this.getControl() || (!sText && !this._oMessageStrip)) { return; } if (this._oMessageStrip) { this._oMessageStrip.setText(sText).setType(sType).setVisible(!!sText); this.getControl().removeAriaLabelledBy(this._oMessageStrip); if (sText) { this.getControl().addAriaLabelledBy(this._oMessageStrip); } } else { sap.ui.require(["sap/m/MessageStrip"], function(MessageStrip) { var oControl = this.getControl(); this._oMessageStrip = new MessageStrip({ showCloseButton: true, showIcon: true, close: function() { oControl.focus(); oControl.removeAriaLabelledBy(this._oMessageStrip); this.fireClose(); }.bind(this) }).addStyleClass("sapUiTinyMargin"); oControl.setAggregation("_messageStrip", this._oMessageStrip); oControl.addAriaLabelledBy(this._oMessageStrip); this._updateLinkControl(); this.showMessage(sText, sType); }.bind(this)); } }; /** * Return whether message filtering is active or not. * * @public * @since 1.89 * @returns {boolean} Whether message filtering is active or not */ DataStateIndicator.prototype.isFiltering = function() { return !!this._bFiltering; }; /** * Refreshes the messages displayed for the current data state. * The current data state is evaluated again, and the filters are applied. * * @public */ DataStateIndicator.prototype.refresh = function() { if (this.isActive()) { var oBinding = this.getControl().getBinding(this._getBindingName()); if (oBinding) { this._processDataState(oBinding.getDataState(), true); if (oBinding.requestFilterForMessages && this._bFiltering) { this._applyFilter(); } } } }; /** * Creates or updates the link control of the message strip. * @private */ DataStateIndicator.prototype._updateLinkControl = function() { if (!this._oMessageStrip) { return; } if (!this._sLinkText) { this._oMessageStrip.setLink(null); } else if (this._oLink) { this._oLink.setText(this._sLinkText); this._oMessageStrip.setLink(this._oLink); } else { sap.ui.require(["sap/m/Link"], function(Link) { this._oLink = new Link({ press: [this._onLinkPress, this] }); this._updateLinkControl(); }.bind(this)); } }; DataStateIndicator.prototype._getBindingName = function() { return this.getConfig("defaultBindingName"); }; DataStateIndicator.prototype._processDataState = function(oDataState, bIgnoreChanges) { if (!oDataState) { return; } if (!bIgnoreChanges && !oDataState.getChanges().messages) { return; } var oParent = this.getParent(); var oControl = this.getControl(); var oBinding = oControl && oControl.getBinding(this._getBindingName()); if (oBinding && oBinding.bIsBeingDestroyed) { oDataState.getAllMessages().forEach(function(oMessage) { oMessage.removeControlId(oControl.getId()); }); return; } var aMessages = oDataState.getMessages(); var fnFilter = this.getFilter(); if (fnFilter) { aMessages = aMessages.filter(function(oMessage) { return fnFilter(oMessage, oParent); }); } if (!this.fireDataStateChange({ dataState: oDataState, filteredMessages: aMessages})) { return; } if (aMessages.length) { var sMessage = ""; var bUpdateMessageModel = false; var oFirstMessage = aMessages[0]; aMessages.forEach(function(oMessage) { if (oMessage.getControlIds().indexOf(oControl.getId()) == -1) { oMessage.addControlId(oControl.getId()); bUpdateMessageModel = true; } }); this._sCombinedType = this._getCombinedType(aMessages); if (aMessages.length == 1 && isMessageRelatedToPath(oFirstMessage, oBinding.getPath())) { sMessage = oFirstMessage.getMessage(); } else { sMessage = this._translate(this._sCombinedType.toUpperCase()); } this.showMessage(sMessage, oFirstMessage.getType()); if (!this._bFiltering && oBinding.requestFilterForMessages && this.getEnableFiltering()) { var fnFilter = this.getFilter(); var fnMessageFilter = fnFilter && function(oMessage) { return fnFilter(oMessage, oParent); }; oBinding.requestFilterForMessages(fnMessageFilter).then(function(oFilter) { this._setLinkText(oFilter ? this._translate("FILTER_ITEMS") : ""); }.bind(this)); } if (bUpdateMessageModel) { Messaging.getMessageModel().checkUpdate(true, true); } } else { this.showMessage(""); if (this._bFiltering) { this._clearFilter(true); } } }; DataStateIndicator.prototype._onLinkPress = function() { if (this._bFiltering) { this._clearFilter(); } else { this._applyFilter(); } }; DataStateIndicator.prototype._clearFilter = function(bClearLink) { if (this._bFiltering) { this._bFiltering = false; this._hideFilterInfo(bClearLink); if (this.fireClearFilter() && this._fnLastFilter) { this._fnLastFilter("Application"); delete this.getControl().getBinding(this._getBindingName()).filter; } } }; DataStateIndicator.prototype._applyFilter = function() { var fnFilter = this.getFilter(); var oControl = this.getControl(); var oParent = this.getParent(); var oBinding = oControl.getBinding(this._getBindingName()); var fnMessageFilter = fnFilter && function(oMessage) { return fnFilter(oMessage, oParent); }; oBinding.requestFilterForMessages(fnMessageFilter).then(function(oFilter) { if (!oFilter) { return this._setLinkText(""); } var bRefresh = this._bFiltering; if (!bRefresh) { this._bFiltering = true; this._showFilterInfo(); } if (!this.fireApplyFilter({ filter : oFilter, revert : this._clearFilter.bind(this) })) { return; } if (!bRefresh) { this._fnLastFilter = oBinding.filter.bind(oBinding, oBinding.aApplicationFilters); this._fnBindingFilter = oBinding.filter; } else { delete oBinding.filter; } oBinding.filter(oFilter, "Application"); oBinding.filter = function(aFilters, sFilterType) { if (sFilterType == "Application") { this._fnLastFilter = this._fnBindingFilter.bind(oBinding, aFilters); return oBinding; } return this._fnBindingFilter.apply(oBinding, arguments); }.bind(this); }.bind(this)); }; DataStateIndicator.prototype._hideFilterInfo = function(bClearLink) { this._oMessageStrip.setShowCloseButton(true); this._setLinkText(bClearLink ? "" : this._translate("FILTER_ITEMS")); this.getConfig("hideInfoToolbar", this.getControl()); }; DataStateIndicator.prototype._showFilterInfo = function() { if (this._oInfoText) { this._oMessageStrip.setShowCloseButton(false); this._setLinkText(this._translate("CLEAR_FILTER")); this._oInfoText.setText(this._translate("FILTERED_BY_" + this._sCombinedType.toUpperCase())); if (!this._oInfoToolbar.getParent()) { this.getConfig("showInfoToolbar", this.getControl(), this._oInfoToolbar); } } else { sap.ui.require(["sap/m/Text", "sap/m/Toolbar"], function(Text, Toolbar) { this._oInfoText = new Text(); this._oInfoToolbar = new Toolbar({ design: "Info", content: this._oInfoText, active: this.hasListeners("filterInfoPress"), press: this.fireEvent.bind(this, "filterInfoPress"), ariaLabelledBy: this._oInfoText }); this._showFilterInfo(); }.bind(this)); } }; DataStateIndicator.prototype._getCombinedType = function(aMessages) { if (aMessages && aMessages.length) { var mTypes = {None: 0, Information: 1, Success: 2, Warning: 4, Error: 8}; var iSeverity = 0; aMessages.forEach(function(oMessage) { iSeverity |= mTypes[oMessage.getType()]; }); if (iSeverity & mTypes.Error && iSeverity & mTypes.Warning) { return "Issue"; } if (iSeverity & mTypes.Error) { return "Error"; } if (iSeverity & mTypes.Warning) { return "Warning"; } if (iSeverity & mTypes.Success || iSeverity & mTypes.Information) { return "Notification"; } } return ""; }; DataStateIndicator.prototype._onAggregatedDataStateChange = function(oEvent) { this._processDataState(oEvent.getParameter("dataState")); }; DataStateIndicator.prototype._observeChanges = function(mChange) { const oBindingInfo = mChange.bindingInfo; const oBinding = oBindingInfo.binding; if (oBinding) { oBinding.detachAggregatedDataStateChange(this._fnOnAggregatedDataStateChange); if (mChange.mutation == "ready") { oBinding.attachAggregatedDataStateChange(this._fnOnAggregatedDataStateChange); } } else if (mChange.mutation == "prepare") { oBindingInfo.events ??= {}; oBindingInfo.events.aggregatedDataStateChange ??= this._fnOnAggregatedDataStateChange; } }; DataStateIndicator.prototype._translate = function(sBundleKey) { var sBundleText = "DATASTATE_" + sBundleKey; var oMetadata = this.getControl().getMetadata(); var sLibraryName = oMetadata.getLibraryName(); var sControlName = oMetadata.getName().split(".").pop().toUpperCase(); var oResourceBundle = Library.getResourceBundleFor(sLibraryName); var sControlBundleText = sControlName + "_" + sBundleText; if (oResourceBundle.hasText(sControlBundleText)) { return oResourceBundle.getText(sControlBundleText); } if (sLibraryName == "sap.m") { return oResourceBundle.getText(sBundleText); } return Library.getResourceBundleFor("sap.m").getText(sBundleText); }; /** * Checks whether the given message is related to the given binding path. * @param {sap.ui.core.message.Message} oMessage * @param {string} sPath * @returns {boolean} Whether the message is related to the path * @private */ function isMessageRelatedToPath(oMessage, sPath) { return oMessage.getTargets().some(function(sTarget) { return sTarget.endsWith(sPath); }); } /** * Plugin-specific control configurations */ PluginBase.setConfigs({ "sap.m.ListBase": { defaultBindingName: "items", useInfoToolbar: function(oParent) { return oParent && oParent.getUseInfoToolbar && oParent.getUseInfoToolbar() == "Off" ? false : true; }, showInfoToolbar: function(oControl, oInfoToolbar) { if (this.useInfoToolbar(oControl.getParent())) { this._oOldInfoToolbar = oControl.getInfoToolbar(); this._oNewInfoToolbar = oInfoToolbar; oControl.setInfoToolbar(oInfoToolbar); } }, hideInfoToolbar: function(oControl) { if (this._oNewInfoToolbar) { oControl.setInfoToolbar(this._oOldInfoToolbar); this._oNewInfoToolbar = this._oOldInfoToolbar = null; } }, onDeactivate: function(oControl) { this.hideInfoToolbar(oControl); } }, "sap.ui.table.Table": { defaultBindingName: "rows", useInfoToolbar: function(oParent) { return oParent && oParent.getUseInfoToolbar && oParent.getUseInfoToolbar() == "Off" ? false : true; }, showInfoToolbar: function(oControl, oInfoToolbar) { if (this.useInfoToolbar(oControl.getParent())) { this._oInfoToolbar = oInfoToolbar; oControl.addExtension(oInfoToolbar); } }, hideInfoToolbar: function(oControl) { if (this._oInfoToolbar) { oControl.removeExtension(this._oInfoToolbar); this._oInfoToolbar = null; } }, onDeactivate: function(oControl) { this.hideInfoToolbar(oControl); } } }, DataStateIndicator); return DataStateIndicator; });