Initial qute:* support for QtWebEngine

This commit is contained in:
Florian Bruhin 2016-09-14 10:18:25 +02:00
parent 4a14083507
commit aa71c9ae58
10 changed files with 433 additions and 286 deletions

View File

@ -47,7 +47,7 @@ from qutebrowser.commands import cmdutils, runners, cmdexc
from qutebrowser.config import style, config, websettings, configexc
from qutebrowser.browser import urlmarks, adblock, history, browsertab
from qutebrowser.browser.webkit import cookies, cache, downloads
from qutebrowser.browser.webkit.network import (qutescheme, proxy,
from qutebrowser.browser.webkit.network import (webkitqutescheme, proxy,
networkmanager)
from qutebrowser.mainwindow import mainwindow
from qutebrowser.misc import readline, ipc, savemanager, sessions, crashsignal
@ -400,7 +400,7 @@ def _init_modules(args, crash_handler):
sessions.init(qApp)
log.init.debug("Initializing js-bridge...")
js_bridge = qutescheme.JSBridge(qApp)
js_bridge = webkitqutescheme.JSBridge(qApp)
objreg.register('js-bridge', js_bridge)
log.init.debug("Initializing websettings...")

View File

@ -0,0 +1,206 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""Backend-independent qute:* code.
Module attributes:
pyeval_output: The output of the last :pyeval command.
_HANDLERS: The handlers registered via decorators.
"""
import mimetypes
import urllib.parse
import qutebrowser
from qutebrowser.utils import (version, utils, jinja, log, message, docutils,
objreg, usertypes)
pyeval_output = ":pyeval was never called"
_HANDLERS = {}
class NoHandlerFound(Exception):
"""Raised when no handler was found for the given URL."""
pass
class QuteSchemeOSError(Exception):
"""Called when there was an OSError inside a handler."""
pass
def add_handler(name):
"""Add a handler to the qute: scheme."""
def namedecorator(function):
_HANDLERS[name] = function
return function
return namedecorator
def data_for_url(url):
"""Get the data to show for the given URL.
Args:
url: The QUrl to show.
Return:
A (mimetype, data) tuple.
"""
path = url.path()
host = url.host()
# A url like "qute:foo" is split as "scheme:path", not "scheme:host".
log.misc.debug("url: {}, path: {}, host {}".format(
url.toDisplayString(), path, host))
try:
handler = _HANDLERS[path]
except KeyError:
try:
handler = _HANDLERS[host]
except KeyError:
raise NoHandlerFound(url)
try:
data = handler(url)
except OSError as e:
# FIXME:qtwebengine how to handle this?
raise QuteSchemeOSError(e)
except QuteSchemeError as e:
raise
mimetype, _encoding = mimetypes.guess_type(url.fileName())
if mimetype is None:
mimetype = 'text/html'
return mimetype, data
@add_handler('bookmarks')
def qute_bookmarks(_url):
"""Handler for qute:bookmarks. Display all quickmarks / bookmarks."""
bookmarks = sorted(objreg.get('bookmark-manager').marks.items(),
key=lambda x: x[1]) # Sort by title
quickmarks = sorted(objreg.get('quickmark-manager').marks.items(),
key=lambda x: x[0]) # Sort by name
html = jinja.render('bookmarks.html',
title='Bookmarks',
bookmarks=bookmarks,
quickmarks=quickmarks)
return html.encode('UTF-8', errors='xmlcharrefreplace')
@add_handler('pyeval')
def qute_pyeval(_url):
"""Handler for qute:pyeval. Return HTML content as bytes."""
html = jinja.render('pre.html', title='pyeval', content=pyeval_output)
return html.encode('UTF-8', errors='xmlcharrefreplace')
@add_handler('version')
@add_handler('verizon')
def qute_version(_url):
"""Handler for qute:version. Return HTML content as bytes."""
html = jinja.render('version.html', title='Version info',
version=version.version(),
copyright=qutebrowser.__copyright__)
return html.encode('UTF-8', errors='xmlcharrefreplace')
@add_handler('plainlog')
def qute_plainlog(url):
"""Handler for qute:plainlog. Return HTML content as bytes.
An optional query parameter specifies the minimum log level to print.
For example, qute://log?level=warning prints warnings and errors.
Level can be one of: vdebug, debug, info, warning, error, critical.
"""
if log.ram_handler is None:
text = "Log output was disabled."
else:
try:
level = urllib.parse.parse_qs(url.query())['level'][0]
except KeyError:
level = 'vdebug'
text = log.ram_handler.dump_log(html=False, level=level)
html = jinja.render('pre.html', title='log', content=text)
return html.encode('UTF-8', errors='xmlcharrefreplace')
@add_handler('log')
def qute_log(url):
"""Handler for qute:log. Return HTML content as bytes.
An optional query parameter specifies the minimum log level to print.
For example, qute://log?level=warning prints warnings and errors.
Level can be one of: vdebug, debug, info, warning, error, critical.
"""
if log.ram_handler is None:
html_log = None
else:
try:
level = urllib.parse.parse_qs(url.query())['level'][0]
except KeyError:
level = 'vdebug'
html_log = log.ram_handler.dump_log(html=True, level=level)
html = jinja.render('log.html', title='log', content=html_log)
return html.encode('UTF-8', errors='xmlcharrefreplace')
@add_handler('gpl')
def qute_gpl(_url):
"""Handler for qute:gpl. Return HTML content as bytes."""
return utils.read_file('html/COPYING.html').encode('ASCII')
@add_handler('help')
def qute_help(url):
"""Handler for qute:help. Return HTML content as bytes."""
try:
utils.read_file('html/doc/index.html')
except OSError:
html = jinja.render(
'error.html',
title="Error while loading documentation",
url=url.toDisplayString(),
error="This most likely means the documentation was not generated "
"properly. If you are running qutebrowser from the git "
"repository, please run scripts/asciidoc2html.py. "
"If you're running a released version this is a bug, please "
"use :report to report it.",
icon='')
return html.encode('UTF-8', errors='xmlcharrefreplace')
urlpath = url.path()
if not urlpath or urlpath == '/':
urlpath = 'index.html'
else:
urlpath = urlpath.lstrip('/')
if not docutils.docs_up_to_date(urlpath):
message.error('current', "Your documentation is outdated! Please "
"re-run scripts/asciidoc2html.py.")
path = 'html/doc/{}'.format(urlpath)
if urlpath.endswith('.png'):
return utils.read_file(path, binary=True)
else:
data = utils.read_file(path)
return data.encode('UTF-8', errors='xmlcharrefreplace')

View File

@ -0,0 +1,74 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""QtWebEngine specific qute:* handlers and glue code."""
from PyQt5.QtCore import QBuffer, QIODevice
from PyQt5.QtWebEngineCore import (QWebEngineUrlSchemeHandler,
QWebEngineUrlRequestJob)
from qutebrowser.browser import qutescheme
from qutebrowser.utils import log
class QuteSchemeHandler(QWebEngineUrlSchemeHandler):
def install(self, profile):
"""Install the handler for qute: URLs on the given profile."""
profile.installUrlSchemeHandler(b'qute', self)
def requestStarted(self, job):
"""This method is called when a request for the scheme is started.
This method must be reimplemented by all custom URL scheme handlers. The
request is asynchronous and does not need to be handled right away.
Args:
job: QWebEngineUrlRequestJob
"""
url = job.requestUrl()
assert job.requestMethod() == b'GET'
assert url.scheme() == 'qute'
log.misc.debug("Got request for {}".format(url.toDisplayString()))
try:
mimetype, data = qutescheme.data_for_url(url)
except qutescheme.NoHandlerFound:
log.misc.debug("No handler found for {}".format(
url.toDisplayString()))
job.fail(QWebEngineUrlRequestJob.UrlNotFound)
except qutescheme.QuteSchemeOSError:
# FIXME:qtwebengine how do we show a better error here?
log.misc.exception("OSError while handling qute:* URL")
job.fail(QWebEngineUrlRequestJob.UrlNotFound)
except QuteSchemeError as e:
# FIXME:qtwebengine how do we show a better error here?
log.misc.exception("Error while handling qute:* URL")
job.fail(QWebEngineUrlRequestJob.RequestFailed)
else:
log.misc.debug("Returning {} data".format(mimetype))
# We can't just use the QBuffer constructor taking a QByteArray,
# because that somehow segfaults...
# https://www.riverbankcomputing.com/pipermail/pyqt/2016-September/038075.html
buf = QBuffer(parent=self)
buf.open(QIODevice.WriteOnly)
buf.write(data)
buf.seek(0)
buf.close()
job.reply(mimetype.encode('ascii'), buf)

View File

@ -34,18 +34,32 @@ from PyQt5.QtWebEngineWidgets import (QWebEnginePage, QWebEngineScript,
from qutebrowser.browser import browsertab, mouse
from qutebrowser.browser.webengine import (webview, webengineelem, tabhistory,
interceptor)
interceptor, webenginequtescheme)
from qutebrowser.utils import (usertypes, qtutils, log, javascript, utils,
objreg)
_qute_scheme_handler = None
def init():
"""Initialize QtWebEngine-specific modules."""
# For some reason we need to keep a reference, otherwise the scheme handler
# won't work...
# https://www.riverbankcomputing.com/pipermail/pyqt/2016-September/038075.html
global _qute_scheme_handler
app = QApplication.instance()
profile = QWebEngineProfile.defaultProfile()
log.init.debug("Initializing qute:* handler...")
_qute_scheme_handler = webenginequtescheme.QuteSchemeHandler(parent=app)
_qute_scheme_handler.install(profile)
log.init.debug("Initializing request interceptor...")
host_blocker = objreg.get('host-blocker')
req_interceptor = interceptor.RequestInterceptor(
host_blocker, parent=QApplication.instance())
req_interceptor.install(QWebEngineProfile.defaultProfile())
host_blocker, parent=app)
req_interceptor.install(profile)
# Mapping worlds from usertypes.JsWorld to QWebEngineScript world IDs.

