mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Browser viewer: Allow customizing what information is displayed in the header and footer areas. Access Preferences from the viewer controls to change.
This commit is contained in:
parent
da032270d1
commit
f4272115bf
@ -7,13 +7,15 @@ from gettext import gettext as _
|
||||
|
||||
from book_list.globals import get_session_data
|
||||
from dom import unique_id
|
||||
from session import get_interface_data
|
||||
from utils import fmt_sidx
|
||||
|
||||
CONTAINER = unique_id('reader-hf-prefs')
|
||||
|
||||
|
||||
def create_item(region, label):
|
||||
def sep():
|
||||
return E.option('\xa0', disabled=True, style='min-height: 1pt; max-height: 1pt; font-size: 1pt; background-color: currentColor')
|
||||
return E.option('\xa0', disabled=True)
|
||||
|
||||
def opt(label, name, selected):
|
||||
return E.option(label, id=name, value=name, selected=bool(selected))
|
||||
@ -26,6 +28,7 @@ def create_item(region, label):
|
||||
sep(),
|
||||
opt(_('Book title'), 'title'),
|
||||
opt(_('Authors'), 'authors'),
|
||||
opt(_('Series'), 'series'),
|
||||
sep(),
|
||||
opt(_('Top level section'), 'top-section'),
|
||||
opt(_('Current section'), 'section'),
|
||||
@ -85,6 +88,49 @@ def create_head_foot_panel(container):
|
||||
|
||||
def commit_head_foot(onchange, container):
|
||||
sd = get_session_data()
|
||||
changed = False
|
||||
for which in 'header footer'.split(' '):
|
||||
prev = sd.get(which) or {}
|
||||
table = container.querySelector(f'table[data-which={which}]')
|
||||
current = get_setting(table)
|
||||
for region in 'left middle right'.split(' '):
|
||||
if prev[region] is not current[region]:
|
||||
changed = True
|
||||
sd.set(which, get_setting(table))
|
||||
|
||||
if changed:
|
||||
onchange()
|
||||
|
||||
|
||||
if window.Intl?.DateTimeFormat:
|
||||
date_formatter = window.Intl.DateTimeFormat(undefined, {'hour':'numeric', 'minute':'numeric'})
|
||||
else:
|
||||
date_formatter = {'format': def(date):
|
||||
return '{}:{}'.format(date.getHours(), date.getMinutes())
|
||||
}
|
||||
|
||||
|
||||
def render_head_foot(div, which, region, progress_frac, metadata):
|
||||
template = get_session_data().get(which) or {}
|
||||
field = template[region] or 'empty'
|
||||
interface_data = get_interface_data()
|
||||
text = ''
|
||||
has_clock = False
|
||||
if field is 'progress':
|
||||
percent = min(100, max(Math.round(progress_frac * 100), 0))
|
||||
text = percent + '%'
|
||||
elif field is 'title':
|
||||
text = metadata.title or _('Untitled')
|
||||
elif field is 'authors':
|
||||
text = ' & '.join(metadata.authors or v'[]')
|
||||
elif field is 'series':
|
||||
if metadata.series:
|
||||
ival = fmt_sidx(ival, use_roman=interface_data.use_roman_numerals_for_series_number)
|
||||
text = _('{0} of {1}').format(ival, metadata.series)
|
||||
elif field is 'clock':
|
||||
text = date_formatter.format(Date())
|
||||
has_clock = True
|
||||
if text is not div.textContent:
|
||||
div.textContent = text
|
||||
div.style.display = 'block' if text else 'none'
|
||||
return text, has_clock
|
||||
|
@ -6,7 +6,7 @@ from elementmaker import E
|
||||
from gettext import gettext as _
|
||||
|
||||
from ajax import ajax_send
|
||||
from book_list.book_details import render_metadata, CLASS_NAME as BD_CLASS_NAME
|
||||
from book_list.book_details import CLASS_NAME as BD_CLASS_NAME, render_metadata
|
||||
from book_list.globals import get_session_data
|
||||
from book_list.router import push_state, read_book_mode
|
||||
from book_list.theme import get_color
|
||||
@ -19,6 +19,7 @@ from read_book.goto import get_next_section
|
||||
from read_book.overlay import Overlay
|
||||
from read_book.prefs.colors import resolve_color_scheme
|
||||
from read_book.prefs.font_size import change_font_size_by
|
||||
from read_book.prefs.head_foot import render_head_foot
|
||||
from read_book.resources import load_resources
|
||||
from read_book.search import SearchOverlay, find_in_spine
|
||||
from read_book.toc import update_visible_toc_nodes
|
||||
@ -93,10 +94,11 @@ def show_metadata_overlay(mi):
|
||||
def margin_elem(sd, which, id, onclick):
|
||||
sz = sd.get(which, 20)
|
||||
fsz = min(max(0, sz - 6), 12)
|
||||
s = '; text-overflow: ellipsis; white-space: nowrap; overflow: hidden'
|
||||
ans = E.div(
|
||||
style=f'height:{sz}px; overflow: hidden; font-size:{fsz}px; width:100%; padding: 0; display: flex; justify-content: space-between; align-items: center',
|
||||
id=id,
|
||||
E.div(), E.div()
|
||||
E.div(style='margin-right: 1.5em' + s), E.div(style=s), E.div(style='margin-left: 1.5em' + s)
|
||||
)
|
||||
if onclick:
|
||||
ans.addEventListener('click', onclick)
|
||||
@ -114,6 +116,8 @@ class View:
|
||||
def __init__(self, container, ui):
|
||||
self.ui = ui
|
||||
self.loaded_resources = {}
|
||||
self.current_progress_frac = 0
|
||||
self.clock_timer_id = 0
|
||||
sd = get_session_data()
|
||||
left_margin = E.div(svgicon('caret-left'), style='width:{}px;'.format(sd.get('margin_left', 20)), class_='book-side-margin', id='book-left-margin', onclick=self.left_margin_clicked)
|
||||
set_left_margin_handler(left_margin)
|
||||
@ -479,7 +483,8 @@ class View:
|
||||
self.book.last_read_position[unkey] = data.cfi
|
||||
self.ui.db.update_last_read_time(self.book)
|
||||
lrd = {'device':get_device_uuid(), 'cfi':data.cfi, 'pos_frac':data.progress_frac}
|
||||
self.update_read_percent(data.progress_frac)
|
||||
self.current_progress_frac = data.progress_frac
|
||||
self.update_header_footer()
|
||||
key = self.book.key
|
||||
if username:
|
||||
ajax_send('book-set-last-read-position/{library_id}/{book_id}/{fmt}'.format(
|
||||
@ -488,17 +493,41 @@ class View:
|
||||
print('Failed to update last read position, AJAX call did not succeed')
|
||||
)
|
||||
|
||||
def update_read_percent(self, pos_frac):
|
||||
def update_header_footer(self):
|
||||
sd = get_session_data()
|
||||
has_clock = False
|
||||
|
||||
def render_template(div, sz_attr, name):
|
||||
nonlocal has_clock
|
||||
if sd.get(sz_attr, 20) > 5:
|
||||
mi = self.book.metadata
|
||||
texta, hca = render_head_foot(div.firstChild, name, 'left', self.current_progress_frac, mi)
|
||||
textb, hcb = render_head_foot(div.firstChild.nextSibling, name, 'middle', self.current_progress_frac, mi)
|
||||
textc, hcc = render_head_foot(div.lastChild, name, 'right', self.current_progress_frac, mi)
|
||||
has_clock = hca or hcb or hcc
|
||||
if textc and not textb and not texta:
|
||||
# There is only a right, we want it to be right aligned,
|
||||
# not left-aligned
|
||||
div.firstChild.style.display = 'block'
|
||||
div.firstChild.nextSibling.style.display = 'block'
|
||||
else:
|
||||
for c in div.childNodes:
|
||||
c.style.display = 'none'
|
||||
|
||||
div = document.getElementById('book-bottom-margin')
|
||||
if not div:
|
||||
return
|
||||
pcelem = div.lastChild
|
||||
percent = min(100, max(Math.round(pos_frac * 100), 0))
|
||||
text = percent + '%'
|
||||
if text is not pcelem.textContent:
|
||||
pcelem.textContent = text
|
||||
pcelem.style.display = 'block' if sd.get('margin_bottom', 20) > 5 else 'none'
|
||||
if div:
|
||||
render_template(div, 'margin_bottom', 'footer')
|
||||
div = document.getElementById('book-top-margin')
|
||||
if div:
|
||||
render_template(div, 'margin_top', 'header')
|
||||
if has_clock:
|
||||
if not self.clock_timer_id:
|
||||
self.clock_timer_id = window.setInterval(self.update_header_footer, 60000)
|
||||
else:
|
||||
if self.clock_timer_id:
|
||||
window.clearInterval(self.clock_timer_id)
|
||||
self.clock_timer_id = 0
|
||||
|
||||
|
||||
def on_update_toc_position(self, data):
|
||||
update_visible_toc_nodes(data.visible_anchors)
|
||||
@ -525,7 +554,8 @@ class View:
|
||||
self.processing_spine_item_display = False
|
||||
self.hide_loading()
|
||||
frac = data.progress_frac or 0
|
||||
self.update_read_percent(frac)
|
||||
self.current_progress_frac = frac
|
||||
self.update_header_footer()
|
||||
window.scrollTo(0, 0) # ensure window is at 0 on mobile where the navbar causes issues
|
||||
|
||||
def update_font_size(self):
|
||||
|
Loading…
x
Reference in New Issue
Block a user