summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorluccioman <luccioman@users.noreply.github.com>2019-02-28 22:56:49 +0100
committerluccioman <luccioman@users.noreply.github.com>2019-02-28 22:56:49 +0100
commit6e9d5f60ad5455decaa8972efaa64c662606e5f0 (patch)
tree93d1ed59e5c89ee1da5e2045ee1385d286268bee
parent4b9cc4746db12e71e14ae237abee273d4cbfef53 (diff)
Server side initial pagination links rendering
For better support of the search page usage with JavaScript disabled. Reduces also the number of initial refreshes of the paginations links. When JavaScript is enabled, pagination links are still regularly refreshed until all the search feeds are terminated on server side.
-rw-r--r--htroot/js/yacysearch.js15
-rw-r--r--htroot/yacysearch.html18
-rw-r--r--htroot/yacysearchpagination.html22
-rw-r--r--htroot/yacysearchpagination.java135
4 files changed, 168 insertions, 22 deletions
diff --git a/htroot/js/yacysearch.js b/htroot/js/yacysearch.js
index 09305031d..dc9a19868 100644
--- a/htroot/js/yacysearch.js
+++ b/htroot/js/yacysearch.js
@@ -62,7 +62,8 @@ function renderPaginationButtons(buttonsList, offset, itemsperpage, totalcount,
var firstPage = thispage - (thispage % 10);
var prevPageElement = buttons[0];
- var prevPageLink = prevPageElement.firstChild;
+ var links = prevPageElement.getElementsByTagName("a");
+ var prevPageLink = links.length == 1 ? links[0] : null;
if (thispage == 0) {
/* First page : the prev page button is disabled */
prevPageElement.className = "disabled";
@@ -83,14 +84,12 @@ function renderPaginationButtons(buttonsList, offset, itemsperpage, totalcount,
}
}
- var nextPageElement = buttons[buttons.length - 1];
-
var totalPagesNb = Math.floor(1 + ((totalcount - 1) / itemsperpage));
var numberofpages = Math.min(10, totalPagesNb - firstPage);
if (!numberofpages) {
numberofpages = 10;
}
- if(numberofpages > 1) {
+ if(totalPagesNb > 1 && numberofpages >= 1) {
buttonsList.className = "pagination";
} else {
/* Hide the pagination buttons when there is less than one page of results */
@@ -140,7 +139,9 @@ function renderPaginationButtons(buttonsList, offset, itemsperpage, totalcount,
buttonsList.removeChild(buttons[buttons.length - 2]);
}
- var nextPageLink = nextPageElement.firstChild;
+ var nextPageElement = buttons[buttons.length - 1];
+ links = nextPageElement.getElementsByTagName("a");
+ var nextPageLink = links.length == 1 ? links[0] : null;
if ((localQuery && thispage >= (totalPagesNb - 1))
|| (!localQuery && thispage >= (numberofpages - 1))) {
/* Last page on a local query, or last fetchable page in p2p mode : the next page button is disabled */
@@ -181,7 +182,7 @@ function parseFormattedInt(strIntValue) {
return intValue;
}
-function statistics(offset, itemscount, itemsperpage, totalcount, localIndexCount, remoteIndexCount, remotePeerCount, navurlbase, localQuery, feedRunning, jsResort) {
+function statistics(offset, itemscount, itemsperpage, totalcount, localIndexCount, remoteIndexCount, remotePeerCount, navurlbase, localQuery, feedRunning, jsResort, updatePagination) {
var totalcountIntValue = parseFormattedInt(totalcount);
var offsetIntValue = parseFormattedInt(offset);
var itemscountIntValue = parseFormattedInt(itemscount);
@@ -259,7 +260,7 @@ function statistics(offset, itemscount, itemsperpage, totalcount, localIndexCoun
progresseBarElement.setAttribute('style',"width:" + percent + "%");
}
var buttonsList = document.getElementById("paginationButtons");
- if (buttonsList != null && !jsResort) {
+ if (buttonsList != null && !jsResort && updatePagination) {
renderPaginationButtons(buttonsList, offsetIntValue, itemsperpageIntValue, totalcountIntValue, navurlbase, localQuery, jsResort);
}
}
diff --git a/htroot/yacysearch.html b/htroot/yacysearch.html
index 824d4d23d..4d8cb281c 100644
--- a/htroot/yacysearch.html
+++ b/htroot/yacysearch.html
@@ -255,19 +255,7 @@ document.getElementById("Enter").innerHTML = "search again";
#(resultTable)#::</table>::</table>#(/resultTable)#
<!-- linklist end -->
-#(num-results)#
- ::
- ::
- ::
- <span id="resNav" class="col-sm-12 col-md-12" style="display: inline;">
- <ul id="paginationButtons" class="pagination hidden">
- <li id="prevpage" class="disabled"><a title="Previous page" href="#">&laquo;</a></li>
- <li class="active"><a href="#">1</a></li>
- <li id="nextpage" class="disabled"><a title="Next page" href="#">&raquo;</a></li>
- </ul>
- </span>
- ::
-#(/num-results)#
+<!--#include virtual="yacysearchpagination.html?eventID=#[eventID]#&maximumRecords=#[count]#&jsResort=#(jsResort)#false::true#(/jsResort)##(authSearch)#::&auth#(/authSearch)#" -->
</div> <!-- close main -->
@@ -306,9 +294,9 @@ function latestinfo() {
if(rsp && rsp.offset != null) {
#(jsResort)#
- statistics(rsp.offset, rsp.itemscount, rsp.itemsperpage, rsp.totalcount, rsp.localIndexCount, rsp.remoteIndexCount, rsp.remotePeerCount, rsp.navurlBase, #[localQuery]#, rsp.feedRunning, false);
+ statistics(rsp.offset, rsp.itemscount, rsp.itemsperpage, rsp.totalcount, rsp.localIndexCount, rsp.remoteIndexCount, rsp.remotePeerCount, rsp.navurlBase, #[localQuery]#, rsp.feedRunning, false, true);
::
- statistics($("#resultscontainer .searchresults.earlierpage").length + 1, $("#resultscontainer .searchresults.earlierpage").length + $("#resultscontainer .searchresults.currentpage").length, rsp.itemsperpage, rsp.totalcount, rsp.localIndexCount, rsp.remoteIndexCount, rsp.remotePeerCount, rsp.navurlBase, #[localQuery]#, rsp.feedRunning, true);
+ statistics($("#resultscontainer .searchresults.earlierpage").length + 1, $("#resultscontainer .searchresults.earlierpage").length + $("#resultscontainer .searchresults.currentpage").length, rsp.itemsperpage, rsp.totalcount, rsp.localIndexCount, rsp.remoteIndexCount, rsp.remotePeerCount, rsp.navurlBase, #[localQuery]#, rsp.feedRunning, true, false);
#(/jsResort)#
if(rsp.feedRunning) {
/* Refresh statistics while server feeders are still running */
diff --git a/htroot/yacysearchpagination.html b/htroot/yacysearchpagination.html
new file mode 100644
index 000000000..00b550f3d
--- /dev/null
+++ b/htroot/yacysearchpagination.html
@@ -0,0 +1,22 @@
+#(pagination)#
+ ::
+ <span id="resNav" class="col-sm-12 col-md-12" style="display: inline;">
+ <ul id="paginationButtons" class="pagination#(hidePagination)#:: hidden#(/hidePagination)#">
+ <li id="prevpage" class="#(prevDisabled)#::disabled#(/prevDisabled)#">
+ <a title="Previous page"
+ #(prevDisabled)#href="#[prevHref]#"::href="#"#(/prevDisabled)#
+ #(prevDisabled)#accesskey="p"#(/prevDisabled)#>&laquo;</a>
+ </li>
+ #{pages}#
+ <li class="#(active)#::active#(/active)#">
+ <a href="#(active)##[href]#::##(/active)#">#[pageNum]#</a>
+ </li>
+ #{/pages}#
+ <li id="nextpage" class="#(nextDisabled)#::disabled#(/nextDisabled)#">
+ <a title="Next page"
+ #(nextDisabled)#href="#[nextHref]#"::href="#"#(/nextDisabled)#
+ #(prevDisabled)#accesskey="n"#(/prevDisabled)#>&raquo;</a>
+ </li>
+ </ul>
+ </span>
+#(/pagination)# \ No newline at end of file
diff --git a/htroot/yacysearchpagination.java b/htroot/yacysearchpagination.java
new file mode 100644
index 000000000..52ba39c26
--- /dev/null
+++ b/htroot/yacysearchpagination.java
@@ -0,0 +1,135 @@
+
+// yacysearchpagination.java
+// ---------------------------
+// Copyright 2019 by luccioman; https://github.com/luccioman
+//
+// This is a part of YaCy, a peer-to-peer based web search engine
+//
+// LICENSE
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import net.yacy.cora.protocol.RequestHeader;
+import net.yacy.http.servlets.TemplateMissingParameterException;
+import net.yacy.search.Switchboard;
+import net.yacy.search.SwitchboardConstants;
+import net.yacy.search.query.QueryParams;
+import net.yacy.search.query.SearchEvent;
+import net.yacy.search.query.SearchEventCache;
+import net.yacy.server.serverObjects;
+import net.yacy.server.serverSwitch;
+
+/**
+ * Render yacysearch results page fragment containing pagination links.
+ */
+public class yacysearchpagination {
+
+ /** The maximum number of pagination links to render */
+ private static final int MAX_PAGINATION_LINKS = 10;
+
+ /**
+ * @param header servlet request headers
+ * @param post request parameters
+ * @param env server environment
+ * @return the servlet answer object
+ */
+ public static serverObjects respond(final RequestHeader header, final serverObjects post, final serverSwitch env) {
+ if (post == null) {
+ throw new TemplateMissingParameterException("The eventID parameter is required");
+ }
+
+ final serverObjects prop = new serverObjects();
+ final Switchboard sb = (Switchboard) env;
+ final String eventID = post.get("eventID");
+ if (eventID == null) {
+ throw new TemplateMissingParameterException("The eventID parameter is required");
+ }
+ final boolean jsResort = post.getBoolean("jsResort");
+ final boolean authFeatures = post.containsKey("auth");
+ final int defaultItemsPerPage = sb.getConfigInt(SwitchboardConstants.SEARCH_ITEMS, 10);
+
+ /* Detailed rules on items per page limits are handle in yacysearch.html */
+ int itemsPerPage = Math.max(1, post.getInt("maximumRecords", defaultItemsPerPage));
+
+ final SearchEvent theSearch = SearchEventCache.getEvent(eventID);
+ if (theSearch == null) {
+ /*
+ * the event does not exist in cache
+ */
+ prop.put("pagination", false);
+ } else {
+ prop.put("pagination", true);
+
+ final RequestHeader.FileType fileType = header.fileType();
+
+ if(jsResort) {
+ /* Pagination links are processed on browser side : just prepare prev and next buttons */
+ prop.put("pagination_hidePagination", true);
+ prop.put("pagination_prevDisabled", true);
+ prop.put("pagination_pages", 0);
+ prop.put("pagination_nextDisabled", true);
+ } else {
+ final int startRecord = post.getInt("startRecord", post.getInt("offset", post.getInt("start", 0)));
+ final int totalCount = theSearch.getResultCount();
+
+ final int activePage = (int) Math.floor(startRecord / (double) itemsPerPage);
+ final int firstLinkedPage = activePage - (activePage % MAX_PAGINATION_LINKS);
+ final int totalPagesNb = (int) Math.floor(1 + ((totalCount - 1) / (double) itemsPerPage));
+ final int displayedPagesNb = Math.min(MAX_PAGINATION_LINKS, totalPagesNb - firstLinkedPage);
+
+
+ prop.put("pagination_prevDisabled", activePage == 0);
+ prop.putUrlEncoded(fileType, "pagination_prevDisabled_prevHref", QueryParams
+ .navurl(fileType, Math.max(activePage - 1, 0), theSearch.query, null, false, authFeatures).toString());
+
+ prop.put("pagination_hidePagination", totalPagesNb <= 1 || displayedPagesNb < 1);
+
+ for (int i = 0; i < displayedPagesNb; i++) {
+ if (activePage == (firstLinkedPage + i)) {
+ prop.put("pagination_pages_" + i + "_active", true);
+ } else {
+ prop.put("pagination_pages_" + i + "_active", false);
+ prop.put("pagination_pages_" + i + "_active_pageIndex", (firstLinkedPage + i));
+ prop.putUrlEncoded(fileType, "pagination_pages_" + i + "_active_href",
+ QueryParams
+ .navurl(fileType, firstLinkedPage + i, theSearch.query, null, false, authFeatures)
+ .toString());
+ }
+ prop.put("pagination_pages_" + i + "_pageNum", firstLinkedPage + i + 1L);
+ }
+ prop.put("pagination_pages", displayedPagesNb);
+
+ final boolean localQuery = theSearch.query.isLocal();
+ if ((localQuery && activePage >= (totalPagesNb - 1))
+ || (!localQuery && activePage >= (displayedPagesNb - 1))) {
+ /*
+ * Last page on a local query, or last fetchable page in p2p mode : the next
+ * page button is disabled
+ */
+ prop.put("pagination_nextDisabled", true);
+ } else {
+ prop.put("pagination_nextDisabled", false);
+ prop.putUrlEncoded(fileType, "pagination_nextDisabled_nextHref", QueryParams
+ .navurl(fileType, activePage + 1, theSearch.query, null, false, authFeatures).toString());
+ }
+ }
+
+
+ }
+
+ return prop;
+ }
+
+} \ No newline at end of file