View File

@ -32,7 +32,7 @@ from qutebrowser.config import config
from qutebrowser.utils import (message, log, usertypes, utils, objreg, qtutils,
urlutils, debug)
from qutebrowser.browser import shared
from qutebrowser.browser.webkit.network import qutescheme, networkreply
from qutebrowser.browser.webkit.network import webkitqutescheme, networkreply
from qutebrowser.browser.webkit.network import filescheme
@ -164,7 +164,7 @@ class NetworkManager(QNetworkAccessManager):
self._tab_id = tab_id
self._requests = []
self._scheme_handlers = {
'qute': qutescheme.QuteSchemeHandler(win_id),
'qute': webkitqutescheme.QuteSchemeHandler(win_id),
'file': filescheme.FileSchemeHandler(win_id),
}
self._set_cookiejar(private=config.get('general', 'private-browsing'))

View File

@ -1,275 +0,0 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""Handler functions for different qute:... pages.
Module attributes:
pyeval_output: The output of the last :pyeval command.
"""
import functools
import configparser
import mimetypes
import urllib.parse
from PyQt5.QtCore import pyqtSlot, QObject
from PyQt5.QtNetwork import QNetworkReply
import qutebrowser
from qutebrowser.browser import pdfjs
from qutebrowser.browser.webkit.network import schemehandler, networkreply
from qutebrowser.utils import (version, utils, jinja, log, message, docutils,
objreg)
from qutebrowser.config import configexc, configdata
pyeval_output = ":pyeval was never called"
HANDLERS = {}
def add_handler(name):
"""Add a handler to the qute: scheme."""
def namedecorator(function):
HANDLERS[name] = function
return function
return namedecorator
class QuteSchemeError(Exception):
"""Exception to signal that a handler should return an ErrorReply.
Attributes correspond to the arguments in
networkreply.ErrorNetworkReply.
Attributes:
errorstring: Error string to print.
error: Numerical error value.
"""
def __init__(self, errorstring, error):
"""Constructor."""
self.errorstring = errorstring
self.error = error
super().__init__(errorstring)
class QuteSchemeHandler(schemehandler.SchemeHandler):
"""Scheme handler for qute: URLs."""
def createRequest(self, _op, request, _outgoing_data):
"""Create a new request.
Args:
request: const QNetworkRequest & req
_op: Operation op
_outgoing_data: QIODevice * outgoingData
Return:
A QNetworkReply.
"""
path = request.url().path()
host = request.url().host()
# A url like "qute:foo" is split as "scheme:path", not "scheme:host".
log.misc.debug("url: {}, path: {}, host {}".format(
request.url().toDisplayString(), path, host))
try:
handler = HANDLERS[path]
except KeyError:
try:
handler = HANDLERS[host]
except KeyError:
errorstr = "No handler found for {}!".format(
request.url().toDisplayString())
return networkreply.ErrorNetworkReply(
request, errorstr, QNetworkReply.ContentNotFoundError,
self.parent())
try:
data = handler(self._win_id, request)
except OSError as e:
return networkreply.ErrorNetworkReply(
request, str(e), QNetworkReply.ContentNotFoundError,
self.parent())
except QuteSchemeError as e:
return networkreply.ErrorNetworkReply(request, e.errorstring,
e.error, self.parent())
mimetype, _encoding = mimetypes.guess_type(request.url().fileName())
if mimetype is None:
mimetype = 'text/html'
return networkreply.FixedDataNetworkReply(request, data, mimetype,
self.parent())
class JSBridge(QObject):
"""Javascript-bridge for special qute:... pages."""
@pyqtSlot(int, str, str, str)
def set(self, win_id, sectname, optname, value):
"""Slot to set a setting from qute:settings."""
# https://github.com/The-Compiler/qutebrowser/issues/727
if ((sectname, optname) == ('content', 'allow-javascript') and
value == 'false'):
message.error(win_id, "Refusing to disable javascript via "
"qute:settings as it needs javascript support.")
return
try:
objreg.get('config').set('conf', sectname, optname, value)
except (configexc.Error, configparser.Error) as e:
message.error(win_id, e)
@add_handler('pyeval')
def qute_pyeval(_win_id, _request):
"""Handler for qute:pyeval. Return HTML content as bytes."""
html = jinja.render('pre.html', title='pyeval', content=pyeval_output)
return html.encode('UTF-8', errors='xmlcharrefreplace')
@add_handler('version')
@add_handler('verizon')
def qute_version(_win_id, _request):
"""Handler for qute:version. Return HTML content as bytes."""
html = jinja.render('version.html', title='Version info',
version=version.version(),
copyright=qutebrowser.__copyright__)
return html.encode('UTF-8', errors='xmlcharrefreplace')
@add_handler('plainlog')
def qute_plainlog(_win_id, request):
"""Handler for qute:plainlog. Return HTML content as bytes.
An optional query parameter specifies the minimum log level to print.
For example, qute://log?level=warning prints warnings and errors.
Level can be one of: vdebug, debug, info, warning, error, critical.
"""
if log.ram_handler is None:
text = "Log output was disabled."
else:
try:
level = urllib.parse.parse_qs(request.url().query())['level'][0]
except KeyError:
level = 'vdebug'
text = log.ram_handler.dump_log(html=False, level=level)
html = jinja.render('pre.html', title='log', content=text)
return html.encode('UTF-8', errors='xmlcharrefreplace')
@add_handler('log')
def qute_log(_win_id, request):
"""Handler for qute:log. Return HTML content as bytes.
An optional query parameter specifies the minimum log level to print.
For example, qute://log?level=warning prints warnings and errors.
Level can be one of: vdebug, debug, info, warning, error, critical.
"""
if log.ram_handler is None:
html_log = None
else:
try:
level = urllib.parse.parse_qs(request.url().query())['level'][0]
except KeyError:
level = 'vdebug'
html_log = log.ram_handler.dump_log(html=True, level=level)
html = jinja.render('log.html', title='log', content=html_log)
return html.encode('UTF-8', errors='xmlcharrefreplace')
@add_handler('gpl')
def qute_gpl(_win_id, _request):
"""Handler for qute:gpl. Return HTML content as bytes."""
return utils.read_file('html/COPYING.html').encode('ASCII')
@add_handler('help')
def qute_help(win_id, request):
"""Handler for qute:help. Return HTML content as bytes."""
try:
utils.read_file('html/doc/index.html')
except OSError:
html = jinja.render(
'error.html',
title="Error while loading documentation",
url=request.url().toDisplayString(),
error="This most likely means the documentation was not generated "
"properly. If you are running qutebrowser from the git "
"repository, please run scripts/asciidoc2html.py. "
"If you're running a released version this is a bug, please "
"use :report to report it.",
icon='')
return html.encode('UTF-8', errors='xmlcharrefreplace')
urlpath = request.url().path()
if not urlpath or urlpath == '/':
urlpath = 'index.html'
else:
urlpath = urlpath.lstrip('/')
if not docutils.docs_up_to_date(urlpath):
message.error(win_id, "Your documentation is outdated! Please re-run "
"scripts/asciidoc2html.py.")
path = 'html/doc/{}'.format(urlpath)
if urlpath.endswith('.png'):
return utils.read_file(path, binary=True)
else:
data = utils.read_file(path)
return data.encode('UTF-8', errors='xmlcharrefreplace')
@add_handler('settings')
def qute_settings(win_id, _request):
"""Handler for qute:settings. View/change qute configuration."""
config_getter = functools.partial(objreg.get('config').get, raw=True)
html = jinja.render('settings.html', win_id=win_id, title='settings',
config=configdata, confget=config_getter)
return html.encode('UTF-8', errors='xmlcharrefreplace')
@add_handler('pdfjs')
def qute_pdfjs(_win_id, request):
"""Handler for qute://pdfjs. Return the pdf.js viewer."""
urlpath = request.url().path()
try:
return pdfjs.get_pdfjs_res(urlpath)
except pdfjs.PDFJSNotFound as e:
# Logging as the error might get lost otherwise since we're not showing
# the error page if a single asset is missing. This way we don't lose
# information, as the failed pdfjs requests are still in the log.
log.misc.warning(
"pdfjs resource requested but not found: {}".format(e.path))
raise QuteSchemeError("Can't find pdfjs resource '{}'".format(e.path),
QNetworkReply.ContentNotFoundError)
@add_handler('bookmarks')
def qute_bookmarks(_win_id, _request):
"""Handler for qute:bookmarks. Display all quickmarks / bookmarks."""
bookmarks = sorted(objreg.get('bookmark-manager').marks.items(),
key=lambda x: x[1]) # Sort by title
quickmarks = sorted(objreg.get('quickmark-manager').marks.items(),
key=lambda x: x[0]) # Sort by name
html = jinja.render('bookmarks.html',
title='Bookmarks',
bookmarks=bookmarks,
quickmarks=quickmarks)
return html.encode('UTF-8', errors='xmlcharrefreplace')

View File

@ -0,0 +1,127 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""QtWebKit specific qute:* handlers and glue code."""
import functools
import configparser
from PyQt5.QtCore import pyqtSlot, QObject
from PyQt5.QtNetwork import QNetworkReply
from qutebrowser.browser import pdfjs, qutescheme
from qutebrowser.browser.webkit.network import schemehandler, networkreply
from qutebrowser.utils import jinja, log, message, objreg
from qutebrowser.config import configexc, configdata
class QuteSchemeError(Exception):
"""Exception to signal that a handler should return an ErrorReply.
Attributes correspond to the arguments in
networkreply.ErrorNetworkReply.
Attributes:
errorstring: Error string to print.
error: Numerical error value.
"""
def __init__(self, errorstring, error):
self.errorstring = errorstring
self.error = error
super().__init__(errorstring)
class QuteSchemeHandler(schemehandler.SchemeHandler):
"""Scheme handler for qute: URLs."""
def createRequest(self, _op, request, _outgoing_data):
"""Create a new request.
Args:
request: const QNetworkRequest & req
_op: Operation op
_outgoing_data: QIODevice * outgoingData
Return:
A QNetworkReply.
"""
try:
mimetype, data = qutescheme.data_for_url(request.url())
except qutescheme.NoHandlerFound:
errorstr = "No handler found for {}!".format(
request.url().toDisplayString())
return networkreply.ErrorNetworkReply(
request, errorstr, QNetworkReply.ContentNotFoundError,
self.parent())
except qutescheme.QuteSchemeOSError:
return networkreply.ErrorNetworkReply(
request, str(e), QNetworkReply.ContentNotFoundError,
self.parent())
except QuteSchemeError as e:
return networkreply.ErrorNetworkReply(request, e.errorstring,
e.error, self.parent())
return networkreply.FixedDataNetworkReply(request, data, mimetype,
self.parent())
class JSBridge(QObject):
"""Javascript-bridge for special qute:... pages."""
@pyqtSlot(str, str, str)
def set(self, sectname, optname, value):
"""Slot to set a setting from qute:settings."""
# https://github.com/The-Compiler/qutebrowser/issues/727
if ((sectname, optname) == ('content', 'allow-javascript') and
value == 'false'):
message.error('current', "Refusing to disable javascript via "
"qute:settings as it needs javascript support.")
return
try:
objreg.get('config').set('conf', sectname, optname, value)
except (configexc.Error, configparser.Error) as e:
message.error('current', e)
@qutescheme.add_handler('settings')
def qute_settings(_url):
"""Handler for qute:settings. View/change qute configuration."""
config_getter = functools.partial(objreg.get('config').get, raw=True)
html = jinja.render('settings.html', title='settings', config=configdata,
confget=config_getter)
return html.encode('UTF-8', errors='xmlcharrefreplace')
@qutescheme.add_handler('pdfjs')
def qute_pdfjs(url):
"""Handler for qute://pdfjs. Return the pdf.js viewer."""
try:
return pdfjs.get_pdfjs_res(url.path())
except pdfjs.PDFJSNotFound as e:
# Logging as the error might get lost otherwise since we're not showing
# the error page if a single asset is missing. This way we don't lose
# information, as the failed pdfjs requests are still in the log.
log.misc.warning(
"pdfjs resource requested but not found: {}".format(e.path))
raise QuteSchemeError("Can't find pdfjs resource '{}'".format(e.path),
QNetworkReply.ContentNotFoundError)

View File

@ -1,10 +1,9 @@
{% extends "base.html" %}
{% block script %}
var win_id = {{ win_id }};
var cset = function(section, option, el) {
value = el.value;
window.qute.set(win_id, section, option, value);
window.qute.set(section, option, value);
}
{% endblock %}

View File

@ -33,7 +33,7 @@ from PyQt5.QtCore import QUrl
# so it's available for :debug-pyeval
from PyQt5.QtWidgets import QApplication # pylint: disable=unused-import
from qutebrowser.browser.webkit.network import qutescheme
from qutebrowser.browser import qutescheme
from qutebrowser.utils import log, objreg, usertypes, message, debug, utils
from qutebrowser.commands import cmdutils, runners, cmdexc
from qutebrowser.config import style

View File

@ -33,7 +33,9 @@ import qutebrowser.app # pylint: disable=unused-import
from qutebrowser.commands import cmdutils
from qutebrowser.utils import utils
from qutebrowser.browser.webkit import rfc6266
from qutebrowser.browser.webkit.network import qutescheme
# To run the decorators from there
from qutebrowser.browser.webkit.network import webkitqutescheme
from qutebrowser.browser import qutescheme
def whitelist_generator():