@openui5/sap.ui.core
Version:
OpenUI5 Core Library sap.ui.core
471 lines (436 loc) • 14.8 kB
JavaScript
/*!
* 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/base/future",
"sap/base/util/deepEqual",
"sap/base/util/merge",
"sap/ui/core/message/ControlMessageProcessor",
"sap/ui/core/message/Message",
"sap/ui/core/message/MessageType",
"sap/ui/core/message/MessageProcessor",
"sap/ui/model/message/MessageModel"
], (
future,
deepEqual,
merge,
ControlMessageProcessor,
Message,
MessageType,
MessageProcessor,
MessageModel
) => {
"use strict";
var oMessageModel;
var mRegisteredProcessors = {};
var mAllMessages = {};
var oControlMessageProcessor;
/**
* Messaging provides a central place for managing <code>sap.ui.core.message.Message</code>s.
*
* @namespace
* @alias module:sap/ui/core/Messaging
* @public
* @since 1.118.0
*
*/
const Messaging = {
/**
* Add messages to Messaging
*
* @param {sap.ui.core.message.Message|sap.ui.core.message.Message[]} vMessages Array of <code>Message</code> or single <code>Message</code>
* @public
*/
addMessages: function(vMessages) {
var oMessage = vMessages,
mProcessorsNeedsUpdate = _getAffectedProcessors(vMessages);
if (!vMessages) {
return;
} else if (Array.isArray(vMessages)) {
for (var i = 0; i < vMessages.length; i++) {
oMessage = vMessages[i];
_importMessage(oMessage);
}
} else {
_importMessage(vMessages);
}
_updateMessageModel(mProcessorsNeedsUpdate);
},
/**
* Remove given Messages
*
* @param {sap.ui.core.message.Message|sap.ui.core.message.Message[]} vMessages - The message(s) to be removed.
* @public
*/
removeMessages: function(vMessages) {
// Do not expose bOnlyValidationMessages to public API
_removeMessages.apply(Messaging, arguments);
},
/**
* Remove all messages
* @public
*/
removeAllMessages: function() {
var mProcessorsNeedsUpdate = {};
for (var sProcessorId in mAllMessages) {
//use the first Message/Message array to get the processor for the update
var sFirstKey = Object.keys(mAllMessages[sProcessorId])[0];
var vMessages = mAllMessages[sProcessorId][sFirstKey];
Object.assign(mProcessorsNeedsUpdate, _getAffectedProcessors(vMessages));
}
mAllMessages = {};
_updateMessageModel(mProcessorsNeedsUpdate);
},
/**
* Update Messages by providing two arrays of old and new messages.
*
* The old ones will be removed, the new ones will be added.
*
* @param {Array<sap.ui.core.message.Message>} aOldMessages Array of old messages to be removed
* @param {Array<sap.ui.core.message.Message>} aNewMessages Array of new messages to be added
* @public
*/
updateMessages: function(aOldMessages, aNewMessages) {
Messaging.removeMessages(aOldMessages);
Messaging.addMessages(aNewMessages);
var aAllMessages = [].concat(aOldMessages || [], aNewMessages || []);
var mProcessors = _getAffectedProcessors(aAllMessages);
for (var sProcessorId in mProcessors) {
mProcessors[sProcessorId].fireEvent("messageChange", {
newMessages: aNewMessages,
oldMessages: aOldMessages
});
}
},
/**
* Register MessageProcessor
*
* @param {sap.ui.core.message.MessageProcessor} oProcessor The MessageProcessor
* @public
*/
registerMessageProcessor: function(oProcessor) {
var sProcessorId = oProcessor.getId(),
mProcessorsNeedsUpdate = {};
if (!mRegisteredProcessors[sProcessorId]) {
mRegisteredProcessors[sProcessorId] = sProcessorId;
if (sProcessorId in mAllMessages) {
mProcessorsNeedsUpdate[sProcessorId] = oProcessor;
_pushMessages(mProcessorsNeedsUpdate);
}
if (!MessageProcessor._isRegistered) {
var Messaging = sap.ui.require("sap/ui/core/Messaging");
var fnDestroy = MessageProcessor.prototype.destroy;
MessageProcessor.prototype.destroy = function () {
fnDestroy.apply(this);
Messaging.unregisterMessageProcessor(this);
};
MessageProcessor._isRegistered = true;
}
}
},
/**
* Deregister MessageProcessor
*
* @param {sap.ui.core.message.MessageProcessor} oProcessor The MessageProcessor
* @public
*/
unregisterMessageProcessor: function(oProcessor) {
_removeMessagesByProcessor(oProcessor.getId());
delete mRegisteredProcessors[oProcessor.getId()];
},
/**
* When using the databinding type system, the validation/parsing of a new property value could fail.
* In this case, a validationError/parseError event is fired. These events bubble up to the core.
* For registered ManagedObjects, the Messaging attaches to these events and creates a
* <code>sap.ui.core.message.Message</code> (bHandleValidation=true) for each of these errors
* and cancels the event bubbling.
*
* @param {sap.ui.base.ManagedObject} oObject The sap.ui.base.ManagedObject
* @param {boolean} bHandleValidation Handle validationError/parseError events for this object. If set to true,
* the Messaging creates a Message for each validation/parse error. The event bubbling is canceled in every case.
* @public
*/
registerObject: function(oObject, bHandleValidation) {
if (!(oObject && oObject.isA && (oObject.isA(["sap.ui.base.ManagedObject", "sap.ui.core.Core"])))) {
future.errorThrows("Messaging: " + oObject.toString() + " is not an instance of sap.ui.base.ManagedObject");
} else {
oObject.attachValidationSuccess(bHandleValidation, _handleSuccess);
oObject.attachValidationError(bHandleValidation, _handleError);
oObject.attachParseError(bHandleValidation, _handleError);
oObject.attachFormatError(bHandleValidation, _handleError);
}
},
/**
* Unregister ManagedObject
*
* @param {sap.ui.base.ManagedObject} oObject The sap.ui.base.ManagedObject
* @public
*/
unregisterObject: function(oObject) {
if (!(oObject && oObject.isA && oObject.isA("sap.ui.base.ManagedObject"))) {
future.errorThrows("Messaging: " + oObject.toString() + " is not an instance of sap.ui.base.ManagedObject");
} else {
oObject.detachValidationSuccess(_handleSuccess);
oObject.detachValidationError(_handleError);
oObject.detachParseError(_handleError);
oObject.detachFormatError(_handleError);
}
},
/**
* Get the MessageModel
* @return {sap.ui.model.message.MessageModel} oMessageModel The Message Model
* @public
*/
getMessageModel: function() {
if (!oMessageModel) {
oMessageModel = new MessageModel();
oMessageModel.setData([]);
}
return oMessageModel;
}
};
/**
* handle validation/parse/format error
*
* @param {object} oEvent The Event object
* @param {boolean} bHandleValidation Wether validation errors should be handled or not.
* @private
*/
function _handleError(oEvent, bHandleValidation) {
if (!oControlMessageProcessor) {
oControlMessageProcessor = new ControlMessageProcessor();
}
if (bHandleValidation) {
var oElement = oEvent.getParameter("element");
var sProperty = oEvent.getParameter("property");
var sTarget = oElement.getId() + '/' + sProperty;
var sProcessorId = oControlMessageProcessor.getId();
var bTechnical = oEvent.sId === "formatError";
if (mAllMessages[sProcessorId] && mAllMessages[sProcessorId][sTarget]) {
_removeMessages(mAllMessages[sProcessorId][sTarget], true);
}
var oReference = {};
oReference[oElement.getId()] = {
properties:{},
fieldGroupIds: oElement.getFieldGroupIds ? oElement.getFieldGroupIds() : undefined
};
oReference[oElement.getId()].properties[sProperty] = true;
var oMessage = new Message({
type: MessageType.Error,
message: oEvent.getParameter("message"),
target: sTarget,
processor: oControlMessageProcessor,
technical: bTechnical,
references: oReference,
validation: true
});
Messaging.addMessages(oMessage);
}
oEvent.cancelBubble();
}
/**
* handle validation success
*
* @param {object} oEvent The Event object
* @param {boolean} bHandleValidation Wether validation success should be handled or not.
* @private
*/
function _handleSuccess(oEvent, bHandleValidation) {
if (!oControlMessageProcessor) {
oControlMessageProcessor = new ControlMessageProcessor();
}
if (bHandleValidation) {
var oElement = oEvent.getParameter("element");
var sProperty = oEvent.getParameter("property");
var sTarget = oElement.getId() + '/' + sProperty;
var sProcessorId = oControlMessageProcessor.getId();
if (mAllMessages[sProcessorId] && mAllMessages[sProcessorId][sTarget]) {
_removeMessages(mAllMessages[sProcessorId][sTarget], true);
}
}
oEvent.cancelBubble();
}
/**
* import message to internal map of messages
* @param {sap.ui.core.message.Message} oMessage The Message to import
* @private
*/
function _importMessage(oMessage) {
var oProcessor = oMessage.getMessageProcessor(),
sProcessorId = oProcessor && oProcessor.getId(),
aTargets = oMessage.getTargets();
if (!mAllMessages[sProcessorId]) {
mAllMessages[sProcessorId] = {};
}
if (!aTargets.length) { // unbound message => add it to undefined entry
aTargets = [undefined];
}
aTargets.forEach(function (sTarget) {
var aMessages = mAllMessages[sProcessorId][sTarget] ? mAllMessages[sProcessorId][sTarget] : [];
aMessages.push(oMessage);
mAllMessages[sProcessorId][sTarget] = aMessages;
});
}
/**
* push messages to registered MessageProcessors
* @param {Object<string,sap.ui.core.message.MessageProcessor>} mProcessors A map containing the affected processor IDs
* @private
*/
function _pushMessages(mProcessors) {
var oProcessor, sId;
for (sId in mProcessors) {
oProcessor = mProcessors[sId];
var vMessages = mAllMessages[sId] ? mAllMessages[sId] : {};
_sortMessages(vMessages);
//push a copy
vMessages = Object.keys(vMessages).length === 0 ? null : merge({}, vMessages);
oProcessor.setMessages(vMessages);
}
}
/**
* Sort messages by type as specified in {@link sap.ui.core.message.Message#compare}.
*
* @param {Object<string,sap.ui.core.message.Message[]>|sap.ui.core.message.Message[]} vMessages
* Map or array of Messages to be sorted (in order of severity) by their type property
* @private
*/
function _sortMessages(vMessages) {
var sTarget, aMessages;
if (Array.isArray(vMessages)) {
vMessages = { "ignored": vMessages };
}
for (sTarget in vMessages) {
aMessages = vMessages[sTarget];
if (aMessages.length > 1) {
aMessages.sort(Message.compare);
}
}
}
/**
* update MessageModel
* @param {Object<string,sap.ui.core.message.MessageProcessor>} mProcessors A map containing the affected processor IDs
* @private
*/
function _updateMessageModel(mProcessors) {
var mUpdatedMessages = new Map(),
sProcessorId,
oMessageModel = Messaging.getMessageModel(),
sTarget;
function setMessage(oMessage) {
mUpdatedMessages.set(oMessage, true);
}
for (sProcessorId in mAllMessages) {
for (sTarget in mAllMessages[sProcessorId]) {
mAllMessages[sProcessorId][sTarget].forEach(setMessage);
}
}
_pushMessages(mProcessors);
oMessageModel.setData(Array.from(mUpdatedMessages.keys()));
}
/**
* Like module:sap/ui/core/Messaging.removeMessage but with an additional argument to only remove validation
* messages.
*
* @param {sap.ui.core.message.Message|sap.ui.core.message.Message[]} vMessages - The message(s) to be removed.
* @param {boolean} bOnlyValidationMessages - If set to true only messages that have been added due to validation
* errors are removed.
* @private
*/
function _removeMessages(vMessages, bOnlyValidationMessages) {
var mProcessors = _getAffectedProcessors(vMessages);
if (!vMessages || (Array.isArray(vMessages) && vMessages.length == 0)) {
return;
} else if (Array.isArray(vMessages)) {
// We need to work on a copy since the messages reference is changed by _removeMessage()
var aOriginalMessages = vMessages.slice(0);
for (var i = 0; i < aOriginalMessages.length; i++) {
if (!bOnlyValidationMessages || aOriginalMessages[i].validation) {
_removeMessage(aOriginalMessages[i]);
}
}
} else if (vMessages instanceof Message && (!bOnlyValidationMessages || vMessages.validation)){
_removeMessage(vMessages);
} else {
//map with target as key
for (var sTarget in vMessages) {
_removeMessages(vMessages[sTarget], bOnlyValidationMessages);
}
}
_updateMessageModel(mProcessors);
}
/**
* remove Message
*
* @param {sap.ui.core.message.Message} oMessage The Message to remove
* @private
*/
function _removeMessage(oMessage) {
var oProcessor = oMessage.getMessageProcessor(),
sProcessorId = oProcessor && oProcessor.getId(),
mProcessorMessages = mAllMessages[sProcessorId],
aTargets;
if (!mProcessorMessages) {
return;
}
aTargets = oMessage.getTargets();
if (!aTargets.length) { // unbound message => remove it from undefined entry
aTargets = [undefined];
}
aTargets.forEach(function (sTarget) {
var aMessages = mProcessorMessages[sTarget];
if (aMessages) {
for (var i = 0; i < aMessages.length; i++) {
var oMsg = aMessages[i];
if (deepEqual(oMsg, oMessage)) {
aMessages.splice(i,1);
--i; // Decrease counter as one element has been removed
}
}
// delete empty message array
if (mProcessorMessages[sTarget].length === 0) {
delete mProcessorMessages[sTarget];
}
}
});
}
/**
* get affected processors
* @param {sap.ui.core.message.Message|sap.ui.core.message.Message[]} vMessages Array of sap.ui.core.message.Message or single sap.ui.core.message.Message
* @return {Object<string,sap.ui.core.message.MessageProcessor>} mProcessors A map containing the affected processor IDs
* @private
*/
function _getAffectedProcessors(vMessages) {
var oProcessor,
sProcessorId,
mAffectedProcessors = {};
if (vMessages) {
if (!Array.isArray(vMessages)) {
vMessages = [vMessages];
}
vMessages.forEach(function(oMessage) {
oProcessor = oMessage.getMessageProcessor();
if (oProcessor) {
sProcessorId = oProcessor.getId();
mAffectedProcessors[sProcessorId] = oProcessor;
Messaging.registerMessageProcessor(oProcessor);
}
});
}
return mAffectedProcessors;
}
/**
* Removes all Messages for the given Processor ID. This function
* is used only during deregistration of a MessageProcessor. No
* further 'pushMessages' needed.
*
* @param {string} sProcessorId The ID of a MessageProcessor
* @private
*/
function _removeMessagesByProcessor(sProcessorId) {
delete mAllMessages[sProcessorId];
_updateMessageModel({});
}
return Messaging;
});