mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
E-book viewer: Allow clicking links in popup footnotes. Fixes #1931646 [Footnotes/Endnotes don't return to text](https://bugs.launchpad.net/calibre/+bug/1931646)
This commit is contained in:
parent
cff4d491ea
commit
78dea8e439
@ -58,6 +58,8 @@ class ContentPopupOverlay:
|
||||
'ready': self.on_iframe_ready,
|
||||
'error': self.view.on_iframe_error,
|
||||
'content_loaded': self.on_content_loaded,
|
||||
'print': self.on_print,
|
||||
'link_activated': self.on_link_activated,
|
||||
}
|
||||
iframe_kw = {
|
||||
'seamless': True, 'sandbox': 'allow-scripts', 'style': 'width: 100%; max-height: 70vh'
|
||||
@ -72,6 +74,12 @@ class ContentPopupOverlay:
|
||||
c = self.container
|
||||
c.firstChild.appendChild(iframe)
|
||||
|
||||
def on_print(self, data):
|
||||
print(data.string)
|
||||
|
||||
def on_link_activated(self, data):
|
||||
self.view.link_in_content_popup_activated(data.name, data.frag, data.is_popup, data.title)
|
||||
|
||||
@property
|
||||
def container(self):
|
||||
return document.getElementById('book-content-popup-overlay')
|
||||
|
@ -4,6 +4,7 @@ from __python__ import bound_methods, hash_literals
|
||||
|
||||
from dom import clear
|
||||
from iframe_comm import IframeClient
|
||||
from read_book.globals import runtime, current_spine_item, set_current_spine_item
|
||||
from read_book.resources import finalize_resources, unserialize_html
|
||||
from read_book.settings import (
|
||||
apply_settings, set_color_scheme_class, update_settings
|
||||
@ -194,11 +195,12 @@ class PopupIframeBoss:
|
||||
self.blob_url_map = {}
|
||||
self.name = None
|
||||
self.frag = None
|
||||
self.link_attr = None
|
||||
|
||||
def initialize(self, data):
|
||||
window.addEventListener('error', self.onerror)
|
||||
window.addEventListener('error', self.on_error)
|
||||
|
||||
def onerror(self, evt):
|
||||
def on_error(self, evt):
|
||||
msg = evt.message
|
||||
script_url = evt.filename
|
||||
line_number = evt.lineno
|
||||
@ -217,6 +219,16 @@ class PopupIframeBoss:
|
||||
self.book = data.book
|
||||
self.name = data.name
|
||||
self.frag = data.frag
|
||||
self.link_attr = 'data-' + self.book.manifest.link_uid
|
||||
spine = self.book.manifest.spine
|
||||
index = spine.indexOf(data.name)
|
||||
set_current_spine_item({
|
||||
'name':data.name,
|
||||
'is_first':index is 0,
|
||||
'is_last':index is spine.length - 1,
|
||||
'index': index,
|
||||
'initial_position':data.initial_position
|
||||
})
|
||||
update_settings(data.settings)
|
||||
for name in self.blob_url_map:
|
||||
window.URL.revokeObjectURL(self.blob_url_map[name])
|
||||
@ -224,6 +236,35 @@ class PopupIframeBoss:
|
||||
root_data, self.mathjax, self.blob_url_map = finalize_resources(self.book, data.name, data.resource_data)
|
||||
self.resource_urls = unserialize_html(root_data, self.content_loaded, self.show_only_footnote, data.name)
|
||||
|
||||
def connect_links(self):
|
||||
for a in document.body.querySelectorAll(f'a[{self.link_attr}]'):
|
||||
a.addEventListener('click', self.link_activated)
|
||||
if runtime.is_standalone_viewer:
|
||||
# links with a target get turned into requests to open a new window by Qt
|
||||
for a in document.body.querySelectorAll('a[target]'):
|
||||
a.removeAttribute('target')
|
||||
|
||||
def link_activated(self, evt):
|
||||
try:
|
||||
data = JSON.parse(evt.currentTarget.getAttribute(self.link_attr))
|
||||
except:
|
||||
print('WARNING: Failed to parse link data {}, ignoring'.format(evt.currentTarget?.getAttribute?(self.link_attr)))
|
||||
return
|
||||
self.activate_link(data.name, data.frag, evt.currentTarget)
|
||||
|
||||
def activate_link(self, name, frag, target_elem):
|
||||
if not name:
|
||||
name = current_spine_item().name
|
||||
try:
|
||||
is_popup = is_footnote_link(target_elem, name, frag, current_spine_item().name, self.book.manifest.link_to_map or {})
|
||||
title = target_elem.textContent
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
is_popup = False
|
||||
title = ''
|
||||
self.comm.send_message('link_activated', is_popup=is_popup, name=name, frag=frag, title=title)
|
||||
|
||||
def on_clear(self, data):
|
||||
clear(document.head)
|
||||
clear(document.body)
|
||||
@ -242,6 +283,7 @@ class PopupIframeBoss:
|
||||
if not self.comm.encrypted_communications:
|
||||
window.setTimeout(self.content_loaded, 2)
|
||||
return
|
||||
self.connect_links()
|
||||
# this is the loading styles used to suppress scrollbars during load
|
||||
# added in unserialize_html
|
||||
document.head.removeChild(document.head.firstChild)
|
||||
|
@ -154,6 +154,7 @@ class IframeBoss:
|
||||
'scroll_to_anchor': self.on_scroll_to_anchor,
|
||||
'scroll_to_frac': self.on_scroll_to_frac,
|
||||
'scroll_to_ref': self.on_scroll_to_ref,
|
||||
'fake_popup_activation': self.on_fake_popup_activation,
|
||||
'set_reference_mode': self.set_reference_mode,
|
||||
'toggle_autoscroll': self.toggle_autoscroll,
|
||||
'fake_wheel_event': self.fake_wheel_event,
|
||||
@ -718,7 +719,7 @@ class IframeBoss:
|
||||
traceback.print_exc()
|
||||
is_popup = False
|
||||
if is_popup:
|
||||
self.send_message('show_footnote', name=name, frag=frag, title=target_elem.textContent, cols_per_screen=calc_columns_per_screen())
|
||||
self.on_fake_popup_activation({'name': name, 'frag': frag, 'title': target_elem.textContent})
|
||||
return
|
||||
if name is current_spine_item().name:
|
||||
self.replace_history_on_next_cfi_update = False
|
||||
@ -726,6 +727,9 @@ class IframeBoss:
|
||||
else:
|
||||
self.send_message('scroll_to_anchor', name=name, frag=frag)
|
||||
|
||||
def on_fake_popup_activation(self, data):
|
||||
self.send_message('show_footnote', name=data.name, frag=data.frag, title=data.title, cols_per_screen=calc_columns_per_screen())
|
||||
|
||||
def scroll_to_anchor(self, frag):
|
||||
if frag:
|
||||
elem = document.getElementById(frag)
|
||||
|
@ -1062,6 +1062,13 @@ class View:
|
||||
def on_scroll_to_anchor(self, data):
|
||||
self.show_name(data.name, initial_position={'type':'anchor', 'anchor':data.frag, 'replace_history':False})
|
||||
|
||||
def link_in_content_popup_activated(self, name, frag, is_popup, title):
|
||||
self.content_popup_overlay.hide()
|
||||
if is_popup:
|
||||
self.iframe_wrapper.send_message('fake_popup_activation', name=name, frag=frag, title=title)
|
||||
else:
|
||||
self.goto_named_destination(name, frag)
|
||||
|
||||
def goto_cfi(self, bookpos, add_to_history):
|
||||
cfiname, internal_cfi = self.parse_cfi(bookpos, self.book)
|
||||
if cfiname and internal_cfi:
|
||||
|
Loading…
x
Reference in New Issue
Block a user