@openui5/sap.m
Version:
OpenUI5 UI Library sap.m
743 lines (660 loc) • 21.1 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.
*/
// Provides control sap.m.ObjectMarker.
sap.ui.define([
"sap/ui/core/Control",
"sap/ui/core/Renderer",
"sap/ui/Device",
"sap/m/library",
"sap/ui/core/library",
"sap/ui/core/Icon",
"sap/m/TextRenderer",
"sap/m/Text",
"sap/m/LinkRenderer",
"sap/m/Link",
"./ObjectMarkerRenderer"
], function(
Control,
Renderer,
Device,
library,
coreLibrary,
Icon,
TextRenderer,
Text,
LinkRenderer,
Link,
ObjectMarkerRenderer
) {
"use strict";
// shortcut for sap.ui.core.TextAlign
var TextAlign = coreLibrary.TextAlign;
// shortcut for sap.m.ObjectMarkerVisibility
var ObjectMarkerVisibility = library.ObjectMarkerVisibility;
/**
* Constructor for a new ObjectMarker.
*
* @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
* The <code>sap.m.ObjectMarker</code> control represents one of the following predefined types:
* <ul>
* <li><code>Flagged</code>
* <li><code>Favorite</code>
* <li><code>Draft</code>
* <li><code>Locked</code>
* <li><code>LockedBy</code>
* <li><code>Unsaved</code>
* <li><code>UnsavedBy</code>
* </ul>
* <b>Note</b>: Use the <code>LockedBy/UnsavedBy</code> type along with the <code>additionalInfo</code> property to display the name of the user who locked/changed the object.
* If <code>additionalInfo</code> property is not set when using <code>LockedBy/UnsavedBy</code> types, the string "Locked by another user"/"Unsaved changes by another user" will be displayed.
* If you don't want to display name of the user, simply use the <code>Locked/Unsaved</code> types.
*
* @extends sap.ui.core.Control
*
* @author SAP SE
* @version 1.117.4
*
* @constructor
* @public
* @since 1.38
* @alias sap.m.ObjectMarker
* @see {@link fiori:https://experience.sap.com/fiori-design-web/object-display-elements/#-object-status Object Marker}
*/
var ObjectMarker = Control.extend("sap.m.ObjectMarker", /** @lends sap.m.ObjectMarker.prototype */ {
metadata: {
library: "sap.m",
designtime: "sap/m/designtime/ObjectMarker.designtime",
properties: {
/**
* Sets one of the predefined types.
*
* <b>Note</b>: If the <code>visibility</code> property is not specified explicitly, every <code>type</code> comes with predefined one as follows:
* <ul>
* <li>For <code>Flagged</code> and <code>Favorite</code> the icon is visible and the text is not displayed</li>
* <li>For <code>Draft</code> the text is visible and the icon is not displayed</li>
* <li>For <code>Locked</code>, <code>LockedBy</code>, <code>Unsaved</code> and <code>UnsavedBy</code> - on screens larger than 600px both icon and text are visible, otherwise only the icon</li>
*
* </ul>
*/
type: {type: "sap.m.ObjectMarkerType", group: "Misc"},
/**
* Sets one of the visibility states.
* Visibility states are as follows:
* <ul>
* <li><code>IconOnly</code> - displays only icon, regardless of the screen size</li>
* <li><code>TextOnly</code> - displays only text, regardless of the screen size</li>
* <li><code>IconAndText</code> - displays both icon and text, regardless of the screen size</li>
* </ul>
*/
visibility: {type: "sap.m.ObjectMarkerVisibility", group: "Misc"},
/**
* Sets additional information to the displayed <code>type</code>.
*
* <b>Note:</b> If no type is set, the additional information will not be displayed.
*/
additionalInfo: {type: "string", group: "Misc", defaultValue: ""}
},
aggregations: {
/**
* Internal control that should be <code>sap.m.Link</code> for interactive and <code>sap.m.Text</code>
* for non-interactive <code>ObjectMarker</code>.
*/
_innerControl: {type: "sap.ui.core.Control", multiple: false, visibility: "hidden"}
},
associations: {
/**
* Association to controls / ids which describe this control (see WAI-ARIA attribute aria-describedby).
*/
ariaDescribedBy: {type: "sap.ui.core.Control", multiple: true, singularName: "ariaDescribedBy"},
/**
* 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: {
/**
* Event is fired when the <code>ObjectMarker</code> is interactive and the user taps/clicks on it.
*/
press: {
parameters: {
/**
* Type of the <code>ObjectMarker</code>.
*/
type: {type: "sap.m.ObjectMarkerType"}
}
}
},
dnd: { draggable: true, droppable: false }
},
renderer: ObjectMarkerRenderer
});
/**
* Map of predefined <code>ObjectMarker</code> types.
*
* @static
*/
ObjectMarker.M_PREDEFINED_TYPES = {
Flagged: {
icon: {
src: "sap-icon://flag",
visibility: {
small: true,
large: true
}
},
text: {
value: "OM_FLAG",
visibility: {
small: false,
large: false
}
}
},
Favorite: {
icon: {
src: "sap-icon://favorite",
visibility: {
small: true,
large: true
}
},
text: {
value: "OM_FAVORITE",
visibility: {
small: false,
large: false
}
}
},
Draft: {
icon: {
src: "sap-icon://request",
visibility: {
small: false,
large: false
}
},
text: {
value: "OM_DRAFT",
visibility: {
small: true,
large: true
}
}
},
Locked: {
icon: {
src: "sap-icon://private",
visibility: {
small: true,
large: true
}
},
text: {
value: "OM_LOCKED",
visibility: {
small: false,
large: true
}
}
},
Unsaved: {
icon: {
src: "sap-icon://user-edit",
visibility: {
small: true,
large: true
}
},
text: {
value: "OM_UNSAVED",
visibility: {
small: false,
large: true
}
}
},
LockedBy: {
icon: {
src: "sap-icon://private",
visibility: {
small: true,
large: true
}
},
text: {
value: "OM_LOCKED_BY",
visibility: {
small: false,
large: true
}
}
},
UnsavedBy: {
icon: {
src: "sap-icon://user-edit",
visibility: {
small: true,
large: true
}
},
text: {
value: "OM_UNSAVED_BY",
visibility: {
small: false,
large: true
}
}
}
};
/**
* Initializes the control.
*
* @override
*/
ObjectMarker.prototype.init = function() {
// Defines custom screen range set: smaller or equal 600px defines 'small' and bigger that defines 'large' screen
Device.media.initRangeSet("DeviceSet", [600], "px", ["small", "large"]);
};
/**
* Function is called when the rendering of the control is completed.
*
* @override
*/
ObjectMarker.prototype.onAfterRendering = function() {
this._attachMediaContainerWidthChange(this._handleMediaChange, this, "DeviceSet");
};
/**
* Function is called before the rendering of the control is started.
*
* @override
*/
ObjectMarker.prototype.onBeforeRendering = function() {
// Cleanup resize event registration before re-rendering
this._cleanup();
// Inner control can be determined here as all property values are known
this._adjustControl(false);
};
/**
* Cleans up the element instance before destruction.
*
* @override
*/
ObjectMarker.prototype.exit = function() {
// Cleanup resize event registration on exit
this._cleanup();
};
/**
* Intercepts <code>attachPress</code> to be able to re-render.
* If <code>press</code> event is attached and the control is rendered as text, than the control will be
* re-rendered as link.
*
* @returns {this} <code>this</code> pointer for chaining
*/
ObjectMarker.prototype.attachPress = function () {
var oInnerControl = this._getInnerControl();
Array.prototype.unshift.apply(arguments, ["press"]);
Control.prototype.attachEvent.apply(this, arguments);
if (this.hasListeners("press") && oInnerControl && oInnerControl instanceof CustomText) {
oInnerControl.destroy();
this.setAggregation("_innerControl", this._createCustomLink(), true);
this._adjustControl();
}
return this;
};
/**
* Intercepts <code>detachPress</code> to be able to re-render.
* If <code>press</code> event is detached and the control is rendered as a link, than the control will be
* re-rendered as a text.
*
* @returns {this} <code>this</code> pointer for chaining
*/
ObjectMarker.prototype.detachPress = function() {
var oInnerControl = this._getInnerControl();
Array.prototype.unshift.apply(arguments, ["press"]);
Control.prototype.detachEvent.apply(this, arguments);
if (!this.hasListeners("press") && oInnerControl && oInnerControl instanceof CustomLink) {
oInnerControl.destroy();
this.setAggregation("_innerControl", this._createCustomText(), true);
this._adjustControl();
}
return this;
};
/**
* Cleans up the control.
*
* @private
*/
ObjectMarker.prototype._cleanup = function() {
// Device Media Change handler
this._detachMediaContainerWidthChange(this._handleMediaChange, this, "DeviceSet");
};
/**
* Device Media Change handler.
*
* @private
*/
ObjectMarker.prototype._handleMediaChange = function() {
this._adjustControl();
};
/**
* Determines if the icon/text should be visible, etc.
*
* @param {boolean} [bSuppressInvalidate=false] if the setters called inside the function should invalidate the internal controls.
* This is done since the function is called onBeforeRendering, where there is no need of invalidation,
* since the internal controls are not rendered yet.
* @returns {boolean} <code>true</code> if the adjustment is done and <code>false</code> if there is no inner control and no adjustment happened.
* @private
*/
ObjectMarker.prototype._adjustControl = function(bSuppressInvalidate) {
var oType = ObjectMarker.M_PREDEFINED_TYPES[this.getType()],
oInnerControl = this._getInnerControl(),
oInnerIcon = oInnerControl && oInnerControl._getIconAggregation(),
sAdditionalInfo = this.getAdditionalInfo(),
bIsIconVisible = this._isIconVisible(),
bIsTextVisible = this._isTextVisible(),
bIsIconOnly = bIsIconVisible && !bIsTextVisible,
sType = this.getType(),
sText;
// If we have no inner control at this stage we don't need to adjust
if (!oInnerControl) {
return false;
}
if (oType) {
sText = this._getMarkerText(oType, sType, sAdditionalInfo);
}
if (bIsIconVisible) {
oInnerControl.setIcon(oType.icon.src, bSuppressInvalidate);
oInnerIcon.setDecorative(!bIsIconOnly); // icon should be decorative if we have text
if (bIsTextVisible) {
oInnerIcon.setAlt(sText);
}
oInnerIcon.setUseIconTooltip(false);
this.addStyleClass("sapMObjectMarkerIcon");
} else {
oInnerControl.setIcon(null, bSuppressInvalidate);
this.removeStyleClass("sapMObjectMarkerIcon");
}
if (bIsTextVisible) {
oInnerControl.setAggregation("tooltip", null, bSuppressInvalidate);
oInnerIcon && oInnerIcon.setAggregation("tooltip", null, bSuppressInvalidate);
oInnerControl.setText(sText, bSuppressInvalidate);
this.addStyleClass("sapMObjectMarkerText");
} else {
if (oInnerIcon) {
oInnerControl.setAggregation("tooltip", this.getTooltip_AsString() || sText, bSuppressInvalidate);
}
oInnerControl.setText(null, bSuppressInvalidate);
this.removeStyleClass("sapMObjectMarkerText");
}
oInnerControl.removeAllAssociation("ariaLabelledBy", bSuppressInvalidate);
oInnerControl.removeAllAssociation("ariaDescribedBy", bSuppressInvalidate);
this.getAriaLabelledBy().forEach(function(ariaLabelledBy) {
oInnerControl.addAssociation("ariaLabelledBy", ariaLabelledBy, bSuppressInvalidate);
});
this.getAriaDescribedBy().forEach(function(ariaDescribedBy){
oInnerControl.addAssociation("ariaDescribedBy", ariaDescribedBy, bSuppressInvalidate);
});
return true;
};
/**
* Gets the marker text.
*
* @param {object} oType The object type
* @param {string} sType The string type
* @param {string} sAdditionalInfo The additional information
* @returns {string} concatenated from type and additionalInfo text
* @private
*/
ObjectMarker.prototype._getMarkerText = function (oType, sType, sAdditionalInfo) {
var oRB = sap.ui.getCore().getLibraryResourceBundle("sap.m");
switch (sType) {
case "LockedBy":
return (sAdditionalInfo === "") ? oRB.getText('OM_LOCKED_BY_ANOTHER_USER') : oRB.getText('OM_LOCKED_BY', [sAdditionalInfo]);
case "UnsavedBy":
return (sAdditionalInfo === "") ? oRB.getText('OM_UNSAVED_BY_ANOTHER_USER') : oRB.getText('OM_UNSAVED_BY', [sAdditionalInfo]);
default:
return (sAdditionalInfo === "") ? oRB.getText(oType.text.value) : oRB.getText(oType.text.value) + " " + sAdditionalInfo;
}
};
/**
* Determines if the icon of the control should be visible or not.
*
* @returns {boolean} <code>true</code>, if the icon should be visible
* @private
*/
ObjectMarker.prototype._isIconVisible = function () {
var oType = ObjectMarker.M_PREDEFINED_TYPES[this.getType()],
sVisibility = this.getVisibility(),
sDeviceType = this._getDeviceType(),
bTypeIconVisibility = oType && oType.icon.visibility[sDeviceType] || false;
return sVisibility === ObjectMarkerVisibility.IconOnly ||
sVisibility === ObjectMarkerVisibility.IconAndText ||
(sVisibility !== ObjectMarkerVisibility.TextOnly && bTypeIconVisibility);
};
/**
* Determines if the text of the control should be visible or not.
*
* @returns {boolean} <code>true</code>, if the text should be visible
* @private
*/
ObjectMarker.prototype._isTextVisible = function () {
var oType = ObjectMarker.M_PREDEFINED_TYPES[this.getType()],
sVisibility = this.getVisibility(),
sDeviceType = this._getDeviceType(),
bTypeTextVisibility = oType && oType.text.visibility[sDeviceType] || false;
return sVisibility === ObjectMarkerVisibility.TextOnly ||
sVisibility === ObjectMarkerVisibility.IconAndText ||
(sVisibility !== ObjectMarkerVisibility.IconOnly && bTypeTextVisibility);
};
/**
* Returns the device type according to the current range set.
*
* @returns {string} type of the device ("small" or "large")
* @private
*/
ObjectMarker.prototype._getDeviceType = function () {
return this._getCurrentMediaContainerRange("DeviceSet").name.toLowerCase();
};
/**
* Returns the inner control.
*
* We don't need to invalidate control here since _getInnerControl is called either in renderer or in attachPress or detachPress
* where the control is invalidated in case if its not from the correct type.
* That's why _adjustControl is called with true in order to suppress invalidation.
* @returns {object} The inner control
* @private
*/
ObjectMarker.prototype._getInnerControl = function () {
var oInnerControl = this.getAggregation("_innerControl");
if (!oInnerControl && this.getType()) {
oInnerControl = this._createInnerControl();
this.setAggregation("_innerControl", oInnerControl, true);
this._adjustControl(true);
}
return oInnerControl;
};
/**
* Returns an inner control: <code>sap.m.Text</code> if <code>ObjectMarker</code> is non-interactive or
* <code>sap.m.Link</code> - if interactive.
* @returns {object} The inner control
* @private
*/
ObjectMarker.prototype._createInnerControl = function () {
if (this.hasListeners("press")) {
return this._createCustomLink();
} else {
return this._createCustomText();
}
};
/**
* Returns a new custom link control.
*
* @returns {*} custom link control
* @private
*/
ObjectMarker.prototype._createCustomLink = function () {
var oCustomLink = new CustomLink(this.getId() + "-link", {
wrapping: true
});
oCustomLink.attachPress(this._firePress, this);
return oCustomLink;
};
ObjectMarker.prototype._firePress = function() {
this.firePress({
type: this.getType()
});
};
/**
* Returns a new custom text control.
*
* @returns {*} custom text control
* @private
*/
ObjectMarker.prototype._createCustomText = function () {
return new CustomText(this.getId() + "-text", {
textAlign: TextAlign.Initial
});
};
["getAccessibilityInfo"].map(function(sFn) {
var bChainable = /^add/.test(sFn);
ObjectMarker.prototype[sFn] = function() {
var oInnerControl = this._getInnerControl(),
oResult;
if (oInnerControl && oInnerControl[sFn]) {
oResult = oInnerControl[sFn].apply(oInnerControl, arguments);
}
return bChainable ? this : oResult;
};
});
/****************************************** CUSTOM TEXT CONTROL ****************************************************/
var CustomTextRenderer = Renderer.extend(TextRenderer);
CustomTextRenderer.apiVersion = 2;
CustomTextRenderer.render = function(oRm, oControl) {
if (oControl.getIconOnly()) {
var oIconControl = oControl._getIconAggregation();
oIconControl.setAlt(oControl.getTooltip_AsString());
oRm.renderControl(oIconControl);
} else {
TextRenderer.render.call(this, oRm, oControl);
}
};
CustomTextRenderer.renderText = function(oRm, oControl) {
oRm.renderControl(oControl._getIconAggregation());
TextRenderer.renderText(oRm, oControl);
};
var CustomText = Text.extend("sap.m.internal.ObjectMarkerCustomText", {
metadata: {
library: "sap.m",
properties: {
icon: {type: "sap.ui.core.URI", group: "Data", defaultValue: null},
iconOnly: {type: "boolean", group: "Appearance", defaultValue: false}
},
aggregations: {
_iconControl: {type: "sap.ui.core.Icon", multiple: false, visibility: "hidden"}
}
},
renderer: CustomTextRenderer
});
CustomText.prototype.setIcon = function(sIcon, bSuppressInvalidate) {
var oIcon = this._getIconAggregation();
this.setProperty("icon", sIcon , bSuppressInvalidate);
oIcon.setSrc(sIcon);
return this;
};
/**
* Returns the _iconControl aggregation.
*
* The callers of this function must take care of the rendering, because it does not invalidate the control,
* it creates and sets the aggregation in case it is not already created.
*
* @returns {*} _iconControl aggregation
* @private
*/
CustomText.prototype._getIconAggregation = function() {
var oIcon = this.getAggregation("_iconControl");
if (!oIcon) {
oIcon = new Icon();
this.setAggregation("_iconControl", oIcon, true);
}
return oIcon;
};
/****************************************** CUSTOM LINK CONTROL ****************************************************/
var CustomLinkRenderer = Renderer.extend(LinkRenderer);
CustomLinkRenderer.apiVersion = 2;
CustomLinkRenderer.render = function(oRm, oControl) {
if (oControl.getIconOnly()) {
var oIconControl = oControl._getIconAggregation(),
sTooltip = oControl.getTooltip_AsString();
oIconControl.setAlt(sTooltip);
oIconControl.setTooltip(sTooltip);
oRm.renderControl(oIconControl);
} else {
LinkRenderer.render.call(this, oRm, oControl);
}
};
CustomLinkRenderer.renderText = function(oRm, oControl) {
oRm.renderControl(oControl._getIconAggregation());
LinkRenderer.renderText(oRm, oControl);
};
var CustomLink = Link.extend("sap.m.internal.ObjectMarkerCustomLink", {
metadata: {
library: "sap.m",
properties: {
icon: {type: "sap.ui.core.URI", group: "Data", defaultValue: null},
iconOnly: {type: "boolean", group: "Appearance", defaultValue: false}
},
aggregations: {
_iconControl: {type: "sap.ui.core.Icon", multiple: false, visibility: "hidden"}
}
},
renderer: CustomLinkRenderer
});
CustomLink.prototype.setIcon = function(sIcon, bSuppressInvalidate) {
var oIcon = this._getIconAggregation();
this.setProperty("icon", sIcon , bSuppressInvalidate);
oIcon.setSrc(sIcon);
return this;
};
CustomLink.prototype._getTabindex = function () {
return "0";
};
/**
* Returns the _iconControl aggregation.
*
* The callers of this function must take care of the rendering, because it does not invalidate the control,
* it creates and sets the aggregation in case it is not already created.
*
* @returns {*} _iconControl aggregation
* @private
*/
CustomLink.prototype._getIconAggregation = function() {
var oIcon = this.getAggregation("_iconControl");
if (!oIcon) {
oIcon = new Icon();
this.setAggregation("_iconControl", oIcon, true);
}
return oIcon;
};
/*
* Determines whether self-reference should be added.
*
* @returns {boolean}
* @override
* @private
*/
CustomLink.prototype._determineSelfReferencePresence = function () {
if (this.getIcon() && !this.getText()) {
return false;
} else {
return Link.prototype._determineSelfReferencePresence.apply(this, arguments);
}
};
return ObjectMarker;
});