@openui5/sap.m
Version:
OpenUI5 UI Library sap.m
919 lines (791 loc) • 30.2 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.Image.
sap.ui.define([
'./library',
'sap/ui/core/Control',
'sap/ui/base/DataType',
'sap/base/security/URLListValidator',
'./ImageRenderer',
"sap/ui/events/KeyCodes",
"sap/ui/thirdparty/jquery",
"sap/base/security/encodeCSS",
"sap/ui/Device",
"sap/ui/core/library"
],
function(library, Control, DataType, URLListValidator, ImageRenderer, KeyCodes, jQuery, encodeCSS, Device, coreLibrary) {
"use strict";
// shortcut for sap.m.ImageMode
var ImageMode = library.ImageMode;
// shortcut for sap.ui.core.aria.HasPopup
var AriaHasPopup = coreLibrary.aria.HasPopup;
/**
* Constructor for a new Image.
*
* @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
* A wrapper around the <img> tag; the image can be loaded from a remote or local server.
*
* If property <code>densityAware</code> is true, a density-specific image will be loaded by constructing
* a density-specific image name in format <code>[imageName]@[densityValue].[extension]</code> from the
* given <code>src</code> and the <code>devicePixelRatio</code> of the current device. The only supported
* density values are 1, 1.5 and 2. If the original <code>devicePixelRatio</code> ratio isn't one of the
* three valid numbers, it will be rounded to the nearest one.
*
* There are various size setting options available, and the images can be combined with actions.
*
* From version 1.30, a new image mode {@link sap.m.ImageMode.Background} is added. When this mode
* is set, the <code>src</code> property is set using the CSS style <code>background-image</code>.
* The properties <code>backgroundSize</code>, <code>backgroundPosition</code>, and <code>backgroundRepeat</code>
* take effect only when the image is in <code>sap.m.ImageMode.Background</code> mode. In order to display
* the high density image correctly, the <code>backgroundSize</code> should be set to the dimension of the
* normal density version.
*
* @see {@link topic:f86dbe9d7f7d48dea5286003b1322165 Image}
* @see {@link fiori:https://experience.sap.com/fiori-design-web/image/ Image}
*
* @extends sap.ui.core.Control
* @implements sap.ui.core.IFormContent
*
* @author SAP SE
* @version 1.117.4
*
* @public
* @alias sap.m.Image
*/
var Image = Control.extend("sap.m.Image", /** @lends sap.m.Image.prototype */ {
metadata : {
interfaces : ["sap.ui.core.IFormContent"],
library : "sap.m",
designtime: "sap/m/designtime/Image.designtime",
properties : {
/**
* Relative or absolute path to URL where the image file is stored.
*
* The path will be adapted to the density-aware format according to the density of the device
* following the naming convention [imageName]@[densityValue].[extension].
*/
src : {type : "sap.ui.core.URI", group : "Data", defaultValue : null},
/**
* When the empty value is kept, the original size is not changed.
*
* It is also possible to make settings for width or height only, in which case the original
* ratio between width/height is maintained. When the <code>mode</code> property is set to
* <code>sap.m.ImageMode.Background</code>, this property always needs to be set.
* Otherwise the output DOM element has a 0 size.
*/
width : {type : "sap.ui.core.CSSSize", group : "Appearance", defaultValue : null},
/**
* When the empty value is kept, the original size is not changed.
*
* It is also possible to make settings for width or height only, in which case the original
* ratio between width/height is maintained. When the <code>mode</code> property is set to
* <code>sap.m.ImageMode.Background</code>, this property always needs to be set.
* Otherwise the output DOM element has a 0 size.
*/
height : {type : "sap.ui.core.CSSSize", group : "Appearance", defaultValue : null},
/**
* A decorative image is included for design reasons; accessibility tools will ignore decorative images.
*
* Note: If the image has an image map (<code>useMap</code> is set), this property will be overridden
* (the image will not be rendered as decorative). A decorative image has no <code>ALT</code> attribute,
* so the <code>alt</code> property is ignored if the image is decorative.
*/
decorative : {type : "boolean", group : "Accessibility", defaultValue : true},
/**
* The alternative text that is displayed in case the image is not available, or cannot be displayed.
*
* If the image is set to decorative, this property is ignored.
*/
alt : {type : "string", group : "Accessibility", defaultValue : null},
/**
* The name of the image map that defines the clickable areas.
*/
useMap : {type : "string", group : "Misc", defaultValue : null},
/**
* If this is set to <code>true</code>, one or more network requests will be made
* that try to obtain the density perfect version of the image.
*
* By default, this is set to <code>false</code>, so the <code>src</code> image is loaded
* directly without attempting to fetch the density perfect image for high-density devices.
*
* <b>Note:</b> Before 1.60, the default value was set to <code>true</code>, which
* brought redundant network requests for apps that used the default but did not
* provide density perfect image versions on server-side.
* You should set this property to <code>true</code> only if you also provide the
* corresponding image versions for high-density devices.
*/
densityAware : {type : "boolean", group : "Misc", defaultValue : false},
/**
* The source property which is used when the image is pressed.
*/
activeSrc : {type : "sap.ui.core.URI", group : "Data", defaultValue : ""},
/**
* Defines how the <code>src</code> and the <code>activeSrc</code> is output to the DOM Element.
*
* When set to <code>sap.m.ImageMode.Image</code>, which is the default value, the <code>src</code>
* (<code>activeSrc</code>) is set to the <code>src</code> attribute of the <img> tag. When
* set to <code>sap.m.ImageMode.Background</code>, the <code>src</code> (<code>activeSrc</code>)
* is set to the CSS style <code>background-image</code> and the root DOM element is rendered as a
* <span> tag instead of an <img> tag.
* @since 1.30.0
*/
mode : {type : "sap.m.ImageMode", group : "Misc", defaultValue : "Image"},
/**
* Defines the size of the image in <code>sap.m.ImageMode.Background</code> mode.
*
* This property is set on the output DOM element using the CSS style <code>background-size</code>.
* It takes effect only when the <code>mode</code> property is set to <code>sap.m.ImageMode.Background</code>.
* @since 1.30.0
*/
backgroundSize : {type : "string", group : "Appearance", defaultValue : "cover"},
/**
* Defines the position of the image in <code>sap.m.ImageMode.Background</code> mode.
*
* This property is set on the output DOM element using the CSS style <code>background-position</code>.
* It takes effect only when the <code>mode</code> property is set to <code>sap.m.ImageMode.Background</code>.
* @since 1.30.0
*/
backgroundPosition : {type : "string", group : "Appearance", defaultValue : "initial"},
/**
* Defines whether the source image is repeated when the output DOM element is bigger than the source.
*
* This property is set on the output DOM element using the CSS style <code>background-repeat</code>.
* It takes effect only when the <code>mode</code> property is set to <code>sap.m.ImageMode.Background</code>.
* @since 1.30.0
*/
backgroundRepeat : {type : "string", group : "Appearance", defaultValue : "no-repeat"},
/**
* Enables lazy loading for images that are offscreen. If set to <code>true</code>, the property
* ensures that offscreen images are loaded early enough so that they have finished loading once
* the user scrolls near them.
*
* <b>Note:</b> Keep in mind that the property uses the loading attribute of HTML <code><img></code> element
* which is not supported for Internet Explorer.
*
* @since 1.87
*/
lazyLoading : {type : "boolean", defaultValue : false },
/**
* Defines the aria-haspopup attribute of the <code>Image</code>.
*
* <b>Guidance for choosing appropriate value:</b>
* <ul>
* <li> We recommend you to use the property only when press handler is set.</li>
* <li> If you use controls based on <code>sap.m.Popover</code> or <code>sap.m.Dialog</code>,
* then you must use <code>AriaHasPopup.Dialog</code> (both <code>sap.m.Popover</code> and
* <code>sap.m.Dialog</code> have role "dialog" assigned internally).</li>
* <li> If you use other controls, or directly <code>sap.ui.core.Popup</code>, you need to check
* the container role/type and map the value of <code>ariaHasPopup</code> accordingly.</li>
* </ul>
*
* @since 1.87.0
*/
ariaHasPopup : {type : "sap.ui.core.aria.HasPopup", group : "Accessibility", defaultValue : AriaHasPopup.None}
},
aggregations : {
/**
* A <code>sap.m.LightBox</code> instance that will be opened automatically when the user interacts
* with the <code>Image</code> control.
*
* The <code>tap</code> event will still be fired.
*/
detailBox: {type: 'sap.m.LightBox', multiple: false, bindable: "bindable"}
},
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"},
/**
* Association to controls / IDs which are details to this control (see WAI-ARIA attribute aria-details).
* @since 1.79
*/
ariaDetails: {type : "sap.ui.core.Control", multiple : true, singularName : "ariaDetails"}
},
events : {
/**
* Event is fired when the user clicks on the control. (This event is deprecated, use the press event instead)
* @deprecated As of version 1.107.0
*/
tap : {},
/**
* Event is fired when the user clicks on the control.
*/
press : {},
/**
* Event is fired when the image resource is loaded.
* @since 1.36.2
*/
load : {},
/**
* Event is fired when the image resource can't be loaded. If densityAware is set to true, the event is fired when none of the fallback resources can be loaded.
* @since 1.36.2
*/
error : {}
},
dnd: { draggable: true, droppable: false }
},
renderer: ImageRenderer
});
Image._currentDevicePixelRatio = (function() {
// if devicePixelRatio property is not available, value 1 is assumed by default.
var ratio = (window.devicePixelRatio === undefined ? 1 : window.devicePixelRatio);
// for ratio in our library, only 1 1.5 2 are valid
if (ratio <= 1) {
ratio = 1;
} else {
// round it to the nearest valid value
ratio *= 2;
ratio = Math.round(ratio);
ratio /= 2;
}
if (ratio > 2) {
ratio = 2;
}
return ratio;
}());
Image.prototype.init = function () {
this._oSvgCachedData = {};
};
/**
* Function is called when image is loaded successfully.
*
* @param {jQuery.Event} oEvent
* @private
*/
Image.prototype.onload = function(oEvent) {
var iWidth,
iHeight;
// This is used to fix the late load event handler problem on ios platform, if the event handler
// has not been called right after image is loaded, event is triggered manually in onAfterRendering
// method.
if (!this._defaultEventTriggered) {
this._defaultEventTriggered = true;
}
// reset the flag for the next rerendering
this._bVersion2Tried = false;
var $DomNode = this.$(),
oDomRef = $DomNode[0];
// set the src to the real dom node
if (this.getMode() === ImageMode.Background) {
// In Background mode, the src is applied to the output DOM element only when the source image is finally loaded to the client side
$DomNode.css("background-image", "url(\"" + encodeCSS(this._oImage.src) + "\")");
}
if (!this._isWidthOrHeightSet()) {
if (this._iLoadImageDensity > 1) {
iWidth = Math.round(oDomRef.getBoundingClientRect().width);
iHeight = Math.round(oDomRef.getBoundingClientRect().height);
if ((iWidth === oDomRef.naturalWidth) && (iHeight === oDomRef.naturalHeight)) {
$DomNode.width(iWidth / this._iLoadImageDensity);
}
}
}
$DomNode.removeClass("sapMNoImg");
this.fireLoad();
};
/**
* Function is called when error occurs during image loading.
*
* @param {jQuery.Event} oEvent
* @private
*/
Image.prototype.onerror = function(oEvent) {
// This is used to fix the late load event handler problem on ios platform, if the event handler
// has not been called right after image is loaded with errors, event is triggered manually in onAfterRendering
// method.
if (!this._defaultEventTriggered) {
this._defaultEventTriggered = true;
}
var $DomNode = this.$(),
sMode = this.getMode(),
// In Background mode, the src property should be read from the temp Image object
sSrc = (sMode === ImageMode.Image) ? this._getDomImg().attr("src") : this._oImage.src,
d = Image._currentDevicePixelRatio,
sCurrentSrc = this._isActiveState ? this.getActiveSrc() : this.getSrc();
$DomNode.addClass("sapMNoImg");
// if src is empty or there's no image existing, just stop
if (!sSrc || this._iLoadImageDensity === 1) {
// BCP: 1880526262
if (this.getAlt() && !this.getDecorative()) {
// remove the "sapMNoImg" in order to show the alt text
$DomNode.removeClass("sapMNoImg");
}
this.fireError();
return;
}
if (d === 2 || d < 1) {
// load the default image
this._iLoadImageDensity = 1;
this._updateDomSrc(this._generateSrcByDensity(sCurrentSrc, 1));
} else if (d === 1.5) {
if (this._bVersion2Tried) {
setTimeout(jQuery.proxy(function() {
// if version 2 isn't on the server, load the default image
this._iLoadImageDensity = 1;
this._updateDomSrc(this._generateSrcByDensity(sCurrentSrc, 1));
}, this), 0);
} else {
setTimeout(jQuery.proxy(function() {
// special treatment for density 1.5
// verify if the version for density 2 is provided or not
this._iLoadImageDensity = 2;
this._updateDomSrc(this._generateSrcByDensity(sCurrentSrc, 2));
this._bVersion2Tried = true;
}, this), 0);
}
}
};
/**
* Sets the <code>detailBox</code> aggregation.
* @param {sap.m.LightBox|undefined} oLightBox - Instance of the <code>LightBox</code> control or undefined
* @returns {this} <code>this</code> for chaining
* @override
* @public
*/
Image.prototype.setDetailBox = function (oLightBox) {
var oCurrentDetailBox = this.getDetailBox();
if (oLightBox) {
// In case someone try's to set the same LightBox twice we don't do anything
if (oLightBox === oCurrentDetailBox) {
return this;
}
// If we already have a LightBox detach old one's event
if (oCurrentDetailBox) {
this.detachPress(this._fnLightBoxOpen, oCurrentDetailBox);
}
// Bind the LightBox open method to the press event of the Image
this._fnLightBoxOpen = oLightBox.open;
this.attachPress(this._fnLightBoxOpen, oLightBox);
} else if (this._fnLightBoxOpen) {
// If there was a LightBox - cleanup
this.detachPress(this._fnLightBoxOpen, oCurrentDetailBox);
this._fnLightBoxOpen = null;
}
return this.setAggregation("detailBox", oLightBox);
};
Image.prototype.setSrc = function (sSrc) {
var oPreviousSrc = this.getSrc(),
oResult = this.setProperty("src", sSrc);
if (sSrc && oPreviousSrc !== this.getSrc() && this.getMode() === ImageMode.InlineSvg) {
sSrc.endsWith("svg") && this._loadSvg();
}
return oResult;
};
/*
* @override
*/
Image.prototype.clone = function () {
var oClone = Control.prototype.clone.apply(this, arguments),
oCloneDetailBox = oClone.getDetailBox();
// Handle press event if DetailBox is available
if (oCloneDetailBox) {
// Detach the old event
oClone.detachPress(this._fnLightBoxOpen, this.getDetailBox());
// Attach new event with the cloned detail box
oClone._fnLightBoxOpen = oCloneDetailBox.open;
oClone.attachPress(oClone._fnLightBoxOpen, oCloneDetailBox);
}
return oClone;
};
/**
* the 'beforeRendering' event handler
* @private
*/
Image.prototype.onBeforeRendering = function() {
this._defaultEventTriggered = false;
if (this.getMode() == ImageMode.Image) {
var $DomNode = this.getDetailBox() ? this.$().find(".sapMImg") : this.$();
$DomNode.off("load").off("error");
}
if (this.getMode() === ImageMode.InlineSvg) {
this._loadSvg();
}
};
/**
* This function is called to register event handlers for load and error event on the image DOM after it's rendered.
* It also check if the event handlers are called accordingly after the image is loaded, if not the event handlers are triggered
* manually.
*
* @private
*/
Image.prototype.onAfterRendering = function() {
// BCP 1870456103. Error should be thrown when we have invalid src and DetailBox present.
var $DomNode = this.getDetailBox() ? this.$().find(".sapMImg") : this.$(),
sMode = this.getMode(),
oDomImageRef;
if (sMode === ImageMode.Image) {
// bind the load and error event handler
$DomNode.on("load", jQuery.proxy(this.onload, this));
$DomNode.on("error", jQuery.proxy(this.onerror, this));
oDomImageRef = $DomNode[0];
}
if (sMode === ImageMode.Background) {
oDomImageRef = this._oImage;
}
// if image has already been loaded and the load or error event handler hasn't been called, trigger it manually.
if (oDomImageRef && oDomImageRef.complete && !this._defaultEventTriggered) {
// need to use the naturalWidth property instead of jDomNode.width(),
// the later one returns positive value even in case of broken image
if (Device.browser.firefox && this.getSrc().indexOf(".svg") > -1) {
return;
}
if (oDomImageRef.naturalWidth > 0) {
this.onload({/* empty event object*/});
} else {
this.onerror({/* empty event object*/});
}
}
};
Image.prototype.exit = function() {
if (this._oImage) {
// deregister the events from the window.Image object
jQuery(this._oImage).off("load", this.onload).off("error", this.onerror);
this._oImage = null;
} else {
this.$().off("load", this.onload).off("error", this.onerror);
}
if (this._fnLightBoxOpen) {
this._fnLightBoxOpen = null;
}
this._oSvgCachedData = null;
};
/**
* This binds to the touchstart event to change the src property of the image to the activeSrc.
*
* @private
*/
Image.prototype.ontouchstart = function(oEvent) {
/**
* @deprecated event
*/
if (oEvent.srcControl.mEventRegistry["press"] || oEvent.srcControl.mEventRegistry["tap"]) {
// mark the event for components that needs to know if the event was handled by the Image
oEvent.setMarked();
}
if (oEvent.targetTouches.length === 1 && this.getActiveSrc()) {
// change the source only when the first finger is on the image, the following fingers doesn't affect
this._updateDomSrc(this._getDensityAwareActiveSrc());
this._isActiveState = true;
}
};
/**
* This changes the src property of the image back to the src property of the image control.
*
* @private
*/
Image.prototype.ontouchend = function(oEvent) {
// change the source back only when all fingers leave the image
// avoid setting the normal state src again when there's no activeSrc property set
if (oEvent.targetTouches.length === 0 && this.getActiveSrc()) {
this._isActiveState = false;
this._updateDomSrc(this._getDensityAwareSrc());
this.$().removeClass("sapMNoImg");
}
};
Image.prototype.attachPress = function() {
Array.prototype.unshift.apply(arguments, ["press"]);
Control.prototype.attachEvent.apply(this, arguments);
if (this.hasListeners("press")) {
this.$().attr("tabindex", "0");
this.$().attr("role", "button");
}
return this;
};
Image.prototype.detachPress = function() {
Array.prototype.unshift.apply(arguments, ["press"]);
Control.prototype.detachEvent.apply(this, arguments);
if (!this.hasListeners("press")) {
this.$().removeAttr("tabindex");
if (this.getDecorative()) {
this.$().attr("role", "presentation");
} else {
this.$().removeAttr("role");
}
}
return this;
};
/**
* Function is called when image is clicked.
*
* @param {jQuery.Event} oEvent
* @private
*/
Image.prototype.ontap = function(oEvent) {
/**
* @deprecated event
*/
this.fireTap({/* no parameters */}); // (This event is deprecated, use the press event instead)
this.firePress({/* no parameters */});
};
/**
* Handle the key up event for SPACE and ENTER.
*
* @param {jQuery.Event} oEvent - the keyboard event.
* @private
*/
Image.prototype.onkeyup = function(oEvent) {
if (oEvent.which === KeyCodes.SPACE || oEvent.which === KeyCodes.ENTER) {
this.firePress({/* no parameters */});
// stop the propagation it is handled by the control
oEvent.stopPropagation();
}
};
/**
* Handles the keydown event for SPACE on which we have to prevent the browser scrolling.
*
* @param {jQuery.Event} oEvent The event object.
* @private
*/
Image.prototype.onsapspace = function(oEvent) {
oEvent.preventDefault();
};
/**
* Loads "svg"
* @private
*/
Image.prototype._loadSvg = function() {
var that = this,
sSrc = this.getSrc(),
oSvg;
if (!this._oSvgCachedData[sSrc]) {
that._oSvgCachedData[sSrc] = {};
jQuery.get(this.getSrc(), function(data) {
oSvg = jQuery(data).find('svg')[0];
if (oSvg) {
sap.ui.require(["sap/m/_thirdparty/purify"],
function(DOMPurify) {
that._oSvgCachedData[sSrc].oSvgDomRef = DOMPurify.sanitize(oSvg, {RETURN_DOM: true});
that.invalidate();
});
}
})
.done(function() {
that.fireLoad();
})
.fail(function() {
that.fireError();
});
}
};
Image.prototype._getSvgCachedData = function () {
var sSrc = this.getSrc();
if (this._oSvgCachedData[sSrc]
&& typeof this._oSvgCachedData[sSrc].oSvgDomRef === "object") {
return this._oSvgCachedData[sSrc].oSvgDomRef;
}
};
/**
* Checks if href is valid
* @private
*/
Image.prototype._isHrefValid = function (sURL) {
return URLListValidator.validate(sURL);
};
/**
* Update the source image either on the output DOM element (when in sap.m.ImageMode.Image mode) or on the window.Image object (when in sap.m.ImageMode.Background mode)
* @private
*/
Image.prototype._updateDomSrc = function(sSrc) {
var $DomNode = this.$(),
sMode = this.getMode();
if ($DomNode.length) {
// the src is updated on the output DOM element when mode is set to Image
// the src is updated on the temp Image object when mode is set to Background
if (sMode === ImageMode.Image) {
this._getDomImg().attr("src", sSrc);
} else {
$DomNode.addClass("sapMNoImg");
jQuery(this._oImage).attr("src", sSrc);
}
}
};
/**
* Returns the img Dom element
* @private
*/
Image.prototype._getDomImg = function() {
var $DomNode = this.$();
return this.getDetailBox() ? $DomNode.children("img") : $DomNode;
};
/**
* When sap.m.ImageMode.Background mode is set, the availability of the source image (including the high density version) is checked via the window.Image object. Because when source
* image is set via 'background-image' CSS style, browser doesn't fire 'load' or 'error' event anymore. These two events can still be fired when the source uri is set to an instance
* of window.Image.
*
* @private
*/
Image.prototype._preLoadImage = function(sSrc) {
if (this.getMode() !== ImageMode.Background) {
return;
}
var $InternalImage = jQuery(this._oImage);
if (!this._oImage) {
this._oImage = new window.Image();
// register to the 'load' and 'error' events
$InternalImage = jQuery(this._oImage);
$InternalImage.on("load", jQuery.proxy(this.onload, this)).on("error", jQuery.proxy(this.onerror, this));
}
this._oImage.src = sSrc;
};
/**
* Test if at least one of the width and height properties is set.
*
* @private
*/
Image.prototype._isWidthOrHeightSet = function() {
return (this.getWidth() && this.getWidth() !== '') || (this.getHeight() && this.getHeight() !== '');
};
/**
* This function returns the density aware source based on the deviceDensityRatio value.
* The return value is in the format [src]@[densityValue].[extension] if the densityValue not equal 1, otherwise it returns the src property.
*
* @private
*/
Image.prototype._getDensityAwareSrc = function() {
var sSrc = this.getSrc(),
bDensityAware = this.getDensityAware(),
d = bDensityAware ? Image._currentDevicePixelRatio : 1;
// this property is used for resizing the higher resolution image when image is loaded.
this._iLoadImageDensity = d;
return this._generateSrcByDensity(sSrc, d);
};
/**
* This function returns the density aware version of the Active source base on the deviceDensityRatio value.
*
* @private
*/
Image.prototype._getDensityAwareActiveSrc = function() {
var sActiveSrc = this.getActiveSrc(),
bDensityAware = this.getDensityAware(),
d = bDensityAware ? Image._currentDevicePixelRatio : 1;
// this property is used for resizing the higher resolution image when image is loaded.
this._iLoadImageDensity = d;
return this._generateSrcByDensity(sActiveSrc, d);
};
/**
* This function generates the density aware version of the src property according to the iDensity provided.
* It returns the density aware version of the src property.
*
* @private
*/
Image.prototype._generateSrcByDensity = function(sSrc, iDensity) {
if (!sSrc) {
return "";
}
// if src is in data uri format, disable the density handling
if (this._isDataUri(sSrc)) {
this._iLoadImageDensity = 1;
return sSrc;
}
// if the density equals 1, simply return the src property
if (iDensity === 1) {
return sSrc;
}
var iLastDotPos = sSrc.lastIndexOf("."),
iLastSlashPos = sSrc.lastIndexOf("/"),
sName = sSrc.substring(0, iLastDotPos),
sExtension = sSrc.substring(iLastDotPos);
// if there's no extension
// or there's slash after the last dot, this means that the dot may come from the host name
if (iLastDotPos === -1 || (iLastSlashPos > iLastDotPos)) {
return sSrc + "@" + iDensity;
}
sName = sName + "@" + iDensity;
return sName + sExtension;
};
Image.prototype._isDataUri = function(src) {
return src ? src.indexOf("data:") === 0 : false;
};
/**
* Checks if the given value is valid for the <code>background-size</code>
* CSS property
*
* @param {string} sValue the value to check
* @protected
* @returns {boolean} the check result
*/
Image.prototype._isValidBackgroundSizeValue = function (sValue) {
// compress whitespace
sValue = normWS(sValue);
return isSubSet(sValue.split(" "), ["auto", "cover", "contain", "initial"])
|| DataType.getType("sap.ui.core.CSSSizeShortHand").isValid(sValue);
};
/**
* Checks if the given value is valid for the <code>background-position</code>
* CSS property
*
* @param {string} sValue the value to check
* @protected
* @returns {boolean} the check result
*/
Image.prototype._isValidBackgroundPositionValue = function (sValue) {
// compress whitespace
sValue = normWS(sValue);
return isSubSet(sValue.split(" "), ["left", "right", "top", "center", "bottom", "initial"])
|| DataType.getType("sap.ui.core.CSSSizeShortHand").isValid(sValue);
};
/**
* Returns the <code>sap.m.Image</code> accessibility information.
*
* @see sap.ui.core.Control#getAccessibilityInfo
* @protected
* @returns {sap.ui.core.AccessibilityInfo}
* The object contains the accessibility information for <code>sap.m.Image</code>
*/
Image.prototype.getAccessibilityInfo = function() {
var bHasPressListeners = this.hasListeners("press");
if (this.getDecorative() && !this.getUseMap() && !bHasPressListeners) {
return null;
}
return {
role: bHasPressListeners ? "button" : "img",
type: sap.ui.getCore().getLibraryResourceBundle("sap.m").getText(bHasPressListeners ? "ACC_CTR_TYPE_BUTTON" : "ACC_CTR_TYPE_IMAGE"),
description: this.getAlt() || this.getTooltip_AsString() || "",
focusable: bHasPressListeners
};
};
/**
* @see sap.ui.core.Element.prototype.getFocusDomRef
* @private
*/
Image.prototype.getFocusDomRef = function() {
return this.getDomRef("inner") || this.getDomRef();
};
/*
* Image must not be stretched in Form because should have its original size.
*/
Image.prototype.getFormDoNotAdjustWidth = function() {
return true;
};
/**
* Utility function that checks if the content of an array
* is a subset of the content of a second (reference) array
*/
function isSubSet (aTestArray, aRefArray) {
function isOutsideSet(sTestValue) {
return aRefArray.indexOf(sTestValue) < 0; // value is not part of the reference set
}
return aTestArray && aRefArray && !aTestArray.some(isOutsideSet);
}
/**
* Utility function to normalize whitespace in a CSS value.
* @param {string} sValue String value to normalize
* @returns {string} Normalized value
*/
function normWS(sValue) {
var whitespaceRegEx = /\s+/g;
// compress whitespace
return sValue == null ? "" : String(sValue).trim().replace(whitespaceRegEx, " ");
}
return Image;
});