From cec5d41697cc10990db1059a4b2217c21b30b940 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 8 Aug 2014 17:54:46 +0530 Subject: [PATCH] Recognize footnote links --- src/calibre/ebooks/oeb/display/extract.coffee | 41 +++++++++++++++++++ src/calibre/gui2/viewer/documentview.py | 8 ++++ src/calibre/gui2/viewer/footnote.py | 23 ++++++++++- 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/calibre/ebooks/oeb/display/extract.coffee b/src/calibre/ebooks/oeb/display/extract.coffee index 92ed91a24f..a8499dd00e 100644 --- a/src/calibre/ebooks/oeb/display/extract.coffee +++ b/src/calibre/ebooks/oeb/display/extract.coffee @@ -29,6 +29,38 @@ inline_styles = (node) -> return cnode +is_footnote_link = (node, url) -> + if not url or url.substr(0, 'file://'.length).toLowerCase() != 'file://' + return false # Ignore non-local links + # Check for epub:type="noteref", a little complex as we dont operate in XML + # mode + epub_type = node.getAttributeNS("http://www.idpf.org/2007/ops", 'type') or node.getAttribute('epub:type') + if not epub_type + for x in node.attributes # consider any xxx:type="noteref" attribute as marking a note + if x.nodeName and x.nodeValue == 'noteref' and x.nodeName.slice(-':type'.length) == ':type' + epub_type = 'noteref' + break + if epub_type and epub_type.toLowerCase() == 'noteref' + return true + + # Check if node or any of its first few parents have vertical-align set + [x, num] = [node, 3] + while x and num > 0 + style = window.getComputedStyle(x) + if style.verticalAlign in ['sub', 'super'] + return true + x = x.parentNode + num -= 1 + + # Check if node has a single child with the appropriate css + children = (x for x in node.childNodes when x.nodeType == Node.ELEMENT_NODE) + if children.length == 1 + style = window.getComputedStyle(children[0]) + if style.verticalAlign in ['sub', 'super'] + return true + + return false + class CalibreExtract # This class is a namespace to expose functions via the # window.calibre_extract object. @@ -47,6 +79,15 @@ class CalibreExtract cnode = inline_styles(node) return cnode.outerHTML + get_footnote_data: () => + ans = {} + for a in document.querySelectorAll('a[href]') + url = a.href # .href returns the full URL while getAttribute() returns the value of the attribute + if not is_footnote_link(a, url) + continue + ans[url] = 1 + return JSON.stringify(ans) + if window? window.calibre_extract = new CalibreExtract() diff --git a/src/calibre/gui2/viewer/documentview.py b/src/calibre/gui2/viewer/documentview.py index 5f081281aa..a5a3aedba6 100644 --- a/src/calibre/gui2/viewer/documentview.py +++ b/src/calibre/gui2/viewer/documentview.py @@ -27,6 +27,7 @@ from calibre.gui2.viewer.image_popup import ImagePopup from calibre.gui2.viewer.table_popup import TablePopup from calibre.gui2.viewer.inspector import WebInspector from calibre.gui2.viewer.gestures import GestureHandler +from calibre.gui2.viewer.footnote import Footnotes from calibre.ebooks.oeb.display.webview import load_html from calibre.constants import isxp, iswindows, DEBUG # }}} @@ -507,6 +508,7 @@ class DocumentView(QWebView): # {{{ self.to_bottom = False self.document = Document(self.shortcuts, parent=self, debug_javascript=debug_javascript) + self.footnotes = Footnotes(self.document) self.setPage(self.document) self.inspector = WebInspector(self, self.document) self.manager = None @@ -1306,6 +1308,12 @@ class DocumentView(QWebView): # {{{ return QWebView.event(self, ev) def mouseReleaseEvent(self, ev): + url = self.document.mainFrame().hitTestContent(ev.pos()).linkUrl() + if url.isValid(): + fd = self.footnotes.get_footnote_data(url) + if fd is not None: + print (fd) + return opos = self.document.ypos if self.manager is not None: prev_pos = self.manager.update_page_number() diff --git a/src/calibre/gui2/viewer/footnote.py b/src/calibre/gui2/viewer/footnote.py index 8f7421ee3f..f75f9ab6bc 100644 --- a/src/calibre/gui2/viewer/footnote.py +++ b/src/calibre/gui2/viewer/footnote.py @@ -6,11 +6,30 @@ from __future__ import (unicode_literals, division, absolute_import, __license__ = 'GPL v3' __copyright__ = '2014, Kovid Goyal ' +import json + +from PyQt4.Qt import QUrl + class Footnotes(object): - def __init__(self): + def __init__(self, document): + self.document = document self.clear() def clear(self): - self.url_cache = {} + self.footnote_data_cache = {} + + def get_footnote_data(self, url): + current_url = unicode(self.document.mainFrame().baseUrl().toLocalFile()) + if not current_url: + return # Not viewing a local file + fd = self.footnote_data_cache.get(current_url, None) + if fd is None: + raw = self.document.javascript('window.calibre_extract.get_footnote_data()', typ='string') + try: + fd = frozenset(unicode(QUrl(x).toLocalFile()) for x in json.loads(raw)) + except Exception: + fd = frozenset() + self.footnote_data_cache[current_url] = fd +