All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gwt.material.design.addins.client.combobox.MaterialComboBox Maven / Gradle / Ivy

There is a newer version: 2.8.3
Show newest version
/*
 * #%L
 * GwtMaterial
 * %%
 * Copyright (C) 2015 - 2017 GwtMaterialDesign
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
package gwt.material.design.addins.client.combobox;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.logical.shared.*;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.Widget;
import gwt.material.design.addins.client.MaterialAddins;
import gwt.material.design.addins.client.base.constants.AddinsCssName;
import gwt.material.design.addins.client.combobox.base.HasUnselectItemHandler;
import gwt.material.design.addins.client.combobox.events.ComboBoxEvents;
import gwt.material.design.addins.client.combobox.events.SelectItemEvent;
import gwt.material.design.addins.client.combobox.events.UnselectItemEvent;
import gwt.material.design.addins.client.combobox.js.JsComboBox;
import gwt.material.design.addins.client.combobox.js.JsComboBoxOptions;
import gwt.material.design.addins.client.combobox.js.LanguageOptions;
import gwt.material.design.addins.client.combobox.js.options.Data;
import gwt.material.design.addins.client.combobox.js.options.Params;
import gwt.material.design.client.MaterialDesignBase;
import gwt.material.design.client.base.*;
import gwt.material.design.client.base.mixin.EnabledMixin;
import gwt.material.design.client.base.mixin.FieldTypeMixin;
import gwt.material.design.client.base.mixin.ReadOnlyMixin;
import gwt.material.design.client.base.mixin.StatusTextMixin;
import gwt.material.design.client.constants.CssName;
import gwt.material.design.client.constants.FieldType;
import gwt.material.design.client.ui.MaterialLabel;
import gwt.material.design.client.ui.html.Label;
import gwt.material.design.client.ui.html.OptGroup;
import gwt.material.design.client.ui.html.Option;
import gwt.material.design.jquery.client.api.Functions;
import gwt.material.design.jquery.client.api.JQueryElement;

import java.util.*;

import static gwt.material.design.addins.client.combobox.js.JsComboBox.$;

//@formatter:off

/**
 * ComboBox component used on chat module
 * 

*

XML Namespace Declaration

*
 * {@code
 * xmlns:ma='urn:import:gwt.material.design.addins.client'
 * }
 * 
*

*

UiBinder Usage:

*
 * {@code
 * 
 *   
 *   
 *   
 * 
 * }
 * 
* * @author kevzlou7979 * @author Ben Dol * @see Material ComboBox * @see Select2 4.0.3 */ //@formatter:on public class MaterialComboBox extends AbstractValueWidget> implements JsLoader, HasPlaceholder, HasOpenHandlers, HasCloseHandlers, HasUnselectItemHandler, HasReadOnly, HasFieldTypes { static { if (MaterialAddins.isDebug()) { MaterialDesignBase.injectDebugJs(MaterialComboBoxDebugClientBundle.INSTANCE.select2DebugJs()); MaterialDesignBase.injectCss(MaterialComboBoxDebugClientBundle.INSTANCE.select2DebugCss()); } else { MaterialDesignBase.injectJs(MaterialComboBoxClientBundle.INSTANCE.select2Js()); MaterialDesignBase.injectCss(MaterialComboBoxClientBundle.INSTANCE.select2Css()); } } private int selectedIndex; private boolean suppressChangeEvent; protected List values = new ArrayList<>(); private Label label = new Label(); private MaterialLabel errorLabel = new MaterialLabel(); protected MaterialWidget listbox = new MaterialWidget(Document.get().createSelectElement()); private KeyFactory keyFactory = Object::toString; private JsComboBoxOptions options = JsComboBoxOptions.create(); private StatusTextMixin statusTextMixin; private ReadOnlyMixin readOnlyMixin; private EnabledMixin enabledMixin; private FieldTypeMixin fieldTypeMixin; public MaterialComboBox() { super(Document.get().createDivElement(), CssName.INPUT_FIELD, AddinsCssName.COMBOBOX); } @Override protected void onLoad() { label.setInitialClasses(AddinsCssName.SELECT2LABEL); super.add(listbox); super.add(label); super.add(errorLabel); errorLabel.setMarginTop(8); listbox.setGwtDisplay(Style.Display.BLOCK); super.onLoad(); load(); registerHandler(addSelectionHandler(valueChangeEvent -> $(getElement()).find("input").val(""))); } @Override public void load() { JsComboBox jsComboBox = $(listbox.getElement()); jsComboBox.select2(options); jsComboBox.on(ComboBoxEvents.CHANGE, event -> { if (!suppressChangeEvent) { ValueChangeEvent.fire(this, getValue()); } return true; }); jsComboBox.on(ComboBoxEvents.SELECT, event -> { SelectItemEvent.fire(this, getValue()); displayArrowForAllowClearOption(false); return true; }); jsComboBox.on(ComboBoxEvents.UNSELECT, event -> { UnselectItemEvent.fire(this, getValue()); displayArrowForAllowClearOption(true); return true; }); jsComboBox.on(ComboBoxEvents.OPEN, (event1, o) -> { OpenEvent.fire(this, null); return true; }); jsComboBox.on(ComboBoxEvents.CLOSE, (event1, o) -> { CloseEvent.fire(this, null); return true; }); displayArrowForAllowClearOption(false); if (getTextColor() != null) { $(getElement()).find(".select2-selection__rendered").css("color", getTextColor().getCssName()); } } @Override protected void onUnload() { super.onUnload(); unload(); } @Override public void unload() { JsComboBox jsComboBox = $(listbox.getElement()); jsComboBox.off(ComboBoxEvents.CHANGE); jsComboBox.off(ComboBoxEvents.SELECT); jsComboBox.off(ComboBoxEvents.UNSELECT); jsComboBox.off(ComboBoxEvents.OPEN); jsComboBox.off(ComboBoxEvents.CLOSE); jsComboBox.select2("destroy"); } @Override public void reload() { unload(); load(); } @Override public void reset() { super.reset(); displayArrowForAllowClearOption(false); setSelectedIndex(0); } @Override public void add(Widget child) { if (child instanceof OptGroup) { for (Widget w : ((OptGroup) child).getChildren()) { if (w instanceof Option) { values.add((T) ((Option) w).getValue()); } } } else if (child instanceof Option) { values.add((T) ((Option) child).getValue()); } listbox.add(child); } /** * Add OptionGroup directly to combobox component * * @param group - Option Group component */ public void addGroup(OptGroup group) { listbox.add(group); } /** * Add item directly to combobox component with existing OptGroup * * @param text - The text you want to labeled on the option item * @param value - The value you want to pass through in this option * @param optGroup - Add directly this option into the existing group */ public void addItem(String text, T value, OptGroup optGroup) { if (!values.contains(value)) { values.add(value); optGroup.add(buildOption(text, value)); } } /** * Add Value directly to combobox component * * @param text - The text you want to labeled on the option item * @param value - The value you want to pass through in this option */ public Option addItem(String text, T value) { if (!values.contains(value)) { Option option = buildOption(text, value); values.add(value); listbox.add(option); return option; } return null; } public Option addItem(T value) { return addItem(keyFactory.generateKey(value), value); } public void setItems(Collection items) { clear(); addItems(items); } public void addItems(Collection items) { items.forEach(this::addItem); } /** * Build the Option Element with provided params */ protected Option buildOption(String text, T value) { Option option = new Option(); option.setText(text); option.setValue(keyFactory.generateKey(value)); return option; } /** * Programmatically open the combobox component */ public void open() { $(listbox.getElement()).select2("open"); } /** * Programmatically close the combobox component */ public void close() { $(listbox.getElement()).select2("close"); } @Override public void clear() { final Iterator it = iterator(); while (it.hasNext()) { final Widget widget = it.next(); if (widget != label && widget != errorLabel && widget != listbox) { it.remove(); } } listbox.clear(); values.clear(); } /** * Sets the parent element of the dropdown */ public void setDropdownParent(String dropdownParent) { options.dropdownParent = $(dropdownParent); } public JQueryElement getDropdownParent() { return options.dropdownParent; } /** * Will get the Selection Results ul element containing all the combobox items. */ public JQueryElement getDropdownResultElement() { String dropdownId = getDropdownContainerElement().attr("id").toString(); if (dropdownId != null && !(dropdownId.isEmpty())) { dropdownId = dropdownId.replace("container", "results"); return $("#" + dropdownId); } else { GWT.log("The element dropdown-result ul element is undefined.", new NullPointerException()); } return null; } /** * Will get the Clear Icon element */ public JQueryElement getClearIconElement() { return $(getElement()).find(".select2-selection__clear"); } public JQueryElement getArrowIconElement() { return $(getElement()).find(".select2-selection__arrow"); } /** * Will automatically check for allowClear option to display / hide the * arrow caret. */ protected void displayArrowForAllowClearOption(boolean displayArrow) { if (isAllowClear()) { if (displayArrow && getArrowIconElement() != null) { getArrowIconElement().css("display", "block"); } else { getArrowIconElement().css("display", "none"); } } } /** * Will get the Selection dropdown container rendered */ public JQueryElement getDropdownContainerElement() { JQueryElement element = $(getElement()).find(".select2 .selection .select2-selection__rendered"); if (element == null) { GWT.log("The element dropdown-container element is undefined.", new NullPointerException()); } return element; } /** * Set the upper label above the combobox */ public void setLabel(String text) { label.setText(text); } @Override public String getPlaceholder() { return options.placeholder; } @Override public void setPlaceholder(String placeholder) { options.placeholder = placeholder; } /** * Check if allow clear option is enabled */ public boolean isAllowClear() { return options.allowClear; } /** * Add a clear button on the right side of the combobox */ public void setAllowClear(boolean allowClear) { options.allowClear = allowClear; } /** * Get the maximum number of items to be entered on multiple combobox */ public int getLimit() { return options.maximumSelectionLength; } /** * Set the maximum number of items to be entered on multiple combobox */ public void setLimit(int limit) { options.maximumSelectionLength = limit; } /** * Check whether the search box is enabled on combobox */ public boolean isHideSearch() { return options.minimumResultsForSearch.equals("Infinity"); } /** * Set the option to display the search box inside the combobox component */ public void setHideSearch(boolean hideSearch) { if (hideSearch) { options.minimumResultsForSearch = "Infinity"; } } /** * Check whether the multiple option is enabled */ public boolean isMultiple() { if (listbox != null) { return listbox.getElement().hasAttribute("multiple"); } return false; } /** * Sets multi-value select boxes. */ public void setMultiple(boolean multiple) { if (multiple) { $(listbox.getElement()).attr("multiple", "multiple"); } else { $(listbox.getElement()).removeAttr("multiple"); } } public void setMatcher(Functions.FuncRet2 matcher) { options.matcher = matcher; } public void setAcceptableValues(Collection values) { setItems(values); } @Override public List getValue() { if (!isMultiple()) { int index = getSelectedIndex(); T value; if (index != -1) { // Check when the value is a custom tag if (isTags()) { value = (T) $(listbox.getElement()).val(); } else { value = values.get(index); } return Collections.singletonList(value); } } else { return getSelectedValues(); } return new ArrayList<>(); } /** * Gets the value for currently selected item. If multiple items are * selected, this method will return the value of the first selected item. * * @return the value for selected item, or {@code null} if none is selected */ public List getSelectedValue() { return getValue(); } /** * Only return a single value even if multi support is activate. */ public T getSingleValue() { List values = getSelectedValue(); if (!values.isEmpty()) { return values.get(0); } return null; } @Override public void setValue(List value) { setValue(value, false); } /** * Set the selected value using a single item, generally used * in single selection mode. */ public void setSingleValue(T value) { setValue(Collections.singletonList(value)); } @Override public void setValue(List values, boolean fireEvents) { if (!isMultiple()) { if (!values.isEmpty()) { setSingleValue(values.get(0), fireEvents); } } else { setValues(values, fireEvents); } } /** * Set the selected value using a single item, generally used * in single selection mode. */ public void setSingleValue(T value, boolean fireEvents) { int index = this.values.indexOf(value); if (index < 0 && value instanceof String) { index = getIndexByString((String) value); } if (index > -1) { List before = getValue(); setSelectedIndex(index); if (fireEvents) { ValueChangeEvent.fireIfNotEqual(this, before, Collections.singletonList(value)); } } } // TODO: Optimize performance (maybe use a map) public T getValueByString(String key) { for (T value : values) { if (keyFactory.generateKey(value).equals(key)) { return value; } } return null; } // TODO: Optimize performance (maybe use a map) public int getIndexByString(String key) { int index = -1; for (T value : values) { ++index; if (keyFactory.generateKey(value).equals(key)) { return index; } } return index; } /** * Set directly all the values that will be stored into * combobox and build options into it. */ public void setValues(List values) { setValues(values, true); } /** * Set directly all the values that will be stored into * combobox and build options into it. */ public void setValues(List values, boolean fireEvents) { String[] stringValues = new String[values.size()]; for (int i = 0; i < values.size(); i++) { stringValues[i] = keyFactory.generateKey(values.get(i)); } suppressChangeEvent = !fireEvents; $(listbox.getElement()).val(stringValues).trigger("change", selectedIndex); suppressChangeEvent = false; } /** * Gets the index of the value pass in this method * * @param value - The Object you want to pass as value on combobox */ public int getValueIndex(T value) { return values.indexOf(value); } /** * Sets the currently selected index. *

