From 26d1126c62c0cb9c61cd27a18a5dff881236b8bf Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 19 Aug 2024 22:14:26 +0530 Subject: [PATCH] E-book viewer: Allow going to links from the pagelist in the book via the Goto action in the viewer controls. Typically, these are locations in the book corresponding to paper edition page boundaries. --- src/pyj/read_book/goto.pyj | 17 +++++++++++++++-- src/pyj/read_book/iframe.pyj | 17 +++++++++++++++++ src/pyj/read_book/overlay.pyj | 8 +++++++- src/pyj/read_book/view.pyj | 5 +++++ 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/pyj/read_book/goto.pyj b/src/pyj/read_book/goto.pyj index 02983a7b16..f69e70832d 100644 --- a/src/pyj/read_book/goto.pyj +++ b/src/pyj/read_book/goto.pyj @@ -16,7 +16,7 @@ from read_book.toc import get_border_nodes, get_toc_maps from widgets import create_button -def create_goto_list(onclick, current_position_data): +def create_goto_list(onclick, current_position_data, page_list): ans = E.div() items = v'[]' location_text = format_pos(current_position_data.progress_frac, current_position_data.book_length) + ' :: ' @@ -40,6 +40,8 @@ def create_goto_list(onclick, current_position_data): view.open_book_page() ))) items.push(create_item(_('Location'), subtitle=location_text, action=onclick.bind(None, def(view): view.overlay.show_ask_for_location();))) + if page_list and page_list.length > 0: + items.push(create_item(_('Page number'), subtitle=_('Typically the page number from a paper edition of this book'), action=onclick.bind(None, def(view): view.overlay.show_page_list(page_list);))) for l in landmarks: items.push(create_item(l.title, action=onclick.bind(None, l.dest, l.frag))) build_list(ans, items) @@ -54,12 +56,23 @@ def get_next_section(forward): def create_goto_panel(current_position_data, book, container, onclick): - panel = create_goto_list(onclick, current_position_data) + panel = create_goto_list(onclick, current_position_data, book.manifest.page_list) set_css(container, display='flex', flex_direction='column') set_css(panel, flex_grow='10') container.appendChild(panel) +def create_page_list_overlay(book, overlay, container): + page_list = book.manifest.page_list or v'[]' + items = v'[]' + for x in page_list: + items.push(create_item(x['pagenum'], action=def(): + overlay.view.goto_pagelist_item(x) + overlay.hide() + )) + build_list(container, items) + + def create_location_overlay(current_position_data, book, overlay, container): container_id = ensure_id(container) container.appendChild(E.div(style='margin: 0 1rem')) diff --git a/src/pyj/read_book/iframe.pyj b/src/pyj/read_book/iframe.pyj index 607a1b156f..a04156a097 100644 --- a/src/pyj/read_book/iframe.pyj +++ b/src/pyj/read_book/iframe.pyj @@ -480,6 +480,8 @@ class IframeBoss: , 5) elif ipos.type is 'smil_id': self.audio_ebook_msg_received({'type': 'play', 'anchor': ipos.anchor}) + elif ipos.type is 'pagelist_ref': + self.scroll_to_pagelist_ref(ipos.anchor) spine = self.book.manifest.spine files = self.book.manifest.files spine_index = csi.index @@ -758,6 +760,21 @@ class IframeBoss: else: scroll_viewport.scroll_to(0, 0) + def scroll_to_pagelist_ref(self, frag): + elem = document.getElementById(frag) + if not elem: + c = document.getElementsByName(frag) + if c and c.length: + elem = c[0] + if elem: + # The stupid EPUB 3 examples have page list links pointing to + # display:none divs. Sigh. + if window.getComputedStyle(elem).display is 'none': + elem.textContent = '' + elem.setAttribute('style', 'all: revert') + elem.style.display = 'block' + scroll_to_elem(elem) + def scroll_to_ref(self, refnum): refnum = int(refnum) elem = elem_for_ref(refnum) diff --git a/src/pyj/read_book/overlay.pyj b/src/pyj/read_book/overlay.pyj index d881eb1fb5..096502ff9f 100644 --- a/src/pyj/read_book/overlay.pyj +++ b/src/pyj/read_book/overlay.pyj @@ -20,7 +20,7 @@ from gettext import gettext as _ from modals import error_dialog, question_dialog from read_book.bookmarks import create_bookmarks_panel from read_book.globals import runtime, ui_operations -from read_book.goto import create_goto_panel, create_location_overlay +from read_book.goto import create_goto_panel, create_location_overlay, create_page_list_overlay from read_book.highlights import create_highlights_panel from read_book.profiles import create_profiles_panel from read_book.open_book import create_open_book @@ -854,6 +854,12 @@ class Overlay: self, create_location_overlay.bind(None, self.view.current_position_data, self.view.book), _('Go to location, position or reference…'))) self.show_current_panel() + def show_page_list(self): + self.hide_current_panel() + self.panels.push(SimpleOverlay( + self, create_page_list_overlay.bind(None, self.view.book), _('Go to page'))) + self.show_current_panel() + def show_search(self): self.hide() self.view.show_search() diff --git a/src/pyj/read_book/view.pyj b/src/pyj/read_book/view.pyj index 8ee5504674..0e8a38278d 100644 --- a/src/pyj/read_book/view.pyj +++ b/src/pyj/read_book/view.pyj @@ -1115,6 +1115,11 @@ class View: val = max(0, min(1000 * float(bpos) / self.current_position_data.book_length, 1)) return self.goto_frac(val) + def goto_pagelist_item(self, item): + name = item.dest + frag = item.frag or '' + self.show_name(name, initial_position={'type':'pagelist_ref', 'anchor':frag, 'replace_history':False}) + def on_scroll_to_anchor(self, data): self.show_name(data.name, initial_position={'type':'anchor', 'anchor':data.frag, 'replace_history':False})