mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
More work on the EM page
This commit is contained in:
parent
124ef1f08e
commit
33d7426e09
@ -356,12 +356,17 @@ def render_metadata(mi, table, book_id): # {{{
|
|||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
add_extra_css(def():
|
def basic_table_rules(sel):
|
||||||
sel = '.' + CLASS_NAME + ' '
|
|
||||||
style = ''
|
style = ''
|
||||||
style += build_rule(sel + 'table.metadata td', vertical_align='top')
|
style += build_rule(sel + 'table.metadata td', vertical_align='top')
|
||||||
style += build_rule(sel + 'table.metadata td:first-of-type', font_weight='bold', padding_right='1em', white_space='nowrap')
|
style += build_rule(sel + 'table.metadata td:first-of-type', font_weight='bold', padding_right='1em', white_space='nowrap')
|
||||||
style += build_rule(sel + 'table.metadata td:last-of-type', overflow_wrap='break-word')
|
style += build_rule(sel + 'table.metadata td:last-of-type', overflow_wrap='break-word')
|
||||||
|
return style
|
||||||
|
|
||||||
|
|
||||||
|
add_extra_css(def():
|
||||||
|
sel = '.' + CLASS_NAME + ' '
|
||||||
|
style = basic_table_rules(sel)
|
||||||
style += build_rule(sel + 'table.metadata a[href]', color='blue')
|
style += build_rule(sel + 'table.metadata a[href]', color='blue')
|
||||||
style += build_rule(sel + 'table.metadata a[href]:hover', color=get_color('window-hover-foreground'))
|
style += build_rule(sel + 'table.metadata a[href]:hover', color=get_color('window-hover-foreground'))
|
||||||
style += build_rule(sel + 'table.metadata a[href]:active', color=get_color('window-hover-foreground'), transform='scale(1.5)')
|
style += build_rule(sel + 'table.metadata a[href]:active', color=get_color('window-hover-foreground'), transform='scale(1.5)')
|
||||||
|
@ -2,18 +2,233 @@
|
|||||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
from __python__ import bound_methods, hash_literals
|
from __python__ import bound_methods, hash_literals
|
||||||
|
|
||||||
|
import traceback
|
||||||
from elementmaker import E
|
from elementmaker import E
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
|
|
||||||
from book_list.book_details import fetch_metadata, no_book, report_load_failure
|
from book_list.book_details import (
|
||||||
from book_list.library_data import book_metadata, load_status
|
basic_table_rules, fetch_metadata, field_sorter, no_book, report_load_failure
|
||||||
|
)
|
||||||
|
from book_list.library_data import book_metadata, library_data, load_status
|
||||||
from book_list.router import back
|
from book_list.router import back
|
||||||
from book_list.top_bar import create_top_bar, set_title
|
from book_list.top_bar import create_top_bar, set_title
|
||||||
from book_list.ui import set_panel_handler, show_panel
|
from book_list.ui import set_panel_handler, show_panel
|
||||||
from dom import clear
|
from date import format_date
|
||||||
from utils import conditional_timeout, parse_url_params
|
from dom import add_extra_css, build_rule, clear, svgicon
|
||||||
|
from session import get_interface_data
|
||||||
|
from utils import (
|
||||||
|
conditional_timeout, fmt_sidx, parse_url_params, safe_set_inner_html
|
||||||
|
)
|
||||||
|
|
||||||
CLASS_NAME = 'edit-metadata-panel'
|
CLASS_NAME = 'edit-metadata-panel'
|
||||||
|
IGNORED_FIELDS = {'formats', 'sort', 'uuid', 'id', 'urls_from_identifiers', 'lang_names', 'last_modified', 'path', 'marked', 'size', 'ondevice', 'cover', 'au_map', 'isbn'}
|
||||||
|
|
||||||
|
add_extra_css(def():
|
||||||
|
sel = '.' + CLASS_NAME + ' '
|
||||||
|
style = basic_table_rules(sel)
|
||||||
|
style += build_rule(sel + 'table.metadata', margin_left='1rem')
|
||||||
|
style += build_rule(sel + 'table.metadata td', padding_bottom='0.5ex', padding_top='0.5ex', cursor='pointer')
|
||||||
|
style += build_rule(sel + 'table.metadata tr:hover', color='red')
|
||||||
|
style += build_rule(sel + 'table.metadata tr:active', transform='scale(1.5)')
|
||||||
|
return style
|
||||||
|
)
|
||||||
|
|
||||||
|
def truncated_html(val):
|
||||||
|
ans = val.replace(/<[^>]+>/g, '')
|
||||||
|
if ans.length > 40:
|
||||||
|
ans = ans[:40] + '…'
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
def edit_field(container_id, book_id, field):
|
||||||
|
print(1111111, field)
|
||||||
|
|
||||||
|
|
||||||
|
def render_metadata(mi, table, container_id, book_id): # {{{
|
||||||
|
field_metadata = library_data.field_metadata
|
||||||
|
interface_data = get_interface_data()
|
||||||
|
current_edit_action = None
|
||||||
|
|
||||||
|
def allowed_fields(field):
|
||||||
|
if field.endswith('_index'):
|
||||||
|
fm = field_metadata[field[:-len('_index')]]
|
||||||
|
if fm and fm.datatype is 'series':
|
||||||
|
return False
|
||||||
|
if field.startswith('#'):
|
||||||
|
return True
|
||||||
|
if field in IGNORED_FIELDS or field.endswith('_sort') or field[0] is '@':
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
fields = library_data.book_display_fields
|
||||||
|
if not fields or not fields.length:
|
||||||
|
fields = sorted(filter(allowed_fields, mi), key=field_sorter(field_metadata))
|
||||||
|
else:
|
||||||
|
fields = filter(allowed_fields, fields)
|
||||||
|
fields = list(fields)
|
||||||
|
added_fields = {f:True for f in fields}
|
||||||
|
if not added_fields.title:
|
||||||
|
added_fields.title = True
|
||||||
|
fields.insert(0, 'title')
|
||||||
|
for other_field in Object.keys(library_data.field_metadata):
|
||||||
|
if not added_fields[other_field] and allowed_fields(other_field) and other_field not in IGNORED_FIELDS:
|
||||||
|
fields.push(other_field)
|
||||||
|
|
||||||
|
def add_row(name, val, is_html=False, join=None):
|
||||||
|
if val is undefined or val is None:
|
||||||
|
val = v'[" "]' if join else '\xa0'
|
||||||
|
def add_val(v):
|
||||||
|
if not v.appendChild:
|
||||||
|
v += ''
|
||||||
|
if v.appendChild:
|
||||||
|
table.lastChild.lastChild.appendChild(v)
|
||||||
|
else:
|
||||||
|
table.lastChild.lastChild.appendChild(document.createTextNode(v))
|
||||||
|
|
||||||
|
table.appendChild(E.tr(onclick=current_edit_action, E.td(name + ':'), E.td()))
|
||||||
|
if is_html:
|
||||||
|
table.lastChild.lastChild.appendChild(document.createTextNode(truncated_html(val + '')))
|
||||||
|
else:
|
||||||
|
if not join:
|
||||||
|
add_val(val)
|
||||||
|
else:
|
||||||
|
for v in val:
|
||||||
|
add_val(v)
|
||||||
|
if v is not val[-1]:
|
||||||
|
table.lastChild.lastChild.appendChild(document.createTextNode(join))
|
||||||
|
return table.lastChild.lastChild
|
||||||
|
|
||||||
|
def process_composite(field, fm, name, val):
|
||||||
|
if fm.display and fm.display.contains_html:
|
||||||
|
add_row(name, val, is_html=True)
|
||||||
|
elif fm.is_multiple and fm.is_multiple.list_to_ui:
|
||||||
|
all_vals = filter(None, map(str.strip, val.split(fm.is_multiple.list_to_ui)))
|
||||||
|
add_row(name, all_vals, join=fm.is_multiple.list_to_ui)
|
||||||
|
else:
|
||||||
|
add_row(name, val)
|
||||||
|
|
||||||
|
def process_authors(field, fm, name, val):
|
||||||
|
add_row(name, val, join=' & ')
|
||||||
|
|
||||||
|
def process_publisher(field, fm, name, val):
|
||||||
|
add_row(name, val)
|
||||||
|
|
||||||
|
def process_rating(field, fm, name, val):
|
||||||
|
stars = E.span()
|
||||||
|
val = int(val or 0)
|
||||||
|
if val > 0:
|
||||||
|
for i in range(val // 2):
|
||||||
|
stars.appendChild(svgicon('star'))
|
||||||
|
if fm.display.allow_half_stars and (val % 2):
|
||||||
|
stars.appendChild(svgicon('star-half'))
|
||||||
|
add_row(name, stars)
|
||||||
|
else:
|
||||||
|
add_row(name, None)
|
||||||
|
|
||||||
|
def process_identifiers(field, fm, name, val):
|
||||||
|
if val:
|
||||||
|
keys = Object.keys(val)
|
||||||
|
if keys.length:
|
||||||
|
table.appendChild(E.tr(onclick=current_edit_action, E.td(name + ':'), E.td()))
|
||||||
|
td = table.lastChild.lastChild
|
||||||
|
for k in keys:
|
||||||
|
if td.childNodes.length:
|
||||||
|
td.appendChild(document.createTextNode(', '))
|
||||||
|
td.appendChild(document.createTextNode(k))
|
||||||
|
return
|
||||||
|
add_row(name, None)
|
||||||
|
|
||||||
|
def process_languages(field, fm, name, val):
|
||||||
|
if val and val.length:
|
||||||
|
table.appendChild(E.tr(onclick=current_edit_action, E.td(name + ':'), E.td()))
|
||||||
|
td = table.lastChild.lastChild
|
||||||
|
for k in val:
|
||||||
|
lang = mi.lang_names[k] or k
|
||||||
|
td.appendChild(document.createTextNode(lang))
|
||||||
|
if k is not val[-1]:
|
||||||
|
td.appendChild(document.createTextNode(', '))
|
||||||
|
return
|
||||||
|
add_row(name, None)
|
||||||
|
|
||||||
|
def process_datetime(field, fm, name, val):
|
||||||
|
if val:
|
||||||
|
fmt = interface_data['gui_' + field + '_display_format'] or (fm['display'] or {}).date_format
|
||||||
|
add_row(name, format_date(val, fmt))
|
||||||
|
else:
|
||||||
|
add_row(name, None)
|
||||||
|
|
||||||
|
def process_series(field, fm, name, val):
|
||||||
|
if val:
|
||||||
|
ifield = field + '_index'
|
||||||
|
try:
|
||||||
|
ival = float(mi[ifield])
|
||||||
|
except Exception:
|
||||||
|
ival = 1.0
|
||||||
|
ival = fmt_sidx(ival, use_roman=interface_data.use_roman_numerals_for_series_number)
|
||||||
|
table.appendChild(E.tr(onclick=current_edit_action, E.td(name + ':'), E.td()))
|
||||||
|
s = safe_set_inner_html(E.span(), _('{0} of <i>{1}</i>').format(ival, val))
|
||||||
|
table.lastChild.lastChild.appendChild(s)
|
||||||
|
else:
|
||||||
|
add_row(name, None)
|
||||||
|
|
||||||
|
def process_field(field, fm):
|
||||||
|
name = fm.name or field
|
||||||
|
datatype = fm.datatype
|
||||||
|
val = mi[field]
|
||||||
|
if field is 'comments' or datatype is 'comments':
|
||||||
|
add_row(name, truncated_html(val or ''))
|
||||||
|
return
|
||||||
|
func = None
|
||||||
|
if datatype is 'composite':
|
||||||
|
func = process_composite
|
||||||
|
elif datatype is 'rating':
|
||||||
|
func = process_rating
|
||||||
|
elif field is 'identifiers':
|
||||||
|
func = process_identifiers
|
||||||
|
elif field is 'authors':
|
||||||
|
func = process_authors
|
||||||
|
elif field is 'publisher':
|
||||||
|
func = process_publisher
|
||||||
|
elif field is 'languages':
|
||||||
|
func = process_languages
|
||||||
|
elif datatype is 'datetime':
|
||||||
|
func = process_datetime
|
||||||
|
elif datatype is 'series':
|
||||||
|
func = process_series
|
||||||
|
if func:
|
||||||
|
func(field, fm, name, val)
|
||||||
|
else:
|
||||||
|
if datatype is 'text' or datatype is 'enumeration':
|
||||||
|
if val is not undefined and val is not None:
|
||||||
|
join = fm.is_multiple.list_to_ui if fm.is_multiple else None
|
||||||
|
add_row(name, val, join=join)
|
||||||
|
else:
|
||||||
|
add_row(name, None)
|
||||||
|
elif datatype is 'bool':
|
||||||
|
add_row(name, _('Yes') if val else _('No'))
|
||||||
|
elif datatype is 'int' or datatype is 'float':
|
||||||
|
if val is not undefined and val is not None:
|
||||||
|
fmt = (fm.display or {}).number_format
|
||||||
|
if fmt:
|
||||||
|
val = fmt.format(val)
|
||||||
|
else:
|
||||||
|
val += ''
|
||||||
|
add_row(name, val)
|
||||||
|
else:
|
||||||
|
add_row(name, None)
|
||||||
|
|
||||||
|
for field in fields:
|
||||||
|
fm = field_metadata[field]
|
||||||
|
if not fm:
|
||||||
|
continue
|
||||||
|
current_edit_action = edit_field.bind(None, container_id, book_id, field)
|
||||||
|
try:
|
||||||
|
process_field(field, fm)
|
||||||
|
except Exception:
|
||||||
|
print('Failed to render metadata field: ' + field)
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
def show_book(container_id, book_id):
|
def show_book(container_id, book_id):
|
||||||
@ -26,6 +241,8 @@ def show_book(container_id, book_id):
|
|||||||
return
|
return
|
||||||
div.appendChild(E.div(style='margin: 1ex 1rem', _(
|
div.appendChild(E.div(style='margin: 1ex 1rem', _(
|
||||||
'Tap any field below to edit it')))
|
'Tap any field below to edit it')))
|
||||||
|
div.appendChild(E.table(class_='metadata'))
|
||||||
|
render_metadata(mi, div.lastChild, container_id, book_id)
|
||||||
|
|
||||||
|
|
||||||
def on_close(container_id):
|
def on_close(container_id):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user