Commit f7f540d4 authored by Christoph Glaubitz's avatar Christoph Glaubitz
Browse files

added a little single file jquery based webui

with documentation how to use this with nginx for serving books as
static assets.
parent abbcb352
......@@ -71,18 +71,54 @@ result set via xpath, talking to http api using requests_.
(See python-workshop_).
Next Steps...
`````````````
Little webui
````````````
... that will very likely never happen ;)
I just added a little webui based on jquery_. This only queries solr for json
results and show author, title, cover and description.
As a requirement, your library must be at::
* Hacking a little web UI for querying solr
* Must be mobile compatible to look nice on Kindle
* Serve mobi files as static assets
$DOCUMENTROOT/books
However, your DOCUMENTROOT should look like this::
.
|-- books -> /YOUR/EBOOK/LIBRARY
|-- css
|   |-- master.css
|-- img
|   |-- next_book.png
|   |-- next.png
|   |-- prev_book.png
|   |-- prev.png
|   |-- top.png
|-- index.html
|-- js
|-- jquery-2.1.1.min.js
You have to configure your webserver to pass requests to /ebooks directly to
solr. This is how to do it with nginx_::
location /ebooks {
proxy_pass http://localhost:8983/ebooks;
}
This is what it looks like.
.. image:: screen.png
Unfortunately, the buttons with internal references does not work on the
Kindle :/
.. _calibre: http://calibre-ebook.com/
.. _solr: http://lucene.apache.org/solr/
.. _requests: http://docs.python-requests.org/
.. _python-workshop: https://github.com/chrigl/python-workshop
.. _jquery: http://jquery.com/
.. _nginx: http://nginx.org/
screen.png

55.5 KB

body {
margin: 0px;
}
#searchbar {
background: none repeat scroll 0 0 #036185;
padding: 5%;
color: white;
}
#searchbar input[type=text] {
width: 100%;
}
#searchbar #searchbutton {
margin-top: 1em;
float: right;
}
#statusbar,
#footer {
padding: 1%;
background-color: lightgrey;
}
#content {
}
#content .bookentry {
}
#content .bookentry .bookheader,
#content .bookentry .bookfooter,
#content .bookentry .bookdesc {
padding: 1%;
}
#content .bookentry .bookheader {
background: none repeat scroll 0 0 #036185;
color: white;
}
#content .bookentry .bookheader a {
color: white;
text-decoration:none;
}
#content .bookentry .bookdesc {
margin: 1%;
}
#content .bookentry .bookfooter {
text-align: right;
margin-bottom: 3%;
margin-right: 1%;
}
#content .bookentry .bookfooter a {
background-color: #036185;
color: white;
border-color: #036185;
border-radius: 0.5em;
padding: 1em;
}
.error {
color: #d74d4d;
}
.bookheader {
}
.booktitle {
float: left;
}
.booktitle .bookauthor {
font-weight: bold;
margin-bottom: 1.5em;
}
.bookcover {
width: 10%;
float: right;
}
.bookcover img {
width: 100%;
height: auto;
}
.bookdesc {
}
#footer a {
color: black;
text-decoration: none;
}
#content .bookentry .booknext,
#content .bookentry .bookprev {
text-align: center;
}
#spacefooter {
height: 20em;
width: 100%;
}
#footer #toplnk {
float: left;
}
#footer #pager {
position: absolute;
left: 47%;
float: left
}
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Ebook Search</title>
<link rel="stylesheet" type="text/css" media="screen" href="css/master.css" />
<script type="text/javascript" src="js/jquery-2.1.1.min.js"></script>
<script type="text/javascript">
$(function() {
var start = 0;
var num_docs = 0;
function get_ebooks(query, start_pos) {
if(query) {
$('#statusbar').removeClass('error').text('Start searching. Please be patient.');
$.getJSON('/ebooks/select?q=' + query + '&wt=json&start=' + start_pos, function(data) {
if(data['responseHeader']['status'] != 0) {
$('#statusbar').addClass('error').text('Unable to find results for: ' + query);
} else {
num_docs = data['response']['numFound'];
start = data['response']['start'];
console.log('num_docs: ' + num_docs);
console.log('start: ' + start);
if(num_docs > start+10) {
$('#next').show();
} else {
$('#next').hide();
}
if(start > 0) {
$('#prev').show();
} else {
$('#prev').hide();
}
var end = start + 10;
if(end > num_docs) {
end = num_docs;
}
$('#statusbar').removeClass('error').text('Showing ' + start + ' to ' + end + ' of ' + num_docs + '.');
// clear result set
$('#content').text('');
var cnt=0;
$.each(data['response']['docs'], function(key, val) {
var url_prefix = '/books/' + val['path']
var url = url_prefix + '/' + val['mobi']
var lnk = $('<a href="' + url + '">' + val['title'] + '</a>');
var div = $('<div class="bookentry" id="book-' + cnt++ +'" />');
var hdr = $('<div class="bookheader"/>');
var title = $('<div class="booktitle"/>');
var author = $('<div class="bookauthor">' + val['author'] + '</div>');
var desc = $('<div class="bookdesc"/>');
var footer = $('<div class="bookfooter"/>');
var button = $('<a class="button" href="' + url + '">Download</a>');
var clr = $('<div style="clear: both" />');
var show_next_book = num_docs - start;
if(show_next_book > cnt && cnt < 10) {
var next = $('<div class="booknext"><a href="#book-' + cnt + '"><img src="img/next_book.png" alt="next book" /></a></div>');
}
if(cnt > 1) {
var prev_cnt = cnt - 2;
var prev = $('<div class="bookprev"><a href="#book-' + prev_cnt + '"><img src="img/prev_book.png" alt="prev book" /></a></div>');
}
footer.append(button);
title.append(author);
title.append(lnk);
if(prev) {
hdr.append(prev);
}
hdr.append(title);
if (val['description']) {
desc.append(val['description']);
} else {
desc.text('No description available');
}
div.append(hdr);
if (val['cover']) {
var img_url = url_prefix + '/' + val['cover'];
var cover = $('<div class="bookcover"><a href="' + url + '"><img src="' + img_url + '" alt="cover" /></a></div>');
hdr.append(cover);
}
hdr.append(clr);
if(next) {
hdr.append(next);
}
div.append(desc);
div.append(footer);
$('#content').append(div);
});
}
$('#footer').show();
}).fail(function() {
$('#statusbar').addClass('error').text('Unable to reach database');
});
}
}
function get_query() {
var query = $('input#search_q').val();
if(query) {
query = '*' + query + '*';
} else {
query = '*';
}
var lang = $('#language input:checked');
var author = $('input#search_author');
if(lang && lang.val()) {
var lang_query = ' AND language:' + lang.val();
}
if(author && author.val()) {
var author_query = ' AND author:*' + author.val() + '*';
}
if(author_query || lang_query) {
query = '(' + query;
}
if(author_query) {
query = query + author_query;
}
if(lang_query) {
query = query + lang_query;
}
if(author_query || lang_query) {
query = query + ')';
}
return query
}
$('#next').click(function(ev) {
var query = get_query();
get_ebooks(query, start_pos=start+10);
});
$('#prev').click(function(ev) {
var query = get_query();
get_ebooks(query, start_pos=start-10);
});
$('#searchform').submit(function(ev) {
var query = get_query();
get_ebooks(query, start_pos=0);
return false;
});
});
</script>
</head>
<body>
<form id="searchform" action="/ebooks/select" method="post">
<input type="hidden" name="wt" value="json" />
<div id="searchbar">
<div id="search">
<label for="q">Title</label>
<input type="text" name="q" id="search_q" />
</div>
<div id="author">
<label for="author">Author</label>
<input type="text" name="author" id="search_author" />
</div>
<div id="language">
<label for="lang">Language</label>
<input type="radio" name="lang" id="search_lang_0" value="" checked />Both
<input type="radio" name="lang" id="search_lang_1" value="deu" />German
<input type="radio" name="lang" id="search_lang_2" value="eng" />English
</div>
<div id="searchbutton">
<input type="submit" value="Search" />
</div>
<div style="clear: both"></div>
</div>
</form>
<div id="statusbar">
</div>
<div id="content">
</div>
<div id="footer" style="display: none">
<div id="toplnk">
<a href="#searchbar" class="button"><img src="img/top.png" alt="top" /></a>
</div>
<div id="pager">
<a href="#statusbar" class="button" id="prev" style="display:none"><img src="img/prev.png" alt="prev" /></a>
<a href="#statusbar" class="button" id="next" style="display:none"><img src="img/next.png" alt="next" /></a>
</div>
<div style="clear: both">
</div>
</div>
<div id="spacefooter">
</div>
</body>
</html>
This diff is collapsed.
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment