Skip to content

Commit

Permalink
Redesigned the paging in the Grid widget.
Browse files Browse the repository at this point in the history
  • Loading branch information
nmihajlovski committed May 4, 2016
1 parent 38cb890 commit e711dfb
Show file tree
Hide file tree
Showing 11 changed files with 105 additions and 69 deletions.
Expand Up @@ -286,7 +286,7 @@ public Set<V> map(K src) throws Exception {
}); });
} }


public static <T> Iterable<T> range(Iterable<T> items, int from, int to) { public static <T> List<T> range(Iterable<T> items, int from, int to) {
U.must(from <= to, "'from' must be <= 'to'!"); U.must(from <= to, "'from' must be <= 'to'!");


if (from == to) { if (from == to) {
Expand Down
28 changes: 18 additions & 10 deletions rapidoid-commons/src/main/java/org/rapidoid/util/Msc.java
Expand Up @@ -21,6 +21,7 @@
import org.rapidoid.log.Log; import org.rapidoid.log.Log;
import org.rapidoid.u.U; import org.rapidoid.u.U;
import org.rapidoid.validation.InvalidData; import org.rapidoid.validation.InvalidData;
import org.rapidoid.wrap.BoolWrap;


import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException; import javax.validation.ConstraintViolationException;
Expand Down Expand Up @@ -820,19 +821,26 @@ public static ErrCodeAndMsg getErrorCodeAndMsg(Throwable err) {
return new ErrCodeAndMsg(code, msg); return new ErrCodeAndMsg(code, msg);
} }


public static <T> List<T> range(Iterable<T> items, int fromIndex, int toIndex) { public static <T> List<T> page(Iterable<T> items, int page, int pageSize) {
// TODO more efficient implementation return Coll.range(items, (page - 1) * pageSize, page * pageSize);
List<T> list = U.list(items); }


fromIndex = U.limit(0, fromIndex, list.size()); public static List<?> getPage(Iterable<?> items, int page, int pageSize, Integer size, BoolWrap isLastPage) {
toIndex = U.limit(fromIndex, toIndex, list.size()); int pageFrom = Math.max((page - 1) * pageSize, 0);
int pageTo = (page) * pageSize + 1;


return U.list(list.subList(fromIndex, toIndex)); if (size != null) {
} pageTo = Math.min(pageTo, size);
}


public static <T> List<T> page(Iterable<T> items, int page, int pageSize) { List<?> range = Coll.range(items, pageFrom, pageTo);
return range(items, (page - 1) * pageSize, page * pageSize); isLastPage.value = range.size() < pageSize + 1;
}
if (!isLastPage.value && !range.isEmpty()) {
range.remove(range.size() - 1);
}


return range; // 1 item extra, to test if there are more results
}


} }
4 changes: 2 additions & 2 deletions rapidoid-gui/src/main/java/org/rapidoid/gui/GUI.java
Expand Up @@ -401,7 +401,7 @@ public static HtmlPage page(Object... contents) {
return Cls.customizable(HtmlPage.class, new Object[]{AnyObj.flat(contents)}); return Cls.customizable(HtmlPage.class, new Object[]{AnyObj.flat(contents)});
} }


public static <T> Grid grid(Iterable<T> items) { public static Grid grid(Iterable<?> items) {
return Cls.customizable(Grid.class).items(items); return Cls.customizable(Grid.class).items(items);
} }


Expand Down Expand Up @@ -954,7 +954,7 @@ public static String uriFor(String baseUri, Object target) {
} }


Object id = getIdentifier(target); Object id = getIdentifier(target);
return id != null ? Msc.uri(baseUri, id + "", "view") : ""; return id != null ? Msc.uri(baseUri, id + "") : "";
} }


