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));
+ }
}