sirius.web.controller.Page Maven / Gradle / Ivy
Show all versions of sirius-web Show documentation
/*
* Made with all the love in the world
* by scireum in Remshalden, Germany
*
* Copyright by scireum GmbH
* http://www.scireum.de - [email protected]
*/
package sirius.web.controller;
import com.google.common.collect.Lists;
import sirius.kernel.cache.ValueComputer;
import sirius.kernel.commons.Monoflop;
import sirius.kernel.commons.Strings;
import sirius.kernel.nls.NLS;
import sirius.web.http.WebContext;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
/**
* Represents a slice of a result set which is being "paged through" and can provide filter facets.
*
* @param the type of object in the page
*/
public class Page {
private static final int DEFAULT_PAGE_SIZE = 25;
private String query;
private int start;
private int total;
private List items = Collections.emptyList();
private boolean more;
private String duration;
private List facets = Lists.newArrayList();
private Supplier> facetsSupplier;
private Boolean hasFacets = null;
private int pageSize = DEFAULT_PAGE_SIZE;
/**
* Specifies the query used to compute the result list.
*
* @param query the query string which was used to create the result set
* @return the page itself for fluent method calls
*/
public Page withQuery(String query) {
this.query = query;
return this;
}
/**
* Specifies the index of the first item.
*
* @param start the index of the first item shown on this page (relative to the overall list).
* @return the page itself for fluent method calls
*/
public Page withStart(int start) {
this.start = Math.max(start, 1);
return this;
}
/**
* Specifies the effective items this page contains.
*
* @param items the items contained in the page.
* @return the page itself for fluent method calls
*/
public Page withItems(List items) {
this.items = items;
return this;
}
/**
* Specifies the duration (as string) it took to compute (query) the page items.
*
* @param duration the duration required to compute the page items.
* @return the page itself for fluent method calls
*/
public Page withDuration(String duration) {
this.duration = duration;
return this;
}
/**
* Specifies the facets available to further filter the page (or underlying data source).
*
* @param facets the facets available for further filtering
* @return the page itself for fluent method calls
*/
public Page withFactes(List facets) {
this.facets.addAll(facets);
this.hasFacets = null;
return this;
}
/**
* Adds a filter facet with the given name, title and translator.
*
* @param field the name of the field being filtered
* @param title the title of the filter shown to the user
* @param translator the trnanslater used to convert filter values to visual representations for the user
* @return a newly created facet
*/
public Facet addFacet(String field, String title, @Nullable ValueComputer translator) {
Facet facet = new Facet(title, field, null, translator);
addFacet(facet);
return facet;
}
/**
* Adds a filter facet to this result page.
*
* @param facet the facet to add
* @return the page itself for fluent method calls
*/
public Page addFacet(Facet facet) {
if (this.facets == null) {
this.facets = Lists.newArrayList();
}
facets.add(facet);
facet.parent = this;
hasFacets = null;
return this;
}
/**
* Binds the page to the request.
*
* This will read start, query and all facet values from the given request.
*
* @param ctx the request to parse
* @return the page itself for fluent method calls
*/
public Page bindToRequest(WebContext ctx) {
if (ctx.get("start").isFilled()) {
withStart(ctx.get("start").asInt(1));
}
withQuery(ctx.get("query").asString());
for (Facet f : getFacets()) {
f.withValue(ctx.get(f.getName()).asString());
}
return this;
}
/**
* Specifies the supplier used to compute the facets available to further filter the page (or underlying data
* source).
*
* @param facetsSupplier the facets supplier computing the facets available for further filtering
* @return the page itself for fluent method calls
*/
public Page withFactesSupplier(Supplier> facetsSupplier) {
this.facetsSupplier = facetsSupplier;
return this;
}
/**
* Specifies the flag which indicates if "more" items are available.
*
* @param more indicates if more items are available or not.
* @return the page itself for fluent method calls
*/
public Page withHasMore(boolean more) {
this.more = more;
return this;
}
/**
* Specifies the number of items shown per page.
*
* @param pageSize the number of items shown per page
* @return the page itself for fluent method calls
*/
public Page withPageSize(int pageSize) {
this.pageSize = pageSize;
return this;
}
/**
* Specifies the number of total items.
*
* @param total the number of items in the data source (applying the current filters)
* @return the page itself for fluent method calls
*/
public Page withTotalItems(int total) {
this.total = total;
return this;
}
/**
* Returns the query string which was used to create the result set.
*
* @return the query string which was used to create the result set
*/
public String getQuery() {
return query == null ? "" : query;
}
/**
* Returns the absolute index (1 based) of the first item on this page.
*
* @return the one based index of the first item on this page
*/
public int getStart() {
return start;
}
/**
* Returns the absolute index (1 based) of the last item on this page.
*
* @return the one based index of the last item on this page
*/
public int getEnd() {
return start + items.size() - 1;
}
/**
* Returns the items on this page.
*
* @return the list of items on this page
*/
public List getItems() {
return items;
}
/**
* Returns the index of the previous page.
*
* @return the index of the first item of the previous page
*/
public int getPreviousStart() {
return Math.max(1, start - pageSize);
}
/**
* Returns the index of the next page.
*
* @return the index of the first item of the next page
*/
public int getNextStart() {
return start + pageSize;
}
/**
* Determines if there is a previous page.
*
* @return true if there is a page before this one
*/
public boolean hasLess() {
return start > 1;
}
/**
* Determines if there is a next page.
*
* @return true if there are more items in the underlying result
*/
public boolean hasMore() {
return more;
}
/**
* Returns a string representation naming the first and last index contained on this page.
*
* @return a string naming the first and last index of this page
*/
public String getRange() {
if (getItems().isEmpty()) {
return NLS.get("Page.noResults");
}
return start + " - " + getEnd();
}
/**
* Returns the search duration.
*
* @return a string representation of the search duration used to create the underlying result set
*/
public String getDuration() {
return duration;
}
/**
* Creates a query string containing all filters, the search query and a start parameter selecting the
* previous page.
*
* @return a query string selecting the previous page
*/
public String createPrevPageQueryString() {
return createQueryString("start", String.valueOf(getPreviousStart()), false);
}
/**
* Creates a query string containing all filters, the search query and a start parameter selecting the
* next page.
*
* @return a query string selecting the next page
*/
public String createNextPageQueryString() {
return createQueryString("start", String.valueOf(getNextStart()), false);
}
/**
* Creates a query string containing all filters and the search query and a start parameter selecting the
* current page.
*
* @return a query string selecting the current page
*/
public String createQueryString() {
return createQueryString(null, null, false);
}
/**
* Creates a query string containing all filters and the search query along with a given custom field.
*
* @param field the additional field to set
* @param value the value of the field to set
* @param resetStart determines if the start value should be kept (false) or reset to 1 (true)
* @return a query string containing all filters, the query and the given parameter
*/
public String createQueryString(String field, String value, boolean resetStart) {
StringBuilder sb = new StringBuilder();
boolean fieldFound = false;
Monoflop mf = Monoflop.create();
for (Facet f : getFacets()) {
if (Strings.areEqual(field, f.getName())) {
fieldFound = true;
if (Strings.isFilled(value)) {
sb.append(mf.firstCall() ? "" : "&");
sb.append(field);
sb.append("=");
sb.append(Strings.urlEncode(value));
}
} else if (Strings.isFilled(f.getValue())) {
sb.append(mf.firstCall() ? "" : "&");
sb.append(f.getName());
sb.append("=");
sb.append(Strings.urlEncode(f.getValue()));
}
}
if (!resetStart) {
sb.append(mf.firstCall() ? "" : "&");
sb.append("start=");
if ("start".equals(field)) {
fieldFound = true;
sb.append(value);
} else {
sb.append(start);
}
}
if ("query".equals(field)) {
sb.append(mf.firstCall() ? "" : "&");
sb.append("query=");
fieldFound = true;
sb.append(Strings.urlEncode(value));
} else if (Strings.isFilled(query)) {
sb.append(mf.firstCall() ? "" : "&");
sb.append("query=");
sb.append(Strings.urlEncode(query));
}
if (!fieldFound && Strings.isFilled(value)) {
sb.append(mf.firstCall() ? "" : "&");
sb.append(field);
sb.append("=");
sb.append(Strings.urlEncode(value));
}
return sb.toString();
}
/**
* Creates an incomplete query string to be completed by appending the start index.
* The Query String will contain all filters and the search query except 'start', for which the value must be
* appended.
*
* ex.:
*
* var startIndex = "33";
* $('a.config-start').attr("href", "@prefix/@[email protected]()" + startIndex);
*
*
* @return a query string missing the start value
*/
public String createQueryStringForConfigurableStart() {
String result = createQueryString(null, null, true);
if (Strings.isFilled(result)) {
return result + "&start=";
} else {
return "start=";
}
}
/**
* Returns all filter facets available.
*
* @return all filter facets of the underlying result set
*/
public List getFacets() {
if (facetsSupplier != null) {
facets.addAll(facetsSupplier.get());
facetsSupplier = null;
hasFacets = null;
}
if (hasFacets == null) {
hasFacets = false;
for (Facet facet : facets) {
facet.parent = this;
if (facet.hasItems()) {
hasFacets = true;
}
}
}
return facets;
}
/**
* Determines if there is at least one filter facet with filter items.
*
* @return true if there is at least one filter facet with items
*/
public boolean hasFacets() {
if (hasFacets == null) {
getFacets();
}
return hasFacets;
}
/**
* Returns the total page size.
*
* This not the number of items in the page but rather the general paging size currently being used.
*
* @return the max number of items in a page
* @see #DEFAULT_PAGE_SIZE
*/
public int getPageSize() {
return pageSize;
}
}