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.Element; 024import com.google.gwt.event.dom.client.ChangeEvent; 025import com.google.gwt.event.dom.client.ChangeHandler; 026import com.google.gwt.event.dom.client.HasChangeHandlers; 027import com.google.gwt.event.shared.HandlerRegistration; 028import gwt.material.design.client.base.AbstractValueWidget; 029import gwt.material.design.client.base.HasError; 030import gwt.material.design.client.base.mixin.ErrorMixin; 031import gwt.material.design.client.constants.CssName; 032import gwt.material.design.client.constants.InputType; 033import gwt.material.design.client.ui.html.Paragraph; 034import gwt.material.design.client.ui.html.Span; 035 036import static gwt.material.design.jquery.client.api.JQuery.$; 037 038//@formatter:off 039 040/** 041 * Material Range - a slider that initialize the minimum and maximum values. 042 * <p> 043 * <h3>UiBinder Usage:</h3> 044 * <pre> 045 * {@code <m:MaterialRange value="2" min="20" max="50" value="25"/>} 046 * </pre> 047 * 048 * @author kevzlou7979 049 * @author Ben Dol 050 * @see <a href="http://gwtmaterialdesign.github.io/gwt-material-demo/#range">Material Range</a> 051 * @see <a href="https://material.io/guidelines/components/sliders.html">Material Design Specification</a> 052 */ 053//@formatter:on 054public class MaterialRange extends AbstractValueWidget<Integer> implements HasChangeHandlers, HasError { 055 056 private Paragraph paragraph = new Paragraph(); 057 private MaterialInput rangeInputElement = new MaterialInput(); 058 private Span thumb = new Span(); 059 private Span value = new Span(); 060 private static String VALUE = "value"; 061 private static String MAX = "max"; 062 private static String MIN = "min"; 063 private MaterialLabel errorLabel = new MaterialLabel(); 064 private ErrorMixin<AbstractValueWidget, MaterialLabel> errorMixin; 065 066 /** 067 * Creates a range 068 */ 069 public MaterialRange() { 070 super(Document.get().createFormElement()); 071 } 072 073 /** 074 * Creates a range with specified values 075 * 076 * @param min - start min value 077 * @param max - end max value 078 * @param value - default range value 079 */ 080 public MaterialRange(Integer min, Integer max, Integer value) { 081 this(); 082 setMin(min); 083 setMax(max); 084 setValue(value); 085 } 086 087 public void reset() { 088 setValue(getMin()); 089 clearErrorOrSuccess(); 090 } 091 092 @Override 093 protected void onLoad() { 094 super.onLoad(); 095 096 getElement().setAttribute("action", "#"); 097 errorLabel.setVisible(false); 098 paragraph.setStyleName(CssName.RANGE_FIELD); 099 rangeInputElement.setType(InputType.RANGE); 100 paragraph.add(rangeInputElement); 101 thumb.getElement().setClassName(CssName.THUMB); 102 value.getElement().setClassName(CssName.VALUE); 103 thumb.add(value); 104 paragraph.add(thumb); 105 add(paragraph); 106 add(errorLabel); 107 108 registerHandler(addChangeHandler(changeEvent -> setValue(getValue(), true))); 109 } 110 111 /** 112 * Retrieve the Integer value from the given Attribute of the range element 113 * 114 * @param attribute The name of the attribute on the range element 115 * @return The Integer vaulue read from the given attribute or null 116 */ 117 protected Integer getIntFromRangeElement(String attribute) { 118 Element ele = $(rangeInputElement).asElement(); 119 if (ele != null) { 120 return ele.getPropertyInt(attribute); 121 } 122 return null; 123 } 124 125 /** 126 * Set the given Integer value to the attribute of the range element. 127 */ 128 protected void setIntToRangeElement(String attribute, Integer val) { 129 Element ele = $(rangeInputElement).asElement(); 130 if (ele != null) { 131 ele.setPropertyInt(attribute, val); 132 } 133 } 134 135 /** 136 * Read the current value 137 * 138 * @return The Integer value or null 139 */ 140 @Override 141 public Integer getValue() { 142 return getIntFromRangeElement(VALUE); 143 } 144 145 @Override 146 public void setValue(Integer value, boolean fireEvents) { 147 if (value == null) { 148 throw new IllegalArgumentException("Value must not be null"); 149 } 150 if (value < getMin()) { 151 throw new IllegalArgumentException("Value must not be less than the minimum range value."); 152 } 153 if (value > getMax()) { 154 throw new IllegalArgumentException("Value must not be greater than the maximum range value"); 155 } 156 setIntToRangeElement(VALUE, value); 157 158 super.setValue(value, fireEvents); 159 } 160 161 /** 162 * Read the min value 163 * 164 * @return The Integer or null 165 */ 166 public Integer getMin() { 167 return getIntFromRangeElement(MIN); 168 } 169 170 /** 171 * Write the current min value 172 * 173 * @param min value must be < max 174 */ 175 public void setMin(Integer min) { 176 setIntToRangeElement(MIN, min); 177 } 178 179 /** 180 * Read the max value 181 * 182 * @return The Integer or null 183 */ 184 public Integer getMax() { 185 return getIntFromRangeElement(MAX); 186 } 187 188 /** 189 * Write the current max value 190 * 191 * @param max value must be > min 192 */ 193 public void setMax(Integer max) { 194 setIntToRangeElement(MAX, max); 195 } 196 197 @Override 198 public void setError(String error) { 199 getErrorMixin().setError(error); 200 } 201 202 @Override 203 public void setSuccess(String success) { 204 getErrorMixin().setSuccess(success); 205 } 206 207 @Override 208 public void setHelperText(String helperText) { 209 getErrorMixin().setHelperText(helperText); 210 } 211 212 @Override 213 public void clearErrorOrSuccess() { 214 getErrorMixin().clearErrorOrSuccess(); 215 } 216 217 public MaterialLabel getErrorLabel() { 218 return errorLabel; 219 } 220 221 public MaterialInput getRangeInputElement() { 222 return rangeInputElement; 223 } 224 225 public Paragraph getParagraph() { 226 return paragraph; 227 } 228 229 public Span getThumb() { 230 return thumb; 231 } 232 233 /** 234 * Register the ChangeHandler to become notified if the user changes the slider. 235 * The Handler is called when the user releases the mouse only at the end of the slide 236 * operation. 237 */ 238 @Override 239 public HandlerRegistration addChangeHandler(final ChangeHandler handler) { 240 return getRangeInputElement().addDomHandler(handler, ChangeEvent.getType()); 241 } 242 243 @Override 244 public ErrorMixin<AbstractValueWidget, MaterialLabel> getErrorMixin() { 245 if (errorMixin == null) { 246 errorMixin = new ErrorMixin<>(this, errorLabel, null); 247 } 248 return errorMixin; 249 } 250}