diff --git a/src/pyj/read_book/iframe.pyj b/src/pyj/read_book/iframe.pyj index 0ddbd1c006..b9e8c2c34d 100644 --- a/src/pyj/read_book/iframe.pyj +++ b/src/pyj/read_book/iframe.pyj @@ -8,7 +8,7 @@ from gettext import install from read_book.globals import set_boss, set_current_spine_item, current_layout_mode, current_spine_item, set_layout_mode from read_book.resources import finalize_resources, unserialize_html from read_book.flow_mode import flow_to_scroll_fraction, flow_onwheel, flow_onkeydown, layout as flow_layout -from read_book.paged_mode import layout as paged_layout, scroll_to_fraction as paged_scroll_to_fraction, onwheel as paged_onwheel, onkeydown as paged_onkeydown +from read_book.paged_mode import layout as paged_layout, scroll_to_fraction as paged_scroll_to_fraction, onwheel as paged_onwheel, onkeydown as paged_onkeydown, scroll_to_elem from read_book.settings import apply_settings from utils import debounce @@ -76,11 +76,12 @@ class Boss: self.handle_keydown = paged_onkeydown self.to_scroll_fraction = paged_scroll_to_fraction apply_settings(data.settings) - set_current_spine_item({'name':data.name, 'is_first':index is 0, 'is_last':index is spine.length - 1, 'initial_scroll_fraction':data.initial_scroll_fraction}) + set_current_spine_item({'name':data.name, 'is_first':index is 0, 'is_last':index is spine.length - 1, 'initial_position':data.initial_position}) root_data = finalize_resources(self.book, data.name, data.resource_data) unserialize_html(root_data, self.content_loaded) def content_loaded(self): + self.connect_links() document.documentElement.style.overflow = 'hidden' window.addEventListener('scroll', debounce(self.update_cfi, 1000)) window.addEventListener('resize', debounce(self.onresize, 500)) @@ -88,8 +89,12 @@ class Boss: window.addEventListener('keydown', self.onkeydown) self.do_layout() csi = current_spine_item() - if csi.initial_scroll_fraction is not None: - self.to_scroll_fraction(csi.initial_scroll_fraction) + if csi.initial_position: + ipos = csi.initial_position + if ipos.type is 'frac': + self.to_scroll_fraction(ipos.frac) + elif ipos.type is 'anchor': + self.scroll_to_anchor(ipos.anchor) def update_cfi(self): pass # TODO: Update CFI @@ -112,6 +117,32 @@ class Boss: data = self.gcm_to_parent.encrypt(JSON.stringify(data)) window.parent.postMessage(data, '*') + def connect_links(self): + link_attr = 'data-' + self.book.manifest.link_uid + for a in document.body.querySelectorAll('a[{}]'.format(link_attr)): + a.addEventListener('click', self.link_activated) + + def link_activated(self, evt): + link_attr = 'data-' + self.book.manifest.link_uid + try: + data = JSON.parse(evt.currentTarget.getAttribute(link_attr)) + except: + return + name, frag = data.name, data.frag + if name is current_spine_item().name: + self.scroll_to_anchor(frag) + else: + self.send_message('scroll_to_anchor', name=name, frag=frag) + + def scroll_to_anchor(self, frag): + if frag: + elem = document.getElementById(frag) + if not elem: + c = document.getElementsByName(frag) + if c and c.length: + elem = c[0] + if elem: + scroll_to_elem(elem) def init(): script = document.getElementById('bootstrap') diff --git a/src/pyj/read_book/paged_mode.pyj b/src/pyj/read_book/paged_mode.pyj index 6a03d5605e..6ada2b6b48 100644 --- a/src/pyj/read_book/paged_mode.pyj +++ b/src/pyj/read_book/paged_mode.pyj @@ -361,6 +361,9 @@ def jump_to_anchor(name): elem = elems[0] if not elem: return + scroll_to_elem(elem) + +def scroll_to_elem(elem): # TODO: Re-enable this once you have added mathjax support # if window.mathjax?.math_present # # MathJax links to children of SVG tags and scrollIntoView doesn't diff --git a/src/pyj/read_book/view.pyj b/src/pyj/read_book/view.pyj index 1c94282d3c..d30ed73708 100644 --- a/src/pyj/read_book/view.pyj +++ b/src/pyj/read_book/view.pyj @@ -61,6 +61,7 @@ class View: 'error': self.on_iframe_error, 'next_spine_item': self.on_next_spine_item, 'goto_doc_boundary': self.goto_doc_boundary, + 'scroll_to_anchor': self.on_scroll_to_anchor, } self.currently_showing = {'spine':0, 'cfi':None} @@ -150,7 +151,7 @@ class View: # TODO: Check for last open position of book self.show_name(book.manifest.spine[1]) - def show_name(self, name, initial_scroll_fraction=None, cfi=None): + def show_name(self, name, initial_position=None, cfi=None): if self.currently_showing.loading: return sd = get_session_data() @@ -160,13 +161,16 @@ class View: 'read_mode': sd.get('read_mode'), 'cols_per_screen': sd.get('cols_per_screen'), } - self.currently_showing = {'name':name, 'cfi':cfi, 'settings':settings, 'initial_scroll_fraction':initial_scroll_fraction, 'loading':True} + self.currently_showing = {'name':name, 'cfi':cfi, 'settings':settings, 'initial_position':initial_position, 'loading':True} self.set_margins(name is self.book.manifest.title_page_name) load_resources(self.ui.db, self.book, name, self.loaded_resources, self.show_spine_item) def goto_doc_boundary(self, data): name = self.book.manifest.spine[0 if data.start else self.book.manifest.spine.length - 1] - self.show_name(name, initial_scroll_fraction=0 if data.start else 1) + self.show_name(name, initial_position={'type':'frac', 'frac':0 if data.start else 1}) + + def on_scroll_to_anchor(self, data): + self.show_name(data.name, initial_position={'type':'anchor', 'anchor':data.frag}) def on_next_spine_item(self, data): spine = self.book.manifest.spine @@ -175,7 +179,7 @@ class View: if idx is 0: return idx = min(spine.length - 1, max(idx - 1, 0)) - self.show_name(spine[idx], initial_scroll_fraction=1) + self.show_name(spine[idx], initial_position={'type':'frac', 'frac':1}) else: if idx is spine.length - 1: return @@ -193,7 +197,7 @@ class View: self.currently_showing.loading = False self.send_message('display', resource_data=resource_data, book=self.book, name=self.currently_showing.name, - initial_scroll_fraction=self.currently_showing.initial_scroll_fraction, + initial_position=self.currently_showing.initial_position, settings=self.currently_showing.settings, ) self.encrypted_communications = True