Handle visibility of elements on screen correctly
This commit is contained in:
parent
f2f413e2d0
commit
50f31ca7cb
@ -244,7 +244,10 @@ class HintManager(QObject):
|
|||||||
else:
|
else:
|
||||||
target = self._target
|
target = self._target
|
||||||
self.set_open_target.emit(Target[target])
|
self.set_open_target.emit(Target[target])
|
||||||
pos = webelem.pos_on_screen(elem)
|
# FIXME Instead of clicking the center, we could have nicer heuristics.
|
||||||
|
# e.g. parse (-webkit-)border-radius correctly and click text fields at
|
||||||
|
# the bottom right, and everything else on the top left or so.
|
||||||
|
pos = webelem.rect_on_screen(elem).center()
|
||||||
logging.debug("Clicking on \"{}\" at {}/{}".format(
|
logging.debug("Clicking on \"{}\" at {}/{}".format(
|
||||||
elem.toPlainText(), pos.x(), pos.y()))
|
elem.toPlainText(), pos.x(), pos.y()))
|
||||||
events = [
|
events = [
|
||||||
@ -346,12 +349,12 @@ class HintManager(QObject):
|
|||||||
return
|
return
|
||||||
self.openurl.emit(link, newtab)
|
self.openurl.emit(link, newtab)
|
||||||
|
|
||||||
def start(self, frame, baseurl, group=webelem.Group.all,
|
def start(self, mainframe, baseurl, group=webelem.Group.all,
|
||||||
target=Target.normal):
|
target=Target.normal):
|
||||||
"""Start hinting.
|
"""Start hinting.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
frame: The QWebFrame to place hints in.
|
mainframe: The main QWebFrame.
|
||||||
baseurl: URL of the current page.
|
baseurl: URL of the current page.
|
||||||
group: Which group of elements to hint.
|
group: Which group of elements to hint.
|
||||||
target: What to do with the link. See attribute docstring.
|
target: What to do with the link. See attribute docstring.
|
||||||
@ -361,19 +364,19 @@ class HintManager(QObject):
|
|||||||
"""
|
"""
|
||||||
self._target = target
|
self._target = target
|
||||||
self._baseurl = baseurl
|
self._baseurl = baseurl
|
||||||
if frame is None:
|
if mainframe is None:
|
||||||
# This should never happen since we check frame before calling
|
# This should never happen since we check frame before calling
|
||||||
# start. But since we had a bug where frame is None in
|
# start. But since we had a bug where frame is None in
|
||||||
# on_mode_left, we are extra careful here.
|
# on_mode_left, we are extra careful here.
|
||||||
raise ValueError("start() was called with frame=None")
|
raise ValueError("start() was called with frame=None")
|
||||||
self._frames = webelem.get_child_frames(frame)
|
self._frames = webelem.get_child_frames(mainframe)
|
||||||
elems = []
|
elems = []
|
||||||
for f in self._frames:
|
for f in self._frames:
|
||||||
elems += f.findAllElements(webelem.SELECTORS[group])
|
elems += f.findAllElements(webelem.SELECTORS[group])
|
||||||
filterfunc = webelem.FILTERS.get(group, lambda e: True)
|
filterfunc = webelem.FILTERS.get(group, lambda e: True)
|
||||||
visible_elems = []
|
visible_elems = []
|
||||||
for e in elems:
|
for e in elems:
|
||||||
if filterfunc(e) and webelem.is_visible(e):
|
if filterfunc(e) and webelem.is_visible(e, mainframe):
|
||||||
visible_elems.append(e)
|
visible_elems.append(e)
|
||||||
if not visible_elems:
|
if not visible_elems:
|
||||||
message.error("No elements found.")
|
message.error("No elements found.")
|
||||||
|
@ -58,56 +58,47 @@ FILTERS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def is_visible(elem):
|
def is_visible(elem, mainframe):
|
||||||
"""Check whether the element is currently visible in its frame.
|
"""Check whether the element is currently visible on the screen.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
elem: The QWebElement to check.
|
elem: The QWebElement to check.
|
||||||
|
mainframe: The main QWebFrame.
|
||||||
|
|
||||||
Return:
|
Return:
|
||||||
True if the element is visible, False otherwise.
|
True if the element is visible, False otherwise.
|
||||||
"""
|
"""
|
||||||
if elem.isNull():
|
if elem.isNull():
|
||||||
raise ValueError("Element is a null-element!")
|
raise ValueError("Element is a null-element!")
|
||||||
## We're starting in the innermost (element) frame and check if every frame
|
if (not elem.geometry().isValid()) and elem.geometry().x() == 0:
|
||||||
## is visible in its parent.
|
|
||||||
base = elem.webFrame()
|
|
||||||
parent = base.parentFrame()
|
|
||||||
while parent is not None:
|
|
||||||
parentgeom = parent.geometry()
|
|
||||||
parentgeom.translate(parent.scrollPosition())
|
|
||||||
if not parentgeom.intersects(base.geometry()):
|
|
||||||
return False
|
|
||||||
base = parent
|
|
||||||
parent = parent.parentFrame()
|
|
||||||
rect = elem.geometry()
|
|
||||||
## Now check if the element is visible in the frame.
|
|
||||||
if (not rect.isValid()) and rect.x() == 0:
|
|
||||||
# Most likely an invisible link
|
# Most likely an invisible link
|
||||||
return False
|
return False
|
||||||
frame = elem.webFrame()
|
# First check if the element is visible on screen
|
||||||
framegeom = frame.geometry()
|
elem_rect = rect_on_screen(elem)
|
||||||
framegeom.moveTo(0, 0)
|
visible_on_screen = mainframe.geometry().intersects(elem_rect)
|
||||||
framegeom.translate(frame.scrollPosition())
|
# Then check if it's visible in its frame if it's not in the main frame.
|
||||||
if framegeom.intersects(rect):
|
elem_frame = elem.webFrame()
|
||||||
return True
|
if elem_frame.parentFrame() is not None:
|
||||||
return False
|
framegeom = elem_frame.geometry()
|
||||||
|
framegeom.moveTo(0, 0)
|
||||||
|
framegeom.translate(elem_frame.scrollPosition())
|
||||||
|
visible_in_frame = framegeom.intersects(elem.geometry())
|
||||||
|
else:
|
||||||
|
visible_in_frame = visible_on_screen
|
||||||
|
return all([visible_on_screen, visible_in_frame])
|
||||||
|
|
||||||
|
|
||||||
def pos_on_screen(elem):
|
def rect_on_screen(elem):
|
||||||
"""Get the position of the element on the screen."""
|
"""Get the geometry of the element relative to the screen."""
|
||||||
# FIXME Instead of clicking the center, we could have nicer heuristics.
|
|
||||||
# e.g. parse (-webkit-)border-radius correctly and click text fields at
|
|
||||||
# the bottom right, and everything else on the top left or so.
|
|
||||||
frame = elem.webFrame()
|
frame = elem.webFrame()
|
||||||
pos = elem.geometry().center()
|
rect = elem.geometry()
|
||||||
while frame is not None:
|
while frame is not None:
|
||||||
pos += frame.geometry().topLeft()
|
rect.translate(frame.geometry().topLeft())
|
||||||
logging.debug("After adding frame pos: {}".format(pos))
|
logging.debug("After adding frame pos: {}".format(rect))
|
||||||
pos -= frame.scrollPosition()
|
rect.translate(frame.scrollPosition() * -1)
|
||||||
logging.debug("After removing frame scrollpos: {}".format(pos))
|
logging.debug("After removing frame scrollpos: {}".format(rect))
|
||||||
frame = frame.parentFrame()
|
frame = frame.parentFrame()
|
||||||
return pos
|
return rect
|
||||||
|
|
||||||
|
|
||||||
def javascript_escape(text):
|
def javascript_escape(text):
|
||||||
|
Loading…
Reference in New Issue
Block a user