Hi! First, I want to apologise for having pasted all this code in this post, but tinyurl said "414 Request-URI Too Large"
In order to hack a bit the qx.ui.basic.Image code.. I had to copy the source in the playgground into a new class "kreimer.MyImage2" inserting a few lines in the __checkForContentElementReplacement private method: // kreimer var currentStyles = currentContentElement.getAllStyles(); this.info("currentStyles" + currentStyles); for(var prop in currentStyles) { styles[prop] = currentStyles[prop]; } //kreimer I don't know for sure if its the best solution, it's not fully tested, but it seems to solve the issue. Can somebody try this? Thanks everybody in the community! Here, the code to paste into the playground: qx.Class.define("kreimer.MyImage2", { extend : qx.ui.core.Widget, /* ***************************************************************************** CONSTRUCTOR ***************************************************************************** */ /** * @param source {String?null} The URL of the image to display. */ construct : function(source) { this.__contentElements = {}; this.base(arguments); if (source) { this.setSource(source); } }, /* ***************************************************************************** PROPERTIES ***************************************************************************** */ properties : { /** The URL of the image. Setting it will possibly abort loading of current image. */ source : { check : "String", init : null, nullable : true, event : "changeSource", apply : "_applySource", themeable : true }, /** * Whether the image should be scaled to the given dimensions * * This is disabled by default because it prevents the usage * of image clipping when enabled. */ scale : { check : "Boolean", init : false, themeable : true, apply : "_applyScale" }, // overridden appearance : { refine : true, init : "image" }, // overridden allowShrinkX : { refine : true, init : false }, // overridden allowShrinkY : { refine : true, init : false }, // overridden allowGrowX : { refine : true, init : false }, // overridden allowGrowY : { refine : true, init : false } }, /* ***************************************************************************** EVENTS ***************************************************************************** */ events : { /** * Fired if the image source can not be loaded. This event can only be * fired for the first loading of an unmanaged resource (external image). */ loadingFailed : "qx.event.type.Event", /** * Fired if the image has been loaded. This is even true for managed * resources (images known by generator). */ loaded : "qx.event.type.Event", /** Fired when the pending request has been aborted. */ aborted : "qx.event.type.Event" }, statics: { PLACEHOLDER_IMAGE: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" }, /* ***************************************************************************** MEMBERS ***************************************************************************** */ members : { __width : null, __height : null, __mode : null, __contentElements : null, __currentContentElement : null, __wrapper : null, __requestId : 0, //overridden _onChangeTheme : function() { this.base(arguments); // restyle source (theme change might have changed the resolved url) this._styleSource(); }, /* --------------------------------------------------------------------------- WIDGET API --------------------------------------------------------------------------- */ // overridden getContentElement : function() { return this.__getSuitableContentElement(); }, // overridden _createContentElement : function() { return this.__getSuitableContentElement(); }, // overridden _getContentHint : function() { return { width : this.__width || 0, height : this.__height || 0 }; }, // overridden _applyDecorator : function(value, old) { this.base(arguments, value, old); var source = this.getSource(); source = qx.util.AliasManager.getInstance().resolve(source); var el = this.getContentElement(); if (this.__wrapper) { el = el.getChild(0); } this.__setSource(el, source); }, // overridden _applyPadding : function(value, old, name) { this.base(arguments, value, old, name); var element = this.getContentElement(); if (this.__wrapper) { element.getChild(0).setStyles({ top: this.getPaddingTop() || 0, left: this.getPaddingLeft() || 0 }); } else { element.setPadding( this.getPaddingLeft() || 0, this.getPaddingTop() || 0 ); } }, renderLayout : function(left, top, width, height) { this.base(arguments, left, top, width, height); var element = this.getContentElement(); if (this.__wrapper) { element.getChild(0).setStyles({ width: width - (this.getPaddingLeft() || 0) - (this.getPaddingRight() || 0), height: height - (this.getPaddingTop() || 0) - (this.getPaddingBottom() || 0), top: this.getPaddingTop() || 0, left: this.getPaddingLeft() || 0 }); } }, /* --------------------------------------------------------------------------- IMAGE API --------------------------------------------------------------------------- */ // property apply, overridden _applyEnabled : function(value, old) { this.base(arguments, value, old); if (this.getSource()) { this._styleSource(); } }, // property apply _applySource : function(value, old) { // abort loading current image if (old) { if (qx.io.ImageLoader.isLoading(old)) { qx.io.ImageLoader.abort(old); } } this._styleSource(); }, // property apply _applyScale : function(value) { this._styleSource(); }, /** * Remembers the mode to keep track which contentElement is currently in use. * @param mode {String} internal mode (alphaScaled|scaled|nonScaled) */ __setMode : function(mode) { this.__mode = mode; }, /** * Returns the current mode if set. Otherwise checks the current source and * the current scaling to determine the current mode. * * @return {String} current internal mode */ __getMode : function() { if (this.__mode == null) { var source = this.getSource(); var isPng = false; if (source != null) { isPng = qx.lang.String.endsWith(source, ".png"); } if (this.getScale() && isPng && qx.core.Environment.get("css.alphaimageloaderneeded")) { this.__mode = "alphaScaled"; } else if (this.getScale()) { this.__mode = "scaled"; } else { this.__mode = "nonScaled"; } } return this.__mode; }, /** * Creates a contentElement suitable for the current mode * * @param mode {String} internal mode * @return {qx.html.Image} suitable image content element */ __createSuitableContentElement : function(mode) { var scale; var tagName; if (mode == "alphaScaled") { scale = true; tagName = "div"; } else if (mode == "nonScaled") { scale = false; tagName = "div"; } else { scale = true; tagName = "img"; } var element = new qx.html.Image(tagName); element.setAttribute("$$widget", this.toHashCode()); element.setScale(scale); element.setStyles({ "overflowX": "hidden", "overflowY": "hidden", "boxSizing": "border-box" }); if (qx.core.Environment.get("css.alphaimageloaderneeded")) { var wrapper = this.__wrapper = new qx.html.Element("div"); wrapper.setAttribute("$$widget", this.toHashCode()); wrapper.setStyle("position", "absolute"); wrapper.add(element); return wrapper; } return element; }, /** * Returns a contentElement suitable for the current mode * * @return {qx.html.Image} suitable image contentElement */ __getSuitableContentElement : function() { if (this.$$disposed) { return null; } var mode = this.__getMode(); if (this.__contentElements[mode] == null) { this.__contentElements[mode] = this.__createSuitableContentElement(mode); } var element = this.__contentElements[mode]; if (!this.__currentContentElement) { this.__currentContentElement = element; } return element; }, /** * Applies the source to the clipped image instance or preload * an image to detect sizes and apply it afterwards. * */ _styleSource : function() { var AliasManager = qx.util.AliasManager.getInstance(); var ResourceManager = qx.util.ResourceManager.getInstance(); var source = AliasManager.resolve(this.getSource()); var element = this.getContentElement(); if (this.__wrapper) { element = element.getChild(0); } if (!source) { element.resetSource(); return; } this.__checkForContentElementSwitch(source); if ((qx.core.Environment.get("engine.name") == "mshtml") && (parseInt(qx.core.Environment.get("engine.version"), 10) < 9 || qx.core.Environment.get("browser.documentmode") < 9)) { var repeat = this.getScale() ? "scale" : "no-repeat"; element.tagNameHint = qx.bom.element.Decoration.getTagName(repeat, source); } var contentEl = this.__getContentElement(); // Detect if the image registry knows this image if (qx.util.ResourceManager.getInstance().has(source)) { var highResolutionSource = this._findHighResolutionSource(source); if (highResolutionSource) { var imageWidth = ResourceManager.getImageHeight(source); var imageHeight = ResourceManager.getImageWidth(source); this.setWidth(imageWidth); this.setHeight(imageHeight); // set backgroud size on current element (div or img) var backgroundSize = imageWidth + "px, " + imageHeight + "px"; this.__currentContentElement.setStyle("background-size", backgroundSize); this.setSource(highResolutionSource); source = highResolutionSource; } this.__setManagedImage(contentEl, source); this.__fireLoadEvent(); } else if (qx.io.ImageLoader.isLoaded(source)) { this.__setUnmanagedImage(contentEl, source); this.__fireLoadEvent(); } else { this.__loadUnmanagedImage(contentEl, source); } }, /** * Helper function, which fires <code>loaded</code> event asynchronously. * It emulates native <code>loaded</code> event of an image object. This * helper will be called, if you try to load a managed image or an * previously loaded unmanaged image. */ __fireLoadEvent : function() { this.__requestId++; qx.bom.AnimationFrame.request(function(rId){ // prevent firing of the event if source changed in the meantime if (rId === this.__requestId) { this.fireEvent("loaded"); } else { this.fireEvent("aborted"); } }.bind(this, this.__requestId)); }, /** * Returns the content element. * @return {qx.html.Image} content element */ __getContentElement : function() { var contentEl = this.__currentContentElement; if (this.__wrapper) { contentEl = contentEl.getChild(0); } return contentEl; }, /** * Checks if the current content element is capable to display the image * with the current settings (scaling, alpha PNG) * * @param source {String} source of the image */ __checkForContentElementSwitch : qx.core.Environment.select("engine.name", { "mshtml" : function(source) { var alphaImageLoader = qx.core.Environment.get("css.alphaimageloaderneeded"); var isPng = qx.lang.String.endsWith(source, ".png"); if (alphaImageLoader && isPng) { if (this.getScale() && this.__getMode() != "alphaScaled") { this.__setMode("alphaScaled"); } else if (!this.getScale() && this.__getMode() != "nonScaled") { this.__setMode("nonScaled"); } } else { if (this.getScale() && this.__getMode() != "scaled") { this.__setMode("scaled"); } else if (!this.getScale() && this.__getMode() != "nonScaled") { this.__setMode("nonScaled"); } } this.__checkForContentElementReplacement(this.__getSuitableContentElement()); }, "default" : function(source) { if (this.getScale() && this.__getMode() != "scaled") { this.__setMode("scaled"); } else if (!this.getScale() && this.__getMode("nonScaled")) { this.__setMode("nonScaled"); } this.__checkForContentElementReplacement(this.__getSuitableContentElement()); } }), /** * Checks the current child and replaces it if necessary * * @param elementToAdd {qx.html.Image} content element to add */ __checkForContentElementReplacement : function(elementToAdd) { var currentContentElement = this.__currentContentElement; if (currentContentElement != elementToAdd) { if (currentContentElement != null) { var pixel = "px"; var styles = {}; // kreimer var currentStyles = currentContentElement.getAllStyles(); this.info("currentStyles" + currentStyles); for(var prop in currentStyles) { styles[prop] = currentStyles[prop]; } //kreimer // Copy dimension and location of the current content element var bounds = this.getBounds(); if (bounds != null) { styles.width = bounds.width + pixel; styles.height = bounds.height + pixel; } var insets = this.getInsets(); styles.left = parseInt(currentContentElement.getStyle("left") || insets.left) + pixel; styles.top = parseInt(currentContentElement.getStyle("top") || insets.top) + pixel; styles.zIndex = 10; var newEl = this.__wrapper ? elementToAdd.getChild(0) : elementToAdd; newEl.setStyles(styles, true); newEl.setSelectable(this.getSelectable()); if (!currentContentElement.isVisible()) { elementToAdd.hide(); } if (!currentContentElement.isIncluded()) { elementToAdd.exclude(); } var container = currentContentElement.getParent(); if (container) { var index = container.getChildren().indexOf(currentContentElement); container.removeAt(index); container.addAt(elementToAdd, index); } // force re-application of source so __setSource is called again var hint = newEl.getNodeName(); newEl.setSource(null); var currentEl = this.__getContentElement(); newEl.tagNameHint = hint; newEl.setAttribute("class", currentEl.getAttribute("class")); // Flush elements to make sure the DOM elements are created. qx.html.Element.flush(); var currentDomEl = currentEl.getDomElement(); var newDomEl = elementToAdd.getDomElement(); // copy event listeners var listeners = currentContentElement.getListeners() || []; listeners.forEach(function(listenerData) { elementToAdd.addListener(listenerData.type, listenerData.handler, listenerData.self, listenerData.capture); }); if (currentDomEl && newDomEl) { // Switch the DOM elements' hash codes. This is required for the event // layer to work [BUG #7447] var currentHash = currentDomEl.$$hash; currentDomEl.$$hash = newDomEl.$$hash; newDomEl.$$hash = currentHash; } this.__currentContentElement = elementToAdd; } } }, /** * Use the ResourceManager to set a managed image * * @param el {Element} image DOM element * @param source {String} source path */ __setManagedImage : function(el, source) { var ResourceManager = qx.util.ResourceManager.getInstance(); // Try to find a disabled image in registry if (!this.getEnabled()) { var disabled = source.replace(/\.([a-z]+)$/, "-disabled.$1"); if (ResourceManager.has(disabled)) { source = disabled; this.addState("replacement"); } else { this.removeState("replacement"); } } // Optimize case for enabled changes when no disabled image was found if (el.getSource() === source) { return; } // Apply source this.__setSource(el, source); // Compare with old sizes and relayout if necessary this.__updateContentHint( ResourceManager.getImageWidth(source), ResourceManager.getImageHeight(source) ); }, /** * Use the infos of the ImageLoader to set an unmanaged image * * @param el {Element} image DOM element * @param source {String} source path */ __setUnmanagedImage : function(el, source) { var ImageLoader = qx.io.ImageLoader; // Apply source this.__setSource(el, source); // Compare with old sizes and relayout if necessary var width = ImageLoader.getWidth(source); var height = ImageLoader.getHeight(source); this.__updateContentHint(width, height); }, /** * Use the ImageLoader to load an unmanaged image * * @param el {Element} image DOM element * @param source {String} source path */ __loadUnmanagedImage : function(el, source) { var ImageLoader = qx.io.ImageLoader; if (qx.core.Environment.get("qx.debug")) { // loading external images via HTTP/HTTPS is a common usecase, as is // using data URLs. var sourceLC = source.toLowerCase(); var startsWith = qx.lang.String.startsWith; if (!startsWith(sourceLC, "http") && !startsWith(sourceLC, "data:image/")) { var self = this.self(arguments); if (!self.__warned) { self.__warned = {}; } if (!self.__warned[source]) { this.debug("try to load an unmanaged relative image: " + source); self.__warned[source] = true; } } } // only try to load the image if it not already failed if(!ImageLoader.isFailed(source)) { ImageLoader.load(source, this.__loaderCallback, this); } else { if (el != null) { el.resetSource(); } } }, /** * Combines the decorator's image styles with our own image to make sure * gradient and backgroundImage decorators work on Images. * * @param el {Element} image DOM element * @param source {String} source path */ __setSource: function (el, source) { if (el.getNodeName() == "div") { // checks if a decorator already set. // In this case we have to merge background styles var decorator = qx.theme.manager.Decoration.getInstance().resolve(this.getDecorator()); if (decorator) { var hasGradient = (decorator.getStartColor() && decorator.getEndColor()); var hasBackground = decorator.getBackgroundImage(); if (hasGradient || hasBackground) { var repeat = this.getScale() ? "scale" : "no-repeat"; // get the style attributes for the given source var attr = qx.bom.element.Decoration.getAttributes(source, repeat); // get the background image(s) defined by the decorator var decoratorStyle = decorator.getStyles(true); var combinedStyles = { "backgroundImage": attr.style.backgroundImage, "backgroundPosition": (attr.style.backgroundPosition || "0 0"), "backgroundRepeat": (attr.style.backgroundRepeat || "no-repeat") }; if (hasBackground) { combinedStyles["backgroundPosition"] += "," + decoratorStyle["background-position"] || "0 0"; combinedStyles["backgroundRepeat"] += ", " + decorator.getBackgroundRepeat(); } if (hasGradient) { combinedStyles["backgroundPosition"] += ", 0 0"; combinedStyles["backgroundRepeat"] += ", no-repeat"; } combinedStyles["backgroundImage"] += "," + decoratorStyle["background-image"]; // apply combined background images el.setStyles(combinedStyles); return; } } else { // force re-apply to remove old decorator styles el.setSource(null); } } el.setSource(source); }, /** * Detects whether there is a high-resolution image available. * A high-resolution image is assumed to have the same file name as * the parameter source, but with a pixelRatio identifier before the file * extension, like "@2x". * Medium Resolution: "example.png", high-resolution: "exam...@2x.png" * * @param lowResImgSrc {String} source of the low resolution image. * @return {String|Boolean} If a high-resolution image source. */ _findHighResolutionSource: function(lowResImgSrc) { var pixelRatioCandidates = ["3", "2", "1.5"]; // Calculate the optimal ratio, based on the rem scale factor of the application and the device pixel ratio. var factor = parseFloat(qx.bom.client.Device.getDevicePixelRatio().toFixed(2)); if (factor <= 1) { return false; } var i = pixelRatioCandidates.length; while (i > 0 && factor > pixelRatioCandidates[--i]) {} var hiResImgSrc; var k; // Search for best img with a higher resolution. for (k = i; k >= 0; k--) { hiResImgSrc = this._getHighResolutionSource(lowResImgSrc, pixelRatioCandidates[k]); if (hiResImgSrc) { return hiResImgSrc; } } // Search for best img with a lower resolution. for (k = i + 1; k < pixelRatioCandidates.length; k++) { hiResImgSrc = this._getHighResolutionSource(lowResImgSrc, pixelRatioCandidates[k]); if (hiResImgSrc) { return hiResImgSrc; } } return null; }, /** * Returns the source name for the high-resolution image based on the passed * parameters. * @param source {String} the source of the medium resolution image. * @param pixelRatio {Number} the pixel ratio of the high-resolution image. * @return {String} the high-resolution source name or null if no source could be found. */ _getHighResolutionSource : function(source, pixelRatio) { var fileExtIndex = source.lastIndexOf('.'); if (fileExtIndex > -1) { var pixelRatioIdentifier = "@" + pixelRatio + "x"; var candidate = source.slice(0, fileExtIndex) + pixelRatioIdentifier + source.slice(fileExtIndex); if(qx.util.ResourceManager.getInstance().has(candidate)) { return candidate; } } return null; }, /** * Event handler fired after the preloader has finished loading the icon * * @param source {String} Image source which was loaded * @param imageInfo {Map} Dimensions of the loaded image */ __loaderCallback : function(source, imageInfo) { // Ignore the callback on already disposed images if (this.$$disposed === true) { return; } // Ignore when the source has already been modified if (source !== qx.util.AliasManager.getInstance().resolve(this.getSource())) { this.fireEvent("aborted"); return; } /// Output a warning if the image could not loaded and quit if (imageInfo.failed) { this.warn("Image could not be loaded: " + source); this.fireEvent("loadingFailed"); } else if (imageInfo.aborted) { this.fireEvent("aborted"); return; } else { this.fireEvent("loaded"); } // Update image this.__setUnmanagedImage(this.__getContentElement(), source); }, /** * Updates the content hint when the image size has been changed * * @param width {Integer} width of the image * @param height {Integer} height of the image */ __updateContentHint : function(width, height) { // Compare with old sizes and relayout if necessary if (width !== this.__width || height !== this.__height) { this.__width = width; this.__height = height; qx.ui.core.queue.Layout.add(this); } } }, /* ***************************************************************************** DESTRUCTOR ***************************************************************************** */ destruct : function() { for (var mode in this.__contentElements) { if (this.__contentElements.hasOwnProperty(mode)) { this.__contentElements[mode].setAttribute("$$widget", null, true); } } delete this.__currentContentElement; if (this.__wrapper) { delete this.__wrapper; } this._disposeMap("__contentElements"); } }); var btn = new qx.ui.form.CheckBox("Image#scale").set({ value : true}); var setSrcBtn = new qx.ui.form.Button("setGreen"); setSrcBtn.addListener("execute", function(e) { img.setBackgroundColor("green"); }, this); var img = new kreimer.MyImage2("http://support.showreelfinder.com/hc/en-us/article_attachments/201500876/reset.png").set({ cursor : "pointer", backgroundColor : "orange", height : 64, width : 64, scale : true }); var doc = this.getRoot(); doc.add(btn, { left: 10, top: 10 }); doc.add(setSrcBtn, { left: 150, top: 10 }); doc.add(img, { left: 10, top: 50 }); btn.bind("value", img, "scale"); -- View this message in context: http://qooxdoo.678.n2.nabble.com/cursor-on-images-with-scale-true-tp7588002p7588101.html Sent from the qooxdoo mailing list archive at Nabble.com. ------------------------------------------------------------------------------ Site24x7 APM Insight: Get Deep Visibility into Application Performance APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month Monitor end-to-end web transactions and take corrective actions now Troubleshoot faster and improve end-user experience. Signup Now! http://pubads.g.doubleclick.net/gampad/clk?id=272487151&iu=/4140 _______________________________________________ qooxdoo-devel mailing list qooxdoo-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel