Hi Bernardo That looks like a sensible fix - please can you submit it as a pull request?
Cheers John On 23/02/2016, 13:49, "kreimer" <kreimerkrei...@gmail.com> wrote: >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 ------------------------------------------------------------------------------ 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