summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKnoobie <Knoobie@gmx.de>2018-12-18 14:29:59 +0100
committerSun Zhe <31067185+ZheSun88@users.noreply.github.com>2018-12-18 15:29:59 +0200
commit353ba29cfdefddb032122cbeae5f02f6d9de76ba (patch)
tree05ee1da595faaab05976e9ab339472799648135b
parent9c9c962549eb04adac87b0cfe26d24b17843fb6a (diff)
downloadvaadin-framework-353ba29cfdefddb032122cbeae5f02f6d9de76ba.tar.gz
vaadin-framework-353ba29cfdefddb032122cbeae5f02f6d9de76ba.zip
Checkbox allow customizing of input and label classNames. (#11372)
* add client side integration for custom styles for checkbox.label and checkbox.input * add server side integration for checkbox element styling * add server side tests * add client side test
-rw-r--r--client/src/main/java/com/vaadin/client/ui/VCheckBox.java19
-rw-r--r--client/src/main/java/com/vaadin/client/ui/checkbox/CheckBoxConnector.java42
-rw-r--r--server/src/main/java/com/vaadin/ui/CheckBox.java201
-rw-r--r--server/src/main/java/com/vaadin/ui/HasStyleNames.java179
-rw-r--r--server/src/test/java/com/vaadin/ui/CheckBoxTest.java107
-rw-r--r--shared/src/main/java/com/vaadin/shared/ui/ComponentStateUtil.java7
-rw-r--r--shared/src/main/java/com/vaadin/shared/ui/checkbox/CheckBoxState.java4
-rw-r--r--uitest/src/main/java/com/vaadin/tests/components/checkbox/CheckboxLabelInputElement.java33
-rw-r--r--uitest/src/test/java/com/vaadin/tests/components/checkbox/CheckboxLabelInputElementTest.java48
9 files changed, 636 insertions, 4 deletions
diff --git a/client/src/main/java/com/vaadin/client/ui/VCheckBox.java b/client/src/main/java/com/vaadin/client/ui/VCheckBox.java
index 2c2df0a27e..f535086d94 100644
--- a/client/src/main/java/com/vaadin/client/ui/VCheckBox.java
+++ b/client/src/main/java/com/vaadin/client/ui/VCheckBox.java
@@ -84,19 +84,32 @@ public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox
*
* @return Element of the CheckBox itself
*/
- private Element getCheckBoxElement() {
+ public Element getInputElement() {
+ // public to allow CheckBoxState to access it.
// FIXME: Would love to use a better way to access the checkbox element
return getElement().getFirstChildElement();
}
+ /**
+ * Gives access to the label element.
+ *
+ * @return Element of the Label itself
+ * @since
+ */
+ public Element getLabelElement() {
+ // public to allow CheckBoxState to access it.
+ // FIXME: Would love to use a better way to access the label element
+ return getInputElement().getNextSiblingElement();
+ }
+
@Override
public void setAriaRequired(boolean required) {
- AriaHelper.handleInputRequired(getCheckBoxElement(), required);
+ AriaHelper.handleInputRequired(getInputElement(), required);
}
@Override
public void setAriaInvalid(boolean invalid) {
- AriaHelper.handleInputInvalid(getCheckBoxElement(), invalid);
+ AriaHelper.handleInputInvalid(getInputElement(), invalid);
}
@Override
diff --git a/client/src/main/java/com/vaadin/client/ui/checkbox/CheckBoxConnector.java b/client/src/main/java/com/vaadin/client/ui/checkbox/CheckBoxConnector.java
index e9582d1755..df9b9b11cf 100644
--- a/client/src/main/java/com/vaadin/client/ui/checkbox/CheckBoxConnector.java
+++ b/client/src/main/java/com/vaadin/client/ui/checkbox/CheckBoxConnector.java
@@ -15,6 +15,8 @@
*/
package com.vaadin.client.ui.checkbox;
+import com.google.gwt.core.client.JsArrayString;
+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.DOM;
@@ -30,11 +32,14 @@ import com.vaadin.client.ui.Icon;
import com.vaadin.client.ui.VCheckBox;
import com.vaadin.shared.EventId;
import com.vaadin.shared.MouseEventDetails;
+import com.vaadin.shared.ui.ComponentStateUtil;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.checkbox.CheckBoxServerRpc;
import com.vaadin.shared.ui.checkbox.CheckBoxState;
import com.vaadin.ui.CheckBox;
+import java.util.List;
+
/**
* The client-side connector for the {@code CheckBoxGroup} component.
*
@@ -45,6 +50,22 @@ import com.vaadin.ui.CheckBox;
public class CheckBoxConnector extends AbstractFieldConnector
implements ClickHandler {
+ /**
+ * The style names from getState().inputStyles which are currently applied
+ * to the checkbox.
+ *
+ * @since
+ */
+ private JsArrayString inputStyleNames = JsArrayString.createArray().cast();
+
+ /**
+ * The style names from getState().labelStyles which are currently applied
+ * to the checkbox.
+ *
+ * @since
+ */
+ private JsArrayString labelStyleNames = JsArrayString.createArray().cast();
+
@Override
public boolean delegateCaptionHandling() {
return false;
@@ -88,6 +109,10 @@ public class CheckBoxConnector extends AbstractFieldConnector
VCaption.setCaptionText(getWidget(), getState());
getWidget().setValue(getState().checked);
+
+ // Set styles for input and label
+ updateStyles(getWidget().getInputElement(), inputStyleNames, getState().inputStyles);
+ updateStyles(getWidget().getLabelElement(), labelStyleNames, getState().labelStyles);
}
@Override
@@ -134,4 +159,21 @@ public class CheckBoxConnector extends AbstractFieldConnector
contextEventSunk = true;
}
}
+
+ private void updateStyles(Element clientElement, JsArrayString clientSideStyles, List<String> serverSideStyes) {
+ // Remove all old stylenames
+ for (int i = 0; i < clientSideStyles.length(); i++) {
+ clientElement.removeClassName(clientSideStyles.get(i));
+ }
+ clientSideStyles.setLength(0);
+
+ if (ComponentStateUtil.hasStyles(serverSideStyes)) {
+ // add new style names
+ for (String newStyle : serverSideStyes) {
+ clientElement.addClassName(newStyle);
+ clientSideStyles.push(newStyle);
+ }
+
+ }
+ }
}
diff --git a/server/src/main/java/com/vaadin/ui/CheckBox.java b/server/src/main/java/com/vaadin/ui/CheckBox.java
index 30ec0487b2..c0e259f330 100644
--- a/server/src/main/java/com/vaadin/ui/CheckBox.java
+++ b/server/src/main/java/com/vaadin/ui/CheckBox.java
@@ -16,8 +16,12 @@
package com.vaadin.ui;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
import java.util.Objects;
+import java.util.StringTokenizer;
import org.jsoup.nodes.Attributes;
import org.jsoup.nodes.Element;
@@ -30,6 +34,7 @@ import com.vaadin.event.FieldEvents.FocusEvent;
import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.Registration;
+import com.vaadin.shared.ui.ComponentStateUtil;
import com.vaadin.shared.ui.checkbox.CheckBoxServerRpc;
import com.vaadin.shared.ui.checkbox.CheckBoxState;
import com.vaadin.ui.declarative.DesignAttributeHandler;
@@ -64,6 +69,175 @@ public class CheckBox extends AbstractField<Boolean>
}
};
+ private CheckBoxInputElement checkBoxInputElement = null;
+ private CheckBoxLabelElement checkBoxLabelElement = null;
+
+ /**
+ * The inner input element of the CheckBox.
+ */
+ public static class CheckBoxInputElement implements HasStyleNames {
+
+ private final CheckBox checkBox;
+
+ private CheckBoxInputElement(CheckBox checkBox){
+ this.checkBox = checkBox;
+ }
+
+ @Override
+ // Implementation copied from AbstractComponent
+ public String getStyleName() {
+ // replaced String with StringBuilder
+ StringBuilder s = new StringBuilder();
+ if (ComponentStateUtil.hasStyles(checkBox.getState(false).inputStyles)) {
+ for (final Iterator<String> it = checkBox.getState(false).inputStyles
+ .iterator(); it.hasNext();) {
+ s.append(it.next());
+ if (it.hasNext()) {
+ s.append(" ");
+ }
+ }
+ }
+ return s.toString();
+ }
+
+ @Override
+ // Implementation copied from AbstractComponent
+ public void setStyleName(String style) {
+ if (style == null || style.isEmpty()) {
+ checkBox.getState().inputStyles = null;
+ return;
+ }
+ if (checkBox.getState().inputStyles == null) {
+ checkBox.getState().inputStyles = new ArrayList<>();
+ }
+ List<String> styles = checkBox.getState().inputStyles;
+ styles.clear();
+ StringTokenizer tokenizer = new StringTokenizer(style, " ");
+ while (tokenizer.hasMoreTokens()) {
+ styles.add(tokenizer.nextToken());
+ }
+ }
+
+ @Override
+ // Implementation copied from AbstractComponent
+ public void addStyleName(String style) {
+ if (style == null || style.isEmpty()) {
+ return;
+ }
+ if (checkBox.getState().inputStyles != null && checkBox.getState().inputStyles.contains(style)) {
+ return;
+ }
+ if (style.contains(" ")) {
+ // Split space separated style names and add them one by one.
+ StringTokenizer tokenizer = new StringTokenizer(style, " ");
+ while (tokenizer.hasMoreTokens()) {
+ addStyleName(tokenizer.nextToken());
+ }
+ return;
+ }
+
+ if (checkBox.getState().inputStyles == null) {
+ checkBox.getState().inputStyles = new ArrayList<>();
+ }
+ List<String> styles = checkBox.getState().inputStyles;
+ styles.add(style);
+ }
+
+ @Override
+ // Implementation copied from AbstractComponent
+ public void removeStyleName(String style) {
+ if (ComponentStateUtil.hasStyles(checkBox.getState().inputStyles)) {
+ StringTokenizer tokenizer = new StringTokenizer(style, " ");
+ while (tokenizer.hasMoreTokens()) {
+ checkBox.getState().inputStyles.remove(tokenizer.nextToken());
+ }
+ }
+ }
+ }
+
+ /**
+ * The inner label element of the CheckBox.
+ */
+ public static class CheckBoxLabelElement implements HasStyleNames {
+
+ private final CheckBox checkBox;
+
+ private CheckBoxLabelElement(CheckBox checkBox){
+ this.checkBox = checkBox;
+ }
+
+ @Override
+ // Implementation copied from AbstractComponent
+ public String getStyleName() {
+ // replaced String with StringBuilder
+ StringBuilder s = new StringBuilder();
+ if (ComponentStateUtil.hasStyles(checkBox.getState(false).labelStyles)) {
+ for (final Iterator<String> it = checkBox.getState(false).labelStyles
+ .iterator(); it.hasNext();) {
+ s.append(it.next());
+ if (it.hasNext()) {
+ s.append(" ");
+ }
+ }
+ }
+ return s.toString();
+ }
+
+ @Override
+ // Implementation copied from AbstractComponent
+ public void setStyleName(String style) {
+ if (style == null || style.isEmpty()) {
+ checkBox.getState().labelStyles = null;
+ return;
+ }
+ if (checkBox.getState().labelStyles == null) {
+ checkBox.getState().labelStyles = new ArrayList<>();
+ }
+ List<String> styles = checkBox.getState().labelStyles;
+ styles.clear();
+ StringTokenizer tokenizer = new StringTokenizer(style, " ");
+ while (tokenizer.hasMoreTokens()) {
+ styles.add(tokenizer.nextToken());
+ }
+ }
+
+ @Override
+ // Implementation copied from AbstractComponent
+ public void addStyleName(String style) {
+ if (style == null || style.isEmpty()) {
+ return;
+ }
+ if (checkBox.getState().labelStyles != null && checkBox.getState().labelStyles.contains(style)) {
+ return;
+ }
+ if (style.contains(" ")) {
+ // Split space separated style names and add them one by one.
+ StringTokenizer tokenizer = new StringTokenizer(style, " ");
+ while (tokenizer.hasMoreTokens()) {
+ addStyleName(tokenizer.nextToken());
+ }
+ return;
+ }
+
+ if (checkBox.getState().labelStyles == null) {
+ checkBox.getState().labelStyles = new ArrayList<>();
+ }
+ List<String> styles = checkBox.getState().labelStyles;
+ styles.add(style);
+ }
+
+ @Override
+ // Implementation copied from AbstractComponent
+ public void removeStyleName(String style) {
+ if (ComponentStateUtil.hasStyles(checkBox.getState().labelStyles)) {
+ StringTokenizer tokenizer = new StringTokenizer(style, " ");
+ while (tokenizer.hasMoreTokens()) {
+ checkBox.getState().labelStyles.remove(tokenizer.nextToken());
+ }
+ }
+ }
+ }
+
/**
* Creates a new checkbox.
*/
@@ -211,4 +385,31 @@ public class CheckBox extends AbstractField<Boolean>
def.getValue(), Boolean.class, designContext);
}
+ /**
+ * Returns the {@link CheckBoxInputElement} element to manipulate
+ * the style name of the {@code input} element of the {@link CheckBox}.
+ *
+ * @since
+ * @return the current {@link CheckBoxInputElement}, not {@code null}.
+ */
+ public CheckBoxInputElement getInputElement() {
+ if(checkBoxInputElement == null) {
+ checkBoxInputElement = new CheckBoxInputElement(this);
+ }
+ return checkBoxInputElement;
+ }
+
+ /**
+ * Returns the {@link CheckBoxLabelElement} element to manipulate
+ * the style name of the {@code label} element of the {@link CheckBox}.
+ *
+ * @since
+ * @return the current {@link CheckBoxLabelElement}, not {@code null}.
+ */
+ public CheckBoxLabelElement getLabelElement() {
+ if(checkBoxLabelElement == null) {
+ checkBoxLabelElement = new CheckBoxLabelElement(this);
+ }
+ return checkBoxLabelElement;
+ }
}
diff --git a/server/src/main/java/com/vaadin/ui/HasStyleNames.java b/server/src/main/java/com/vaadin/ui/HasStyleNames.java
new file mode 100644
index 0000000000..953711b1e6
--- /dev/null
+++ b/server/src/main/java/com/vaadin/ui/HasStyleNames.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2000-2018 Vaadin Ltd.
+ *
+ * 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.vaadin.ui;
+
+import java.io.Serializable;
+
+/**
+ * Implemented by components which support style names.
+ *
+ * <p>
+ * Each style name will occur only once as specified and it is not
+ * prefixed with the style name of the component.
+ * </p>
+ *
+ * @since
+ */
+public interface HasStyleNames extends Serializable {
+
+ /**
+ * Gets all user-defined CSS style names of a component. If the component
+ * has multiple style names defined, the return string is a space-separated
+ * list of style names. Built-in style names defined in Vaadin or GWT are
+ * not returned.
+ *
+ * <p>
+ * The style names are returned only in the basic form in which they were
+ * added.
+ * </p>
+ *
+ * @since
+ * @return the style name or a space-separated list of user-defined style
+ * names of the component
+ * @see #setStyleName(String)
+ * @see #addStyleName(String)
+ * @see #removeStyleName(String)
+ */
+ String getStyleName();
+
+ /**
+ * Sets one or more user-defined style names of the component, replacing any
+ * previous user-defined styles. Multiple styles can be specified as a
+ * space-separated list of style names. The style names must be valid CSS
+ * class names.
+ *
+ * <p>
+ * It is normally a good practice to use {@link #addStyleName(String)
+ * addStyleName()} rather than this setter, as different software
+ * abstraction layers can then add their own styles without accidentally
+ * removing those defined in other layers.
+ * </p>
+ *
+ * @since
+ * @param style
+ * the new style or styles of the component as a space-separated
+ * list
+ * @see #getStyleName()
+ * @see #addStyleName(String)
+ * @see #removeStyleName(String)
+ */
+ void setStyleName(String style);
+
+ /**
+ * Adds or removes a style name. Multiple styles can be specified as a
+ * space-separated list of style names.
+ *
+ * If the {@code add} parameter is true, the style name is added to the
+ * component. If the {@code add} parameter is false, the style name is
+ * removed from the component.
+ * <p>
+ * Functionally this is equivalent to using {@link #addStyleName(String)} or
+ * {@link #removeStyleName(String)}
+ *
+ * @since
+ * @param style
+ * the style name to be added or removed
+ * @param add
+ * <code>true</code> to add the given style, <code>false</code>
+ * to remove it
+ * @see #addStyleName(String)
+ * @see #removeStyleName(String)
+ */
+ default void setStyleName(String style, boolean add) {
+ if (add) {
+ addStyleName(style);
+ } else {
+ removeStyleName(style);
+ }
+ }
+
+ /**
+ * Adds one or more style names to this component. Multiple styles can be
+ * specified as a space-separated list of style names. The style name will
+ * be rendered as a HTML class name, which can be used in a CSS definition.
+ *
+ *
+ * @since
+ * @param style
+ * the new style to be added to the component
+ * @see #getStyleName()
+ * @see #setStyleName(String)
+ * @see #removeStyleName(String)
+ */
+ void addStyleName(String style);
+
+ /**
+ * Adds one or more style names to this component by using one or multiple
+ * parameters.
+ *
+ * @since
+ * @param styles
+ * the style name or style names to be added to the component
+ * @see #addStyleName(String)
+ * @see #setStyleName(String)
+ * @see #removeStyleName(String)
+ */
+ default void addStyleNames(String... styles) {
+ for (String style : styles) {
+ addStyleName(style);
+ }
+ }
+
+ /**
+ * Removes one or more style names from component. Multiple styles can be
+ * specified as a space-separated list of style names.
+ *
+ * <p>
+ * The parameter must be a valid CSS style name. Only user-defined style
+ * names added with {@link #addStyleName(String) addStyleName()} or
+ * {@link #setStyleName(String) setStyleName()} can be removed; built-in
+ * style names defined in Vaadin or GWT can not be removed.
+ * </p>
+ *
+ * @since
+ * @param style
+ * the style name or style names to be removed
+ * @see #getStyleName()
+ * @see #setStyleName(String)
+ * @see #addStyleName(String)
+ */
+ void removeStyleName(String style);
+
+ /**
+ * Removes one or more style names from component. Multiple styles can be
+ * specified by using multiple parameters.
+ *
+ * <p>
+ * The parameter must be a valid CSS style name. Only user-defined style
+ * names added with {@link #addStyleName(String) addStyleName()} or
+ * {@link #setStyleName(String) setStyleName()} can be removed; built-in
+ * style names defined in Vaadin or GWT can not be removed.
+ * </p>
+ *
+ * @since
+ * @param styles
+ * the style name or style names to be removed
+ * @see #removeStyleName(String)
+ * @see #setStyleName(String)
+ * @see #addStyleName(String)
+ */
+ default void removeStyleNames(String... styles) {
+ for (String style : styles) {
+ removeStyleName(style);
+ }
+ }
+
+}
diff --git a/server/src/test/java/com/vaadin/ui/CheckBoxTest.java b/server/src/test/java/com/vaadin/ui/CheckBoxTest.java
index 042bc07482..0fbd6fa694 100644
--- a/server/src/test/java/com/vaadin/ui/CheckBoxTest.java
+++ b/server/src/test/java/com/vaadin/ui/CheckBoxTest.java
@@ -1,10 +1,13 @@
package com.vaadin.ui;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.concurrent.atomic.AtomicBoolean;
+import org.junit.Ignore;
import org.junit.Test;
import com.vaadin.server.ServerRpcManager;
@@ -68,4 +71,108 @@ public class CheckBoxTest {
cb.setValue(null);
}
+ @Test
+ public void getComboBoxInput() {
+ CheckBox cb = new CheckBox();
+ assertNotNull("getInputElement should always return a element", cb.getInputElement());
+ assertHasStyleNames(cb.getInputElement());
+ }
+
+ @Test
+ public void getCheckBoxLabel() {
+ CheckBox cb = new CheckBox();
+ assertNotNull("getLabelElement should always return a element", cb.getLabelElement());
+ assertHasStyleNames(cb.getLabelElement());
+ }
+
+ @Test
+ @Ignore("Component#setStyleName(null, false) should not throw a NPE")
+ public void setStyleName_null_false_throws_NPE() {
+ // FIXME? - Currently it throws a NPE like the implementation in Component.java
+ // waiting for other ticket that fixes the behaviour in Component.java before
+ CheckBox cb = new CheckBox();
+ cb.getLabelElement().addStyleName("first");
+ cb.getLabelElement().setStyleName(null, false);
+ assertEquals("Removing a null style should be ignored",
+ "first", cb.getLabelElement().getStyleName());
+ }
+
+ private void assertHasStyleNames(HasStyleNames hasStyleNames) {
+ assertEquals("Given element should not have a default style name",
+ "", hasStyleNames.getStyleName());
+
+ hasStyleNames.addStyleName("first");
+ assertEquals("first", hasStyleNames.getStyleName());
+
+ hasStyleNames.addStyleName("first");
+ assertEquals("Adding two times the same style should be ignored",
+ "first", hasStyleNames.getStyleName());
+
+ hasStyleNames.addStyleName(null);
+ assertEquals("Adding null as style should be ignored",
+ "first", hasStyleNames.getStyleName());
+
+ hasStyleNames.addStyleName("");
+ assertEquals("Adding an empty string as style should be ignored",
+ "first", hasStyleNames.getStyleName());
+
+ hasStyleNames.addStyleName("second");
+ assertEquals("first second", hasStyleNames.getStyleName());
+
+ hasStyleNames.removeStyleName("second");
+ assertEquals("first", hasStyleNames.getStyleName());
+
+ hasStyleNames.addStyleName("second third fourth");
+ assertEquals("first second third fourth", hasStyleNames.getStyleName());
+
+ hasStyleNames.removeStyleName("third fourth");
+ assertEquals("first second", hasStyleNames.getStyleName());
+
+ hasStyleNames.addStyleNames("third", "fourth");
+ assertEquals("first second third fourth", hasStyleNames.getStyleName());
+
+ hasStyleNames.removeStyleNames("second", "fourth");
+ assertEquals("first third", hasStyleNames.getStyleName());
+
+ hasStyleNames.setStyleName(null);
+ assertEquals("Setting null as style should reset them",
+ "", hasStyleNames.getStyleName());
+
+ hasStyleNames.setStyleName("set-style");
+ assertEquals("set-style", hasStyleNames.getStyleName());
+
+ hasStyleNames.setStyleName("");
+ assertEquals("Setting an empty string as style should reset them",
+ "", hasStyleNames.getStyleName());
+
+ hasStyleNames.setStyleName("set-style multiple values");
+ assertEquals("set-style multiple values", hasStyleNames.getStyleName());
+
+ hasStyleNames.setStyleName("set-style", false);
+ assertEquals("multiple values", hasStyleNames.getStyleName());
+
+ hasStyleNames.setStyleName("", false);
+ assertEquals("Removing an empty style should be ignored",
+ "multiple values", hasStyleNames.getStyleName());
+
+ hasStyleNames.setStyleName("", true);
+ assertEquals("Adding an empty style should be ignored",
+ "multiple values", hasStyleNames.getStyleName());
+
+ hasStyleNames.setStyleName(null, true);
+ assertEquals("Adding a null style should be ignored",
+ "multiple values", hasStyleNames.getStyleName());
+
+ hasStyleNames.setStyleName("multiple values", false);
+ assertEquals("Removing all set style names should result in an empty style name",
+ "", hasStyleNames.getStyleName());
+
+ hasStyleNames.setStyleName("set-style", true);
+ assertEquals("set-style", hasStyleNames.getStyleName());
+
+ hasStyleNames.setStyleName("multiple values", true);
+ assertEquals("set-style multiple values", hasStyleNames.getStyleName());
+
+ }
+
}
diff --git a/shared/src/main/java/com/vaadin/shared/ui/ComponentStateUtil.java b/shared/src/main/java/com/vaadin/shared/ui/ComponentStateUtil.java
index 494af9151d..3daa91d436 100644
--- a/shared/src/main/java/com/vaadin/shared/ui/ComponentStateUtil.java
+++ b/shared/src/main/java/com/vaadin/shared/ui/ComponentStateUtil.java
@@ -17,6 +17,7 @@ package com.vaadin.shared.ui;
import java.io.Serializable;
import java.util.HashSet;
+import java.util.List;
import com.vaadin.shared.AbstractComponentState;
import com.vaadin.shared.Registration;
@@ -42,7 +43,11 @@ public final class ComponentStateUtil implements Serializable {
}
public static final boolean hasStyles(AbstractComponentState state) {
- return state.styles != null && !state.styles.isEmpty();
+ return hasStyles(state.styles);
+ }
+
+ public static final boolean hasStyles(List<String> styles) {
+ return styles != null && !styles.isEmpty();
}
public static final boolean isRelativeWidth(AbstractComponentState state) {
diff --git a/shared/src/main/java/com/vaadin/shared/ui/checkbox/CheckBoxState.java b/shared/src/main/java/com/vaadin/shared/ui/checkbox/CheckBoxState.java
index c3e4c29c83..2a35a23726 100644
--- a/shared/src/main/java/com/vaadin/shared/ui/checkbox/CheckBoxState.java
+++ b/shared/src/main/java/com/vaadin/shared/ui/checkbox/CheckBoxState.java
@@ -17,10 +17,14 @@ package com.vaadin.shared.ui.checkbox;
import com.vaadin.shared.AbstractFieldState;
+import java.util.List;
+
public class CheckBoxState extends AbstractFieldState {
{
primaryStyleName = "v-checkbox";
}
public boolean checked = false;
+ public List<String> inputStyles = null;
+ public List<String> labelStyles = null;
}
diff --git a/uitest/src/main/java/com/vaadin/tests/components/checkbox/CheckboxLabelInputElement.java b/uitest/src/main/java/com/vaadin/tests/components/checkbox/CheckboxLabelInputElement.java
new file mode 100644
index 0000000000..248f214d1b
--- /dev/null
+++ b/uitest/src/main/java/com/vaadin/tests/components/checkbox/CheckboxLabelInputElement.java
@@ -0,0 +1,33 @@
+package com.vaadin.tests.components.checkbox;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.ui.CheckBox;
+
+public class CheckboxLabelInputElement extends AbstractTestUIWithLog {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ final CheckBox cb = new CheckBox("Test custom style names for inner elements", true);
+ cb.getInputElement().addStyleName("my-input-class");
+ cb.getLabelElement().addStyleName("my-label-class");
+
+ addComponent(cb);
+
+ addButton("add-style", e -> {
+ cb.getInputElement().addStyleName("later-applied-input-class");
+ cb.getLabelElement().addStyleName("later-applied-label-class");
+ });
+
+ addButton("remove-style", e -> {
+ cb.getInputElement().removeStyleName("my-input-class");
+ cb.getLabelElement().removeStyleName("my-label-class");
+ });
+
+ addButton("remove-style-2", e -> {
+ cb.getInputElement().removeStyleName("later-applied-input-class");
+ cb.getLabelElement().removeStyleName("later-applied-label-class");
+ });
+ }
+
+}
diff --git a/uitest/src/test/java/com/vaadin/tests/components/checkbox/CheckboxLabelInputElementTest.java b/uitest/src/test/java/com/vaadin/tests/components/checkbox/CheckboxLabelInputElementTest.java
new file mode 100644
index 0000000000..16ac7ee1fc
--- /dev/null
+++ b/uitest/src/test/java/com/vaadin/tests/components/checkbox/CheckboxLabelInputElementTest.java
@@ -0,0 +1,48 @@
+package com.vaadin.tests.components.checkbox;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.testbench.elements.CheckBoxElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+public class CheckboxLabelInputElementTest extends MultiBrowserTest {
+
+ @Test
+ public void contextClickCheckboxAndText() {
+ openTestURL();
+ CheckBoxElement checkBoxElement = $(CheckBoxElement.class).first();
+ WebElement labelElem = checkBoxElement.findElement(By.tagName("label"));
+ WebElement inputElem = checkBoxElement.findElement(By.tagName("input"));
+
+ assertEquals("my-label-class", labelElem.getAttribute("class"));
+ assertEquals("my-input-class", inputElem.getAttribute("class"));
+ assertTrue("The Checkbox Widget should not contain the classes that are " +
+ "defined as style names for the input or label.",
+ !checkBoxElement.getAttribute("class").contains("my-label-class") &&
+ !checkBoxElement.getAttribute("class").contains("my-input-class"));
+
+ $(ButtonElement.class).caption("add-style").first().click();
+
+ assertEquals("my-label-class later-applied-label-class", labelElem.getAttribute("class"));
+ assertEquals("my-input-class later-applied-input-class", inputElem.getAttribute("class"));
+ assertTrue("The Checkbox Widget should not contain the classes that are " +
+ "defined as style names for the input or label.",
+ !checkBoxElement.getAttribute("class").contains("later-applied-label-class") &&
+ !checkBoxElement.getAttribute("class").contains("later-applied-input-class"));
+
+ $(ButtonElement.class).caption("remove-style").first().click();
+
+ assertEquals("later-applied-label-class", labelElem.getAttribute("class"));
+ assertEquals("later-applied-input-class", inputElem.getAttribute("class"));
+
+ $(ButtonElement.class).caption("remove-style-2").first().click();
+
+ assertTrue(labelElem.getAttribute("class").isEmpty());
+ assertTrue(inputElem.getAttribute("class").isEmpty());
+ }
+}