Fix bug for IE frames where onload events don't fire.

Issue: http://code.google.com/p/google-webtoolkit/issues/detail?id=1720

Review at http://gwt-code-reviews.appspot.com/1353801

Review by: jlabanca@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9785 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplOpera.java b/user/src/com/google/gwt/user/client/impl/DOMImplOpera.java
index 5b02b1c..abc2162 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplOpera.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplOpera.java
@@ -59,7 +59,7 @@
     elem.onscroll      = (bits & 0x04000) ?
         @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent : null;
     elem.onload        = (bits & 0x08000) ?
-        @com.google.gwt.user.client.impl.DOMImplStandard::dispatchUnhandledEvent : null;
+        @com.google.gwt.user.client.impl.DOMImplStandard::dispatchOnLoadEvent : null;
     elem.onerror       = (bits & 0x10000) ?
         @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent : null;
     elem.onmousewheel  = (bits & 0x20000) ?
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java b/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
index f40b951..ca0a226 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
@@ -39,7 +39,7 @@
   private static JavaScriptObject dispatchEvent;
 
   @SuppressWarnings("unused")
-  private static JavaScriptObject dispatchUnhandledEvent;
+  private static JavaScriptObject dispatchOnLoadEvent;
 
   @Override
   public Element eventGetFromElement(Event evt) {
@@ -167,8 +167,8 @@
       return true;
     });
 
