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.core.client.Scheduler; 023import com.google.gwt.dom.client.Document; 024import com.google.gwt.dom.client.Style; 025import com.google.gwt.editor.client.Editor; 026import com.google.gwt.editor.client.IsEditor; 027import com.google.gwt.editor.ui.client.adapters.ValueBoxEditor; 028import com.google.gwt.event.dom.client.*; 029import com.google.gwt.event.logical.shared.ValueChangeHandler; 030import com.google.gwt.event.shared.HandlerRegistration; 031import com.google.gwt.i18n.client.AutoDirectionHandler; 032import com.google.gwt.i18n.shared.DirectionEstimator; 033import com.google.gwt.i18n.shared.HasDirectionEstimator; 034import com.google.gwt.uibinder.client.UiChild; 035import com.google.gwt.user.client.DOM; 036import com.google.gwt.user.client.ui.HasName; 037import com.google.gwt.user.client.ui.HasText; 038import com.google.gwt.user.client.ui.ValueBoxBase; 039import com.google.gwt.user.client.ui.ValueBoxBase.TextAlignment; 040import gwt.material.design.client.base.*; 041import gwt.material.design.client.base.mixin.*; 042import gwt.material.design.client.constants.*; 043import gwt.material.design.client.events.DragEndEvent; 044import gwt.material.design.client.events.DragEnterEvent; 045import gwt.material.design.client.events.DragLeaveEvent; 046import gwt.material.design.client.events.*; 047import gwt.material.design.client.events.DragOverEvent; 048import gwt.material.design.client.events.DragStartEvent; 049import gwt.material.design.client.events.DropEvent; 050import gwt.material.design.client.ui.html.Label; 051 052//@formatter:off 053 054/** 055 * MaterialValueBox is an input field that accepts any text based string from user. 056 * <h3>UiBinder Usage:</h3> 057 * <pre> 058 * {@code <m:MaterialTextBox placeholder="First Name" />} 059 * </pre> 060 * 061 * @author kevzlou7979 062 * @author Ben Dol 063 * @author paulux84 064 * @see <a href="http://gwtmaterialdesign.github.io/gwt-material-demo/#textfields">Material TextBox</a> 065 * @see <a href="https://material.io/guidelines/components/text-fields.html#">Material Design Specification</a> 066 */ 067//@formatter:on 068public class MaterialValueBox<T> extends AbstractValueWidget<T> implements HasChangeHandlers, HasName, 069 HasDirectionEstimator, HasText, AutoDirectionHandler.Target, IsEditor<ValueBoxEditor<T>>, HasIcon, 070 HasInputType, HasPlaceholder, HasCounter, HasReadOnly, HasActive { 071 072 private InputType type = InputType.TEXT; 073 private ValueBoxEditor<T> editor; 074 private Label label = new Label(); 075 private MaterialLabel errorLabel = new MaterialLabel(); 076 private MaterialIcon icon = new MaterialIcon(); 077 078 @Editor.Ignore 079 protected ValueBoxBase<T> valueBoxBase; 080 081 private CounterMixin<MaterialValueBox<T>> counterMixin; 082 private ErrorMixin<AbstractValueWidget, MaterialLabel> errorMixin; 083 private ReadOnlyMixin<MaterialValueBox, ValueBoxBase> readOnlyMixin; 084 private FocusableMixin<MaterialWidget> focusableMixin; 085 private ActiveMixin<MaterialValueBox> activeMixin; 086 087 public class MaterialValueBoxEditor<V> extends ValueBoxEditor<V> { 088 private final ValueBoxBase<V> valueBoxBase; 089 090 private MaterialValueBoxEditor(ValueBoxBase<V> valueBoxBase) { 091 super(valueBoxBase); 092 this.valueBoxBase = valueBoxBase; 093 } 094 095 @Override 096 public void setValue(V value) { 097 super.setValue(value); 098 if (valueBoxBase.getText() != null && !valueBoxBase.getText().isEmpty()) { 099 label.addStyleName(CssName.ACTIVE); 100 } else { 101 label.removeStyleName(CssName.ACTIVE); 102 } 103 } 104 } 105 106 protected MaterialValueBox() { 107 super(Document.get().createDivElement(), CssName.INPUT_FIELD); 108 } 109 110 public MaterialValueBox(ValueBoxBase<T> tValueBox) { 111 this(); 112 setup(tValueBox); 113 } 114 115 public void setup(ValueBoxBase<T> tValueBox) { 116 valueBoxBase = tValueBox; 117 add(valueBoxBase); 118 } 119 120 @Deprecated 121 @UiChild(limit = 1) 122 public void addValueBox(ValueBoxBase<T> widget) { 123 setup(widget); 124 } 125 126 @Override 127 protected void onLoad() { 128 super.onLoad(); 129 130 String id = DOM.createUniqueId(); 131 valueBoxBase.getElement().setId(id); 132 label.getElement().setAttribute("for", id); 133 134 // Make valueBoxBase the primary focus target 135 getFocusableMixin().setUiObject(new MaterialWidget(valueBoxBase.getElement())); 136 } 137 138 /** 139 * Resets the text box by removing its content and resetting visual state. 140 */ 141 public void clear() { 142 valueBoxBase.setText(""); 143 clearErrorOrSuccess(); 144 label.removeStyleName(CssName.ACTIVE); 145 } 146 147 public void removeErrorModifiers() { 148 valueBoxBase.getElement().removeClassName(CssName.VALID); 149 valueBoxBase.getElement().removeClassName(CssName.INVALID); 150 } 151 152 @Override 153 public String getText() { 154 return valueBoxBase.getText(); 155 } 156 157 @Override 158 public void setText(String text) { 159 valueBoxBase.setText(text); 160 161 if (text != null && !text.isEmpty()) { 162 label.addStyleName(CssName.ACTIVE); 163 } 164 } 165 166 /** 167 * Set the label of this field. 168 * <p> 169 * This will be displayed above the field when values are 170 * assigned to the box, otherwise the value is displayed 171 * inside the box. 172 * </p> 173 */ 174 public void setLabel(String label) { 175 this.label.setText(label); 176 177 if(!getPlaceholder().isEmpty()) { 178 this.label.setStyleName(CssName.ACTIVE); 179 } 180 } 181 182 @Override 183 public String getPlaceholder() { 184 return valueBoxBase.getElement().getAttribute("placeholder"); 185 } 186 187 @Override 188 public void setPlaceholder(String placeholder) { 189 valueBoxBase.getElement().setAttribute("placeholder", placeholder); 190 191 if(!label.getText().isEmpty()) { 192 label.setStyleName(CssName.ACTIVE); 193 } 194 } 195 196 @Override 197 public InputType getType() { 198 return type; 199 } 200 201 @Override 202 public void setType(InputType type) { 203 this.type = type; 204 valueBoxBase.getElement().setAttribute("type", type.getType()); 205 if (getType() != InputType.SEARCH) { 206 add(label); 207 errorLabel.setVisible(false); 208 add(errorLabel); 209 } 210 } 211 212 @Override 213 public T getValue() { 214 return valueBoxBase.getValue(); 215 } 216 217 @Override 218 public void setValue(T value, boolean fireEvents) { 219 valueBoxBase.setValue(value, fireEvents); 220 221 if (value != null && !value.toString().isEmpty()) { 222 label.addStyleName(CssName.ACTIVE); 223 } 224 } 225 226 @Override 227 public void setDirection(Direction direction) { 228 valueBoxBase.setDirection(direction); 229 } 230 231 @Override 232 public Direction getDirection() { 233 return valueBoxBase.getDirection(); 234 } 235 236 @Override 237 public ValueBoxEditor<T> asEditor() { 238 if (editor == null) { 239 editor = new MaterialValueBoxEditor<>(valueBoxBase); 240 } 241 return editor; 242 } 243 244 @Override 245 public DirectionEstimator getDirectionEstimator() { 246 return valueBoxBase.getDirectionEstimator(); 247 } 248 249 @Override 250 public void setDirectionEstimator(boolean enabled) { 251 valueBoxBase.setDirectionEstimator(enabled); 252 } 253 254 @Override 255 public void setDirectionEstimator(DirectionEstimator directionEstimator) { 256 valueBoxBase.setDirectionEstimator(directionEstimator); 257 } 258 259 @Override 260 public void setName(String name) { 261 valueBoxBase.setName(name); 262 } 263 264 @Override 265 public String getName() { 266 return valueBoxBase.getName(); 267 } 268 269 @Override 270 public void setError(String error) { 271 super.setError(error); 272 removeErrorModifiers(); 273 valueBoxBase.getElement().addClassName(CssName.INVALID); 274 } 275 276 @Override 277 public void setSuccess(String success) { 278 super.setSuccess(success); 279 removeErrorModifiers(); 280 valueBoxBase.getElement().addClassName(CssName.VALID); 281 } 282 283 @Override 284 public void clearErrorOrSuccess() { 285 super.clearErrorOrSuccess(); 286 removeErrorModifiers(); 287 } 288 289 @Override 290 public MaterialIcon getIcon() { 291 return icon; 292 } 293 294 @Override 295 public void setIconType(IconType iconType) { 296 icon.setIconType(iconType); 297 icon.setIconPrefix(true); 298 errorLabel.setPaddingLeft(44); 299 insert(icon, 0); 300 } 301 302 @Override 303 public void setIconPosition(IconPosition position) { 304 icon.setIconPosition(position); 305 } 306 307 @Override 308 public void setIconSize(IconSize size) { 309 icon.setIconSize(size); 310 } 311 312 @Override 313 public void setIconFontSize(double size, Style.Unit unit) { 314 icon.setIconFontSize(size, unit); 315 } 316 317 @Override 318 public void setIconColor(Color iconColor) { 319 icon.setIconColor(iconColor); 320 } 321 322 @Override 323 public Color getIconColor() { 324 return icon.getIconColor(); 325 } 326 327 @Override 328 public void setIconPrefix(boolean prefix) { 329 icon.setIconPrefix(prefix); 330 } 331 332 @Override 333 public boolean isIconPrefix() { 334 return icon.isIconPrefix(); 335 } 336 337 @Override 338 public void setLength(int length) { 339 getCounterMixin().setLength(length); 340 } 341 342 @Override 343 public int getLength() { 344 return getCounterMixin().getLength(); 345 } 346 347 @Editor.Ignore 348 public ValueBoxBase<T> asValueBoxBase() { 349 return valueBoxBase; 350 } 351 352 @Override 353 public int getTabIndex() { 354 return valueBoxBase.getTabIndex(); 355 } 356 357 @Override 358 public void setAccessKey(char key) { 359 valueBoxBase.setAccessKey(key); 360 } 361 362 @Override 363 public void setFocus(final boolean focused) { 364 Scheduler.get().scheduleDeferred(() -> { 365 valueBoxBase.setFocus(focused); 366 if (focused) { 367 label.addStyleName(CssName.ACTIVE); 368 } else { 369 updateLabelActiveStyle(); 370 } 371 }); 372 } 373 374 /** 375 * Updates the style of the field label according to the field value if the 376 * field value is empty - null or "" - removes the label 'active' style else 377 * will add the 'active' style to the field label. 378 */ 379 protected void updateLabelActiveStyle() { 380 if (this.valueBoxBase.getText() != null && !this.valueBoxBase.getText().isEmpty()) { 381 label.addStyleName(CssName.ACTIVE); 382 } else { 383 label.removeStyleName(CssName.ACTIVE); 384 } 385 } 386 387 public String getSelectedText() { 388 return valueBoxBase.getSelectedText(); 389 } 390 391 public int getSelectionLength() { 392 return valueBoxBase.getSelectionLength(); 393 } 394 395 public void setSelectionRange(int pos, int length) { 396 valueBoxBase.setSelectionRange(pos, length); 397 } 398 399 @Override 400 public void setActive(boolean active) { 401 getActiveMixin().setActive(active); 402 } 403 404 @Override 405 public boolean isActive() { 406 return getActiveMixin().isActive(); 407 } 408 409 @Override 410 public void setReadOnly(boolean readOnly) { 411 getReadOnlyMixin().setReadOnly(readOnly); 412 } 413 414 @Override 415 public boolean isReadOnly() { 416 return getReadOnlyMixin().isReadOnly(); 417 } 418 419 @Override 420 public void setToggleReadOnly(boolean toggle) { 421 getReadOnlyMixin().setToggleReadOnly(toggle); 422 } 423 424 @Override 425 public boolean isToggleReadOnly() { 426 return getReadOnlyMixin().isToggleReadOnly(); 427 } 428 429 public void setCursorPos(int pos) { 430 valueBoxBase.setCursorPos(pos); 431 } 432 433 public void setAlignment(TextAlignment align) { 434 valueBoxBase.setAlignment(align); 435 } 436 437 @Override 438 public void setTabIndex(int tabIndex) { 439 valueBoxBase.setTabIndex(tabIndex); 440 } 441 442 @Override 443 public void setEnabled(boolean enabled) { 444 super.setEnabled(enabled); 445 valueBoxBase.setEnabled(enabled); 446 } 447 448 @Override 449 public boolean isEnabled() { 450 return valueBoxBase.isEnabled(); 451 } 452 453 @Ignore 454 public ValueBoxBase<T> getValueBoxBase() { 455 return valueBoxBase; 456 } 457 458 public Label getLabel() { 459 return label; 460 } 461 462 public MaterialLabel getErrorLabel() { 463 return errorLabel; 464 } 465 466 @Override 467 public HandlerRegistration addValueChangeHandler(final ValueChangeHandler<T> handler) { 468 return valueBoxBase.addValueChangeHandler(event -> { 469 if (isEnabled()) { 470 handler.onValueChange(event); 471 } 472 }); 473 } 474 475 @Override 476 public HandlerRegistration addDragStartHandler(DragStartEvent.DragStartHandler handler) { 477 return valueBoxBase.addHandler(event -> { 478 if (isEnabled()) { 479 handler.onDragStart(event); 480 } 481 }, DragStartEvent.getType()); 482 } 483 484 @Override 485 public HandlerRegistration addDragMoveHandler(DragMoveEvent.DragMoveHandler handler) { 486 return valueBoxBase.addHandler(event -> { 487 if (isEnabled()) { 488 handler.onDragMove(event); 489 } 490 }, DragMoveEvent.getType()); 491 } 492 493 @Override 494 public HandlerRegistration addDragEndHandler(DragEndEvent.DragEndHandler handler) { 495 return valueBoxBase.addHandler(event -> { 496 if (isEnabled()) { 497 handler.onDragEnd(event); 498 } 499 }, DragEndEvent.getType()); 500 } 501 502 @Override 503 public HandlerRegistration addDropActivateHandler(DropActivateEvent.DropActivateHandler handler) { 504 return valueBoxBase.addHandler(event -> { 505 if (isEnabled()) { 506 handler.onDropActivate(event); 507 } 508 }, DropActivateEvent.getType()); 509 } 510 511 @Override 512 public HandlerRegistration addDragEnterHandler(DragEnterEvent.DragEnterHandler handler) { 513 return valueBoxBase.addHandler(event -> { 514 if (isEnabled()) { 515 handler.onDragEnter(event); 516 } 517 }, DragEnterEvent.getType()); 518 } 519 520 @Override 521 public HandlerRegistration addDragLeaveHandler(DragLeaveEvent.DragLeaveHandler handler) { 522 return valueBoxBase.addHandler(event -> { 523 if (isEnabled()) { 524 handler.onDragLeave(event); 525 } 526 }, DragLeaveEvent.getType()); 527 } 528 529 @Override 530 public HandlerRegistration addDragOverHandler(DragOverEvent.DragOverHandler handler) { 531 return valueBoxBase.addHandler(event -> { 532 if (isEnabled()) { 533 handler.onDragOver(event); 534 } 535 }, DragOverEvent.getType()); 536 } 537 538 @Override 539 public HandlerRegistration addDropDeactivateHandler(DropDeactivateEvent.DropDeactivateHandler handler) { 540 return valueBoxBase.addHandler(event -> { 541 if (isEnabled()) { 542 handler.onDropDeactivate(event); 543 } 544 }, DropDeactivateEvent.getType()); 545 } 546 547 @Override 548 public HandlerRegistration addDropHandler(DropEvent.DropHandler handler) { 549 return valueBoxBase.addHandler(event -> { 550 if (isEnabled()) { 551 handler.onDrop(event); 552 } 553 }, DropEvent.getType()); 554 } 555 556 @Override 557 public HandlerRegistration addKeyUpHandler(final KeyUpHandler handler) { 558 return valueBoxBase.addDomHandler(event -> { 559 if (isEnabled()) { 560 handler.onKeyUp(event); 561 } 562 }, KeyUpEvent.getType()); 563 } 564 565 @Override 566 public HandlerRegistration addChangeHandler(final ChangeHandler handler) { 567 return valueBoxBase.addChangeHandler(event -> { 568 if (isEnabled()) { 569 handler.onChange(event); 570 } 571 }); 572 } 573 574 @Override 575 public HandlerRegistration addFocusHandler(final FocusHandler handler) { 576 return valueBoxBase.addFocusHandler(event -> { 577 if (isEnabled()) { 578 handler.onFocus(event); 579 } 580 }); 581 } 582 583 @Override 584 public HandlerRegistration addBlurHandler(final BlurHandler handler) { 585 return valueBoxBase.addBlurHandler(event -> { 586 if (isEnabled()) { 587 handler.onBlur(event); 588 } 589 }); 590 } 591 592 @Override 593 public HandlerRegistration addGestureStartHandler(final GestureStartHandler handler) { 594 return valueBoxBase.addGestureStartHandler(event -> { 595 if (isEnabled()) { 596 handler.onGestureStart(event); 597 } 598 }); 599 } 600 601 @Override 602 public HandlerRegistration addGestureChangeHandler(final GestureChangeHandler handler) { 603 return valueBoxBase.addGestureChangeHandler(event -> { 604 if (isEnabled()) { 605 handler.onGestureChange(event); 606 } 607 }); 608 } 609 610 @Override 611 public HandlerRegistration addGestureEndHandler(final GestureEndHandler handler) { 612 return valueBoxBase.addGestureEndHandler(event -> { 613 if (isEnabled()) { 614 handler.onGestureEnd(event); 615 } 616 }); 617 } 618 619 @Override 620 public HandlerRegistration addKeyDownHandler(final KeyDownHandler handler) { 621 return valueBoxBase.addKeyDownHandler(event -> { 622 if (isEnabled()) { 623 handler.onKeyDown(event); 624 } 625 }); 626 } 627 628 @Override 629 public HandlerRegistration addKeyPressHandler(final KeyPressHandler handler) { 630 return valueBoxBase.addKeyPressHandler(event -> { 631 if (isEnabled()) { 632 handler.onKeyPress(event); 633 } 634 }); 635 } 636 637 @Override 638 public HandlerRegistration addMouseDownHandler(final MouseDownHandler handler) { 639 return valueBoxBase.addMouseDownHandler(event -> { 640 if (isEnabled()) { 641 handler.onMouseDown(event); 642 } 643 }); 644 } 645 646 @Override 647 public HandlerRegistration addMouseUpHandler(final MouseUpHandler handler) { 648 return valueBoxBase.addMouseUpHandler(event -> { 649 if (isEnabled()) { 650 handler.onMouseUp(event); 651 } 652 }); 653 } 654 655 @Override 656 public HandlerRegistration addMouseOutHandler(final MouseOutHandler handler) { 657 return valueBoxBase.addMouseOutHandler(event -> { 658 if (isEnabled()) { 659 handler.onMouseOut(event); 660 } 661 }); 662 } 663 664 @Override 665 public HandlerRegistration addMouseOverHandler(final MouseOverHandler handler) { 666 return valueBoxBase.addMouseOverHandler(event -> { 667 if (isEnabled()) { 668 handler.onMouseOver(event); 669 } 670 }); 671 } 672 673 @Override 674 public HandlerRegistration addMouseMoveHandler(final MouseMoveHandler handler) { 675 return valueBoxBase.addMouseMoveHandler(event -> { 676 if (isEnabled()) { 677 handler.onMouseMove(event); 678 } 679 }); 680 } 681 682 @Override 683 public HandlerRegistration addMouseWheelHandler(final MouseWheelHandler handler) { 684 return valueBoxBase.addMouseWheelHandler(event -> { 685 if (isEnabled()) { 686 handler.onMouseWheel(event); 687 } 688 }); 689 } 690 691 @Override 692 public HandlerRegistration addTouchStartHandler(final TouchStartHandler handler) { 693 return valueBoxBase.addTouchStartHandler(event -> { 694 if (isEnabled()) { 695 handler.onTouchStart(event); 696 } 697 }); 698 } 699 700 @Override 701 public HandlerRegistration addTouchMoveHandler(final TouchMoveHandler handler) { 702 return valueBoxBase.addTouchMoveHandler(event -> { 703 if (isEnabled()) { 704 handler.onTouchMove(event); 705 } 706 }); 707 } 708 709 @Override 710 public HandlerRegistration addTouchEndHandler(final TouchEndHandler handler) { 711 return valueBoxBase.addTouchEndHandler(event -> { 712 if (isEnabled()) { 713 handler.onTouchEnd(event); 714 } 715 }); 716 } 717 718 @Override 719 public HandlerRegistration addTouchCancelHandler(final TouchCancelHandler handler) { 720 return valueBoxBase.addTouchCancelHandler(event -> { 721 if (isEnabled()) { 722 handler.onTouchCancel(event); 723 } 724 }); 725 } 726 727 @Override 728 public HandlerRegistration addDoubleClickHandler(final DoubleClickHandler handler) { 729 return valueBoxBase.addDoubleClickHandler(event -> { 730 if (isEnabled()) { 731 handler.onDoubleClick(event); 732 } 733 }); 734 } 735 736 @Override 737 public HandlerRegistration addClickHandler(final ClickHandler handler) { 738 return valueBoxBase.addClickHandler(event -> { 739 if (isEnabled()) { 740 handler.onClick(event); 741 } 742 }); 743 } 744 745 @Override 746 protected FocusableMixin<MaterialWidget> getFocusableMixin() { 747 if (focusableMixin == null) { 748 focusableMixin = new FocusableMixin<>(new MaterialWidget(valueBoxBase.getElement())); 749 } 750 return focusableMixin; 751 } 752 753 @Override 754 protected ErrorMixin<AbstractValueWidget, MaterialLabel> getErrorMixin() { 755 if (errorMixin == null) { 756 errorMixin = new ErrorMixin<>(this, errorLabel, valueBoxBase, label); 757 } 758 return errorMixin; 759 } 760 761 protected ReadOnlyMixin<MaterialValueBox, ValueBoxBase> getReadOnlyMixin() { 762 if (readOnlyMixin == null) { 763 readOnlyMixin = new ReadOnlyMixin<>(this, valueBoxBase); 764 } 765 return readOnlyMixin; 766 } 767 768 protected ActiveMixin<MaterialValueBox> getActiveMixin() { 769 if (activeMixin == null) { 770 activeMixin = new ActiveMixin<>(this, label); 771 } 772 return activeMixin; 773 } 774 775 protected CounterMixin<MaterialValueBox<T>> getCounterMixin() { 776 if (counterMixin == null) { 777 counterMixin = new CounterMixin<>(this); 778 } 779 return counterMixin; 780 } 781}