001/* 002 * #%L 003 * GwtMaterial 004 * %% 005 * Copyright (C) 2015 - 2017 GwtMaterialDesign 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package gwt.material.design.client.ui; 021 022import com.google.gwt.dom.client.Document; 023import com.google.gwt.dom.client.Style.Unit; 024import com.google.gwt.event.logical.shared.ValueChangeEvent; 025import com.google.gwt.event.logical.shared.ValueChangeHandler; 026import com.google.gwt.event.shared.HandlerRegistration; 027import com.google.gwt.user.client.ui.HasValue; 028import gwt.material.design.client.base.AbstractValueWidget; 029import gwt.material.design.client.base.mixin.ErrorMixin; 030import gwt.material.design.client.constants.CssName; 031import gwt.material.design.client.constants.InputType; 032import gwt.material.design.client.ui.html.Label; 033import gwt.material.design.client.ui.html.Span; 034 035//@formatter:off 036 037/** 038 * Material Switch or other call it toggle - used for an alternative for checkbox 039 * <p> 040 * <h3>UiBinder Usage:</h3> 041 * <pre> 042 * {@code <m:MaterialSwitch value="true"/> 043 * <m:MaterialSwitch value="true" disabled="true"/> 044 * } 045 * </pre> 046 * 047 * @author kevzlou7979 048 * @see <a href="http://gwtmaterialdesign.github.io/gwt-material-demo/#switches">Material Switch</a> 049 * @see <a href="https://material.io/guidelines/components/selection-controls.html#selection-controls-switch">Material Design Specification</a> 050 */ 051//@formatter:on 052public class MaterialSwitch extends AbstractValueWidget<Boolean> implements HasValue<Boolean> { 053 054 private MaterialInput input = new MaterialInput(); 055 private MaterialLabel errorLabel = new MaterialLabel(); 056 private Label label = new Label(); 057 private Span span = new Span(); 058 private Span onLabel = new Span(); 059 private Span offLabel = new Span(); 060 061 private ErrorMixin<AbstractValueWidget, MaterialLabel> errorMixin; 062 063 /** 064 * Creates a switch element 065 */ 066 public MaterialSwitch() { 067 super(Document.get().createDivElement(), CssName.SWITCH); 068 span.setStyleName(CssName.LEVER); 069 input.setType(InputType.CHECKBOX); 070 } 071 072 public MaterialSwitch(String onLabel, String offLabel) { 073 this(); 074 setOnLabel(onLabel); 075 setOffLabel(offLabel); 076 } 077 078 public MaterialSwitch(String onLabel, String offLabel, Boolean value) { 079 this(onLabel, offLabel); 080 setValue(value); 081 } 082 083 /** 084 * Creates a material switch with default value. 085 */ 086 public MaterialSwitch(boolean value) { 087 this(); 088 setValue(value); 089 } 090 091 @Override 092 protected void onLoad() { 093 super.onLoad(); 094 095 label.add(offLabel); 096 label.add(input); 097 label.add(span); 098 add(label); 099 add(errorLabel); 100 errorLabel.getElement().getStyle().setMarginTop(16, Unit.PX); 101 label.add(onLabel); 102 103 // Register click handler here in order to have it at first position 104 // and therefore it will deal with clicks as first and setup the value 105 // right before others get notified. 106 registerHandler(addClickHandler(event -> { 107 event.preventDefault(); 108 event.stopPropagation(); 109 })); 110 111 registerHandler(addClickHandler(event -> setValue(!getValue(), true))); 112 } 113 114 @Override 115 public void setEnabled(boolean enabled) { 116 super.setEnabled(enabled); 117 span.setEnabled(enabled); 118 input.setEnabled(enabled); 119 } 120 121 /** 122 * Set the value of switch component. 123 */ 124 @Override 125 public void setValue(Boolean value, boolean fireEvents) { 126 boolean oldValue = getValue(); 127 if (value) { 128 input.getElement().setAttribute("checked", "true"); 129 } else { 130 input.getElement().removeAttribute("checked"); 131 } 132 133 if (fireEvents && oldValue != value) { 134 ValueChangeEvent.fire(this, getValue()); 135 } 136 } 137 138 @Override 139 public void setValue(Boolean value) { 140 setValue(value, false); 141 } 142 143 /** 144 * Gets the value of switch component. 145 */ 146 @Override 147 public Boolean getValue() { 148 return input.getElement().hasAttribute("checked"); 149 } 150 151 /** 152 * @return the input 153 */ 154 public MaterialInput getInput() { 155 return input; 156 } 157 158 /** 159 * @param input the input to set 160 */ 161 public void setInput(MaterialInput input) { 162 this.input = input; 163 } 164 165 /** 166 * @return the span 167 */ 168 public Span getSpan() { 169 return span; 170 } 171 172 /** 173 * @param span the span to set 174 */ 175 public void setSpan(Span span) { 176 this.span = span; 177 } 178 179 /** 180 * @return the label 181 */ 182 public Label getLabel() { 183 return label; 184 } 185 186 /** 187 * @param label the label to set 188 */ 189 @Deprecated 190 public void setLabel(Label label) { 191 this.label = label; 192 } 193 194 @Override 195 public void setError(String error) { 196 getErrorMixin().setError(error); 197 } 198 199 @Override 200 public void setSuccess(String success) { 201 getErrorMixin().setSuccess(success); 202 } 203 204 @Override 205 public void setHelperText(String helperText) { 206 getErrorMixin().setHelperText(helperText); 207 } 208 209 @Override 210 public void clearErrorOrSuccess() { 211 getErrorMixin().clearErrorOrSuccess(); 212 } 213 214 /** 215 * Set the On State Label of the switch component 216 */ 217 public void setOnLabel(String label) { 218 onLabel.setText(label); 219 } 220 221 /** 222 * Set the Off State Label of the switch component 223 */ 224 public void setOffLabel(String label) { 225 offLabel.setText(label); 226 } 227 228 public MaterialLabel getErrorLabel() { 229 return errorLabel; 230 } 231 232 public Span getOnLabel() { 233 return onLabel; 234 } 235 236 public Span getOffLabel() { 237 return offLabel; 238 } 239 240 @Override 241 public HandlerRegistration addValueChangeHandler(final ValueChangeHandler<Boolean> handler) { 242 return addHandler(handler, ValueChangeEvent.getType()); 243 } 244 245 @Override 246 protected ErrorMixin<AbstractValueWidget, MaterialLabel> getErrorMixin() { 247 if (errorMixin == null) { 248 errorMixin = new ErrorMixin<>(this, errorLabel, null); 249 } 250 return errorMixin; 251 } 252}