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