diff --git a/resources/content_server/browse/browse.css b/resources/content_server/browse/browse.css index d66ae744cf..d2e8106ba0 100644 --- a/resources/content_server/browse/browse.css +++ b/resources/content_server/browse/browse.css @@ -265,9 +265,66 @@ h2.library_name { display: none; } +#booklist .load_data { display: none } + .loading img { 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; +} + /* }}} */ diff --git a/resources/content_server/browse/browse.js b/resources/content_server/browse/browse.js index f3f278fc48..5f2af3299e 100644 --- a/resources/content_server/browse/browse.js +++ b/resources/content_server/browse/browse.js @@ -89,11 +89,14 @@ function render_error(msg) { } // Category feed {{{ + +function category_clicked() { + var href = $(this).find("span.href").html(); + window.location = href; +} + function category() { - $(".category .category-item").click(function() { - var href = $(this).find("span.href").html(); - window.location = href; - }); + $(".category .category-item").click(category_clicked); $(".category a.navlink").button(); @@ -115,6 +118,7 @@ function category() { this.children(".loaded").html(data); this.children(".loaded").show(); this.children(".loading").hide(); + this.find('.category-item').click(category_clicked); }, context: ui.newContent, 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")); + +} + +// }}} diff --git a/resources/content_server/browse/summary.html b/resources/content_server/browse/summary.html new file mode 100644 index 0000000000..0caf710a43 --- /dev/null +++ b/resources/content_server/browse/summary.html @@ -0,0 +1,14 @@ +
+
+ Cover of {title} + {read_string} +
+
+
{stars}{series}
+
{title}
+
{authors}
+
{comments}
+
{tags}
+
{other_formats}
+
+
diff --git a/src/calibre/library/comments.py b/src/calibre/library/comments.py index 32ae65b31e..670d9f2564 100644 --- a/src/calibre/library/comments.py +++ b/src/calibre/library/comments.py @@ -42,6 +42,8 @@ def comments_to_html(comments): Deprecated HTML returns as HTML via BeautifulSoup() ''' + if not comments: + return u'

' if not isinstance(comments, unicode): comments = comments.decode(preferred_encoding, 'replace') diff --git a/src/calibre/library/server/browse.py b/src/calibre/library/server/browse.py index ffbd958688..e1415decdb 100644 --- a/src/calibre/library/server/browse.py +++ b/src/calibre/library/server/browse.py @@ -14,16 +14,20 @@ import cherrypy from calibre.constants import filesystem_encoding from calibre import isbytestring, force_unicode, prepare_string_for_xml as xml 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): pages = [] + num = len(ids) while ids: page = list(ids[:25]) pages.append(page) ids = ids[25:] page_template = u'''\
-
+
/browse/booklist_page
{2}
@@ -41,7 +45,7 @@ def render_book_list(ids): {pages} ''' - return templ.format(_('Browsing %d books')%len(ids), pages=rpages) + return templ.format(_('Browsing %d books')%num, pages=rpages) def utf8(x): # {{{ if isinstance(x, unicode): @@ -49,11 +53,13 @@ def utf8(x): # {{{ return x # }}} -def render_rating(rating, container='span'): # {{{ +def render_rating(rating, container='span', prefix=None): # {{{ if rating < 0.1: return '', '' 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) ans = ['<%s class="rating">' % (container)] for i in range(5): @@ -89,7 +95,7 @@ def get_category_items(category, items, db, datatype): # {{{ id_ = xml(str(id_)) desc = '' if i.count > 0: - desc += '[' + _('%d items')%i.count + ']' + desc += '[' + _('%d books')%i.count + ']' href = '/browse/matches/%s/%s'%(category, id_) return templ.format(xml(name), rating, xml(desc), xml(quote(href)), rstring) @@ -193,6 +199,14 @@ class BrowseServer(object): self.__browse_template__ = generate() 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 {{{ def browse_toplevel(self): @@ -329,7 +343,6 @@ class BrowseServer(object): return json.dumps(entries, ensure_ascii=False) - @Endpoint() def browse_catalog(self, category=None, category_sort=None): 'Entry point for top-level, categories and sub-categories' @@ -401,16 +414,57 @@ class BrowseServer(object): ids = json.loads(ids) except: 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'%s: '%_('Tags') + args['tags'] + args['other_formats'] = '' + other_fmts = [x for x in fmts if x.lower() != fmt.lower()] + + if other_fmts: + ofmts = [u'{3}'\ + .format(fmt, fname, id_, fmt.upper()) for fmt in + other_fmts] + ofmts = ', '.join(ofmts) + args['other_formats'] = u'%s: ' % \ + _('Other formats') + ofmts + + + summs.append(self.browse_summary_template.format(**args)) + + + return json.dumps('\n'.join(summs), ensure_ascii=False) # }}} # Search {{{ - def browse_search(self, query=None, offset=0, sort=None): - raise NotImplementedError() - # }}} - - # Book {{{ - def browse_book(self, uuid=None): + def browse_search(self, query=None): raise NotImplementedError() # }}}