Fixes the firing of focus by FocusImplSafari. Calls to element.focus and
element.blur are unreliable in an event handler, so the impl now makes
the calls from within a setTimeout. This also has the side-effect of
fixing mouse-initiated keyboard navigation in CustomButtons.
Patch by: bobv, scottb
Review by: knorton
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1176 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/client/ui/impl/FocusImplOld.java b/user/src/com/google/gwt/user/client/ui/impl/FocusImplOld.java
index 09c952b..e0d7ab6 100644
--- a/user/src/com/google/gwt/user/client/ui/impl/FocusImplOld.java
+++ b/user/src/com/google/gwt/user/client/ui/impl/FocusImplOld.java
@@ -24,37 +24,13 @@
*/
public class FocusImplOld extends FocusImpl {
- static JavaScriptObject blurHandler = createBlurHandler();
- static JavaScriptObject focusHandler = createFocusHandler();
- static JavaScriptObject mouseHandler = createMouseHandler();
-
- private static native JavaScriptObject createBlurHandler() /*-{
- return function(evt) {
- // This function is called directly as an event handler, so 'this' is
- // set up by the browser to be the input on which the event is fired.
- if (this.parentNode.onblur) {
- this.parentNode.onblur(evt);
- }
- };
- }-*/;
-
- private static native JavaScriptObject createFocusHandler() /*-{
- return function(evt) {
- // This function is called directly as an event handler, so 'this' is
- // set up by the browser to be the input on which the event is fired.
- if (this.parentNode.onfocus) {
- this.parentNode.onfocus(evt);
- }
- };
- }-*/;
-
- private static native JavaScriptObject createMouseHandler() /*-{
- return function() {
- // This function is called directly as an event handler, so 'this' is
- // set up by the browser to be the div on which the event is fired.
- this.firstChild.focus();
- };
- }-*/;
+ /*
+ * Use isolated method calls to create all of the handlers to avoid creating
+ * memory leaks via handler-closures-element.
+ */
+ JavaScriptObject blurHandler = createBlurHandler();
+ JavaScriptObject focusHandler = createFocusHandler();
+ JavaScriptObject mouseHandler = createMouseHandler();
public native void blur(Element elem) /*-{
elem.firstChild.blur();
@@ -77,17 +53,17 @@
input.addEventListener(
'blur',
- @com.google.gwt.user.client.ui.impl.FocusImplOld::blurHandler,
+ this.@com.google.gwt.user.client.ui.impl.FocusImplOld::blurHandler,
false);
input.addEventListener(
'focus',
- @com.google.gwt.user.client.ui.impl.FocusImplOld::focusHandler,
+ this.@com.google.gwt.user.client.ui.impl.FocusImplOld::focusHandler,
false);
div.addEventListener(
'mousedown',
- @com.google.gwt.user.client.ui.impl.FocusImplOld::mouseHandler,
+ this.@com.google.gwt.user.client.ui.impl.FocusImplOld::mouseHandler,
false);
div.appendChild(input);
@@ -110,6 +86,26 @@
elem.firstChild.tabIndex = index;
}-*/;
+ protected native JavaScriptObject createBlurHandler() /*-{
+ return function(evt) {
+ // This function is called directly as an event handler, so 'this' is
+ // set up by the browser to be the input on which the event is fired.
+ if (this.parentNode.onblur) {
+ this.parentNode.onblur(evt);
+ }
+ };
+ }-*/;
+
+ protected native JavaScriptObject createFocusHandler() /*-{
+ return function(evt) {
+ // This function is called directly as an event handler, so 'this' is
+ // set up by the browser to be the input on which the event is fired.
+ if (this.parentNode.onfocus) {
+ this.parentNode.onfocus(evt);
+ }
+ };
+ }-*/;
+
protected native Element createHiddenInput() /*-{
var input = $doc.createElement('input');
input.type = 'text';
@@ -118,4 +114,12 @@
input.style.position = 'absolute';
return input;
}-*/;
+
+ protected native JavaScriptObject createMouseHandler() /*-{
+ return function() {
+ // This function is called directly as an event handler, so 'this' is
+ // set up by the browser to be the div on which the event is fired.
+ this.firstChild.focus();
+ };
+ }-*/;
}
diff --git a/user/src/com/google/gwt/user/client/ui/impl/FocusImplSafari.java b/user/src/com/google/gwt/user/client/ui/impl/FocusImplSafari.java
index 82fa984..7f39aad 100644
--- a/user/src/com/google/gwt/user/client/ui/impl/FocusImplSafari.java
+++ b/user/src/com/google/gwt/user/client/ui/impl/FocusImplSafari.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.user.client.ui.impl;
+import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.user.client.Element;
/**
@@ -23,6 +24,23 @@
* element that has zero width and height.
*/
public class FocusImplSafari extends FocusImplOld {
+
+ public native void blur(Element elem) /*-{
+ // Attempts to blur elements from within an event callback will generally
+ // be unsuccessful, so we invoke blur() from outside of the callback.
+ $wnd.setTimeout(function() {
+ elem.firstChild.blur();
+ }, 0);
+ }-*/;
+
+ public native void focus(Element elem) /*-{
+ // Attempts to focus elements from within an event callback will generally
+ // be unsuccessful, so we invoke focus() from outside of the callback.
+ $wnd.setTimeout(function() {
+ elem.firstChild.focus();
+ }, 0);
+ }-*/;
+
protected native Element createHiddenInput() /*-{
var input = $doc.createElement('input');
input.type = 'text';
@@ -31,4 +49,19 @@
input.style.position = 'absolute';
return input;
}-*/;
+
+ protected native JavaScriptObject createMouseHandler() /*-{
+ return function() {
+ // This function is called directly as an event handler, so 'this' is
+ // set up by the browser to be the div on which the event is fired.
+ var firstChild = this.firstChild;
+
+ // Attempts to focus elements from within an event callback will generally
+ // be unsuccessful, so we invoke focus() from outside of the callback.
+ $wnd.setTimeout(function() {
+ firstChild.focus();
+ }, 0);
+ }
+ }-*/;
+
}