@openui5/sap.m
Version:
OpenUI5 UI Library sap.m
1,412 lines (1,214 loc) • 45.4 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/core/Control',
'sap/ui/core/library',
'sap/m/library',
'sap/ui/Device',
"sap/base/Log",
'sap/m/Link',
'sap/m/Text',
"sap/ui/thirdparty/jquery",
"sap/ui/util/defaultLinkTypes",
"sap/ui/core/Configuration"
],
function(Control, coreLibrary, library, Device, Log, Link, Text, jQuery, defaultLinkTypes, Configuration) {
"use strict";
// shortcut for sap.ui.core.TextDirection
var TextDirection = coreLibrary.TextDirection;
// shortcut for sap.m.BackgroundDesign
var BackgroundDesign = library.BackgroundDesign;
// shortcut for sap.ui.core.TitleLevel
var TitleLevel = coreLibrary.TitleLevel;
/**
* ObjectHeader renderer.
* @namespace
*/
var ObjectHeaderRenderer = {
apiVersion: 2
};
/**
* Check if the object exists. In case object has _isEmpty() method then this method is called. If there is no such method then object is not empty.
*
* @param {sap.ui.core.Control} oObject to be checked
*
* @returns {boolean} true is the object is not empty, false - otherwise
* @private
*/
ObjectHeaderRenderer._isEmptyObject = function(oObject) {
if (!oObject) {
return true;
}
if ((!oObject._isEmpty || !oObject._isEmpty()) && (!oObject.getVisible || oObject.getVisible())) {
return false;
}
return true;
};
/**
* Array is considered empty if it is null or undefined or has no controls or all the controls are empty.
*
* @param {sap.ui.core.Control[]} aArray array of controls to be checked
*
* @returns {boolean} true if array is empty, false - otherwise
* @private
*/
ObjectHeaderRenderer._isEmptyArray = function(aArray) {
if (aArray) {
for (var i = 0; i < aArray.length; i++) {
if (!ObjectHeaderRenderer._isEmptyObject(aArray[i])) {
return false;
}
}
}
return true;
};
/**
* A row is considered empty if both input parameters are empty.
*
* @param {sap.m.ObjectAttribute} oLeft control to be checked
*
* @param {sap.ui.core.Control[]} aRight array of controls to be checked
*
* @returns {boolean} true if array is empty, false - otherwise
* @private
*/
ObjectHeaderRenderer._isEmptyRow = function(oLeft, aRight) {
return ObjectHeaderRenderer._isEmptyObject(oLeft) && ObjectHeaderRenderer._isEmptyArray(aRight);
};
/**
* Render an array of controls.
*
* @param {sap.ui.core.RenderManager} oRM the RenderManager that can be used for writing to the render output buffer
*
* @param {sap.ui.core.Control[]} aObjects array of controls to be renderer
*
* @param {sap.m.ObjectHeader} oOH the ObjectHeader
* @private
*/
ObjectHeaderRenderer._renderObjects = function(oRM, aObjects, oOH) {
for (var i = 0; i < aObjects.length; i++) {
if (aObjects[i] instanceof Control) {
this._renderChildControl(oRM, oOH, aObjects[i]);
}
}
};
/**
* Gather all controls that should be rendered inside Object Header.
*
* @param {sap.m.ObjectHeader} oOH the ObjectHeader
* @private
*/
ObjectHeaderRenderer._computeChildControlsToBeRendered = function(oOH){
oOH.__controlsToBeRendered = {};
var aChildren = oOH.getAttributes();
for (var i = 0; i < aChildren.length; i++) {
oOH.__controlsToBeRendered[aChildren[i].getId()] = aChildren[i];
}
aChildren = oOH.getStatuses();
for (var i = 0; i < aChildren.length; i++) {
oOH.__controlsToBeRendered[aChildren[i].getId()] = aChildren[i];
}
var oChild = oOH.getFirstStatus();
if (oChild) {
oOH.__controlsToBeRendered[oChild.getId()] = oChild;
}
oChild = oOH.getSecondStatus();
if (oChild) {
oOH.__controlsToBeRendered[oChild.getId()] = oChild;
}
oChild = oOH.getAggregation("_objectNumber");
if (oChild) {
oOH.__controlsToBeRendered[oChild.getId()] = oChild;
}
};
/**
* Delete all controls that were empty and were not rendered inside Object Header.
*
* @param {sap.ui.core.RenderManager} oRM the RenderManager that can be used for writing to the render output buffer
*
* @param {sap.m.ObjectHeader} oOH the ObjectHeader
* @private
*/
ObjectHeaderRenderer._cleanupNotRenderedChildControls = function(oRM, oOH){
for (var id in oOH.__controlsToBeRendered) {
oRM.cleanupControlWithoutRendering(oOH.__controlsToBeRendered[id]);
}
delete oOH.__controlsToBeRendered;
};
/**
* Returns the array of markers from ObjectHeader.
*
* @param {sap.m.ObjectHeader} oOH the ObjectHeader that contains markers
*
* @returns {sap.m.ObjectMarker[]} array of ObjectMarker controls
*
* @private
*/
ObjectHeaderRenderer._getMarkers = function(oOH) {
return oOH._getVisibleMarkers();
};
/**
* Render intro as sap.m.Text or sap.m.Link depending if it's active or not.
* used in both ObjectHeader and ObjectHeaderResponsive
*
* @param {sap.ui.core.RenderManager} oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader} oOH the ObjectHeader that contains icons
* @param {string} sIntroClass the css class of the intro container
* @param {string} sIntroActiveClass the css class of the intro container if the intro is active
* @private
*/
ObjectHeaderRenderer._renderIntro = function(oRM, oOH, sIntroClass, sIntroActiveClass) {
if (oOH.getIntroActive()) {
oOH._introText = new Link(oOH.getId() + "-intro");
oOH._introText.setText(oOH.getIntro());
oOH._introText.setHref(oOH.getIntroHref());
oOH._introText.setTarget(oOH.getIntroTarget());
oOH._introText.press = oOH.introPress;
} else {
oOH._introText = new Text(oOH.getId() + "-intro");
oOH._introText.setText(oOH.getIntro());
oOH._introText.setMaxLines(3);
}
// set text direction of the intro
oOH._introText.setTextDirection(oOH.getIntroTextDirection());
oRM.openStart("div");
oRM.class(sIntroClass);
if (oOH.getIntroActive()) {
oRM.class(sIntroActiveClass);
}
oRM.openEnd();
this._renderChildControl(oRM, oOH, oOH._introText);
oRM.close("div");
};
/**
* Renders the HTML for Attribute.
*
* @param {sap.ui.core.RenderManager}
* oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader}
* oOH an object to be rendered
* @param {sap.m.ObjectAttribute}
* oAttr an attribute to be rendered
* @param {boolean} bFullWidth set the attribute width to 100%
* @private
*/
ObjectHeaderRenderer._renderAttribute = function(oRM, oOH, oAttr, bFullWidth) {
oRM.openStart("div");
oRM.class("sapMOHAttr");
if (bFullWidth) {
oRM.style("width", "100%");
}
oRM.openEnd();
this._renderChildControl(oRM, oOH, oAttr);
oRM.close("div");
};
/**
* Validate the statuses control list to only display sap.m.ObjectStatus and
* sap.m.ProgressIndicator and returns only the visible once that should be rendered
*
* @param {sap.m.ObjectHeader} oOH an object to be rendered
* @returns {Array<sap.m.ObjectStatus|sap.m.ProgressIndicator>} The visible statuses
* @private
*/
ObjectHeaderRenderer._getVisibleStatuses = function(oOH) {
var aVisibleStatuses = [];
if (oOH.getFirstStatus() && oOH.getFirstStatus().getVisible()) {
aVisibleStatuses.push([oOH.getFirstStatus()]);
}
if (oOH.getSecondStatus() && oOH.getSecondStatus().getVisible()) {
aVisibleStatuses.push([oOH.getSecondStatus()]);
}
if (oOH.getStatuses()) {
var aStatuses = oOH.getStatuses();
for (var i = 0; i < aStatuses.length; i++) {
if (!aStatuses[i].getVisible || aStatuses[i].getVisible()) {
if ((aStatuses[i].isA("sap.m.ObjectStatus") && !aStatuses[i]._isEmpty()) || aStatuses[i].isA("sap.m.ProgressIndicator")) {
aVisibleStatuses.push([aStatuses[i]]);
} else {
Log.warning("Only sap.m.ObjectStatus or sap.m.ProgressIndicator are allowed in \"sap.m.ObjectHeader.statuses\" aggregation." + " Current object is "
+ aStatuses[i].constructor.getMetadata().getName() + " with id \"" + aStatuses[i].getId() + "\"");
}
}
}
}
return aVisibleStatuses;
};
/**
* Returns only the visible statuses and attributes that should be rendered
*
* @param {sap.m.ObjectHeader} oOH an object representation of the control that should be rendered
* @returns {array} The visible statuses and attributes
* @private
*/
ObjectHeaderRenderer._getVisibleAttribsAndStatuses = function(oOH) {
var aResult = [],
aAttribs = oOH.getAttributes(),
aVisibleAttribs = [];
for (var j = 0; j < aAttribs.length; j++) {
if (aAttribs[j].getVisible() && !aAttribs[j]._isEmpty()) {
aVisibleAttribs.push(aAttribs[j]);
}
}
var aVisibleStatuses = this._getVisibleStatuses(oOH);
aResult[0] = aVisibleAttribs;
aResult[1] = aVisibleStatuses;
return aResult;
};
/**
* Renders the HTML for single line of Attribute and Status.
*
* @param {sap.ui.core.RenderManager}
* oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader}
* oOH an object to be rendered
* @param {sap.m.ObjectAttribute}
* oLeft an attribute to be rendered
* @param {sap.ui.core.Control[]}
* aRight a status or Progress Indicator Array to be rendered
* @private
*/
ObjectHeaderRenderer._renderRow = function(oRM, oOH, oLeft, aRight) {
if (ObjectHeaderRenderer._isEmptyRow(oLeft, aRight)) {
return; // nothing to render
}
oRM.openStart("div"); // Start attribute row container
oRM.class("sapMOHAttrRow");
oRM.openEnd();
if (!ObjectHeaderRenderer._isEmptyObject(oLeft)) { // if the object with the attributes is not empty then render the attributes
this._renderAttribute(oRM, oOH, oLeft, ObjectHeaderRenderer._isEmptyArray(aRight));
} else if (ObjectHeaderRenderer._isEmptyObject(oLeft) && !ObjectHeaderRenderer._isEmptyArray(aRight)) {
// if there are no attributes at all and the array containing statuses and progress indicators isn't empty
if (aRight[0] && aRight[0].isA("sap.m.ProgressIndicator")) { // check if the first element in the array is progress indicator, and if it's so then place an empty "attribute" div before the progress indicator
oRM.openStart("div");
oRM.class("sapMOHAttr");
oRM.openEnd();
oRM.close("div");
}
}
if (!ObjectHeaderRenderer._isEmptyArray(aRight)) { // check do we have statuses, icons or progress indicators and render them accordingly
oRM.openStart("div");
if (aRight[0] && aRight[0].isA("sap.m.ProgressIndicator")) {
oRM.class("sapMOHStatusFixedWidth");
} else if (aRight[0] && aRight[0].isA("sap.m.ObjectMarker")) {
oRM.class("sapMOHStatusFixedWidth");
oRM.class("sapMObjStatusMarker");
} else {
oRM.class("sapMOHStatus");
}
oRM.openEnd();
ObjectHeaderRenderer._renderObjects(oRM, aRight, oOH);
oRM.close("div");
}
oRM.close("div"); // end attribute row container
};
/**
* Renders the HTML for attributes and statuses, using the provided {@link sap.ui.core.RenderManager}. Validate the statuses control list to only display ObjectStatus and
* ProgressIndicator
*
* @param {sap.ui.core.RenderManager}
* oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader}
* oOH an object to be rendered
* @private
*/
ObjectHeaderRenderer._renderAttributesAndStatuses = function(oRM, oOH) {
var aAttribs = oOH.getAttributes();
var aVisibleAttribs = [];
for (var j = 0; j < aAttribs.length; j++) {
if (aAttribs[j].getVisible()) {
aVisibleAttribs.push(aAttribs[j]);
}
}
var iAttribsLength = aVisibleAttribs.length;
var aMarkersAndStatuses = [];
var aMarkers = ObjectHeaderRenderer._getMarkers(oOH);
// flag and favorite are not rendered here in responsive mode
if (!oOH.getResponsive() && !ObjectHeaderRenderer._isEmptyArray(aMarkers)) {
aMarkersAndStatuses.push(aMarkers);
}
var aVisibleStatuses = this._getVisibleStatuses(oOH);
aMarkersAndStatuses = aMarkersAndStatuses.concat(aVisibleStatuses);
var iMarkersAndStatusesLength = aMarkersAndStatuses.length;
var iNoOfRows = iAttribsLength > iMarkersAndStatusesLength ? iAttribsLength : iMarkersAndStatusesLength;
if (!oOH.getResponsive()) {
for (var iCount = 0; iCount < iNoOfRows; iCount++) {
this._renderRow(oRM, oOH, aVisibleAttribs[iCount], aMarkersAndStatuses[iCount]);
}
}
};
/**
* Renders the HTML for the given control, using the provided {@link sap.ui.core.RenderManager}.
*
* @param {sap.ui.core.RenderManager}
* oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader}
* oOH an object representation of the control that should be rendered
* @private
*/
ObjectHeaderRenderer._renderNumber = function(oRM, oOH) {
var numbers = oOH.getAdditionalNumbers();
if (!oOH.getNumber() && (numbers && !numbers.length)) {
return;
}
// Container for a number and a units qualifier.
oRM.openStart("div", oOH.getId() + "-numberdiv"); // Start Number/units container
oRM.class("sapMOHNumberDiv");
oRM.openEnd();
var oObjectNumber = oOH.getAggregation("_objectNumber");
if (oObjectNumber && oObjectNumber.getNumber()) {
oObjectNumber.setTextDirection(oOH.getNumberTextDirection());
this._renderChildControl(oRM, oOH, oObjectNumber);
}
oRM.close("div"); // End Number/units container
if (!oOH.getCondensed()) {
this._renderAdditionalNumbers(oRM, oOH);
}
};
/**
* Renders the HTML for the provided in aggregation additionalNumbers {@link sap.ui.core.RenderManager}.
*
* @param {sap.ui.core.RenderManager}
* oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader}
* oOH an object representation of the ObjectHeader
* @private
*/
ObjectHeaderRenderer._renderAdditionalNumbers = function(oRM, oOH) {
var numbers = oOH.getAdditionalNumbers();
if (numbers && !numbers.length) {
return;
}
if (numbers.length === 1) {
oRM.openStart("div");
oRM.class("additionalOHNumberSeparatorDiv");
oRM.openEnd();
oRM.close("div");
}
for (var i = 0; i < numbers.length; i++) {
oRM.openStart("div", oOH.getId() + "-additionalNumber" + i);
oRM.class("sapMOHNumberDiv");
oRM.class("additionalOHNumberDiv");
if (numbers.length === 1) {
oRM.class("sapMOHOnlyANumber");
}
oRM.openEnd();
numbers[i].setTextDirection(oOH.getNumberTextDirection());
this._renderChildControl(oRM, oOH, numbers[i]);
oRM.close("div"); // End container
}
};
/**
* Renders the HTML for the given control, using the provided {@link sap.ui.core.RenderManager}.
*
* @param {sap.ui.core.RenderManager}
* oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader}
* oOH an object representation of the control that should be rendered
* @private
*/
ObjectHeaderRenderer._renderTitle = function(oRM, oOH) {
// Start title text and title arrow container
oOH._oTitleArrowIcon.setVisible(oOH.getShowTitleSelector());
if (oOH.getShowTitleSelector() && oOH._oTitleArrowIcon.getVisible()) {
oRM.openStart("div");
oRM.class("sapMOHTitleAndArrow");
oRM.openEnd();
}
if (oOH.getTitle()) {
var sTitleLevel = (oOH.getTitleLevel() === TitleLevel.Auto) ? TitleLevel.H1 : oOH.getTitleLevel();
sTitleLevel = sTitleLevel.toLowerCase();
oOH._titleText.setText(oOH.getTitle());
// set text direction of the title
oOH._titleText.setTextDirection(oOH.getTitleTextDirection());
if (oOH.getTitleActive()) {
oRM.openStart("a", oOH.getId() + "-title"); // Start Title Text container
if (oOH.getTitleHref()) { // if title is link write it
oRM.attr("href", oOH.getTitleHref());
if (oOH.getTitleTarget()) {
oRM.attr("target", oOH.getTitleTarget());
oRM.attr("rel", defaultLinkTypes('', oOH.getTitleTarget()));
}
}
//ARIA attributes
oRM.accessibilityState({
role: "link"
});
} else {
oRM.openStart("div", oOH.getId() + "-title"); // Start Title Text container
}
oRM.class("sapMOHTitle");
if (oOH.getTitleActive()) {
oRM.attr("tabindex", "0");
oRM.class("sapMOHTitleActive");
}
if (oOH.getShowTitleSelector()) {
oRM.class("sapMOHTitleFollowArrow");
}
oRM.openEnd();
oRM.openStart(sTitleLevel);
oRM.openEnd();
this._renderChildControl(oRM, oOH, oOH._titleText);
oRM.close(sTitleLevel);
if (oOH.getTitleActive()) {
oRM.close("a"); // End Title Text container
} else {
oRM.close("div"); // End Title Text container
}
}
if (oOH.getShowTitleSelector()) {
oRM.openStart("span"); // Start title arrow container
oRM.class("sapMOHTitleArrow");
oRM.openEnd();
this._renderChildControl(oRM, oOH, oOH._oTitleArrowIcon);
oRM.close("span"); // end title arrow container
}
if (oOH.getShowTitleSelector() && oOH._oTitleArrowIcon.getVisible()) {
oRM.close("div"); // end title text and title arrow container
}
};
/**
* Renders the HTML for the given control, using the provided {@link sap.ui.core.RenderManager}.
*
* @param {sap.ui.core.RenderManager}
* oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader}
* oOH an object representation of the control that should be rendered
* @private
*/
ObjectHeaderRenderer._renderFullTitle = function(oRM, oOH) {
var numbers = oOH.getAdditionalNumbers();
if (!oOH.getNumber() && (numbers && !numbers.length)) {
oRM.class("sapMOHTitleDivFull");
}
};
/**
* Renders the HTML for the given control, using the provided {@link sap.ui.core.RenderManager}.
*
* @param {sap.ui.core.RenderManager}
* oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader}
* oOH an object representation of the control that should be rendered
* @private
*/
ObjectHeaderRenderer._renderFullOH = function(oRM, oOH) {
// Introductory text at the top of the item, like "On behalf of Julie..."
if (oOH.getIntro()) {
this._renderIntro(oRM, oOH, "sapMOHIntro", "sapMOHIntroActive");
}
// Container for fields placed on the top half of the item, below the intro. This
// includes title icon, title, title arrow, number, and number units.
oRM.openStart("div"); // Start Top row container
oRM.class("sapMOHTopRow");
oRM.openEnd();
// Title container displayed to the left of the number and number units container.
oRM.openStart("div", oOH.getId() + "-titlediv"); // Start Title container
oRM.class("sapMOHTitleDiv");
if (oOH._hasIcon()) {
oRM.class("sapMOHTitleIcon");
}
this._renderFullTitle(oRM, oOH);
oRM.openEnd();
// Container for icon
if (oOH._hasIcon()) {
oRM.openStart("div"); // Start icon container
oRM.class("sapMOHIcon");
oRM.class('sapMOHIcon' + oOH.getImageShape());
if (oOH.getIconActive()) {
oRM.class("sapMPointer");
}
oRM.openEnd();
this._renderChildControl(oRM, oOH, oOH._getImageControl());
oRM.close("div"); // end icon container
}
this._renderTitle(oRM, oOH);
oRM.close("div"); // End Title container
this._renderNumber(oRM, oOH);
oRM.openStart("div");
oRM.class("sapMOHDivider");
oRM.openEnd();
oRM.close("div");
oRM.close("div"); // End Top row container
if (oOH._hasBottomContent()) {
oRM.openStart("div"); // Start Bottom row container
oRM.class("sapMOHBottomRow");
oRM.openEnd();
this._renderAttributesAndStatuses(oRM, oOH);
oRM.openStart("div");
oRM.class("sapMOHDivider");
oRM.openEnd();
oRM.close("div");
oRM.close("div"); // End Bottom row container
}
};
/**
* Renders the HTML for the given control, using the provided {@link sap.ui.core.RenderManager}.
*
* @param {sap.ui.core.RenderManager}
* oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader}
* oOH an object representation of the control that should be rendered
* @private
*/
ObjectHeaderRenderer._renderCondensedOH = function(oRM, oOH) {
// Title container displayed to the left of the number and number units container.
oRM.openStart("div", oOH.getId() + "-titlediv"); // Start Title container
oRM.class("sapMOHTitleDiv");
this._renderFullTitle(oRM, oOH);
oRM.openEnd();
this._renderTitle(oRM, oOH);
oRM.close("div"); // End Title container
this._renderNumber(oRM, oOH);
var oFirstAttr = oOH.getAttributes()[0];
if (oFirstAttr && !oFirstAttr._isEmpty()) {
this._renderAttribute(oRM, oOH, oFirstAttr);
}
};
/**
* Renders the HTML for the given control, using the provided {@link sap.ui.core.RenderManager}.
*
* @param {sap.ui.core.RenderManager}
* oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader}
* oOH an object representation of the control that should be rendered
*/
ObjectHeaderRenderer.render = function(oRM, oOH) {
// render responsive OH
if (oOH.getResponsive()) {
this._renderResponsive(oRM, oOH);
return;
}
// === old renderer, no changes here for downwards compatibility
this._computeChildControlsToBeRendered(oOH);
var bCondensed = oOH.getCondensed();
oRM.openStart("div", oOH);
oRM.openEnd();
oRM.openStart("div"); // Start Main container
oRM.class("sapMOH");
// set contrast container, only when the background is not transparent
if (oOH._getBackground() !== BackgroundDesign.Transparent) {
oRM.class("sapContrastPlus");
}
if (bCondensed) {
oRM.class("sapMOHC");
}
oRM.class("sapMOHBg" + oOH._getBackground());
var sTooltip = oOH.getTooltip_AsString();
if (sTooltip) {
oRM.attr("title", sTooltip);
}
// ARIA attributes
var mAccProps = {
role: "region"
};
if (oOH.getTitle()) {
mAccProps.labelledby = { value: oOH.getId() + "-titleText-inner", append: true };
}
oRM.accessibilityState(oOH, mAccProps);
oRM.openEnd();
if (bCondensed) {
this._renderCondensedOH(oRM, oOH);
} else {
this._renderFullOH(oRM, oOH);
}
oRM.openStart("div");
oRM.class("sapMOHLastDivider");
oRM.openEnd();
oRM.close("div");
oRM.close("div");
oRM.close("div"); // End Main container\
this._cleanupNotRenderedChildControls(oRM, oOH);
};
/**
* Renders the child control contained in the OH
*
* @param {sap.ui.core.RenderManager}
* oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader}
* oOH an object representation of the control that should be rendered
* @param {sap.ui.core.Control}
* oControl an object representation of the child control that should be rendered
* @private
**/
ObjectHeaderRenderer._renderChildControl = function(oRM, oOH, oControl){
oRM.renderControl(oControl);
if (!oOH.getResponsive() && oOH.__controlsToBeRendered) { // if control is rendered remove it from the array
oOH.__controlsToBeRendered[oControl.getId()] = undefined;
}
};
/**
* Responsive rendering start
*
* @param {sap.ui.core.RenderManager}
* oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader}
* oOH an object representation of the control that should be rendered
* @private
**/
ObjectHeaderRenderer._renderResponsive = function(oRM, oOH) {
var bStates = this._hasResponsiveStates(oOH),
bTabs = this._hasResponsiveTabs(oOH),
oHeaderContainer = oOH.getHeaderContainer();
// start outer div (containing ObjectHeader and IconTabBar content div)
oRM.openStart("div", oOH);
oRM.class("sapMOHROuter");
var sTooltip = oOH.getTooltip_AsString();
if (sTooltip) {
oRM.attr("title", sTooltip);
}
//ARIA attributes
oRM.accessibilityState({
role : "region",
labelledby: {
value: oOH.getId() + "-txt",
append: true
}
});
oRM.openEnd();
oRM.openStart("div");
oRM.class("sapMOHR");
// set contrast container, only when the background is not transparent
if (oOH._getBackground() !== BackgroundDesign.Transparent) {
oRM.class("sapContrastPlus");
}
if (bTabs) {
oRM.class("sapMOHRNoBorder");
}
oRM.class("sapMOHRBg" + oOH._getBackground());
oRM.openEnd();
oRM.openStart("div");
if (Device.system.desktop && oOH._isMediaSize("Desktop") && oOH.getFullScreenOptimized() && oOH._iCountVisAttrStat >= 1 && oOH._iCountVisAttrStat <= 3) {
oRM.class("sapMOHRStatesOneOrThree");
}
oRM.openEnd();
this._renderResponsiveTitleBlock(oRM, oOH);
if (bStates) {
this._renderResponsiveStates(oRM, oOH);
}
oRM.close("div"); // end wrapper div
if (bTabs) {
this._renderResponsiveTabs(oRM, oOH);
}
oRM.close("div");
if (oHeaderContainer && oHeaderContainer.isA("sap.m.IconTabBar")) {
this._renderChildControl(oRM, oOH, oHeaderContainer);
}
oRM.close("div"); // end outer div
if (!oOH.getTitle()) {
//if value is set through data binding, there is time delay and fake warning will be logged, so set warning only if not data binding
if (!oOH.getBinding("title")) {
Log.warning("The title shouldn't be empty!");
}
}
};
/**
* first building block for the responsive object header, it contains
* - intro
* - image
* - title
* - number and unit
*
* @param {sap.ui.core.RenderManager}
* oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader}
* oControl an object representation of the control that should be rendered
* @private
**/
ObjectHeaderRenderer._renderResponsiveTitleBlock = function(oRM, oControl) {
// Title container displayed to the left of the number and number units container.
oRM.openStart("div", oControl.getId() + "-titlenumdiv"); // Start Title and Number container (block1 and block2)
oRM.class("sapMOHRTitleNumberDiv"); // first block class
oRM.openEnd();
oRM.openStart("div", oControl.getId() + "-titlediv"); // Start Title container
oRM.class("sapMOHRTitleDiv");
if (oControl._hasIcon()) {
if (Device.system.phone || oControl._isMediaSize("Phone")) {
if (Device.orientation.landscape || (oControl._isMediaSize("Phone") && !Device.system.phone)) {
oRM.class("sapMOHRTitleIcon");
}
} else {
oRM.class("sapMOHRTitleIcon");
}
}
if (!oControl.getNumber()) {
oRM.class("sapMOHRTitleDivFull");
}
oRM.openEnd();
this._renderResponsiveTitle(oRM, oControl);
// render the title icon in a separate container
if (oControl._hasIcon()) {
oRM.openStart("div", oControl.getId() + "-titleIcon");
oRM.class("sapMOHRIcon");
oRM.class('sapMOHRIcon' + oControl.getImageShape());
if ((Device.system.phone && Device.orientation.portrait)) {
oRM.class("sapMOHRHideIcon");
}
if (oControl.getIconActive()) {
oRM.class("sapMPointer");
}
oRM.openEnd();
this._renderChildControl(oRM, oControl, oControl._getImageControl());
oRM.close("div"); // end icon container
}
oRM.close("div"); // End Title container
this._renderResponsiveNumber(oRM, oControl);
oRM.close("div"); // End Title and Number container
};
/**
* Renders the HTML for attributes and statuses, using the provided {@link sap.ui.core.RenderManager}.
*
* @param {sap.ui.core.RenderManager}
* oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader}
* oControl an object to be rendered
* @private
*/
ObjectHeaderRenderer._renderResponsiveStates = function(oRM, oControl) {
oRM.openStart("div", oControl.getId() + "-states");
oRM.class("sapMOHRStates");
oRM.openEnd();
this._renderResponsiveRow(oRM, oControl);
oRM.close("div");
};
/**
* Renders the HTML for the row which contains columns in which attributes and statuses are displayed.
*
* @param {sap.ui.core.RenderManager}
* oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader}
* oOH an object representation of the control that should be rendered
* @private
*/
ObjectHeaderRenderer._renderResponsiveRow = function(oRM, oOH) {
var aVisAtribsStatuses = [];
aVisAtribsStatuses = this._getVisibleAttribsAndStatuses(oOH);
var aVisibleAttrAndStat = aVisAtribsStatuses[0].concat(aVisAtribsStatuses[1]),
iCountVisibleAttr = aVisAtribsStatuses[0].length,
iCountAttrAndStat = aVisibleAttrAndStat.length,
iRenderCols = 1,
sClassColCount = '';
if (iCountAttrAndStat === 0) {
return; //nothing to render
}
if (Device.system.desktop) {
if (!oOH.getFullScreenOptimized()) { // if master detail
if (iCountAttrAndStat >= 1 && iCountAttrAndStat <= 4) {
iRenderCols = 2; // render two columns
sClassColCount = 'sapMOHRTwoCols';
}
if (iCountAttrAndStat >= 5) {
iRenderCols = 3; // render three columns
sClassColCount = 'sapMOHRThreeCols';
}
} else { // if full screen
if (iCountAttrAndStat >= 1 && iCountAttrAndStat <= 3) {
iRenderCols = 1; // render one column
sClassColCount = 'sapMOHROneCols';
}
if (iCountAttrAndStat >= 4) {
iRenderCols = 4; // render four columns
sClassColCount = 'sapMOHRFourCols';
}
}
}
if ((Device.system.tablet && !Device.system.desktop) || (Device.system.desktop && oOH._isMediaSize("Tablet"))) {
if (!oOH.getFullScreenOptimized() || (Device.orientation.portrait && oOH.getFullScreenOptimized())) { // full screen portrait or master detail
iRenderCols = 2; //render two columns
sClassColCount = 'sapMOHRTwoCols';
} else {
if (oOH.getFullScreenOptimized() && ( Device.orientation.landscape || (Device.system.desktop && oOH._isMediaSize("Tablet")))) { //full screen landscape
if (iCountAttrAndStat >= 1 && iCountAttrAndStat <= 2) {
iRenderCols = 2; // render two columns
sClassColCount = 'sapMOHRTwoCols';
}
if (iCountAttrAndStat >= 3) {
iRenderCols = 3; // render three columns
sClassColCount = 'sapMOHRThreeCols';
}
}
}
}
if (Device.system.phone || (Device.system.desktop && oOH._isMediaSize("Phone"))) {
iRenderCols = 1; // render one column
sClassColCount = 'sapMOHROneCols';
}
this._renderResponsiveStatesColumn(oRM, oOH, iRenderCols, aVisibleAttrAndStat, iCountVisibleAttr, sClassColCount);
};
/**
* Renders the HTML for the columns containing the states.
*
* @param {sap.ui.core.RenderManager} oRM The RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader} oOH An object representation of the control that should be rendered
* @param {int} iRenderCols The number of columns that should be rendered
* @param {array} aVisibleAttrAndStat The array of attributes and statuses that should be rendered
* @param {int} iCountVisibleAttr The number of attributes that should be rendered, since they should be rendered before the states
* @param {string} sClassColCount The name of the appropriate css class that should be set
* @private
*/
ObjectHeaderRenderer._renderResponsiveStatesColumn = function(oRM, oOH, iRenderCols, aVisibleAttrAndStat, iCountVisibleAttr, sClassColCount) {
var iCountInCols = Math.floor( aVisibleAttrAndStat.length / iRenderCols ); // number of attributes and states in each column
var iCountInBigCols = aVisibleAttrAndStat.length % iRenderCols;
var iCurrentCountInCol = 0; // contains current number of attributes and statuses in the column (will be reset to zero when it becames equal to iCountInCols)
var iContNum = 1; // container number (start from the first one)
for (var i = 0; i < aVisibleAttrAndStat.length; i++) {
if (iCurrentCountInCol == 0) {
oRM.openStart("div"); // Start container
oRM.class("sapMOHRStatesCont" + iContNum);
oRM.class(sClassColCount);
oRM.openEnd();
}
if (i < iCountVisibleAttr) {
this._renderResponsiveAttribute(oRM, oOH, aVisibleAttrAndStat[i]);
} else {
this._renderResponsiveStatus(oRM, oOH, aVisibleAttrAndStat[i]);
}
iCurrentCountInCol++;
if ((iCurrentCountInCol == iCountInCols && iContNum > iCountInBigCols) || (iCurrentCountInCol == (iCountInCols + 1) && iContNum <= iCountInBigCols) || i == aVisibleAttrAndStat.length - 1) {
oRM.close("div"); // end container
iCurrentCountInCol = 0;
iContNum++;
}
}
};
/**
* Renders the HTML for Attribute.
*
* @param {sap.ui.core.RenderManager} oRM The RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader} oOH An object representation of the control that should be rendered
* @param {sap.m.ObjectAttribute} oAttr An object representation of the sap.m.ObjectAtribute that should be rendered
* @private
*/
ObjectHeaderRenderer._renderResponsiveAttribute = function(oRM, oOH, oAttr) {
oRM.openStart("div");
oRM.class("sapMOHRAttr");
oRM.openEnd();
this._renderChildControl(oRM, oOH, oAttr);
oRM.close("div");
};
/**
* Renders the HTML for Status.
*
* @param {sap.ui.core.RenderManager} oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader} oOH an object representation of the control that should be rendered
* @param {sap.m.ObjectStatus} oStatus an object representation of the sap.m.ObjectStatus that should be rendered
* @private
*/
ObjectHeaderRenderer._renderResponsiveStatus = function(oRM, oOH, oStatus) {
oRM.openStart("div");
oRM.class("sapMOHRStatus");
oRM.openEnd();
this._renderChildControl(oRM, oOH, oStatus[0]);
oRM.close("div");
};
/**
* Renders flag and favorite icon
*
* @param {sap.ui.core.RenderManager}
* oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader}
* oControl an object representation of the control that should be rendered
* @private
*/
ObjectHeaderRenderer._renderResponsiveMarkers = function(oRM, oControl) {
var aMarkers = [],
sTextDir = oControl.getTitleTextDirection(),
bPageRTL = Configuration.getRTL();
// load markers based on control state
aMarkers = oControl._getVisibleMarkers();
// render markers
oRM.openStart("span", oControl.getId() + "-markers");
oRM.class("sapMObjStatusMarker");
if ((sTextDir === TextDirection.LTR && bPageRTL) || (sTextDir === TextDirection.RTL && !bPageRTL)) {
oRM.class("sapMObjStatusMarkerOpposite");
}
oRM.openEnd();
for (var i = 0; i < aMarkers.length; i++) {
this._renderChildControl(oRM, oControl, aMarkers[i]);
}
oRM.close("span");
};
/**
* Renders the ObjectNumber, using the provided {@link sap.ui.core.RenderManager}.
*
* @param {sap.ui.core.RenderManager}
* oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader}
* oControl an object representation of the control that should be rendered
* @private
*/
ObjectHeaderRenderer._renderResponsiveNumber = function(oRM, oControl) {
var oObjectNumber = oControl.getAggregation("_objectNumber");
if (oObjectNumber && oObjectNumber.getNumber()) {
oObjectNumber.setTextDirection(oControl.getNumberTextDirection());
this._renderChildControl(oRM, oControl, oObjectNumber);
}
};
/**
* Helper function to determine whether states need to be rendered or not
*
* @param {sap.m.ObjectHeader} oControl The sap.m.ObjectHeader
* @returns {boolean} If there is need for rerendering
* @private
*/
ObjectHeaderRenderer._hasResponsiveStates = function (oControl) {
var aAttribs = oControl.getAttributes(),
aVisibleAttribs = [];
if (!(oControl._hasAttributes() || oControl._hasStatus())) {
oControl._iCountVisAttrStat = 0;
return false;
}
for (var j = 0; j < aAttribs.length; j++) {
if (aAttribs[j].getVisible()) {
aVisibleAttribs.push(aAttribs[j]);
}
}
var aVisibleStatuses = this._getVisibleStatuses(oControl);
//this value needs to be adapted when an attribute or status is set to visible(false) after rendering
oControl._iCountVisAttrStat = aVisibleAttribs.length + aVisibleStatuses.length;
return !!(aVisibleAttribs.length + aVisibleStatuses.length);
};
/**
* helper function to determine whether tabs need to be rendered or not
* @param {sap.m.ObjectHeader} oControl The sap.m.ObjectHeader
* @returns {boolean} If there is need for rerendering
*
* @private
*/
ObjectHeaderRenderer._hasResponsiveTabs = function (oControl) {
var oHeaderContainer = oControl.getHeaderContainer(),
oIconTabHeader;
if (oHeaderContainer) {
if (oHeaderContainer.isA("sap.m.IconTabBar")) {
oIconTabHeader = oHeaderContainer._getIconTabHeader();
if (oIconTabHeader.getVisible()) {
oControl._iCountVisTabs = oIconTabHeader.getItems().length;
return !!oIconTabHeader.getItems().length;
}
} else if (oHeaderContainer.isA("sap.m.HeaderContainer")) {
return !!oHeaderContainer.getContent().length;
} else if (oHeaderContainer.isA("sap.suite.ui.commons.HeaderContainer")) {
return !!oHeaderContainer.getItems().length;
}
}
return false;
};
/**
* Renders the ITB, using the provided {@link sap.ui.core.RenderManager}.
*
* @param {sap.ui.core.RenderManager}
* oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader}
* oControl an object representation of the control that should be rendered
* @private
*/
ObjectHeaderRenderer._renderResponsiveTabs = function(oRM, oControl) {
var oHeaderContainer = oControl.getHeaderContainer(),
oIconTabHeader;
oRM.openStart("div");
oRM.class("sapMOHRTabs");
if (oHeaderContainer && oHeaderContainer.isA("sap.m.IconTabBar")) {
oRM.class("sapMOHRTabsITB");
}
oRM.openEnd();
if (oHeaderContainer) {
if (oHeaderContainer.isA("sap.m.IconTabBar")) {
oIconTabHeader = oHeaderContainer._getIconTabHeader();
this._renderChildControl(oRM, oControl, oIconTabHeader);
// tell iconTabBar to not render the header
oHeaderContainer._bHideHeader = true;
} else if (oHeaderContainer.isA(["sap.m.HeaderContainer", "sap.suite.ui.commons.HeaderContainer"])) {
// render the header container
this._renderChildControl(oRM, oControl, oHeaderContainer);
} else {
Log.warning("The control " + oHeaderContainer + " is not supported for aggregation \"headerContainer\"");
}
}
oRM.close("div");
};
/**
* Renders the HTML for the given control, using the provided {@link sap.ui.core.RenderManager}.
*
* @param {sap.ui.core.RenderManager}
* oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader}
* oOH an object representation of the control that should be rendered
* @private
*/
ObjectHeaderRenderer._renderResponsiveTitle = function(oRM, oOH) {
var nCutLen;
// Start title text and title arrow container
oOH._oTitleArrowIcon.setVisible(oOH.getShowTitleSelector());
oRM.openStart("div", oOH.getId() + "-title"); // Start Title Text container
oRM.class("sapMOHRTitle");
if (oOH.getTitle().length && oOH.getTitleActive()) {
oRM.class("sapMOHRTitleActive");
}
if (oOH.getShowTitleSelector()) {
oRM.class("sapMOHRTitleFollowArrow");
}
oRM.openEnd();
// Cut the title to 50 or 80 chars according to the design specification
if ((Device.system.phone && Device.orientation.portrait)) {
nCutLen = 50;
} else {
nCutLen = 80;
}
oRM.openStart("div", oOH.getId() + "-title-arrow"); // Start TitleArrow container
oRM.style("display", "inline-block");
oRM.openEnd();
this._renderResponsiveTitleAndArrow(oRM, oOH, nCutLen);
oRM.close("div");
// Introductory text at the top of the item, like "On behalf of Julie..."
if (oOH.getIntro()) {
this._renderIntro(oRM, oOH, "sapMOHRIntro", "sapMOHRIntroActive");
}
oRM.close("div"); // End Title Text container
};
/**
* Rerenders the HTML for the title of the Object Header, also called on rerender Title.
*
* @param {sap.ui.core.RenderManager} oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader} oOH an object representation of the control that should be rendered
* @param {int} nCutLen number of chars to which the title should be cut
* @private
*/
ObjectHeaderRenderer._rerenderTitle = function(oRM, oOH, nCutLen) {
var sId = oOH.getId();
this._renderResponsiveTitleAndArrow(oRM, oOH, nCutLen);
oRM.flush(jQuery(document.getElementById(sId + "-title-arrow")));
};
/**
* Renders the HTML for the title and arrow.
*
* @param {sap.ui.core.RenderManager} oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader} oOH an object representation of the control that should be rendered
* @param {int} nCutLen number of chars to which the title should be cut
* @private
*/
ObjectHeaderRenderer._renderResponsiveTitleAndArrow = function(oRM, oOH, nCutLen) {
var sOHTitle, sEllipsis = '', sTextDir = oOH.getTitleTextDirection();
var bMarkers = !!oOH._getVisibleMarkers().length;
var sTitleLevel = (oOH.getTitleLevel() === TitleLevel.Auto) ? TitleLevel.H1 : oOH.getTitleLevel();
sTitleLevel = sTitleLevel.toLowerCase();
oRM.openStart(sTitleLevel);
oRM.openEnd();
oRM.openStart("span");
oRM.class("sapMOHRTitleTextContainer");
// set title text direction, it will be inherit from the "flags" also
if (sTextDir != TextDirection.Inherit) {
oRM.attr("dir", sTextDir.toLowerCase());
}
oRM.openEnd();
if (oOH.getTitle().length && oOH.getTitleActive()) {
oRM.openStart("a", oOH.getId() + "-txt");
if (oOH.getTitleHref()) { // if title is link write it
oRM.attr("href", oOH.getTitleHref());
if (oOH.getTitleTarget()) {
oRM.attr("target", oOH.getTitleTarget());
oRM.attr("rel", defaultLinkTypes('', oOH.getTitleTarget()));
}
}
oRM.attr("tabindex", "0");
//ARIA attributes
oRM.accessibilityState({
role: "link"
});
} else {
oRM.openStart("span", oOH.getId() + "-txt");
}
oRM.class("sapMOHRTitleText");
oRM.openEnd();
oRM.openStart("span", oOH.getId() + "-titletxtwrap");
oRM.class("sapMOHRTitleTextWrappable");
oRM.openEnd();
if (oOH.getTitle().length > nCutLen) {
sOHTitle = oOH.getTitle().substr(0, nCutLen).trim();
sEllipsis = '...';
} else {
sOHTitle = oOH.getTitle();
}
if (bMarkers) {
var sOHTitleEnd = sOHTitle.substr(sOHTitle.lastIndexOf(" ") + 1);
var sOHTitleStart = sOHTitle.substr(0, sOHTitle.lastIndexOf(" ") + 1);
if (sOHTitleEnd.length === 1) {
sOHTitleEnd = sOHTitle;
sOHTitleStart = '';
}
oRM.text(sOHTitleStart);
oRM.close("span");
oRM.text(sOHTitleEnd);
oRM.text(sEllipsis);
if (oOH.getTitleActive()) {
oRM.close("a");
} else {
oRM.close("span");
}
this._renderResponsiveMarkers(oRM, oOH);
oRM.close("span");
} else {
if (!sEllipsis){
oRM.text(sOHTitle);
} else {
oRM.text(sOHTitle + sEllipsis);
}
if (oOH.getTitleActive()) {
oRM.close("span");
oRM.close("a");
oRM.close("span");
} else {
oRM.close("span");
oRM.close("span");
oRM.close("span");
}
}
if (oOH.getShowTitleSelector()) {
oRM.openStart("span"); // Start title arrow container
oRM.class("sapMOHRTitleArrow");
oRM.openEnd();
this._renderChildControl(oRM, oOH, oOH._oTitleArrowIcon);
oRM.close("span"); // end title arrow container
}
oRM.close(sTitleLevel);
};
/**
* Rerenders the HTML for the states of the responsive Object Header.
*
* @param {sap.ui.core.RenderManager}
* oRM the RenderManager that can be used for writing to the render output buffer
* @param {sap.m.ObjectHeader}
* oOH an object representation of the control that should be rendered
* @private
*/
ObjectHeaderRenderer._rerenderResponsiveStates = function(oRM, oOH) {
var sId = oOH.getId(),
aVisAtribsStatuses = this._getVisibleAttribsAndStatuses(oOH),
aVisibleAttrAndStat = aVisAtribsStatuses[0].concat(aVisAtribsStatuses[1]),
iCountVisibleAttr = aVisAtribsStatuses[0].length,
iCountAttrAndStat = aVisibleAttrAndStat.length,
iRenderCols = 1,
sClassColCount = '';
if (iCountAttrAndStat === 0) {
return; //nothing to render
}
// tablet case
if (Device.orientation.portrait) { // full screen portrait or master detail
iRenderCols = 2; //render two columns
sClassColCount = 'sapMOHRTwoCols';
} else {
if (iCountAttrAndStat >= 1 && iCountAttrAndStat <= 2) {
iRenderCols = 2; // render two columns
sClassColCount = 'sapMOHRTwoCols';
}
if (iCountAttrAndStat >= 3) {
iRenderCols = 3; // render three columns
sClassColCount = 'sapMOHRThreeCols';
}
}
this._renderResponsiveStatesColumn(oRM, oOH, iRenderCols, aVisibleAttrAndStat, iCountVisibleAttr, sClassColCount);
oRM.flush(jQuery(document.getElementById(sId + "-states"))[0]);
};
/**** responsive rendering end ****/
return ObjectHeaderRenderer;
}, /* bExport= */ true);