/*
* Copyright (C) 2013-2017 NTT DATA Corporation
*
* 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.
*/
package org.terasoluna.gfw.web.pagination;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import javax.servlet.jsp.JspException;
import org.springframework.data.domain.Page;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.tags.RequestContextAwareTag;
import org.springframework.web.servlet.tags.form.TagWriter;
import org.terasoluna.gfw.web.pagination.PaginationInfo.BeginAndEnd;
import org.terasoluna.gfw.web.util.JspTagUtils;
/**
* JSP tag that provides pagination functionality<br>
*/
public class PaginationTag extends RequestContextAwareTag {
/**
* Page object
*/
private Object page;
/**
* Path template of pagination
*/
private String pathTmpl = PaginationInfo.DEFAULT_PATH_TEMPLATE;
/**
* Query template of pagination
*/
private String queryTmpl = PaginationInfo.DEFAULT_QUERY_TEMPLATE;
/**
* Query of search criteria
* @since 1.0.1
*/
private String criteriaQuery;
/**
* Flag to indicate whether html escaping of criteriaQuery is to be disabled or not
* @since 1.0.1
*/
private boolean disableHtmlEscapeOfCriteriaQuery;
/**
* Flag to enable the link of current page.
* @since 5.0.0
*/
private boolean enableLinkOfCurrentPage;
/**
* Maximum display count
*/
private int maxDisplayCount = PaginationInfo.DEFAULT_MAX_DISPLAY_COUNT;
/**
* Outer tag of HTML that make up pagination
*/
private String outerElement = PaginationInfo.DEFAULT_OUTER_ELM;
/**
* Value of "class" attribute of outer tag of pagination
*/
private String outerElementClass = PaginationInfo.DEFAULT_OUTER_CLASS;
/**
* Inner tag of HTML that make up pagination
*/
private String innerElement = PaginationInfo.DEFAULT_INNER_ELM;
/**
* Display text of the link of back to the top
*/
private String firstLinkText = PaginationInfo.DEFAULT_FIRST_LINK_TEXT;
/**
* Display text of the link of back to previous
*/
private String previousLinkText = PaginationInfo.DEFAULT_PREVIOUS_LINK_TEXT;
/**
* Display text of the link to proceed to the next
*/
private String nextLinkText = PaginationInfo.DEFAULT_NEXT_LINK_TEXT;
/**
* Display text of the link to forward to the last page
*/
private String lastLinkText = PaginationInfo.DEFAULT_LAST_LINK_TEXT;
/**
* Anchor link which is set when the link is disabled.
*/
private String disabledHref = PaginationInfo.DEFAULT_DISABLED_HREF;
/**
* Class name that enables the link
*/
private String activeClass = PaginationInfo.DEFAULT_ACTIVE_CLASS;
/**
* Class name that enables the link
*/
private String disabledClass = PaginationInfo.DEFAULT_DISABLED_CLASS;
/**
* serialVersionUID
*/
private static final long serialVersionUID = 6608906896698983954L;
/**
* create {@code TagWriter} instance.
* @return {@code TagWriter} instance that will render the content of the tag to JSP page.
*/
TagWriter createTagWriter() {
TagWriter tagWriter = new TagWriter(this.pageContext);
return tagWriter;
}
/**
* Renders a pagination link.
* @return {@link javax.servlet.jsp.tagext.Tag#EVAL_BODY_INCLUDE}
* @throws Exception If fail a tag writing
*/
@Override
protected int doStartTagInternal() throws Exception {
if (page instanceof Page) {
Page<?> p = (Page<?>) page;
if (p.getTotalElements() <= 0) {
return EVAL_BODY_INCLUDE;
}
TagWriter tagWriter = createTagWriter();
PaginationInfo info = new PaginationInfo(p, pathTmpl, queryTmpl, criteriaQuery, disableHtmlEscapeOfCriteriaQuery, maxDisplayCount);
BeginAndEnd be = info.getBeginAndEnd();
startOuterElement(tagWriter);
writeFirstAndPreviousLink(tagWriter, info);
for (int i = be.getBegin(); i <= be.getEnd(); i++) {
writePageLink(tagWriter, info, i);
}
writeNextAndLastLink(tagWriter, info);
endOuterElement(tagWriter);
}
return EVAL_BODY_INCLUDE;
}
/**
* Renders a anchor.<br>
* @param tagWriter {@code TagWriter} instance that will render the content of the tag to JSP page
* @param href url of anchor
* @param value text of anchor
* @throws JspException If fail a tag writing
*/
protected void writeAnchor(TagWriter tagWriter, String href, String value) throws JspException {
if (StringUtils.hasText(href)) {
tagWriter.startTag(PaginationInfo.A_ELM);
tagWriter.writeAttribute(PaginationInfo.HREF_ATTR, href);
tagWriter.appendValue(value);
tagWriter.endTag(true);
} else {
tagWriter.appendValue(value);
}
}
/**
* Renders start tag.
* @param tagWriter {@code TagWriter} instance that will render the content of the tag to JSP page
* @throws JspException If fail a tag writing
*/
protected void startOuterElement(TagWriter tagWriter) throws JspException {
if (StringUtils.hasText(outerElement)) {
tagWriter.startTag(outerElement);
if (StringUtils.hasText(outerElementClass)) {
tagWriter.writeAttribute(PaginationInfo.CLASS_ATTR,
outerElementClass);
}
}
}
/**
* Renders end tag.<br>
* @param tagWriter {@code TagWriter} instance that will render the content of the tag to JSP page
* @throws JspException If fail a tag writing
*/
protected void endOuterElement(TagWriter tagWriter) throws JspException {
if (StringUtils.hasText(outerElement)) {
tagWriter.endTag(true); // ul
}
}
/**
* Renders page link.<br>
* @param tagWriter {@code TagWriter} instance that will render the content of the tag to JSP page
* @param info {@code PaginationInfo} instance the holds all the information required by the {@code PaginationTag}
* @param page page position
* @throws JspException If fail a tag writing
*/
protected void writePageLink(TagWriter tagWriter, PaginationInfo info,
int page) throws JspException {
tagWriter.startTag(innerElement); // <li>
if (info.isCurrent(page)) {
tagWriter.writeAttribute(PaginationInfo.CLASS_ATTR, activeClass);
if (enableLinkOfCurrentPage) {
writeAnchor(tagWriter, info.getPageUrl(page), String
.valueOf(page + 1)); // a
} else {
writeAnchor(tagWriter, disabledHref, String.valueOf(page + 1)); // a
}
} else {
writeAnchor(tagWriter, info.getPageUrl(page), String
.valueOf(page + 1)); // a
}
tagWriter.endTag(true); // </li>
}
/**
* Renders link for going to the first page and previous page.<br>
* @param tagWriter {@code TagWriter} instance that will render the content of the tag to JSP page
* @param info {@code PaginationInfo} instance the holds all the information required by the {@code PaginationTag}
* @throws JspException If fail a tag writing
*/
protected void writeFirstAndPreviousLink(TagWriter tagWriter,
PaginationInfo info) throws JspException {
if (info.isFirstPage()) {
if (StringUtils.hasText(firstLinkText)) {
// write first link
tagWriter.startTag(innerElement); // <li>
tagWriter.writeAttribute(PaginationInfo.CLASS_ATTR,
disabledClass);
writeAnchor(tagWriter, disabledHref, firstLinkText); // a
tagWriter.endTag(true); // </li>
}
if (StringUtils.hasText(previousLinkText)) {
// write previous link
tagWriter.startTag(innerElement); // <li>
tagWriter.writeAttribute(PaginationInfo.CLASS_ATTR,
disabledClass);
writeAnchor(tagWriter, disabledHref, previousLinkText); // a
tagWriter.endTag(true); // </li>
}
} else {
if (StringUtils.hasText(firstLinkText)) {
// write first link
tagWriter.startTag(innerElement); // <li>
writeAnchor(tagWriter, info.getFirstUrl(), firstLinkText); // a
tagWriter.endTag(true); // </li>
}
if (StringUtils.hasText(previousLinkText)) {
// write previous link
tagWriter.startTag(innerElement); // <li>
writeAnchor(tagWriter, info.getPreviousUrl(), previousLinkText); // a
tagWriter.endTag(true); // </li>
}
}
}
/**
* Renders link for going to the next page and last page <br>
* @param tagWriter {@code TagWriter} instance that will render the content of the tag to JSP page
* @param info {@code PaginationInfo} instance the holds all the information required by the {@code PaginationTag}
* @throws JspException If fail a tag writing
*/
protected void writeNextAndLastLink(TagWriter tagWriter, PaginationInfo info) throws JspException {
if (info.isLastPage()) {
if (StringUtils.hasText(nextLinkText)) {
// write next link
tagWriter.startTag(innerElement); // <li>
tagWriter.writeAttribute(PaginationInfo.CLASS_ATTR,
disabledClass);
writeAnchor(tagWriter, disabledHref, nextLinkText); // a
tagWriter.endTag(true); // </li>
}
if (StringUtils.hasText(lastLinkText)) {
// write last link
tagWriter.startTag(innerElement); // <li>
tagWriter.writeAttribute(PaginationInfo.CLASS_ATTR,
disabledClass); // a
writeAnchor(tagWriter, disabledHref, lastLinkText);
tagWriter.endTag(true); // </li>
}
} else {
if (StringUtils.hasText(nextLinkText)) {
// write next link
tagWriter.startTag(innerElement); // <li>
writeAnchor(tagWriter, info.getNextUrl(), nextLinkText); // a
tagWriter.endTag(true); // </li>
}
if (StringUtils.hasText(lastLinkText)) {
// write last link
tagWriter.startTag(innerElement); // <li>
writeAnchor(tagWriter, info.getLastUrl(), lastLinkText); // a
tagWriter.endTag(true); // </li>
}
}
}
/**
* Release state.
* <p>
* Set to null all fields.
* </p>
*/
@Override
public void release() {
super.release();
this.page = null;
this.pathTmpl = null;
this.queryTmpl = null;
this.criteriaQuery = null;
this.disableHtmlEscapeOfCriteriaQuery = false;
this.enableLinkOfCurrentPage = false;
this.outerElement = null;
this.outerElementClass = null;
this.innerElement = null;
this.firstLinkText = null;
this.previousLinkText = null;
this.nextLinkText = null;
this.lastLinkText = null;
this.disabledHref = null;
this.activeClass = null;
this.disabledClass = null;
}
/**
* Set page object<br>
* @param page a Page instance
*/
public void setPage(Object page) {
this.page = page;
}
/**
* Set path template of pagination<br>
* @param pathTmpl Path template of pagination
*/
public void setPathTmpl(String pathTmpl) {
this.pathTmpl = pathTmpl;
}
/**
* Set query template of pagination<br>
* @param queryTmpl Query template of pagination
*/
public void setQueryTmpl(String queryTmpl) {
this.queryTmpl = queryTmpl;
}
/**
* Set query of search criteria<br>
* @param criteriaQuery Query of search criteria
* @since 1.0.1
*/
public void setCriteriaQuery(String criteriaQuery) {
this.criteriaQuery = criteriaQuery;
}
/**
* Sets the value for disableHtmlEscapeOfCriteriaQuery property.
* <p>
* IF set to true, html escaping of criteriaQuery is disabled. <br>
* By default, disableHtmlEscapeOfCriteriaQuery is set to <code>false</code>. This means <br>
* html escaping is enable and will be performed by default.
* @param disableHtmlEscapeOfCriteriaQuery value of disableHtmlEscapeOfCriteriaQuery
* @throws JspException If value that is not true or false is specified.
* @since 1.0.1
*/
public void setDisableHtmlEscapeOfCriteriaQuery(
String disableHtmlEscapeOfCriteriaQuery) throws JspException {
this.disableHtmlEscapeOfCriteriaQuery = JspTagUtils.toBoolean(
disableHtmlEscapeOfCriteriaQuery, false,
"disableHtmlEscapeOfCriteriaQuery");
}
/**
* Sets the value for enableLinkOfCurrentPage property.
* <p>
* IF set to true, link of current page is enabled. <br>
* By default, enableLinkOfCurrentPage is set to <code>false</code>. This means <br>
* link of current page is disabled by default.
* @param enableLinkOfCurrentPage value of enableLinkOfCurrentPage
* @throws JspException If value that is not true or false is specified.
* @since 5.0.0
*/
public void setEnableLinkOfCurrentPage(String enableLinkOfCurrentPage) throws JspException {
this.enableLinkOfCurrentPage = JspTagUtils.toBoolean(
enableLinkOfCurrentPage, false, "enableLinkOfCurrentPage");
}
/**
* Set maximum display count<br>
* @param maxDisplayCount Maximum display count
*/
public void setMaxDisplayCount(int maxDisplayCount) {
this.maxDisplayCount = maxDisplayCount;
}
/**
* Set outer tag of HTML that make up pagination<br>
* @param outerElement Outer tag of HTML that make up pagination
*/
public void setOuterElement(String outerElement) {
this.outerElement = outerElement;
}
/**
* Set value of "class" attribute of outer tag of pagination <br>
* @param outerElementClass Value of "class" attribute of outer tag of pagination
*/
public void setOuterElementClass(String outerElementClass) {
this.outerElementClass = outerElementClass;
}
/**
* Set inner tag of HTML that make up pagination <br>
* @param innerElement Inner tag of HTML that make up pagination
*/
public void setInnerElement(String innerElement) {
this.innerElement = innerElement;
}
/**
* Set display text of the link of back to the top <br>
* @param firstLinkText Display text of the link of back to the top
*/
public void setFirstLinkText(String firstLinkText) {
this.firstLinkText = firstLinkText;
}
/**
* Set display text of the link of back to previous <br>
* @param previousLinkText Display text of the link of back to previous
*/
public void setPreviousLinkText(String previousLinkText) {
this.previousLinkText = previousLinkText;
}
/**
* Set display text of the link to proceed to the next <br>
* @param nextLinkText Display text of the link to proceed to the next
*/
public void setNextLinkText(String nextLinkText) {
this.nextLinkText = nextLinkText;
}
/**
* Set display text of the link to forward to the last page <br>
* @param lastLinkText Display text of the link to forward to the last page
*/
public void setLastLinkText(String lastLinkText) {
this.lastLinkText = lastLinkText;
}
/**
* Set anchor link which is set when the link is disabled. <br>
* @param disabledHref Anchor link which is set when the link is disabled
*/
public void setDisabledHref(String disabledHref) {
this.disabledHref = disabledHref;
}
/**
* Set class name that enables the link <br>
* @param activeClass Class name that enables the link
*/
public void setActiveClass(String activeClass) {
this.activeClass = activeClass;
}
/**
* Set class name that enables the link <br>
* @param disabledClass Class name that enables the link
*/
public void setDisabledClass(String disabledClass) {
this.disabledClass = disabledClass;
}
/**
* special handling for the serialization and deserialization process
* @param out ObjectOutputStream
* @throws IOException
* @see java.io.Serializable
*/
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
}
/**
* special handling for the serialization and deserialization process
* @param in ObjectInputStream
* @throws IOException
* @throws ClassNotFoundException
* @see java.io.Serializable
*/
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
}
}