From 031b14fc78c159420946d09d270deb0230cdf75e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 16 Aug 2019 08:44:26 +0530 Subject: [PATCH] Implement Go to location (with CFI) --- src/pyj/read_book/globals.pyj | 1 + src/pyj/read_book/goto.pyj | 7 ++-- src/pyj/read_book/overlay.pyj | 2 +- src/pyj/read_book/ui.pyj | 4 ++ src/pyj/read_book/view.pyj | 73 ++++++++++++++++++++++++++++++++--- src/pyj/viewer-main.pyj | 4 +- 6 files changed, 81 insertions(+), 10 deletions(-) diff --git a/src/pyj/read_book/globals.pyj b/src/pyj/read_book/globals.pyj index 882800c4a2..e7ff35efe3 100644 --- a/src/pyj/read_book/globals.pyj +++ b/src/pyj/read_book/globals.pyj @@ -78,4 +78,5 @@ ui_operations = { 'forward_gesture': None, 'update_color_scheme': None, 'update_font_size': None, + 'goto_bookpos': None, } diff --git a/src/pyj/read_book/goto.pyj b/src/pyj/read_book/goto.pyj index 433c4b87f4..533447ef3c 100644 --- a/src/pyj/read_book/goto.pyj +++ b/src/pyj/read_book/goto.pyj @@ -11,7 +11,7 @@ from read_book.toc import get_toc_maps, get_border_nodes from read_book.globals import current_book -def create_goto_list(onclick): +def create_goto_list(onclick, current_cfi): ans = E.div() items = v'[]' landmarks = current_book().manifest.landmarks @@ -25,6 +25,7 @@ def create_goto_list(onclick): items.push(create_item(_('Document start'), action=onclick.bind(None, def(view): view.goto_doc_boundary(True);))) items.push(create_item(_('Document end'), action=onclick.bind(None, def(view): view.goto_doc_boundary(False);))) items.push(create_item(_('Metadata'), subtitle=_('Details about this book'), action=onclick.bind(None, def(view): view.show_book_metadata();))) + items.push(create_item(_('Location'), subtitle=current_cfi or None, action=onclick.bind(None, def(view): view.ask_for_location();))) for l in landmarks: items.push(create_item(l.title, action=onclick.bind(None, l.dest, l.frag))) build_list(ans, items) @@ -38,8 +39,8 @@ def get_next_section(forward): return after if forward else before -def create_goto_panel(book, container, onclick): - panel = create_goto_list(onclick) +def create_goto_panel(current_cfi, book, container, onclick): + panel = create_goto_list(onclick, current_cfi) set_css(container, display='flex', flex_direction='column') set_css(panel, flex_grow='10') container.appendChild(panel) diff --git a/src/pyj/read_book/overlay.pyj b/src/pyj/read_book/overlay.pyj index c32838f9e3..c53fea18fc 100644 --- a/src/pyj/read_book/overlay.pyj +++ b/src/pyj/read_book/overlay.pyj @@ -520,7 +520,7 @@ class Overlay: def show_goto(self): self.hide_current_panel() - self.panels.push(TOCOverlay(self, create_goto_panel, _('Go to…'))) + self.panels.push(TOCOverlay(self, create_goto_panel.bind(None, self.view.currently_showing.bookpos), _('Go to…'))) self.show_current_panel() def show_search(self): diff --git a/src/pyj/read_book/ui.pyj b/src/pyj/read_book/ui.pyj index 0bf1b5f40f..e6c740373a 100644 --- a/src/pyj/read_book/ui.pyj +++ b/src/pyj/read_book/ui.pyj @@ -65,6 +65,7 @@ class ReadUI: ui_operations.forward_gesture = self.forward_gesture.bind(self) ui_operations.update_color_scheme = self.update_color_scheme.bind(self) ui_operations.update_font_size = self.update_font_size.bind(self) + ui_operations.goto_bookpos = self.goto_bookpos.bind(self) def on_resize(self): self.view.on_resize() @@ -154,6 +155,9 @@ class ReadUI: def update_font_size(self): self.view.update_font_size() + def goto_bookpos(self, bookpos): + return self.view.goto_bookpos(bookpos) + def update_color_scheme(self): self.view.update_color_scheme() diff --git a/src/pyj/read_book/view.pyj b/src/pyj/read_book/view.pyj index 3271e3ca99..e18949caaa 100644 --- a/src/pyj/read_book/view.pyj +++ b/src/pyj/read_book/view.pyj @@ -30,6 +30,7 @@ from read_book.toc import get_current_toc_nodes, update_visible_toc_nodes from read_book.touch import set_left_margin_handler, set_right_margin_handler from session import get_device_uuid, get_interface_data from utils import html_escape, is_ios, parse_url_params, username_key +from widgets import create_button add_extra_css(def(): sel = '.book-side-margin' @@ -73,14 +74,14 @@ def show_controls_help(): )) -def show_metadata_overlay(mi): +def setup_metadata_overlay(title): container = document.getElementById('book-metadata-overlay') clear(container) container.style.display = 'block' container.style.backgroundColor = get_color('window-background') container.appendChild(E.div( style='padding: 1ex 1em; border-bottom: solid 1px currentColor; display:flex; justify-content: space-between;', - E.h2(mi.title), + E.h2(title), E.div(svgicon('close'), style='cursor:pointer', class_='simple-link', onclick=def(event): event.preventDefault() event.stopPropagation() @@ -88,11 +89,58 @@ def show_metadata_overlay(mi): ) ) ) + return container + + +def show_metadata_overlay(mi): + container = setup_metadata_overlay(mi.title) container.appendChild(E.div(class_=BD_CLASS_NAME, style='padding: 1ex 1em')) table = E.table(class_='metadata') container.lastChild.appendChild(table) render_metadata(mi, table) + +def show_location_overlay(current_cfi): + container = setup_metadata_overlay(_('Go to location…')) + container_id = container.id + if current_cfi: + container.appendChild(E.div( + style='margin: 1rem; display: flex; align-items: baseline', + E.input( + type='text', readonly='readonly', value=_('Currently at: {}').format(current_cfi), name='current_location', + style='border-width: 0; background-color: transparent; outline: none; flex-grow: 10; font-family: inherit' + ), + create_button(_('Copy'), action=def(): + src = document.querySelector(f'#{container_id} [name=current_location]') + orig = src.value + src.value = current_cfi + src.focus() + src.select() + try: + document.execCommand('copy') + finally: + src.value = orig + src.blur() + ) + )) + container.appendChild(E.div( + style='margin: 1rem;', + E.div( + style='display: flex; align-items: baseline', + E.label(_('Go to:'), style='margin-right: 1rem'), + E.input(name='newloc', type='text', style='flex-grow: 10; margin-right: 1rem'), E.span(' '), + create_button(_('Go'), action=def(): + src = document.querySelector(f'#{container_id} [name=newloc]') + if src.value: + if ui_operations.goto_bookpos(src.value): + document.getElementById(container_id).style.display = 'none' + else: + error_dialog(_('No such location'), _( + 'No location {} found').format(src.value)) + ) + ) + )) + # }}} def margin_elem(sd, which, id, onclick): @@ -122,6 +170,8 @@ class View: self.loaded_resources = {} self.current_progress_frac = self.current_file_progress_frac = 0 self.current_toc_node = self.current_toc_toplevel_node = None + self.report_cfi_callbacks = {} + self.show_chrome_counter = 0 self.clock_timer_id = 0 sd = get_session_data() left_margin = E.div(svgicon('caret-left'), style='width:{}px;'.format(sd.get('margin_left', 20)), class_='book-side-margin', id='book-left-margin', onclick=self.left_margin_clicked) @@ -269,7 +319,12 @@ class View: self.content_popup_overlay.hide() def show_chrome(self): + self.show_chrome_counter += 1 + self.get_current_cfi('show-chrome-' + self.show_chrome_counter, self.do_show_chrome) + + def do_show_chrome(self, request_id, cfi_data): self.hide_overlays() + self.on_update_cfi(cfi_data) self.overlay.show() def show_search(self): @@ -451,6 +506,9 @@ class View: mi = self.book.metadata show_metadata_overlay(mi) + def ask_for_location(self): + show_location_overlay(self.currently_showing.bookpos) + def on_scroll_to_anchor(self, data): self.show_name(data.name, initial_position={'type':'anchor', 'anchor':data.frag, 'replace_history':False}) @@ -463,6 +521,8 @@ class View: name = cfiname pos.type, pos.cfi = 'cfi', internal_cfi self.show_name(name, initial_position=pos) + return True + return False def goto_named_destination(self, name, frag): if self.currently_showing.name is name: @@ -507,12 +567,15 @@ class View: if toc_node: self.goto_named_destination(toc_node.dest, toc_node.frag) - def get_current_cfi(self, request_id): + def get_current_cfi(self, request_id, callback): + self.report_cfi_callbacks[request_id] = callback self.iframe_wrapper.send_message('get_current_cfi', request_id=request_id) def on_report_cfi(self, data): - ui_operations.report_cfi( - data.request_id, {'cfi': data.cfi, 'progress_frac': data.progress_frac, 'file_progress_frac': data.file_progress_frac}) + cb = self.report_cfi_callbacks[data.request_id] + if cb: + cb(data.request_id, {'cfi': data.cfi, 'progress_frac': data.progress_frac, 'file_progress_frac': data.file_progress_frac}) + v'delete self.report_cfi_callbacks[data.request_id]' def on_update_cfi(self, data): overlay_shown = not self.processing_spine_item_display and self.overlay.is_visible diff --git a/src/pyj/viewer-main.pyj b/src/pyj/viewer-main.pyj index 17aab37162..9d6ad671dd 100644 --- a/src/pyj/viewer-main.pyj +++ b/src/pyj/viewer-main.pyj @@ -216,7 +216,7 @@ def full_screen_state_changed(viewer_in_full_screen): @from_python def get_current_cfi(request_id): - view.get_current_cfi(request_id) + view.get_current_cfi(request_id, ui_operations.report_cfi) def onerror(msg, script_url, line_number, column_number, error_object): @@ -251,6 +251,8 @@ if window is window.top: view.update_color_scheme() ui_operations.update_font_size = def(): view.update_font_size() + ui_operations.goto_bookpos = def(cfi): + return view.goto_bookpos(cfi) ui_operations.toggle_toc = def(): to_python.toggle_toc() ui_operations.toggle_bookmarks = def():