Commit 3e24352d authored by Citronalco's avatar Citronalco
Browse files

update jquery

search as you type
clicking in book metadata refines search
many bug fixes
_many_ improvements
parent 5aa81929
...@@ -61,12 +61,11 @@ body { ...@@ -61,12 +61,11 @@ body {
width: 16rem; width: 16rem;
} }
#searchfields input[type=radio] { #searchfields input[type=radio] {
margin-top: 0.5rem; margin-top: 0.8rem;
} }
#searchcontainer label.radio {
#searchfields label.radio {
text-align: left; text-align: left;
width: 4rem; width: auto;
line-height: 2em; line-height: 2em;
} }
...@@ -80,11 +79,14 @@ body { ...@@ -80,11 +79,14 @@ body {
#searchbar-bottom input[type=text] { #searchbar-bottom input[type=text] {
flex-grow: 5; flex-grow: 5;
max-width: 62rem; max-width: 62rem;
font-size: 80%;
} }
#searchbar-bottom input[type=button],input[type=submit] { #searchbar-bottom input[type=button],input[type=submit] {
width: 7rem; width: 7rem;
} }
#searchbar-bottom-readonly {
display: none;
}
#status { #status {
min-width: 14rem; min-width: 14rem;
...@@ -108,7 +110,7 @@ body { ...@@ -108,7 +110,7 @@ body {
/* booklist is a container for items of the class bookentry */ /* booklist is a container for items of the class bookentry */
#booklist { #booklist {
width: 100%; width: 100%;
padding-top: 14em; padding-top: 12em;
display: table; display: table;
} }
...@@ -159,7 +161,7 @@ div .bookcover { ...@@ -159,7 +161,7 @@ div .bookcover {
display: inline-block; display: inline-block;
margin-right: 10px; margin-right: 10px;
} }
.bookdata .download a { .bookdata a.download {
display: inline-block; display: inline-block;
background-color: #408ccb; background-color: #408ccb;
color: white; color: white;
...@@ -167,35 +169,31 @@ div .bookcover { ...@@ -167,35 +169,31 @@ div .bookcover {
border: 8px solid #408ccb; border: 8px solid #408ccb;
border-radius: 3px; border-radius: 3px;
} }
.bookdata .booktitle { .bookdata .title li {
font-size: 160%; font-size: 160%;
} }
.bookdata .bookauthors li { .bookdata .author li {
color: #43b49e; color: #43b49e;
cursor: pointer; cursor: pointer;
margin-bottom: 20px;
} }
.bookdata .bookdate li { .bookdata .year li {
color: #43b49e; color: #43b49e;
cursor: pointer; cursor: pointer;
} }
.bookdata .bookseries span { .bookdata .series li {
color: #43b49e; color: #43b49e;
cursor: pointer; cursor: pointer;
} }
.bookdata .language li {
.bookdata .booklanguages li {
background-color: #9a9a9a; background-color: #9a9a9a;
color: white; color: white;
font-size: 85%; font-size: 85%;
border: 3px solid #9a9a9a; border: 3px solid #9a9a9a;
border-radius: 3px; border-radius: 3px;
}
.bookdata .booklanguages li {
color: white;
cursor: pointer; cursor: pointer;
} }
.bookdata .identifier li {
.bookdata .bookidentifiers li {
background-color: #57b555; background-color: #57b555;
color: white; color: white;
font-size: 85%; font-size: 85%;
...@@ -203,21 +201,25 @@ div .bookcover { ...@@ -203,21 +201,25 @@ div .bookcover {
border-radius: 3px; border-radius: 3px;
} }
.bookdata .booktags li { .bookdata .tag li {
background-color: #5bc1df; background-color: #5bc1df;
color: white; color: white;
font-size: 85%; font-size: 85%;
border: 3px solid #5bc1df; border: 3px solid #5bc1df;
border-radius: 3px; border-radius: 3px;
}
.bookdata .booktags li {
color: white;
cursor: pointer; cursor: pointer;
}
.bookdata li.selected {
padding: 3px;
border: 3px solid red;
} }
.bookdata .bookdescription h1 { .bookdata .description label {
font-size: 120%; display: block;
font-weight: bold;
font-size: 110%;
padding-top: 10px;
padding-bottom: 5px;
} }
/* /*
...@@ -229,13 +231,14 @@ div .bookcover { ...@@ -229,13 +231,14 @@ div .bookcover {
@media (max-width: 1000px) { @media (max-width: 1000px) {
#searchfields { #searchfields {
display: none; visibility: hidden;
height: 0;
padding: 0;
} }
#searchbar-top label { #searchbar-top label {
display: none; display: none;
} }
#clearbutton { #clearbutton {
display: none;
} }
#status { #status {
display: none; display: none;
...@@ -243,6 +246,17 @@ div .bookcover { ...@@ -243,6 +246,17 @@ div .bookcover {
#searchbar-bottom { #searchbar-bottom {
display: none; display: none;
} }
#searchbar-bottom-readonly {
padding: 0;
font-size: 66%;
display: block;
height: 20px;
width: 100%;
}
#searchcontainer label {
width: auto;
line-height: 0;
}
#booklist { #booklist {
padding-top: 3rem; padding-top: 3rem;
} }
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<title>Ebook Suche</title> <title>Ebook Suche</title>
<link rel="stylesheet" type="text/css" media="screen" href="css/master.css" /> <link rel="stylesheet" type="text/css" media="screen" href="css/master.css" />
<script type="text/javascript" src="js/jquery-3.2.1.min.js"></script> <script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="js/mustache.min.js"></script> <script type="text/javascript" src="js/mustache.min.js"></script>
</head> </head>
...@@ -14,47 +14,44 @@ ...@@ -14,47 +14,44 @@
<script type="text/template" id="template-bookitem"> <script type="text/template" id="template-bookitem">
<div class="bookentry" id="book-{{{num}}}"> <div class="bookentry" id="book-{{{num}}}">
<div class="bookcover"> <div class="bookcover">
<a href="{{{bookurl}}}"> <a href="{{{url}}}">
<img src="{{{coverurl}}}" alt="Buchcover"></a> <img src="{{{coverurl}}}" alt="Buchcover"></a>
</div> </div>
<div class="bookdata"> <div class="bookdata">
<div class="download"> <a class="download" href="{{{url}}}">Download {{format}}</a>
<a href="{{{url}}}"> <div class="title">
Download {{format}}
</a>
</div>
<div class="booktitle">
<ul>{{{title}}}</ul> <ul>{{{title}}}</ul>
</div> </div>
<div class="bookauthors">
<div class="series">{{{series}}}</div>
<div class="author">
<ul>{{{authors}}}</ul> <ul>{{{authors}}}</ul>
</div> </div>
<div class="bookseries">
<ul>{{{series}}}</ul> <div class="language">
</div> <label>Sprache:</label>
<div class="booklanguages">
Sprache:
<ul>{{{languages}}}</ul> <ul>{{{languages}}}</ul>
</div> </div>
<div class="bookidentifiers"> <div class="identifier">
Kennungen: <label>Kennungen:</label>
<ul>{{{identifiers}}}</ul> <ul>{{{identifiers}}}</ul>
</div> </div>
<div class="booktags"> <div class="tag">
Schlagwörter: <label>Schlagwörter:</label>
<ul>{{{tags}}}</ul> <ul>{{{tags}}}</ul>
</div> </div>
<div class="bookpublisher"> <div class="publisher">
Herausgeber: <label>Herausgeber:</label>
<ul>{{publisher}}</ul> <ul>{{{publisher}}}</ul>
</div> </div>
<div class="bookdate"> <div class="year">
Herausgabedatum: <label>Erscheinungsdatum:</label>
<ul><li>{{date}}</li></ul> <ul>{{{year}}}</ul>
</div> </div>
<div class="bookdescription"> <div class="description">
<h1>Beschreibung</h1> <label>Beschreibung:</label>
{{description}} {{description}}
</div> </div>
</div> </div>
...@@ -67,7 +64,17 @@ ...@@ -67,7 +64,17 @@
var solr_url_prefix = '/ebooksearch/solr/select/'; var solr_url_prefix = '/ebooksearch/solr/select/';
// retrieve max. NUM results at once // retrieve max. NUM results at once
var query_limit = 5; var query_limit = 10;
var query_params = {
'text' : null,
'title' : null,
'author' : null,
'series' : null,
'language' : null,
'tag' : [],
'year' : null
}
$(function() { $(function() {
var start = 0; var start = 0;
...@@ -75,6 +82,9 @@ ...@@ -75,6 +82,9 @@
var cnt = 0; // counter for bookitems var cnt = 0; // counter for bookitems
var query = ''; var query = '';
var previous_query;
var previous_start_pos;
var scroll_load_finished = true; // Flag to avoid multiple AJAX calls at once when scrolling to bottom var scroll_load_finished = true; // Flag to avoid multiple AJAX calls at once when scrolling to bottom
//$('#searchfields').stop(false,true).slideDown('fast'); // start with searchfield visible //$('#searchfields').stop(false,true).slideDown('fast'); // start with searchfield visible
...@@ -89,7 +99,10 @@ ...@@ -89,7 +99,10 @@
}); });
function get_ebooks(start_pos) { function get_ebooks(start_pos) {
if (query) { if ((query) && !(query == previous_query && start_pos == previous_start_pos)) {
previous_query = query;
previous_start_pos = start_pos;
$('#status').removeClass('error').text('Suche läuft...'); $('#status').removeClass('error').text('Suche läuft...');
$.getJSON(solr_url_prefix + '/?q=' + encodeURIComponent(query) + '&wt=json&rows=' + query_limit + '&start=' + start_pos+ '&sort=date%20desc', function(data) { $.getJSON(solr_url_prefix + '/?q=' + encodeURIComponent(query) + '&wt=json&rows=' + query_limit + '&start=' + start_pos+ '&sort=date%20desc', function(data) {
if (data['responseHeader']['status'] != 0) { if (data['responseHeader']['status'] != 0) {
...@@ -112,9 +125,11 @@ ...@@ -112,9 +125,11 @@
$('body,html').scrollTop(0); $('body,html').scrollTop(0);
} }
var template = $('#template-bookitem').html(); // load template // load template
var template = $('#template-bookitem').html();
$.each(data['response']['docs'], function(key, val) { // fill template for each book // fill template for each book
$.each(data['response']['docs'], function(key, val) {
// Book URL // Book URL
var bookurl = calibre_url_prefix + '/' + val['path'] + '/' +val['filename'] var bookurl = calibre_url_prefix + '/' + val['path'] + '/' +val['filename']
...@@ -124,7 +139,7 @@ ...@@ -124,7 +139,7 @@
} }
// Book Title // Book Title
var booktitle = val['title_output']; var booktitle = '<li>' + htmlEncode(val['title_output']) + '</li>';
// Book Format // Book Format
var bookformat = val['filetype'].toUpperCase(); var bookformat = val['filetype'].toUpperCase();
...@@ -165,9 +180,9 @@ ...@@ -165,9 +180,9 @@
// Book Series // Book Series
var bookseries=''; var bookseries='';
if (val['series']) { if (val['series']) {
bookseries = '<span>' + htmlEncode(val['series']) + '</span>'; bookseries = htmlEncode(val['series']);
if (val['series_index']) { if (val['series_index']) {
bookseries = 'Band ' + htmlEncode(val['series_index']) + ' von ' + bookseries; bookseries = 'Band ' + htmlEncode(val['series_index']) + ' von <ul><li>' + bookseries + '</li></ul>';
} }
} }
...@@ -177,11 +192,11 @@ ...@@ -177,11 +192,11 @@
bookdescription=val['abstract_output']; bookdescription=val['abstract_output'];
} }
// Date // Year
var bookdate = val['year']; var bookyear = '<li>' + htmlEncode(val['year']) + '</li>';
// Publisher // Publisher
var bookpublisher = val['publisher']; var bookpublisher = '<li>' + htmlEncode(val['publisher']) + '</li>';
// stick everything in a array for Mustache to fill the Template // stick everything in a array for Mustache to fill the Template
var bookdata = { var bookdata = {
...@@ -194,7 +209,7 @@ ...@@ -194,7 +209,7 @@
tags: booktags, tags: booktags,
identifiers: bookidentifiers, identifiers: bookidentifiers,
series: bookseries, series: bookseries,
date: bookdate, year: bookyear,
publisher: bookpublisher, publisher: bookpublisher,
languages: booklanguages, languages: booklanguages,
description: bookdescription description: bookdescription
...@@ -202,8 +217,30 @@ ...@@ -202,8 +217,30 @@
var bookdetails = Mustache.render(template,bookdata); // fill template with values var bookdetails = Mustache.render(template,bookdata); // fill template with values
$('#booklist').append(bookdetails).children(':last').hide().fadeIn(1000); // append book to booklist $('#booklist').append(bookdetails).children(':last').hide().fadeIn(1000); // append book to booklist
// mark selected properties
for (var key in query_params) {
if (query_params[key]) {
if (Array.isArray(query_params[key])) {
for (var i = 0; i < query_params[key].length; i++) {
if (query_params[key][i]) {
$('div.bookdata>div.'+key+'>ul>li').each(function() {
if (query_params[key][i].toUpperCase() === $(this).text().toUpperCase()) {
$(this).addClass('selected');
}
});
}
}
}
else {
$('div.bookdata>div.'+key+'>ul>li').each(function() {
if (query_params[key].toUpperCase() === $(this).text().toUpperCase()) {
$(this).addClass('selected');
}
});
}
}
}
}); });
} }
}).fail(function() { }).fail(function() {
$('#status').addClass('error').text('Fehler'); $('#status').addClass('error').text('Fehler');
...@@ -211,51 +248,57 @@ ...@@ -211,51 +248,57 @@
scroll_load_finished = true; scroll_load_finished = true;
} }
} }
/* this makes the page unusable on smaller devices: */
/*
$('#searchcontainer').mouseenter(function(){
$('#searchfields').stop(false,true).slideDown('fast');
});
$('#searchcontainer').mouseleave(function(){
if (num_docs > 0) {
$('#searchfields').stop(false,true).slideUp('fast');
}
});
*/
/*
$('#searchcontainer:not("input[type=text]")').on("click",function(){
$('#searchfields').stop(false,true).slideToggle('fast');
});
*/
// construct solr query // construct solr query
function build_query() { function build_query() {
var form_params = { //var queryparts = new Array;
'title' : $('input#search_title').filter(':visible').val(), var queryparts = [];
'author' : $('input#search_author').filter(':visible').val(), for (var key in query_params) {
'series' : $('input#search_series').filter(':visible').val(), if (Array.isArray(query_params[key])) {
'text' : $('input#search_text').filter(':visible').val(), for (var i = 0; i < query_params[key].length; i++) {
'year' : $('input#search_year').filter(':visible').val(), if (query_params[key][i]) {
'tag' : $('input#search_tag').filter(':visible').val(), queryparts.push( key + ':' + '(' + escape_lucene(query_params[key][i]) + ')' );
'language' : $('#language input:checked').filter(':visible').val() }
} }
var queryparts = new Array; }
for (var key in form_params) { else if (query_params[key]) {
if (form_params[key]) { queryparts.push( key + ':' + '(' + escape_lucene(query_params[key]) + ')' );
queryparts.push( key + ':' + '(' + form_params[key] + ')' );
} }
} }
query = queryparts.join(' AND '); return queryparts.join(' AND ');
return query
}; };
// escape special characters solr in solr query
function escape_lucene(s) {
var escape = ['+', '-', '&', '!', '(', ')', '{', '}', '[', ']', '^', '"', '~', '*', '?', ':', '\\'];
var regexp = new RegExp("(\\" + escape.join("|\\") + ")", "g");
return s.replace(regexp, "\\$1");
}
// clear button // clear button
$('#clearbutton').on("click",function() { $('#clearbutton').on("click",function() {
reset_form(); $('span#solr_query_readonly').text('');
$("#searchcontainer").find('input:text').val('');
$('span#solr_query_readonly').text('');
$("#search_lang_any").prop("checked",true);
query = null;
query_params = {
'text' : null,
'title' : null,
'author' : null,
'series' : null,
'year' : null,
'tag' : [],
'language' : null
}
}); });
// mark search form as irrelevant if solr query gets changed // mark search form as "irrelevant" if solr query gets changed
$('#solr_query').bind('change keyup',function() { $('#solr_query').bind('init change keyup paste',function() {
console.log("solr__query_init");
if ($('input#solr_query').val() != build_query()) { if ($('input#solr_query').val() != build_query()) {
$('#searchfields').addClass('irrelevant'); $('#searchfields').addClass('irrelevant');
$('#searchbar-top').addClass('irrelevant'); $('#searchbar-top').addClass('irrelevant');
...@@ -264,91 +307,110 @@ ...@@ -264,91 +307,110 @@
$('#searchfields').removeClass('irrelevant'); $('#searchfields').removeClass('irrelevant');
$('#searchbar-top').removeClass('irrelevant'); $('#searchbar-top').removeClass('irrelevant');
} }
}); query = $('input#solr_query').val();
get_ebooks(start_pos=0);
}).trigger('init');
// update solr query if search form values change $.each(query_params, function(key,value) {
$('#searchfields,#searchbar-top input:text').bind('change keyup',function() { $(document).on('change keyup paste','#searchfields>div>input[name='+key+'],#searchbar-top>input[name='+key+']',function() {
$('input#solr_query').val(build_query()).change(); $('#searchfields').removeClass('irrelevant');
}); $('#searchbar-top').removeClass('irrelevant');