From 53a12f615ad79a7c6c478ed51fabaaaef75037ab Mon Sep 17 00:00:00 2001 From: Matti Tahvonen Date: Mon, 8 Dec 2008 14:15:24 +0000 Subject: [PATCH] fixes #2297, #2287 and optimizes other onload event handlings. svn changeset:6121/svn branch:trunk --- .../toolkit/terminal/gwt/client/ICaption.java | 9 +-- .../toolkit/terminal/gwt/client/Util.java | 64 +++++++++++++-- .../terminal/gwt/client/ui/IButton.java | 7 +- .../terminal/gwt/client/ui/ICheckBox.java | 6 +- .../terminal/gwt/client/ui/ICustomLayout.java | 80 +++++++++++-------- .../terminal/gwt/client/ui/IEmbedded.java | 8 +- .../terminal/gwt/client/ui/IGridLayout.java | 5 +- .../terminal/gwt/client/ui/ILabel.java | 25 ++++++ .../toolkit/terminal/gwt/client/ui/ILink.java | 6 +- 9 files changed, 138 insertions(+), 72 deletions(-) diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ICaption.java b/src/com/itmill/toolkit/terminal/gwt/client/ICaption.java index 2b99b3fb1a..f1e73ef536 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/ICaption.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ICaption.java @@ -4,14 +4,10 @@ package com.itmill.toolkit.terminal.gwt.client; -import java.util.HashSet; -import java.util.Set; - import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.HTML; -import com.google.gwt.user.client.ui.Widget; import com.itmill.toolkit.terminal.gwt.client.ui.Icon; public class ICaption extends HTML { @@ -236,11 +232,8 @@ public class ICaption extends HTML { * The size of the icon might affect the size of the component so we * must report the size change to the parent */ - Set w = new HashSet(); - w.add((Widget) owner); - Util.componentSizeUpdated(w); + Util.notifyParentOfSizeChange(this, true); } - } public static boolean isNeeded(UIDL uidl) { diff --git a/src/com/itmill/toolkit/terminal/gwt/client/Util.java b/src/com/itmill/toolkit/terminal/gwt/client/Util.java index c08648089c..183a5001e0 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/Util.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/Util.java @@ -14,6 +14,7 @@ import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.DeferredCommand; import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.HasWidgets; import com.google.gwt.user.client.ui.RootPanel; @@ -34,6 +35,56 @@ public class Util { debugger; }-*/; + private static final int LAZY_SIZE_CHANGE_TIMEOUT = 400; + private static Set latelyChangedWidgets = new HashSet(); + + private static Timer lazySizeChangeTimer = new Timer() { + private boolean lazySizeChangeTimerScheduled = false; + + public void run() { + componentSizeUpdated(latelyChangedWidgets); + latelyChangedWidgets.clear(); + lazySizeChangeTimerScheduled = false; + } + + @Override + public void schedule(int delayMillis) { + if (lazySizeChangeTimerScheduled) { + cancel(); + } else { + lazySizeChangeTimerScheduled = true; + } + super.schedule(delayMillis); + } + }; + + /** + * This helper method can be called if components size have been changed + * outside rendering phase. It notifies components parent about the size + * change so it can react. + * + * When using this method, developer should consider if size changes could + * be notified lazily. If lazy flag is true, method will save widget and + * wait for a moment until it notifies parents in chunks. This may vastly + * optimize layout in various situation. Example: if component have a lot of + * images their onload events may fire "layout phase" many times in a short + * period. + * + * @param widget + * @param lazy + * run componentSizeUpdated lazyly + */ + public static void notifyParentOfSizeChange(Widget widget, boolean lazy) { + if (lazy) { + latelyChangedWidgets.add(widget); + lazySizeChangeTimer.schedule(LAZY_SIZE_CHANGE_TIMEOUT); + } else { + Set widgets = new HashSet(); + widgets.add(widget); + Util.componentSizeUpdated(widgets); + } + } + /** * Called when the size of one or more widgets have changed during * rendering. Finds parent container and notifies them of the size change. @@ -428,13 +479,14 @@ public class Util { RootPanel.getBodyElement().appendChild(scroller); detectedScrollbarSize = scroller.getOffsetWidth() - scroller.getPropertyInt("clientWidth"); - + // Asserting the detected value causes a problem - // at least in Hosted Mode Browser/Linux/GWT-1.5.3, so - // use a default if detection fails. - if (detectedScrollbarSize == 0) - detectedScrollbarSize = 20; - + // at least in Hosted Mode Browser/Linux/GWT-1.5.3, so + // use a default if detection fails. + if (detectedScrollbarSize == 0) { + detectedScrollbarSize = 20; + } + RootPanel.getBodyElement().removeChild(scroller); } diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/IButton.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/IButton.java index 1faeda88ec..80d5078e6f 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/ui/IButton.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/IButton.java @@ -4,8 +4,6 @@ package com.itmill.toolkit.terminal.gwt.client.ui; -import java.util.HashSet; - import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; @@ -128,9 +126,8 @@ public class IButton extends Button implements Paintable { super.onBrowserEvent(event); if (DOM.eventGetType(event) == Event.ONLOAD) { - HashSet set = new HashSet(); - set.add(this); - Util.componentSizeUpdated(set); + Util.notifyParentOfSizeChange(this, true); + } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) { clickPending = true; } else if (DOM.eventGetType(event) == Event.ONMOUSEMOVE) { diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/ICheckBox.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/ICheckBox.java index c3b3c8d0c0..96db1ed2c2 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/ui/ICheckBox.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/ICheckBox.java @@ -4,8 +4,6 @@ package com.itmill.toolkit.terminal.gwt.client.ui; -import java.util.HashSet; - import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; @@ -96,9 +94,7 @@ public class ICheckBox extends com.google.gwt.user.client.ui.CheckBox implements public void onBrowserEvent(Event event) { super.onBrowserEvent(event); if (event.getTypeInt() == Event.ONLOAD) { - HashSet set = new HashSet(); - set.add(this); - Util.componentSizeUpdated(set); + Util.notifyParentOfSizeChange(this, true); } if (client != null) { client.handleTooltipEvent(event, this); diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/ICustomLayout.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/ICustomLayout.java index e3e2cda345..03eea1a630 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/ui/ICustomLayout.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/ICustomLayout.java @@ -9,8 +9,11 @@ import java.util.HashSet; import java.util.Iterator; import java.util.Set; +import com.google.gwt.dom.client.ImageElement; +import com.google.gwt.dom.client.NodeList; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.ComplexPanel; import com.google.gwt.user.client.ui.Widget; import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection; @@ -21,6 +24,7 @@ import com.itmill.toolkit.terminal.gwt.client.ICaptionWrapper; import com.itmill.toolkit.terminal.gwt.client.Paintable; import com.itmill.toolkit.terminal.gwt.client.RenderSpace; import com.itmill.toolkit.terminal.gwt.client.UIDL; +import com.itmill.toolkit.terminal.gwt.client.Util; /** * Custom Layout implements complex layout defined with HTML template. @@ -56,6 +60,8 @@ public class ICustomLayout extends ComplexPanel implements Paintable, /** Has the template been loaded from contents passed in UIDL **/ private boolean hasTemplateContents = false; + private Element elementWithNativeResizeFunction; + public ICustomLayout() { setElement(DOM.createDiv()); // Clear any unwanted styling @@ -204,16 +210,20 @@ public class ICustomLayout extends ComplexPanel implements Paintable, // Connect body of the template to DOM template = extractBodyAndScriptsFromTemplate(template); - DOM.setInnerHTML(getElement(), template); + getElement().setInnerHTML(template); // Remap locations to elements locationToElement.clear(); scanForLocations(getElement()); String themeUri = client.getThemeUri(); - prefixImgSrcs(getElement(), themeUri + "/layouts/"); + initImgElements(getElement(), themeUri + "/layouts/"); - publishResizedFunction(DOM.getFirstChild(getElement())); + elementWithNativeResizeFunction = DOM.getFirstChild(getElement()); + if (elementWithNativeResizeFunction == null) { + elementWithNativeResizeFunction = getElement(); + } + publishResizedFunction(elementWithNativeResizeFunction); } @@ -236,10 +246,10 @@ public class ICustomLayout extends ComplexPanel implements Paintable, /** Collect locations from template */ private void scanForLocations(Element elem) { - final String location = getLocation(elem); - if (location != null) { + final String location = elem.getAttribute("location"); + if (!"".equals(location)) { locationToElement.put(location, elem); - DOM.setInnerHTML(elem, ""); + elem.setInnerHTML(""); } else { final int len = DOM.getChildCount(elem); for (int i = 0; i < len; i++) { @@ -248,12 +258,6 @@ public class ICustomLayout extends ComplexPanel implements Paintable, } } - /** Get the location attribute for given element */ - private static native String getLocation(Element elem) - /*-{ - return elem.getAttribute("location"); - }-*/; - /** Evaluate given script in browser document */ private static native void eval(String script) /*-{ @@ -264,25 +268,28 @@ public class ICustomLayout extends ComplexPanel implements Paintable, } }-*/; - /** Prefix all img tag srcs with given prefix. */ - private static native void prefixImgSrcs(Element e, String srcPrefix) - /*-{ - try { - var divs = e.getElementsByTagName("img"); - var base = "" + $doc.location; - var l = base.length-1; - while (l >= 0 && base.charAt(l) != "/") l--; - base = base.substring(0,l+1); - for (var i = 0; i < divs.length; i++) { - var div = divs[i]; - var src = div.getAttribute("src"); - if (src.indexOf("/")==0 || src.match(/\w+:\/\//)) { - continue; - } - div.setAttribute("src",srcPrefix + src); - } - } catch (e) { alert(e + " " + srcPrefix);} - }-*/; + /** + * Img elements needs some special handling in custom layout + * + * Prefixes img tag srcs with given prefix, if it has a relative uri. + * + * Img elements will also get their onload events sunk to notify paren of + * possible size change. + * + */ + private static void initImgElements(Element e, String srcPrefix) { + NodeList nodeList = e + .getElementsByTagName("IMG"); + for (int i = 0; i < nodeList.getLength(); i++) { + com.google.gwt.dom.client.ImageElement img = (ImageElement) nodeList + .getItem(i); + String src = img.getSrc(); + if (!(src.startsWith("/") || src.contains("://"))) { + img.setSrc(srcPrefix + src); + } + DOM.sinkEvents((Element) img.cast(), Event.ONLOAD); + } + } /** * Extract body part and script tags from raw html-template. @@ -436,7 +443,7 @@ public class ICustomLayout extends ComplexPanel implements Paintable, @Override public void onDetach() { super.onDetach(); - detachResizedFunction(DOM.getFirstChild(getElement())); + detachResizedFunction(elementWithNativeResizeFunction); } private native void detachResizedFunction(Element element) @@ -491,4 +498,13 @@ public class ICustomLayout extends ComplexPanel implements Paintable, return new RenderSpace(pe.getOffsetWidth(), pe.getOffsetHeight(), true); } + @Override + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + if (event.getTypeInt() == Event.ONLOAD) { + Util.notifyParentOfSizeChange(this, true); + event.cancelBubble(true); + } + } + } diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/IEmbedded.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/IEmbedded.java index 883a75c333..5598552dbb 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/ui/IEmbedded.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/IEmbedded.java @@ -4,14 +4,10 @@ package com.itmill.toolkit.terminal.gwt.client.ui; -import java.util.HashSet; -import java.util.Set; - import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.HTML; -import com.google.gwt.user.client.ui.Widget; import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection; import com.itmill.toolkit.terminal.gwt.client.Paintable; import com.itmill.toolkit.terminal.gwt.client.UIDL; @@ -137,9 +133,7 @@ public class IEmbedded extends HTML implements Paintable { public void onBrowserEvent(Event event) { super.onBrowserEvent(event); if (DOM.eventGetType(event) == Event.ONLOAD) { - Set w = new HashSet(); - w.add(this); - Util.componentSizeUpdated(w); + Util.notifyParentOfSizeChange(this, true); } } } diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/IGridLayout.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/IGridLayout.java index b4c2f862ef..e135c30b29 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/ui/IGridLayout.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/IGridLayout.java @@ -327,11 +327,8 @@ public class IGridLayout extends SimplePanel implements Paintable, Container { client.handleComponentRelativeSize((Widget) c); } if (heightChanged && "".equals(height)) { - Set s = new HashSet(); - s.add(this); - Util.componentSizeUpdated(s); + Util.notifyParentOfSizeChange(this, false); } - } } } diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/ILabel.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/ILabel.java index 1336578fb7..77addf8323 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/ui/ILabel.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/ILabel.java @@ -4,6 +4,9 @@ package com.itmill.toolkit.terminal.gwt.client.ui; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.NodeList; +import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.HTML; import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection; @@ -33,6 +36,11 @@ public class ILabel extends HTML implements Paintable { public void onBrowserEvent(Event event) { super.onBrowserEvent(event); + if (event.getTypeInt() == Event.ONLOAD) { + Util.notifyParentOfSizeChange(this, true); + event.cancelBubble(true); + return; + } if (client != null) { client.handleTooltipEvent(event, this); } @@ -46,6 +54,8 @@ public class ILabel extends HTML implements Paintable { this.client = client; + boolean sinkOnloads = false; + final String mode = uidl.getStringAttribute("mode"); if (mode == null || "text".equals(mode)) { setText(uidl.getChildString(0)); @@ -55,13 +65,28 @@ public class ILabel extends HTML implements Paintable { setHTML(uidl.getChildrenAsXML()); } else if ("xhtml".equals(mode)) { setHTML(uidl.getChildUIDL(0).getChildUIDL(0).getChildString(0)); + sinkOnloads = true; } else if ("xml".equals(mode)) { setHTML(uidl.getChildUIDL(0).getChildString(0)); } else if ("raw".equals(mode)) { setHTML(uidl.getChildUIDL(0).getChildString(0)); + sinkOnloads = true; } else { setText(""); } + if (sinkOnloads) { + sinkOnloadsForContainedImgs(); + } + } + + private void sinkOnloadsForContainedImgs() { + NodeList images = getElement().getElementsByTagName("img"); + for (int i = 0; i < images.getLength(); i++) { + Element img = images.getItem(i); + DOM.sinkEvents((com.google.gwt.user.client.Element) img, + Event.ONLOAD); + } + } @Override diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/ILink.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/ILink.java index 80154fb9d0..4e5f5ee34c 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/ui/ILink.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/ILink.java @@ -4,8 +4,6 @@ package com.itmill.toolkit.terminal.gwt.client.ui; -import java.util.HashSet; - import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; @@ -164,9 +162,7 @@ public class ILink extends HTML implements Paintable, ClickListener { public void onBrowserEvent(Event event) { final Element target = DOM.eventGetTarget(event); if (event.getTypeInt() == Event.ONLOAD) { - HashSet set = new HashSet(); - set.add(this); - Util.componentSizeUpdated(set); + Util.notifyParentOfSizeChange(this, true); } if (client != null) { client.handleTooltipEvent(event, this); -- 2.39.5