Owen Leonard
e12e0ef016
This patch updates the browse search interface to confirm to new interface patterns in the Bootstrap 4 framework, especially in the form markup. The results list has been changed to a Bootstrap "Collapse" component configured as an accordion (https://getbootstrap.com/docs/4.5/components/collapse/#accordion-example). Instead of loading the bibliographic record results below the list of terms returned, the bibliographic results are now displayed in the "panel" expanded below the selected term. Subtitle has been added to the information displayed about the bibliographic record. To test you must be using ElasticSearch and the OpacBrowseSearch preference must be enabled. Apply the patch and rebuild the OPAC CSS (https://wiki.koha-community.org/wiki/Working_with_SCSS_in_the_OPAC_and_staff_client). - Open the "Browse search" page in the OPAC. - Test various searches: Author, Subject, and Title. - When results are found, the should be displayed as a Bootstrap-styled accordion widget. Clicking any individual result should expand the panel containing the corresponding records. - Clicking the record link should open the bibliographic detail page in a new window. - When no results are found, a Bootstrap-style "alert" box should appear. Signed-off-by: Victor Grousset/tuxayo <victor@tuxayo.net> Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
151 lines
6.2 KiB
JavaScript
151 lines
6.2 KiB
JavaScript
jQuery.fn.overflowScrollReset = function() {
|
|
$(this).scrollTop($(this).scrollTop() - $(this).offset().top);
|
|
return this;
|
|
};
|
|
|
|
$(document).ready(function(){
|
|
var xhrGetSuggestions, xhrGetResults;
|
|
|
|
$('#browse-search form').submit(function(event) {
|
|
// if there is an in progress request, abort it so we
|
|
// don't end up with a race condition
|
|
if(xhrGetSuggestions && xhrGetSuggestions.readyState != 4){
|
|
xhrGetSuggestions.abort();
|
|
}
|
|
|
|
var userInput = $('#browse-searchterm').val().trim();
|
|
var userField = $('#browse-searchfield').val();
|
|
var userFuzziness = $('input[name=browse-searchfuzziness]:checked', '#browse-searchfuzziness').val();
|
|
var card_template = $("#card_template");
|
|
|
|
event.preventDefault();
|
|
|
|
if(!userInput) {
|
|
return;
|
|
}
|
|
|
|
/* return the browsing results to empty state in case previous results have been loaded */
|
|
$("#browse-searchresults").empty().append( card_template );
|
|
|
|
// remove any error states and show the results area
|
|
$('#browse-suggestionserror').addClass('d-none');
|
|
$('.no-results').addClass('d-none');
|
|
$('#browse-resultswrapper').removeClass('d-none');
|
|
/* Reset results browser to default state */
|
|
|
|
// show the spinner
|
|
$('.loading').removeClass('d-none');
|
|
|
|
xhrGetSuggestions = $.get(window.location.pathname, {api: "GetSuggestions", field: userField, prefix: userInput, fuzziness: userFuzziness})
|
|
.always(function() {
|
|
// hide spinner
|
|
$('.loading').addClass('d-none');
|
|
})
|
|
.done(function(data) {
|
|
var fragment = document.createDocumentFragment();
|
|
|
|
if (data.length === 0) {
|
|
$('.no-results').removeClass('d-none');
|
|
return;
|
|
}
|
|
|
|
// store the type of search that was performed as an attrib
|
|
$('#browse-searchresults').data('field', userField);
|
|
|
|
$.each(data, function(index, object) {
|
|
// use a document fragment so we don't need to nest the elems
|
|
// or append during each iteration (which would be slow)
|
|
var card = card_template.clone().removeAttr("id");
|
|
// change card-header id
|
|
card
|
|
.find(".card-header")
|
|
.attr("id", "heading" + index)
|
|
.find("a").attr("data-target", "#collapse" + index)
|
|
.attr("aria-controls", "collapse" + index)
|
|
.text(object.text);
|
|
card
|
|
.find(".collapse")
|
|
.attr("id", "collapse" + index)
|
|
.attr("aria-labelledby", "heading" + index);
|
|
$(fragment).append(card);
|
|
});
|
|
|
|
$('#browse-searchresults').append(fragment.cloneNode(true));
|
|
})
|
|
.fail(function(jqXHR) {
|
|
//if 500 or 404 (abort is okay though)
|
|
if (jqXHR.statusText !== "abort") {
|
|
$('#browse-resultswrapper').addClass('d-none');
|
|
$('#browse-suggestionserror').removeClass('d-none');
|
|
}
|
|
});
|
|
});
|
|
|
|
$('#browse-searchresults').on("click", 'a.expand-result', function(event) {
|
|
// if there is an in progress request, abort it so we
|
|
// don't end up with a race condition
|
|
if(xhrGetResults && xhrGetResults.readyState != 4){
|
|
xhrGetResults.abort();
|
|
}
|
|
|
|
var link = $(this);
|
|
var target = link.data("target");
|
|
var term = link.text();
|
|
|
|
var field = $('#browse-searchresults').data('field');
|
|
|
|
event.preventDefault();
|
|
|
|
/* Don't load data via AJAX if it has already been loaded */
|
|
if ($(target).find(".result-title").length == 0) {
|
|
// do the query for the term
|
|
xhrGetResults = $.get(window.location.pathname, {api: "GetResults", field: field, term: term})
|
|
.done(function(data) {
|
|
var fragment = document.createDocumentFragment();
|
|
|
|
if (data.length === 0) {
|
|
$('#browse-selectionsearch .no-results').removeClass('d-none');
|
|
return;
|
|
}
|
|
|
|
|
|
$.each(data, function(index, object) {
|
|
// use a document fragment so we don't need to nest the elems
|
|
// or append during each iteration (which would be slow)
|
|
var elem = document.createElement("div");
|
|
elem.className = "result-title";
|
|
|
|
var destination = window.location.pathname;
|
|
destination = destination.replace("browse", "detail");
|
|
destination = destination + "?biblionumber=" + object.id;
|
|
|
|
var link = document.createElement("a");
|
|
link.setAttribute("href", destination);
|
|
link.setAttribute("target", "_blank");
|
|
link.textContent = object.title;
|
|
if( object.subtitle ){
|
|
link.textContent += " " + object.subtitle;
|
|
}
|
|
elem.appendChild(link);
|
|
|
|
if( object.author ){
|
|
var author = document.createElement("span");
|
|
author.className = "author";
|
|
author.textContent = " " + object.author;
|
|
elem.appendChild(author);
|
|
}
|
|
fragment.appendChild(elem);
|
|
});
|
|
|
|
$( target ).find(".card-body").append(fragment.cloneNode(true));
|
|
})
|
|
.fail(function(jqXHR) {
|
|
//if 500 or 404 (abort is okay though)
|
|
if (jqXHR.statusText !== "abort") {
|
|
$('#browse-resultswrapper').addClass('d-none');
|
|
$('#browse-suggestionserror').removeClass('d-none');
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|