Remove overlapping highlights when applying a new one

This commit is contained in:
Kovid Goyal 2020-04-11 09:40:28 +05:30
parent 5af73fee86
commit 37a60e366a
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 57 additions and 3 deletions

View File

@ -60,6 +60,11 @@ def unwrap(node):
p.normalize()
def unwrap_crw(crw):
for node in document.querySelectorAll(f'span[data-calibre-range-wrapper="{crw}"]'):
unwrap(node)
def create_wrapper_function(wrapper_elem, r):
start_node = r.startContainer
end_node = r.endContainer
@ -109,3 +114,33 @@ def wrap_text_in_range(style, r):
def reset_highlight_counter():
nonlocal wrapper_counter
wrapper_counter = 0
def is_text_node(node):
return node.nodeType is Node.TEXT_NODE or node.nodeType is Node.CDATA_SECTION_NODE
def range_wrappers_intersecting_selection(sel):
ans = {}
sel = sel or window.getSelection()
if not sel:
return ans
r = sel.getRangeAt(0)
if not r:
return ans
walker = document.createTreeWalker(r.commonAncestorContainer, NodeFilter.SHOW_ALL, None, False)
in_selection = False
while True:
node = walker.nextNode()
if not node:
break
if not in_selection and node is not r.startContainer:
continue
in_selection = True
if node.nodeType is Node.ELEMENT_NODE and node.dataset.calibreRangeWrapper:
ans[node.dataset.calibreRangeWrapper] = True
elif is_text_node(node) and node.parentNode.dataset.calibreRangeWrapper:
ans[node.parentNode.dataset.calibreRangeWrapper] = True
if node is r.endContainer:
break
return Object.keys(ans)

View File

@ -11,7 +11,10 @@ from select import (
from fs_images import fix_fullscreen_svg_images
from iframe_comm import IframeClient
from range_utils import reset_highlight_counter, wrap_text_in_range
from range_utils import (
range_wrappers_intersecting_selection, reset_highlight_counter, unwrap_crw,
wrap_text_in_range
)
from read_book.cfi import cfi_for_selection, scroll_to as scroll_to_cfi
from read_book.extract import get_elements
from read_book.find import reset_find_caches, select_search_result
@ -646,12 +649,28 @@ class IframeBoss:
elif data.type is 'set-highlight-style':
set_selection_style(data.style)
elif data.type is 'apply-highlight':
sel = window.getSelection()
text = ''
if sel:
text = sel.toString()
bounds = cfi_for_selection()
intersecting_wrappers = range_wrappers_intersecting_selection()
annot_id = wrap_text_in_range(data.style)
removed_highlights = {}
if annot_id is not None:
window.getSelection().removeAllRanges()
sel.removeAllRanges()
self.annot_id_uuid_map[annot_id] = data.uuid
self.send_message('annotations', type='highlight-applied', uuid=data.uuid, ok=annot_id is not None, bounds=bounds)
for crw in intersecting_wrappers:
unwrap_crw(crw)
removed_highlights[self.annot_id_uuid_map[crw]] = True
self.send_message(
'annotations',
type='highlight-applied',
uuid=data.uuid, ok=annot_id is not None,
bounds=bounds,
removed_highlights=Object.keys(removed_highlights),
highlighted_text=text,
)
reset_find_caches()
else:
console.log('Ignoring annotations message to iframe with unknown type: ' + data.type)