diff --git a/src/pyj/read_book/cfi.pyj b/src/pyj/read_book/cfi.pyj index f964ac8523..5a1b1ed054 100644 --- a/src/pyj/read_book/cfi.pyj +++ b/src/pyj/read_book/cfi.pyj @@ -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: diff --git a/src/pyj/read_book/test_cfi.pyj b/src/pyj/read_book/test_cfi.pyj index 5422946131..3629f18201 100644 --- a/src/pyj/read_book/test_cfi.pyj +++ b/src/pyj/read_book/test_cfi.pyj @@ -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})