@openui5/sap.m
Version:
OpenUI5 UI Library sap.m
553 lines (483 loc) • 17.3 kB
JavaScript
/*!
* OpenUI5
* (c) Copyright 2026 SAP SE or an SAP affiliate company.
* Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
*/
// Provides control sap.m.BusyDialog.
sap.ui.define(['./library', 'sap/ui/core/Control', 'sap/m/Dialog', 'sap/m/BusyIndicator', 'sap/m/Label', 'sap/m/Button', "sap/base/Log", 'sap/ui/core/InvisibleText', "sap/ui/core/Lib"],
function(library, Control, Dialog, BusyIndicator, Label, Button, Log, InvisibleText, Library) {
"use strict";
// shortcut for sap.m.TitleAlignment
var TitleAlignment = library.TitleAlignment;
/**
* Constructor for a new BusyDialog.
*
* @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
* BusyDialog is used to indicate that the system is busy.
* <h3>Overview</h3>
* When the busy dialog is displayed, the whole application is blocked.
* <h3>Structure</h3>
* The busy dialog can hold several elements, most of which are optional.
* <ul>
* <li><code>title</code> - A title for the dialog. By default, there is no title.</li>
* <li><code>text</code> - A text displayed above the busy animation.</li>
* <li><code>showCancelButton</code> - An optional Cancel button to stop the execution.</li>
* <li><code>customIcon</code> - An optional alternative icon to use as a busy animation.</li>
* </ul>
* <h3>Usage</h3>
* <h4>When to use</h4>
* <ul>
* <li>The operation lasts more than one second.</li>
* <li>You want to indicate loading in a page-to-page navigation (lightweight version).</li>
* <li>Offer a Cancel button if you expect the process to run more than 10 seconds.</li>
* <li> If you do not show a title or text, use the {@link sap.ui.core.InvisibleText invisible text} control to provide the reason for users with assistive technologies.</li>
* </ul>
* <h4>When not to use</h4>
* <ul>
* <li>The screen is not supposed to be blocked. Use a {@link sap.m.BusyIndicator} for the specific application part.</li>
* <li>Do not use the title of the busy dialog. Provide a precise text describing the operation in <code>text</code>.</li>
* </ul>
* @extends sap.ui.core.Control
*
* @author SAP SE
* @version 1.146.0
*
* @public
* @alias sap.m.BusyDialog
* @see {@link fiori:https://experience.sap.com/fiori-design-web/busydialog Busy Dialog}
*/
var BusyDialog = Control.extend("sap.m.BusyDialog", /** @lends sap.m.BusyDialog.prototype */ {
metadata: {
library: "sap.m",
properties: {
/**
* Optional text displayed inside the dialog.
*/
text: {type: "string", group: "Appearance", defaultValue: ''},
/**
* Sets the title of the BusyDialog. The default value is an empty string.
*/
title: {type: "string", group: "Appearance", defaultValue: ''},
/**
* Icon, used from the BusyIndicator. This icon is invisible in iOS platform and it is density aware. You can use the density convention (@2, @1.5, etc.) to provide higher resolution image for higher density screens.
*/
customIcon: {type: "sap.ui.core.URI", group: "Appearance", defaultValue: ''},
/**
* Defines the rotation speed of the given image. If GIF file is used, the speed has to be set to 0. The value is in milliseconds.
*/
customIconRotationSpeed: {type: "int", group: "Appearance", defaultValue: 1000},
/**
* If this is set to <code>false</code>, the source image will be loaded directly without attempting to fetch the density perfect image for high density devices.
* By default, this is set to <code>true</code> but then one or more requests are sent trying to get the density perfect version of the image.
*
* If bandwidth is the key for the application, set this value to <code>false</code>.
*/
customIconDensityAware: {type: "boolean", defaultValue: true},
/**
* Width of the provided icon with default value "44px".
*/
customIconWidth: {type: "sap.ui.core.CSSSize", group: "Appearance", defaultValue: "44px"},
/**
* Height of the provided icon with default value "44px".
*/
customIconHeight: {type: "sap.ui.core.CSSSize", group: "Appearance", defaultValue: "44px"},
/**
* The text of the cancel button. The default text is "Cancel" (translated to the respective language).
*/
cancelButtonText: {type: "string", group: "Misc", defaultValue: ''},
/**
* Indicates if the cancel button will be rendered inside the busy dialog. The default value is set to <code>false</code>.
*/
showCancelButton: {type: "boolean", group: "Appearance", defaultValue: false},
/**
* Specifies the Title alignment (theme specific).
* If set to <code>TitleAlignment.Auto</code>, the Title will be aligned as it is set in the theme (if not set, the default value is <code>center</code>);
* Other possible values are <code>TitleAlignment.Start</code> (left or right depending on LTR/RTL), and <code>TitleAlignment.Center</code> (centered)
* @since 1.72
* @public
*/
titleAlignment : {type : "sap.m.TitleAlignment", group : "Misc", defaultValue : TitleAlignment.Auto}
},
associations: {
/**
* Association to controls / IDs which label this control (see WAI-ARIA attribute aria-labelledby).
*/
ariaLabelledBy: {type: "sap.ui.core.Control", multiple: true, singularName: "ariaLabelledBy"}
},
events: {
/**
* Fires when the busy dialog is closed. Note: the BusyDialog will not be closed by the InstanceManager.closeAllDialogs method
*/
close: {
parameters: {
/**
* Indicates if the close events are triggered by a user, pressing a cancel button or because the operation was terminated.
* This parameter is set to true if the close event is fired by user interaction.
*/
cancelPressed: {type: "boolean"}
}
}
},
designtime: "sap/m/designtime/BusyDialog.designtime"
},
// requires a dummy render function to avoid loading of separate
// renderer file and in case of usage in control tree a render
// function has to be available to not crash the rendering
renderer: {
apiVersion: 2,
render: function(oRm, oControl) { /* just do nothing */ }
}
});
/**
* Initiates the BusyDialog.
* @private
*/
BusyDialog.prototype.init = function () {
/**
* Creates a busyIndicator for the dialog.
* @private
*/
this._busyIndicator = new BusyIndicator(this.getId() + '-busyInd', {
visible: true
});
/**
* Creates the dialog with its class.
* @private
*/
this._oDialog = new Dialog(this.getId() + '-Dialog', {
content: this._busyIndicator,
titleAlignment: this.getTitleAlignment(),
showHeader: false,
afterClose: this._fnCloseHandler.bind(this),
initialFocus: this._busyIndicator.getId() + '-busyIndicator'
}).addStyleClass('sapMBusyDialog');
/**
* Overrides the close method, so the BusyDialog won't get closed by the InstanceManager.closeAllDialogs method.
* @method
* @private
*/
this._oDialog.close = function () {
};
/**
* Adds onBeforeRendering to the dialog.
*/
this._oDialog.addEventDelegate({
onBeforeRendering: function () {
var text = this.getText(),
title = this.getTitle(),
showCancelButton = this.getShowCancelButton() || this.getCancelButtonText();
if (!text && !title && !showCancelButton) {
this._oDialog.addStyleClass('sapMBusyDialog-Light');
} else {
this._oDialog.removeStyleClass('sapMBusyDialog-Light');
}
}
}, this);
/**
* Adds keyboard handling for the popup in the dialog. it's used for closing the popup.
* @method
* @public
* @param {Event} e Expected keyboard event.
*/
this._oDialog.oPopup.onsapescape = function (e) {
this.close(true);
}.bind(this);
};
/**
* Destroys the BusyDialog.
* @private
*/
BusyDialog.prototype.exit = function () {
if (this._iOpenTimer) {
clearTimeout(this._iOpenTimer);
this._iOpenTimer = null;
}
/**
* Destroys the busyIndicator and nullifies it.
*/
this._busyIndicator.destroy();
this._busyIndicator = null;
if (this._cancelButton) {
this._cancelButton.destroy();
this._cancelButton = null;
}
if (this._oLabel) {
this._oLabel.destroy();
this._oLabel = null;
}
if (this._oDialog) {
this._oDialog.destroy();
this._oDialog = null;
}
};
/**
* Opens the BusyDialog.
*
* @public
* @returns {this} BusyDialog reference for chaining.
*/
BusyDialog.prototype.open = function () {
Log.debug("sap.m.BusyDialog.open called at " + Date.now());
//if the code is not ready yet (new sap.m.BusyDialog().open()) wait 50ms and then try ot open it.
if (!document.body) {
this._iOpenTimer = setTimeout(function () {
this.open();
}.bind(this), 50);
return this;
}
var aAriaLabelledBy = this.getAriaLabelledBy();
if (aAriaLabelledBy && aAriaLabelledBy.length) {
if (!this._oDialog._$dialog) {
var that = this;
aAriaLabelledBy.forEach(function (item) {
that._oDialog.addAriaLabelledBy(item);
});
}
} else if (!this._oDialog.getShowHeader()) {
this._oDialog.addAriaLabelledBy(InvisibleText.getStaticId("sap.m", "BUSYDIALOG_TITLE"));
}
this._oDialog.open();
return this;
};
/**
* Closes the BusyDialog.
*
* @public
* @param {boolean} [isClosedFromUserInteraction] Indicates if the BusyDialog is closed from a user interaction.
* @returns {this} The modified BusyDialog.
*/
BusyDialog.prototype.close = function (isClosedFromUserInteraction) {
this._isClosedFromUserInteraction = isClosedFromUserInteraction;
if (this._iOpenTimer) {
clearTimeout(this._iOpenTimer);
this._iOpenTimer = null;
}
// the instance "close" method is overridden,
// so call the prototype close method
Dialog.prototype.close.call(this._oDialog);
return this;
};
/**
* Fire close of the BusyDialog only after the Dialog close is fired.
*
* @private
*/
BusyDialog.prototype._fnCloseHandler = function () {
//fire the close event with 'cancelPressed' = true/false depending on how the busyDialog is closed
this.fireClose({cancelPressed: this._isClosedFromUserInteraction || false});
if (this._oDialog) {
this._oDialog.removeAllAriaLabelledBy();
}
};
/**
* Sets the title for the BusyDialog.
*
* @public
* @param {string} sTitle The title for the BusyDialog.
* @returns {this} BusyDialog reference for chaining.
*/
BusyDialog.prototype.setTitle = function (sTitle) {
//the text can be changed only before opening
this.setProperty('title', sTitle, true);
this._oDialog.setTitle(sTitle).setShowHeader(!!sTitle);
return this;
};
BusyDialog.prototype.setTitleAlignment = function (sAlignment) {
this.setProperty("titleAlignment", sAlignment, true);
if (this._oDialog) {
this._oDialog.setTitleAlignment(sAlignment);
}
return this;
};
/**
* Sets the tooltip for the BusyDialog.
*
* @public
* @param {string} sTooltip The tooltip for the BusyDialog.
* @returns {this} BusyDialog reference for chaining.
*/
BusyDialog.prototype.setTooltip = function (sTooltip) {
this._oDialog.setTooltip(sTooltip);
return this;
};
/**
* Gets the tooltip of the BusyDialog.
*
* @public
* @return {string|sap.ui.core.TooltipBase} The tooltip of the BusyDialog.
* @override
*/
BusyDialog.prototype.getTooltip = function () {
return this._oDialog.getTooltip();
};
/**
* Sets the text for the BusyDialog.
*
* @public
* @param {string} sText The text for the BusyDialog.
* @returns {this} BusyDialog reference for chaining.
*/
BusyDialog.prototype.setText = function (sText) {
//the text can be changed only before opening
this.setProperty('text', sText, true);
if (!this._oLabel) {
if (sText) {
this._oLabel = new Label(this.getId() + '-TextLabel', {text: sText}).addStyleClass('sapMBusyDialogLabel');
this._oDialog.insertAggregation('content', this._oLabel, 0);
if (this._oDialog.getShowHeader()) {
this._oDialog.addAriaLabelledBy(this._oLabel.getId());
}
}
} else {
if (sText) {
this._oLabel.setText(sText).setVisible(true);
} else {
this._oLabel.setVisible(false);
}
}
return this;
};
/**
* Sets custom icon.
*
* @public
* @param {sap.ui.core.URI} sIcon Icon to use as a busy animation.
* @returns {this} BusyDialog reference for chaining.
*/
BusyDialog.prototype.setCustomIcon = function (sIcon) {
this.setProperty("customIcon", sIcon, true);
this._busyIndicator.setCustomIcon(sIcon);
return this;
};
/**
* Sets the rotation speed of the custom icon.
*
* @public
* @param {int} iSpeed Defines the rotation speed of the given image.
* @returns {this} BusyDialog reference for chaining.
*/
BusyDialog.prototype.setCustomIconRotationSpeed = function (iSpeed) {
this.setProperty("customIconRotationSpeed", iSpeed, true);
this._busyIndicator.setCustomIconRotationSpeed(iSpeed);
return this;
};
/**
* Sets the density of the custom icon.
*
* @public
* @param {boolean} bIsDensityAware Determines if the source image will be loaded directly without attempting to fetch the density for high density devices.
* @returns {this} BusyDialog reference for chaining.
*/
BusyDialog.prototype.setCustomIconDensityAware = function (bIsDensityAware) {
this.setProperty("customIconDensityAware", bIsDensityAware, true);
this._busyIndicator.setCustomIconDensityAware(bIsDensityAware);
return this;
};
/**
* Sets the width of the custom icon.
*
* @public
* @param {sap.ui.core.CSSSize} sWidth Width of the provided icon in CSSSize.
* @returns {this} BusyDialog reference for chaining.
*/
BusyDialog.prototype.setCustomIconWidth = function (sWidth) {
this.setProperty("customIconWidth", sWidth, true);
this._busyIndicator.setCustomIconWidth(sWidth);
return this;
};
/**
* Sets the height of the custom icon.
*
* @public
* @param {sap.ui.core.CSSSize} sHeight Height of the provided icon in CSSSize.
* @returns {this} BusyDialog reference for chaining.
*/
BusyDialog.prototype.setCustomIconHeight = function (sHeight) {
this.setProperty("customIconHeight", sHeight, true);
this._busyIndicator.setCustomIconHeight(sHeight);
return this;
};
/**
* Shows the cancel button.
*
* @public
* @param {boolean} bIsCancelButtonShown Determines if the Cancel button is shown.
* @returns {this} BusyDialog reference for chaining.
*/
BusyDialog.prototype.setShowCancelButton = function (bIsCancelButtonShown) {
this.setProperty("showCancelButton", bIsCancelButtonShown, false);
if (bIsCancelButtonShown) {
this._oDialog.setEndButton(this._getCancelButton());
} else {
this._destroyTheCancelButton();
}
return this;
};
/**
* Shows the text for the cancel button.
*
* @public
* @param {string} sText Text for the cancel button.
* @returns {this} The modified BusyDialog.
*/
BusyDialog.prototype.setCancelButtonText = function (sText) {
this.setProperty("cancelButtonText", sText, false);
if (sText) {
this._getCancelButton().setText(sText);
this._oDialog.setEndButton(this._getCancelButton());
} else {
this._destroyTheCancelButton();
}
return this;
};
/**
* Gets the DOM reference for the BusyDialog.
*
* @public
* @returns {Element} Dom reference.
*/
BusyDialog.prototype.getDomRef = function () {
return this._oDialog && this._oDialog.getDomRef();
};
//Forward methods to the inner dialog: addStyleClass, removeStyleClass, hasStyleClass, toggleStyleClass
["addStyleClass", "removeStyleClass", "toggleStyleClass", "hasStyleClass"].forEach(function (sActionName) {
BusyDialog.prototype[sActionName] = function () {
if (this._oDialog && this._oDialog[sActionName]) {
this._oDialog[sActionName].apply(this._oDialog, arguments);
return this;
}
};
});
//private functions
/**
* Destroys the cancel button.
*
* @private
*/
BusyDialog.prototype._destroyTheCancelButton = function () {
this._oDialog.destroyEndButton();
this._cancelButton = null;
};
/**
* Gets the cancel button.
*
* @private
* @returns {sap.m.Button} The cancel button in the BusyDialog.
*/
BusyDialog.prototype._getCancelButton = function () {
var cancelButtonText = this.getCancelButtonText();
cancelButtonText = cancelButtonText ? cancelButtonText : Library.getResourceBundleFor("sap.m").getText("BUSYDIALOG_CANCELBUTTON_TEXT");
// eslint-disable-next-line no-return-assign
return this._cancelButton ? this._cancelButton : this._cancelButton = new Button(this.getId() + 'busyCancelBtn', {
text: cancelButtonText,
press: function () {
this.close(true);
}.bind(this)
});
};
return BusyDialog;
}
);