Refactor initialization of internal JavaScript
- Initialize JavaScript in webenginesettings.py instead of webenginetab.py - Move JavaScript snippet into a .js file - Make sure scripts can be re-run and do nothing if already run. - Run scripts on DocumentCreation *and* DocumentReady. Closes #3717. - Give each script an unique name for debugging. - Also make custom stylesheets work on chrome:// pages
This commit is contained in:
parent
f2864c6253
commit
1b84bbd61d
@ -169,31 +169,65 @@ class WebEngineSettings(websettings.AbstractSettings):
|
||||
self._ATTRIBUTES[name] = [value]
|
||||
|
||||
|
||||
def _inject_early_js(profile, name, js_code, *,
|
||||
world=QWebEngineScript.ApplicationWorld, subframes=False):
|
||||
"""Inject the given script to run early on a page load.
|
||||
|
||||
This runs the script both on DocumentCreation and DocumentReady as on some
|
||||
internal pages, DocumentCreation will not work.
|
||||
|
||||
That is a WORKAROUND for https://bugreports.qt.io/browse/QTBUG-66011
|
||||
"""
|
||||
for injection in ['creation', 'ready']:
|
||||
injection_points = {
|
||||
'creation': QWebEngineScript.DocumentCreation,
|
||||
'ready': QWebEngineScript.DocumentReady,
|
||||
}
|
||||
script = QWebEngineScript()
|
||||
script.setInjectionPoint(injection_points[injection])
|
||||
script.setSourceCode(js_code)
|
||||
script.setWorldId(world)
|
||||
script.setRunsOnSubFrames(subframes)
|
||||
script.setName('_qute_{}_{}'.format(name, injection))
|
||||
profile.scripts().insert(script)
|
||||
|
||||
|
||||
def _remove_early_js(profile, name):
|
||||
"""Remove an early QWebEngineScript."""
|
||||
scripts = profile.scripts()
|
||||
for injection in ['creation', 'ready']:
|
||||
full_name = '_qute_{}_{}'.format(name, injection)
|
||||
script = scripts.findScript(full_name)
|
||||
if not script.isNull():
|
||||
scripts.remove(script)
|
||||
|
||||
|
||||
def _init_stylesheet(profile):
|
||||
"""Initialize custom stylesheets.
|
||||
|
||||
Partially inspired by QupZilla:
|
||||
https://github.com/QupZilla/qupzilla/blob/v2.0/src/lib/app/mainapplication.cpp#L1063-L1101
|
||||
"""
|
||||
old_script = profile.scripts().findScript('_qute_stylesheet')
|
||||
if not old_script.isNull():
|
||||
profile.scripts().remove(old_script)
|
||||
|
||||
_remove_early_js(profile, 'stylesheet')
|
||||
css = shared.get_user_stylesheet()
|
||||
source = '\n'.join([
|
||||
'"use strict";',
|
||||
'window._qutebrowser = window._qutebrowser || {};',
|
||||
js_code = javascript.wrap_global(
|
||||
'stylesheet',
|
||||
utils.read_file('javascript/stylesheet.js'),
|
||||
javascript.assemble('stylesheet', 'set_css', css),
|
||||
])
|
||||
)
|
||||
_inject_early_js(profile, 'stylesheet', js_code, subframes=True)
|
||||
|
||||
script = QWebEngineScript()
|
||||
script.setName('_qute_stylesheet')
|
||||
script.setInjectionPoint(QWebEngineScript.DocumentCreation)
|
||||
script.setWorldId(QWebEngineScript.ApplicationWorld)
|
||||
script.setRunsOnSubFrames(True)
|
||||
script.setSourceCode(source)
|
||||
profile.scripts().insert(script)
|
||||
|
||||
def _init_js(profile):
|
||||
"""Initialize global qutebrowser JavaScript."""
|
||||
js_code = javascript.wrap_global(
|
||||
'scripts',
|
||||
utils.read_file('javascript/scroll.js'),
|
||||
utils.read_file('javascript/webelem.js'),
|
||||
utils.read_file('javascript/caret.js'),
|
||||
)
|
||||
# FIXME:qtwebengine what about subframes=True?
|
||||
_inject_early_js(profile, 'js', js_code, subframes=True)
|
||||
|
||||
|
||||
def _update_stylesheet():
|
||||
@ -288,6 +322,7 @@ def _update_settings(option):
|
||||
|
||||
def _init_profile(profile):
|
||||
"""Init the given profile."""
|
||||
_init_js(profile)
|
||||
_init_stylesheet(profile)
|
||||
_set_http_headers(profile)
|
||||
_set_http_cache_size(profile)
|
||||
|
@ -630,31 +630,10 @@ class WebEngineTab(browsertab.AbstractTab):
|
||||
self._set_widget(widget)
|
||||
self._connect_signals()
|
||||
self.backend = usertypes.Backend.QtWebEngine
|
||||
self._init_js()
|
||||
self._child_event_filter = None
|
||||
self._saved_zoom = None
|
||||
self._reload_url = None
|
||||
|
||||
def _init_js(self):
|
||||
js_code = '\n'.join([
|
||||
'"use strict";',
|
||||
'window._qutebrowser = window._qutebrowser || {};',
|
||||
utils.read_file('javascript/scroll.js'),
|
||||
utils.read_file('javascript/webelem.js'),
|
||||
utils.read_file('javascript/caret.js'),
|
||||
])
|
||||
script = QWebEngineScript()
|
||||
# We can't use DocumentCreation here as WORKAROUND for
|
||||
# https://bugreports.qt.io/browse/QTBUG-66011
|
||||
script.setInjectionPoint(QWebEngineScript.DocumentReady)
|
||||
script.setSourceCode(js_code)
|
||||
|
||||
page = self._widget.page()
|
||||
script.setWorldId(QWebEngineScript.ApplicationWorld)
|
||||
|
||||
# FIXME:qtwebengine what about runsOnSubFrames?
|
||||
page.scripts().insert(script)
|
||||
|
||||
def _install_event_filter(self):
|
||||
self._widget.focusProxy().installEventFilter(self._mouse_event_filter)
|
||||
self._child_event_filter = mouse.ChildEventFilter(
|
||||
|
@ -2,3 +2,4 @@
|
||||
pac_utils.js
|
||||
# Actually a jinja template so eslint chokes on the {{}} syntax.
|
||||
greasemonkey_wrapper.js
|
||||
global_wrapper.js
|
||||
|
12
qutebrowser/javascript/global_wrapper.js
Normal file
12
qutebrowser/javascript/global_wrapper.js
Normal file
@ -0,0 +1,12 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
if (!("_qutebrowser" in window)) {
|
||||
window._qutebrowser = {"initialized": {}};
|
||||
}
|
||||
|
||||
if (window._qutebrowser.initialized["{{name}}"]) {
|
||||
return;
|
||||
}
|
||||
{{code}}
|
||||
window._qutebrowser.initialized["{{name}}"] = true;
|
||||
})();
|
@ -20,6 +20,9 @@
|
||||
"""Utilities related to javascript interaction."""
|
||||
|
||||
|
||||
from qutebrowser.utils import jinja
|
||||
|
||||
|
||||
def string_escape(text):
|
||||
"""Escape values special to javascript in strings.
|
||||
|
||||
@ -70,3 +73,9 @@ def assemble(module, function, *args):
|
||||
parts = ['window', '_qutebrowser', module, function]
|
||||
code = '"use strict";\n{}({});'.format('.'.join(parts), js_args)
|
||||
return code
|
||||
|
||||
|
||||
def wrap_global(name, *sources):
|
||||
"""Wrap a script using window._qutebrowser."""
|
||||
template = jinja.js_environment.get_template('global_wrapper.js')
|
||||
return template.render(code='\n'.join(sources), name=name)
|
||||
|
@ -100,3 +100,12 @@ def test_convert_js_arg(arg, expected):
|
||||
def test_assemble(base, expected_base):
|
||||
expected = '"use strict";\n{}.func(23);'.format(expected_base)
|
||||
assert javascript.assemble(base, 'func', 23) == expected
|
||||
|
||||
|
||||
def test_wrap_global():
|
||||
source = javascript.wrap_global('name',
|
||||
'console.log("foo");',
|
||||
'console.log("bar");')
|
||||
assert 'window._qutebrowser.initialized["name"]' in source
|
||||
assert 'console.log("foo");' in source
|
||||
assert 'console.log("bar");' in source
|
||||
|
Loading…
Reference in New Issue
Block a user