One more fix to address Window level events.  This time, all browsers except IE sink the events directly on the outer window.  IE still embeds a script element on the outer window in order to sink events in the correct context.

Patch by: jlabanca
Review by: ajr (desk)



git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@3607 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/client/Window.java b/user/src/com/google/gwt/user/client/Window.java
index 4e3b2a6..7667fd9 100644
--- a/user/src/com/google/gwt/user/client/Window.java
+++ b/user/src/com/google/gwt/user/client/Window.java
@@ -253,12 +253,8 @@
   public static void addWindowResizeListener(WindowResizeListener listener) {
     if (resizeListeners == null) {
       resizeListeners = new ArrayList<WindowResizeListener>();
-      initHandler(getWindowResizeHandlerMethodString(),
-          "__gwt_initWindowResizeHandler", new Command() {
-            public void execute() {
-              initWindowResizeHandler();
-            }
-          });
+      maybeInitializeCloseHandlers();
+      impl.initWindowResizeHandler();
     }
     resizeListeners.add(listener);
   }
@@ -271,12 +267,8 @@
   public static void addWindowScrollListener(WindowScrollListener listener) {
     if (scrollListeners == null) {
       scrollListeners = new ArrayList<WindowScrollListener>();
-      initHandler(getWindowScrollHandlerMethodString(),
-          "__gwt_initWindowScrollHandler", new Command() {
-            public void execute() {
-              initWindowScrollHandler();
-            }
-          });
+      maybeInitializeCloseHandlers();
+      impl.initWindowScrollHandler();
     }
     scrollListeners.add(listener);
   }
@@ -577,150 +569,10 @@
     }
   }
 
