mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Ensure iframe has focus after overlay is closed
Also use the regular overlay mechanism for metadata and location overlays
This commit is contained in:
parent
782c088bb9
commit
102be318d8
@ -1,14 +1,16 @@
|
|||||||
# vim:fileencoding=utf-8
|
# vim:fileencoding=utf-8
|
||||||
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
from __python__ import hash_literals, bound_methods
|
from __python__ import bound_methods, hash_literals
|
||||||
|
|
||||||
from dom import set_css
|
|
||||||
from elementmaker import E
|
from elementmaker import E
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
|
|
||||||
from book_list.item_list import create_item, build_list
|
from book_list.item_list import build_list, create_item
|
||||||
from read_book.toc import get_toc_maps, get_border_nodes
|
from dom import ensure_id, set_css
|
||||||
from read_book.globals import current_book
|
from modals import error_dialog
|
||||||
|
from read_book.globals import current_book, ui_operations
|
||||||
|
from read_book.toc import get_border_nodes, get_toc_maps
|
||||||
|
from widgets import create_button
|
||||||
|
|
||||||
|
|
||||||
def create_goto_list(onclick, current_cfi):
|
def create_goto_list(onclick, current_cfi):
|
||||||
@ -24,8 +26,10 @@ def create_goto_list(onclick, current_cfi):
|
|||||||
items.push(create_item(_('Previous section'), icon='caret-left', subtitle=before.title, action=onclick.bind(None, before.dest, before.frag)))
|
items.push(create_item(_('Previous section'), icon='caret-left', subtitle=before.title, action=onclick.bind(None, before.dest, before.frag)))
|
||||||
items.push(create_item(_('Document start'), action=onclick.bind(None, def(view): view.goto_doc_boundary(True);)))
|
items.push(create_item(_('Document start'), action=onclick.bind(None, def(view): view.goto_doc_boundary(True);)))
|
||||||
items.push(create_item(_('Document end'), action=onclick.bind(None, def(view): view.goto_doc_boundary(False);)))
|
items.push(create_item(_('Document end'), action=onclick.bind(None, def(view): view.goto_doc_boundary(False);)))
|
||||||
items.push(create_item(_('Metadata'), subtitle=_('Details about this book'), action=onclick.bind(None, def(view): view.show_book_metadata();)))
|
items.push(create_item(_('Metadata'), subtitle=_('Details about this book'), action=onclick.bind(None, def(view):
|
||||||
items.push(create_item(_('Location'), subtitle=current_cfi or None, action=onclick.bind(None, def(view): view.ask_for_location();)))
|
view.overlay.show_metadata()
|
||||||
|
)))
|
||||||
|
items.push(create_item(_('Location'), subtitle=current_cfi or None, action=onclick.bind(None, def(view): view.overlay.show_ask_for_location();)))
|
||||||
for l in landmarks:
|
for l in landmarks:
|
||||||
items.push(create_item(l.title, action=onclick.bind(None, l.dest, l.frag)))
|
items.push(create_item(l.title, action=onclick.bind(None, l.dest, l.frag)))
|
||||||
build_list(ans, items)
|
build_list(ans, items)
|
||||||
@ -44,3 +48,45 @@ def create_goto_panel(current_cfi, book, container, onclick):
|
|||||||
set_css(container, display='flex', flex_direction='column')
|
set_css(container, display='flex', flex_direction='column')
|
||||||
set_css(panel, flex_grow='10')
|
set_css(panel, flex_grow='10')
|
||||||
container.appendChild(panel)
|
container.appendChild(panel)
|
||||||
|
|
||||||
|
|
||||||
|
def create_location_overlay(current_cfi, overlay, container):
|
||||||
|
container_id = ensure_id(container)
|
||||||
|
if current_cfi:
|
||||||
|
container.appendChild(E.div(
|
||||||
|
style='margin: 1rem; display: flex; align-items: baseline',
|
||||||
|
E.input(
|
||||||
|
type='text', readonly='readonly', value=_('Currently at: {}').format(current_cfi), name='current_location',
|
||||||
|
style='border-width: 0; background-color: transparent; outline: none; flex-grow: 10; font-family: inherit'
|
||||||
|
),
|
||||||
|
create_button(_('Copy'), action=def():
|
||||||
|
src = document.querySelector(f'#{container_id} [name=current_location]')
|
||||||
|
orig = src.value
|
||||||
|
src.value = current_cfi
|
||||||
|
src.focus()
|
||||||
|
src.select()
|
||||||
|
try:
|
||||||
|
document.execCommand('copy')
|
||||||
|
finally:
|
||||||
|
src.value = orig
|
||||||
|
src.blur()
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
|
container.appendChild(E.div(
|
||||||
|
style='margin: 1rem;',
|
||||||
|
E.div(
|
||||||
|
style='display: flex; align-items: baseline',
|
||||||
|
E.label(_('Go to:'), style='margin-right: 1rem'),
|
||||||
|
E.input(name='newloc', type='text', style='flex-grow: 10; margin-right: 1rem'), E.span(' '),
|
||||||
|
create_button(_('Go'), action=def():
|
||||||
|
src = document.querySelector(f'#{container_id} [name=newloc]')
|
||||||
|
if src.value:
|
||||||
|
if ui_operations.goto_bookpos(src.value):
|
||||||
|
overlay.hide()
|
||||||
|
else:
|
||||||
|
error_dialog(_('No such location'), _(
|
||||||
|
'No location {} found').format(src.value))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
))
|
||||||
|
@ -5,13 +5,14 @@ from __python__ import bound_methods, hash_literals
|
|||||||
from elementmaker import E
|
from elementmaker import E
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
|
|
||||||
|
from book_list.book_details import CLASS_NAME as BD_CLASS_NAME, render_metadata
|
||||||
from book_list.library_data import sync_library_books
|
from book_list.library_data import sync_library_books
|
||||||
from book_list.router import home
|
from book_list.router import home
|
||||||
from book_list.theme import get_color
|
from book_list.theme import get_color
|
||||||
from dom import add_extra_css, build_rule, clear, set_css, svgicon, unique_id
|
from dom import add_extra_css, build_rule, clear, set_css, svgicon, unique_id
|
||||||
from modals import error_dialog
|
from modals import error_dialog
|
||||||
from read_book.globals import runtime, ui_operations
|
from read_book.globals import runtime, ui_operations
|
||||||
from read_book.goto import create_goto_panel
|
from read_book.goto import create_goto_panel, create_location_overlay
|
||||||
from read_book.open_book import create_open_book
|
from read_book.open_book import create_open_book
|
||||||
from read_book.prefs.font_size import create_font_size_panel
|
from read_book.prefs.font_size import create_font_size_panel
|
||||||
from read_book.prefs.main import create_prefs_panel
|
from read_book.prefs.main import create_prefs_panel
|
||||||
@ -170,8 +171,7 @@ class SyncBook: # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
# MainOverlay {{{
|
# CSS {{{
|
||||||
|
|
||||||
MAIN_OVERLAY_TS_CLASS = 'read-book-main-overlay-top-section'
|
MAIN_OVERLAY_TS_CLASS = 'read-book-main-overlay-top-section'
|
||||||
MAIN_OVERLAY_ACTIONS_CLASS = 'read-book-main-overlay-actions'
|
MAIN_OVERLAY_ACTIONS_CLASS = 'read-book-main-overlay-actions'
|
||||||
|
|
||||||
@ -188,8 +188,22 @@ add_extra_css(def():
|
|||||||
style += build_rule(sel + ':active > *:first-child', transform='scale(1.8)')
|
style += build_rule(sel + ':active > *:first-child', transform='scale(1.8)')
|
||||||
return style
|
return style
|
||||||
)
|
)
|
||||||
|
# }}}
|
||||||
|
|
||||||
class MainOverlay:
|
def simple_overlay_title(title, overlay, container):
|
||||||
|
container.style.backgroundColor = get_color('window-background')
|
||||||
|
container.appendChild(E.div(
|
||||||
|
style='padding: 1ex 1em; border-bottom: solid 1px currentColor; display:flex; justify-content: space-between',
|
||||||
|
E.h2(title),
|
||||||
|
E.div(svgicon('close'), style='cursor:pointer', onclick=def (event):
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
overlay.hide_current_panel(event)
|
||||||
|
, class_='simple-link'),
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
class MainOverlay: # {{{
|
||||||
|
|
||||||
def __init__(self, overlay):
|
def __init__(self, overlay):
|
||||||
self.overlay = overlay
|
self.overlay = overlay
|
||||||
@ -317,23 +331,30 @@ class MainOverlay:
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class TOCOverlay: # {{{
|
class SimpleOverlay: # {{{
|
||||||
|
|
||||||
|
def __init__(self, overlay, create_func, title):
|
||||||
|
self.overlay = overlay
|
||||||
|
self.create_func = create_func
|
||||||
|
self.title = title
|
||||||
|
|
||||||
|
def on_container_click(self, evt):
|
||||||
|
pass # Dont allow panel to be closed by a click
|
||||||
|
|
||||||
|
def show(self, container):
|
||||||
|
simple_overlay_title(self.title, self.overlay, container)
|
||||||
|
self.create_func(self.overlay, container)
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
class TOCOverlay(SimpleOverlay): # {{{
|
||||||
|
|
||||||
def __init__(self, overlay, create_func, title):
|
def __init__(self, overlay, create_func, title):
|
||||||
self.overlay = overlay
|
self.overlay = overlay
|
||||||
self.create_func = create_func or create_toc_panel
|
self.create_func = create_func or create_toc_panel
|
||||||
self.title = title or _('Table of Contents')
|
self.title = title or _('Table of Contents')
|
||||||
|
|
||||||
def on_container_click(self, evt):
|
|
||||||
pass # Dont allow panel to be closed by a click
|
|
||||||
|
|
||||||
def show(self, container):
|
def show(self, container):
|
||||||
container.style.backgroundColor = get_color('window-background')
|
simple_overlay_title(self.title, self.overlay, container)
|
||||||
container.appendChild(E.div(
|
|
||||||
style='padding: 1ex 1em; border-bottom: solid 1px currentColor; display:flex; justify-content: space-between',
|
|
||||||
E.h2(self.title),
|
|
||||||
E.div(svgicon('close'), style='cursor:pointer', onclick=def(event):event.preventDefault(), event.stopPropagation(), self.overlay.hide_current_panel(event);, class_='simple-link'),
|
|
||||||
))
|
|
||||||
self.create_func(self.overlay.view.book, container, self.handle_activate)
|
self.create_func(self.overlay.view.book, container, self.handle_activate)
|
||||||
|
|
||||||
def handle_activate(self, dest, frag):
|
def handle_activate(self, dest, frag):
|
||||||
@ -444,7 +465,11 @@ class Overlay:
|
|||||||
return self.container.style.display is not 'none'
|
return self.container.style.display is not 'none'
|
||||||
|
|
||||||
def update_visibility(self):
|
def update_visibility(self):
|
||||||
self.container.style.display = 'block' if self.panels.length else 'none'
|
if self.panels.length:
|
||||||
|
self.container.style.display = 'block'
|
||||||
|
elif self.container.style.display is 'block':
|
||||||
|
self.container.style.display = 'none'
|
||||||
|
self.view.focus_iframe()
|
||||||
|
|
||||||
def container_clicked(self, evt):
|
def container_clicked(self, evt):
|
||||||
if self.panels.length and jstype(self.panels[-1].on_container_click) is 'function':
|
if self.panels.length and jstype(self.panels[-1].on_container_click) is 'function':
|
||||||
@ -523,6 +548,24 @@ class Overlay:
|
|||||||
self.panels.push(TOCOverlay(self, create_goto_panel.bind(None, self.view.currently_showing.bookpos), _('Go to…')))
|
self.panels.push(TOCOverlay(self, create_goto_panel.bind(None, self.view.currently_showing.bookpos), _('Go to…')))
|
||||||
self.show_current_panel()
|
self.show_current_panel()
|
||||||
|
|
||||||
|
def show_metadata(self):
|
||||||
|
self.hide_current_panel()
|
||||||
|
|
||||||
|
def show_metadata_overlay(mi, overlay, container):
|
||||||
|
container.appendChild(E.div(class_=BD_CLASS_NAME, style='padding: 1ex 1em'))
|
||||||
|
table = E.table(class_='metadata')
|
||||||
|
container.lastChild.appendChild(table)
|
||||||
|
render_metadata(mi, table)
|
||||||
|
|
||||||
|
self.panels.push(SimpleOverlay(self, show_metadata_overlay.bind(None, self.view.book.metadata), self.view.book.metadata.title))
|
||||||
|
self.show_current_panel()
|
||||||
|
|
||||||
|
def show_ask_for_location(self):
|
||||||
|
self.hide_current_panel()
|
||||||
|
self.panels.push(SimpleOverlay(
|
||||||
|
self, create_location_overlay.bind(None, self.view.currently_showing.bookpos), _('Go to location…')))
|
||||||
|
self.show_current_panel()
|
||||||
|
|
||||||
def show_search(self):
|
def show_search(self):
|
||||||
self.hide()
|
self.hide()
|
||||||
self.view.show_search()
|
self.view.show_search()
|
||||||
|
@ -7,10 +7,9 @@ from gettext import gettext as _
|
|||||||
|
|
||||||
import read_book.iframe # noqa
|
import read_book.iframe # noqa
|
||||||
from ajax import ajax_send
|
from ajax import ajax_send
|
||||||
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.globals import get_session_data
|
||||||
from book_list.theme import get_color
|
from book_list.theme import get_color
|
||||||
from dom import add_extra_css, build_rule, clear, set_css, svgicon, unique_id
|
from dom import add_extra_css, build_rule, set_css, svgicon, unique_id
|
||||||
from iframe_comm import IframeWrapper
|
from iframe_comm import IframeWrapper
|
||||||
from modals import error_dialog, warning_dialog
|
from modals import error_dialog, warning_dialog
|
||||||
from read_book.content_popup import ContentPopupOverlay
|
from read_book.content_popup import ContentPopupOverlay
|
||||||
@ -30,7 +29,6 @@ from read_book.toc import get_current_toc_nodes, update_visible_toc_nodes
|
|||||||
from read_book.touch import set_left_margin_handler, set_right_margin_handler
|
from read_book.touch import set_left_margin_handler, set_right_margin_handler
|
||||||
from session import get_device_uuid, get_interface_data
|
from session import get_device_uuid, get_interface_data
|
||||||
from utils import html_escape, is_ios, parse_url_params, username_key
|
from utils import html_escape, is_ios, parse_url_params, username_key
|
||||||
from widgets import create_button
|
|
||||||
|
|
||||||
add_extra_css(def():
|
add_extra_css(def():
|
||||||
sel = '.book-side-margin'
|
sel = '.book-side-margin'
|
||||||
@ -74,73 +72,6 @@ def show_controls_help():
|
|||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
def setup_metadata_overlay(title):
|
|
||||||
container = document.getElementById('book-metadata-overlay')
|
|
||||||
clear(container)
|
|
||||||
container.style.display = 'block'
|
|
||||||
container.style.backgroundColor = get_color('window-background')
|
|
||||||
container.appendChild(E.div(
|
|
||||||
style='padding: 1ex 1em; border-bottom: solid 1px currentColor; display:flex; justify-content: space-between;',
|
|
||||||
E.h2(title),
|
|
||||||
E.div(svgicon('close'), style='cursor:pointer', class_='simple-link', onclick=def(event):
|
|
||||||
event.preventDefault()
|
|
||||||
event.stopPropagation()
|
|
||||||
document.getElementById('book-metadata-overlay').style.display = 'none'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return container
|
|
||||||
|
|
||||||
|
|
||||||
def show_metadata_overlay(mi):
|
|
||||||
container = setup_metadata_overlay(mi.title)
|
|
||||||
container.appendChild(E.div(class_=BD_CLASS_NAME, style='padding: 1ex 1em'))
|
|
||||||
table = E.table(class_='metadata')
|
|
||||||
container.lastChild.appendChild(table)
|
|
||||||
render_metadata(mi, table)
|
|
||||||
|
|
||||||
|
|
||||||
def show_location_overlay(current_cfi):
|
|
||||||
container = setup_metadata_overlay(_('Go to location…'))
|
|
||||||
container_id = container.id
|
|
||||||
if current_cfi:
|
|
||||||
container.appendChild(E.div(
|
|
||||||
style='margin: 1rem; display: flex; align-items: baseline',
|
|
||||||
E.input(
|
|
||||||
type='text', readonly='readonly', value=_('Currently at: {}').format(current_cfi), name='current_location',
|
|
||||||
style='border-width: 0; background-color: transparent; outline: none; flex-grow: 10; font-family: inherit'
|
|
||||||
),
|
|
||||||
create_button(_('Copy'), action=def():
|
|
||||||
src = document.querySelector(f'#{container_id} [name=current_location]')
|
|
||||||
orig = src.value
|
|
||||||
src.value = current_cfi
|
|
||||||
src.focus()
|
|
||||||
src.select()
|
|
||||||
try:
|
|
||||||
document.execCommand('copy')
|
|
||||||
finally:
|
|
||||||
src.value = orig
|
|
||||||
src.blur()
|
|
||||||
)
|
|
||||||
))
|
|
||||||
container.appendChild(E.div(
|
|
||||||
style='margin: 1rem;',
|
|
||||||
E.div(
|
|
||||||
style='display: flex; align-items: baseline',
|
|
||||||
E.label(_('Go to:'), style='margin-right: 1rem'),
|
|
||||||
E.input(name='newloc', type='text', style='flex-grow: 10; margin-right: 1rem'), E.span(' '),
|
|
||||||
create_button(_('Go'), action=def():
|
|
||||||
src = document.querySelector(f'#{container_id} [name=newloc]')
|
|
||||||
if src.value:
|
|
||||||
if ui_operations.goto_bookpos(src.value):
|
|
||||||
document.getElementById(container_id).style.display = 'none'
|
|
||||||
else:
|
|
||||||
error_dialog(_('No such location'), _(
|
|
||||||
'No location {} found').format(src.value))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
))
|
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
def margin_elem(sd, which, id, onclick):
|
def margin_elem(sd, which, id, onclick):
|
||||||
@ -193,7 +124,6 @@ class View:
|
|||||||
E.div(style='position: absolute; top:0; left:0; width: 100%; pointer-events:none; display:none', id='book-search-overlay'), # search overlay
|
E.div(style='position: absolute; top:0; left:0; width: 100%; pointer-events:none; display:none', id='book-search-overlay'), # search overlay
|
||||||
E.div(style='position: absolute; top:0; left:0; width: 100%; height: 100%; display:none', id='book-content-popup-overlay'), # content popup overlay
|
E.div(style='position: absolute; top:0; left:0; width: 100%; height: 100%; display:none', id='book-content-popup-overlay'), # content popup overlay
|
||||||
E.div(style='position: absolute; top:0; left:0; width: 100%; height: 100%; display:none', id='book-overlay'), # main overlay
|
E.div(style='position: absolute; top:0; left:0; width: 100%; height: 100%; display:none', id='book-overlay'), # main overlay
|
||||||
E.div(style='position: absolute; top:0; left:0; width: 100%; min-height: 100%; display:none', id='book-metadata-overlay'), # book metadata overlay
|
|
||||||
E.div(style='position: absolute; top:0; left:0; width: 100%; height: 100%; display:none', id='controls-help-overlay'), # controls help overlay
|
E.div(style='position: absolute; top:0; left:0; width: 100%; height: 100%; display:none', id='controls-help-overlay'), # controls help overlay
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -317,6 +247,10 @@ class View:
|
|||||||
self.overlay.hide()
|
self.overlay.hide()
|
||||||
self.search_overlay.hide()
|
self.search_overlay.hide()
|
||||||
self.content_popup_overlay.hide()
|
self.content_popup_overlay.hide()
|
||||||
|
self.focus_iframe()
|
||||||
|
|
||||||
|
def focus_iframe(self):
|
||||||
|
self.iframe.contentWindow.focus()
|
||||||
|
|
||||||
def show_chrome(self):
|
def show_chrome(self):
|
||||||
self.show_chrome_counter += 1
|
self.show_chrome_counter += 1
|
||||||
@ -509,13 +443,6 @@ class View:
|
|||||||
name = self.book.manifest.spine[0 if start else self.book.manifest.spine.length - 1]
|
name = self.book.manifest.spine[0 if start else self.book.manifest.spine.length - 1]
|
||||||
self.show_name(name, initial_position={'type':'frac', 'frac':0 if start else 1, 'replace_history':False})
|
self.show_name(name, initial_position={'type':'frac', 'frac':0 if start else 1, 'replace_history':False})
|
||||||
|
|
||||||
def show_book_metadata(self):
|
|
||||||
mi = self.book.metadata
|
|
||||||
show_metadata_overlay(mi)
|
|
||||||
|
|
||||||
def ask_for_location(self):
|
|
||||||
show_location_overlay(self.currently_showing.bookpos)
|
|
||||||
|
|
||||||
def on_scroll_to_anchor(self, data):
|
def on_scroll_to_anchor(self, data):
|
||||||
self.show_name(data.name, initial_position={'type':'anchor', 'anchor':data.frag, 'replace_history':False})
|
self.show_name(data.name, initial_position={'type':'anchor', 'anchor':data.frag, 'replace_history':False})
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user