Permalink
Browse files

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.
  • Loading branch information...
The-Compiler committed Aug 9, 2016
1 parent 00673ef commit 6b7a39685e43a8728eaf24567b407b0f625cff7a
@@ -33,7 +33,7 @@
from qutebrowser.browser import browsertab
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):
@@ -191,11 +191,9 @@ def _init_widget(self, widget):
super()._init_widget(widget)
page = widget.page()
try:
- page.scrollPositionChanged.connect(
- self._on_scroll_pos_changed)
+ page.scrollPositionChanged.connect(self._update_pos)
except AttributeError:
log.stub('scrollPositionChanged, on Qt < 5.7')
- self._on_scroll_pos_changed()
def _key_press(self, key, count=1):
# FIXME:qtwebengine Abort scrolling if the minimum/maximum was reached.
@@ -209,9 +207,9 @@ def _key_press(self, key, count=1):
QApplication.postEvent(recipient, release_evt)
@pyqtSlot()
- def _on_scroll_pos_changed(self):
+ def _update_pos(self):
"""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."""
if jsret is None:
# This can happen when the callback would get called after
@@ -222,8 +220,8 @@ def update_scroll_pos(jsret):
self._pos_px = QPoint(jsret['px']['x'], jsret['px']['y'])
self.perc_changed.emit(*self._pos_perc)
- js_code = javascript.assemble('scroll', 'scroll_pos')
- self._tab.run_js_async(js_code, update_scroll_pos)
+ js_code = javascript.assemble('scroll', 'pos')
+ self._tab.run_js_async(js_code, update_pos_cb)
def pos_px(self):
return self._pos_px
@@ -232,7 +230,7 @@ def pos_perc(self):
return self._pos_perc
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)
def to_point(self, point):
@@ -243,7 +241,7 @@ def delta(self, x=0, y=0):
self._tab.run_js_async("window.scrollBy({x}, {y});".format(x=x, y=y))
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)
def up(self, count=1):
@@ -334,6 +332,31 @@ def __init__(self, win_id, mode_manager, parent=None):
self._set_widget(widget)
self._connect_signals()
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):
self._openurl_prepare(url)
@@ -427,7 +450,7 @@ def _find_all_elements_js_cb(self, callback, js_elems):
callback(elems)
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)
self.run_js_async(js_code, js_cb)
@@ -33,7 +33,3 @@ rules:
no-undefined: "off"
wrap-iife: ["error", "inside"]
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";
-function _qutebrowser_scroll_to_perc(x, y) {
- var elem = document.documentElement;
- var x_px = window.scrollX;
- var y_px = window.scrollY;
+window._qutebrowser.scroll = (function() {
+ var funcs = {};
- if (x !== undefined) {
- x_px = (elem.scrollWidth - elem.clientWidth) / 100 * x;
- }
+ funcs.to_perc = function(x, y) {
+ var elem = document.documentElement;
+ var x_px = window.scrollX;
+ var y_px = window.scrollY;
- if (y !== undefined) {
- y_px = (elem.scrollHeight - elem.clientHeight) / 100 * y;
- }
+ if (x !== undefined) {
+ 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) {
- var dx = document.documentElement.clientWidth * x;
- var dy = document.documentElement.clientHeight * y;
- window.scrollBy(dx, dy);
-}
+ window.scroll(x_px, y_px);
+ };
+
+ funcs.delta_page = function(x, y) {
+ 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;
-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 (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;
+ }
- 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},
+ };
- var pos = {
- "perc": {"x": perc_x, "y": perc_y},
- "px": {"x": window.scrollX, "y": window.scrollY},
+ // console.log(JSON.stringify(pos));
+ return pos;
};
- // console.log(JSON.stringify(pos));
- return pos;
-}
+ return funcs;
+})();
@@ -19,60 +19,62 @@
"use strict";
-document._qutebrowser_elements = [];
-
-
-function _qutebrowser_serialize_elem(elem, id) {
- var out = {
- "id": id,
- "text": elem.text,
- "tag_name": elem.tagName,
- "outer_xml": elem.outerHTML,
- };
-
- var attributes = {};
- for (var i = 0; i < elem.attributes.length; ++i) {
- var attr = elem.attributes[i];
- attributes[attr.name] = attr.value;
+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,
+ };
+
+ var attributes = {};
+ for (var i = 0; i < elem.attributes.length; ++i) {
+ var attr = elem.attributes[i];
+ attributes[attr.name] = attr.value;
+ }
+ out.attributes = attributes;
+
+ // console.log(JSON.stringify(out));
+
+ return out;
}
- 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;
-function _qutebrowser_find_all_elements(selector) {
- var elems = document.querySelectorAll(selector);
- var out = [];
- var id = document._qutebrowser_elements.length;
+ for (var i = 0; i < elems.length; ++i) {
+ var elem = elems[i];
+ out.push(serialize_elem(elem, id));
+ elements[id] = elem;
+ id++;
+ }
- for (var i = 0; i < elems.length; ++i) {
- var elem = elems[i];
- out.push(_qutebrowser_serialize_elem(elem, id));
- document._qutebrowser_elements[id] = elem;
- id++;
- }
-
- return out;
-}
+ return out;
+ };
+ funcs.focus_element = function() {
+ var elem = document.activeElement;
-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;
+ }
- if (!elem || elem === document.body) {
- // "When there is no selection, the active element is the page's <body>
- // or null."
- return null;
- }
+ var id = elements.length;
+ return serialize_elem(elem, id);
+ };
- var id = document._qutebrowser_elements.length;
- return _qutebrowser_serialize_elem(elem, id);
-}
+ funcs.get_element = function(id) {
+ return elements[id];
+ };
-function _qutebrowser_get_element(id) {
- return document._qutebrowser_elements[id];
-}
+ return funcs;
+})();
@@ -19,6 +19,7 @@
"""Utilities related to javascript interaction."""
+import textwrap
from qutebrowser.utils import utils
@@ -62,10 +63,13 @@ def _convert_js_arg(arg):
arg, type(arg).__name__))
-def assemble(name, function, *args):
+def assemble(module, function, *args):
"""Assemble a javascript file and a function call."""
- code = "{code}\n_qutebrowser_{function}({args});".format(
- code=utils.read_file('javascript/{}.js'.format(name)),
+ code = textwrap.dedent("""
+ "use strict";
+ window._qutebrowser.{module}.{function}({args});
+ """).format(
+ module=module,
function=function,
args=', '.join(_convert_js_arg(arg) for arg in args),
)

0 comments on commit 6b7a396

Please sign in to comment.