Refactor acceptNavigationRequest handling to use signals
This commit is contained in:
parent
2a7998847f
commit
7c1fb1d215
@ -30,7 +30,8 @@ from PyQt5.QtWidgets import QWidget, QApplication
|
||||
|
||||
from qutebrowser.keyinput import modeman
|
||||
from qutebrowser.config import config
|
||||
from qutebrowser.utils import utils, objreg, usertypes, log, qtutils
|
||||
from qutebrowser.utils import (utils, objreg, usertypes, log, qtutils, urlutils,
|
||||
message)
|
||||
from qutebrowser.misc import miscwidgets, objects
|
||||
from qutebrowser.browser import mouse, hints
|
||||
|
||||
@ -94,6 +95,8 @@ class TabData:
|
||||
keep_icon: Whether the (e.g. cloned) icon should not be cleared on page
|
||||
load.
|
||||
inspector: The QWebInspector used for this webview.
|
||||
open_target: Where to open the next link.
|
||||
Only used for QtWebKit.
|
||||
override_target: Override for open_target for fake clicks (like hints).
|
||||
Only used for QtWebKit.
|
||||
pinned: Flag to pin the tab.
|
||||
@ -104,6 +107,7 @@ class TabData:
|
||||
|
||||
keep_icon = attr.ib(False)
|
||||
inspector = attr.ib(None)
|
||||
open_target = attr.ib(usertypes.ClickTarget.normal)
|
||||
override_target = attr.ib(None)
|
||||
pinned = attr.ib(False)
|
||||
fullscreen = attr.ib(False)
|
||||
@ -719,6 +723,22 @@ class AbstractTab(QWidget):
|
||||
self._set_load_status(usertypes.LoadStatus.loading)
|
||||
self.load_started.emit()
|
||||
|
||||
@pyqtSlot(usertypes.NavigationRequest)
|
||||
def _on_navigation_request(self, navigation):
|
||||
"""Handle common acceptNavigationRequest code."""
|
||||
log.webview.debug("navigation request: url {}, type {}, is_main_frame "
|
||||
"{}".format(navigation.url.toDisplayString(),
|
||||
navigation.navigation_type,
|
||||
navigation.is_main_frame))
|
||||
|
||||
if (navigation.navigation_type == navigation.Type.link_clicked and
|
||||
not navigation.url.isValid()):
|
||||
msg = urlutils.get_errstring(navigation.url,
|
||||
"Invalid link clicked")
|
||||
message.error(msg)
|
||||
self.data.open_target = usertypes.ClickTarget.normal
|
||||
navigation.accepted = False
|
||||
|
||||
def handle_auto_insert_mode(self, ok):
|
||||
"""Handle `input.insert_mode.auto_load` after loading finished."""
|
||||
if not config.val.input.insert_mode.auto_load or not ok:
|
||||
|
@ -886,6 +886,7 @@ class WebEngineTab(browsertab.AbstractTab):
|
||||
self._on_proxy_authentication_required)
|
||||
page.fullScreenRequested.connect(self._on_fullscreen_requested)
|
||||
page.contentsSizeChanged.connect(self.contents_size_changed)
|
||||
page.navigation_request.connect(self._on_navigation_request)
|
||||
|
||||
view.titleChanged.connect(self.title_changed)
|
||||
view.urlChanged.connect(self._on_url_changed)
|
||||
|
@ -124,10 +124,12 @@ class WebEnginePage(QWebEnginePage):
|
||||
Signals:
|
||||
certificate_error: Emitted on certificate errors.
|
||||
shutting_down: Emitted when the page is shutting down.
|
||||
navigation_request: Emitted on acceptNavigationRequest.
|
||||
"""
|
||||
|
||||
certificate_error = pyqtSignal()
|
||||
shutting_down = pyqtSignal()
|
||||
navigation_request = pyqtSignal(usertypes.NavigationRequest)
|
||||
|
||||
def __init__(self, *, theme_color, profile, parent=None):
|
||||
super().__init__(profile, parent)
|
||||
@ -288,21 +290,26 @@ class WebEnginePage(QWebEnginePage):
|
||||
url: QUrl,
|
||||
typ: QWebEnginePage.NavigationType,
|
||||
is_main_frame: bool):
|
||||
"""Override acceptNavigationRequest to handle clicked links.
|
||||
|
||||
This only show an error on invalid links - everything else is handled
|
||||
in createWindow.
|
||||
"""
|
||||
log.webview.debug("navigation request: url {}, type {}, is_main_frame "
|
||||
"{}".format(url.toDisplayString(),
|
||||
debug.qenum_key(QWebEnginePage, typ),
|
||||
is_main_frame))
|
||||
if (typ == QWebEnginePage.NavigationTypeLinkClicked and
|
||||
not url.isValid()):
|
||||
msg = urlutils.get_errstring(url, "Invalid link clicked")
|
||||
message.error(msg)
|
||||
return False
|
||||
return True
|
||||
"""Override acceptNavigationRequest to forward it to the tab API."""
|
||||
type_map = {
|
||||
QWebEnginePage.NavigationTypeLinkClicked:
|
||||
usertypes.NavigationRequest.Type.link_clicked,
|
||||
QWebEnginePage.NavigationTypeTyped:
|
||||
usertypes.NavigationRequest.Type.typed,
|
||||
QWebEnginePage.NavigationTypeFormSubmitted:
|
||||
usertypes.NavigationRequest.Type.form_submitted,
|
||||
QWebEnginePage.NavigationTypeBackForward:
|
||||
usertypes.NavigationRequest.Type.back_forward,
|
||||
QWebEnginePage.NavigationTypeReload:
|
||||
usertypes.NavigationRequest.Type.reloaded,
|
||||
QWebEnginePage.NavigationTypeOther:
|
||||
usertypes.NavigationRequest.Type.other,
|
||||
}
|
||||
navigation = usertypes.NavigationRequest(url=url,
|
||||
navigation_type=type_map[typ],
|
||||
is_main_frame=is_main_frame)
|
||||
self.navigation_request.emit(navigation)
|
||||
return navigation.accepted
|
||||
|
||||
@pyqtSlot('QUrl')
|
||||
def _inject_userjs(self, url):
|
||||
|
@ -35,7 +35,7 @@ from PyQt5.QtWebKitWidgets import QWebPage, QWebFrame
|
||||
from PyQt5.QtWebKit import QWebSettings
|
||||
from PyQt5.QtPrintSupport import QPrinter
|
||||
|
||||
from qutebrowser.browser import browsertab
|
||||
from qutebrowser.browser import browsertab, shared
|
||||
from qutebrowser.browser.webkit import (webview, tabhistory, webkitelem,
|
||||
webkitsettings)
|
||||
from qutebrowser.utils import qtutils, objreg, usertypes, utils, log, debug
|
||||
@ -762,6 +762,25 @@ class WebKitTab(browsertab.AbstractTab):
|
||||
def _on_contents_size_changed(self, size):
|
||||
self.contents_size_changed.emit(QSizeF(size))
|
||||
|
||||
@pyqtSlot(usertypes.NavigationRequest)
|
||||
def _on_navigation_request(self, navigation):
|
||||
super()._on_navigation_request(navigation)
|
||||
log.webview.debug("target {} override {}".format(
|
||||
self.data.open_target, self.data.override_target))
|
||||
|
||||
if self.data.override_target is not None:
|
||||
target = self.data.override_target
|
||||
self.data.override_target = None
|
||||
else:
|
||||
target = self.data.open_target
|
||||
|
||||
if (navigation.navigation_type == navigation.Type.link_clicked and
|
||||
target != usertypes.ClickTarget.normal):
|
||||
tab = shared.get_tab(self.win_id, target)
|
||||
tab.openurl(navigation.url)
|
||||
self.data.open_target = usertypes.ClickTarget.normal
|
||||
navigation.accepted = False
|
||||
|
||||
def _connect_signals(self):
|
||||
view = self._widget
|
||||
page = view.page()
|
||||
@ -780,6 +799,7 @@ class WebKitTab(browsertab.AbstractTab):
|
||||
page.frameCreated.connect(self._on_frame_created)
|
||||
frame.contentsSizeChanged.connect(self._on_contents_size_changed)
|
||||
frame.initialLayoutCompleted.connect(self._on_history_trigger)
|
||||
page.navigation_request.connect(self._on_navigation_request)
|
||||
|
||||
self.url_changed.connect(
|
||||
functools.partial(webkitsettings.update_for_tab, self))
|
||||
|
@ -54,10 +54,12 @@ class BrowserPage(QWebPage):
|
||||
shutting_down: Emitted when the page is currently shutting down.
|
||||
reloading: Emitted before a web page reloads.
|
||||
arg: The URL which gets reloaded.
|
||||
navigation_request: Emitted on acceptNavigationRequest.
|
||||
"""
|
||||
|
||||
shutting_down = pyqtSignal()
|
||||
reloading = pyqtSignal(QUrl)
|
||||
navigation_request = pyqtSignal(usertypes.NavigationRequest)
|
||||
|
||||
def __init__(self, win_id, tab_id, tabdata, private, parent=None):
|
||||
super().__init__(parent)
|
||||
@ -70,7 +72,6 @@ class BrowserPage(QWebPage):
|
||||
}
|
||||
self._ignore_load_started = False
|
||||
self.error_occurred = False
|
||||
self.open_target = usertypes.ClickTarget.normal
|
||||
self._networkmanager = networkmanager.NetworkManager(
|
||||
win_id=win_id, tab_id=tab_id, private=private, parent=self)
|
||||
self.setNetworkAccessManager(self._networkmanager)
|
||||
@ -474,7 +475,7 @@ class BrowserPage(QWebPage):
|
||||
source, line, msg)
|
||||
|
||||
def acceptNavigationRequest(self,
|
||||
_frame: QWebFrame,
|
||||
frame: QWebFrame,
|
||||
request: QNetworkRequest,
|
||||
typ: QWebPage.NavigationType):
|
||||
"""Override acceptNavigationRequest to handle clicked links.
|
||||
@ -486,36 +487,27 @@ class BrowserPage(QWebPage):
|
||||
Checks if it should open it in a tab (middle-click or control) or not,
|
||||
and then conditionally opens the URL here or in another tab/window.
|
||||
"""
|
||||
url = request.url()
|
||||
log.webview.debug("navigation request: url {}, type {}, "
|
||||
"target {} override {}".format(
|
||||
url.toDisplayString(),
|
||||
debug.qenum_key(QWebPage, typ),
|
||||
self.open_target,
|
||||
self._tabdata.override_target))
|
||||
type_map = {
|
||||
QWebPage.NavigationTypeLinkClicked:
|
||||
usertypes.NavigationRequest.Type.link_clicked,
|
||||
QWebPage.NavigationTypeFormSubmitted:
|
||||
usertypes.NavigationRequest.Type.form_submitted,
|
||||
QWebPage.NavigationTypeFormResubmitted:
|
||||
usertypes.NavigationRequest.Type.form_resubmitted,
|
||||
QWebPage.NavigationTypeBackOrForward:
|
||||
usertypes.NavigationRequest.Type.back_forward,
|
||||
QWebPage.NavigationTypeReload:
|
||||
usertypes.NavigationRequest.Type.reloaded,
|
||||
QWebPage.NavigationTypeOther:
|
||||
usertypes.NavigationRequest.Type.other,
|
||||
}
|
||||
is_main_frame = frame is self.mainFrame()
|
||||
navigation = usertypes.NavigationRequest(url=request.url(),
|
||||
navigation_type=type_map[typ],
|
||||
is_main_frame=is_main_frame)
|
||||
|
||||
if self._tabdata.override_target is not None:
|
||||
target = self._tabdata.override_target
|
||||
self._tabdata.override_target = None
|
||||
else:
|
||||
target = self.open_target
|
||||
if navigation.navigation_type == navigation.Type.reloaded:
|
||||
self.reloading.emit(navigation.url)
|
||||
|
||||
if typ == QWebPage.NavigationTypeReload:
|
||||
self.reloading.emit(url)
|
||||
return True
|
||||
elif typ != QWebPage.NavigationTypeLinkClicked:
|
||||
return True
|
||||
|
||||
if not url.isValid():
|
||||
msg = urlutils.get_errstring(url, "Invalid link clicked")
|
||||
message.error(msg)
|
||||
self.open_target = usertypes.ClickTarget.normal
|
||||
return False
|
||||
|
||||
if target == usertypes.ClickTarget.normal:
|
||||
return True
|
||||
|
||||
tab = shared.get_tab(self._win_id, target)
|
||||
tab.openurl(url)
|
||||
self.open_target = usertypes.ClickTarget.normal
|
||||
return False
|
||||
self.navigation_request.emit(navigation)
|
||||
return navigation.accepted
|
||||
|
@ -262,10 +262,10 @@ class WebView(QWebView):
|
||||
target = usertypes.ClickTarget.tab_bg
|
||||
else:
|
||||
target = usertypes.ClickTarget.tab
|
||||
self.page().open_target = target
|
||||
self._tabdata.open_target = target
|
||||
log.mouse.debug("Ctrl/Middle click, setting target: {}".format(
|
||||
target))
|
||||
else:
|
||||
self.page().open_target = usertypes.ClickTarget.normal
|
||||
self._tabdata.open_target = usertypes.ClickTarget.normal
|
||||
log.mouse.debug("Normal click, setting normal target")
|
||||
super().mousePressEvent(e)
|
||||
|
@ -27,6 +27,7 @@ import operator
|
||||
import collections.abc
|
||||
import enum
|
||||
|
||||
import attr
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QTimer
|
||||
|
||||
from qutebrowser.utils import log, qtutils, utils
|
||||
@ -394,3 +395,22 @@ class AbstractCertificateErrorWrapper:
|
||||
|
||||
def is_overridable(self):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
@attr.s
|
||||
class NavigationRequest:
|
||||
|
||||
Type = enum.Enum('Type', [
|
||||
'link_clicked',
|
||||
'typed', # QtWebEngine only
|
||||
'form_submitted',
|
||||
'form_resubmitted', # QtWebKit only
|
||||
'back_forward',
|
||||
'reloaded',
|
||||
'other'
|
||||
])
|
||||
|
||||
url = attr.ib()
|
||||
navigation_type = attr.ib()
|
||||
is_main_frame = attr.ib()
|
||||
accepted = attr.ib(default=True)
|
||||
|
@ -207,7 +207,7 @@ Feature: Using hints
|
||||
Scenario: Using :follow-hint inside an iframe
|
||||
When I open data/hints/iframe.html
|
||||
And I hint with args "links normal" and follow a
|
||||
Then "navigation request: url http://localhost:*/data/hello.txt, type NavigationTypeLinkClicked, *" should be logged
|
||||
Then "navigation request: url http://localhost:*/data/hello.txt, type Type.link_clicked, *" should be logged
|
||||
|
||||
Scenario: Using :follow-hint inside an iframe button
|
||||
When I open data/hints/iframe_button.html
|
||||
@ -228,12 +228,12 @@ Feature: Using hints
|
||||
And I hint with args "all normal" and follow a
|
||||
And I run :scroll bottom
|
||||
And I hint with args "links normal" and follow a
|
||||
Then "navigation request: url http://localhost:*/data/hello2.txt, type NavigationTypeLinkClicked, *" should be logged
|
||||
Then "navigation request: url http://localhost:*/data/hello2.txt, type Type.link_clicked, *" should be logged
|
||||
|
||||
Scenario: Opening a link inside a specific iframe
|
||||
When I open data/hints/iframe_target.html
|
||||
And I hint with args "links normal" and follow a
|
||||
Then "navigation request: url http://localhost:*/data/hello.txt, type NavigationTypeLinkClicked, *" should be logged
|
||||
Then "navigation request: url http://localhost:*/data/hello.txt, type Type.link_clicked, *" should be logged
|
||||
|
||||
Scenario: Opening a link with specific target frame in a new tab
|
||||
When I open data/hints/iframe_target.html
|
||||
|
@ -250,7 +250,7 @@ Feature: Searching on a page
|
||||
And I run :search follow
|
||||
And I wait for "search found follow" in the log
|
||||
And I run :follow-selected
|
||||
Then "navigation request: url http://localhost:*/data/hello.txt, type NavigationTypeLinkClicked, is_main_frame False" should be logged
|
||||
Then "navigation request: url http://localhost:*/data/hello.txt, type Type.link_clicked, is_main_frame False" should be logged
|
||||
|
||||
@qtwebkit_skip: Not supported in qtwebkit
|
||||
Scenario: Follow a tabbed searched link in an iframe
|
||||
|
Loading…
Reference in New Issue
Block a user