public static String typeUri(Class<?> entityType) { public static String typeUri(Class<?> entityType) {
Expand Down
99 changes: 64 additions & 35 deletions rapidoid-gui/src/main/java/org/rapidoid/gui/Grid.java
Expand Up @@ -2,6 +2,7 @@


import org.rapidoid.annotation.Authors; import org.rapidoid.annotation.Authors;
import org.rapidoid.annotation.Since; import org.rapidoid.annotation.Since;
import org.rapidoid.commons.Coll;
import org.rapidoid.gui.base.AbstractWidget; import org.rapidoid.gui.base.AbstractWidget;
import org.rapidoid.html.Tag; import org.rapidoid.html.Tag;
import org.rapidoid.html.tag.TdTag; import org.rapidoid.html.tag.TdTag;
Expand All @@ -12,7 +13,9 @@
import org.rapidoid.model.Models; import org.rapidoid.model.Models;
import org.rapidoid.model.Property; import org.rapidoid.model.Property;
import org.rapidoid.u.U; import org.rapidoid.u.U;
import org.rapidoid.util.Msc;
import org.rapidoid.var.Var; import org.rapidoid.var.Var;
import org.rapidoid.wrap.BoolWrap;


import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
Expand Down Expand Up @@ -52,51 +55,76 @@ public class Grid extends AbstractWidget<Grid> {
private volatile Mapper<Object, String> toUri; private volatile Mapper<Object, String> toUri;


@Override @Override
protected Tag render() { protected Object render() {


Iterator<?> it = items.iterator(); Pager pager = noPager();
Class<?> type = it.hasNext() ? it.next().getClass() : Object.class; boolean paging = pageSize > 0;
Iterable<?> rows;

BoolWrap isLastPage = new BoolWrap();

if (paging) {
String pageParam = "_p" + seq("pager");
pager = GUI.pager(pageParam).min(1);

Integer size = Coll.getSizeOrNull(items);

if (size != null) {
int pages = (int) Math.ceil(size / (double) pageSize);
pager.max(pages);
}

rows = Msc.getPage(items, pager.pageNumber(), pageSize, size, isLastPage);


Items itemsModel;
if (items instanceof Items) {
itemsModel = (Items) items;
} else { } else {
itemsModel = Models.beanItems(type, U.array(items)); rows = items;
} }


final List<Property> props = itemsModel.properties(columns); return renderGridPage(pager, rows, isLastPage.value);
}


int total = itemsModel.size(); private Object renderGridPage(Pager pager, Iterable<?> rows, boolean isLastPage) {
int pages = (int) Math.ceil(total / (double) pageSize); Iterator<?> it = rows.iterator();
boolean hasData = it.hasNext();


boolean ordered = !U.isEmpty(orderBy); if (isLastPage || !hasData) {
Var<String> order = null; pager.max(pager.pageNumber());
}


Items slice = itemsModel; if (!hasData) {
return U.list(noDataAvailable(), pager); // no data
}


String currentOrder = orderBy; Class<?> type = it.next().getClass();


if (ordered) { Items itemsModel;
order = GUI.local("_order_" + widgetId(), orderBy); if (rows instanceof Items) {
currentOrder = order.get(); itemsModel = (Items) rows;
slice = slice.orderedBy(currentOrder); } else {
itemsModel = Models.beanItems(type, U.array(rows));
} }


boolean paging = pageSize > 0; final List<Property> props = itemsModel.properties(columns);
Var<Integer> pageNumber = null; boolean ordered = !U.isEmpty(orderBy);
Var<String> order = null;
String currentOrder = orderBy;


if (paging) { if (ordered) {
pageNumber = GUI.local("_page_" + widgetId(), 1, 1, pages); order = GUI.local("_o" + seq("order"), orderBy);
slice = getPage(slice, pageNumber.get()); currentOrder = order.get();
itemsModel = itemsModel.orderedBy(currentOrder);
} }


Tag header = tableHeader(props, order); Tag header = tableHeader(props, order);
Tag body = tableBody(props, slice); Tag body = tableBody(props, itemsModel);
Pager pager = paging ? GUI.pager(pageNumber.name()).min(1).max(pages) : noPager();


return fullTable(header, body, pager); return fullTable(header, body, pager);
} }


protected Tag noDataAvailable() {
return GUI.h4("No data available!");
}

protected Pager noPager() { protected Pager noPager() {
return null; return null;
} }
Expand All @@ -105,15 +133,6 @@ protected Tag fullTable(Tag header, Tag body, Pager pager) {
return GUI.row(GUI.table_(GUI.thead(header), body), pager); return GUI.row(GUI.table_(GUI.thead(header), body), pager);
} }


protected Items getPage(Items items, Integer pageN) {
Items pageOrAll;
int pageFrom = Math.max((pageN - 1) * pageSize, 0);
int pageTo = Math.min((pageN) * pageSize, items.size());

pageOrAll = items.range(pageFrom, pageTo);
return pageOrAll;
}

protected Tag tableBody(final List<Property> props, Items pageOrAll) { protected Tag tableBody(final List<Property> props, Items pageOrAll) {
Tag body = GUI.tbody(); Tag body = GUI.tbody();


Expand Down Expand Up @@ -181,7 +200,16 @@ protected Tag itemRow(List<Property> properties, Item item) {
} }


protected String onClickScript(Item item) { protected String onClickScript(Item item) {
String uri = toUri != null ? Lmbd.eval(toUri, item.value()) : GUI.uriFor(item.value()); String uri;
if (toUri != null) {
uri = Lmbd.eval(toUri, item.value());
} else {
uri = GUI.uriFor(item.value());
if (U.notEmpty(uri)) {
uri = Msc.uri(uri, "view");
}
}

return U.notEmpty(uri) ? U.frmt("Rapidoid.goAt('%s');", uri) : null; return U.notEmpty(uri) ? U.frmt("Rapidoid.goAt('%s');", uri) : null;
} }


Expand All @@ -194,6 +222,7 @@ public Iterable<?> items() {
} }


public Grid items(Iterable<?> items) { public Grid items(Iterable<?> items) {
U.must(!(items instanceof Items));
this.items = items; this.items = items;
return this; return this;
} }
Expand Down
2 changes: 1 addition & 1 deletion rapidoid-gui/src/main/java/org/rapidoid/gui/Pager.java
Expand Up @@ -62,7 +62,7 @@ protected String pageUri(int pageN) {
} }


protected boolean shouldDisplay() { protected boolean shouldDisplay() {
return U.neq(min, max); return U.neq(min, max) || max == null || min == null;
} }


protected Tag pagination() { protected Tag pagination() {
Expand Down
Expand Up @@ -12,10 +12,9 @@
import org.rapidoid.html.tag.ATag; import org.rapidoid.html.tag.ATag;
import org.rapidoid.html.tag.TdTag; import org.rapidoid.html.tag.TdTag;
import org.rapidoid.html.tag.ThTag; import org.rapidoid.html.tag.ThTag;
import org.rapidoid.u.U;
import org.rapidoid.util.Constants; import org.rapidoid.util.Constants;


import java.util.UUID;

/* /*
* #%L * #%L
* rapidoid-gui * rapidoid-gui
Expand Down Expand Up @@ -62,7 +61,18 @@ public final Object render(Object extra) {
} }


public String widgetId() { public String widgetId() {
return getClass().getSimpleName() + "-" + UUID.randomUUID(); String type = getClass().getSimpleName().toLowerCase();
return type + seq(type);
}

public String seq(String seqName) {
String seq = "__seq_" + seqName;
int seqNum = (Integer) U.or(req().attrs().get(seq), 0);

seqNum++;
req().attrs().put(seq, seqNum);

return "" + seqNum;
} }


public boolean visible() { public boolean visible() {
Expand Down
Expand Up @@ -25,13 +25,11 @@
import org.rapidoid.annotation.Since; import org.rapidoid.annotation.Since;
import org.rapidoid.gui.GUI; import org.rapidoid.gui.GUI;
import org.rapidoid.gui.Grid; import org.rapidoid.gui.Grid;
import org.rapidoid.model.Items;
import org.rapidoid.model.Models;
import org.rapidoid.u.U; import org.rapidoid.u.U;


@Authors("Nikolche Mihajlovski") @Authors("Nikolche Mihajlovski")
@Since("2.0.0") @Since("5.1.0")
public class TableWidgetTest extends WidgetTestCommons { public class GridWidgetTest extends WidgetTestCommons {


@Test @Test
public void testTableWidget() { public void testTableWidget() {
Expand All @@ -41,9 +39,7 @@ public void testTableWidget() {
Person rambo = new Person("Rambo", 50); Person rambo = new Person("Rambo", 50);
rambo.id = 2; rambo.id = 2;


Items items = Models.beanItemsInfer(john, rambo); Grid table = GUI.grid(U.list(john, rambo)).pageSize(10);

Grid table = GUI.grid(items).pageSize(10);
verifyGUI("persons-grid", table); verifyGUI("persons-grid", table);


verifyGUI("map-grid", GUI.grid(U.map("name", "Foo", "year", "2016"))); verifyGUI("map-grid", GUI.grid(U.map("name", "Foo", "year", "2016")));
Expand Down
Expand Up @@ -47,11 +47,11 @@ public Object call() throws Exception {


info.add(h3("Classpath folders:")); info.add(h3("Classpath folders:"));


info.add(grid(ClasspathUtil.getClasspathFolders()).columns("trim").headers("Classpath entries (folders)")); info.add(grid(ClasspathUtil.getClasspathFolders()).columns("trim").headers("Classpath entries (folders)").pageSize(0));


info.add(h3("Classpath JARs:")); info.add(h3("Classpath JARs:"));


info.add(grid(ClasspathUtil.getClasspathJars()).columns("trim").headers("Classpath entries (JARs)")); info.add(grid(ClasspathUtil.getClasspathJars()).columns("trim").headers("Classpath entries (JARs)").pageSize(0));


return info; return info;
} }
Expand Down
9 changes: 1 addition & 8 deletions rapidoid-web/src/main/java/org/rapidoid/goodies/X.java
Expand Up @@ -13,12 +13,10 @@
import org.rapidoid.http.ReqRespHandler; import org.rapidoid.http.ReqRespHandler;
import org.rapidoid.http.Resp; import org.rapidoid.http.Resp;
import org.rapidoid.jpa.JPA; import org.rapidoid.jpa.JPA;
import org.rapidoid.lambda.Mapper;
import org.rapidoid.setup.On; import org.rapidoid.setup.On;
import org.rapidoid.setup.Setup; import org.rapidoid.setup.Setup;
import org.rapidoid.sql.JDBC; import org.rapidoid.sql.JDBC;
import org.rapidoid.u.U; import org.rapidoid.u.U;
import org.rapidoid.util.Msc;


import javax.persistence.metamodel.EntityType; import javax.persistence.metamodel.EntityType;
import java.util.List; import java.util.List;
Expand Down Expand Up @@ -136,12 +134,7 @@ public Object execute(Req req, Resp resp) throws Exception {
IRange range = Range.of((page - 1) * pageSize, pageSize); IRange range = Range.of((page - 1) * pageSize, pageSize);
List<?> records = JPA.of(entityType).page(range.start(), range.length()); List<?> records = JPA.of(entityType).page(range.start(), range.length());


Grid grid = GUI.grid(records).toUri(new Mapper<Object, String>() { Grid grid = GUI.grid(records);
@Override
public String map(Object target) throws Exception {
return Msc.uri(GUI.uriFor(baseUri, target), "view");
}
});


Btn add = GUI.btn("Add " + name(entityType)).primary().go(baseUri + "/add"); Btn add = GUI.btn("Add " + name(entityType)).primary().go(baseUri + "/add");


Expand Down

0 comments on commit e711dfb

Please sign in to comment.