E-book viewer: Fix creating multiple highlights in a single paragraph that also contains some extra text formatting at the start causing the second and subsequent highlights to malfunction. Fixes #1940005 [Arbitrarliy lost/moved/expanded highlights on refresh.](https://bugs.launchpad.net/calibre/+bug/1940005)

This commit is contained in:
Kovid Goyal 2021-08-17 20:49:01 +05:30
parent 3843f661de
commit 94920612a6
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 29 additions and 4 deletions

View File

@ -183,9 +183,11 @@ def increment_index_for_children(children, index, sentinel):
def non_range_wrapper_parent(node):
p = node.parentNode
child = node
while p.dataset?.calibreRangeWrapper:
child = p
p = p.parentNode
return p
return p, child
def encode(doc, node, offset, tail):
@ -218,7 +220,7 @@ def encode(doc, node, offset, tail):
# Construct the path to node from root
is_first = True
while node is not doc:
p = non_range_wrapper_parent(node)
p, sentinel = non_range_wrapper_parent(node)
if not p:
if node.nodeType == Node.DOCUMENT_NODE: # Document node (iframe)
win = node.defaultView
@ -229,7 +231,7 @@ def encode(doc, node, offset, tail):
break
# Find position of node in parent
index = increment_index_for_children(p.childNodes, 0, node)
index = increment_index_for_children(p.childNodes, 0, sentinel)
if is_first:
is_first = False
if node.nodeType is Node.ELEMENT_NODE and node.dataset.calibreRangeWrapper:

View File

@ -4,7 +4,7 @@ from __python__ import bound_methods, hash_literals
from elementmaker import E
from read_book.cfi import encode, decode, escape_for_cfi, unescape_from_cfi
from read_book.cfi import encode, decode, escape_for_cfi, unescape_from_cfi, cfi_for_selection
from testing import assert_equal, test
@ -106,3 +106,26 @@ def cfi_with_range_wrappers():
assert_equal(decode(f'{path_to_p}/1:5'), {'node': p.firstChild.nextSibling, 'offset': 2})
assert_equal(decode(f'{path_to_p}/1:7'), {'node': rw.firstChild, 'offset': 1})
assert_equal(decode(f'{path_to_p}/1:11'), {'node': rw.nextSibling, 'offset': 2})
document.body.appendChild(E.p(
E.span('Labor is', data_calibre_range_wrapper='10'),
E.em(E.span('not the source', data_calibre_range_wrapper='10')),
E.span(' of all wealth.', data_calibre_range_wrapper='10'),
' ',
E.em('Nature'),
' is just as much. The above',
))
p = document.body.lastChild
path_to_p = encode(document, p)
r = document.createRange()
em = p.querySelectorAll('em')[-1]
r.setStart(em.firstChild, 0)
r.setEnd(p.lastChild, 3)
assert_equal(r.toString(), 'Nature is')
bounds = cfi_for_selection(r)
s = decode(bounds.start)
r.setStart(s.node, s.offset)
e = decode(bounds.end)
r.setEnd(e.node, e.offset)
assert_equal(r.toString(), 'Nature is')
assert_equal(decode(bounds.end), {'node': p.lastChild, 'offset': 3})