-  /**
-   * This method defines a function that sinks an event on the Window.  However,
-   * this method returns the function as a String so it can be added to the
-   * outer window.
-   * 
-   * We need to declare this method on the outer window because you cannot
-   * attach Window listeners from within an iframe on IE6.
-   * 
-   * Per ECMAScript 262 spec 15.3.4.2, Function.prototype.toString() returns a
-   * string representation of the function that has the syntax of the function.
-   */
-  private static native String getWindowCloseHandlerMethodString() /*-{
-    return function(beforeunload, unload) {
-      var wnd = window
-      , oldOnBeforeUnload = wnd.onbeforeunload
-      , oldOnUnload = wnd.onunload;
-      
-      wnd.onbeforeunload = function(evt) {
-        var ret, oldRet;
-        try {
-          ret = beforeunload();
-        } finally {
-          oldRet = oldOnBeforeUnload && oldOnBeforeUnload(evt);
-        }
-        // Avoid returning null as IE6 will coerce it into a string.
-        // Ensure that "" gets returned properly.
-        if (ret != null) {
-          return ret;
-        }
-        if (oldRet != null) {
-          return oldRet;
-        }
-        // returns undefined.
-      };
-      
-      wnd.onunload = function(evt) {
-        try {
-          unload();
-        } finally {
-          oldOnUnload && oldOnUnload(evt);
-          wnd.onresize = null;
-          wnd.onscroll = null;
-          wnd.onbeforeunload = null;
-          wnd.onunload = null;
-        }
-      };
-      
-      // Remove the reference once we've initialize the handler
-      wnd.__gwt_initWindowCloseHandler = undefined;
-    }.toString();
-  }-*/;
-
-  /**
-   * @see #getWindowCloseHandlerMethodString()
-   */
-  private static native String getWindowResizeHandlerMethodString() /*-{
-    return function(resize) {
-      var wnd = window, oldOnResize = wnd.onresize;
-      
-      wnd.onresize = function(evt) {
-        try {
-          resize();
-        } finally {
-          oldOnResize && oldOnResize(evt);
-        }
-      };
-      
-      // Remove the reference once we've initialize the handler
-      wnd.__gwt_initWindowResizeHandler = undefined;
-    }.toString();
-  }-*/;
-
-  /**
-   * @see #getWindowCloseHandlerMethodString()
-   */
-  private static native String getWindowScrollHandlerMethodString() /*-{
-    return function(scroll) {
-      var wnd = window, oldOnScroll = wnd.onscroll;
-      
-      wnd.onscroll = function(evt) {
-        try {
-          scroll();
-        } finally {
-          oldOnScroll && oldOnScroll(evt);
-        }
-      };
-      
-      // Remove the reference once we've initialize the handler
-      wnd.__gwt_initWindowScrollHandler = undefined;
-    }.toString();
-  }-*/;
-
-  /**
-   * Initialize an event on the outer window.
-   * 
-   * @param initFunc the string representation of the init function
-   * @param funcName the name to assign to the init function
-   * @param cmd the command to execute the init function
-   */
-  private static void initHandler(String initFunc, String funcName, Command cmd) {
-    if (GWT.isClient()) {
-      // Always initialize the close handlers first
-      maybeInitializeCloseHandlers();
-
-      impl.initHandler(initFunc, funcName, cmd);
-    }
-  }
-
-  private static native void initWindowCloseHandler() /*-{
-    $wnd.__gwt_initWindowCloseHandler(
-      function() {
-        return @com.google.gwt.user.client.Window::onClosing()();
-      },
-      function() {
-        @com.google.gwt.user.client.Window::onClosed()();
-      }
-    );
-  }-*/;
-
-  private static native void initWindowResizeHandler() /*-{
-    $wnd.__gwt_initWindowResizeHandler(
-      function() {
-        @com.google.gwt.user.client.Window::onResize()();
-      }
-    );
-  }-*/;
-
-  private static native void initWindowScrollHandler() /*-{
-    $wnd.__gwt_initWindowScrollHandler(
-      function() {
-        @com.google.gwt.user.client.Window::onScroll()();
-      }
-    );
-  }-*/;
-
   private static void maybeInitializeCloseHandlers() {
     if (GWT.isClient() && !handlersAreInitialized) {
-      handlersAreInitialized = true;      
-      initHandler(getWindowCloseHandlerMethodString(),
-          "__gwt_initWindowCloseHandler", new Command() {
-            public void execute() {
-              initWindowCloseHandler();
-            }
-          });
+      handlersAreInitialized = true;
+      impl.initWindowCloseHandler();
     }
   }
 
diff --git a/user/src/com/google/gwt/user/client/impl/WindowImpl.java b/user/src/com/google/gwt/user/client/impl/WindowImpl.java
index 3eaeca2..9bb6333 100644
--- a/user/src/com/google/gwt/user/client/impl/WindowImpl.java
+++ b/user/src/com/google/gwt/user/client/impl/WindowImpl.java
@@ -15,8 +15,6 @@
  */
 package com.google.gwt.user.client.impl;
 
-import com.google.gwt.user.client.Command;
-
 /**
  * Native implementation associated with
  * {@link com.google.gwt.user.client.Window}.
@@ -51,16 +49,60 @@
    return @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.scrollTop;
   }-*/;
 
