/* * #%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.dom.client.Document; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.Event; import gwt.material.design.client.base.MaterialWidget; import gwt.material.design.client.constants.CssName; import gwt.material.design.client.constants.IconPosition; import gwt.material.design.client.constants.IconType; import gwt.material.design.client.constants.WavesType; import gwt.material.design.client.events.PageSelectionEvent; import gwt.material.design.client.ui.html.ListItem; import static gwt.material.design.client.events.PageSelectionEvent.PageSelectionHandler; import static gwt.material.design.client.events.PageSelectionEvent.TYPE; //@formatter:off /** * Material Pager with page event * <h3>UiBinder Usage:</h3> * <pre> * {@code <m:MaterialPager ui:field='pager' />} * </pre> * * @author Guaido79 */ public class MaterialPager extends MaterialWidget { private int total; private int pageSize = 10; private int currentPage = 1; private int maxPageLinksShown = 10; private int calcTotalPages; private int calcShowingPageFrom; private int calcShowingPageTo; private boolean enableIndicator; private boolean calcInitialized; private String indicatorTemplate = "Page {page} of {total}"; private PagerListItem linkLeft; private PagerListItem linkRight; private MaterialChip indicator; public MaterialPager() { super(Document.get().createULElement(), CssName.PAGINATION); setWaves(WavesType.DEFAULT); removeStyleName(CssName.WAVES_EFFECT); } public MaterialPager(int total, int pageSize) { this(); this.total = total; this.pageSize = pageSize; } public MaterialPager(int total, int pageSize, int currentPage) { this(total, pageSize); this.currentPage = currentPage; } @Override protected void onLoad() { super.onLoad(); load(); } protected void load() { if (!calcInitialized) { calcTotalPages = total / pageSize + (((double) total % (double) pageSize) > 0 ? 1 : 0); add(getOrCreateLiElementLeft()); moveNextPagesRange(); add(getOrCreateLiElementRight()); if (enableIndicator) { add(createLiElementIndicator()); } onPageSelection(1); calcInitialized = true; } } protected void moveNextPagesRange() { calcShowingPageFrom = currentPage; calcShowingPageTo = Math.min(currentPage + maxPageLinksShown - 1, calcTotalPages); createPageNumberLinks(); } protected void movePreviousPagesRange() { calcShowingPageFrom = currentPage - maxPageLinksShown + 1; calcShowingPageTo = currentPage; createPageNumberLinks(); } protected void createPageNumberLinks() { for (int i = 0; i < getWidgetCount(); i++) { final PagerListItem widget = (PagerListItem) getWidget(i); if (!widget.isFixed()) { Scheduler.get().scheduleDeferred(widget::removeFromParent); } } int insertionIndex = 1; for (int i = calcShowingPageFrom; i <= calcShowingPageTo; i++) { final PagerListItem liElementForPage = createLiElementForPage(i); Scheduler.get().scheduleDeferred(new InsertElementAtPositionCommand(insertionIndex++) { @Override public void execute() { insert(liElementForPage, insertionIndex); } }); } } protected PagerListItem createLiElementForPage(final int page) { final PagerListItem pageLiElement = new PagerListItem(); pageLiElement.setFixed(false); pageLiElement.add(createLinkPage(page)); registerHandler(addPageSelectionHandler(event -> pageLiElement.setActive(event.getPageTo() == page))); registerHandler(pageLiElement.addHandler(event -> { onPageSelection(page); event.preventDefault(); event.stopPropagation(); }, ClickEvent.getType())); return pageLiElement; } protected PagerListItem getOrCreateLiElementLeft() { linkLeft = new PagerListItem(); linkLeft.setFixed(true); registerHandler(linkLeft.addHandler(event -> { if (linkLeft.isEnabled()) { onPageSelection(currentPage - 1); } event.preventDefault(); event.stopPropagation(); }, ClickEvent.getType())); linkLeft.add(createLinkLeft()); registerHandler(addPageSelectionHandler(event -> MaterialPager.this.linkLeft.setEnabled(event.getPageTo() > 1))); return linkLeft; } protected PagerListItem getOrCreateLiElementRight() { linkRight = new PagerListItem(); linkRight.setFixed(true); registerHandler(linkRight.addHandler(event -> { if (linkRight.isEnabled()) { onPageSelection(currentPage + 1); } event.stopPropagation(); event.preventDefault(); }, ClickEvent.getType())); linkRight.add(createLinkRight()); registerHandler(addPageSelectionHandler(event -> MaterialPager.this.linkRight.setEnabled(event.getPageTo() < calcTotalPages))); return linkRight; } protected PagerListItem createLiElementIndicator() { PagerListItem indicatorLi = new PagerListItem(false); indicatorLi.setFixed(true); indicatorLi.add(getOrCreateIndicator()); return indicatorLi; } protected MaterialChip getOrCreateIndicator() { indicator = new MaterialChip(); indicator.getElement().getStyle().setBackgroundColor("inherit"); registerHandler(addPageSelectionHandler(event -> indicator.setText(indicatorTemplate .replaceAll("\\{page\\}", String.valueOf(event.getPageTo())) .replaceAll("\\{total\\}", String.valueOf(event.getTotalPage())) ))); return indicator; } protected MaterialLink createLinkPage(int page) { return new MaterialLink(String.valueOf(page)); } protected MaterialLink createLinkLeft() { final MaterialLink linkLeft = new MaterialLink(IconType.CHEVRON_LEFT); linkLeft.setIconPosition(IconPosition.NONE); return linkLeft; } protected MaterialLink createLinkRight() { final MaterialLink linkRight = new MaterialLink(IconType.CHEVRON_RIGHT); linkRight.setIconPosition(IconPosition.NONE); return linkRight; } protected void onPageSelection(int page) { currentPage = page; if (currentPage > calcShowingPageTo) { moveNextPagesRange(); } if (currentPage < calcShowingPageFrom) { movePreviousPagesRange(); } PageSelectionEvent event = new PageSelectionEvent(); event.setPageFrom(currentPage); event.setPageTo(page); event.setTotalPage(calcTotalPages); fireEvent(event); } public HandlerRegistration addPageSelectionHandler(PageSelectionHandler handler) { return addHandler(handler, TYPE); } public boolean isEnableIndicator() { return enableIndicator; } public void setEnableIndicator(boolean enableIndicator) { this.enableIndicator = enableIndicator; } public int getTotal() { return total; } public void setTotal(final int total) { boolean needToClear = total != this.total; this.total = total; currentPage = 1; if (calcInitialized && needToClear) { clear(); load(); } } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } public int getCurrentPage() { return currentPage; } public void setCurrentPage(int currentPage) { this.currentPage = currentPage; } public int getMaxPageLinksShown() { return maxPageLinksShown; } public void setMaxPageLinksShown(int maxPageLinksShown) { this.maxPageLinksShown = maxPageLinksShown; } public String getIndicatorTemplate() { return indicatorTemplate; } /** * Set the paging indicator label with a custom template * <ul> * <li><strong>{page}</strong> is the current page</li> * <li><strong>{total}</strong> is the total page</li> * </ul> * Example * <pre> * {@code * Page {page} of {total} * }</pre> */ public void setIndicatorTemplate(String indicatorTemplate) { this.indicatorTemplate = indicatorTemplate; } static abstract class InsertElementAtPositionCommand implements Scheduler.ScheduledCommand { protected int insertionIndex; InsertElementAtPositionCommand(int insertionIndex) { this.insertionIndex = insertionIndex; } } static class PagerListItem extends ListItem { private boolean fixed; private boolean enabled; public PagerListItem() { this(true); } public PagerListItem(boolean clickable) { if (clickable) { addStyleName(CssName.WAVES_EFFECT); sinkEvents(Event.ONCLICK | Event.TOUCHEVENTS); } } public boolean isFixed() { return fixed; } public void setFixed(boolean fixed) { this.fixed = fixed; } public void setActive(boolean active) { if (active) { addStyleName(CssName.ACTIVE); } else { removeStyleName(CssName.ACTIVE); } } @Override public boolean isEnabled() { return enabled; } @Override public void setEnabled(boolean enabled) { this.enabled = enabled; if (!enabled) { addStyleName(CssName.DISABLED); } else { removeStyleName(CssName.DISABLED); } } } public MaterialChip getIndicator() { return indicator; } }