From 33fed392695b6cd9432cebb8f5b287f555bc53f3 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 8 Apr 2020 20:16:52 +0530 Subject: [PATCH] Make extending the selection on scroll more robust --- src/pyj/read_book/create_annotation.pyj | 9 ++++ src/pyj/read_book/iframe.pyj | 18 +++++--- src/pyj/read_book/paged_mode.pyj | 4 ++ src/pyj/select.pyj | 60 ++++++++++++++++--------- 4 files changed, 62 insertions(+), 29 deletions(-) diff --git a/src/pyj/read_book/create_annotation.pyj b/src/pyj/read_book/create_annotation.pyj index efef517229..84a0fb37fb 100644 --- a/src/pyj/read_book/create_annotation.pyj +++ b/src/pyj/read_book/create_annotation.pyj @@ -378,6 +378,15 @@ class CreateAnnotation: self.place_handles(msg.extents) elif msg.type is 'update-handles': self.place_handles(msg.extents) + if msg.from_scroll and not msg.selection_extended: + middle = map_from_iframe_coords({ + 'x': msg.page_rect.left + msg.page_rect.width // 2, + 'y': msg.page_rect.top + msg.page_rect.height // 2 + }) + handle = self.left_handle if msg.backwards else self.right_handle + handle.style.display = 'block' + handle.style.left = f'{middle.x}px' + handle.style.top = f'{middle.y}px' elif msg.type is 'highlight-applied': if not msg.ok: return error_dialog( diff --git a/src/pyj/read_book/iframe.pyj b/src/pyj/read_book/iframe.pyj index e2ac24a262..9ef91b543d 100644 --- a/src/pyj/read_book/iframe.pyj +++ b/src/pyj/read_book/iframe.pyj @@ -31,11 +31,11 @@ from read_book.mathjax import apply_mathjax from read_book.paged_mode import ( anchor_funcs as paged_anchor_funcs, auto_scroll_action as paged_auto_scroll_action, calc_columns_per_screen, - current_cfi, get_columns_per_screen_data, handle_gesture as paged_handle_gesture, - handle_shortcut as paged_handle_shortcut, jump_to_cfi as paged_jump_to_cfi, - layout as paged_layout, onwheel as paged_onwheel, - prepare_for_resize as paged_prepare_for_resize, progress_frac, - reset_paged_mode_globals, resize_done as paged_resize_done, + current_cfi, current_page_width, get_columns_per_screen_data, + handle_gesture as paged_handle_gesture, handle_shortcut as paged_handle_shortcut, + jump_to_cfi as paged_jump_to_cfi, layout as paged_layout, + onwheel as paged_onwheel, prepare_for_resize as paged_prepare_for_resize, + progress_frac, reset_paged_mode_globals, resize_done as paged_resize_done, scroll_by_page as paged_scroll_by_page, scroll_to_elem, scroll_to_extend_annotation as paged_annotation_scroll, scroll_to_fraction as paged_scroll_to_fraction, snap_to_selection, @@ -634,8 +634,12 @@ class IframeBoss: extents=selection_extents_at_point(data.x, data.y, in_flow_mode)) elif data.type is 'scroll': if self.scroll_to_extend_annotation(data.backwards): - extend_selection_after_scroll(data.backwards, in_flow_mode) - self.send_message('annotations', type='update-handles', extents=selection_extents(in_flow_mode)) + page_rect = {'width': current_page_width()} + extended = extend_selection_after_scroll(data.backwards, in_flow_mode, page_rect) + self.send_message( + 'annotations', type='update-handles', extents=selection_extents(in_flow_mode), + backwards=data.backwards, from_scroll=True, selection_extended=extended, page_rect=page_rect + ) elif data.type is 'perp-scroll': if in_flow_mode and flow_annotation_scroll(data.backwards, True): self.send_message('annotations', type='update-handles', extents=selection_extents(in_flow_mode)) diff --git a/src/pyj/read_book/paged_mode.pyj b/src/pyj/read_book/paged_mode.pyj index f120a49aac..b2a5d968f0 100644 --- a/src/pyj/read_book/paged_mode.pyj +++ b/src/pyj/read_book/paged_mode.pyj @@ -164,6 +164,10 @@ def will_columns_per_screen_change(): return calc_columns_per_screen() != cols_per_screen +def current_page_width(): + return col_width + + def layout(is_single_page, on_resize): nonlocal _in_paged_mode, col_width, col_and_gap, screen_height, gap, screen_width, is_full_screen_layout, cols_per_screen, number_of_cols body_style = window.getComputedStyle(document.body) diff --git a/src/pyj/select.pyj b/src/pyj/select.pyj index 987a022007..bcea829677 100644 --- a/src/pyj/select.pyj +++ b/src/pyj/select.pyj @@ -98,37 +98,53 @@ def selection_extents_at_point(x, y, in_flow_mode): return ans -def extend_selection_after_scroll(backwards, in_flow_mode): +def extend_selection_after_scroll(backwards, in_flow_mode, page_rect): + page_rect.top = page_rect.left = 0 + page_rect.bottom = window.innerHeight + page_rect.right = page_rect.width + if not in_flow_mode and not backwards: + page_rect.right = window.innerWidth + page_rect.left = window.innerWidth - page_rect.width + page_rect.width = page_rect.right - page_rect.left + page_rect.height = page_rect.bottom - page_rect.top + sel = window.getSelection() if not sel.rangeCount: - return + return False + if in_flow_mode: + page_rect.width = window.innerWidth r = sel.getRangeAt(0) q = r.cloneRange() q.collapse(backwards) - rects = r.getClientRects() + rects = q.getClientRects() if not rects.length: - return + return False rect = rects[0] - if backwards: - if in_flow_mode and rect.bottom <= window.innerHeight: - return - if not in_flow_mode and rect.right <= window.innerWidth: - return - else: - if in_flow_mode and rect.top >= 0: - return - if not in_flow_mode and rect.left >= 0: - return - x = window.innerWidth // 2 - y = window.innerHeight // 3 - if backwards: - y *= 2 - p = range_from_point(x, y) - if p: + + in_page_already = rect.left >= page_rect.left and rect.top >= page_rect.top and rect.bottom <= page_rect.bottom and rect.right <= page_rect.right + if in_page_already: + return True + dx = page_rect.width // 10 + dy = page_rect.height // 10 + middle_x = page_rect.left + page_rect.width // 2 + for yi in range(1, 10): if backwards: - r.setStart(p.startContainer, p.startOffset) + y = page_rect.bottom - dy * yi else: - r.setEnd(p.startContainer, p.startOffset) + y = page_rect.top + dy * yi + for xi in range(4): + xvals = v'[-1, 1]' if xi else v'[1]' + for xw in xvals: + x = middle_x + xw * dx + p = range_from_point(x, y) + if p: + if backwards: + r.setStart(p.startContainer, p.startOffset) + else: + r.setEnd(p.startContainer, p.startOffset) + return True + # could not find any content on page + return False def set_selections_extents_to(extents):