diff --git a/resources/content_server/browse/browse.css b/resources/content_server/browse/browse.css
index 406de09f53..d50b6936ff 100644
--- a/resources/content_server/browse/browse.css
+++ b/resources/content_server/browse/browse.css
@@ -384,3 +384,41 @@ h2.library_name {
/* }}} */
+/* Details {{{ */
+
+.details .left {
+ float: left;
+ max-width: 50%;
+ margin-right: 2em;
+ overflow: auto;
+}
+
+.details .right {
+ overflow: auto;
+}
+
+.details .formats {
+ margin-bottom: 2ex;
+}
+
+#book_details_dialog .details a {
+ color: blue;
+ text-decoration: none;
+}
+
+#book_details_dialog .details a:hover {
+ color: red;
+}
+
+.details .field {
+ margin-bottom: 0.5em;
+}
+
+.details .comment {
+ margin-left: 1em;
+ overflow: auto;
+ max-height: 50%;
+}
+
+/* }}} */
+
diff --git a/resources/content_server/browse/details.html b/resources/content_server/browse/details.html
new file mode 100644
index 0000000000..59af5c535e
--- /dev/null
+++ b/resources/content_server/browse/details.html
@@ -0,0 +1,10 @@
+
+
+

+
+
+
{formats}
+ {fields}
+ {comments}
+
+
diff --git a/src/calibre/library/field_metadata.py b/src/calibre/library/field_metadata.py
index b43a6620d0..69dd7ae636 100644
--- a/src/calibre/library/field_metadata.py
+++ b/src/calibre/library/field_metadata.py
@@ -161,7 +161,7 @@ class FieldMetadata(dict):
'datatype':'text',
'is_multiple':None,
'kind':'field',
- 'name':None,
+ 'name':_('Comments'),
'search_terms':['comments', 'comment'],
'is_custom':False, 'is_category':False}),
('cover', {'table':None,
diff --git a/src/calibre/library/server/browse.py b/src/calibre/library/server/browse.py
index 805a8f6424..5e7de43d45 100644
--- a/src/calibre/library/server/browse.py
+++ b/src/calibre/library/server/browse.py
@@ -245,6 +245,14 @@ class BrowseServer(object):
P('content_server/browse/summary.html', data=True).decode('utf-8')
return self.__browse_summary_template__
+ @property
+ def browse_details_template(self):
+ if not hasattr(self, '__browse_details_template__') or \
+ self.opts.develop:
+ self.__browse_details_template__ = \
+ P('content_server/browse/details.html', data=True).decode('utf-8')
+ return self.__browse_details_template__
+
# }}}
# Catalogs {{{
@@ -503,10 +511,10 @@ class BrowseServer(object):
if mi.rating:
args['stars'] = render_rating(mi.rating/2.0, prefix=_('Rating'))[0]
if args['tags']:
- args['tags'] = u'%s: '%_('Tags') + \
- xml(args['tags'])
+ args['tags'] = u'%s: '%xml(_('Tags')) + \
+ args['tags']
if args['series']:
- args['series'] = xml(args['series'])
+ args['series'] = args['series']
args['read_string'] = xml(_('Read'), True)
args['details'] = xml(_('Details'), True)
args['details_tt'] = xml(_('Show book details'), True)
@@ -535,9 +543,38 @@ class BrowseServer(object):
.format(fmt, fname, id_, fmt.upper()) for fmt in
fmts]
ofmts = ', '.join(ofmts)
- args['formats'] = u'%s: ' % \
- _('Formats') + ofmts
+ args['formats'] = ofmts
+ fields, comments = [], []
+ for field, m in list(mi.get_all_standard_metadata(False).items()) + \
+ list(mi.get_all_user_metadata(False).items()):
+ if m['datatype'] == 'comments' or field == 'comments':
+ comments.append((m['name'], comments_to_html(mi.get(field,
+ ''))))
+ continue
+ if field in ('title', 'formats') or not args.get(field, False) \
+ or not m['name']:
+ continue
+ if m['datatype'] == 'rating':
+ r = u'%s: '%xml(m['name']) + \
+ render_rating(mi.rating/2.0, prefix=m['name'])[0]
+ else:
+ r = u'%s: '%xml(m['name']) + \
+ args[field]
+ fields.append((m['name'], r))
+ fields.sort(key=lambda x: x[0].lower())
+ fields = [u'{0}
'.format(f[1]) for f in
+ fields]
+ fields = u'%s
'%('\n\n'.join(fields))
+
+ comments.sort(key=lambda x: x[0].lower())
+ comments = [(u'%s: '
+ u'
') % (xml(c[0]),
+ c[1]) for c in comments]
+ comments = u''%('\n\n'.join(comments))
+ ans = self.browse_details_template.format(id=id_,
+ title=xml(mi.title, True), fields=fields,
+ formats=args['formats'], comments=comments)
return json.dumps(ans, ensure_ascii=False)