From e6044fae91631730e9755ad8bf0e8beb83dbd890 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 9 Dec 2019 17:02:30 +0530 Subject: [PATCH] Implement support for references with --open-at --- src/calibre/gui2/viewer/main.py | 5 +++-- src/calibre/gui2/viewer/ui.py | 2 ++ src/pyj/read_book/iframe.pyj | 18 +++++++++++++++++- src/pyj/read_book/referencing.pyj | 6 ++++++ src/pyj/read_book/view.pyj | 16 ++++++++++++++++ 5 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/calibre/gui2/viewer/main.py b/src/calibre/gui2/viewer/main.py index e660c56b97..164571998a 100644 --- a/src/calibre/gui2/viewer/main.py +++ b/src/calibre/gui2/viewer/main.py @@ -168,7 +168,8 @@ View an e-book. 'at the location of the first Table of Contents entry that contains ' 'the string "something". The form toc-href:something will match the ' 'href (internal link destination) of toc nodes. The matching is exact, ' - 'If you want to match a substring, use the form toc-href-contains:something. ')) + 'If you want to match a substring, use the form toc-href-contains:something. ' + 'The form ref:something will use Reference mode references.')) a('--continue', default=False, action='store_true', dest='continue_reading', help=_('Continue reading at the previously opened book')) @@ -192,7 +193,7 @@ def main(args=sys.argv): oat = opts.open_at if oat and not ( oat.startswith('toc:') or oat.startswith('toc-href:') or oat.startswith('toc-href-contains:') or - oat.startswith('epubcfi(/') or is_float(oat)): + oat.startswith('epubcfi(/') or is_float(oat) or oat.startswith('ref:')): raise SystemExit('Not a valid --open-at value: {}'.format(opts.open_at)) listener = None diff --git a/src/calibre/gui2/viewer/ui.py b/src/calibre/gui2/viewer/ui.py index 67eae34ed4..4da692158f 100644 --- a/src/calibre/gui2/viewer/ui.py +++ b/src/calibre/gui2/viewer/ui.py @@ -416,6 +416,8 @@ class EbookViewer(MainWindow): initial_position = {'type': 'toc', 'data': initial_toc_node} elif open_at.startswith('epubcfi(/'): initial_position = {'type': 'cfi', 'data': open_at} + elif open_at.startswith('ref:'): + initial_position = {'type': 'ref', 'data': open_at[len('ref:'):]} elif is_float(open_at): initial_position = {'type': 'bookpos', 'data': float(open_at)} self.web_view.start_book_load(initial_position=initial_position) diff --git a/src/pyj/read_book/iframe.pyj b/src/pyj/read_book/iframe.pyj index cd47ecabe1..fe9446cdbd 100644 --- a/src/pyj/read_book/iframe.pyj +++ b/src/pyj/read_book/iframe.pyj @@ -29,7 +29,9 @@ from read_book.paged_mode import ( scroll_by_page as paged_scroll_by_page, scroll_to_elem, scroll_to_fraction as paged_scroll_to_fraction, snap_to_selection ) -from read_book.referencing import end_reference_mode, start_reference_mode +from read_book.referencing import ( + elem_for_ref, end_reference_mode, start_reference_mode +) from read_book.resources import finalize_resources, unserialize_html from read_book.settings import ( apply_colors, apply_font_size, apply_settings, apply_stylesheet, opts, @@ -92,6 +94,7 @@ class IframeBoss: 'initialize':self.initialize, 'display': self.display, 'scroll_to_anchor': self.on_scroll_to_anchor, + 'scroll_to_ref': self.on_scroll_to_ref, 'scroll_to_frac': self.on_scroll_to_frac, 'next_screen': self.on_next_screen, 'change_font_size': self.change_font_size, @@ -275,6 +278,8 @@ class IframeBoss: self.to_scroll_fraction(ipos.frac) elif ipos.type is 'anchor': self.scroll_to_anchor(ipos.anchor) + elif ipos.type is 'ref': + self.scroll_to_ref(ipos.refnum) elif ipos.type is 'cfi': self.jump_to_cfi(ipos.cfi) elif ipos.type is 'search': @@ -466,6 +471,17 @@ class IframeBoss: else: scroll_viewport.scroll_to(0, 0) + def scroll_to_ref(self, refnum): + refnum = int(refnum) + elem = elem_for_ref(refnum) + if elem: + scroll_to_elem(elem) + + def on_scroll_to_ref(self, data): + refnum = data.refnum + if refnum?: + self.scroll_to_ref(refnum) + def find(self, data, from_load): if data.searched_in_spine: window.getSelection().removeAllRanges() diff --git a/src/pyj/read_book/referencing.pyj b/src/pyj/read_book/referencing.pyj index ad437ada20..a4e1203003 100644 --- a/src/pyj/read_book/referencing.pyj +++ b/src/pyj/read_book/referencing.pyj @@ -6,6 +6,12 @@ from __python__ import bound_methods, hash_literals from read_book.globals import get_boss +def elem_for_ref(refnum): + refnum = int(refnum) + p = document.getElementsByTagName('p')[refnum - 1] + return p + + def on_mouse_over(ev): p = this if p.dataset.calibreRefNum: diff --git a/src/pyj/read_book/view.pyj b/src/pyj/read_book/view.pyj index 096c65bb05..60d39b9317 100644 --- a/src/pyj/read_book/view.pyj +++ b/src/pyj/read_book/view.pyj @@ -655,6 +655,8 @@ class View: elif initial_position.type is 'bookpos': navigated = True self.goto_book_position(initial_position.data) + elif initial_position.type is 'ref': + navigated = self.goto_reference(initial_position.data) if navigated: self.hide_loading() else: @@ -769,6 +771,20 @@ class View: return True return False + def goto_reference(self, reference): + if not self.book or not self.book.manifest: + return + index, refnum = reference.split('.') + index, refnum = int(index), int(refnum) + chapter_name = self.book.manifest.spine[index] + if not chapter_name: + return False + if self.currently_showing.name is chapter_name: + self.iframe_wrapper.send_message('scroll_to_ref', refnum=refnum) + else: + self.show_name(chapter_name, initial_position={'type':'ref', 'refnum':refnum, 'replace_history':True}) + return True + def goto_named_destination(self, name, frag): if self.currently_showing.name is name: self.iframe_wrapper.send_message('scroll_to_anchor', frag=frag)