]> source.dussan.org Git - vaadin-framework.git/commitdiff
fixes #2297, #2287 and optimizes other onload event handlings.
authorMatti Tahvonen <matti.tahvonen@itmill.com>
Mon, 8 Dec 2008 14:15:24 +0000 (14:15 +0000)
committerMatti Tahvonen <matti.tahvonen@itmill.com>
Mon, 8 Dec 2008 14:15:24 +0000 (14:15 +0000)
svn changeset:6121/svn branch:trunk

src/com/itmill/toolkit/terminal/gwt/client/ICaption.java
src/com/itmill/toolkit/terminal/gwt/client/Util.java
src/com/itmill/toolkit/terminal/gwt/client/ui/IButton.java
src/com/itmill/toolkit/terminal/gwt/client/ui/ICheckBox.java
src/com/itmill/toolkit/terminal/gwt/client/ui/ICustomLayout.java
src/com/itmill/toolkit/terminal/gwt/client/ui/IEmbedded.java
src/com/itmill/toolkit/terminal/gwt/client/ui/IGridLayout.java
src/com/itmill/toolkit/terminal/gwt/client/ui/ILabel.java
src/com/itmill/toolkit/terminal/gwt/client/ui/ILink.java

index 2b99b3fb1a3a5227e95123b668bbaea33375486f..f1e73ef5368c1f530bfd8993d874bf43258b6495 100644 (file)
@@ -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<Widget> w = new HashSet<Widget>();
-            w.add((Widget) owner);
-            Util.componentSizeUpdated(w);
+            Util.notifyParentOfSizeChange(this, true);
         }
-
     }
 
     public static boolean isNeeded(UIDL uidl) {
index c08648089cec22b7d336c3f23ca6e0a9370fbd92..183a5001e03ccbc463194da34702058f5ed968a2 100644 (file)
@@ -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<Widget> latelyChangedWidgets = new HashSet<Widget>();
+
+    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<Widget> widgets = new HashSet<Widget>();
+            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);
 
         }
index 1faeda88ecb38503868a760f3773bda968717ef4..80d5078e6f0d84108e73b0603c62d0b97db70df8 100644 (file)
@@ -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<Widget> set = new HashSet<Widget>();
-            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) {
index c3b3c8d0c003065d83f23e3b177348aada64aa04..96db1ed2c210ba82f8f4a71e3636c61c79377ce0 100644 (file)
@@ -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<Widget> set = new HashSet<Widget>();
-            set.add(this);
-            Util.componentSizeUpdated(set);
+            Util.notifyParentOfSizeChange(this, true);
         }
         if (client != null) {
             client.handleTooltipEvent(event, this);
index e3e2cda345e58c22b711806c7962201fc9833e8b..03eea1a63066b7a10d5f3a68e567c631bfd79d98 100644 (file)
@@ -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<com.google.gwt.dom.client.Element> 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);
+        }
+    }
+
 }
index 883a75c3339022399d417d352c701b44b81d850f..5598552dbbe7dd53a598dfc5275425b6ce36c441 100644 (file)
@@ -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<Widget> w = new HashSet<Widget>();
-            w.add(this);
-            Util.componentSizeUpdated(w);
+            Util.notifyParentOfSizeChange(this, true);
         }
     }
 }
index b4c2f862ef32a31aa8dd9e4567f5cfd97f9d2f32..e135c30b2971866a06e166070f138cb3e17d692c 100644 (file)
@@ -327,11 +327,8 @@ public class IGridLayout extends SimplePanel implements Paintable, Container {
                     client.handleComponentRelativeSize((Widget) c);
                 }
                 if (heightChanged && "".equals(height)) {
-                    Set<Widget> s = new HashSet<Widget>();
-                    s.add(this);
-                    Util.componentSizeUpdated(s);
+                    Util.notifyParentOfSizeChange(this, false);
                 }
-
             }
         }
     }
index 1336578fb7e6035f7bf6e4bd37fc8d9ffdb47359..77addf832313dbacbe1d0fbe19e1e3ba79775d1c 100644 (file)
@@ -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<Element> 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
index 80154fb9d0f0499d687b6c03d5e42cc0a9f46060..4e5f5ee34c58f89c9d5a94eb8464a45c5c318959 100644 (file)
@@ -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<Widget> set = new HashSet<Widget>();
-            set.add(this);
-            Util.componentSizeUpdated(set);
+            Util.notifyParentOfSizeChange(this, true);
         }
         if (client != null) {
             client.handleTooltipEvent(event, this);