Ensure iframe has focus after overlay is closed

Also use the regular overlay mechanism for metadata and
location overlays
This commit is contained in:
Kovid Goyal 2019-08-19 09:50:06 +05:30
parent 782c088bb9
commit 102be318d8
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 116 additions and 100 deletions

View File

@ -1,14 +1,16 @@
# vim:fileencoding=utf-8
# 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 gettext import gettext as _
from book_list.item_list import create_item, build_list
from read_book.toc import get_toc_maps, get_border_nodes
from read_book.globals import current_book
from book_list.item_list import build_list, create_item
from dom import ensure_id, set_css
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):
@ -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(_('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(_('Metadata'), subtitle=_('Details about this book'), action=onclick.bind(None, def(view): view.show_book_metadata();)))
items.push(create_item(_('Location'), subtitle=current_cfi or None, action=onclick.bind(None, def(view): view.ask_for_location();)))
items.push(create_item(_('Metadata'), subtitle=_('Details about this book'), action=onclick.bind(None, def(view):
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:
items.push(create_item(l.title, action=onclick.bind(None, l.dest, l.frag)))
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(panel, flex_grow='10')
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))
)
)
))

View File

@ -5,13 +5,14 @@ from __python__ import bound_methods, hash_literals
from elementmaker import E
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.router import home
from book_list.theme import get_color
from dom import add_extra_css, build_rule, clear, set_css, svgicon, unique_id
from modals import error_dialog
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.prefs.font_size import create_font_size_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_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)')
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):
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):
self.overlay = overlay
self.create_func = create_func or create_toc_panel
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):
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(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'),
))
simple_overlay_title(self.title, self.overlay, container)
self.create_func(self.overlay.view.book, container, self.handle_activate)
def handle_activate(self, dest, frag):
@ -444,7 +465,11 @@ class Overlay:
return self.container.style.display is not 'none'
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):
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.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):
self.hide()
self.view.show_search()

View File

@ -7,10 +7,9 @@ from gettext import gettext as _
import read_book.iframe # noqa
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.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 modals import error_dialog, warning_dialog
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 session import get_device_uuid, get_interface_data
from utils import html_escape, is_ios, parse_url_params, username_key
from widgets import create_button
add_extra_css(def():
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):
@ -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%; 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%; 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
)
)
@ -317,6 +247,10 @@ class View:
self.overlay.hide()
self.search_overlay.hide()
self.content_popup_overlay.hide()
self.focus_iframe()
def focus_iframe(self):
self.iframe.contentWindow.focus()
def show_chrome(self):
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]
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):
self.show_name(data.name, initial_position={'type':'anchor', 'anchor':data.frag, 'replace_history':False})