001package org.gwtbootstrap3.extras.toggleswitch.client.ui.base; 002 003/* 004 * #%L 005 * GwtBootstrap3 006 * %% 007 * Copyright (C) 2013 - 2016 GwtBootstrap3 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 org.gwtbootstrap3.client.ui.Icon; 024import org.gwtbootstrap3.client.ui.base.HasId; 025import org.gwtbootstrap3.client.ui.base.HasReadOnly; 026import org.gwtbootstrap3.client.ui.base.HasResponsiveness; 027import org.gwtbootstrap3.client.ui.base.HasSize; 028import org.gwtbootstrap3.client.ui.base.helper.StyleHelper; 029import org.gwtbootstrap3.client.ui.base.mixin.AttributeMixin; 030import org.gwtbootstrap3.client.ui.base.mixin.IdMixin; 031import org.gwtbootstrap3.client.ui.constants.DeviceSize; 032import org.gwtbootstrap3.client.ui.constants.IconSize; 033import org.gwtbootstrap3.client.ui.constants.IconType; 034import org.gwtbootstrap3.extras.toggleswitch.client.ui.base.constants.ColorType; 035import org.gwtbootstrap3.extras.toggleswitch.client.ui.base.constants.SizeType; 036 037import com.google.gwt.dom.client.Element; 038import com.google.gwt.dom.client.InputElement; 039import com.google.gwt.editor.client.IsEditor; 040import com.google.gwt.editor.client.LeafValueEditor; 041import com.google.gwt.editor.client.adapters.TakesValueEditor; 042import com.google.gwt.event.logical.shared.HasValueChangeHandlers; 043import com.google.gwt.event.logical.shared.ValueChangeEvent; 044import com.google.gwt.event.logical.shared.ValueChangeHandler; 045import com.google.gwt.event.shared.HandlerRegistration; 046import com.google.gwt.user.client.ui.HasEnabled; 047import com.google.gwt.user.client.ui.HasName; 048import com.google.gwt.user.client.ui.HasValue; 049import com.google.gwt.user.client.ui.HasVisibility; 050import com.google.gwt.user.client.ui.Widget; 051 052/** 053 * Original source from http://www.bootstrap-switch.org/ 054 * 055 * @author Grant Slender 056 * @author Steven Jardine 057 */ 058public class ToggleSwitchBase extends Widget implements HasSize<SizeType>, HasValue<Boolean>, HasValueChangeHandlers<Boolean>, 059 HasEnabled, HasVisibility, HasId, HasName, HasReadOnly, HasResponsiveness, IsEditor<LeafValueEditor<Boolean>> { 060 061 private final InputElement element; 062 private SizeType size = SizeType.REGULAR; 063 private ColorType onColor = ColorType.DEFAULT; 064 private ColorType offColor = ColorType.PRIMARY; 065 private final IdMixin<ToggleSwitchBase> idMixin = new IdMixin<ToggleSwitchBase>(this); 066 private final AttributeMixin<ToggleSwitchBase> attributeMixin = new AttributeMixin<ToggleSwitchBase>(this); 067 private LeafValueEditor<Boolean> editor; 068 069 protected ToggleSwitchBase(InputElement element) { 070 this.element = element; 071 setElement(element); 072 } 073 074 @Override 075 protected void onLoad() { 076 super.onLoad(); 077 switchInit(getElement()); 078 } 079 080 @Override 081 protected void onUnload() { 082 super.onUnload(); 083 switchDestroy(getElement()); 084 } 085 086 @Override 087 public void setVisibleOn(final DeviceSize deviceSize) { 088 StyleHelper.setVisibleOn(this, deviceSize); 089 } 090 091 @Override 092 public void setHiddenOn(final DeviceSize deviceSize) { 093 StyleHelper.setHiddenOn(this, deviceSize); 094 } 095 096 @Override 097 public void setId(final String id) { 098 idMixin.setId(id); 099 } 100 101 @Override 102 public String getId() { 103 return idMixin.getId(); 104 } 105 106 @Override 107 public void setName(String name) { 108 element.setName(name); 109 } 110 111 @Override 112 public String getName() { 113 return element.getName(); 114 } 115 116 @Override 117 public boolean isEnabled() { 118 return !getBooleanAttribute(Option.DISABLED); 119 } 120 121 @Override 122 public void setEnabled(final boolean enabled) { 123 updateSwitch(Option.DISABLED, !enabled); 124 } 125 126 @Override 127 public SizeType getSize() { 128 return size; 129 } 130 131 @Override 132 public void setSize(final SizeType size) { 133 this.size = size; 134 updateSwitch(Option.SIZE, size.getType()); 135 } 136 137 public ColorType getOnColor() { 138 return onColor; 139 } 140 141 public void setOnColor(final ColorType onColor) { 142 this.onColor = onColor; 143 updateSwitch(Option.ON_COLOR, onColor.getType()); 144 } 145 146 public ColorType getOffColor() { 147 return offColor; 148 } 149 150 public void setOffColor(final ColorType offColor) { 151 this.offColor = offColor; 152 updateSwitch(Option.OFF_COLOR, offColor.getType()); 153 } 154 155 public boolean isAnimate() { 156 return getBooleanAttribute(Option.ANIMATE); 157 } 158 159 public void setAnimate(final boolean animate) { 160 updateSwitch(Option.ANIMATE, animate); 161 } 162 163 public String getOnText() { 164 return getStringAttribute(Option.ON_TEXT); 165 } 166 167 public void setOnText(final String onText) { 168 updateSwitch(Option.ON_TEXT, onText); 169 } 170 171 public void setOnIcon(final IconType iconType) { 172 String text = createIconHtml(iconType); 173 setOnText(text); 174 } 175 176 public String getOffText() { 177 return getStringAttribute(Option.OFF_TEXT); 178 } 179 180 public void setOffText(final String offText) { 181 updateSwitch(Option.OFF_TEXT, offText); 182 } 183 184 public void setOffIcon(final IconType iconType) { 185 String text = createIconHtml(iconType); 186 setOffText(text); 187 } 188 189 public String getLabelText() { 190 return getStringAttribute(Option.LABEL_TEXT); 191 } 192 193 public void setLabelText(final String labelText) { 194 updateSwitch(Option.LABEL_TEXT, labelText); 195 } 196 197 @Override 198 public HandlerRegistration addValueChangeHandler(final ValueChangeHandler<Boolean> handler) { 199 return addHandler(handler, ValueChangeEvent.getType()); 200 } 201 202 @Override 203 public Boolean getValue() { 204 if (isAttached()) { 205 return switchState(getElement()); 206 } 207 return element.isChecked(); 208 } 209 210 @Override 211 public void setValue(final Boolean value) { 212 setValue(value, false); 213 } 214 215 @Override 216 public void setValue(final Boolean value, final boolean fireEvents) { 217 Boolean oldValue = getValue(); 218 if (isAttached()) { 219 switchState(getElement(), value, true); 220 } else { 221 element.setChecked(value); 222 } 223 if (fireEvents) { 224 ValueChangeEvent.fireIfNotEqual(ToggleSwitchBase.this, oldValue, value); 225 } 226 } 227 228 public void onChange(final boolean value) { 229 ValueChangeEvent.fire(this, value); 230 } 231 232 @Override 233 public LeafValueEditor<Boolean> asEditor() { 234 if (editor == null) { 235 editor = TakesValueEditor.of(this); 236 } 237 return editor; 238 } 239 240 @Override 241 public boolean isReadOnly() { 242 return getBooleanAttribute(Option.READONLY); 243 } 244 245 @Override 246 public void setReadOnly(boolean readOnly) { 247 updateSwitch(Option.READONLY, readOnly); 248 } 249 250 public boolean isIndeterminate() { 251 return getBooleanAttribute(Option.INDETERMINATE); 252 } 253 254 /** 255 * Indeterminate state. 256 */ 257 public void setIndeterminate(boolean indeterminate) { 258 updateSwitch(Option.INDETERMINATE, indeterminate); 259 } 260 261 public boolean isInverse() { 262 return getBooleanAttribute(Option.INVERSE); 263 } 264 265 /** 266 * Inverse switch direction. 267 */ 268 public void setInverse(boolean inverse) { 269 updateSwitch(Option.INVERSE, inverse); 270 } 271 272 public boolean isRadioAllOff() { 273 return getBooleanAttribute(Option.RADIO_ALL_OFF); 274 } 275 276 /** 277 * Allow this radio button to be unchecked by the user. 278 */ 279 public void setRadioAllOff(boolean radioAllOff) { 280 updateSwitch(Option.RADIO_ALL_OFF, radioAllOff); 281 } 282 283 /** 284 * Sets the handle's width. 285 * @param labelWidth - set to "auto" (default) for automatic sizing, integer otherwise 286 */ 287 public void setHandleWidth(String handleWidth) { 288 updateSwitch(Option.HANDLE_WIDTH, handleWidth); 289 } 290 291 /** 292 * Sets the label's width (the space between handles). 293 * @param labelWidth - set to "auto" (default) for automatic sizing, integer otherwise 294 */ 295 public void setLabelWidth(String labelWidth) { 296 updateSwitch(Option.LABEL_WIDTH, labelWidth); 297 } 298 299 @Override 300 public void setVisible(boolean visible) { 301 if (isAttached()) { 302 setVisible(getElement().getParentElement().getParentElement(), visible); 303 } else { 304 super.setVisible(visible); 305 } 306 } 307 308 @Override 309 public boolean isVisible() { 310 if (isAttached()) { 311 return isVisible(getElement().getParentElement().getParentElement()); 312 } 313 return super.isVisible(); 314 } 315 316 private String createIconHtml(IconType iconType) { 317 // Fix incorrect handle width when using icons 318 setHandleWidth("30"); 319 final Icon icon = new Icon(iconType); 320 icon.setSize(IconSize.LARGE); 321 return icon.getElement().getString(); 322 } 323 324 private void updateSwitch(Option option, String value) { 325 if (isAttached()) { 326 switchCmd(getElement(), option.getCommand(), value); 327 } else { 328 attributeMixin.setAttribute(option.getAttribute(), value); 329 } 330 } 331 332 private void updateSwitch(Option option, boolean value) { 333 if (isAttached()) { 334 switchCmd(getElement(), option.getCommand(), value); 335 } else { 336 attributeMixin.setAttribute(option.getAttribute(), Boolean.toString(value)); 337 } 338 } 339 340 private String getStringAttribute(Option option) { 341 if (isAttached()) { 342 return getCommandStringValue(getElement(), option.getCommand()); 343 } else { 344 return attributeMixin.getAttribute(option.getAttribute()); 345 } 346 } 347 348 private boolean getBooleanAttribute(Option option) { 349 if (isAttached()) { 350 return getCommandBooleanValue(getElement(), option.getCommand()); 351 } else { 352 String value = attributeMixin.getAttribute(option.getAttribute()); 353 if (value != null && !value.isEmpty()) { 354 return Boolean.valueOf(value); 355 } else { 356 return false; 357 } 358 } 359 } 360 361 private native void switchInit(Element e) /*-{ 362 $wnd.jQuery(e).bootstrapSwitch(); 363 364 var me = this; 365 $wnd.jQuery(e).on('switchChange.bootstrapSwitch', function (em, state) { 366 me.@org.gwtbootstrap3.extras.toggleswitch.client.ui.base.ToggleSwitchBase::onChange(Z)(state); 367 }); 368 }-*/; 369 370 private native void switchDestroy(Element e) /*-{ 371 $wnd.jQuery(e).off('switchChange.bootstrapSwitch'); 372 $wnd.jQuery(e).bootstrapSwitch('destroy'); 373 }-*/; 374 375 private native void switchCmd(Element e, String cmd, String value) /*-{ 376 $wnd.jQuery(e).bootstrapSwitch(cmd, value); 377 }-*/; 378 379 private native void switchCmd(Element e, String cmd, boolean value) /*-{ 380 $wnd.jQuery(e).bootstrapSwitch(cmd, value); 381 }-*/; 382 383 private native String getCommandStringValue(Element e, String cmd) /*-{ 384 return $wnd.jQuery(e).bootstrapSwitch(cmd); 385 }-*/; 386 387 private native boolean getCommandBooleanValue(Element e, String cmd) /*-{ 388 return $wnd.jQuery(e).bootstrapSwitch(cmd); 389 }-*/; 390 391 private native void switchState(Element e, boolean value, boolean skip) /*-{ 392 $wnd.jQuery(e).bootstrapSwitch('state', value, skip); 393 }-*/; 394 395 private native boolean switchState(Element e) /*-{ 396 return $wnd.jQuery(e).bootstrapSwitch('state'); 397 }-*/; 398}