-  public void initHandler(String initFunc, String funcName, Command cmd) {
-    // Eval the init script
-    initFunc = initFunc.replaceFirst("function", "function " + funcName);
-    eval(initFunc);
+  public native void initWindowCloseHandler() /*-{
+    var oldOnBeforeUnload = $wnd.onbeforeunload;
+    var oldOnUnload = $wnd.onunload;
+    
+    $wnd.onbeforeunload = function(evt) {
+      var ret, oldRet;
+      try {
+        ret = @com.google.gwt.user.client.Window::onClosing()();
+      } finally {
+        oldRet = oldOnBeforeUnload && oldOnBeforeUnload(evt);
+      }
+      // Avoid returning null as IE6 will coerce it into a string.
+      // Ensure that "" gets returned properly.
+      if (ret != null) {
+        return ret;
+      }
+      if (oldRet != null) {
+        return oldRet;
+      }
+      // returns undefined.
+    };
+    
+    $wnd.onunload = function(evt) {
+      try {
+        @com.google.gwt.user.client.Window::onClosed()();
+      } finally {
+        oldOnUnload && oldOnUnload(evt);
+        $wnd.onresize = null;
+        $wnd.onscroll = null;
+        $wnd.onbeforeunload = null;
+        $wnd.onunload = null;
+      }
+    };
+  }-*/;
 
-    // Initialize the handler
-    cmd.execute();
-  }
+  public native void initWindowResizeHandler() /*-{
+    var oldOnResize = $wnd.onresize;
+    $wnd.onresize = function(evt) {
+      try {
+        @com.google.gwt.user.client.Window::onResize()();
+      } finally {
+        oldOnResize && oldOnResize(evt);
+      }
+    };
+  }-*/;
 
-  private native void eval(String expr) /*-{
-    $wnd.eval(expr);
+  public native void initWindowScrollHandler() /*-{
+    var oldOnScroll = $wnd.onscroll;
+    $wnd.onscroll = function(evt) {
+      try {
+        @com.google.gwt.user.client.Window::onScroll()();
+      } finally {
+        oldOnScroll && oldOnScroll(evt);
+      }
+    };
   }-*/;
 }
diff --git a/user/src/com/google/gwt/user/client/impl/WindowImplIE.java b/user/src/com/google/gwt/user/client/impl/WindowImplIE.java
index 6e2d70c..46ec347 100644
--- a/user/src/com/google/gwt/user/client/impl/WindowImplIE.java
+++ b/user/src/com/google/gwt/user/client/impl/WindowImplIE.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.user.client.impl;
 
+import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.ScriptElement;
 import com.google.gwt.user.client.Command;
@@ -51,22 +52,177 @@
     return (questionLoc > 0) ? href.substring(questionLoc) : "";
   }-*/;
 
