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]
|
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):
|
def _init_stylesheet(profile):
|
||||||
"""Initialize custom stylesheets.
|
"""Initialize custom stylesheets.
|
||||||
|
|
||||||
Partially inspired by QupZilla:
|
Partially inspired by QupZilla:
|
||||||
https://github.com/QupZilla/qupzilla/blob/v2.0/src/lib/app/mainapplication.cpp#L1063-L1101
|
https://github.com/QupZilla/qupzilla/blob/v2.0/src/lib/app/mainapplication.cpp#L1063-L1101
|
||||||
"""
|
"""
|
||||||
old_script = profile.scripts().findScript('_qute_stylesheet')
|
_remove_early_js(profile, 'stylesheet')
|
||||||
if not old_script.isNull():
|
|
||||||
profile.scripts().remove(old_script)
|
|
||||||
|
|
||||||
css = shared.get_user_stylesheet()
|
css = shared.get_user_stylesheet()
|
||||||
source = '\n'.join([
|
js_code = javascript.wrap_global(
|
||||||
'"use strict";',
|
'stylesheet',
|
||||||
'window._qutebrowser = window._qutebrowser || {};',
|
|
||||||
utils.read_file('javascript/stylesheet.js'),
|
utils.read_file('javascript/stylesheet.js'),
|
||||||
javascript.assemble('stylesheet', 'set_css', css),
|
javascript.assemble('stylesheet', 'set_css', css),
|
||||||
])
|
)
|
||||||
|
_inject_early_js(profile, 'stylesheet', js_code, subframes=True)
|
||||||
|
|
||||||
script = QWebEngineScript()
|
|
||||||
script.setName('_qute_stylesheet')
|
def _init_js(profile):
|
||||||
script.setInjectionPoint(QWebEngineScript.DocumentCreation)
|
"""Initialize global qutebrowser JavaScript."""
|
||||||
script.setWorldId(QWebEngineScript.ApplicationWorld)
|
js_code = javascript.wrap_global(
|
||||||
script.setRunsOnSubFrames(True)
|
'scripts',
|
||||||
script.setSourceCode(source)
|
utils.read_file('javascript/scroll.js'),
|
||||||
profile.scripts().insert(script)
|
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():
|
def _update_stylesheet():
|
||||||
@ -288,6 +322,7 @@ def _update_settings(option):
|
|||||||
|
|
||||||
def _init_profile(profile):
|
def _init_profile(profile):
|
||||||
"""Init the given profile."""
|
"""Init the given profile."""
|
||||||
|
_init_js(profile)
|
||||||
_init_stylesheet(profile)
|
_init_stylesheet(profile)
|
||||||
_set_http_headers(profile)
|
_set_http_headers(profile)
|
||||||
_set_http_cache_size(profile)
|
_set_http_cache_size(profile)
|
||||||
|
@ -630,31 +630,10 @@ class WebEngineTab(browsertab.AbstractTab):
|
|||||||
self._set_widget(widget)
|
self._set_widget(widget)
|
||||||
self._connect_signals()
|
self._connect_signals()
|
||||||
self.backend = usertypes.Backend.QtWebEngine
|
self.backend = usertypes.Backend.QtWebEngine
|
||||||
self._init_js()
|
|
||||||
self._child_event_filter = None
|
self._child_event_filter = None
|
||||||
self._saved_zoom = None
|
self._saved_zoom = None
|
||||||
self._reload_url = 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):
|
def _install_event_filter(self):
|
||||||
self._widget.focusProxy().installEventFilter(self._mouse_event_filter)
|
self._widget.focusProxy().installEventFilter(self._mouse_event_filter)
|
||||||
self._child_event_filter = mouse.ChildEventFilter(
|
self._child_event_filter = mouse.ChildEventFilter(
|
||||||
|
@ -2,3 +2,4 @@
|
|||||||
pac_utils.js
|
pac_utils.js
|
||||||
# Actually a jinja template so eslint chokes on the {{}} syntax.
|
# Actually a jinja template so eslint chokes on the {{}} syntax.
|
||||||
greasemonkey_wrapper.js
|
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."""
|
"""Utilities related to javascript interaction."""
|
||||||
|
|
||||||
|
|
||||||
|
from qutebrowser.utils import jinja
|
||||||
|
|
||||||
|
|
||||||
def string_escape(text):
|
def string_escape(text):
|
||||||
"""Escape values special to javascript in strings.
|
"""Escape values special to javascript in strings.
|
||||||
|
|
||||||
@ -70,3 +73,9 @@ def assemble(module, function, *args):
|
|||||||
parts = ['window', '_qutebrowser', module, function]
|
parts = ['window', '_qutebrowser', module, function]
|
||||||
code = '"use strict";\n{}({});'.format('.'.join(parts), js_args)
|
code = '"use strict";\n{}({});'.format('.'.join(parts), js_args)
|
||||||
return code
|
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):
|
def test_assemble(base, expected_base):
|
||||||
expected = '"use strict";\n{}.func(23);'.format(expected_base)
|
expected = '"use strict";\n{}.func(23);'.format(expected_base)
|
||||||
assert javascript.assemble(base, 'func', 23) == expected
|
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