-    @com.google.gwt.user.client.impl.DOMImplStandard::dispatchUnhandledEvent = $entry(function(evt) {
-      this.__gwtLastUnhandledEvent = evt.type;
+    @com.google.gwt.user.client.impl.DOMImplStandard::dispatchOnLoadEvent = $entry(function(evt) {
+      this.__gwtLastOnLoadEvent = evt.type;
       @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent.call(this, evt);
     });
 
@@ -248,7 +248,7 @@
     if (chMask & 0x04000) elem.onscroll      = (bits & 0x04000) ?
         @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent : null;
     if (chMask & 0x08000) elem.onload        = (bits & 0x08000) ?
-        @com.google.gwt.user.client.impl.DOMImplStandard::dispatchUnhandledEvent : null;
+        @com.google.gwt.user.client.impl.DOMImplStandard::dispatchOnLoadEvent : null;
     if (chMask & 0x10000) elem.onerror       = (bits & 0x10000) ?
         @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent : null;
     if (chMask & 0x20000) elem.onmousewheel  = (bits & 0x20000) ? 
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplTrident.java b/user/src/com/google/gwt/user/client/impl/DOMImplTrident.java
index 7bed0d0..4419056 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplTrident.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplTrident.java
@@ -31,7 +31,7 @@
   private static JavaScriptObject callDispatchDblClickEvent;
 
   @SuppressWarnings("unused")
-  private static JavaScriptObject callDispatchUnhandledEvent;
+  private static JavaScriptObject callDispatchOnLoadEvent;
 
   /**
    * Let every GWT app on the page preview the current event. If any app cancels
@@ -154,8 +154,8 @@
       }
     });
 
-    var dispatchUnhandledEvent = $entry(function() {
-      this.__gwtLastUnhandledEvent = $wnd.event.type;
+    var dispatchOnLoadEvent = $entry(function() {
+      this.__gwtLastOnLoadEvent = $wnd.event.type;
       dispatchEvent.call(this);
     });
 
@@ -173,9 +173,9 @@
     @com.google.gwt.user.client.impl.DOMImplTrident::callDispatchDblClickEvent = new Function('w',
       'return function() { w.__gwt_dispatchDblClickEvent_' + moduleName + '.call(this)}')($wnd);
  
-    $wnd['__gwt_dispatchUnhandledEvent_' + moduleName] = dispatchUnhandledEvent;
-    @com.google.gwt.user.client.impl.DOMImplTrident::callDispatchUnhandledEvent = new Function('w',
-      'return function() { w.__gwt_dispatchUnhandledEvent_' + moduleName + '.call(this)}')($wnd);
+    $wnd['__gwt_dispatchOnLoadEvent_' + moduleName] = dispatchOnLoadEvent;
+    @com.google.gwt.user.client.impl.DOMImplTrident::callDispatchOnLoadEvent = new Function('w',
+      'return function() { w.__gwt_dispatchOnLoadEvent_' + moduleName + '.call(w.event.srcElement)}')($wnd);
 
     // We need to create these delegate functions to fix up the 'this' context.
     // Normally, 'this' is the firing element, but this is only true for
@@ -268,8 +268,13 @@
         @com.google.gwt.user.client.impl.DOMImplTrident::callDispatchEvent : null;
     if (chMask & 0x04000) elem.onscroll      = (bits & 0x04000) ?
         @com.google.gwt.user.client.impl.DOMImplTrident::callDispatchEvent : null;
-    if (chMask & 0x08000) elem.onload        = (bits & 0x08000) ?
-        @com.google.gwt.user.client.impl.DOMImplTrident::callDispatchUnhandledEvent : null;
+    if (chMask & 0x08000) {
+      if (bits & 0x08000) {
+        elem.attachEvent('onload', @com.google.gwt.user.client.impl.DOMImplTrident::callDispatchOnLoadEvent);
+      } else {
+        elem.detachEvent('onload', @com.google.gwt.user.client.impl.DOMImplTrident::callDispatchOnLoadEvent);
+      }
+    }
     if (chMask & 0x10000) elem.onerror       = (bits & 0x10000) ?
         @com.google.gwt.user.client.impl.DOMImplTrident::callDispatchEvent : null;
     if (chMask & 0x20000) elem.onmousewheel  = (bits & 0x20000) ? 
diff --git a/user/src/com/google/gwt/user/client/ui/Frame.java b/user/src/com/google/gwt/user/client/ui/Frame.java
index c6b09da..0471176 100644
--- a/user/src/com/google/gwt/user/client/ui/Frame.java
+++ b/user/src/com/google/gwt/user/client/ui/Frame.java
@@ -15,10 +15,16 @@
  */
 package com.google.gwt.user.client.ui;
 
+import com.google.gwt.user.client.Event;
+
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.FrameElement;
 import com.google.gwt.dom.client.IFrameElement;
+import com.google.gwt.event.dom.client.HasLoadHandlers;
+import com.google.gwt.event.dom.client.LoadEvent;
+import com.google.gwt.event.dom.client.LoadHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
 
 /**
  * A widget that wraps an IFRAME element, which can contain an arbitrary web
@@ -37,7 +43,7 @@
  * <h3>Example</h3> {@example com.google.gwt.examples.FrameExample}
  * </p>
  */
-public class Frame extends Widget {
+public class Frame extends Widget implements HasLoadHandlers {
 
   static final String DEFAULT_STYLENAME = "gwt-Frame";
 
@@ -69,6 +75,8 @@
   public Frame() {
     setElement(Document.get().createIFrameElement());
     setStyleName(DEFAULT_STYLENAME);
+
+    sinkEvents(Event.ONLOAD);
   }
 
   /**
@@ -93,6 +101,17 @@
   }
 
   /**
+   * Adds a {@link LoadEvent} load handler which will be called
+   * when the frame loads.
+   *
+   * @param handler the load handler
+   * @return {@link HandlerRegistration} that can be used to remove this handler
+   */
+  public HandlerRegistration addLoadHandler(LoadHandler handler) {
+    return addHandler(handler, LoadEvent.getType());
+  }
+
+  /**
    * Gets the URL of the frame's resource.
    * 
    * @return the frame's URL
diff --git a/user/src/com/google/gwt/user/client/ui/Image.java b/user/src/com/google/gwt/user/client/ui/Image.java
index b057c2c..04a28fc 100644
--- a/user/src/com/google/gwt/user/client/ui/Image.java
+++ b/user/src/com/google/gwt/user/client/ui/Image.java
@@ -117,7 +117,7 @@
    * The attribute that is set when an image fires a native load or error event
    * before it is attached.
    */
-  private static final String UNHANDLED_EVENT_ATTR = "__gwtLastUnhandledEvent";
+  private static final String UNHANDLED_EVENT_ATTR = "__gwtLastOnLoadEvent";
 
   /**
    * Implementation of behaviors associated with the clipped state of an image.
diff --git a/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImpl.java b/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImpl.java
index 9d112af..9a39dbf 100644
--- a/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImpl.java
+++ b/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImpl.java
@@ -51,7 +51,7 @@
         + (-top + "px");
 
     String clippedImgHtml = "<img "
-        + "onload='this.__gwtLastUnhandledEvent=\"load\";' src='"
+        + "onload='this.__gwtLastOnLoadEvent=\"load\";' src='"
         + GWT.getModuleBaseURL() + "clear.cache.gif' style='" + style
         + "' border='0'>";
 
diff --git a/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImplIE6.java b/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImplIE6.java
index 8895b68..5155253 100644
--- a/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImplIE6.java
+++ b/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImplIE6.java
@@ -115,7 +115,7 @@
      */
     String clippedImgHtml = "<gwt:clipper style=\""
         + clipperStyle
-        + "\"><img onload='this.__gwtLastUnhandledEvent=\"load\";' src='"
+        + "\"><img onload='this.__gwtLastOnLoadEvent=\"load\";' src='"
         + moduleBaseUrlProtocol
         + "' onerror='if(window.__gwt_transparentImgHandler)window.__gwt_transparentImgHandler(this);else this.src=\"" + GWT.getModuleBaseURL() + "clear.cache.gif\"' style=\""
         + imgStyle + "\" width=" + (left + width) + " height=" + (top + height)
diff --git a/user/test/com/google/gwt/dom/DOMSuite.java b/user/test/com/google/gwt/dom/DOMSuite.java
index 42d0be6..231c3d8 100644
--- a/user/test/com/google/gwt/dom/DOMSuite.java
+++ b/user/test/com/google/gwt/dom/DOMSuite.java
@@ -18,6 +18,7 @@
 import com.google.gwt.dom.client.DocumentTest;
 import com.google.gwt.dom.client.ElementTest;
 import com.google.gwt.dom.client.FormTests;
+import com.google.gwt.dom.client.FrameTests;
 import com.google.gwt.dom.client.MapTests;
 import com.google.gwt.dom.client.NodeTest;
 import com.google.gwt.dom.client.SelectTests;
@@ -40,6 +41,7 @@
     suite.addTestSuite(NodeTest.class);
     suite.addTestSuite(ElementTest.class);
     suite.addTestSuite(FormTests.class);
+    suite.addTestSuite(FrameTests.class);
     suite.addTestSuite(MapTests.class);
     suite.addTestSuite(SelectTests.class);
     suite.addTestSuite(StyleInjectorTest.class);
diff --git a/user/test/com/google/gwt/dom/client/FrameTests.java b/user/test/com/google/gwt/dom/client/FrameTests.java
index 183ea9d..cb6226a 100644
--- a/user/test/com/google/gwt/dom/client/FrameTests.java
+++ b/user/test/com/google/gwt/dom/client/FrameTests.java
@@ -16,12 +16,20 @@
 package com.google.gwt.dom.client;
 
 import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Frame;
+import com.google.gwt.user.client.ui.RootPanel;
+
+import com.google.gwt.event.dom.client.LoadEvent;
+import com.google.gwt.event.dom.client.LoadHandler;
 
 /**
  * Tests for the FrameElement and IFrameElement classes.
  */
 public class FrameTests extends GWTTestCase {
 
+  private static final int FRAME_LOAD_DELAY = 3000;
+
   @Override
   public String getModuleName() {
     return "com.google.gwt.dom.DOMTest";
@@ -34,4 +42,52 @@
     doc.getBody().appendChild(iframe);
     assertNotNull(iframe.getContentDocument());
   }
+
+  public void testOnLoadEventFiresWithBrowerEvent() {
+    delayTestFinish(FRAME_LOAD_DELAY);
+
+    Frame frame = new Frame() {
+      public void onBrowserEvent(Event event) {
+        if (event.getTypeInt() == Event.ONLOAD) {
+          finishTest();
+        }
+        super.onBrowserEvent(event);
+      }
+    };
+
+    frame.sinkEvents(Event.ONLOAD);
+    RootPanel.get().add(frame);
+    frame.setUrl("iframetest.html");
+  }
+
+  public void testOnLoadEventFiresWithLoadHandler() {
+    delayTestFinish(FRAME_LOAD_DELAY);
+
+    Frame frame = new Frame();
+    frame.addLoadHandler(new LoadHandler() {
+      public void onLoad(LoadEvent event) {
+        finishTest();
+      }
+    });
+
+    RootPanel.get().add(frame);
+    frame.setUrl("iframetest.html");
+  }
+
+  public void testOnLoadEventFiresWithDomLoadHandler() {
+    delayTestFinish(FRAME_LOAD_DELAY);
+
+    Frame frame = new Frame() {
+      {
+        addDomHandler(new LoadHandler() {
+          public void onLoad(LoadEvent event) {
+            finishTest();
+          }
+        }, LoadEvent.getType());
+      }
+    };
+
+    RootPanel.get().add(frame);
+    frame.setUrl("iframetest.html");
+  }
 }
diff --git a/user/test/com/google/gwt/dom/public-test/iframetest.html b/user/test/com/google/gwt/dom/public-test/iframetest.html
new file mode 100644
index 0000000..7e315bb
--- /dev/null
+++ b/user/test/com/google/gwt/dom/public-test/iframetest.html
@@ -0,0 +1,10 @@
+<html>
+<body>
+IFRAME TEST
+</body>
+</html>
+<html>
+<body>
+IFRAME TEST
+</body>
+</html>
\ No newline at end of file