Skip to content
Permalink
Browse files

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.
  • Loading branch information...
luccioman committed Feb 28, 2019
1 parent 4b9cc47 commit 6e9d5f60ad5455decaa8972efaa64c662606e5f0
Showing with 168 additions and 22 deletions.
  1. +8 −7 htroot/js/yacysearch.js
  2. +3 −15 htroot/yacysearch.html
  3. +22 −0 htroot/yacysearchpagination.html
  4. +135 −0 htroot/yacysearchpagination.java
@@ -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);
}
}
@@ -255,19 +255,7 @@ <h4 class="linktitle">
#(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 @@ <h4 class="linktitle">
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 */
@@ -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)#
@@ -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;
}

}

0 comments on commit 6e9d5f6

Please sign in to comment.
You can’t perform that action at this time.