Fix selection extents not being reported correctly when selection ends at an element node

This commit is contained in:
Kovid Goyal 2020-07-23 20:04:35 +05:30
parent f037fe8dbe
commit a3bc2c9d56
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 23 additions and 14 deletions

View File

@ -82,12 +82,12 @@ class SelectionBar:
} }
def map_boundary(x): def map_boundary(x):
return {'x': x.x + margins.left, 'y': x.y + margins.top, 'height': x.height, 'onscreen': x.onscreen} return {'x': (x.x or 0) + margins.left, 'y': (x.y or 0) + margins.top, 'height': x.height or 0, 'onscreen': x.onscreen}
if not cs.selection_start.onscreen and not cs.selection_end.onscreen:
return self.hide()
start = map_boundary(cs.selection_start) start = map_boundary(cs.selection_start)
end = map_boundary(cs.selection_end) end = map_boundary(cs.selection_end)
if not start.onscreen and not end.onscreen:
return self.hide()
self.show() self.show()
end_after_start = start.y < end.y or (start.y is end.y and start.x < end.x) end_after_start = start.y < end.y or (start.y is end.y and start.x < end.x)

View File

@ -44,11 +44,15 @@ def word_at_point(x, y):
return r return r
def range_extents(start, end, in_flow_mode): def empty_range_extents():
ans = { return {
'start': {'x': None, 'y': None, 'height': None, 'onscreen': False}, 'start': {'x': 0, 'y': 0, 'height': 0, 'onscreen': False},
'end': {'x': None, 'y': None, 'height': None, 'onscreen': False} 'end': {'x': 0, 'y': 0, 'height': 0, 'onscreen': False}
} }
def range_extents(start, end, in_flow_mode):
ans = empty_range_extents()
if not start or not end: if not start or not end:
return ans return ans
start = start.cloneRange() start = start.cloneRange()
@ -57,13 +61,18 @@ def range_extents(start, end, in_flow_mode):
end.collapse(False) end.collapse(False)
def for_boundary(r, ans): def for_boundary(r, ans):
rects = r.getClientRects() rect = r.getBoundingClientRect()
if not rects.length: if rect.height is 0:
return if r.startContainer?.nodeType is Node.ELEMENT_NODE:
rect = rects[0] node = r.startContainer
if r.startOffset and node.childNodes.length > r.startOffset:
node = node.childNodes[r.startOffset]
if node.getBoundingClientRect:
erect = node.getBoundingClientRect()
rect = {'left': erect.left, 'top': erect.top, 'height': 2}
ans.x = Math.round(rect.left) ans.x = Math.round(rect.left)
ans.y = Math.round(rect.top) ans.y = Math.round(rect.top)
ans.height = rect.bottom - rect.top ans.height = rect.height
if rect.right <= window.innerWidth and rect.bottom <= window.innerHeight and rect.left >= 0 and rect.top >= 0: if rect.right <= window.innerWidth and rect.bottom <= window.innerHeight and rect.left >= 0 and rect.top >= 0:
ans.onscreen = True ans.onscreen = True
@ -76,7 +85,7 @@ def range_extents(start, end, in_flow_mode):
def selection_extents(in_flow_mode, end_must_be_focus): def selection_extents(in_flow_mode, end_must_be_focus):
sel = window.getSelection() sel = window.getSelection()
if not sel or not sel.rangeCount or sel.isCollapsed: if not sel or not sel.rangeCount or sel.isCollapsed:
return range_extents() return empty_range_extents()
if end_must_be_focus: if end_must_be_focus:
start = document.createRange() start = document.createRange()
start.setStart(sel.anchorNode, sel.anchorOffset) start.setStart(sel.anchorNode, sel.anchorOffset)
@ -97,7 +106,7 @@ def selection_extents_at_point(x, y, in_flow_mode):
sel.removeAllRanges() sel.removeAllRanges()
sel.addRange(r) sel.addRange(r)
return selection_extents(r, r) return selection_extents(r, r)
ans = range_extents() ans = empty_range_extents()
ans.start.y = ans.end.y = y ans.start.y = ans.end.y = y
ans.start.height = ans.end.height = parseInt(window.getComputedStyle(document.body).fontSize) + 4 ans.start.height = ans.end.height = parseInt(window.getComputedStyle(document.body).fontSize) + 4
ans.start.x = x ans.start.x = x