mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Start work on popup footnote support in the browser viewer
This commit is contained in:
parent
3809604157
commit
41bc26645a
@ -201,6 +201,7 @@ class Container(ContainerBase):
|
|||||||
'spine_length': 0,
|
'spine_length': 0,
|
||||||
'toc_anchor_map': toc_anchor_map(toc),
|
'toc_anchor_map': toc_anchor_map(toc),
|
||||||
'landmarks': landmarks,
|
'landmarks': landmarks,
|
||||||
|
'link_to_map': {},
|
||||||
}
|
}
|
||||||
# Mark the spine as dirty since we have to ensure it is normalized
|
# Mark the spine as dirty since we have to ensure it is normalized
|
||||||
for name in data['spine']:
|
for name in data['spine']:
|
||||||
@ -328,6 +329,8 @@ class Container(ContainerBase):
|
|||||||
changed.add(base)
|
changed.add(base)
|
||||||
return url
|
return url
|
||||||
|
|
||||||
|
ltm = self.book_render_data['link_to_map']
|
||||||
|
|
||||||
for name, mt in self.mime_map.iteritems():
|
for name, mt in self.mime_map.iteritems():
|
||||||
mt = mt.lower()
|
mt = mt.lower()
|
||||||
if mt in OEB_STYLES:
|
if mt in OEB_STYLES:
|
||||||
@ -350,7 +353,9 @@ class Container(ContainerBase):
|
|||||||
if href.startswith(link_uid):
|
if href.startswith(link_uid):
|
||||||
a.set('href', 'javascript:void(0)')
|
a.set('href', 'javascript:void(0)')
|
||||||
parts = decode_url(href.split('|')[1])
|
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:
|
else:
|
||||||
a.set('target', '_blank')
|
a.set('target', '_blank')
|
||||||
a.set('rel', 'noopener noreferrer')
|
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 (
|
EPUB_TYPE_MAP = {k:'doc-' + k for k in (
|
||||||
'abstract acknowledgements afterword appendix biblioentry bibliography biblioref chapter colophon conclusion cover credit'
|
'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(' ')}
|
' 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(' '):
|
for k in 'figure term definition directory list list-item table row cell'.split(' '):
|
||||||
EPUB_TYPE_MAP[k] = k
|
EPUB_TYPE_MAP[k] = k
|
||||||
|
70
src/pyj/read_book/footnotes.pyj
Normal file
70
src/pyj/read_book/footnotes.pyj
Normal 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}
|
@ -12,6 +12,7 @@ from read_book.flow_mode import (
|
|||||||
flow_to_scroll_fraction, handle_gesture as flow_handle_gesture,
|
flow_to_scroll_fraction, handle_gesture as flow_handle_gesture,
|
||||||
layout as flow_layout, scroll_by_page as flow_scroll_by_page
|
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 (
|
from read_book.globals import (
|
||||||
current_book, current_layout_mode, current_spine_item, set_boss,
|
current_book, current_layout_mode, current_spine_item, set_boss,
|
||||||
set_current_spine_item, set_layout_mode
|
set_current_spine_item, set_layout_mode
|
||||||
@ -383,6 +384,14 @@ class IframeBoss:
|
|||||||
name, frag = data.name, data.frag
|
name, frag = data.name, data.frag
|
||||||
if not name:
|
if not name:
|
||||||
name = current_spine_item().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:
|
if name is current_spine_item().name:
|
||||||
self.replace_history_on_next_cfi_update = False
|
self.replace_history_on_next_cfi_update = False
|
||||||
self.scroll_to_anchor(frag)
|
self.scroll_to_anchor(frag)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user