Start work on popup footnote support in the browser viewer

This commit is contained in:
Kovid Goyal 2017-10-13 10:39:32 +05:30
parent 3809604157
commit 41bc26645a
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 86 additions and 2 deletions

View File

@ -201,6 +201,7 @@ class Container(ContainerBase):
'spine_length': 0,
'toc_anchor_map': toc_anchor_map(toc),
'landmarks': landmarks,
'link_to_map': {},
}
# Mark the spine as dirty since we have to ensure it is normalized
for name in data['spine']:
@ -328,6 +329,8 @@ class Container(ContainerBase):
changed.add(base)
return url
ltm = self.book_render_data['link_to_map']
for name, mt in self.mime_map.iteritems():
mt = mt.lower()
if mt in OEB_STYLES:
@ -350,7 +353,9 @@ class Container(ContainerBase):
if href.startswith(link_uid):
a.set('href', 'javascript:void(0)')
parts = decode_url(href.split('|')[1])
a.set('data-' + link_uid, json.dumps({'name':parts[0], 'frag':parts[1]}, ensure_ascii=False))
lname, lfrag = parts[0], parts[1]
ltm.setdefault(lname, {}).setdefault(lfrag or '', []).append(name)
a.set('data-' + link_uid, json.dumps({'name':lname, 'frag':lfrag}, ensure_ascii=False))
else:
a.set('target', '_blank')
a.set('rel', 'noopener noreferrer')
@ -382,7 +387,7 @@ boolean_attributes = frozenset('allowfullscreen,async,autofocus,autoplay,checked
EPUB_TYPE_MAP = {k:'doc-' + k for k in (
'abstract acknowledgements afterword appendix biblioentry bibliography biblioref chapter colophon conclusion cover credit'
' credits dedication epigraph epilogue errata footnote footnotes forward glossary glossref index introduction noteref notice'
' credits dedication epigraph epilogue errata footnote footnotes forward glossary glossref index introduction link noteref notice'
' pagebreak pagelist part preface prologue pullquote qna locator subtitle title toc').split(' ')}
for k in 'figure term definition directory list list-item table row cell'.split(' '):
EPUB_TYPE_MAP[k] = k

View File

@ -0,0 +1,70 @@
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
from __python__ import bound_methods, hash_literals
def elem_roles(elem):
return {k.toLowerCase(): True for k in (elem.getAttribute('role') or '').split(' ')}
def get_containing_block(node):
while node and node.tagName and get_containing_block.block_names[node.tagName.toLowerCase()] is not True:
node = node.parentNode
return node
get_containing_block.block_names = dict.fromkeys(v"['p', 'div', 'li', 'td', 'h1', 'h2', 'h2', 'h3', 'h4', 'h5', 'h6', 'body']", True).as_object()
def is_footnote_link(a, dest_name, dest_frag, src_name, link_to_map):
roles = elem_roles(a)
if roles['doc-noteref']:
return True
if roles['doc-link']:
return False
# Check if node or any of its first few parents have vertical-align set
x, num = a, 3
while x and num > 0:
style = window.getComputedStyle(x)
if not is_footnote_link.inline_displays[style.display]:
break
if is_footnote_link.vert_aligns[style.verticalAlign]:
return True
x = x.parentNode
num -= 1
# Check if node has a single child with the appropriate css
children = [x for x in a.childNodes if x.nodeType is Node.ELEMENT_NODE]
if children.length == 1:
style = window.getComputedStyle(children[0])
if is_footnote_link.inline_displays[style.display] and is_footnote_link.vert_aligns[style.verticalAlign]:
text_children = [x for x in a.childNodes if x.nodeType is Node.TEXT_NODE and x.nodeValue and /\S+/.test(x.nodeValue)]
if not text_children.length:
return True
eid = a.getAttribute('id') or a.getAttribute('name')
files_linking_to_self = link_to_map[src_name]
if eid and files_linking_to_self:
files_linking_to_anchor = files_linking_to_self[eid]
if files_linking_to_anchor.length > 1 or (files_linking_to_anchor.length == 1 and files_linking_to_anchor[0] is not src_name):
# An <a href="..." id="..."> link that is linked back from some other
# file in the spine, most likely an endnote. We exclude links that are
# the only content of their parent block tag, as these are not likely
# to be endnotes.
cb = get_containing_block(a)
if not cb or cb.tagName.toLowerCase() == 'body':
return False
ltext = a.textContent
if not ltext:
return False
ctext = cb.textContent
if not ctext:
return False
if ctext.strip() is ltext.strip():
return False
return True
return False
is_footnote_link.inline_displays = {'inline': True, 'inline-block': True}
is_footnote_link.vert_aligns = {'sub': True, 'super': True, 'top': True, 'bottom': True}

View File

@ -12,6 +12,7 @@ from read_book.flow_mode import (
flow_to_scroll_fraction, handle_gesture as flow_handle_gesture,
layout as flow_layout, scroll_by_page as flow_scroll_by_page
)
from read_book.footnotes import is_footnote_link
from read_book.globals import (
current_book, current_layout_mode, current_spine_item, set_boss,
set_current_spine_item, set_layout_mode
@ -383,6 +384,14 @@ class IframeBoss:
name, frag = data.name, data.frag
if not name:
name = current_spine_item().name
try:
is_popup = is_footnote_link(evt.currentTarget, name, frag, current_spine_item().name, self.book.manifest.link_to_map or {})
except:
import traceback
traceback.print_exc()
is_popup = False
if is_popup:
pass
if name is current_spine_item().name:
self.replace_history_on_next_cfi_update = False
self.scroll_to_anchor(frag)