diff --git a/src/pyj/range_utils.pyj b/src/pyj/range_utils.pyj index 7a5200e575..b408f796d9 100644 --- a/src/pyj/range_utils.pyj +++ b/src/pyj/range_utils.pyj @@ -8,7 +8,25 @@ def is_non_empty_text_node(node): return (node.nodeType is Node.TEXT_NODE or node.nodeType is Node.CDATA_SECTION_NODE) and node.nodeValue.length > 0 -def text_nodes_in_range(r): +def is_element_visible(elem): + s = window.getComputedStyle(elem) + return s.display is not 'none' and s.visibility is not 'hidden' + + +def is_node_visible(node): + if node.nodeType is not Node.ELEMENT_NODE: + node = node.parentElement + if not node: + return False + current = node + while current: + if not is_element_visible(current): + return False + current = current.parentElement + return True + + +def select_nodes_from_range(r, predicate): parent = r.commonAncestorContainer doc = parent.ownerDocument or document iterator = doc.createNodeIterator(parent) @@ -21,13 +39,35 @@ def text_nodes_in_range(r): if not in_range and node.isSameNode(r.startContainer): in_range = True if in_range: - if is_non_empty_text_node(node): + if predicate(node): ans.push(node) if node.isSameNode(r.endContainer): break return ans +def select_first_node_from_range(r, predicate): + parent = r.commonAncestorContainer + doc = parent.ownerDocument or document + iterator = doc.createNodeIterator(parent) + in_range = False + while True: + node = iterator.nextNode() + if not node: + break + if not in_range and node.isSameNode(r.startContainer): + in_range = True + if in_range: + if predicate(node): + return node + if node.isSameNode(r.endContainer): + break + + +def text_nodes_in_range(r): + return select_nodes_from_range(r, is_non_empty_text_node) + + def all_annots_in_range(r, annot_id_uuid_map, ans): parent = r.commonAncestorContainer doc = parent.ownerDocument or document diff --git a/src/pyj/read_book/find.pyj b/src/pyj/read_book/find.pyj index 688100632d..f6e34528c7 100644 --- a/src/pyj/read_book/find.pyj +++ b/src/pyj/read_book/find.pyj @@ -2,6 +2,7 @@ # License: GPL v3 Copyright: 2020, Kovid Goyal from __python__ import bound_methods, hash_literals +from range_utils import select_first_node_from_range, is_node_visible def build_text_map(): node_list = v'[]' @@ -27,9 +28,6 @@ def build_text_map(): tag = node.tagName.toLowerCase() if ignored_tags[tag]: return - style = window.getComputedStyle(node) - if style.display is 'none' or style.visibility is 'hidden': - return children = node.childNodes for i in range(children.length): process_node(v'children[i]') @@ -143,7 +141,12 @@ def select_find_result(match): sel.setBaseAndExtent(match.start_node, match.start_offset, match.end_node, match.end_offset) except: # if offset is outside node return False - return True + if not sel.rangeCount: + return False + for i in range(sel.rangeCount): + if select_first_node_from_range(sel.getRangeAt(i), is_node_visible): + return True + return False def select_search_result(sr):