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)#::::#(/resultTable)# -#(num-results)# - :: - :: - :: - - - - :: -#(/num-results)# + @@ -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)# + :: + + + +#(/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