Fix and clean up insertmode checks
This commit is contained in:
parent
fdb4b24148
commit
cf17af147e
@ -30,6 +30,7 @@ Module attributes:
|
||||
from PyQt5.QtCore import QRect, QUrl
|
||||
from PyQt5.QtWebKit import QWebElement
|
||||
|
||||
import qutebrowser.utils.log as log
|
||||
from qutebrowser.utils.usertypes import enum
|
||||
|
||||
|
||||
@ -43,17 +44,21 @@ SELECTORS = {
|
||||
'[role=option], [role=button], img'),
|
||||
Group.links: 'a',
|
||||
Group.images: 'img',
|
||||
Group.editable: ('input[type=text], input[type=email], input[type=url], '
|
||||
'input[type=tel], input[type=number], '
|
||||
'input[type=password], input[type=search], textarea'),
|
||||
# This doesn't contain all the groups where we should switch to insert mode
|
||||
# - it is just used when opening the external editor.
|
||||
Group.editable_focused: ('input[type=text]:focus, '
|
||||
'input[type=email]:focus, '
|
||||
'input[type=url]:focus, '
|
||||
'input[type=tel]:focus, '
|
||||
'input[type=number]:focus, '
|
||||
'input[type=password]:focus, '
|
||||
'input[type=search]:focus, '
|
||||
'textarea:focus'),
|
||||
Group.url: '[src], [href]',
|
||||
Group.prevnext_rel: 'link, [role=link]',
|
||||
Group.prevnext: 'a, button, [role=button]',
|
||||
}
|
||||
|
||||
SELECTORS[Group.editable_focused] = ', '.join(
|
||||
[sel.strip() + ':focus' for sel in SELECTORS[Group.editable].split(',')])
|
||||
|
||||
FILTERS = {
|
||||
Group.links: (lambda e: e.hasAttribute('href') and
|
||||
QUrl(e.attribute('href')).scheme() != 'javascript'),
|
||||
@ -171,3 +176,53 @@ def get_child_frames(startframe):
|
||||
new_frames += frame.childFrames()
|
||||
frames = new_frames
|
||||
return results
|
||||
|
||||
|
||||
def is_editable(elem):
|
||||
"""Check whether we should switch to insert mode for this element.
|
||||
|
||||
FIXME: add tests
|
||||
|
||||
Args:
|
||||
elem: The QWebElement to check.
|
||||
|
||||
Return:
|
||||
True if we should switch to insert mode, False otherwise.
|
||||
"""
|
||||
# Beginnings of div-classes which are actually some kind of editor.
|
||||
div_classes = ['CodeMirror', # Javascript editor over a textarea
|
||||
'kix-'] # Google Docs editor
|
||||
tag = elem.tagName().lower()
|
||||
if tag == 'input':
|
||||
objtype = elem.attribute('type')
|
||||
if objtype in ['text', 'email', 'url', 'tel', 'number', 'password',
|
||||
'search', '']:
|
||||
return is_writable(elem)
|
||||
elif tag == 'textarea':
|
||||
return is_writable(elem)
|
||||
elif tag in ('embed', 'applet', 'select'):
|
||||
# Flash/Java/...
|
||||
return config.get('input', 'insert-mode-on-plugins')
|
||||
elif tag == 'object':
|
||||
# Could be Flash/Java/..., could be image/audio/...
|
||||
if not elem.hasAttribute('type'):
|
||||
log.webview.debug("<object> without type clicked...")
|
||||
return False
|
||||
objtype = elem.attribute('type')
|
||||
if (objtype.startswith('application/') or
|
||||
elem.hasAttribute('classid')):
|
||||
# Let's hope flash/java stuff has an application/* mimetype OR
|
||||
# at least a classid attribute. Oh, and let's hope images/...
|
||||
# DON'T have a classid attribute. HTML sucks.
|
||||
log.webview.debug("<object type='{}'> clicked.".format(objtype))
|
||||
return config.get('input', 'insert-mode-on-plugins')
|
||||
elif tag == 'div':
|
||||
log.webview.debug("div with classes {} clicked!".format(
|
||||
elem.classes()))
|
||||
for klass in elem.classes():
|
||||
if any([klass.startswith(e) for e in div_classes]):
|
||||
return True
|
||||
elif tag == 'span':
|
||||
log.webview.debug("span with classes {} clicked!".format(
|
||||
elem.classes()))
|
||||
return False
|
||||
|
@ -179,47 +179,6 @@ class WebView(QWebView):
|
||||
log.destroy.debug("Everything destroyed, calling callback")
|
||||
self._shutdown_callback()
|
||||
|
||||
def _is_editable(self, hitresult):
|
||||
"""Check if a hit result needs keyboard focus.
|
||||
|
||||
Args:
|
||||
hitresult: A QWebHitTestResult
|
||||
"""
|
||||
# Beginnings of div-classes which are actually some kind of editor.
|
||||
div_classes = ['CodeMirror', # Javascript editor over a textarea
|
||||
'kix-'] # Google Docs editor
|
||||
elem = hitresult.element()
|
||||
tag = elem.tagName().lower()
|
||||
if hitresult.isContentEditable() and webelem.is_writable(elem):
|
||||
# text fields and the like
|
||||
return True
|
||||
elif tag in ('embed', 'applet', 'select'):
|
||||
# Flash/Java/...
|
||||
return config.get('input', 'insert-mode-on-plugins')
|
||||
elif tag == 'object':
|
||||
# Could be Flash/Java/..., could be image/audio/...
|
||||
if not elem.hasAttribute('type'):
|
||||
log.mouse.debug("<object> without type clicked...")
|
||||
return False
|
||||
objtype = elem.attribute('type')
|
||||
if (objtype.startswith('application/') or
|
||||
elem.hasAttribute('classid')):
|
||||
# Let's hope flash/java stuff has an application/* mimetype OR
|
||||
# at least a classid attribute. Oh, and let's hope images/...
|
||||
# DON'T have a classid attribute. HTML sucks.
|
||||
log.mouse.debug("<object type='{}'> clicked.".format(objtype))
|
||||
return config.get('input', 'insert-mode-on-plugins')
|
||||
elif tag == 'div':
|
||||
log.webview.debug("div with classes {} clicked!".format(
|
||||
elem.classes()))
|
||||
for klass in elem.classes():
|
||||
if any([klass.startswith(e) for e in div_classes]):
|
||||
return True
|
||||
elif tag == 'span':
|
||||
log.webview.debug("span with classes {} clicked!".format(
|
||||
elem.classes()))
|
||||
return False
|
||||
|
||||
def _mousepress_backforward(self, e):
|
||||
"""Handle back/forward mouse button presses.
|
||||
|
||||
@ -258,9 +217,11 @@ class WebView(QWebView):
|
||||
# relative to the QWebView, not to the frame. This makes no sense to
|
||||
# me, but it works this way.
|
||||
hitresult = frame.hitTestContent(pos)
|
||||
elem = hitresult.element()
|
||||
if hitresult.isNull():
|
||||
log.mouse.debug("Hitresult is null!")
|
||||
elif self._is_editable(hitresult):
|
||||
elif ((hitresult.isContentEditable() and webelem.is_writable(elem)) or
|
||||
webelem.is_editable(elem)):
|
||||
log.mouse.debug("Clicked editable element!")
|
||||
modeman.enter('insert', 'click')
|
||||
else:
|
||||
@ -453,10 +414,11 @@ class WebView(QWebView):
|
||||
if modeman.instance().mode == 'insert' or not ok:
|
||||
return
|
||||
frame = self.page().currentFrame()
|
||||
elem = frame.findFirstElement(
|
||||
webelem.SELECTORS[webelem.Group.editable_focused])
|
||||
log.modes.debug("focus element: {}".format(not elem.isNull()))
|
||||
if not elem.isNull():
|
||||
elem = frame.findFirstElement(':focus')
|
||||
log.modes.debug("focus element: {}".format(elem.toOuterXml()))
|
||||
if elem.isNull():
|
||||
log.webview.debug("Focused element is null!")
|
||||
elif webelem.is_editable(elem):
|
||||
modeman.enter('insert', 'load finished')
|
||||
|
||||
@pyqtSlot(str)
|
||||
|
Loading…
Reference in New Issue
Block a user