Adds support for Document.create*Event() and Element.dispatchEvent(). Issue: 3166 Review: http://gwt-code-reviews.appspot.com/2013 git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/1.6@4547 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/dom/client/DOMImpl.java b/user/src/com/google/gwt/dom/client/DOMImpl.java index d5d86af..6763044 100644 --- a/user/src/com/google/gwt/dom/client/DOMImpl.java +++ b/user/src/com/google/gwt/dom/client/DOMImpl.java
@@ -50,7 +50,7 @@ public native boolean eventGetAltKey(NativeEvent evt) /*-{ return !!evt.altKey; }-*/; - + public native int eventGetButton(NativeEvent evt) /*-{ return evt.button || 0; }-*/; @@ -275,4 +275,18 @@ public native String toString(Element elem) /*-{ return elem.outerHTML; }-*/; -} \ No newline at end of file + + public abstract NativeEvent createHtmlEvent(Document doc, String type, boolean canBubble, + boolean cancelable); + + public abstract NativeEvent createKeyEvent(Document doc, String type, + boolean canBubble, boolean cancelable, boolean ctrlKey, boolean altKey, + boolean shiftKey, boolean metaKey, int keyCode, int charCode); + + public abstract NativeEvent createMouseEvent(Document doc, String type, + boolean canBubble, boolean cancelable, int detail, int screenX, + int screenY, int clientX, int clientY, boolean ctrlKey, boolean altKey, + boolean shiftKey, boolean metaKey, int button, Element relatedTarget); + + public abstract void dispatchEvent(Element target, NativeEvent evt); +}
diff --git a/user/src/com/google/gwt/dom/client/DOMImplIE6.java b/user/src/com/google/gwt/dom/client/DOMImplIE6.java index 4d3b634..ff7045b 100644 --- a/user/src/com/google/gwt/dom/client/DOMImplIE6.java +++ b/user/src/com/google/gwt/dom/client/DOMImplIE6.java
@@ -22,8 +22,65 @@ class DOMImplIE6 extends DOMImpl { @Override + public native NativeEvent createHtmlEvent(Document doc, String type, boolean canBubble, + boolean cancelable) /*-{ + // NOTE: IE doesn't support changing bubbling and canceling behavior (this + // is documented publicly in Document.createHtmlEvent()). + var evt = doc.createEventObject(); + evt.type = type; + return evt; + }-*/; + + @Override public native InputElement createInputRadioElement(String name) /*-{ return $doc.createElement("<INPUT type='RADIO' name='" + name + "'>"); + }-*/; + + @Override + public native NativeEvent createKeyEvent(Document doc, String type, boolean canBubble, + boolean cancelable, boolean ctrlKey, boolean altKey, boolean shiftKey, + boolean metaKey, int keyCode, int charCode) /*-{ + // NOTE: IE doesn't support changing bubbling and canceling behavior (this + // is documented publicly in Document.createKeyEvent()). + var evt = doc.createEventObject(); + evt.type = type; + evt.ctrlKey = ctrlKey; + evt.altKey = altKey; + evt.shiftKey = shiftKey; + evt.metaKey = metaKey; + evt.keyCode = keyCode; + evt.charCode = charCode; + + return evt; + }-*/; + + @Override + public native NativeEvent createMouseEvent(Document doc, String type, boolean canBubble, + boolean cancelable, int detail, int screenX, int screenY, int clientX, + int clientY, boolean ctrlKey, boolean altKey, boolean shiftKey, + boolean metaKey, int button, Element relatedTarget) /*-{ + // NOTE: IE doesn't support changing bubbling and canceling behavior (this + // is documented publicly in Document.createMouseEvent()). + var evt = doc.createEventObject(); + evt.type = type; + evt.detail = detail; + evt.screenX = screenX; + evt.screenY = screenY; + evt.clientX = clientX; + evt.clientY = clientY; + evt.ctrlKey = ctrlKey; + evt.altKey = altKey; + evt.shiftKey = shiftKey; + evt.metaKey = metaKey; + evt.button = button; + + // It would make sense to set evt.[fromElement | toElement] here, because + // that's what IE uses. However, setting these properties has no effect for + // some reason. So instead we set releatedTarget, and explicitly check for + // its existence in eventGetFromElement() and eventGetToElement(). + evt.relatedTarget = relatedTarget; + + return evt; }-*/; /** @@ -37,7 +94,11 @@ public native SelectElement createSelectElement(boolean multiple) /*-{ var html = multiple ? "<SELECT MULTIPLE>" : "<SELECT>"; return $doc.createElement(html); - }-*/; + }-*/; + + public native void dispatchEvent(Element target, NativeEvent evt) /*-{ + target.fireEvent("on" + evt.type, evt); + }-*/; @Override public native int eventGetMouseWheelVelocityY(NativeEvent evt) /*-{ @@ -46,7 +107,10 @@ @Override public native Element eventGetRelatedTarget(NativeEvent evt) /*-{ - return evt.type == "mouseout"? evt.toElement:evt.fromElement; + // Prefer 'relatedTarget' if it's set (see createMouseEvent(), which + // explicitly sets relatedTarget when synthesizing mouse events). + return evt.relatedTarget || + (evt.type == "mouseout" ? evt.toElement:evt.fromElement); }-*/; @Override @@ -165,5 +229,4 @@ private native double getZoomMultiple() /*-{ return $doc.body.parentElement.offsetWidth / $doc.body.offsetWidth; }-*/; - }
diff --git a/user/src/com/google/gwt/dom/client/DOMImplStandard.java b/user/src/com/google/gwt/dom/client/DOMImplStandard.java index 7f2767f..0fbad02 100644 --- a/user/src/com/google/gwt/dom/client/DOMImplStandard.java +++ b/user/src/com/google/gwt/dom/client/DOMImplStandard.java
@@ -23,6 +23,15 @@ abstract class DOMImplStandard extends DOMImpl { @Override + public native NativeEvent createHtmlEvent(Document doc, String type, boolean canBubble, + boolean cancelable) /*-{ + var evt = doc.createEvent('HTMLEvents'); + evt.initEvent(type, canBubble, cancelable); + + return evt; + }-*/; + + @Override public native InputElement createInputRadioElement(String name) /*-{ var elem = $doc.createElement("INPUT"); elem.type = 'radio'; @@ -31,18 +40,64 @@ }-*/; @Override + public native NativeEvent createKeyEvent(Document doc, String type, boolean canBubble, + boolean cancelable, boolean ctrlKey, boolean altKey, boolean shiftKey, + boolean metaKey, int keyCode, int charCode) /*-{ + // The spec calls for KeyEvents/initKeyEvent(), but that doesn't exist on WebKit. + var evt = doc.createEvent('HTMLEvents'); + evt.initEvent(type, canBubble, cancelable); + evt.ctrlKey = ctrlKey; + evt.altKey = altKey; + evt.shiftKey = shiftKey; + evt.metaKey = metaKey; + evt.keyCode = keyCode; + evt.charCode = charCode; + + return evt; + }-*/; + + @Override + public native NativeEvent createMouseEvent(Document doc, String type, boolean canBubble, + boolean cancelable, int detail, int screenX, int screenY, int clientX, + int clientY, boolean ctrlKey, boolean altKey, boolean shiftKey, + boolean metaKey, int button, Element relatedTarget) /*-{ + // Because Event.getButton() returns bitfield values [1, 4, 2] for [left, + // middle, right], we need to translate them to the standard [0, 1, 2] + // button constants. + if (button == 1) { + button = 0; + } else if (button == 4) { + button = 1; + } else { + button = 2; + } + + var evt = doc.createEvent('MouseEvents'); + evt.initMouseEvent(type, canBubble, cancelable, null, detail, screenX, + screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, + relatedTarget); + + return evt; + }-*/; + + public native void dispatchEvent(Element target, NativeEvent evt) /*-{ + target.dispatchEvent(evt); + }-*/; + + @Override public native int eventGetButton(NativeEvent evt) /*-{ - // Standard browsers and IE disagree on what the button codes for buttons - // should be. Translating to match IE standard. - var button = evt.which; - if(button == 2) { + // All modern browsers return 0, 1, and 2 for left, middle, and right, + // respectively. Because eventGetButton() is expected to return the IE + // bitfield norms of 1, 4, and 2, we translate them here. + var button = evt.button; + if (button == 1) { return 4; - } else if (button == 3) { + } else if (button == 2) { return 2; } - return button || 0; + return 1; }-*/; - + @Override public native Element eventGetRelatedTarget(NativeEvent evt) /*-{ return evt.relatedTarget; @@ -52,7 +107,7 @@ public native Element eventGetTarget(NativeEvent evt) /*-{ return evt.target; }-*/; - + @Override public native void eventPreventDefault(NativeEvent evt) /*-{ evt.preventDefault();
diff --git a/user/src/com/google/gwt/dom/client/Document.java b/user/src/com/google/gwt/dom/client/Document.java index 3d10a25..3526588 100644 --- a/user/src/com/google/gwt/dom/client/Document.java +++ b/user/src/com/google/gwt/dom/client/Document.java
@@ -16,10 +16,9 @@ package com.google.gwt.dom.client; /** - * A Document is the root of the HTML hierarchy and holds the entire - * content. Besides providing access to the hierarchy, it also provides some - * convenience methods for accessing certain sets of information from the - * document. + * A Document is the root of the HTML hierarchy and holds the entire content. + * Besides providing access to the hierarchy, it also provides some convenience + * methods for accessing certain sets of information from the document. */ public class Document extends Node { @@ -628,6 +627,7 @@ * For example, to position an element directly under the mouse cursor * (assuming you are handling a mouse event), do the following: * </p> + * * <pre> * Event event; * Document doc; @@ -743,8 +743,8 @@ * that the two documents may have different DTDs in the XML case. * * @param node the node to import - * @param deep If <code>true</code>, recursively import the subtree under - * the specified node; if <code>false</code>, import only the node + * @param deep If <code>true</code>, recursively import the subtree under the + * specified node; if <code>false</code>, import only the node * itself, as explained above */ public final native void importNode(Node node, boolean deep) /*-{ @@ -760,4 +760,398 @@ public final native void setTitle(String title) /*-{ this.title = title; }-*/; + + /** + * Creates a 'blur' event. + */ + public final NativeEvent createBlurEvent() { + return createHtmlEvent("blur", false, false); + } + + /** + * Creates a 'change' event. + */ + public final NativeEvent createChangeEvent() { + return createHtmlEvent("change", false, true); + } + + /** + * Creates a 'click' event. + * + * <p> + * Note that this method does not allow the event's 'button' field to be + * specified, because not all browsers support it reliably for click events. + * </p> + * + * @param detail the event's detail property + * @param screenX the event's screen-relative x-position + * @param screenY the event's screen-relative y-position + * @param clientX the event's client-relative x-position + * @param clientY the event's client-relative y-position + * @param ctrlKey <code>true</code> if the ctrl key is depressed + * @param altKey <code>true</code> if the alt key is depressed + * @param shiftKey <code>true</code> if the shift key is depressed + * @param metaKey <code>true</code> if the meta key is depressed + * @return the event object + */ + public final NativeEvent createClickEvent(int detail, int screenX, int screenY, + int clientX, int clientY, boolean ctrlKey, boolean altKey, + boolean shiftKey, boolean metaKey) { + // We disallow setting the button here, because IE doesn't provide the + // button property for click events. + return createMouseEvent("click", true, true, detail, screenX, screenY, + clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, + NativeEvent.BUTTON_LEFT, null); + } + + /** + * Creates a 'contextmenu' event. + * + * @return the event object + */ + public final NativeEvent createContextMenuEvent() { + return createHtmlEvent("contextmenu", true, true); + } + + /** + * Creates a 'dblclick' event. + * + * <p> + * Note that this method does not allow the event's 'button' field to be + * specified, because not all browsers support it reliably for click events. + * </p> + * + * <p> + * Note that on some browsers, this may cause 'click' events to be synthesized + * as well. + * </p> + * + * @param detail the event's detail property + * @param screenX the event's screen-relative x-position + * @param screenY the event's screen-relative y-position + * @param clientX the event's client-relative x-position + * @param clientY the event's client-relative y-position + * @param ctrlKey <code>true</code> if the ctrl key is depressed + * @param altKey <code>true</code> if the alt key is depressed + * @param shiftKey <code>true</code> if the shift key is depressed + * @param metaKey <code>true</code> if the meta key is depressed + * @return the event object + */ + public final NativeEvent createDblClickEvent(int detail, int screenX, int screenY, + int clientX, int clientY, boolean ctrlKey, boolean altKey, + boolean shiftKey, boolean metaKey) { + // We disallow setting the button here, because IE doesn't provide the + // button property for click events. + return createMouseEvent("dblclick", true, true, detail, screenX, screenY, + clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, + NativeEvent.BUTTON_LEFT, null); + } + + /** + * Creates an 'error' event. + * + * @return the event object + */ + public final NativeEvent createErrorEvent() { + return createHtmlEvent("error", false, false); + } + + /** + * Creates a 'focus' event. + * + * @return the event object + */ + public final NativeEvent createFocusEvent() { + return createHtmlEvent("focus", false, false); + } + + /** + * Creates an event. + * + * <p> + * While this method may be used to create events directly, it is generally + * preferable to use existing helper methods such as + * {@link #createFocusEvent()}. + * </p> + * + * <p> + * Also, note that on Internet Explorer the 'canBubble' and 'cancelable' + * arguments will be ignored (the event's behavior is inferred by the browser + * based upon its type). + * </p> + * + * @param type the type of event (e.g., "focus", "load", etc) + * @param canBubble <code>true</code> if the event should bubble + * @param cancelable <code>true</code> if the event should be cancelable + * @return the event object + */ + public final NativeEvent createHtmlEvent(String type, boolean canBubble, + boolean cancelable) { + return DOMImpl.impl.createHtmlEvent(this, type, canBubble, cancelable); + } + + /** + * Creates a 'keydown' event. + * + * @param ctrlKey <code>true</code> if the ctrl key is depressed + * @param altKey <code>true</code> if the alt key is depressed + * @param shiftKey <code>true</code> if the shift key is depressed + * @param metaKey <code>true</code> if the meta key is depressed + * @param keyCode the key-code to be set on the event + * @param charCode the char-code to be set on the event + * @return the event object + */ + public final NativeEvent createKeyDownEvent(boolean ctrlKey, boolean altKey, + boolean shiftKey, boolean metaKey, int keyCode, int charCode) { + return createKeyEvent("keydown", true, true, ctrlKey, altKey, shiftKey, + metaKey, keyCode, charCode); + } + + /** + * Creates a key event. + * + * <p> + * While this method may be used to create events directly, it is generally + * preferable to use existing helper methods such as + * {@link #createKeyPressEvent(boolean, boolean, boolean, boolean, int, int)} + * . + * </p> + * + * <p> + * Also, note that on Internet Explorer the 'canBubble' and 'cancelable' + * arguments will be ignored (the event's behavior is inferred by the browser + * based upon its type). + * </p> + * + * @param type the type of event (e.g., "focus", "load", etc) + * @param canBubble <code>true</code> if the event should bubble + * @param cancelable <code>true</code> if the event should be cancelable + * @param ctrlKey <code>true</code> if the ctrl key is depressed + * @param altKey <code>true</code> if the alt key is depressed + * @param shiftKey <code>true</code> if the shift key is depressed + * @param metaKey <code>true</code> if the meta key is depressed + * @param keyCode the key-code to be set on the event + * @param charCode the char-code to be set on the event + * @return the event object + */ + public final NativeEvent createKeyEvent(String type, boolean canBubble, + boolean cancelable, boolean ctrlKey, boolean altKey, boolean shiftKey, + boolean metaKey, int keyCode, int charCode) { + return DOMImpl.impl.createKeyEvent(this, type, canBubble, cancelable, + ctrlKey, altKey, shiftKey, metaKey, keyCode, charCode); + } + + /** + * Creates a 'keypress' event. + * + * @param ctrlKey <code>true</code> if the ctrl key is depressed + * @param altKey <code>true</code> if the alt key is depressed + * @param shiftKey <code>true</code> if the shift key is depressed + * @param metaKey <code>true</code> if the meta key is depressed + * @param keyCode the key-code to be set on the event + * @param charCode the char-code to be set on the event + * @return the event object + */ + public final NativeEvent createKeyPressEvent(boolean ctrlKey, boolean altKey, + boolean shiftKey, boolean metaKey, int keyCode, int charCode) { + return createKeyEvent("keypress", true, true, ctrlKey, altKey, shiftKey, + metaKey, keyCode, charCode); + } + + /** + * Creates a 'keyup' event. + * + * @param ctrlKey <code>true</code> if the ctrl key is depressed + * @param altKey <code>true</code> if the alt key is depressed + * @param shiftKey <code>true</code> if the shift key is depressed + * @param metaKey <code>true</code> if the meta key is depressed + * @param keyCode the key-code to be set on the event + * @param charCode the char-code to be set on the event + * @return the event object + */ + public final NativeEvent createKeyUpEvent(boolean ctrlKey, boolean altKey, + boolean shiftKey, boolean metaKey, int keyCode, int charCode) { + return createKeyEvent("keyup", true, true, ctrlKey, altKey, shiftKey, + metaKey, keyCode, charCode); + } + + /** + * Creates a 'load' event. + * + * @return the event object + */ + public final NativeEvent createLoadEvent() { + return createHtmlEvent("load", false, false); + } + + /** + * Creates a 'mousedown' event. + * + * @param detail the event's detail property + * @param screenX the event's screen-relative x-position + * @param screenY the event's screen-relative y-position + * @param clientX the event's client-relative x-position + * @param clientY the event's client-relative y-position + * @param ctrlKey <code>true</code> if the ctrl key is depressed + * @param altKey <code>true</code> if the alt key is depressed + * @param shiftKey <code>true</code> if the shift key is depressed + * @param metaKey <code>true</code> if the meta key is depressed + * @param button the event's button property (values from + * {@link Event#BUTTON_LEFT} et al) + * @return the event object + */ + public final NativeEvent createMouseDownEvent(int detail, int screenX, int screenY, + int clientX, int clientY, boolean ctrlKey, boolean altKey, + boolean shiftKey, boolean metaKey, int button) { + return createMouseEvent("mousedown", true, true, detail, screenX, screenY, + clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, null); + } + + /** + * Creates an mouse event. + * + * <p> + * While this method may be used to create events directly, it is generally + * preferable to use existing helper methods such as + * {@link #createClickEvent(int, int, int, int, int, boolean, boolean, boolean, boolean)} + * . + * </p> + * + * <p> + * Also, note that on Internet Explorer the 'canBubble' and 'cancelable' + * arguments will be ignored (the event's behavior is inferred by the browser + * based upon its type). + * </p> + * + * @param type the type of event (e.g., "focus", "load", etc) + * @param canBubble <code>true</code> if the event should bubble + * @param cancelable <code>true</code> if the event should be cancelable + * @param detail the event's detail property + * @param screenX the event's screen-relative x-position + * @param screenY the event's screen-relative y-position + * @param clientX the event's client-relative x-position + * @param clientY the event's client-relative y-position + * @param ctrlKey <code>true</code> if the ctrl key is depressed + * @param altKey <code>true</code> if the alt key is depressed + * @param shiftKey <code>true</code> if the shift key is depressed + * @param metaKey <code>true</code> if the meta key is depressed + * @param button the event's button property (values from + * {@link Event#BUTTON_LEFT} et al) + * @param relatedTarget the event's related target (only relevant for + * mouseover and mouseout events) + * @return the event object + */ + public final NativeEvent createMouseEvent(String type, boolean canBubble, + boolean cancelable, int detail, int screenX, int screenY, int clientX, + int clientY, boolean ctrlKey, boolean altKey, boolean shiftKey, + boolean metaKey, int button, Element relatedTarget) { + return DOMImpl.impl.createMouseEvent(this, type, canBubble, cancelable, + detail, screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, + metaKey, button, relatedTarget); + } + + /** + * Creates a 'mousemove' event. + * + * @param detail the event's detail property + * @param screenX the event's screen-relative x-position + * @param screenY the event's screen-relative y-position + * @param clientX the event's client-relative x-position + * @param clientY the event's client-relative y-position + * @param ctrlKey <code>true</code> if the ctrl key is depressed + * @param altKey <code>true</code> if the alt key is depressed + * @param shiftKey <code>true</code> if the shift key is depressed + * @param metaKey <code>true</code> if the meta key is depressed + * @param button the event's button property (values from + * {@link Event#BUTTON_LEFT} et al) + * @return the event object + */ + public final NativeEvent createMouseMoveEvent(int detail, int screenX, int screenY, + int clientX, int clientY, boolean ctrlKey, boolean altKey, + boolean shiftKey, boolean metaKey, int button) { + return createMouseEvent("mousemove", true, true, detail, screenX, screenY, + clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, null); + } + + /** + * Creates a 'mouseout' event. + * + * @param detail the event's detail property + * @param screenX the event's screen-relative x-position + * @param screenY the event's screen-relative y-position + * @param clientX the event's client-relative x-position + * @param clientY the event's client-relative y-position + * @param ctrlKey <code>true</code> if the ctrl key is depressed + * @param altKey <code>true</code> if the alt key is depressed + * @param shiftKey <code>true</code> if the shift key is depressed + * @param metaKey <code>true</code> if the meta key is depressed + * @param button the event's button property (values from + * {@link Event#BUTTON_LEFT} et al) + * @param relatedTarget the event's related target + * @return the event object + */ + public final NativeEvent createMouseOutEvent(int detail, int screenX, int screenY, + int clientX, int clientY, boolean ctrlKey, boolean altKey, + boolean shiftKey, boolean metaKey, int button, Element relatedTarget) { + return createMouseEvent("mouseout", true, true, detail, screenX, screenY, + clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, + relatedTarget); + } + + /** + * Creates a 'mouseover' event. + * + * @param detail the event's detail property + * @param screenX the event's screen-relative x-position + * @param screenY the event's screen-relative y-position + * @param clientX the event's client-relative x-position + * @param clientY the event's client-relative y-position + * @param ctrlKey <code>true</code> if the ctrl key is depressed + * @param altKey <code>true</code> if the alt key is depressed + * @param shiftKey <code>true</code> if the shift key is depressed + * @param metaKey <code>true</code> if the meta key is depressed + * @param button the event's button property (values from + * {@link Event#BUTTON_LEFT} et al) + * @param relatedTarget the event's related target + * @return the event object + */ + public final NativeEvent createMouseOverEvent(int detail, int screenX, int screenY, + int clientX, int clientY, boolean ctrlKey, boolean altKey, + boolean shiftKey, boolean metaKey, int button, Element relatedTarget) { + return createMouseEvent("mouseover", true, true, detail, screenX, screenY, + clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, + relatedTarget); + } + + /** + * Creates a 'mouseup' event. + * + * @param detail the event's detail property + * @param screenX the event's screen-relative x-position + * @param screenY the event's screen-relative y-position + * @param clientX the event's client-relative x-position + * @param clientY the event's client-relative y-position + * @param ctrlKey <code>true</code> if the ctrl key is depressed + * @param altKey <code>true</code> if the alt key is depressed + * @param shiftKey <code>true</code> if the shift key is depressed + * @param metaKey <code>true</code> if the meta key is depressed + * @param button the event's button property (values from + * {@link Event#BUTTON_LEFT} et al) + * @return the event object + */ + public final NativeEvent createMouseUpEvent(int detail, int screenX, int screenY, + int clientX, int clientY, boolean ctrlKey, boolean altKey, + boolean shiftKey, boolean metaKey, int button) { + return createMouseEvent("mouseup", true, true, detail, screenX, screenY, + clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, null); + } + + /** + * Creates a 'scroll' event. + * + * @return the event object + */ + public final NativeEvent createScrollEvent() { + return createHtmlEvent("scroll", false, false); + } }
diff --git a/user/src/com/google/gwt/dom/client/Element.java b/user/src/com/google/gwt/dom/client/Element.java index 54abf0b..9955452 100644 --- a/user/src/com/google/gwt/dom/client/Element.java +++ b/user/src/com/google/gwt/dom/client/Element.java
@@ -15,6 +15,8 @@ */ package com.google.gwt.dom.client; +import com.google.gwt.core.client.GWT; + /** * All HTML element interfaces derive from this class. */ @@ -33,6 +35,22 @@ } /** + * Dispatched the given event with this element as its target. The event will + * go through all phases of the browser's normal event dispatch mechanism. + * + * Note: Because the browser's normal dispatch mechanism is used, exceptions + * thrown from within handlers triggered by this method cannot be caught by + * wrapping this method in a try/catch block. Such exceptions will be caught + * by the {@link GWT#setUncaughtExceptionHandler() uncaught exception handler} + * as usual. + * + * @param evt the event to be dispatched + */ + public final void dispatchEvent(NativeEvent evt) { + DOMImpl.impl.dispatchEvent(this, evt); + } + + /** * Gets an element's absolute left coordinate in the document's coordinate * system. */
diff --git a/user/src/com/google/gwt/dom/client/NativeEvent.java b/user/src/com/google/gwt/dom/client/NativeEvent.java index 217f067..8109652 100644 --- a/user/src/com/google/gwt/dom/client/NativeEvent.java +++ b/user/src/com/google/gwt/dom/client/NativeEvent.java
@@ -23,9 +23,10 @@ public class NativeEvent extends JavaScriptObject { /** - * The left mouse button. + * The left mouse button. */ public static final int BUTTON_LEFT = 1; + /** * The middle mouse button. */ @@ -134,6 +135,7 @@ /** * Gets the related target for this event. + * * @return the related target */ public final Element getRelatedTarget() { @@ -210,5 +212,4 @@ public final void stopPropagation() { DOMImpl.impl.eventStopPropagation(this); } - }
diff --git a/user/src/com/google/gwt/user/client/Event.java b/user/src/com/google/gwt/user/client/Event.java index 2872167..0d633fd 100644 --- a/user/src/com/google/gwt/user/client/Event.java +++ b/user/src/com/google/gwt/user/client/Event.java
@@ -503,6 +503,17 @@ } /** + * Sets the {@link EventListener} to receive events for the given element. + * Only one such listener may exist for a single element. + * + * @param elem the element whose listener is to be set + * @param listener the listener to receive {@link Event events} + */ + public static void setEventListener(Element elem, EventListener listener) { + DOM.setEventListener((com.google.gwt.user.client.Element) elem, listener); + } + + /** * Sets the current set of events sunk by a given element. These events will * be fired to the nearest {@link EventListener} specified on any of the * element's parents.
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java b/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java index 634c74d..2a7dd17 100644 --- a/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java +++ b/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java
@@ -41,15 +41,16 @@ @Override public native Element eventGetFromElement(Event evt) /*-{ - return evt.fromElement; + // Prefer 'relatedTarget' if it's set (see createMouseEvent(), which + // explicitly sets relatedTarget when synthesizing mouse events). + return evt.relatedTarget || evt.fromElement; }-*/; - - - @Override public native Element eventGetToElement(Event evt) /*-{ - return evt.toElement; + // Prefer 'relatedTarget' if it's set (see createMouseEvent(), which + // explicitly sets relatedTarget when synthesizing mouse events). + return evt.relatedTarget || evt.toElement; }-*/; @Override
diff --git a/user/src/com/google/gwt/user/client/ui/CustomButton.java b/user/src/com/google/gwt/user/client/ui/CustomButton.java index 89efb9b..33653cf 100644 --- a/user/src/com/google/gwt/user/client/ui/CustomButton.java +++ b/user/src/com/google/gwt/user/client/ui/CustomButton.java
@@ -16,6 +16,8 @@ package com.google.gwt.user.client.ui; +import com.google.gwt.dom.client.Document; +import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.DOM; @@ -618,9 +620,6 @@ } } break; - case Event.ONCLICK: - // we handle clicks ourselves - return; case Event.ONBLUR: if (isFocusing) { isFocusing = false; @@ -748,7 +747,11 @@ * widget display. */ protected void onClick() { - fireClickListeners(null); + // Mouse coordinates are not always available (e.g., when the click is + // caused by a keyboard event). + NativeEvent evt = Document.get().createClickEvent(1, 0, 0, 0, 0, false, + false, false, false); + getElement().dispatchEvent(evt); } /**
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 ee62223..5fb3006 100644 --- a/user/src/com/google/gwt/user/client/ui/Image.java +++ b/user/src/com/google/gwt/user/client/ui/Image.java
@@ -19,6 +19,7 @@ import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.ImageElement; +import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.ErrorEvent; @@ -113,7 +114,8 @@ image.replaceElement(impl.createStructure(url, left, top, width, height)); // Todo(ecc) This is wrong, we should not be sinking these here on such a // common widget.After the branch is stable, this should be fixed. - image.sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS | Event.ONMOUSEWHEEL); + image.sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS | Event.ONMOUSEWHEEL + | Event.ONLOAD); fireSyntheticLoadEvent(image); } @@ -207,10 +209,8 @@ */ DeferredCommand.addCommand(new Command() { public void execute() { - // TODO(ecc) once event triggering is committed, this call should - // fire a native load event instead. - image.fireEvent(new LoadEvent() { - }); + NativeEvent evt = Document.get().createLoadEvent(); + image.getElement().dispatchEvent(evt); } }); }
diff --git a/user/test/com/google/gwt/user/UISuite.java b/user/test/com/google/gwt/user/UISuite.java index 363fb65..dcedbbc 100644 --- a/user/test/com/google/gwt/user/UISuite.java +++ b/user/test/com/google/gwt/user/UISuite.java
@@ -25,6 +25,7 @@ import com.google.gwt.user.client.ui.CaptionPanelTest; import com.google.gwt.user.client.ui.CheckBoxTest; import com.google.gwt.user.client.ui.CompositeTest; +import com.google.gwt.user.client.ui.CreateEventTest; import com.google.gwt.user.client.ui.CustomButtonTest; import com.google.gwt.user.client.ui.DOMTest; import com.google.gwt.user.client.ui.DateBoxTest; @@ -158,6 +159,7 @@ suite.addTestSuite(XMLTest.class); suite.addTestSuite(ClassInitTest.class); suite.addTestSuite(DateChangeEventTest.class); + suite.addTestSuite(CreateEventTest.class); return suite; } }
diff --git a/user/test/com/google/gwt/user/client/ui/CreateEventTest.java b/user/test/com/google/gwt/user/client/ui/CreateEventTest.java new file mode 100644 index 0000000..7407fd3 --- /dev/null +++ b/user/test/com/google/gwt/user/client/ui/CreateEventTest.java
@@ -0,0 +1,541 @@ +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.user.client.ui; + +import com.google.gwt.dom.client.DivElement; +import com.google.gwt.dom.client.Document; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.ImageElement; +import com.google.gwt.dom.client.InputElement; +import com.google.gwt.junit.client.GWTTestCase; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.EventListener; + +/** + * Tests for the native event triggering methods in {@link Event}. + */ +public class CreateEventTest extends GWTTestCase { + + /** + * Listener for use with key[down up press]. + */ + private class KeyEventListener extends BubbleAssertingEventListener { + public KeyEventListener(String eventType) { + super(eventType); + } + + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + assertAllShiftKeysOn(event); + assertEquals(KEY_CODE, event.getKeyCode()); + } + } + + /** + * Listener for use with mouse[down up move over out]. + */ + private class MouseEventListener extends BubbleAssertingEventListener { + public MouseEventListener(String eventType) { + super(eventType); + } + + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + assertMouseCoordinates(event); + assertAllShiftKeysOn(event); + assertEquals(Event.BUTTON_LEFT, event.getButton()); + } + } + + /** + * An event listener that asserts that the event is passed to child, then + * parent. + */ + private class BubbleAssertingEventListener implements EventListener { + public boolean parentReceived, childReceived; + private final String eventType; + + public BubbleAssertingEventListener(String eventType) { + this.eventType = eventType; + } + + public void onBrowserEvent(Event event) { + assertEquals(eventType, event.getType()); + + Element target = event.getCurrentTarget(); + if (target == child) { + assertFalse("Expecting child to receive the event only once", + childReceived); + assertFalse("Expecting child to receive the event before parent", + parentReceived); + + childReceived = true; + } else if (target == parent) { + assertFalse("Expecting parent to receive the event only once", + parentReceived); + assertTrue("Expecting parent to receive the event after the child", + childReceived); + + parentReceived = true; + } + } + } + + /** + * Used with {@link CreateEventTest#testGetCurrentEvent()}. + */ + private static class CurrentEventListener implements EventListener { + public boolean gotClick, gotKeyPress, gotFocus; + + public void onBrowserEvent(Event event) { + switch (Event.getCurrentEvent().getTypeInt()) { + case Event.ONCLICK: + gotClick = true; + break; + case Event.ONKEYPRESS: + gotKeyPress = true; + break; + case Event.ONFOCUS: + gotFocus = true; + break; + } + } + } + + /** + * An event listener that asserts that the event is passed only to child. + */ + private class NonBubbleAssertingEventListener implements EventListener { + private boolean childReceived; + private String eventType; + + public NonBubbleAssertingEventListener(String eventType) { + this.eventType = eventType; + } + + public void onBrowserEvent(Event event) { + assertEquals(eventType, event.getType()); + + if (event.getTarget() == child) { + assertFalse("Expecting child to receive the event only once", + childReceived); + childReceived = true; + } else if (event.getTarget() == parent) { + fail("Not expecting parent to receive the event"); + } + } + + protected String getEventType() { + return eventType; + } + } + + /** + * An event listener that asserts that events are received properly for the + * img element. + */ + private class ImgEventListener implements EventListener { + private boolean imgReceived; + private final String eventType; + + public ImgEventListener(String eventType) { + this.eventType = eventType; + } + + public void onBrowserEvent(Event event) { + if (event.getType().equals(eventType)) { + if (event.getTarget() == img) { + assertFalse("Expecting img to receive the event only once", + imgReceived); + + imgReceived = true; + } else if (event.getTarget() == parent) { + fail("Not expecting parent to receive the event"); + } + } + } + } + + private static final int MOUSE_DETAIL = 1; + private static final int CLIENT_X = 2; + private static final int CLIENT_Y = 3; + private static final int SCREEN_X = 4; + private static final int SCREEN_Y = 5; + private static final int KEY_CODE = 'A'; + + private static final int ALL_EVENTS = Event.MOUSEEVENTS | Event.KEYEVENTS + | Event.FOCUSEVENTS | Event.ONCHANGE | Event.ONCLICK | Event.ONDBLCLICK + | Event.ONCONTEXTMENU | Event.ONLOAD | Event.ONERROR | Event.ONSCROLL; + private static DivElement parent; + private static InputElement child; + + private static ImageElement img; + + @Override + public String getModuleName() { + return "com.google.gwt.user.UserTest"; + } + + /** + * Tests that {@link Event#getCurrentEvent()} returns the right value for + * synthesized events. + */ + public void testGetCurrentEvent() { + CurrentEventListener listener = new CurrentEventListener(); + Event.setEventListener(child, listener); + + // Test all three major event types. + child.dispatchEvent(Document.get().createClickEvent(0, 0, 0, 0, 0, false, + false, false, false)); + child.dispatchEvent(Document.get().createKeyPressEvent(false, false, false, + false, 65, 65)); + child.dispatchEvent(Document.get().createFocusEvent()); + + assertTrue("Expecting click as current event", listener.gotClick); + assertTrue("Expecting keypress as current event", listener.gotKeyPress); + assertTrue("Expecting focus as current event", listener.gotFocus); + } + + /** + * Tests createBlurEvent(). + */ + public void testTriggerBlurEvent() { + NonBubbleAssertingEventListener listener = new NonBubbleAssertingEventListener( + "blur") { + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + assertEquals("blur", event.getType()); + } + }; + Event.setEventListener(parent, listener); + Event.setEventListener(child, listener); + + child.dispatchEvent(Document.get().createBlurEvent()); + + assertTrue("Expected child to receive event", listener.childReceived); + } + + /** + * Tests createChangeEvent(). + */ + public void testTriggerChangeEvent() { + BubbleAssertingEventListener listener = new BubbleAssertingEventListener( + "change"); + Event.setEventListener(parent, listener); + Event.setEventListener(child, listener); + + child.dispatchEvent(Document.get().createChangeEvent()); + + assertTrue("Expected child to receive event", listener.childReceived); + } + + /** + * Tests createClickEvent(). + */ + public void testTriggerClickEvent() { + BubbleAssertingEventListener listener = new BubbleAssertingEventListener( + "click") { + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + assertMouseCoordinates(event); + assertAllShiftKeysOn(event); + } + }; + Event.setEventListener(parent, listener); + Event.setEventListener(child, listener); + + child.dispatchEvent(Document.get().createClickEvent(MOUSE_DETAIL, SCREEN_X, + SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true)); + + assertTrue("Expected child to receive event", listener.childReceived); + assertTrue("Expected parent to receive event", listener.parentReceived); + } + + /** + * Tests createContextMenuEvent(). + */ + public void testTriggerContextMenuEvent() { + BubbleAssertingEventListener listener = new BubbleAssertingEventListener( + "contextmenu"); + Event.setEventListener(parent, listener); + Event.setEventListener(child, listener); + + child.dispatchEvent(Document.get().createContextMenuEvent()); + + assertTrue("Expected child to receive event", listener.childReceived); + assertTrue("Expected parent to receive event", listener.parentReceived); + } + + /** + * Tests createDblClickEvent(). + */ + public void testTriggerDblClickEvent() { + BubbleAssertingEventListener listener = new BubbleAssertingEventListener( + "dblclick") { + public void onBrowserEvent(Event event) { + if (event.getTypeInt() == Event.ONCLICK) { + // Some browsers (IE, I'm looking at you) synthesize an extra click + // event when a double-click is triggered. This synthesized click + // will *not* have the same properties as the dblclick, so we will + // not try to assert them here. + return; + } + + super.onBrowserEvent(event); + assertMouseCoordinates(event); + assertAllShiftKeysOn(event); + } + }; + Event.setEventListener(parent, listener); + Event.setEventListener(child, listener); + + child.dispatchEvent(Document.get().createDblClickEvent(MOUSE_DETAIL, + SCREEN_X, SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true)); + + assertTrue("Expected child to receive event", listener.childReceived); + assertTrue("Expected parent to receive event", listener.parentReceived); + } + + /** + * Tests createErrorEvent(). + */ + public void testTriggerErrorEvent() { + ImgEventListener listener = new ImgEventListener("error"); + Event.setEventListener(parent, listener); + Event.setEventListener(img, listener); + + img.dispatchEvent(Document.get().createErrorEvent()); + + assertTrue("Expected child to receive event", listener.imgReceived); + } + + /** + * Tests createFocusEvent(). + */ + public void testTriggerFocusEvent() { + NonBubbleAssertingEventListener listener = new NonBubbleAssertingEventListener( + "focus") { + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + assertEquals("focus", event.getType()); + } + }; + Event.setEventListener(parent, listener); + Event.setEventListener(child, listener); + + child.dispatchEvent(Document.get().createFocusEvent()); + + assertTrue("Expected child to receive event", listener.childReceived); + } + + /** + * Tests createKeyDownEvent(). + */ + public void testTriggerKeyDownEvent() { + KeyEventListener listener = new KeyEventListener("keydown"); + Event.setEventListener(parent, listener); + Event.setEventListener(child, listener); + + child.dispatchEvent(Document.get().createKeyDownEvent(true, true, true, + true, KEY_CODE, KEY_CODE)); + + assertTrue("Expected child to receive event", listener.childReceived); + assertTrue("Expected parent to receive event", listener.parentReceived); + } + + /** + * Tests createKeyPressEvent(). + */ + public void testTriggerKeyPressEvent() { + KeyEventListener listener = new KeyEventListener("keypress"); + Event.setEventListener(parent, listener); + Event.setEventListener(child, listener); + + child.dispatchEvent(Document.get().createKeyPressEvent(true, true, true, + true, KEY_CODE, KEY_CODE)); + + assertTrue("Expected child to receive event", listener.childReceived); + assertTrue("Expected parent to receive event", listener.parentReceived); + } + + /** + * Tests createKeyUpEvent(). + */ + public void testTriggerKeyUpEvent() { + KeyEventListener listener = new KeyEventListener("keyup"); + Event.setEventListener(parent, listener); + Event.setEventListener(child, listener); + + child.dispatchEvent(Document.get().createKeyUpEvent(true, true, true, true, + KEY_CODE, KEY_CODE)); + + assertTrue("Expected child to receive event", listener.childReceived); + assertTrue("Expected parent to receive event", listener.parentReceived); + } + + /** + * Tests createLoadEvent(). + */ + public void testTriggerLoadEvent() { + ImgEventListener listener = new ImgEventListener("load"); + Event.setEventListener(parent, listener); + Event.setEventListener(img, listener); + + img.dispatchEvent(Document.get().createLoadEvent()); + + assertTrue("Expected img to receive event", listener.imgReceived); + } + + /** + * Tests createMouseDownEvent(). + */ + public void testTriggerMouseDownEvent() { + MouseEventListener listener = new MouseEventListener("mousedown"); + Event.setEventListener(parent, listener); + Event.setEventListener(child, listener); + + child.dispatchEvent(Document.get().createMouseDownEvent(MOUSE_DETAIL, + SCREEN_X, SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true, + Event.BUTTON_LEFT)); + + assertTrue("Expected child to receive event", listener.childReceived); + assertTrue("Expected parent to receive event", listener.parentReceived); + } + + /** + * Tests createMouseMoveEvent(). + */ + public void testTriggerMouseMoveEvent() { + MouseEventListener listener = new MouseEventListener("mousemove"); + Event.setEventListener(parent, listener); + Event.setEventListener(child, listener); + + child.dispatchEvent(Document.get().createMouseMoveEvent(MOUSE_DETAIL, + SCREEN_X, SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true, + Event.BUTTON_LEFT)); + + assertTrue("Expected child to receive event", listener.childReceived); + assertTrue("Expected parent to receive event", listener.parentReceived); + } + + /** + * Tests createMouseOutEvent(). + */ + public void testTriggerMouseOutEvent() { + MouseEventListener listener = new MouseEventListener("mouseout") { + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + assertEquals("Expected related document.body", + Document.get().getBody(), event.getToElement()); + } + }; + Event.setEventListener(parent, listener); + Event.setEventListener(child, listener); + + child.dispatchEvent(Document.get().createMouseOutEvent(MOUSE_DETAIL, + SCREEN_X, SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true, + Event.BUTTON_LEFT, Document.get().getBody())); + + assertTrue("Expected child to receive event", listener.childReceived); + assertTrue("Expected parent to receive event", listener.parentReceived); + } + + /** + * Tests createMouseOverEvent(). + */ + public void testTriggerMouseOverEvent() { + MouseEventListener listener = new MouseEventListener("mouseover") { + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + assertEquals("Expected related document.body", + Document.get().getBody(), event.getFromElement()); + } + }; + Event.setEventListener(parent, listener); + Event.setEventListener(child, listener); + + child.dispatchEvent(Document.get().createMouseOverEvent(MOUSE_DETAIL, + SCREEN_X, SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true, + Event.BUTTON_LEFT, Document.get().getBody())); + + assertTrue("Expected child to receive event", listener.childReceived); + assertTrue("Expected parent to receive event", listener.parentReceived); + } + + /** + * Tests createMouseUpEvent(). + */ + public void testTriggerMouseUpEvent() { + MouseEventListener listener = new MouseEventListener("mouseup"); + Event.setEventListener(parent, listener); + Event.setEventListener(child, listener); + + child.dispatchEvent(Document.get().createMouseUpEvent(MOUSE_DETAIL, + SCREEN_X, SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true, + Event.BUTTON_LEFT)); + + assertTrue("Expected child to receive event", listener.childReceived); + assertTrue("Expected parent to receive event", listener.parentReceived); + } + + /** + * Tests createScrollEvent(). + */ + public void testTriggerScrollEvent() { + NonBubbleAssertingEventListener listener = new NonBubbleAssertingEventListener( + "scroll") { + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + assertEquals("scroll", event.getType()); + } + }; + Event.setEventListener(parent, listener); + Event.setEventListener(child, listener); + + child.dispatchEvent(Document.get().createScrollEvent()); + + assertTrue("Expected child to receive event", listener.childReceived); + } + + @Override + protected void gwtSetUp() throws Exception { + parent = Document.get().createDivElement(); + child = Document.get().createTextInputElement(); + img = Document.get().createImageElement(); + + Document.get().getBody().appendChild(parent); + parent.appendChild(child); + parent.appendChild(img); + + Event.sinkEvents(parent, ALL_EVENTS); + Event.sinkEvents(child, ALL_EVENTS); + Event.sinkEvents(img, ALL_EVENTS); + } + + private void assertAllShiftKeysOn(Event event) { + assertEquals("Expecting ctrl on", true, event.getCtrlKey()); + assertEquals("Expecting alt on", true, event.getAltKey()); + assertEquals("Expecting shift on", true, event.getShiftKey()); + assertEquals("Expecting meta on", true, event.getMetaKey()); + } + + private void assertMouseCoordinates(Event event) { + assertEquals("clientX", CLIENT_X, event.getClientX()); + assertEquals("clientY", CLIENT_Y, event.getClientY()); + assertEquals("screenX", SCREEN_X, event.getScreenX()); + assertEquals("screenY", SCREEN_Y, event.getScreenY()); + } +}
diff --git a/user/test/com/google/gwt/user/client/ui/CustomButtonTest.java b/user/test/com/google/gwt/user/client/ui/CustomButtonTest.java index 5593cfa..f354e19 100644 --- a/user/test/com/google/gwt/user/client/ui/CustomButtonTest.java +++ b/user/test/com/google/gwt/user/client/ui/CustomButtonTest.java
@@ -16,18 +16,23 @@ package com.google.gwt.user.client.ui; -import com.google.gwt.junit.client.GWTTestCase; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.ui.CustomButton.Face; - +import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; +import com.google.gwt.dom.client.Document; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.junit.client.GWTTestCase; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.ui.CustomButton.Face; + /** - * Test for <code>PushButton</code> as most of this widget's functionality is - * UI based, the primary test will be in the new UI testing framework once it is + * Test for <code>PushButton</code> as most of this widget's functionality is UI + * based, the primary test will be in the new UI testing framework once it is * released. * */ @@ -154,4 +159,31 @@ assertFalse(b.isDown()); assertFalse(b.isEnabled()); } + + public void testSyntheticClick() { + PushButton b = new PushButton(); + final ArrayList<String> events = new ArrayList<String>(); + + b.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + events.add(event.getNativeEvent().getType()); + } + }); + + RootPanel.get().add(b); + + // Synthesize over/down/up events, which should kick off CustomButton's + // internal machinery to synthesize a click. + b.getElement().dispatchEvent( + Document.get().createMouseOverEvent(1, 0, 0, 0, 0, false, false, false, + false, Event.BUTTON_LEFT, null)); + b.getElement().dispatchEvent( + Document.get().createMouseDownEvent(1, 0, 0, 0, 0, false, false, false, + false, Event.BUTTON_LEFT)); + b.getElement().dispatchEvent( + Document.get().createMouseUpEvent(1, 0, 0, 0, 0, false, false, false, + false, Event.BUTTON_LEFT)); + assertEquals("Expecting one click event", 1, events.size()); + assertEquals("Expecting one click event", "click", events.get(0)); + } }