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

gwt.material.design.client.ui.MaterialSearch Maven / Gradle / Ivy

/*
 * #%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.client.ui;

import com.google.gwt.core.client.Scheduler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.logical.shared.*;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.TextBox;
import gwt.material.design.client.base.*;
import gwt.material.design.client.constants.*;
import gwt.material.design.client.events.SearchFinishEvent;
import gwt.material.design.client.events.SearchNoResultEvent;
import gwt.material.design.client.ui.html.Label;

import java.util.ArrayList;
import java.util.List;

import static gwt.material.design.jquery.client.api.JQuery.$;

//@formatter:off

/**
 * Material Search is a value box component that returns a result based on your search
 * 

*

*

UiBinder Usage:

*
 * {@code
 * 
 * }
 * 
*

*

Populating the search result objects

* {@code *

* List objects = new ArrayList<>(); *

* private void onInitSearch() { * objects.add(new SearchObject(IconType.POLYMER, "Pushpin", "#!pushpin")); * objects.add(new SearchObject(IconType.POLYMER, "SideNavs", "#!sidenavs")); * objects.add(new SearchObject(IconType.POLYMER, "Scrollspy", "#!scrollspy")); * objects.add(new SearchObject(IconType.POLYMER, "Tabs", "#!tabs")); * txtSearch.setListSearches(objects); * } *

* } *

* * @author kevzlou7979 * @author Ben Dol * @see Material Search * @see Material Design Specification */ //@formatter:on public class MaterialSearch extends MaterialValueBox implements HasOpenHandlers, HasCloseHandlers, HasActive, HasSearchHandlers, HasOpenClose { private Label label = new Label(); private MaterialIcon iconSearch = new MaterialIcon(IconType.SEARCH); private MaterialIcon iconClose = new MaterialIcon(IconType.CLOSE); private SearchMatcher matcher = new DefaultSearchMatcher(); /** * The list of search objects added to MaterialSearchResult panel to * display the lists of result items */ private List listSearches = new ArrayList<>(); /** * Used to determine the selected searches while matching the keyword to result */ private List tempSearches = new ArrayList<>(); /** * Panel to display the result items */ private MaterialSearchResult searchResultPanel = new MaterialSearchResult(); /** * Link selected to determine easily during the selection event (up / down key events) */ private MaterialLink selectedLink; /** * Gets the selected object after Search Finish event */ private SearchObject selectedObject; /** * -1 means that the selected index is not yet selected. * It will increment or decrement once trigger by key up / down events */ private int curSel = -1; private boolean active; public MaterialSearch() { super(new TextBox()); } public MaterialSearch(String placeholder) { this(); setPlaceholder(placeholder); } public MaterialSearch(String placeholder, Color backgroundColor, Color iconColor, boolean active, int shadow) { this(placeholder); setBackgroundColor(backgroundColor); setIconColor(iconColor); setActive(active); setShadow(shadow); } @Override protected void onLoad() { super.onLoad(); setType(InputType.SEARCH); setAutocomplete(Autocomplete.OFF); label.add(iconSearch); label.getElement().setAttribute("for", "search"); add(label); add(iconClose); registerHandler(iconClose.addClickHandler(clickEvent -> CloseEvent.fire(MaterialSearch.this, getText()))); add(searchResultPanel); // Add Key Up event to filter the searches registerHandler(addKeyUpHandler(new KeyUpHandler() { @Override public void onKeyUp(KeyUpEvent event) { String keyword = getText().toLowerCase(); int keyCode = event.getNativeEvent().getKeyCode(); // Clear the panel and temp objects searchResultPanel.clear(); tempSearches.clear(); // Populate the search result items for (final SearchObject obj : getListSearches()) { MaterialLink link = new MaterialLink(); link.setIconColor(Color.GREY); link.setTextColor(Color.BLACK); // Generate an icon if (obj.getIcon() != null) { link.setIconType(obj.getIcon()); } // Generate an image MaterialImage image = new MaterialImage(); if (obj.getResource() != null) { image.setResource(obj.getResource()); link.insert(image, 0); } if (obj.getImageUrl() != null) { image.setUrl(obj.getImageUrl()); link.insert(image, 0); } if (!obj.getLink().isEmpty()) { link.setHref(obj.getLink()); } link.setText(obj.getKeyword()); link.addClickHandler(event1 -> { setSelectedObject(obj); reset(obj.getKeyword()); }); // If matches add to search result container and object to temp searches if (match(obj, keyword)) { searchResultPanel.add(link); tempSearches.add(obj); } searchResultPanel.setVisible(true); } // Apply selected search if (keyCode == KeyCodes.KEY_ENTER && !tempSearches.isEmpty()) { if (getCurSel() == -1) { setSelectedObject(tempSearches.get(0)); setSelectedLink((MaterialLink) searchResultPanel.getWidget(0)); } else { setSelectedObject(tempSearches.get(curSel)); } MaterialLink selLink = getSelectedLink(); if (!selLink.getHref().isEmpty()) { locateSearch(selLink.getHref()); } reset(selLink.getText()); } // Fire an event if there's no search result if (searchResultPanel.getWidgetCount() == 0) { SearchNoResultEvent.fire(MaterialSearch.this); } // Selection logic using key down event to navigate the search results int totalItems = searchResultPanel.getWidgetCount(); if (totalItems > 0) { if (keyCode == KeyCodes.KEY_DOWN) { if (++curSel >= totalItems) curSel = 0; applyHighlightedItem((MaterialLink) searchResultPanel.getWidget(curSel)); } // Selection logic using key up event to navigate the search results if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_UP) { if (--curSel < 0) curSel = totalItems - 1; applyHighlightedItem((MaterialLink) searchResultPanel.getWidget(curSel)); } } // Add Escape key for closing the result panel if (keyCode == KeyCodes.KEY_ESCAPE) { close(); } } // Resets the search result panel private void reset(String keyword) { SearchFinishEvent.fire(MaterialSearch.this); curSel = -1; setText(keyword); $(valueBoxBase.getElement()).focus(); searchResultPanel.clear(); } })); } protected boolean match(SearchObject obj, String keyword) { return matcher.match(obj, keyword); } public SearchMatcher getMatcher() { return matcher; } /** * Will set a custom matcher to match the keyword. * By Default {@lnk DefaultSearchMatcher} */ public void setMatcher(SearchMatcher matcher) { this.matcher = matcher; } @Override protected void onUnload() { super.onUnload(); clear(); setCurSel(-1); } /** * Programmatically open the search input field component */ @Override public void open() { setActive(true); Scheduler.get().scheduleDeferred(() -> $(valueBoxBase.getElement()).focus()); OpenEvent.fire(MaterialSearch.this, getText()); } @Override public void close() { close(true); } @Override public boolean isOpen() { return isActive(); } public void close(boolean fireEvents) { setActive(false); if (fireEvents) { Scheduler.get().scheduleDeferred(() -> $(valueBoxBase.getElement()).blur()); CloseEvent.fire(MaterialSearch.this, getText()); } } protected void applyHighlightedItem(MaterialLink link) { link.addStyleName(CssName.HIGLIGHTED); setSelectedLink(link); } //TODO: Convert to JSInterop protected native void locateSearch(String location)/*-{ $wnd.window.location.hash = location; }-*/; @Override public void setActive(boolean active) { this.active = active; if (active) { setTextColor(Color.BLACK); iconClose.setIconColor(Color.BLACK); iconSearch.setIconColor(Color.BLACK); } else { iconClose.setIconColor(Color.WHITE); iconSearch.setIconColor(Color.WHITE); } searchResultPanel.setVisible(active); } @Override public boolean isActive() { return active; } public MaterialLink getSelectedLink() { return selectedLink; } public void setSelectedLink(MaterialLink selectedLink) { this.selectedLink = selectedLink; } public List getListSearches() { return listSearches; } public void setListSearches(List listSearches) { this.listSearches = listSearches; } public int getCurSel() { return curSel; } public void setCurSel(int curSel) { this.curSel = curSel; } public SearchObject getSelectedObject() { return selectedObject; } public void setSelectedObject(SearchObject selectedObject) { this.selectedObject = selectedObject; if (selectedObject != null) { setText(selectedObject.getKeyword()); } } /** * Gets the temporary search objects. */ public List getTempSearches() { return tempSearches; } public MaterialIcon getIconClose() { return iconClose; } public MaterialSearchResult getSearchResultPanel() { return searchResultPanel; } @Override public Label getLabelWidget() { return label; } public MaterialIcon getIconSearch() { return iconSearch; } @Override public HandlerRegistration addCloseHandler(final CloseHandler handler) { return addHandler((CloseHandler) handler::onClose, CloseEvent.getType()); } @Override public HandlerRegistration addOpenHandler(OpenHandler handler) { return addHandler((OpenHandler) handler::onOpen, OpenEvent.getType()); } /** * This handler will be triggered when search is finish */ @Override public HandlerRegistration addSearchFinishHandler(final SearchFinishEvent.SearchFinishHandler handler) { return addHandler(handler, SearchFinishEvent.TYPE); } /** * This handler will be triggered when there's no search result */ @Override public HandlerRegistration addSearchNoResultHandler(final SearchNoResultEvent.SearchNoResultHandler handler) { return addHandler(handler, SearchNoResultEvent.TYPE); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy