Permalink
Browse files

(WIP) Optionally sort HTML search items via Javascript.

TODO: Expose a GUI setting for this.
  • Loading branch information...
JeremyRand committed Sep 3, 2017
1 parent 61be709 commit d37df75afaba7bcc18efa0a83f6e581b000db14d
Showing with 190 additions and 5 deletions.
  1. +5 −0 defaults/yacy.init
  2. +139 −0 htroot/js/yacysort.js
  3. +37 −5 htroot/yacysearch.html
  4. +9 −0 htroot/yacysearch.java
@@ -907,6 +907,11 @@ search.excludehosth=
# the cases of nocache, iffresh and ifexist causes an index deletion
search.verify.delete = true

# If enabled, the results are sorted in the browser using Javascript.
# This usually improves ranking accuracy, but doesn't work well for users
# who have Javascript disabled, are using screen readers, or are on slow computers.
search.jsresort = false

# remote search details
remotesearch.maxcount = 10
remotesearch.maxtime = 3000
@@ -0,0 +1,139 @@
var itemCount = 0;
var highestRanking = Infinity;

var displayPage = function() {
// For every search item that has already been displayed...
$("#resultscontainer .searchresults").each( function(i) {
// Apply the "earlierpage" class IFF the item is from an earlier page.
$(this).toggleClass("earlierpage", parseFloat($(this).data("ranking")) > highestRanking);
});

// For every search item from an earlier page...
$("#resultscontainer .searchresults.earlierpage").each( function(i) {
// Hide the item
$(this).removeClass("currentpage");
$(this).hide(1000);
});

// For every search item from a current or later page...
$("#resultscontainer .searchresults:not(.earlierpage)").each( function(i) {
// If we now have too many results, hide the lowest-ranking ones.
if (i >= requestedResults) {
$(this).removeClass("currentpage");
$(this).hide(1000);
}
else {
$(this).addClass("currentpage");
$(this).show(1000);
}
});

$("#offset").html($("#resultscontainer .searchresults.earlierpage").length + 1);
$("#itemscount").html($("#resultscontainer .searchresults.earlierpage").length + $("#resultscontainer .searchresults.currentpage").length);

console.log("Showing results " + ($("#resultscontainer .searchresults.earlierpage").length + 1) + " - " + ($("#resultscontainer .searchresults.earlierpage").length + requestedResults) + " out of " + $("#resultscontainer .searchresults").length + "; notEarlierPage = " + $("#resultscontainer .searchresults:not(.earlierpage)").length);
};

var earlierPage = function() {
// Find all items that are on an earlier page.
var allEarlierItems = $("#resultscontainer .searchresults.earlierpage");

// If going back one page would put us at the beginning...
if (allEarlierItems.length <= requestedResults) {
highestRanking = Infinity;
}
// If going back one page would still be in the middle of the results...
else {
var earlierItem = allEarlierItems.get().reverse()[ requestedResults - 1 ];
highestRanking = parseFloat($(earlierItem).data("ranking"));
console.log("highestRanking is now " + highestRanking);
}

// Update the display to show the new page.
displayPage();
};

var laterPage = function() {
// Find all items that are on a later page.
var allCurrentAndLaterItems = $("#resultscontainer .searchresults:not(.earlierpage)");

// If going forward one page would put us past the end...
if (allCurrentAndLaterItems.length <= requestedResults) {
return;
}
// If going forward one page would still be in the middle of the results...
else {
var laterItem = allCurrentAndLaterItems.get(requestedResults);
highestRanking = parseFloat($(laterItem).data("ranking"));
console.log("highestRanking is now " + highestRanking);
}

// Update the display to show the new page.
displayPage();
};

var processItem = function(data) {
var newItem = $(data).hide();

// If we didn't get a valid response from YaCy, wait 1 second and try again.
if( ! newItem.data("ranking") ) {
//console.log("Got undefined item, waiting 1 second...");
setTimeout(function() {
$.get(
"yacysearchitem.html",
{
eventID: theEventID,
item: itemCount
},
processItem
);
}, 1000);
return;
}

// For every search item that has already been displayed...
$("#resultscontainer .searchresults").each( function(i) {
// If the existing search item is lower-ranked than the new item...
if (parseFloat($(this).data("ranking")) <= parseFloat(newItem.data("ranking")) ) {
// Insert new item before the existing item
newItem.insertBefore(this);

return false;
}
// If the new item is lower-ranked than all existing items...
else if (i == $("#resultscontainer .searchresults").length - 1) {
// And if the new item (position i + 1) would be ranked 0 to requestedResults - 1...
if (i + 1 < requestedResults) {
// Insert new item at the end
newItem.appendTo("#resultscontainer");
return false;
}
// If the new item is too irrelevant to be displayed...
else {
// Insert new item at the end
newItem.appendTo("#resultscontainer");
console.log("Hiding search result because ranking " + newItem.data("ranking") + " too low.");
return false;
}
}
});

// Special case if this is the first search item...
if ($("#resultscontainer .searchresults").length === 0) {
// Display the new item
newItem.appendTo("#resultscontainer");
}

displayPage();

// Increment itemCount and get another item.
itemCount++;
$.get(
"yacysearchitem.html",
{
eventID: theEventID,
item: itemCount
},
processItem
);
};
@@ -12,6 +12,13 @@
<script type="text/javascript" src="js/highslide/highslide.js"></script>
<script type="text/javascript">hs.outlineType = 'rounded-white';</script>
<script type="text/javascript" src="env/bootstrap/js/typeahead.jquery.min.js"></script>
#(jsResort)#::
<script type="text/javascript">
var requestedResults = #[results]#;
var theEventID = "#[eventID]#";
</script>
<script type="text/javascript" src="js/yacysort.js"></script>
#(/jsResort)#
<script type="text/javascript">
var suggestMatcher = function() {
return function opensearch(q, cb) {
@@ -31,7 +38,19 @@
});
};
};
$(document).ready(function() {
#(jsResort)#::
$.get(
"yacysearchitem.html",
{
eventID: theEventID,
item: itemCount
},
processItem
);
#(/jsResort)#
$('#search').typeahead({hint:false,highlight:true,minLength:1}, {
name: 'states',
displayKey: 'value',
@@ -175,17 +194,26 @@ <h4 class="linktitle">

<!-- linklist begin -->
#(resultTable)#::<table width="100%"><tr class="TableHeader"><td width="30%">Media</td><td width="70%">URL</td></tr>#(/resultTable)#
#{results}#
<!--#include virtual="yacysearchitem.html?item=#[item]#&eventID=#[eventID]#" -->
#{/results}#
#(jsResort)#
#{results}#
<!--#include virtual="yacysearchitem.html?item=#[item]#&eventID=#[eventID]#" -->
#{/results}#
::
<div id="resultscontainer">
</div>
#(/jsResort)#
#(resultTable)#::</table>#(/resultTable)#
<!-- linklist end -->

#(num-results)#
::
::
::
<span id="resNav" class="col-sm-12 col-md-12" style="display: inline;"></span>
#(jsResort)#
<span id="resNav" class="col-sm-12 col-md-12" style="display: inline;"></span>
::
<p><br><br><a href="javascript:earlierPage();">Prev Page</a>&nbsp;&nbsp;&nbsp;&nbsp;<a href="javascript:laterPage();">Next Page</a></p>
#(/jsResort)#
::
#(/num-results)#

@@ -222,7 +250,11 @@ <h4 class="linktitle">
}
if(rsp && rsp.offset != null) {
statistics(rsp.offset, rsp.itemscount, rsp.itemsperpage, rsp.totalcount, rsp.localIndexCount, rsp.remoteIndexCount, rsp.remotePeerCount, rsp.navurlBase, #[localQuery]#, rsp.feedRunning);
#(jsResort)#
statistics(rsp.offset, rsp.itemscount, rsp.itemsperpage, rsp.totalcount, rsp.localIndexCount, rsp.remoteIndexCount, rsp.remotePeerCount, rsp.navurlBase, #[localQuery]#, rsp.feedRunning);
::
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);
#(/jsResort)#
if(rsp.feedRunning) {
/* Refresh statistics while server feeders are still running */
window.setTimeout(latestinfo, 1000);
@@ -835,14 +835,22 @@ public static serverObjects respond(
QueryParams.navurlBase(RequestHeader.FileType.HTML, theQuery, null, true).append("&startRecord=")
.append(startRecord).append("&resortCachedResults=true").toString());

prop.put("jsResort", sb.getConfigBool("search.jsresort", false) );
prop.put("num-results_jsResort", sb.getConfigBool("search.jsresort", false) );

// generate the search result lines; the content will be produced by another servlet
for ( int i = 0; i < theQuery.itemsPerPage(); i++ ) {
prop.put("results_" + i + "_item", startRecord + i);
prop.put("results_" + i + "_eventID", theQuery.id(false));

prop.put("jsResort_results_" + i + "_item", startRecord + i);
prop.put("jsResort_results_" + i + "_eventID", theQuery.id(false));
}
prop.put("results", theQuery.itemsPerPage());
prop.put("jsResort_results", theQuery.itemsPerPage());
prop.put("resultTable", (contentdom == ContentDomain.APP || contentdom == ContentDomain.AUDIO || contentdom == ContentDomain.VIDEO) ? 1 : 0);
prop.put("eventID", theQuery.id(false)); // for bottomline
prop.put("jsResort_eventID", theQuery.id(false));

// process result of search
if ( !filtered.isEmpty() ) {
@@ -864,6 +872,7 @@ public static serverObjects respond(

prop.put("depth", "0");
prop.put("localQuery", theSearch.query.isLocal() ? "1" : "0");
prop.put("jsResort_localQuery", theSearch.query.isLocal() ? "1" : "0");

}
prop.put("focus", focus ? 1 : 0); // focus search field

0 comments on commit d37df75

Please sign in to comment.