mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-31 14:33:54 -04:00
Basic book list in the new content server
This commit is contained in:
parent
0a4da453be
commit
1f0d61c630
@ -265,9 +265,66 @@ h2.library_name {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#booklist .load_data { display: none }
|
||||||
|
|
||||||
.loading img {
|
.loading img {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#booklist .summary {
|
||||||
|
margin-bottom: 2ex;
|
||||||
|
border-bottom: solid 1px black;
|
||||||
|
}
|
||||||
|
|
||||||
|
#booklist div.left {
|
||||||
|
float: left;
|
||||||
|
height: 190px;
|
||||||
|
vertical-align: middle;
|
||||||
|
text-align: center;
|
||||||
|
margin-left: 1em;
|
||||||
|
margin-right: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#booklist div.left img {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 1ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#booklist div.right {
|
||||||
|
height: 190px;
|
||||||
|
overflow: auto;
|
||||||
|
margin-left: 1em;
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#booklist div.right .stars {
|
||||||
|
float:right;
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#booklist div.right .stars .rating_container {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#booklist .title {
|
||||||
|
font-size: larger;
|
||||||
|
}
|
||||||
|
|
||||||
|
#booklist .formats a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#booklist .formats a:hover {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
#booklist .left .ui-button-text {
|
||||||
|
font-weight: bold;
|
||||||
|
padding-left: 0.25em;
|
||||||
|
padding-right: 0.25em;
|
||||||
|
padding-top: 0.25em;
|
||||||
|
padding-bottom: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
@ -89,11 +89,14 @@ function render_error(msg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Category feed {{{
|
// Category feed {{{
|
||||||
function category() {
|
|
||||||
$(".category .category-item").click(function() {
|
function category_clicked() {
|
||||||
var href = $(this).find("span.href").html();
|
var href = $(this).find("span.href").html();
|
||||||
window.location = href;
|
window.location = href;
|
||||||
});
|
}
|
||||||
|
|
||||||
|
function category() {
|
||||||
|
$(".category .category-item").click(category_clicked);
|
||||||
|
|
||||||
$(".category a.navlink").button();
|
$(".category a.navlink").button();
|
||||||
|
|
||||||
@ -115,6 +118,7 @@ function category() {
|
|||||||
this.children(".loaded").html(data);
|
this.children(".loaded").html(data);
|
||||||
this.children(".loaded").show();
|
this.children(".loaded").show();
|
||||||
this.children(".loading").hide();
|
this.children(".loading").hide();
|
||||||
|
this.find('.category-item').click(category_clicked);
|
||||||
},
|
},
|
||||||
context: ui.newContent,
|
context: ui.newContent,
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
@ -132,4 +136,45 @@ function category() {
|
|||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
|
// Booklist {{{
|
||||||
|
|
||||||
|
function load_page(elem) {
|
||||||
|
var ids = elem.find(".load_data").attr('title');
|
||||||
|
var href = elem.find(".load_data").html();
|
||||||
|
$.ajax({
|
||||||
|
url: href,
|
||||||
|
context: elem,
|
||||||
|
dataType: "json",
|
||||||
|
type: 'POST',
|
||||||
|
timeout: 600000, //milliseconds (10 minutes)
|
||||||
|
data: {'ids': ids},
|
||||||
|
error: function(xhr, stat, err) {
|
||||||
|
this.children(".loaded").html(render_error(stat));
|
||||||
|
this.children(".loaded").show();
|
||||||
|
this.children(".loading").hide();
|
||||||
|
},
|
||||||
|
success: function(data) {
|
||||||
|
this.children(".loaded").html(data);
|
||||||
|
this.children(".loaded").show();
|
||||||
|
this.children(".loading").hide();
|
||||||
|
this.find(".left a.read").button();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$("#booklist .page").hide();
|
||||||
|
elem.children(".loaded").hide();
|
||||||
|
elem.children(".loading").show();
|
||||||
|
elem.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function booklist() {
|
||||||
|
var test = $("#booklist #page0").html();
|
||||||
|
if (!test) {
|
||||||
|
$("#booklist").html(render_error("No books found"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
load_page($("#booklist #page0"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
14
resources/content_server/browse/summary.html
Normal file
14
resources/content_server/browse/summary.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<div id="summary_{id}" class="summary">
|
||||||
|
<div class="left">
|
||||||
|
<img alt="Cover of {title}" src="/get/thumb_120_120/{id}" />
|
||||||
|
<a href="{href}" class="read" title="{read_tooltip}">{read_string}</a>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<div class="stars"><span class="rating_container">{stars}</span>{series}</div>
|
||||||
|
<div class="title"><strong>{title}</strong></div>
|
||||||
|
<div class="authors">{authors}</div>
|
||||||
|
<div class="comments">{comments}</div>
|
||||||
|
<div class="tags">{tags}</div>
|
||||||
|
<div class="formats">{other_formats}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -42,6 +42,8 @@ def comments_to_html(comments):
|
|||||||
Deprecated HTML returns as HTML via BeautifulSoup()
|
Deprecated HTML returns as HTML via BeautifulSoup()
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
if not comments:
|
||||||
|
return u'<p></p>'
|
||||||
if not isinstance(comments, unicode):
|
if not isinstance(comments, unicode):
|
||||||
comments = comments.decode(preferred_encoding, 'replace')
|
comments = comments.decode(preferred_encoding, 'replace')
|
||||||
|
|
||||||
|
@ -14,16 +14,20 @@ import cherrypy
|
|||||||
from calibre.constants import filesystem_encoding
|
from calibre.constants import filesystem_encoding
|
||||||
from calibre import isbytestring, force_unicode, prepare_string_for_xml as xml
|
from calibre import isbytestring, force_unicode, prepare_string_for_xml as xml
|
||||||
from calibre.utils.ordered_dict import OrderedDict
|
from calibre.utils.ordered_dict import OrderedDict
|
||||||
|
from calibre.utils.filenames import ascii_filename
|
||||||
|
from calibre.utils.config import prefs
|
||||||
|
from calibre.library.comments import comments_to_html
|
||||||
|
|
||||||
def render_book_list(ids):
|
def render_book_list(ids):
|
||||||
pages = []
|
pages = []
|
||||||
|
num = len(ids)
|
||||||
while ids:
|
while ids:
|
||||||
page = list(ids[:25])
|
page = list(ids[:25])
|
||||||
pages.append(page)
|
pages.append(page)
|
||||||
ids = ids[25:]
|
ids = ids[25:]
|
||||||
page_template = u'''\
|
page_template = u'''\
|
||||||
<div class="page" id="page{0}">
|
<div class="page" id="page{0}">
|
||||||
<div class="load_data" title="{1}"></div>
|
<div class="load_data" title="{1}">/browse/booklist_page</div>
|
||||||
<div class="loading"><img src="/static/loading.gif" /> {2}</div>
|
<div class="loading"><img src="/static/loading.gif" /> {2}</div>
|
||||||
<div class="loaded"></div>
|
<div class="loaded"></div>
|
||||||
</div>
|
</div>
|
||||||
@ -41,7 +45,7 @@ def render_book_list(ids):
|
|||||||
{pages}
|
{pages}
|
||||||
</div>
|
</div>
|
||||||
'''
|
'''
|
||||||
return templ.format(_('Browsing %d books')%len(ids), pages=rpages)
|
return templ.format(_('Browsing %d books')%num, pages=rpages)
|
||||||
|
|
||||||
def utf8(x): # {{{
|
def utf8(x): # {{{
|
||||||
if isinstance(x, unicode):
|
if isinstance(x, unicode):
|
||||||
@ -49,11 +53,13 @@ def utf8(x): # {{{
|
|||||||
return x
|
return x
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
def render_rating(rating, container='span'): # {{{
|
def render_rating(rating, container='span', prefix=None): # {{{
|
||||||
if rating < 0.1:
|
if rating < 0.1:
|
||||||
return '', ''
|
return '', ''
|
||||||
added = 0
|
added = 0
|
||||||
rstring = xml(_('Average rating: %.1f stars')% (rating if rating else 0.0),
|
if prefix is None:
|
||||||
|
prefix = _('Average rating')
|
||||||
|
rstring = xml(_('%s: %.1f stars')% (prefix, rating if rating else 0.0),
|
||||||
True)
|
True)
|
||||||
ans = ['<%s class="rating">' % (container)]
|
ans = ['<%s class="rating">' % (container)]
|
||||||
for i in range(5):
|
for i in range(5):
|
||||||
@ -89,7 +95,7 @@ def get_category_items(category, items, db, datatype): # {{{
|
|||||||
id_ = xml(str(id_))
|
id_ = xml(str(id_))
|
||||||
desc = ''
|
desc = ''
|
||||||
if i.count > 0:
|
if i.count > 0:
|
||||||
desc += '[' + _('%d items')%i.count + ']'
|
desc += '[' + _('%d books')%i.count + ']'
|
||||||
href = '/browse/matches/%s/%s'%(category, id_)
|
href = '/browse/matches/%s/%s'%(category, id_)
|
||||||
return templ.format(xml(name), rating,
|
return templ.format(xml(name), rating,
|
||||||
xml(desc), xml(quote(href)), rstring)
|
xml(desc), xml(quote(href)), rstring)
|
||||||
@ -193,6 +199,14 @@ class BrowseServer(object):
|
|||||||
self.__browse_template__ = generate()
|
self.__browse_template__ = generate()
|
||||||
return self.__browse_template__
|
return self.__browse_template__
|
||||||
|
|
||||||
|
@property
|
||||||
|
def browse_summary_template(self):
|
||||||
|
if not hasattr(self, '__browse_summary_template__') or \
|
||||||
|
self.opts.develop:
|
||||||
|
self.__browse_summary_template__ = \
|
||||||
|
P('content_server/browse/summary.html', data=True).decode('utf-8')
|
||||||
|
return self.__browse_summary_template__
|
||||||
|
|
||||||
|
|
||||||
# Catalogs {{{
|
# Catalogs {{{
|
||||||
def browse_toplevel(self):
|
def browse_toplevel(self):
|
||||||
@ -329,7 +343,6 @@ class BrowseServer(object):
|
|||||||
return json.dumps(entries, ensure_ascii=False)
|
return json.dumps(entries, ensure_ascii=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Endpoint()
|
@Endpoint()
|
||||||
def browse_catalog(self, category=None, category_sort=None):
|
def browse_catalog(self, category=None, category_sort=None):
|
||||||
'Entry point for top-level, categories and sub-categories'
|
'Entry point for top-level, categories and sub-categories'
|
||||||
@ -401,16 +414,57 @@ class BrowseServer(object):
|
|||||||
ids = json.loads(ids)
|
ids = json.loads(ids)
|
||||||
except:
|
except:
|
||||||
raise cherrypy.HTTPError(404, 'invalid ids')
|
raise cherrypy.HTTPError(404, 'invalid ids')
|
||||||
|
summs = []
|
||||||
|
for id_ in ids:
|
||||||
|
try:
|
||||||
|
id_ = int(id_)
|
||||||
|
mi = self.db.get_metadata(id_, index_is_id=True)
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
fmts = self.db.formats(id_, index_is_id=True)
|
||||||
|
if not fmts:
|
||||||
|
fmts = ''
|
||||||
|
fmts = [x.lower() for x in fmts.split(',') if x]
|
||||||
|
pf = prefs['output_format'].lower()
|
||||||
|
fmt = pf if pf in fmts else fmts[0]
|
||||||
|
args = {'id':id_, 'mi':mi, 'read_string':_('Read'),}
|
||||||
|
for key in mi.all_field_keys():
|
||||||
|
val = mi.format_field(key)[1]
|
||||||
|
if not val:
|
||||||
|
val = ''
|
||||||
|
args[key] = xml(val, True)
|
||||||
|
fname = ascii_filename(args['title']) + ' - ' + ascii_filename(args['authors'])
|
||||||
|
args['href'] = '/get/%s/%s_%d.%s'%(
|
||||||
|
fmt, fname, id_, fmt)
|
||||||
|
args['comments'] = comments_to_html(mi.comments)
|
||||||
|
args['read_tooltip'] = \
|
||||||
|
_('Read %s in the %s format')%(args['title'], fmt.upper())
|
||||||
|
args['stars'] = ''
|
||||||
|
if mi.rating:
|
||||||
|
args['stars'] = render_rating(mi.rating/2.0, prefix=_('Rating'))[0]
|
||||||
|
if args['tags']:
|
||||||
|
args['tags'] = u'<strong>%s: </strong>'%_('Tags') + args['tags']
|
||||||
|
args['other_formats'] = ''
|
||||||
|
other_fmts = [x for x in fmts if x.lower() != fmt.lower()]
|
||||||
|
|
||||||
|
if other_fmts:
|
||||||
|
ofmts = [u'<a href="/get/{0}/{1}_{2}.{0}" title="{3}">{3}</a>'\
|
||||||
|
.format(fmt, fname, id_, fmt.upper()) for fmt in
|
||||||
|
other_fmts]
|
||||||
|
ofmts = ', '.join(ofmts)
|
||||||
|
args['other_formats'] = u'<strong>%s: </strong>' % \
|
||||||
|
_('Other formats') + ofmts
|
||||||
|
|
||||||
|
|
||||||
|
summs.append(self.browse_summary_template.format(**args))
|
||||||
|
|
||||||
|
|
||||||
|
return json.dumps('\n'.join(summs), ensure_ascii=False)
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
# Search {{{
|
# Search {{{
|
||||||
def browse_search(self, query=None, offset=0, sort=None):
|
def browse_search(self, query=None):
|
||||||
raise NotImplementedError()
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
# Book {{{
|
|
||||||
def browse_book(self, uuid=None):
|
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user