+  @Override
+  public void initWindowCloseHandler() {
+    initHandler(getWindowCloseHandlerMethodString(),
+        "__gwt_initWindowCloseHandler", new Command() {
+          public void execute() {
+            initWindowCloseHandlerImpl();
+          }
+        });
+  }
+
+  @Override
+  public void initWindowResizeHandler() {
+    initHandler(getWindowResizeHandlerMethodString(),
+        "__gwt_initWindowResizeHandler", new Command() {
+          public void execute() {
+            initWindowResizeHandlerImpl();
+          }
+        });
+  }
+
+  @Override
+  public void initWindowScrollHandler() {
+    initHandler(getWindowScrollHandlerMethodString(),
+        "__gwt_initWindowScrollHandler", new Command() {
+          public void execute() {
+            initWindowScrollHandlerImpl();
+          }
+        });
+  }
+
+  /**
+   * This method defines a function that sinks an event on the Window.  However,
+   * this method returns the function as a String so it can be added to the
+   * outer window.
+   * 
+   * We need to declare this method on the outer window because you cannot
+   * attach Window listeners from within an iframe on IE6.
+   * 
+   * Per ECMAScript 262 spec 15.3.4.2, Function.prototype.toString() returns a
+   * string representation of the function that has the syntax of the function.
+   */
+  private native String getWindowCloseHandlerMethodString() /*-{
+    return function(beforeunload, unload) {
+      var wnd = window
+      , oldOnBeforeUnload = wnd.onbeforeunload
+      , oldOnUnload = wnd.onunload;
+      
+      wnd.onbeforeunload = function(evt) {
+        var ret, oldRet;
+        try {
+          ret = beforeunload();
+        } finally {
+          oldRet = oldOnBeforeUnload && oldOnBeforeUnload(evt);
+        }
+        // Avoid returning null as IE6 will coerce it into a string.
+        // Ensure that "" gets returned properly.
+        if (ret != null) {
+          return ret;
+        }
+        if (oldRet != null) {
+          return oldRet;
+        }
+        // returns undefined.
+      };
+      
+      wnd.onunload = function(evt) {
+        try {
+          unload();
+        } finally {
+          oldOnUnload && oldOnUnload(evt);
+          wnd.onresize = null;
+          wnd.onscroll = null;
+          wnd.onbeforeunload = null;
+          wnd.onunload = null;
+        }
+      };
+      
+      // Remove the reference once we've initialize the handler
+      wnd.__gwt_initWindowCloseHandler = undefined;
+    }.toString();
+  }-*/;
+
+  /**
+   * @see #getWindowCloseHandlerMethodString()
+   */
+  private native String getWindowResizeHandlerMethodString() /*-{
+    return function(resize) {
+      var wnd = window, oldOnResize = wnd.onresize;
+      
+      wnd.onresize = function(evt) {
+        try {
+          resize();
+        } finally {
+          oldOnResize && oldOnResize(evt);
+        }
+      };
+      
+      // Remove the reference once we've initialize the handler
+      wnd.__gwt_initWindowResizeHandler = undefined;
+    }.toString();
+  }-*/;
+
+  /**
+   * @see #getWindowCloseHandlerMethodString()
+   */
+  private native String getWindowScrollHandlerMethodString() /*-{
+    return function(scroll) {
+      var wnd = window, oldOnScroll = wnd.onscroll;
+      
+      wnd.onscroll = function(evt) {
+        try {
+          scroll();
+        } finally {
+          oldOnScroll && oldOnScroll(evt);
+        }
+      };
+      
+      // Remove the reference once we've initialize the handler
+      wnd.__gwt_initWindowScrollHandler = undefined;
+    }.toString();
+  }-*/;
+
   /**
    * IE6 does not allow direct access to event handlers on the parent window,
    * so we must embed a script in the parent window that will set the event
    * handlers in the correct context.
+   * 
+   * @param initFunc the string representation of the init function
+   * @param funcName the name to assign to the init function
+   * @param cmd the command to execute the init function
    */
-  @Override
-  public void initHandler(String initFunc, String funcName, Command cmd) {
-    // Embed the init script on the page
-    initFunc = initFunc.replaceFirst("function", "function " + funcName);
-    ScriptElement scriptElem = Document.get().createScriptElement(initFunc);
-    Document.get().getBody().appendChild(scriptElem);
-
-    // Initialize the handler
-    cmd.execute();
-
-    // Remove the script element
-    Document.get().getBody().removeChild(scriptElem);
+  private void initHandler(String initFunc, String funcName, Command cmd) {
+    if (GWT.isClient()) {
+      // Embed the init script on the page
+      initFunc = initFunc.replaceFirst("function", "function " + funcName);
+      ScriptElement scriptElem = Document.get().createScriptElement(initFunc);
+      Document.get().getBody().appendChild(scriptElem);
+  
+      // Initialize the handler
+      cmd.execute();
+  
+      // Remove the script element
+      Document.get().getBody().removeChild(scriptElem);
+    }
   }
+
+  private native void initWindowCloseHandlerImpl() /*-{
+    $wnd.__gwt_initWindowCloseHandler(
+      function() {
+        return @com.google.gwt.user.client.Window::onClosing()();
+      },
+      function() {
+        @com.google.gwt.user.client.Window::onClosed()();
+      }
+    );
+  }-*/;
+
+  private native void initWindowResizeHandlerImpl() /*-{
+    $wnd.__gwt_initWindowResizeHandler(
+      function() {
+        @com.google.gwt.user.client.Window::onResize()();
+      }
+    );
+  }-*/;
+
+  private native void initWindowScrollHandlerImpl() /*-{
+    $wnd.__gwt_initWindowScrollHandler(
+      function() {
+        @com.google.gwt.user.client.Window::onScroll()();
+      }
+    );
+  }-*/;
+
 }