@openui5/sap.m
Version:
OpenUI5 UI Library sap.m
785 lines (658 loc) • 21.9 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.QuickViewPage
sap.ui.define([
"./library",
"sap/ui/core/Control",
"sap/ui/core/IconPool",
"sap/ui/core/Lib",
"sap/ui/layout/form/SimpleForm",
"sap/ui/layout/VerticalLayout",
"sap/ui/layout/HorizontalLayout",
"sap/m/Avatar",
"sap/m/Page",
"sap/m/Button",
"sap/m/Bar",
"sap/m/Title",
"sap/m/Link",
"sap/m/Text",
"sap/m/Label",
"sap/m/HBox",
"sap/ui/core/Icon",
"sap/ui/core/Title",
"sap/ui/core/CustomData",
"sap/ui/core/library",
"sap/ui/layout/library",
"sap/ui/Device",
"sap/ui/layout/form/ResponsiveGridLayout",
"./QuickViewPageRenderer",
"sap/base/Log",
"sap/base/security/encodeURL",
"sap/ui/dom/jquery/Focusable" // jQuery Plugin "firstFocusableDomRef"
], function (
library,
Control,
IconPool,
Library,
SimpleForm,
VerticalLayout,
HorizontalLayout,
Avatar,
Page,
Button,
Bar,
Title,
Link,
Text,
Label,
HBox,
Icon,
CoreTitle,
//SimpleForm is loading ResponsiveGridLayout too late, only need as a dependency
CustomData,
coreLibrary,
layoutLibrary,
Device,
ResponsiveGridLayout,
QuickViewPageRenderer,
Log,
encodeURL
) {
"use strict";
// shortcut for sap.m.URLHelper
var URLHelper = library.URLHelper;
// shortcut for sap.ui.layout.form.SimpleFormLayout
var SimpleFormLayout = layoutLibrary.form.SimpleFormLayout;
// shortcut for sap.ui.core.TitleLevel
var CoreTitleLevel = coreLibrary.TitleLevel;
// shortcut for sap.m.QuickViewGroupElementType
var QuickViewGroupElementType = library.QuickViewGroupElementType;
// shortcut for sap.m.ButtonType
var ButtonType = library.ButtonType;
// shortcut for sap.m.AvatarShape
var AvatarShape = library.AvatarShape;
// shortcut for sap.m.EmptyIndicatorMode
var EmptyIndicatorMode = library.EmptyIndicatorMode;
var oRB = Library.getResourceBundleFor('sap.m');
// shortcut for sap.m.PageBackgroundDesign
var PageBackgroundDesign = library.PageBackgroundDesign;
/**
* Constructor for a new QuickViewPage.
*
* @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 QuickViewPage consists of a page header, an avatar,
* an object name with short description, and an object information divided in groups.
* The control uses the sap.ui.layout.form.SimpleForm control to display information.
*
* @extends sap.ui.core.Control
*
* @author SAP SE
* @version 1.146.0
*
* @constructor
* @public
* @since 1.28.11
* @alias sap.m.QuickViewPage
*/
var QuickViewPage = Control.extend("sap.m.QuickViewPage", /** @lends sap.m.QuickViewPage.prototype */ {
metadata: {
library: "sap.m",
properties: {
/**
* Page id
*/
pageId: { type: "string", group: "Misc", defaultValue: "" },
/**
* Specifies the text displayed in the header of the control.
*/
header: { type: "string", group: "Misc", defaultValue: "" },
/**
* Specifies the text displayed in the header of the content section of the control.
*/
title: { type: "string", group: "Misc", defaultValue: "" },
/**
* Specifies the URL which opens when the title or the avatar is clicked.
* <b>Note:</b> If the avatar has <code>press</code> listeners this URL is not opened automatically.
*/
titleUrl: { type: "string", group: "Misc", defaultValue: "" },
/**
* Specifies the application which provides target and param configuration for cross-application navigation from the 'page header'.
* @deprecated As of version 1.111. Attach listener to the avatar <code>press</code> event and perform navigation as appropriate in your environment instead.
*/
crossAppNavCallback: { type: "object", group: "Misc", deprecated: true },
/**
* Specifies the text displayed under the header of the content section.
*/
description: { type: "string", group: "Misc", defaultValue: "" },
/**
* Specifies the URL of the icon or image displayed under the header of the page.
* @deprecated As of version 1.92. Use the <code>avatar</code> aggregation instead.
*/
icon: { type: "string", group: "Misc", defaultValue: "", deprecated: true },
/**
* Defines the fallback icon displayed in case of wrong image src or loading issues.
*
* <b>Note:</b> Accepted values are only icons from the SAP icon font.
* @deprecated As of version 1.92. Use the <code>avatar</code> aggregation and use its property <code>fallbackIcon</code> instead.
* @since 1.69
*/
fallbackIcon: { type: "sap.ui.core.URI", group: "Appearance", defaultValue: null, deprecated: true }
},
defaultAggregation: "groups",
aggregations: {
/**
* QuickViewGroup consists of a title (optional) and an entity of group elements.
*/
groups: { type: "sap.m.QuickViewGroup", multiple: true, singularName: "group", bindable: "bindable" },
/**
* Specifies the avatar displayed under the header of the page.
* <b>Note:</b> To achieve the recommended design and behavior don't use the
* <code>displaySize</code>, <code>customDisplaySize</code>, <code>customFontSize</code> properties
* and <code>detailBox</code> aggregation of <code>sap.m.Avatar</code>.
* @since 1.92
*/
avatar: { type: "sap.m.Avatar", multiple: false, bindable: "bindable" }
}
},
renderer: QuickViewPageRenderer
});
/**
* Sets a new value for property {@link #setCrossAppNavCallback crossAppNavCallback}.
*
* Specifies the application which provides target and param configuration for cross-application navigation from the 'page header'.
*
* When called with a value of <code>null</code> or <code>undefined</code>, the default value of the property will be restored.
* @deprecated As of version 1.111. Attach listener to the avatar <code>press</code> event and perform navigation as appropriate in your environment instead.
* @method
* @param {function(): {target: object, params: object}} [oCrossAppNavCallback] New value for property <code>crossAppNavCallback</code>
* @public
* @name sap.m.QuickViewPage#setCrossAppNavCallback
* @returns {this} Reference to <code>this</code> in order to allow method chaining
*/
/**
* Gets current value of property {@link #getCrossAppNavCallback crossAppNavCallback}.
*
* Specifies the application which provides target and param configuration for cross-application navigation from the 'page header'.
* @deprecated As of version 1.111. Attach listener to the avatar <code>press</code> event and perform navigation as appropriate in your environment instead.
* @method
* @returns {function(): {target: object, params: object}} Value of property <code>crossAppNavCallback</code>
* @public
* @name sap.m.QuickViewPage#getCrossAppNavCallback
*/
/**
* @deprecated As of version 1.111.
*/
QuickViewPage.prototype._initCrossAppNavigationService = function() {
//see API docu for sap.ushell.services.CrossApplicationNavigation
var fGetService = sap.ushell && sap.ushell.Container && sap.ushell.Container.getService;
if (fGetService) {
this.oCrossAppNavigator = fGetService("CrossApplicationNavigation");
}
};
QuickViewPage.prototype.exit = function() {
if (this._oPage) {
this._oPage.destroy();
this._oPage = null;
} else {
this._destroyPageContent();
}
this._mNavContext = null;
};
/**
* Called before the control is rendered.
* @private
*/
QuickViewPage.prototype.onBeforeRendering = function() {
this._destroyPageContent();
this._createPageContent();
};
/**
* Returns page content containing the header and the form.
* @private
* @returns {Object} Object containing the header and the form
*/
QuickViewPage.prototype.getPageContent = function() {
return this._mPageContent;
};
/**
* Sets context containing navigation information.
* @param {Object} context Object containing specific navigation data.
* @private
*/
QuickViewPage.prototype.setNavContext = function (context) {
this._mNavContext = context;
};
/**
* Returns context containing navigation information.
* @private
* @returns {Object} Object containing specific navigation data
*/
QuickViewPage.prototype.getNavContext = function () {
return this._mNavContext;
};
/**
* Sets page title control.
* @param {sap.ui.core.Control} title The control that is displayed in the title of the page.
* @private
*/
QuickViewPage.prototype.setPageTitleControl = function (title) {
this._oPageTitle = title;
};
/**
* Returns page title control.
* @private
* @returns {sap.ui.core.Control} The control displayed in the title
*/
QuickViewPage.prototype.getPageTitleControl = function () {
return this._oPageTitle;
};
/**
* Helper function that creates a new {@link sap.m.Page} and adds content to it.
* @returns {sap.m.Page} The created page
* @private
*/
QuickViewPage.prototype._createPage = function () {
var mPageContent = this._createPageContent();
var mNavContext = this.getNavContext();
var oPage;
if (this._oPage) {
oPage = this._oPage;
oPage.destroyContent();
oPage.setCustomHeader(new Bar());
} else {
oPage = this._oPage = new Page(mNavContext.quickViewId + '-' + this.getPageId(), {
customHeader : new Bar(),
backgroundDesign: PageBackgroundDesign.Transparent
});
oPage.addEventDelegate({
onAfterRendering: this.onAfterRenderingPage
}, this);
}
//When there is only a single page in QuickView and no header set the header should be removed and device is not a phone
if (this.getHeader() === "" && mNavContext.quickView.getPages().length === 1 && !Device.system.phone) {
oPage.setShowHeader(false);
oPage.addStyleClass('sapMQuickViewPageWithoutHeader');
}
if (mPageContent.header) {
oPage.addContent(mPageContent.header);
}
oPage.addContent(mPageContent.form);
var oCustomHeader = oPage.getCustomHeader();
oCustomHeader.addContentMiddle(
new Title({
text : this.getHeader()
}).addStyleClass("sapMQuickViewTitle")
);
if (mNavContext.hasBackButton) {
oCustomHeader.addContentLeft(
new Button({
type : ButtonType.Back,
tooltip : oRB.getText("PAGE_NAVBUTTON_TEXT"),
press : function() {
if (mNavContext.navContainer) {
mNavContext.quickView._setNavOrigin(null);
mNavContext.navContainer.back();
}
}
})
);
}
if (mNavContext.popover && Device.system.phone) {
oCustomHeader.addContentRight(
new Button({
icon : IconPool.getIconURI("decline"),
press : function() {
mNavContext.popover.close();
}
})
);
}
oPage.addStyleClass('sapMQuickViewPage');
return oPage;
};
QuickViewPage.prototype.onAfterRenderingPage = function () {
var oParent = this.getParent(),
bIsInsideQuickView = oParent instanceof Control && oParent.isA('sap.m.QuickView');
// add tabindex=0, so the content can be scrolled with the keyboard
// jQuery Plugin "firstFocusableDomRef"
if (bIsInsideQuickView && !this._oPage.$().firstFocusableDomRef()) {
this._oPage.$('cont').attr('tabindex', 0);
}
if (this._bItemsChanged) {
var mNavContext = this.getNavContext();
if (mNavContext) {
mNavContext.quickView._restoreFocus();
}
this._bItemsChanged = false;
}
};
/**
* Helper function that creates the content of a QuickViewPage and returns it as an object
* with form and header properties.
* @returns {{form: sap.ui.layout.form.SimpleForm, header: sap.ui.layout.HorizontalLayout}}
* @private
*/
QuickViewPage.prototype._createPageContent = function () {
var oForm = this._createForm();
var oHeader = this._getPageHeaderContent();
// add ARIA title to the form
var oPageTitleControl = this.getPageTitleControl();
if (oHeader && oPageTitleControl) {
oForm.addAriaLabelledBy(oPageTitleControl);
}
this._mPageContent = {
form: oForm,
header: oHeader
};
return this._mPageContent;
};
/**
* Helper function that creates a form object based on the data in the groups of the QuickViewPage
* @returns {sap.ui.layout.form.SimpleForm} The form created based on the groups of the QuickViewPage
* @private
*/
QuickViewPage.prototype._createForm = function () {
var aGroups = this.getAggregation("groups"),
oForm = new SimpleForm({
maxContainerCols: 1,
editable: false,
layout: SimpleFormLayout.ResponsiveGridLayout
});
if (aGroups) {
for (var j = 0; j < aGroups.length; j++) {
if (aGroups[j].getVisible()) {
this._renderGroup(aGroups[j], oForm);
}
}
}
return oForm;
};
/**
* Helper function that creates the header of the QuickViewPage.
* @returns {sap.ui.layout.HorizontalLayout|null} The header of the QuickViewPage
* @private
*/
QuickViewPage.prototype._getPageHeaderContent = function() {
var oAvatar = this._getAvatar(),
oVLayout = new VerticalLayout(),
oHLayout = new HorizontalLayout(),
sTitle = this.getTitle(),
sDescription = this.getDescription(),
sTitleUrl = this.getTitleUrl(),
oTitle,
oDescription;
if (oAvatar && oAvatar.getVisible()) {
oHLayout.addContent(oAvatar);
}
if (sTitleUrl && sTitle) {
oTitle = new Link({
text: sTitle,
href: sTitleUrl,
target: "_blank"
});
} else if (sTitle) {
oTitle = new Title({
text: sTitle,
level: CoreTitleLevel.H3
});
/**
* @deprecated As of version 1.111.
*/
if (this.getCrossAppNavCallback()) {
oTitle.destroy();
oTitle = new Link({
text: sTitle
});
oTitle.attachPress(this._crossApplicationNavigation.bind(this));
}
}
this.setPageTitleControl(oTitle);
if (sDescription) {
oDescription = new Text({
text: sDescription,
maxLines: 2
});
}
if (oTitle) {
oVLayout.addContent(oTitle);
}
if (oDescription) {
oVLayout.addContent(oDescription);
}
if (oVLayout.getContent().length) {
oHLayout.addContent(oVLayout);
} else {
oVLayout.destroy();
}
if (oHLayout.getContent().length) {
return oHLayout;
}
oHLayout.destroy();
return null;
};
/**
* Helper function that renders a QuickViewGroup in the QuickViewPage.
* @param {sap.m.QuickViewGroup} oGroup The group to be rendered.
* @param {sap.ui.layout.form.SimpleForm} oForm The form in which the group is rendered
* @private
*/
QuickViewPage.prototype._renderGroup = function(oGroup, oForm) {
var aElements = oGroup.getAggregation("elements");
var oCurrentGroupElement,
oCurrentGroupElementValue,
oLabel;
if (oGroup.getHeading()) {
oForm.addContent(new CoreTitle({
text: oGroup.getHeading(),
level: CoreTitleLevel.H4
}));
}
if (!aElements) {
return;
}
var mNavContext = this.getNavContext();
for (var k = 0; k < aElements.length; k++) {
oCurrentGroupElement = aElements[k];
if (!oCurrentGroupElement.getVisible()) {
continue;
}
oLabel = new Label({
text: oCurrentGroupElement.getLabel()
});
var sQuickViewId;
if (mNavContext) {
sQuickViewId = mNavContext.quickViewId;
}
oCurrentGroupElementValue = oCurrentGroupElement._getGroupElementValue(sQuickViewId);
oForm.addContent(oLabel);
if (!oCurrentGroupElementValue) {
// Add dummy text element so that the form renders the oLabel
oForm.addContent(new Text({text : "", emptyIndicatorMode: EmptyIndicatorMode.On}));
continue;
}
oLabel.setLabelFor(oCurrentGroupElementValue.getId());
if (oCurrentGroupElement.getType() == QuickViewGroupElementType.pageLink) {
oCurrentGroupElementValue.attachPress(this._attachPressLink(this));
}
if (oCurrentGroupElement.getType() == QuickViewGroupElementType.mobile &&
!Device.system.desktop) {
var oSmsLink = new Icon({
src: IconPool.getIconURI("post"),
tooltip : oRB.getText("QUICKVIEW_SEND_SMS"),
decorative : false,
customData: [new CustomData({
key: "phoneNumber",
value: oCurrentGroupElement.getValue()
})],
press: this._mobilePress
});
var oBox = new HBox({
items: [oCurrentGroupElementValue, oSmsLink]
});
oForm.addContent(oBox);
} else {
oForm.addContent(oCurrentGroupElementValue);
}
}
};
/**
* Helper function used to navigate to another Fiori application (intent based navigation) or
* to an external link.
* This will be applicable only for the header link.
* @private
*/
QuickViewPage.prototype._crossApplicationNavigation = function () {
/**
* @deprecated As of version 1.111.
*/
if (this.getCrossAppNavCallback()) {
this._initCrossAppNavigationService();
if (this.oCrossAppNavigator) {
var targetConfigCallback = this.getCrossAppNavCallback();
if (typeof targetConfigCallback == "function") {
var targetConfig = targetConfigCallback();
var href = this.oCrossAppNavigator.hrefForExternal(
{
target : {
semanticObject : targetConfig.target.semanticObject,
action : targetConfig.target.action
},
params : targetConfig.params
}
);
URLHelper.redirect(href);
}
return;
}
}
if (this.getTitleUrl()) {
URLHelper.redirect(this.getTitleUrl(), true);
}
};
QuickViewPage.prototype._destroyPageContent = function() {
if (!this._mPageContent) {
return;
}
if (this._mPageContent.form) {
this._mPageContent.form.destroy();
}
if (this._mPageContent.header) {
this._mPageContent.header.destroy();
}
this._mPageContent = null;
};
/**
* Helper function used to attach click handler to links in the QuickViewPage
* that should lead to another QuickViewPage.
* @param {sap.m.QuickViewPage} that The page from which the navigation occurs.
* @returns {Function} A function executed when the link is clicked
* @private
*/
QuickViewPage.prototype._attachPressLink = function (that) {
var mNavContext = that.getNavContext();
return function (oEvent) {
oEvent.preventDefault();
var sPageId = this.getCustomData()[0].getValue();
if (mNavContext.navContainer && sPageId) {
mNavContext.quickView._setNavOrigin(this);
mNavContext.navContainer.to(sPageId);
}
};
};
/**
* Function executed when the sms icon in the QuickViewPage is clicked.
* @private
*/
QuickViewPage.prototype._mobilePress = function () {
var sms = "sms://" + encodeURL(this.getCustomData()[0].getValue());
window.location.replace(sms);
};
/**
* Updates the contents of the page and sets the focus on the last focused element or
* on the first focusable element.
* @private
*/
QuickViewPage.prototype._updatePage = function () {
var mNavContext = this.getNavContext();
if (mNavContext && mNavContext.quickView._bRendered) {
this._bItemsChanged = true;
mNavContext.popover.focus();
if (mNavContext.quickView.indexOfPage(this) == 0) {
mNavContext.quickView._clearContainerHeight();
}
this._createPage();
// in some cases the popover has display:none style here,
// which delays the simple form re-arranging and an unwanted scrollbar might appear.
mNavContext.popover.$().css('display', 'block');
mNavContext.quickView._adjustContainerHeight();
mNavContext.quickView._restoreFocus();
}
};
["setModel", "bindAggregation", "setAggregation", "insertAggregation", "addAggregation",
"removeAggregation", "removeAllAggregation", "destroyAggregation"].forEach(function (sFuncName) {
QuickViewPage.prototype[sFuncName] = function () {
var result = Control.prototype[sFuncName].apply(this, arguments);
this._updatePage();
if (["removeAggregation", "removeAllAggregation"].indexOf(sFuncName) !== -1) {
return result;
}
return this;
};
});
QuickViewPage.prototype.setProperty = function () {
Control.prototype.setProperty.apply(this, arguments);
this._updatePage();
return this;
};
QuickViewPage.prototype.getQuickViewBase = function () {
var oParent = this.getParent();
if (oParent && oParent.isA("sap.m.QuickViewBase")) {
return oParent;
}
return null;
};
QuickViewPage.prototype._getAvatar = function () {
var oAvatar = null,
sIcon = this.getIcon && this.getIcon();
if (this.getAvatar()) {
// Copy the values of properties directly, don't clone bindings,
// as this avatar and the whole NavContainer are not aggregated by the real QuickViewPage
oAvatar = this.getAvatar().clone(null, null, { cloneBindings: false, cloneChildren: true });
this._checkAvatarProperties(oAvatar);
} else if (sIcon && this.getFallbackIcon) {
oAvatar = new Avatar({
displayShape: AvatarShape.Square,
fallbackIcon: this.getFallbackIcon(),
src: sIcon
});
}
if (oAvatar) {
if (this.getTitleUrl() && !oAvatar.hasListeners("press")) {
oAvatar.attachPress(this._crossApplicationNavigation.bind(this));
}
oAvatar.addStyleClass("sapMQuickViewThumbnail");
}
return oAvatar;
};
QuickViewPage.prototype._checkAvatarProperties = function (oAvatar) {
var mDefaults = oAvatar.getMetadata().getPropertyDefaults();
if (oAvatar.getDisplaySize() !== mDefaults["displaySize"]) {
Log.warning("'displaySize' property of avatar shouldn't be used in sap.m.QuickViewPage");
}
if (oAvatar.getCustomDisplaySize() !== mDefaults["customDisplaySize"]) {
Log.warning("'customDisplaySize' property of avatar shouldn't be used in sap.m.QuickViewPage");
}
if (oAvatar.getCustomFontSize() !== mDefaults["customFontSize"]) {
Log.warning("'customFontSize' property of avatar shouldn't be used in sap.m.QuickViewPage");
}
if (oAvatar.getDetailBox()) {
Log.warning("'detailBox' aggregation of avatar shouldn't be used in sap.m.QuickViewPage");
}
};
return QuickViewPage;
});