* After calling this method, only the specified item in the list will * remain selected. For a ListBox with multiple selection enabled. * * @param selectedIndex - the index of the item to be selected */ public void setSelectedIndex(int selectedIndex) { this.selectedIndex = selectedIndex; if (values.size() > 0) { T value = values.get(selectedIndex); if (value != null) { $(listbox.getElement()).val(keyFactory.generateKey(value)).trigger("change.select2", selectedIndex); } else { GWT.log("Value index is not found.", new IndexOutOfBoundsException()); } } } /** * Gets the text for currently selected item. If multiple items are * selected, this method will return the text of the first selected item. * * @return the text for selected item, or {@code null} if none is selected */ public int getSelectedIndex() { Object o = $(getElement()).find("option:selected").last().prop("index"); if (o != null) { return Integer.parseInt(o.toString()); } return -1; } /** * Get all the values sets on combobox */ public List getValues() { return values; } /** * Get the selected vales from multiple combobox */ public List getSelectedValues() { Object[] curVal = (Object[]) $(listbox.getElement()).val(); List selectedValues = new ArrayList<>(); if (curVal == null || curVal.length < 1) { return selectedValues; } List keyIndex = getValuesKeyIndex(); for (Object val : curVal) { if (val instanceof String) { int selectedIndex = keyIndex.indexOf(val); if (selectedIndex != -1) { selectedValues.add(values.get(selectedIndex)); } else { if (isTags() && val instanceof String) { selectedValues.add((T) val); } } } } return selectedValues; } protected List getValuesKeyIndex() { List keys = new ArrayList<>(); for (T value : values) { keys.add(keyFactory.generateKey(value)); } return keys; } /** * Use your own key factory for value keys. */ public void setKeyFactory(KeyFactory keyFactory) { this.keyFactory = keyFactory; } @Override public void setReadOnly(boolean value) { getReadOnlyMixin().setReadOnly(value); } @Override public boolean isReadOnly() { return getReadOnlyMixin().isReadOnly(); } @Override public void setToggleReadOnly(boolean toggle) { getReadOnlyMixin().setToggleReadOnly(toggle); registerHandler(addValueChangeHandler(valueChangeEvent -> { if (isToggleReadOnly()) { setReadOnly(true); } })); } @Override public boolean isToggleReadOnly() { return getReadOnlyMixin().isToggleReadOnly(); } /** * Check whether the dropdown will be close or not when result is selected */ public boolean isCloseOnSelect() { return options.closeOnSelect; } /** * Allow or Prevent the dropdown from closing when a result is selected (Default true) */ public void setCloseOnSelect(boolean closeOnSelect) { options.closeOnSelect = closeOnSelect; } public MaterialWidget getListbox() { return listbox; } public Label getLabel() { return label; } public MaterialLabel getErrorLabel() { return errorLabel; } public boolean isTags() { return options.tags; } /** * Note: Tags will only support String as generic params starting 2.x. */ public void setTags(boolean tags) { if (tags) GWT.log("Note: Tags will only support String as generic params."); options.tags = tags; } /** * Will provide a set of text objecs that can be used for i18n language support. */ public void setLanguage(LanguageOptions language) { options.language = language; } public LanguageOptions getLanguage() { return options.language; } public void scrollTop(int offset) { Scheduler.get().scheduleDeferred(() -> getDropdownResultElement().scrollTop(offset)); } @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); getEnabledMixin().updateWaves(enabled, this); } @Override public void setFieldType(FieldType type) { getFieldTypeMixin().setFieldType(type); } @Override public FieldType getFieldType() { return getFieldTypeMixin().getFieldType(); } @Override public void setLabelWidth(double percentWidth) { getFieldTypeMixin().setLabelWidth(percentWidth); } @Override public void setFieldWidth(double percentWidth) { getFieldTypeMixin().setFieldWidth(percentWidth); } public HandlerRegistration addSelectionHandler(SelectItemEvent.SelectComboHandler selectionHandler) { return addHandler(selectionHandler, SelectItemEvent.getType()); } @Override public HandlerRegistration addOpenHandler(OpenHandler openHandler) { return addHandler(openHandler, OpenEvent.getType()); } @Override public HandlerRegistration addCloseHandler(CloseHandler closeHandler) { return addHandler(closeHandler, CloseEvent.getType()); } @Override public HandlerRegistration addRemoveItemHandler(UnselectItemEvent.UnselectComboHandler handler) { return addHandler(handler, UnselectItemEvent.getType()); } @Override protected EnabledMixin getEnabledMixin() { if (enabledMixin == null) { enabledMixin = new EnabledMixin<>(listbox); } return enabledMixin; } @Override public StatusTextMixin getStatusTextMixin() { if (statusTextMixin == null) { statusTextMixin = new StatusTextMixin<>(this, errorLabel, this.asWidget()); } return statusTextMixin; } public ReadOnlyMixin getReadOnlyMixin() { if (readOnlyMixin == null) { readOnlyMixin = new ReadOnlyMixin<>(this, listbox); } return readOnlyMixin; } protected FieldTypeMixin getFieldTypeMixin() { if (fieldTypeMixin == null) { fieldTypeMixin = new FieldTypeMixin<>(this); } return fieldTypeMixin; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy