Merge branch 'perdomainstylesheets' of https://github.com/jcjordyn130/qutebrowser into jcjordyn130/perdomainstylesheets

per-domain-stylesheets
reaysawa 2019-03-11 00:25:12 -03:00
commit 6313a74423
7 changed files with 125 additions and 64 deletions

View File

@ -25,7 +25,7 @@ import netrc
from PyQt5.QtCore import QUrl
from qutebrowser.config import config
from qutebrowser.config import config, configutils
from qutebrowser.utils import usertypes, message, log, objreg, jinja, utils
from qutebrowser.mainwindow import mainwindow
@ -273,20 +273,31 @@ def get_tab(win_id, target):
return tabbed_browser.tabopen(url=None, background=bg_tab)
def get_user_stylesheet(searching=False):
"""Get the combined user-stylesheet."""
def _wrap_bar(css: str, searching: bool):
"""Wrap the passed css in a bar if needed, depending on settings."""
if css is not configutils.UNSET and \
(config.val.scrolling.bar == 'never' or
config.val.scrolling.bar == 'when-searching' and not searching):
css += '\nhtml > ::-webkit-scrollbar { width: 0px; height: 0px; }'
return css
def get_user_stylesheet(searching=False, url=None):
"""Get the combined user-stylesheet.
If `url` is given and there's no overridden stylesheet, return
`configutils.UNSET`.
"""
css = ''
stylesheets = config.val.content.user_stylesheets
stylesheets = config.instance.get('content.user_stylesheets', url,
fallback=url is None)
if stylesheets is configutils.UNSET:
return _wrap_bar(stylesheets, searching)
for filename in stylesheets:
with open(filename, 'r', encoding='utf-8') as f:
css += f.read()
if (config.val.scrolling.bar == 'never' or
config.val.scrolling.bar == 'when-searching' and not searching):
css += '\nhtml > ::-webkit-scrollbar { width: 0px; height: 0px; }'
return css
return _wrap_bar(css, searching)
def netrc_authentication(url, authenticator):

View File

@ -31,7 +31,7 @@ from PyQt5.QtNetwork import QAuthenticator
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebEngineWidgets import QWebEnginePage, QWebEngineScript
from qutebrowser.config import configdata, config
from qutebrowser.config import configdata, config, configutils
from qutebrowser.browser import browsertab, mouse, shared, webelem
from qutebrowser.browser.webengine import (webview, webengineelem, tabhistory,
interceptor, webenginequtescheme,
@ -863,23 +863,43 @@ class _WebEngineScripts(QObject):
def connect_signals(self):
"""Connect signals to our private slots."""
config.instance.changed.connect(self._on_config_changed)
self._tab.url_changed.connect(self._update_stylesheet)
self._tab.load_finished.connect(self._on_load_finished)
self._tab.search.cleared.connect(functools.partial(
self._update_stylesheet, searching=False))
self._tab.search.finished.connect(self._update_stylesheet)
self._tab.search.cleared.connect(
lambda: self._update_stylesheet(self._tab.url(), searching=False, force=True))
self._tab.search.finished.connect(
lambda found: self._update_stylesheet(self._tab.url(), searching=found, force=True))
@pyqtSlot(str)
def _on_config_changed(self, option):
if option in ['scrolling.bar', 'content.user_stylesheets']:
self._init_stylesheet()
self._update_stylesheet()
self._update_stylesheet(self._tab.url(), force=True)
@pyqtSlot(bool)
def _update_stylesheet(self, searching=False):
"""Update the custom stylesheet in existing tabs."""
css = shared.get_user_stylesheet(searching=searching)
code = javascript.assemble('stylesheet', 'set_css', css)
self._tab.run_js_async(code)
@pyqtSlot()
def _on_load_finished(self, searching=False):
url = self._tab.url()
self._update_stylesheet(url, searching=searching)
@pyqtSlot(QUrl)
def _update_stylesheet(self, url, searching=False, force=False):
"""Update the custom stylesheet in existing tabs.
Arguments:
url: The url to get the stylesheet for.
force: Also update the global stylesheet.
"""
if not url.isValid():
# FIXME should we be dropping this request completely?
url = None
css = shared.get_user_stylesheet(searching=searching, url=url)
if css is configutils.UNSET and force:
css = shared.get_user_stylesheet(searching=searching, url=None)
if css is not configutils.UNSET:
code = javascript.assemble('stylesheet', 'set_css', css)
self._tab.run_js_async(code)
def _inject_early_js(self, name, js_code, *,
world=QWebEngineScript.ApplicationWorld,
@ -952,7 +972,7 @@ class _WebEngineScripts(QObject):
https://github.com/QupZilla/qupzilla/blob/v2.0/src/lib/app/mainapplication.cpp#L1063-L1101
"""
self._remove_early_js('stylesheet')
css = shared.get_user_stylesheet()
css = shared.get_user_stylesheet(url=None)
js_code = javascript.wrap_global(
'stylesheet',
utils.read_file('javascript/stylesheet.js'),

View File

@ -29,7 +29,7 @@ import os.path
from PyQt5.QtGui import QFont
from PyQt5.QtWebKit import QWebSettings
from qutebrowser.config import config, websettings
from qutebrowser.config import config, websettings, configutils
from qutebrowser.config.websettings import AttributeInfo as Attr
from qutebrowser.utils import standarddir, urlutils
from qutebrowser.browser import shared
@ -120,43 +120,50 @@ class WebKitSettings(websettings.AbstractSettings):
QWebSettings.FantasyFont: QFont.Fantasy,
}
def _set_user_stylesheet(self, url=None):
"""Set the generated user-stylesheet."""
stylesheet = shared.get_user_stylesheet(url=url)
if stylesheet is configutils.UNSET:
return
url = urlutils.data_url('text/css;charset=utf-8',
stylesheet.encode('utf-8'))
self._settings.setUserStyleSheetUrl(url)
def _set_user_stylesheet(settings):
"""Set the generated user-stylesheet."""
stylesheet = shared.get_user_stylesheet().encode('utf-8')
url = urlutils.data_url('text/css;charset=utf-8', stylesheet)
settings.setUserStyleSheetUrl(url)
def _set_cookie_accept_policy(self):
"""Update the content.cookies.accept setting."""
mapping = {
'all': QWebSettings.AlwaysAllowThirdPartyCookies,
'no-3rdparty': QWebSettings.AlwaysBlockThirdPartyCookies,
'never': QWebSettings.AlwaysBlockThirdPartyCookies,
'no-unknown-3rdparty': QWebSettings.AllowThirdPartyWithExistingCookies,
}
value = config.val.content.cookies.accept
self._settings.setThirdPartyCookiePolicy(mapping[value])
def _set_cache_maximum_pages(self):
"""Update the content.cache.maximum_pages setting."""
value = config.val.content.cache.maximum_pages
self._settings.setMaximumPagesInCache(value)
def _set_cookie_accept_policy(settings):
"""Update the content.cookies.accept setting."""
mapping = {
'all': QWebSettings.AlwaysAllowThirdPartyCookies,
'no-3rdparty': QWebSettings.AlwaysBlockThirdPartyCookies,
'never': QWebSettings.AlwaysBlockThirdPartyCookies,
'no-unknown-3rdparty': QWebSettings.AllowThirdPartyWithExistingCookies,
}
value = config.val.content.cookies.accept
settings.setThirdPartyCookiePolicy(mapping[value])
def update_setting(self, option):
if option in ['scrollbar.hide', 'content.user_stylesheets']:
self._set_user_stylesheet()
elif option == 'content.cookies.accept':
self._set_cookie_accept_policy()
elif option == 'content.cache.maximum_pages':
self._set_cache_maximum_pages()
else:
super().update_setting(option)
def update_for_url(self, url):
super().update_for_url(url)
self._set_user_stylesheet(url)
def _set_cache_maximum_pages(settings):
"""Update the content.cache.maximum_pages setting."""
value = config.val.content.cache.maximum_pages
settings.setMaximumPagesInCache(value)
def _update_settings(option):
"""Update global settings when qwebsettings changed."""
global_settings.update_setting(option)
settings = QWebSettings.globalSettings()
if option in ['scrollbar.hide', 'content.user_stylesheets']:
_set_user_stylesheet(settings)
elif option == 'content.cookies.accept':
_set_cookie_accept_policy(settings)
elif option == 'content.cache.maximum_pages':
_set_cache_maximum_pages(settings)
def init_settings(self):
super().init_settings()
self._set_user_stylesheet()
self._set_cookie_accept_policy()
self._set_cache_maximum_pages()
def init(_args):
@ -172,16 +179,10 @@ def init(_args):
QWebSettings.setOfflineStoragePath(
os.path.join(data_path, 'offline-storage'))
settings = QWebSettings.globalSettings()
_set_user_stylesheet(settings)
_set_cookie_accept_policy(settings)
_set_cache_maximum_pages(settings)
config.instance.changed.connect(_update_settings)
global global_settings
global_settings = WebKitSettings(QWebSettings.globalSettings())
global_settings.init_settings()
config.instance.changed.connect(global_settings.update_setting)
def shutdown():

View File

@ -353,10 +353,15 @@ class Config(QObject):
"""Get the given setting converted for Python code.
Args:
fallback: Use the global value if there's no URL-specific one.
name: The name of the setting to get.
url: The QUrl to get the setting for.
fallback: If False, return configutils.UNSET when there's no
override for this domain.
"""
opt = self.get_opt(name)
obj = self.get_obj(name, url=url, fallback=fallback)
if obj is configutils.UNSET:
return obj
return opt.typ.to_py(obj)
def _maybe_copy(self, value: Any) -> Any:
@ -378,6 +383,12 @@ class Config(QObject):
Note that the returned values are not watched for mutation.
If a URL is given, return the value which should be used for that URL.
Args:
name: The name of the setting to get.
url: The QUrl to get the setting for.
fallback: If False, return configutils.UNSET when there's no
override for this domain.
"""
self.get_opt(name) # To make sure it exists
value = self._values[name].get_for_url(url, fallback=fallback)

View File

@ -742,6 +742,7 @@ content.user_stylesheets:
valtype: File
none_ok: True
default: []
supports_pattern: true
desc: List of user stylesheet filenames to use.
content.webgl:

View File

@ -120,14 +120,19 @@ window._qutebrowser.stylesheet = (function() {
if (!initialized) {
init();
}
if (css_content === css) {
return;
}
css_content = css;
if (style_elem) {
style_elem.textContent = css;
// The browser seems to rewrite the document in same-origin frames
// without notifying the mutation observer. Ensure that the
// stylesheet is in the current document.
watch_root();
} else {
css_content = css;
}
// Propagate the new CSS to all child frames.
// FIXME:qtwebengine This does not work for cross-origin frames.

View File

@ -479,6 +479,18 @@ class TestConfig:
conf.set_obj(name, False, pattern=pattern)
assert conf.get(name, url=QUrl('https://example.com/')) is False
@pytest.mark.parametrize('fallback', [True, False])
def test_get_for_url_unset(self, conf, fallback):
"""Test config.get() with falling back to a global object."""
name = 'content.javascript.enabled'
conf.set_obj(name, False)
val = conf.get(name,
url=QUrl('https://example.com/'),
fallback=fallback)
expected = False if fallback else configutils.UNSET
assert val == expected
@pytest.mark.parametrize('fallback, expected', [
(True, True),
(False, configutils.UNSET)