Fixes a bug where all Buttons default to submit in safari, causing forms to automatically submit when the button is pressed. This patch introduces a button class for each button type.
Patch by: t.broyer
Review by: jlabanca
Issue: 1585, 3962
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6022 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/DefaultMuseum.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/DefaultMuseum.java
index 743694e..7527e09 100644
--- a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/DefaultMuseum.java
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/DefaultMuseum.java
@@ -49,6 +49,7 @@
addIssue(new Issue2553());
addIssue(new Issue2855());
addIssue(new Issue3172());
+ addIssue(new Issue3962());
addIssue(new Issue3973());
}
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue3962.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue3962.java
new file mode 100644
index 0000000..b0e6587
--- /dev/null
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue3962.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2009 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.museum.client.defaultmuseum;
+
+import com.google.gwt.museum.client.common.AbstractIssue;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.FormPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.gwt.user.client.ui.FormPanel.SubmitEvent;
+import com.google.gwt.user.client.ui.FormPanel.SubmitHandler;
+
+/**
+ * Buttons default to type=submit in WebKit (Safari and Chrome) and IE8 (in IE8
+ * mode).
+ */
+public class Issue3962 extends AbstractIssue {
+ private FormPanel form;
+
+ @Override
+ public Widget createIssue() {
+ form = new FormPanel();
+ form.addSubmitHandler(new SubmitHandler() {
+ public void onSubmit(SubmitEvent event) {
+ Window.alert("Form is being submitted.");
+ event.cancel();
+ }
+ });
+ form.setWidget(new Button("Submit"));
+ return form;
+ }
+
+ @Override
+ public String getInstructions() {
+ return "Click the button, it should have no effect.";
+ }
+
+ @Override
+ public String getSummary() {
+ return "In IE8 (in IE8 mode) and WebKit (Safari and Chrome), buttons default"
+ + " to type submit.";
+ }
+
+ @Override
+ public boolean hasCSS() {
+ return false;
+ }
+}
diff --git a/user/src/com/google/gwt/dom/client/DOMImpl.java b/user/src/com/google/gwt/dom/client/DOMImpl.java
index e5ae74b..b9ba351 100644
--- a/user/src/com/google/gwt/dom/client/DOMImpl.java
+++ b/user/src/com/google/gwt/dom/client/DOMImpl.java
@@ -25,6 +25,12 @@
button.click();
}-*/;
+ public native ButtonElement createButtonElement(Document doc, String type) /*-{
+ var e = doc.createElement("BUTTON");
+ e.type = type;
+ return e;
+ }-*/;
+
public native Element createElement(Document doc, String tag) /*-{
return doc.createElement(tag);
}-*/;
diff --git a/user/src/com/google/gwt/dom/client/DOMImplTrident.java b/user/src/com/google/gwt/dom/client/DOMImplTrident.java
index 74b4e19..4bc7ae9 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplTrident.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplTrident.java
@@ -21,12 +21,18 @@
* This field *must* be filled in from JSNI code before dispatching an event
* on IE. It should be set to the 'this' context of the handler that receives
* the event, then restored to its initial value when the dispatcher is done.
- * See {@link com.google.gwt.user.client.impl.DOMImplTrident#initEventSystem()}
+ * See
+ * {@link com.google.gwt.user.client.impl.DOMImplTrident#initEventSystem()}
* for an example of how this should be done.
*/
private static EventTarget currentEventTarget;
@Override
+ public native ButtonElement createButtonElement(Document doc, String type) /*-{
+ return doc.createElement("<BUTTON type='" + type + "'></BUTTON>");
+ }-*/;
+
+ @Override
public Element createElement(Document doc, String tagName) {
if (tagName.contains(":")) {
// Special implementation for tag names with namespace-prefixes. The only
@@ -48,8 +54,8 @@
}
@Override
- public native NativeEvent createHtmlEvent(Document doc, String type, boolean canBubble,
- boolean cancelable) /*-{
+ 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();
@@ -63,9 +69,9 @@
}-*/;
@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) /*-{
+ 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();
@@ -81,10 +87,10 @@
}-*/;
@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) /*-{
+ 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();
@@ -168,7 +174,7 @@
/**
* IE returns a numeric type for some attributes that are really properties,
- * such as offsetWidth. We need to coerce these to strings to prevent a
+ * such as offsetWidth. We need to coerce these to strings to prevent a
* runtime JS exception.
*/
@Override
@@ -192,6 +198,7 @@
return elem.innerText;
}-*/;
+ @Override
public String getTagName(Element elem) {
String tagName = getTagNameInternal(elem);
String scopeName = getScopeNameInternal(elem);
diff --git a/user/src/com/google/gwt/dom/client/Document.java b/user/src/com/google/gwt/dom/client/Document.java
index b962621..d9ce69d 100644
--- a/user/src/com/google/gwt/dom/client/Document.java
+++ b/user/src/com/google/gwt/dom/client/Document.java
@@ -68,7 +68,8 @@
* @return the newly created element
*/
public final QuoteElement createBlockQuoteElement() {
- return (QuoteElement) DOMImpl.impl.createElement(this, QuoteElement.TAG_BLOCKQUOTE);
+ return (QuoteElement) DOMImpl.impl.createElement(this,
+ QuoteElement.TAG_BLOCKQUOTE);
}
/**
@@ -89,11 +90,27 @@
/**
* Creates a <button> element.
+ * <p>
+ * <b>Warning!</b> The button type is actually implementation-dependent and is
+ * read-only.
+ *
+ * @return the newly created element
+ * @deprecated use {@link #createPushButtonElement()},
+ * {@link #createResetButtonElement()} or
+ * {@link #createSubmitButtonElement()} instead.
+ */
+ @Deprecated
+ public final ButtonElement createButtonElement() {
+ return (ButtonElement) DOMImpl.impl.createElement(this, ButtonElement.TAG);
+ }
+
+ /**
+ * Creates an <input type='button'> element.
*
* @return the newly created element
*/
- public final ButtonElement createButtonElement() {
- return (ButtonElement) DOMImpl.impl.createElement(this, ButtonElement.TAG);
+ public final InputElement createButtonInputElement() {
+ return DOMImpl.impl.createInputElement(this, "button");
}
/**
@@ -102,7 +119,8 @@
* @return the newly created element
*/
public final TableCaptionElement createCaptionElement() {
- return (TableCaptionElement) DOMImpl.impl.createElement(this, TableCaptionElement.TAG);
+ return (TableCaptionElement) DOMImpl.impl.createElement(this,
+ TableCaptionElement.TAG);
}
/**
@@ -140,8 +158,8 @@
* @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,
+ 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.
@@ -156,7 +174,8 @@
* @return the newly created element
*/
public final TableColElement createColElement() {
- return (TableColElement) DOMImpl.impl.createElement(this, TableColElement.TAG_COL);
+ return (TableColElement) DOMImpl.impl.createElement(this,
+ TableColElement.TAG_COL);
}
/**
@@ -165,7 +184,8 @@
* @return the newly created element
*/
public final TableColElement createColGroupElement() {
- return (TableColElement) DOMImpl.impl.createElement(this, TableColElement.TAG_COLGROUP);
+ return (TableColElement) DOMImpl.impl.createElement(this,
+ TableColElement.TAG_COLGROUP);
}
/**
@@ -204,8 +224,8 @@
* @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,
+ 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.
@@ -266,7 +286,8 @@
* @return the newly created element
*/
public final FieldSetElement createFieldSetElement() {
- return (FieldSetElement) DOMImpl.impl.createElement(this, FieldSetElement.TAG);
+ return (FieldSetElement) DOMImpl.impl.createElement(this,
+ FieldSetElement.TAG);
}
/**
@@ -311,7 +332,8 @@
* @return the newly created element
*/
public final FrameSetElement createFrameSetElement() {
- return (FrameSetElement) DOMImpl.impl.createElement(this, FrameSetElement.TAG);
+ return (FrameSetElement) DOMImpl.impl.createElement(this,
+ FrameSetElement.TAG);
}
/**
@@ -577,8 +599,8 @@
* {@link NativeEvent#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,
+ 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);
@@ -643,8 +665,8 @@
* {@link NativeEvent#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,
+ 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);
@@ -670,8 +692,8 @@
* @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,
+ 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,
@@ -698,8 +720,8 @@
* @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,
+ 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,
@@ -722,8 +744,8 @@
* {@link NativeEvent#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,
+ 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);
@@ -753,7 +775,8 @@
* @return the newly created element
*/
public final OptGroupElement createOptGroupElement() {
- return (OptGroupElement) DOMImpl.impl.createElement(this, OptGroupElement.TAG);
+ return (OptGroupElement) DOMImpl.impl.createElement(this,
+ OptGroupElement.TAG);
}
/**
@@ -789,7 +812,8 @@
* @return the newly created element
*/
public final ParagraphElement createPElement() {
- return (ParagraphElement) DOMImpl.impl.createElement(this, ParagraphElement.TAG);
+ return (ParagraphElement) DOMImpl.impl.createElement(this,
+ ParagraphElement.TAG);
}
/**
@@ -802,6 +826,15 @@
}
/**
+ * Creates a <button type='button'> element.
+ *
+ * @return the newly created element
+ */
+ public final ButtonElement createPushButtonElement() {
+ return DOMImpl.impl.createButtonElement(this, "button");
+ }
+
+ /**
* Creates a <q> element.
*
* @return the newly created element
@@ -821,6 +854,24 @@
}
/**
+ * Creates a <button type='reset'> element.
+ *
+ * @return the newly created element
+ */
+ public final ButtonElement createResetButtonElement() {
+ return DOMImpl.impl.createButtonElement(this, "reset");
+ }
+
+ /**
+ * Creates an <input type='reset'> element.
+ *
+ * @return the newly created element
+ */
+ public final InputElement createResetInputElement() {
+ return DOMImpl.impl.createInputElement(this, "reset");
+ }
+
+ /**
* Creates a <script> element.
*
* @return the newly created element
@@ -889,6 +940,15 @@
}
/**
+ * Creates a <button type='submit'> element.
+ *
+ * @return the newly created element
+ */
+ public final ButtonElement createSubmitButtonElement() {
+ return DOMImpl.impl.createButtonElement(this, "submit");
+ }
+
+ /**
* Creates an <input type='submit'> element.
*
* @return the newly created element
@@ -912,7 +972,8 @@
* @return the newly created element
*/
public final TableSectionElement createTBodyElement() {
- return (TableSectionElement) DOMImpl.impl.createElement(this, TableSectionElement.TAG_TBODY);
+ return (TableSectionElement) DOMImpl.impl.createElement(this,
+ TableSectionElement.TAG_TBODY);
}
/**
@@ -921,7 +982,8 @@
* @return the newly created element
*/
public final TableCellElement createTDElement() {
- return (TableCellElement) DOMImpl.impl.createElement(this, TableCellElement.TAG_TD);
+ return (TableCellElement) DOMImpl.impl.createElement(this,
+ TableCellElement.TAG_TD);
}
/**
@@ -930,7 +992,8 @@
* @return the newly created element
*/
public final TextAreaElement createTextAreaElement() {
- return (TextAreaElement) DOMImpl.impl.createElement(this, TextAreaElement.TAG);
+ return (TextAreaElement) DOMImpl.impl.createElement(this,
+ TextAreaElement.TAG);
}
/**
@@ -958,7 +1021,8 @@
* @return the newly created element
*/
public final TableSectionElement createTFootElement() {
- return (TableSectionElement) DOMImpl.impl.createElement(this, TableSectionElement.TAG_TFOOT);
+ return (TableSectionElement) DOMImpl.impl.createElement(this,
+ TableSectionElement.TAG_TFOOT);
}
/**
@@ -967,7 +1031,8 @@
* @return the newly created element
*/
public final TableSectionElement createTHeadElement() {
- return (TableSectionElement) DOMImpl.impl.createElement(this, TableSectionElement.TAG_THEAD);
+ return (TableSectionElement) DOMImpl.impl.createElement(this,
+ TableSectionElement.TAG_THEAD);
}
/**
@@ -976,7 +1041,8 @@
* @return the newly created element
*/
public final TableCellElement createTHElement() {
- return (TableCellElement) DOMImpl.impl.createElement(this, TableCellElement.TAG_TH);
+ return (TableCellElement) DOMImpl.impl.createElement(this,
+ TableCellElement.TAG_TH);
}
/**
@@ -994,7 +1060,8 @@
* @return the newly created element
*/
public final TableRowElement createTRElement() {
- return (TableRowElement) DOMImpl.impl.createElement(this, TableRowElement.TAG);
+ return (TableRowElement) DOMImpl.impl.createElement(this,
+ TableRowElement.TAG);
}
/**
diff --git a/user/src/com/google/gwt/user/client/ui/Button.java b/user/src/com/google/gwt/user/client/ui/Button.java
index 0f7863c..895483b 100644
--- a/user/src/com/google/gwt/user/client/ui/Button.java
+++ b/user/src/com/google/gwt/user/client/ui/Button.java
@@ -28,9 +28,10 @@
* </p>
*
* <h3>CSS Style Rules</h3>
- * <ul class="css">
- * <li>.gwt-Button { }</li>
- * </ul>
+ * <dl>
+ * <dt>.gwt-Button</dt>
+ * <dd>the outer element</dd>
+ * </dl>
*
* <p>
* <h3>Example</h3>
@@ -53,6 +54,7 @@
assert Document.get().getBody().isOrHasChild(element);
Button button = new Button(element);
+ assert "button".equalsIgnoreCase(button.getButtonElement().getType());
// Mark it attached and remember it for cleanup.
button.onAttach();
@@ -61,22 +63,11 @@
return button;
}
- static native void adjustType(Element button) /*-{
- // Check before setting this attribute, as not all browsers define it.
- if (button.type == 'submit') {
- try {
- button.setAttribute("type", "button");
- } catch (e) {
- }
- }
- }-*/;
-
/**
* Creates a button with no caption.
*/
public Button() {
- super(Document.get().createButtonElement());
- adjustType(getElement());
+ super(Document.get().createPushButtonElement());
setStyleName("gwt-Button");
}
@@ -132,8 +123,12 @@
getButtonElement().click();
}
- private ButtonElement getButtonElement() {
+ /**
+ * Get the underlying button element.
+ *
+ * @return the {@link ButtonElement}
+ */
+ protected ButtonElement getButtonElement() {
return getElement().cast();
}
}
-
diff --git a/user/src/com/google/gwt/user/client/ui/ResetButton.java b/user/src/com/google/gwt/user/client/ui/ResetButton.java
new file mode 100644
index 0000000..83bc66c
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/ResetButton.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2009 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.ButtonElement;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.event.dom.client.ClickHandler;
+
+/**
+ * A standard push-button widget which will automatically reset its enclosing
+ * {@link FormPanel} if any.
+ *
+ * <h3>CSS Style Rules</h3>
+ * <dl>
+ * <dt>.gwt-ResetButton</dt>
+ * <dd>the outer element</dd>
+ * </dl>
+ */
+public class ResetButton extends Button {
+
+ /**
+ * Creates a ResetButton widget that wraps an existing <button> element.
+ *
+ * This element must already be attached to the document. If the element is
+ * removed from the document, you must call
+ * {@link RootPanel#detachNow(Widget)}.
+ *
+ * @param element the element to be wrapped
+ */
+ public static Button wrap(com.google.gwt.dom.client.Element element) {
+ // Assert that the element is attached.
+ assert Document.get().getBody().isOrHasChild(element);
+
+ ResetButton button = new ResetButton(element);
+
+ // Mark it attached and remember it for cleanup.
+ button.onAttach();
+ RootPanel.detachOnWindowClose(button);
+
+ return button;
+ }
+
+ /**
+ * Creates a button with no caption.
+ */
+ public ResetButton() {
+ super(Document.get().createResetButtonElement());
+ setStyleName("gwt-ResetButton");
+ }
+
+ /**
+ * Creates a button with the given HTML caption.
+ *
+ * @param html the HTML caption
+ */
+ public ResetButton(String html) {
+ this();
+ setHTML(html);
+ }
+
+ /**
+ * Creates a button with the given HTML caption and click listener.
+ *
+ * @param html the HTML caption
+ * @param handler the click handler
+ */
+ public ResetButton(String html, ClickHandler handler) {
+ this(html);
+ addClickHandler(handler);
+ }
+
+ /**
+ * This constructor may be used by subclasses to explicitly use an existing
+ * element. This element must be a <button> element with type reset.
+ *
+ * @param element the element to be used
+ */
+ protected ResetButton(com.google.gwt.dom.client.Element element) {
+ super(element);
+ assert "reset".equalsIgnoreCase(element.<ButtonElement> cast().getType());
+ }
+}
diff --git a/user/src/com/google/gwt/user/client/ui/SubmitButton.java b/user/src/com/google/gwt/user/client/ui/SubmitButton.java
new file mode 100644
index 0000000..c86f466
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/SubmitButton.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2009 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.ButtonElement;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.event.dom.client.ClickHandler;
+
+/**
+ * A standard push-button widget which will automatically submit its enclosing
+ * {@link FormPanel} if any.
+ *
+ * <h3>CSS Style Rules</h3>
+ * <dl>
+ * <dt>.gwt-SubmitButton</dt>
+ * <dd>the outer element</dd>
+ * </dl>
+ */
+public class SubmitButton extends Button {
+
+ /**
+ * Creates a SubmitButton widget that wraps an existing <button>
+ * element.
+ *
+ * This element must already be attached to the document. If the element is
+ * removed from the document, you must call
+ * {@link RootPanel#detachNow(Widget)}.
+ *
+ * @param element the element to be wrapped
+ */
+ public static Button wrap(com.google.gwt.dom.client.Element element) {
+ // Assert that the element is attached.
+ assert Document.get().getBody().isOrHasChild(element);
+
+ SubmitButton button = new SubmitButton(element);
+ assert "submit".equalsIgnoreCase(button.getButtonElement().getType());
+
+ // Mark it attached and remember it for cleanup.
+ button.onAttach();
+ RootPanel.detachOnWindowClose(button);
+
+ return button;
+ }
+
+ /**
+ * Creates a button with no caption.
+ */
+ public SubmitButton() {
+ super(Document.get().createSubmitButtonElement());
+ setStyleName("gwt-SubmitButton");
+ }
+
+ /**
+ * Creates a button with the given HTML caption.
+ *
+ * @param html the HTML caption
+ */
+ public SubmitButton(String html) {
+ this();
+ setHTML(html);
+ }
+
+ /**
+ * Creates a button with the given HTML caption and click listener.
+ *
+ * @param html the HTML caption
+ * @param handler the click handler
+ */
+ public SubmitButton(String html, ClickHandler handler) {
+ this(html);
+ addClickHandler(handler);
+ }
+
+ /**
+ * This constructor may be used by subclasses to explicitly use an existing
+ * element. This element must be a <button> element with type submit.
+ *
+ * @param element the element to be used
+ */
+ protected SubmitButton(com.google.gwt.dom.client.Element element) {
+ super(element);
+ assert "submit".equalsIgnoreCase(element.<ButtonElement> cast().getType());
+ }
+}
diff --git a/user/test/com/google/gwt/dom/client/DocumentTest.java b/user/test/com/google/gwt/dom/client/DocumentTest.java
index 2cf11b8..dc66082 100644
--- a/user/test/com/google/gwt/dom/client/DocumentTest.java
+++ b/user/test/com/google/gwt/dom/client/DocumentTest.java
@@ -37,7 +37,6 @@
assertEquals("blockquote",
doc.createBlockQuoteElement().getTagName().toLowerCase());
assertEquals("br", doc.createBRElement().getTagName().toLowerCase());
- assertEquals("button", doc.createButtonElement().getTagName().toLowerCase());
assertEquals("caption",
doc.createCaptionElement().getTagName().toLowerCase());
assertEquals("col", doc.createColElement().getTagName().toLowerCase());
@@ -91,6 +90,20 @@
assertEquals("tr", doc.createTRElement().getTagName().toLowerCase());
assertEquals("ul", doc.createULElement().getTagName().toLowerCase());
+ assertEquals("button",
+ doc.createPushButtonElement().getTagName().toLowerCase());
+ assertEquals("button",
+ doc.createResetButtonElement().getTagName().toLowerCase());
+ assertEquals("button",
+ doc.createSubmitButtonElement().getTagName().toLowerCase());
+
+ assertEquals("button",
+ doc.createPushButtonElement().getType().toLowerCase());
+ assertEquals("reset",
+ doc.createResetButtonElement().getType().toLowerCase());
+ assertEquals("submit",
+ doc.createSubmitButtonElement().getType().toLowerCase());
+
assertEquals("input",
doc.createCheckInputElement().getTagName().toLowerCase());
assertEquals("input",
@@ -106,6 +119,8 @@
assertEquals("input",
doc.createTextInputElement().getTagName().toLowerCase());
+ assertEquals("button",
+ doc.createButtonInputElement().getType().toLowerCase());
assertEquals("checkbox",
doc.createCheckInputElement().getType().toLowerCase());
assertEquals("file", doc.createFileInputElement().getType().toLowerCase());
@@ -116,6 +131,9 @@
doc.createPasswordInputElement().getType().toLowerCase());
assertEquals("radio",
doc.createRadioInputElement("foo").getType().toLowerCase());
+ assertEquals("reset", doc.createResetInputElement().getType().toLowerCase());
+ assertEquals("submit",
+ doc.createSubmitInputElement().getType().toLowerCase());
assertEquals("text", doc.createTextInputElement().getType().toLowerCase());
}
diff --git a/user/test/com/google/gwt/dom/client/ElementTest.java b/user/test/com/google/gwt/dom/client/ElementTest.java
index 6d19163..b332018 100644
--- a/user/test/com/google/gwt/dom/client/ElementTest.java
+++ b/user/test/com/google/gwt/dom/client/ElementTest.java
@@ -75,7 +75,7 @@
* Test round-trip of the 'disabled' property.
*/
public void testDisabled() {
- ButtonElement button = Document.get().createButtonElement();
+ ButtonElement button = Document.get().createPushButtonElement();
assertFalse(button.isDisabled());
button.setDisabled(true);
assertTrue(button.isDisabled());
diff --git a/user/test/com/google/gwt/user/client/ui/ButtonTest.java b/user/test/com/google/gwt/user/client/ui/ButtonTest.java
index 0fcf4dd..f570f20 100644
--- a/user/test/com/google/gwt/user/client/ui/ButtonTest.java
+++ b/user/test/com/google/gwt/user/client/ui/ButtonTest.java
@@ -19,12 +19,16 @@
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.Timer;
+import com.google.gwt.user.client.ui.FormPanel.SubmitEvent;
+import com.google.gwt.user.client.ui.FormPanel.SubmitHandler;
/**
* Tests for {@link Button}.
*/
public class ButtonTest extends GWTTestCase {
+ @Override
public String getModuleName() {
return "com.google.gwt.user.User";
}
@@ -39,6 +43,26 @@
}
}
+ private static class H2 implements SubmitHandler {
+ boolean submitted;
+
+ public void onSubmit(SubmitEvent event) {
+ submitted = true;
+ event.cancel();
+ }
+ }
+
+ public void testButton() {
+ Button pushButton = new Button();
+ assertEquals("button", pushButton.getButtonElement().getType());
+
+ ResetButton resetButton = new ResetButton();
+ assertEquals("reset", resetButton.getButtonElement().getType());
+
+ SubmitButton submitButton = new SubmitButton();
+ assertEquals("submit", submitButton.getButtonElement().getType());
+ }
+
public void testClick() {
Button b = new Button();
RootPanel.get().add(b);
@@ -53,5 +77,30 @@
// synthesized clicks. This tests the workaround in DOMImplMozillaOld.
assertEquals(b.getElement(), h.target);
}
-}
+ /**
+ * Tests issues 1585 and 3962: a button shouldn't submit a form.
+ */
+ public void testPushButton() {
+ FormPanel f = new FormPanel();
+ f.setAction("javascript:''");
+ RootPanel.get().add(f);
+
+ Button b = new Button();
+ f.setWidget(b);
+
+ final H2 h = new H2();
+ f.addSubmitHandler(h);
+
+ delayTestFinish(5000);
+ new Timer() {
+ @Override
+ public void run() {
+ assertFalse(h.submitted);
+ finishTest();
+ }
+ }.schedule(2500);
+
+ b.click();
+ }
+}