summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJouni Koivuviita <jouni.koivuviita@itmill.com>2009-08-27 12:26:49 +0000
committerJouni Koivuviita <jouni.koivuviita@itmill.com>2009-08-27 12:26:49 +0000
commitad101f842727ca84a184f1bf1ad7c5e63878302b (patch)
treeb636516fa19ef5dab996c9160e576e3169e50f7b /src
parent7072fbb2f053ab9a390ee5e004d65e465c7b93e7 (diff)
downloadvaadin-framework-ad101f842727ca84a184f1bf1ad7c5e63878302b.tar.gz
vaadin-framework-ad101f842727ca84a184f1bf1ad7c5e63878302b.zip
The Button Component Strikes Back
Fixes many theme issues with Button (mostly Reindeer theme), including #3110, #3193, #3194, #3180 and 3079. Default button is now rendered on the client side with a DIV. Disabled buttons can now have descriptions, which fixes #2085. Added a "new" component, NativeButton, which uses native BUTTON element rendering on the client side. Theme compilation script now understands simple @import statements, which help keep things more organized in theme development. svn changeset:8558/svn branch:6.1
Diffstat (limited to 'src')
-rw-r--r--src/com/vaadin/demo/sampler/ModeSwitch.java3
-rw-r--r--src/com/vaadin/demo/sampler/SamplerApplication.java11
-rwxr-xr-xsrc/com/vaadin/terminal/gwt/client/ApplicationConnection.java3
-rw-r--r--src/com/vaadin/terminal/gwt/client/DefaultWidgetSet.java7
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VButton.java429
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java5
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VNativeButton.java182
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java4
-rw-r--r--src/com/vaadin/tests/themes/ButtonsTest.java158
-rw-r--r--src/com/vaadin/tests/themes/ReindeerButtonsTest.java82
-rw-r--r--src/com/vaadin/ui/Button.java34
-rw-r--r--src/com/vaadin/ui/NativeButton.java51
12 files changed, 739 insertions, 230 deletions
diff --git a/src/com/vaadin/demo/sampler/ModeSwitch.java b/src/com/vaadin/demo/sampler/ModeSwitch.java
index 738f9f07cb..62a1ab8ef4 100644
--- a/src/com/vaadin/demo/sampler/ModeSwitch.java
+++ b/src/com/vaadin/demo/sampler/ModeSwitch.java
@@ -7,6 +7,7 @@ import com.vaadin.terminal.Resource;
import com.vaadin.ui.Button;
import com.vaadin.ui.CustomComponent;
import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.NativeButton;
import com.vaadin.ui.Button.ClickEvent;
@SuppressWarnings("serial")
@@ -45,7 +46,7 @@ public class ModeSwitch extends CustomComponent {
if (idToButton.containsKey(id)) {
removeMode(id);
}
- Button b = new Button();
+ Button b = new NativeButton();
if (caption != null) {
b.setCaption(caption);
}
diff --git a/src/com/vaadin/demo/sampler/SamplerApplication.java b/src/com/vaadin/demo/sampler/SamplerApplication.java
index 2b5fc4a8ac..85978c16da 100644
--- a/src/com/vaadin/demo/sampler/SamplerApplication.java
+++ b/src/com/vaadin/demo/sampler/SamplerApplication.java
@@ -30,6 +30,7 @@ import com.vaadin.ui.Embedded;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
+import com.vaadin.ui.NativeButton;
import com.vaadin.ui.Panel;
import com.vaadin.ui.PopupView;
import com.vaadin.ui.SplitPanel;
@@ -358,7 +359,7 @@ public class SamplerApplication extends Application {
}
private Component createLogo() {
- Button logo = new Button("", new Button.ClickListener() {
+ Button logo = new NativeButton("", new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
setFeature((Feature) null);
}
@@ -371,7 +372,7 @@ public class SamplerApplication extends Application {
}
private Button createNextButton() {
- Button b = new Button("", new ClickListener() {
+ Button b = new NativeButton("", new ClickListener() {
public void buttonClick(ClickEvent event) {
Object curr = currentFeature.getValue();
Object next = allFeatures.nextItemId(curr);
@@ -392,7 +393,7 @@ public class SamplerApplication extends Application {
}
private Button createPrevButton() {
- Button b = new Button("", new ClickListener() {
+ Button b = new NativeButton("", new ClickListener() {
public void buttonClick(ClickEvent event) {
Object curr = currentFeature.getValue();
Object prev = allFeatures.prevItemId(curr);
@@ -409,7 +410,7 @@ public class SamplerApplication extends Application {
}
private Component createTreeSwitch() {
- final Button b = new Button();
+ final Button b = new NativeButton();
b.setStyleName("tree-switch");
b.setDescription("Toggle sample tree visibility");
b.addListener(new Button.ClickListener() {
@@ -716,7 +717,7 @@ public class SamplerApplication extends Application {
if (grid.getCursorX() == 0) {
grid.space();
}
- Button b = new Button();
+ Button b = new NativeButton();
b.setStyleName(Button.STYLE_LINK);
b.addStyleName("screenshot");
String resId = "75-" + f.getIconName();
diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
index a6965b2693..69174587a6 100755
--- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
+++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
@@ -1108,10 +1108,11 @@ public class ApplicationConnection {
boolean enabled = !uidl.getBooleanAttribute("disabled");
if (component instanceof FocusWidget) {
FocusWidget fw = (FocusWidget) component;
- fw.setEnabled(enabled);
if (uidl.hasAttribute("tabindex")) {
fw.setTabIndex(uidl.getIntAttribute("tabindex"));
}
+ // Disabled state may affect tabindex
+ fw.setEnabled(enabled);
}
StringBuffer styleBuf = new StringBuffer();
diff --git a/src/com/vaadin/terminal/gwt/client/DefaultWidgetSet.java b/src/com/vaadin/terminal/gwt/client/DefaultWidgetSet.java
index 9ac2337004..f72859dbfb 100644
--- a/src/com/vaadin/terminal/gwt/client/DefaultWidgetSet.java
+++ b/src/com/vaadin/terminal/gwt/client/DefaultWidgetSet.java
@@ -22,6 +22,7 @@ import com.vaadin.terminal.gwt.client.ui.VLabel;
import com.vaadin.terminal.gwt.client.ui.VLink;
import com.vaadin.terminal.gwt.client.ui.VListSelect;
import com.vaadin.terminal.gwt.client.ui.VMenuBar;
+import com.vaadin.terminal.gwt.client.ui.VNativeButton;
import com.vaadin.terminal.gwt.client.ui.VNativeSelect;
import com.vaadin.terminal.gwt.client.ui.VOptionGroup;
import com.vaadin.terminal.gwt.client.ui.VOrderedLayout;
@@ -64,6 +65,8 @@ public class DefaultWidgetSet implements WidgetSet {
return new VCheckBox();
} else if (VButton.class == classType) {
return new VButton();
+ } else if (VNativeButton.class == classType) {
+ return new VNativeButton();
} else if (VWindow.class == classType) {
return new VWindow();
} else if (VOrderedLayout.class == classType) {
@@ -150,9 +153,11 @@ public class DefaultWidgetSet implements WidgetSet {
protected Class resolveWidgetType(UIDL uidl) {
final String tag = uidl.getTag();
- if ("button".equals(tag)) {
+ if ("button".equals(tag) || "nativebutton".equals(tag)) {
if ("switch".equals(uidl.getStringAttribute("type"))) {
return VCheckBox.class;
+ } else if ("nativebutton".equals(tag)) {
+ return VNativeButton.class;
} else {
return VButton.class;
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VButton.java b/src/com/vaadin/terminal/gwt/client/ui/VButton.java
index 768b98727b..b3213b1b8f 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VButton.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VButton.java
@@ -4,14 +4,15 @@
package com.vaadin.terminal.gwt.client.ui;
-import com.google.gwt.user.client.Command;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+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;
-import com.google.gwt.user.client.DeferredCommand;
-import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.Button;
-import com.google.gwt.user.client.ui.ClickListener;
-import com.google.gwt.user.client.ui.Widget;
+import com.google.gwt.user.client.ui.Accessibility;
+import com.google.gwt.user.client.ui.FocusWidget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.Paintable;
@@ -19,70 +20,86 @@ import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VTooltip;
-public class VButton extends Button implements Paintable {
-
- private String width = null;
+public class VButton extends FocusWidget implements Paintable {
public static final String CLASSNAME = "v-button";
+ private static final String CLASSNAME_PRESSED = "v-pressed";
- // Used only for IE, because it doesn't support :active CSS selector
- private static final String CLASSNAME_DOWN = "v-pressed";
-
- private String primaryStyleName;
+ protected String id;
- String id;
+ protected ApplicationConnection client;
- ApplicationConnection client;
+ protected final Element wrapper = DOM.createSpan();
- private Element errorIndicatorElement;
+ protected Element errorIndicatorElement;
- private final Element captionElement = DOM.createSpan();
+ protected final Element captionElement = DOM.createSpan();
- private Icon icon;
+ protected Icon icon;
/**
- * Helper flat to handle special-case where the button is moved from under
+ * Helper flag to handle special-case where the button is moved from under
* mouse while clicking it. In this case mouse leaves the button without
* moving.
*/
private boolean clickPending;
+ /*
+ * BELOW PRIVATE MEMBERS COPY-PASTED FROM GWT CustomButton
+ */
+
+ /**
+ * If <code>true</code>, this widget is capturing with the mouse held down.
+ */
+ private boolean isCapturing;
+
+ /**
+ * If <code>true</code>, this widget has focus with the space bar down.
+ */
+ private boolean isFocusing;
+
+ /**
+ * Used to decide whether to allow clicks to propagate up to the superclass
+ * or container elements.
+ */
+ private boolean allowClick;
+ private boolean isHovering;
+ private boolean enabled = true;
+ private int tabIndex = 0;
+
public VButton() {
+ super(DOM.createDiv());
+ setTabIndex(0);
+ sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS | Event.FOCUSEVENTS
+ | Event.KEYEVENTS);
+ sinkEvents(VTooltip.TOOLTIP_EVENTS);
+
setStyleName(CLASSNAME);
- DOM.appendChild(getElement(), captionElement);
- captionElement.setPropertyString("className", CLASSNAME + "-caption");
+ // Add a11y role "button"
+ Accessibility.setRole(getElement(), Accessibility.ROLE_BUTTON);
- addClickListener(new ClickListener() {
- public void onClick(Widget sender) {
+ wrapper.setClassName(CLASSNAME + "-wrap");
+ getElement().appendChild(wrapper);
+ captionElement.setClassName(CLASSNAME + "-caption");
+ wrapper.appendChild(captionElement);
+
+ addClickHandler(new ClickHandler() {
+ public void onClick(ClickEvent event) {
if (id == null || client == null) {
return;
}
- /*
- * TODO isolate workaround. Safari don't always seem to fire
- * onblur previously focused component before button is clicked.
- */
- VButton.this.setFocus(true);
+ if (BrowserInfo.get().isSafari()) {
+ VButton.this.setFocus(true);
+ }
client.updateVariable(id, "state", true, true);
clickPending = false;
}
});
- sinkEvents(VTooltip.TOOLTIP_EVENTS);
- sinkEvents(Event.ONMOUSEDOWN);
- sinkEvents(Event.ONMOUSEUP);
}
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- // client.updateComponent depends on this, so this must come before
- if (uidl.hasAttribute("primarystyle")
- && primaryStyleName != uidl.getStringAttribute("primarystyle")) {
- primaryStyleName = uidl.getStringAttribute("primarystyle");
- setStyleName(primaryStyleName);
- captionElement.setPropertyString("className", getStylePrimaryName()
- + "-caption");
- }
-
// Ensure correct implementation,
// but don't let container manage caption etc.
if (client.updateComponent(this, uidl, false)) {
@@ -100,115 +117,321 @@ public class VButton extends Button implements Paintable {
if (uidl.hasAttribute("error")) {
if (errorIndicatorElement == null) {
errorIndicatorElement = DOM.createSpan();
- DOM.setElementProperty(errorIndicatorElement, "className",
- "v-errorindicator");
+ errorIndicatorElement.setClassName("v-errorindicator");
}
- DOM.insertChild(getElement(), errorIndicatorElement, 0);
+ wrapper.insertBefore(errorIndicatorElement, captionElement);
// Fix for IE6, IE7
- if (BrowserInfo.get().isIE()) {
- DOM.setInnerText(errorIndicatorElement, " ");
+ if (BrowserInfo.get().isIE6() || BrowserInfo.get().isIE7()) {
+ errorIndicatorElement.setInnerText(" ");
}
} else if (errorIndicatorElement != null) {
- DOM.removeChild(getElement(), errorIndicatorElement);
+ wrapper.removeChild(errorIndicatorElement);
errorIndicatorElement = null;
}
- if (uidl.hasAttribute("readonly")) {
- setEnabled(false);
- }
-
if (uidl.hasAttribute("icon")) {
if (icon == null) {
icon = new Icon(client);
- DOM.insertChild(getElement(), icon.getElement(), 0);
+ wrapper.insertBefore(icon.getElement(), captionElement);
}
icon.setUri(uidl.getStringAttribute("icon"));
} else {
if (icon != null) {
- DOM.removeChild(getElement(), icon.getElement());
+ wrapper.removeChild(icon.getElement());
icon = null;
}
}
- if (BrowserInfo.get().isIE7()) {
- /*
- * Workaround for IE7 size calculation issues. Deferred because of
- * issues with a button with an icon using the reindeer theme
- */
- if (width.equals("")) {
- DeferredCommand.addCommand(new Command() {
-
- public void execute() {
- setWidth("");
- setWidth(getOffsetWidth() + "px");
- }
- });
- }
- }
}
- @Override
public void setText(String text) {
- DOM.setInnerText(captionElement, text);
+ captionElement.setInnerText(text);
}
+ @SuppressWarnings("deprecation")
@Override
+ /*
+ * Copy-pasted from GWT CustomButton, some minor modifications done:
+ *
+ * -for IE/Opera added CLASSNAME_PRESSED
+ *
+ * -event.preventDefault() commented from ONMOUSEDOWN (Firefox won't apply
+ * :active styles if it is present)
+ *
+ * -Tooltip event handling added
+ *
+ * -onload event handler added (for icon handling)
+ */
public void onBrowserEvent(Event event) {
- super.onBrowserEvent(event);
-
+ if (client != null) {
+ client.handleTooltipEvent(event, this);
+ }
if (DOM.eventGetType(event) == Event.ONLOAD) {
Util.notifyParentOfSizeChange(this, true);
+ }
+ // Should not act on button if disabled.
+ if (!isEnabled()) {
+ // This can happen when events are bubbled up from non-disabled
+ // children
+ return;
+ }
- } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN
- && event.getButton() == Event.BUTTON_LEFT) {
- clickPending = true;
- if (BrowserInfo.get().isIE()) {
- // Only for IE, because it doesn't support :active CSS selector
- // Simple check is cheaper than DOM manipulation
- addStyleName(CLASSNAME_DOWN);
+ int type = DOM.eventGetType(event);
+ switch (type) {
+ case Event.ONCLICK:
+ // If clicks are currently disallowed, keep it from bubbling or
+ // being passed to the superclass.
+ if (!allowClick) {
+ event.stopPropagation();
+ return;
}
- } else if (DOM.eventGetType(event) == Event.ONMOUSEMOVE) {
- clickPending = false;
- } else if (DOM.eventGetType(event) == Event.ONMOUSEOUT) {
- if (clickPending) {
- click();
+ break;
+ case Event.ONMOUSEDOWN:
+ if (event.getButton() == Event.BUTTON_LEFT) {
+ clickPending = true;
+ setFocus(true);
+ DOM.setCapture(getElement());
+ isCapturing = true;
+ // Prevent dragging (on some browsers);
+ // DOM.eventPreventDefault(event);
+ if (BrowserInfo.get().isIE() || BrowserInfo.get().isOpera()) {
+ addStyleName(CLASSNAME_PRESSED);
+ }
}
- if (BrowserInfo.get().isIE()) {
- removeStyleName(CLASSNAME_DOWN);
+ break;
+ case Event.ONMOUSEUP:
+ if (isCapturing) {
+ isCapturing = false;
+ DOM.releaseCapture(getElement());
+ if (isHovering() && event.getButton() == Event.BUTTON_LEFT) {
+ onClick();
+ }
+ if (BrowserInfo.get().isIE() || BrowserInfo.get().isOpera()) {
+ removeStyleName(CLASSNAME_PRESSED);
+ }
}
+ break;
+ case Event.ONMOUSEMOVE:
clickPending = false;
- } else if (DOM.eventGetType(event) == Event.ONMOUSEUP) {
- if (BrowserInfo.get().isIE()) {
- removeStyleName(CLASSNAME_DOWN);
+ if (isCapturing) {
+ // Prevent dragging (on other browsers);
+ DOM.eventPreventDefault(event);
+ }
+ break;
+ case Event.ONMOUSEOUT:
+ Element to = event.getRelatedTarget();
+ if (getElement().isOrHasChild(DOM.eventGetTarget(event))
+ && (to == null || !getElement().isOrHasChild(to))) {
+ if (clickPending) {
+ onClick();
+ break;
+ }
+ clickPending = false;
+ if (isCapturing) {
+ }
+ setHovering(false);
+ if (BrowserInfo.get().isIE() || BrowserInfo.get().isOpera()) {
+ removeStyleName(CLASSNAME_PRESSED);
+ }
+ }
+ break;
+ case Event.ONMOUSEOVER:
+ if (DOM.isOrHasChild(getElement(), DOM.eventGetTarget(event))) {
+ setHovering(true);
+ if (isCapturing) {
+ }
+ }
+ break;
+ case Event.ONBLUR:
+ if (isFocusing) {
+ isFocusing = false;
}
+ break;
+ case Event.ONLOSECAPTURE:
+ if (isCapturing) {
+ isCapturing = false;
+ }
+ break;
}
- if (client != null) {
- client.handleTooltipEvent(event, this);
+ super.onBrowserEvent(event);
+
+ // Synthesize clicks based on keyboard events AFTER the normal key
+ // handling.
+ if ((event.getTypeInt() & Event.KEYEVENTS) != 0) {
+ char keyCode = (char) DOM.eventGetKeyCode(event);
+ switch (type) {
+ case Event.ONKEYDOWN:
+ if (keyCode == ' ') {
+ isFocusing = true;
+ event.preventDefault();
+ }
+ break;
+ case Event.ONKEYUP:
+ if (isFocusing && keyCode == ' ') {
+ isFocusing = false;
+ onClick();
+ event.preventDefault();
+ }
+ break;
+ case Event.ONKEYPRESS:
+ if (keyCode == '\n' || keyCode == '\r') {
+ onClick();
+ event.preventDefault();
+ }
+ break;
+ }
+ }
+ }
+
+ final void setHovering(boolean hovering) {
+ if (hovering != isHovering()) {
+ isHovering = hovering;
}
}
+ final boolean isHovering() {
+ return isHovering;
+ }
+
+ /*
+ * ALL BELOW COPY-PASTED FROM GWT CustomButton
+ */
+
+ /**
+ * Called when the user finishes clicking on this button. The default
+ * behavior is to fire the click event to listeners. Subclasses that
+ * override {@link #onClickStart()} should override this method to restore
+ * the normal widget display.
+ */
+ protected void onClick() {
+ // Allow the click we're about to synthesize to pass through to the
+ // superclass and containing elements. Element.dispatchEvent() is
+ // synchronous, so we simply set and clear the flag within this method.
+ allowClick = true;
+
+ // 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);
+
+ allowClick = false;
+ }
+
+ /**
+ * Sets whether this button is enabled.
+ *
+ * @param enabled
+ * <code>true</code> to enable the button, <code>false</code> to
+ * disable it
+ */
+
@Override
- public void setWidth(String width) {
- /* Workaround for IE7 button size part 1 (#2014) */
- if (BrowserInfo.get().isIE7() && this.width != null) {
- if (this.width.equals(width)) {
- return;
+ public final void setEnabled(boolean enabled) {
+ if (isEnabled() != enabled) {
+ this.enabled = enabled;
+ if (!enabled) {
+ cleanupCaptureState();
+ Accessibility.removeState(getElement(),
+ Accessibility.STATE_PRESSED);
+ super.setTabIndex(-1);
+ } else {
+ Accessibility.setState(getElement(),
+ Accessibility.STATE_PRESSED, "false");
+ super.setTabIndex(tabIndex);
}
+ }
+ }
- if (width == null) {
- width = "";
- }
+ @Override
+ public final boolean isEnabled() {
+ return enabled;
+ }
+
+ @Override
+ public final void setTabIndex(int index) {
+ super.setTabIndex(index);
+ tabIndex = index;
+ }
+
+ /**
+ * Resets internal state if this button can no longer service events. This
+ * can occur when the widget becomes detached or disabled.
+ */
+ private void cleanupCaptureState() {
+ if (isCapturing || isFocusing) {
+ DOM.releaseCapture(getElement());
+ isCapturing = false;
+ isFocusing = false;
}
+ }
- this.width = width;
+ @Override
+ public void setWidth(String width) {
+ if (BrowserInfo.get().isIE6() || BrowserInfo.get().isIE7()) {
+ if (width != null && width.length() > 2) {
+ // Assume pixel values are always sent from
+ // ApplicationConnection
+ int w = Integer
+ .parseInt(width.substring(0, width.length() - 2));
+ w -= getHorizontalBorderAndPaddingWidth(getElement());
+ width = w + "px";
+ }
+ }
super.setWidth(width);
+ }
- /* Workaround for IE7 button size part 2 (#2014) */
- if (BrowserInfo.get().isIE7()) {
- super.setWidth(width);
+ private static native int getHorizontalBorderAndPaddingWidth(Element elem)
+ /*-{
+ // THIS METHOD IS ONLY USED FOR INTERNET EXPLORER, IT DOESN'T WORK WITH OTHERS
+
+ var convertToPixel = function(elem, value) {
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // Remember the original values
+ var left = style.left, rsLeft = elem.runtimeStyle.left;
+
+ // Put in the new values to get a computed value out
+ elem.runtimeStyle.left = elem.currentStyle.left;
+ style.left = value || 0;
+ var ret = style.pixelLeft;
+
+ // Revert the changed values
+ style.left = left;
+ elem.runtimeStyle.left = rsLeft;
+
+ return ret;
+ }
+
+ var ret = 0;
+
+ var sides = ["Right","Left"];
+ for(var i=0; i<2; i++) {
+ var side = sides[i];
+ var value;
+ // Border -------------------------------------------------------
+ if(elem.currentStyle["border"+side+"Style"] != "none") {
+ value = elem.currentStyle["border"+side+"Width"];
+ if ( !/^\d+(px)?$/i.test( value ) && /^\d/.test( value ) ) {
+ ret += convertToPixel(elem, value);
+ } else if(value.length > 2) {
+ ret += parseInt(value.substr(0, value.length-2));
+ }
+ }
+
+ // Padding -------------------------------------------------------
+ value = elem.currentStyle["padding"+side];
+ if ( !/^\d+(px)?$/i.test( value ) && /^\d/.test( value ) ) {
+ ret += convertToPixel(elem, value);
+ } else if(value.length > 2) {
+ ret += parseInt(value.substr(0, value.length-2));
+ }
}
- }
+
+ return ret;
+ }-*/;
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java
index 8d688c2ed9..f1f640653e 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java
@@ -394,7 +394,8 @@ public class VCalendarPanel extends FlexTable implements MouseListener {
processClickEvent(sender, true);
}
- private class VEventButton extends VButton implements SourcesMouseEvents {
+ private class VEventButton extends VNativeButton implements
+ SourcesMouseEvents {
private MouseListenerCollection mouseListeners;
@@ -404,6 +405,7 @@ public class VCalendarPanel extends FlexTable implements MouseListener {
| Event.MOUSEEVENTS);
}
+ @Override
public void addMouseListener(MouseListener listener) {
if (mouseListeners == null) {
mouseListeners = new MouseListenerCollection();
@@ -411,6 +413,7 @@ public class VCalendarPanel extends FlexTable implements MouseListener {
mouseListeners.add(listener);
}
+ @Override
public void removeMouseListener(MouseListener listener) {
if (mouseListeners != null) {
mouseListeners.remove(listener);
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VNativeButton.java b/src/com/vaadin/terminal/gwt/client/ui/VNativeButton.java
new file mode 100644
index 0000000000..e544e1f9ce
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VNativeButton.java
@@ -0,0 +1,182 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Button;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.VTooltip;
+
+public class VNativeButton extends Button implements Paintable {
+
+ public static final String CLASSNAME = "v-nativebutton";
+
+ protected String width = null;
+
+ protected String id;
+
+ protected ApplicationConnection client;
+
+ protected Element errorIndicatorElement;
+
+ protected final Element captionElement = DOM.createSpan();
+
+ protected Icon icon;
+
+ /**
+ * Helper flag to handle special-case where the button is moved from under
+ * mouse while clicking it. In this case mouse leaves the button without
+ * moving.
+ */
+ private boolean clickPending;
+
+ public VNativeButton() {
+ setStyleName(CLASSNAME);
+
+ getElement().appendChild(captionElement);
+ captionElement.setClassName(getStyleName() + "-caption");
+
+ addClickHandler(new ClickHandler() {
+ public void onClick(ClickEvent event) {
+ if (id == null || client == null) {
+ return;
+ }
+ if (BrowserInfo.get().isSafari()) {
+ VNativeButton.this.setFocus(true);
+ }
+ client.updateVariable(id, "state", true, true);
+ clickPending = false;
+ }
+ });
+ sinkEvents(VTooltip.TOOLTIP_EVENTS);
+ sinkEvents(Event.ONMOUSEDOWN);
+ sinkEvents(Event.ONMOUSEUP);
+ }
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+
+ // Ensure correct implementation,
+ // but don't let container manage caption etc.
+ if (client.updateComponent(this, uidl, false)) {
+ return;
+ }
+
+ // Save details
+ this.client = client;
+ id = uidl.getId();
+
+ // Set text
+ setText(uidl.getStringAttribute("caption"));
+
+ // handle error
+ if (uidl.hasAttribute("error")) {
+ if (errorIndicatorElement == null) {
+ errorIndicatorElement = DOM.createSpan();
+ errorIndicatorElement.setClassName("v-errorindicator");
+ }
+ getElement().insertBefore(errorIndicatorElement, captionElement);
+
+ // Fix for IE6, IE7
+ if (BrowserInfo.get().isIE()) {
+ errorIndicatorElement.setInnerText(" ");
+ }
+
+ } else if (errorIndicatorElement != null) {
+ getElement().removeChild(errorIndicatorElement);
+ errorIndicatorElement = null;
+ }
+
+ if (uidl.hasAttribute("icon")) {
+ if (icon == null) {
+ icon = new Icon(client);
+ getElement().insertBefore(icon.getElement(), captionElement);
+ }
+ icon.setUri(uidl.getStringAttribute("icon"));
+ } else {
+ if (icon != null) {
+ getElement().removeChild(icon.getElement());
+ icon = null;
+ }
+ }
+
+ if (BrowserInfo.get().isIE7()) {
+ /*
+ * Workaround for IE7 size calculation issues. Deferred because of
+ * issues with a button with an icon using the reindeer theme
+ */
+ if (width.equals("")) {
+ DeferredCommand.addCommand(new Command() {
+
+ public void execute() {
+ setWidth("");
+ setWidth(getOffsetWidth() + "px");
+ }
+ });
+ }
+ }
+ }
+
+ @Override
+ public void setText(String text) {
+ captionElement.setInnerText(text);
+ }
+
+ @Override
+ public void onBrowserEvent(Event event) {
+ super.onBrowserEvent(event);
+
+ if (DOM.eventGetType(event) == Event.ONLOAD) {
+ Util.notifyParentOfSizeChange(this, true);
+
+ } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN
+ && event.getButton() == Event.BUTTON_LEFT) {
+ clickPending = true;
+ } else if (DOM.eventGetType(event) == Event.ONMOUSEMOVE) {
+ clickPending = false;
+ } else if (DOM.eventGetType(event) == Event.ONMOUSEOUT) {
+ if (clickPending) {
+ click();
+ }
+ clickPending = false;
+ }
+
+ if (client != null) {
+ client.handleTooltipEvent(event, this);
+ }
+ }
+
+ @Override
+ public void setWidth(String width) {
+ /* Workaround for IE7 button size part 1 (#2014) */
+ if (BrowserInfo.get().isIE7() && this.width != null) {
+ if (this.width.equals(width)) {
+ return;
+ }
+
+ if (width == null) {
+ width = "";
+ }
+ }
+
+ this.width = width;
+ super.setWidth(width);
+
+ /* Workaround for IE7 button size part 2 (#2014) */
+ if (BrowserInfo.get().isIE7()) {
+ super.setWidth(width);
+ }
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java
index d10bcc6cfa..4d4ba4e579 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java
@@ -58,7 +58,7 @@ abstract class VOptionGroupBase extends Composite implements Paintable, Field,
private VTextField newItemField;
- private VButton newItemButton;
+ private VNativeButton newItemButton;
public VOptionGroupBase(String classname) {
container = new FlowPanel();
@@ -155,7 +155,7 @@ abstract class VOptionGroupBase extends Composite implements Paintable, Field,
if (uidl.getBooleanAttribute("allownewitem")) {
if (newItemField == null) {
- newItemButton = new VButton();
+ newItemButton = new VNativeButton();
newItemButton.setText("+");
newItemButton.addClickListener(this);
newItemField = new VTextField();
diff --git a/src/com/vaadin/tests/themes/ButtonsTest.java b/src/com/vaadin/tests/themes/ButtonsTest.java
new file mode 100644
index 0000000000..9ad2a9f39e
--- /dev/null
+++ b/src/com/vaadin/tests/themes/ButtonsTest.java
@@ -0,0 +1,158 @@
+package com.vaadin.tests.themes;
+
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.terminal.UserError;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Layout;
+import com.vaadin.ui.NativeButton;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+
+@SuppressWarnings("serial")
+public class ButtonsTest extends com.vaadin.Application {
+
+ final Window main = new Window("Button states & themes");
+
+ CheckBox styleToggle;
+ CheckBox iconToggle;
+ CheckBox nativeToggle;
+ CheckBox themeToggle;
+ boolean largeIcons = false;
+ boolean nativeButtons = false;
+
+ final HorizontalLayout toggles = new HorizontalLayout();
+
+ @Override
+ public void init() {
+ setMainWindow(main);
+ setTheme("reindeer");
+
+ themeToggle = new CheckBox("Runo theme", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ if (getTheme() == "reindeer") {
+ setTheme("runo");
+ } else {
+ setTheme("reindeer");
+ }
+ }
+ });
+ themeToggle.setStyleName("small");
+ themeToggle.setImmediate(true);
+
+ styleToggle = new CheckBox("Black style", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ if (!main.getContent().getStyleName().contains("black")) {
+ main.getContent().setStyleName("black");
+ } else {
+ main.getContent().setStyleName("");
+ }
+ }
+ });
+ styleToggle.setImmediate(true);
+ styleToggle.setStyleName("small");
+
+ iconToggle = new CheckBox("64x icons", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ largeIcons = !largeIcons;
+ recreateAll();
+ }
+ });
+ iconToggle.setImmediate(true);
+ iconToggle.setStyleName("small");
+
+ nativeToggle = new CheckBox("Native buttons",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ nativeButtons = !nativeButtons;
+ recreateAll();
+ }
+ });
+ nativeToggle.setImmediate(true);
+ nativeToggle.setStyleName("small");
+
+ toggles.setSpacing(true);
+ toggles.addComponent(themeToggle);
+ toggles.addComponent(styleToggle);
+ toggles.addComponent(iconToggle);
+ toggles.addComponent(nativeToggle);
+ main.addComponent(toggles);
+
+ recreateAll();
+
+ }
+
+ private void recreateAll() {
+ main.removeAllComponents();
+ main.addComponent(toggles);
+
+ main.addComponent(buildButtons(false, false, false, false));
+ main.addComponent(buildButtons(false, false, true, false));
+ main.addComponent(buildButtons(false, true, false, false));
+ main.addComponent(buildButtons(false, true, true, false));
+ main.addComponent(buildButtons(true, false, false, false));
+ main.addComponent(buildButtons(true, false, true, false));
+ main.addComponent(buildButtons(true, true, false, false));
+ main.addComponent(buildButtons(true, true, true, false));
+
+ main.addComponent(buildButtons(false, false, false, true));
+ main.addComponent(buildButtons(false, false, true, true));
+ main.addComponent(buildButtons(false, true, false, true));
+ main.addComponent(buildButtons(false, true, true, true));
+ main.addComponent(buildButtons(true, false, false, true));
+ main.addComponent(buildButtons(true, false, true, true));
+ main.addComponent(buildButtons(true, true, false, true));
+ main.addComponent(buildButtons(true, true, true, true));
+
+ final Button b = new Button("Tabindex");
+ b.setTabIndex(1);
+ main.addComponent(b);
+
+ Button c = new Button("toggle enabled", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ b.setEnabled(!b.isEnabled());
+ }
+ });
+ main.addComponent(c);
+ }
+
+ private Layout buildButtons(boolean disabled, boolean icon, boolean error,
+ boolean sized) {
+
+ String[] buttonStyles = new String[] { "Normal", "Primary", "Small",
+ "Link" };
+
+ HorizontalLayout hl = new HorizontalLayout();
+ hl.setSpacing(true);
+ hl.setMargin(true);
+
+ for (int i = 0; i < buttonStyles.length; i++) {
+ Button b;
+ if (nativeButtons) {
+ b = new NativeButton(buttonStyles[i] + " style");
+ } else {
+ b = new Button(buttonStyles[i] + " style");
+ }
+ b.setStyleName(buttonStyles[i].toLowerCase());
+ if (icon) {
+ b.setIcon(new ThemeResource("../runo/icons/"
+ + (largeIcons ? "64" : "16") + "/document.png"));
+ }
+ if (error) {
+ b.setComponentError(new UserError("Error"));
+ }
+ if (disabled) {
+ b.setEnabled(false);
+ }
+ if (sized) {
+ b.setWidth("250px");
+ b.setCaption(b.getCaption() + " (250px)");
+ }
+ hl.addComponent(b);
+ }
+
+ return hl;
+ }
+
+} \ No newline at end of file
diff --git a/src/com/vaadin/tests/themes/ReindeerButtonsTest.java b/src/com/vaadin/tests/themes/ReindeerButtonsTest.java
deleted file mode 100644
index 952b7ffd1c..0000000000
--- a/src/com/vaadin/tests/themes/ReindeerButtonsTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.vaadin.tests.themes;
-
-import com.vaadin.terminal.ThemeResource;
-import com.vaadin.terminal.UserError;
-import com.vaadin.ui.Button;
-import com.vaadin.ui.HorizontalLayout;
-import com.vaadin.ui.Layout;
-import com.vaadin.ui.Window;
-import com.vaadin.ui.Button.ClickEvent;
-
-@SuppressWarnings("serial")
-public class ReindeerButtonsTest extends com.vaadin.Application {
-
- final Window main = new Window("Reindeer buttons");
-
- @Override
- public void init() {
- setMainWindow(main);
- setTheme("reindeer");
-
- Button toggle = new Button("Toggle black style",
- new Button.ClickListener() {
- public void buttonClick(ClickEvent event) {
- if (!main.getContent().getStyleName().contains("black")) {
- main.getContent().setStyleName("black");
- } else {
- main.getContent().setStyleName("");
- }
- }
- });
- main.addComponent(toggle);
-
- main.addComponent(buildButtons(false, false, false, false));
- main.addComponent(buildButtons(false, false, true, false));
- main.addComponent(buildButtons(false, true, false, false));
- main.addComponent(buildButtons(false, true, true, false));
- main.addComponent(buildButtons(true, false, false, false));
- main.addComponent(buildButtons(true, false, true, false));
- main.addComponent(buildButtons(true, true, false, false));
- main.addComponent(buildButtons(true, true, true, false));
-
- main.addComponent(buildButtons(false, false, false, true));
- main.addComponent(buildButtons(false, false, true, true));
- main.addComponent(buildButtons(false, true, false, true));
- main.addComponent(buildButtons(false, true, true, true));
- main.addComponent(buildButtons(true, false, false, true));
- main.addComponent(buildButtons(true, false, true, true));
- main.addComponent(buildButtons(true, true, false, true));
- main.addComponent(buildButtons(true, true, true, true));
- }
-
- private Layout buildButtons(boolean disabled, boolean icon, boolean error,
- boolean sized) {
-
- String[] buttonStyles = new String[] { "", "primary", "small", "link" };
-
- HorizontalLayout hl = new HorizontalLayout();
- hl.setSpacing(true);
- hl.setMargin(true);
-
- for (int i = 0; i < buttonStyles.length; i++) {
- Button b = new Button(buttonStyles[i] + " style");
- b.setStyleName(buttonStyles[i]);
- if (icon) {
- b.setIcon(new ThemeResource("../runo/icons/16/document.png"));
- }
- if (error) {
- b.setComponentError(new UserError("Error"));
- }
- if (disabled) {
- b.setEnabled(false);
- }
- if (sized) {
- b.setWidth("150px");
- }
- hl.addComponent(b);
- }
-
- return hl;
- }
-
-} \ No newline at end of file
diff --git a/src/com/vaadin/ui/Button.java b/src/com/vaadin/ui/Button.java
index df40aeb018..e4ca734d34 100644
--- a/src/com/vaadin/ui/Button.java
+++ b/src/com/vaadin/ui/Button.java
@@ -28,8 +28,6 @@ public class Button extends AbstractField {
boolean switchMode = false;
- private String primaryStyleName;
-
/**
* Creates a new push button. The value of the push button is false and it
* is immediate by default.
@@ -137,9 +135,6 @@ public class Button extends AbstractField {
public void paintContent(PaintTarget target) throws PaintException {
super.paintContent(target);
- if (primaryStyleName != null) {
- target.addAttribute("primarystyle", primaryStyleName);
- }
if (isSwitchMode()) {
target.addAttribute("type", "switch");
}
@@ -352,33 +347,4 @@ public class Button extends AbstractField {
super.setInternalValue(newValue);
}
- /**
- *
- * <i><b>EXPERIMENTAL FEATURE</b> Use with caution, the method signature
- * might change in following releases.</i>
- * <p>
- * Sets the components primary style name.
- * <p>
- * The primary style name is usually used on the client-side as the prefix
- * for widget CSS classnames (this depends on the terminal implementation).
- * The default primary styles are usually prefixed with Vaadin proprietary
- * "v-" string, e.g. the primary style name for a default Vaadin button is
- * "v-button".
- * <p>
- * With this method, you can change the primary style name to "mybutton",
- * and then on the client-side you would have "mybutton" as the CSS
- * classname. After that, all other style names you set for the component
- * will be prefixed with the new primary style name, i.e. setting an
- * additional style name "red" for the same button would result in a CSS
- * classname "mybutton-red" on the client-side.
- */
- public void setPrimaryStyleName(String primary) {
- primaryStyleName = primary;
- requestRepaint();
- }
-
- public String getPrimaryStyleName() {
- return primaryStyleName;
- }
-
}
diff --git a/src/com/vaadin/ui/NativeButton.java b/src/com/vaadin/ui/NativeButton.java
new file mode 100644
index 0000000000..4df771d054
--- /dev/null
+++ b/src/com/vaadin/ui/NativeButton.java
@@ -0,0 +1,51 @@
+package com.vaadin.ui;
+
+import com.vaadin.data.Property;
+
+@SuppressWarnings("serial")
+public class NativeButton extends Button {
+
+ public NativeButton() {
+ super();
+ }
+
+ public NativeButton(String caption) {
+ super(caption);
+ }
+
+ public NativeButton(String caption, ClickListener listener) {
+ super(caption, listener);
+ }
+
+ public NativeButton(String caption, Object target, String methodName) {
+ super(caption, target, methodName);
+ }
+
+ /**
+ * Creates a new switch button with initial value.
+ *
+ * @param state
+ * the Initial state of the switch-button.
+ * @param initialState
+ */
+ public NativeButton(String caption, boolean initialState) {
+ super(caption, initialState);
+ }
+
+ /**
+ * Creates a new switch button that is connected to a boolean property.
+ *
+ * @param state
+ * the Initial state of the switch-button.
+ * @param dataSource
+ */
+ public NativeButton(String caption, Property dataSource) {
+ super(caption, dataSource);
+ }
+
+ @Override
+ public String getTag() {
+ return "nativebutton";
+ }
+
+} \ No newline at end of file