Modularize javascript code
We now load the JS code as a QWebEngineScript, which sets up window._qutebrowser with various "modules". That means we don't have to pass the whole module every time we want to execute something.
This commit is contained in:
parent
00673ef7da
commit
6b7a39685e
@ -33,7 +33,7 @@ from PyQt5.QtWebEngineWidgets import QWebEnginePage, QWebEngineScript
|
|||||||
|
|
||||||
from qutebrowser.browser import browsertab
|
from qutebrowser.browser import browsertab
|
||||||
from qutebrowser.browser.webengine import webview, webengineelem
|
from qutebrowser.browser.webengine import webview, webengineelem
|
||||||
from qutebrowser.utils import usertypes, qtutils, log, javascript
|
from qutebrowser.utils import usertypes, qtutils, log, javascript, utils
|
||||||
|
|
||||||
|
|
||||||
class WebEnginePrinting(browsertab.AbstractPrinting):
|
class WebEnginePrinting(browsertab.AbstractPrinting):
|
||||||
@ -191,11 +191,9 @@ class WebEngineScroller(browsertab.AbstractScroller):
|
|||||||
super()._init_widget(widget)
|
super()._init_widget(widget)
|
||||||
page = widget.page()
|
page = widget.page()
|
||||||
try:
|
try:
|
||||||
page.scrollPositionChanged.connect(
|
page.scrollPositionChanged.connect(self._update_pos)
|
||||||
self._on_scroll_pos_changed)
|
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
log.stub('scrollPositionChanged, on Qt < 5.7')
|
log.stub('scrollPositionChanged, on Qt < 5.7')
|
||||||
self._on_scroll_pos_changed()
|
|
||||||
|
|
||||||
def _key_press(self, key, count=1):
|
def _key_press(self, key, count=1):
|
||||||
# FIXME:qtwebengine Abort scrolling if the minimum/maximum was reached.
|
# FIXME:qtwebengine Abort scrolling if the minimum/maximum was reached.
|
||||||
@ -209,9 +207,9 @@ class WebEngineScroller(browsertab.AbstractScroller):
|
|||||||
QApplication.postEvent(recipient, release_evt)
|
QApplication.postEvent(recipient, release_evt)
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def _on_scroll_pos_changed(self):
|
def _update_pos(self):
|
||||||
"""Update the scroll position attributes when it changed."""
|
"""Update the scroll position attributes when it changed."""
|
||||||
def update_scroll_pos(jsret):
|
def update_pos_cb(jsret):
|
||||||
"""Callback after getting scroll position via JS."""
|
"""Callback after getting scroll position via JS."""
|
||||||
if jsret is None:
|
if jsret is None:
|
||||||
# This can happen when the callback would get called after
|
# This can happen when the callback would get called after
|
||||||
@ -222,8 +220,8 @@ class WebEngineScroller(browsertab.AbstractScroller):
|
|||||||
self._pos_px = QPoint(jsret['px']['x'], jsret['px']['y'])
|
self._pos_px = QPoint(jsret['px']['x'], jsret['px']['y'])
|
||||||
self.perc_changed.emit(*self._pos_perc)
|
self.perc_changed.emit(*self._pos_perc)
|
||||||
|
|
||||||
js_code = javascript.assemble('scroll', 'scroll_pos')
|
js_code = javascript.assemble('scroll', 'pos')
|
||||||
self._tab.run_js_async(js_code, update_scroll_pos)
|
self._tab.run_js_async(js_code, update_pos_cb)
|
||||||
|
|
||||||
def pos_px(self):
|
def pos_px(self):
|
||||||
return self._pos_px
|
return self._pos_px
|
||||||
@ -232,7 +230,7 @@ class WebEngineScroller(browsertab.AbstractScroller):
|
|||||||
return self._pos_perc
|
return self._pos_perc
|
||||||
|
|
||||||
def to_perc(self, x=None, y=None):
|
def to_perc(self, x=None, y=None):
|
||||||
js_code = javascript.assemble('scroll', 'scroll_to_perc', x, y)
|
js_code = javascript.assemble('scroll', 'to_perc', x, y)
|
||||||
self._tab.run_js_async(js_code)
|
self._tab.run_js_async(js_code)
|
||||||
|
|
||||||
def to_point(self, point):
|
def to_point(self, point):
|
||||||
@ -243,7 +241,7 @@ class WebEngineScroller(browsertab.AbstractScroller):
|
|||||||
self._tab.run_js_async("window.scrollBy({x}, {y});".format(x=x, y=y))
|
self._tab.run_js_async("window.scrollBy({x}, {y});".format(x=x, y=y))
|
||||||
|
|
||||||
def delta_page(self, x=0, y=0):
|
def delta_page(self, x=0, y=0):
|
||||||
js_code = javascript.assemble('scroll', 'scroll_delta_page', x, y)
|
js_code = javascript.assemble('scroll', 'delta_page', x, y)
|
||||||
self._tab.run_js_async(js_code)
|
self._tab.run_js_async(js_code)
|
||||||
|
|
||||||
def up(self, count=1):
|
def up(self, count=1):
|
||||||
@ -334,6 +332,31 @@ 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
|
||||||
|
# init js stuff
|
||||||
|
self._init_js()
|
||||||
|
|
||||||
|
def _init_js(self):
|
||||||
|
js_code = '\n'.join([
|
||||||
|
'"use strict";',
|
||||||
|
'window._qutebrowser = {};',
|
||||||
|
utils.read_file('javascript/scroll.js'),
|
||||||
|
utils.read_file('javascript/webelem.js'),
|
||||||
|
])
|
||||||
|
script = QWebEngineScript()
|
||||||
|
script.setInjectionPoint(QWebEngineScript.DocumentCreation)
|
||||||
|
page = self._widget.page()
|
||||||
|
script.setSourceCode(js_code)
|
||||||
|
|
||||||
|
try:
|
||||||
|
page.runJavaScript("", QWebEngineScript.ApplicationWorld)
|
||||||
|
except TypeError:
|
||||||
|
# We're unable to pass a world to runJavaScript
|
||||||
|
script.setWorldId(QWebEngineScript.MainWorld)
|
||||||
|
else:
|
||||||
|
script.setWorldId(QWebEngineScript.ApplicationWorld)
|
||||||
|
|
||||||
|
# FIXME:qtwebengine what about runsOnSubFrames?
|
||||||
|
page.scripts().insert(script)
|
||||||
|
|
||||||
def openurl(self, url):
|
def openurl(self, url):
|
||||||
self._openurl_prepare(url)
|
self._openurl_prepare(url)
|
||||||
@ -427,7 +450,7 @@ class WebEngineTab(browsertab.AbstractTab):
|
|||||||
callback(elems)
|
callback(elems)
|
||||||
|
|
||||||
def find_all_elements(self, selector, callback, *, only_visible=False):
|
def find_all_elements(self, selector, callback, *, only_visible=False):
|
||||||
js_code = javascript.assemble('webelem', 'find_all_elements', selector)
|
js_code = javascript.assemble('webelem', 'find_all', selector)
|
||||||
js_cb = functools.partial(self._find_all_elements_js_cb, callback)
|
js_cb = functools.partial(self._find_all_elements_js_cb, callback)
|
||||||
self.run_js_async(js_code, js_cb)
|
self.run_js_async(js_code, js_cb)
|
||||||
|
|
||||||
|
@ -33,7 +33,3 @@ rules:
|
|||||||
no-undefined: "off"
|
no-undefined: "off"
|
||||||
wrap-iife: ["error", "inside"]
|
wrap-iife: ["error", "inside"]
|
||||||
func-names: "off"
|
func-names: "off"
|
||||||
|
|
||||||
# FIXME turn these on again after using a _qutebrowser object
|
|
||||||
no-unused-vars: "off"
|
|
||||||
no-implicit-globals: "off"
|
|
||||||
|
@ -19,51 +19,57 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
function _qutebrowser_scroll_to_perc(x, y) {
|
window._qutebrowser.scroll = (function() {
|
||||||
var elem = document.documentElement;
|
var funcs = {};
|
||||||
var x_px = window.scrollX;
|
|
||||||
var y_px = window.scrollY;
|
|
||||||
|
|
||||||
if (x !== undefined) {
|
funcs.to_perc = function(x, y) {
|
||||||
x_px = (elem.scrollWidth - elem.clientWidth) / 100 * x;
|
var elem = document.documentElement;
|
||||||
}
|
var x_px = window.scrollX;
|
||||||
|
var y_px = window.scrollY;
|
||||||
|
|
||||||
if (y !== undefined) {
|
if (x !== undefined) {
|
||||||
y_px = (elem.scrollHeight - elem.clientHeight) / 100 * y;
|
x_px = (elem.scrollWidth - elem.clientWidth) / 100 * x;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.scroll(x_px, y_px);
|
if (y !== undefined) {
|
||||||
}
|
y_px = (elem.scrollHeight - elem.clientHeight) / 100 * y;
|
||||||
|
}
|
||||||
|
|
||||||
function _qutebrowser_scroll_delta_page(x, y) {
|
window.scroll(x_px, y_px);
|
||||||
var dx = document.documentElement.clientWidth * x;
|
|
||||||
var dy = document.documentElement.clientHeight * y;
|
|
||||||
window.scrollBy(dx, dy);
|
|
||||||
}
|
|
||||||
|
|
||||||
function _qutebrowser_scroll_pos() {
|
|
||||||
var elem = document.documentElement;
|
|
||||||
var dx = elem.scrollWidth - elem.clientWidth;
|
|
||||||
var dy = elem.scrollHeight - elem.clientHeight;
|
|
||||||
var perc_x, perc_y;
|
|
||||||
|
|
||||||
if (dx === 0) {
|
|
||||||
perc_x = 0;
|
|
||||||
} else {
|
|
||||||
perc_x = 100 / dx * window.scrollX;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dy === 0) {
|
|
||||||
perc_y = 0;
|
|
||||||
} else {
|
|
||||||
perc_y = 100 / dy * window.scrollY;
|
|
||||||
}
|
|
||||||
|
|
||||||
var pos = {
|
|
||||||
"perc": {"x": perc_x, "y": perc_y},
|
|
||||||
"px": {"x": window.scrollX, "y": window.scrollY},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// console.log(JSON.stringify(pos));
|
funcs.delta_page = function(x, y) {
|
||||||
return pos;
|
var dx = document.documentElement.clientWidth * x;
|
||||||
}
|
var dy = document.documentElement.clientHeight * y;
|
||||||
|
window.scrollBy(dx, dy);
|
||||||
|
};
|
||||||
|
|
||||||
|
funcs.pos = function() {
|
||||||
|
var elem = document.documentElement;
|
||||||
|
var dx = elem.scrollWidth - elem.clientWidth;
|
||||||
|
var dy = elem.scrollHeight - elem.clientHeight;
|
||||||
|
var perc_x, perc_y;
|
||||||
|
|
||||||
|
if (dx === 0) {
|
||||||
|
perc_x = 0;
|
||||||
|
} else {
|
||||||
|
perc_x = 100 / dx * window.scrollX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dy === 0) {
|
||||||
|
perc_y = 0;
|
||||||
|
} else {
|
||||||
|
perc_y = 100 / dy * window.scrollY;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pos = {
|
||||||
|
"perc": {"x": perc_x, "y": perc_y},
|
||||||
|
"px": {"x": window.scrollX, "y": window.scrollY},
|
||||||
|
};
|
||||||
|
|
||||||
|
// console.log(JSON.stringify(pos));
|
||||||
|
return pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
return funcs;
|
||||||
|
})();
|
||||||
|
@ -19,60 +19,62 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
document._qutebrowser_elements = [];
|
window._qutebrowser.webelem = (function() {
|
||||||
|
var funcs = {};
|
||||||
|
var elements = [];
|
||||||
|
|
||||||
|
function serialize_elem(elem, id) {
|
||||||
|
var out = {
|
||||||
|
"id": id,
|
||||||
|
"text": elem.text,
|
||||||
|
"tag_name": elem.tagName,
|
||||||
|
"outer_xml": elem.outerHTML,
|
||||||
|
};
|
||||||
|
|
||||||
function _qutebrowser_serialize_elem(elem, id) {
|
var attributes = {};
|
||||||
var out = {
|
for (var i = 0; i < elem.attributes.length; ++i) {
|
||||||
"id": id,
|
var attr = elem.attributes[i];
|
||||||
"text": elem.text,
|
attributes[attr.name] = attr.value;
|
||||||
"tag_name": elem.tagName,
|
}
|
||||||
"outer_xml": elem.outerHTML,
|
out.attributes = attributes;
|
||||||
|
|
||||||
|
// console.log(JSON.stringify(out));
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
funcs.find_all = function(selector) {
|
||||||
|
var elems = document.querySelectorAll(selector);
|
||||||
|
var out = [];
|
||||||
|
var id = elements.length;
|
||||||
|
|
||||||
|
for (var i = 0; i < elems.length; ++i) {
|
||||||
|
var elem = elems[i];
|
||||||
|
out.push(serialize_elem(elem, id));
|
||||||
|
elements[id] = elem;
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
};
|
};
|
||||||
|
|
||||||
var attributes = {};
|
funcs.focus_element = function() {
|
||||||
for (var i = 0; i < elem.attributes.length; ++i) {
|
var elem = document.activeElement;
|
||||||
var attr = elem.attributes[i];
|
|
||||||
attributes[attr.name] = attr.value;
|
|
||||||
}
|
|
||||||
out.attributes = attributes;
|
|
||||||
|
|
||||||
// console.log(JSON.stringify(out));
|
if (!elem || elem === document.body) {
|
||||||
|
// "When there is no selection, the active element is the page's
|
||||||
|
// <body> or null."
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return out;
|
var id = elements.length;
|
||||||
}
|
return serialize_elem(elem, id);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
function _qutebrowser_find_all_elements(selector) {
|
funcs.get_element = function(id) {
|
||||||
var elems = document.querySelectorAll(selector);
|
return elements[id];
|
||||||
var out = [];
|
};
|
||||||
var id = document._qutebrowser_elements.length;
|
|
||||||
|
|
||||||
for (var i = 0; i < elems.length; ++i) {
|
return funcs;
|
||||||
var elem = elems[i];
|
})();
|
||||||
out.push(_qutebrowser_serialize_elem(elem, id));
|
|
||||||
document._qutebrowser_elements[id] = elem;
|
|
||||||
id++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function _qutebrowser_focus_element() {
|
|
||||||
var elem = document.activeElement;
|
|
||||||
|
|
||||||
if (!elem || elem === document.body) {
|
|
||||||
// "When there is no selection, the active element is the page's <body>
|
|
||||||
// or null."
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var id = document._qutebrowser_elements.length;
|
|
||||||
return _qutebrowser_serialize_elem(elem, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function _qutebrowser_get_element(id) {
|
|
||||||
return document._qutebrowser_elements[id];
|
|
||||||
}
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
"""Utilities related to javascript interaction."""
|
"""Utilities related to javascript interaction."""
|
||||||
|
|
||||||
|
import textwrap
|
||||||
|
|
||||||
from qutebrowser.utils import utils
|
from qutebrowser.utils import utils
|
||||||
|
|
||||||
@ -62,10 +63,13 @@ def _convert_js_arg(arg):
|
|||||||
arg, type(arg).__name__))
|
arg, type(arg).__name__))
|
||||||
|
|
||||||
|
|
||||||
def assemble(name, function, *args):
|
def assemble(module, function, *args):
|
||||||
"""Assemble a javascript file and a function call."""
|
"""Assemble a javascript file and a function call."""
|
||||||
code = "{code}\n_qutebrowser_{function}({args});".format(
|
code = textwrap.dedent("""
|
||||||
code=utils.read_file('javascript/{}.js'.format(name)),
|
"use strict";
|
||||||
|
window._qutebrowser.{module}.{function}({args});
|
||||||
|
""").format(
|
||||||
|
module=module,
|
||||||
function=function,
|
function=function,
|
||||||
args=', '.join(_convert_js_arg(arg) for arg in args),
|
args=', '.join(_convert_js_arg(arg) for arg in args),
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user