summaryrefslogtreecommitdiff
path: root/overrides
diff options
context:
space:
mode:
authorRory MacQueen <rorymacqueen@gmail.com>2014-07-08 17:08:23 -0700
committerWill Greenberg <will@endlessm.com>2014-07-10 12:28:05 -0700
commit5b2cc64e43d16d0ac54fd2def0c5a821bb7391ea (patch)
treefe197da1ddd2ad16a7f5a7698062525dc214d031 /overrides
parent651b0b051777137f5cf73d01016e3f665055e1f8 (diff)
Move InjectableWebview to the SDK
This class could potentially be used by other pseudo-WebApps in our system, so it makes sense to stick it in the SDK. Provides functionality for cleanly injecting custom CSS and JS into a webview.
Diffstat (limited to 'overrides')
-rw-r--r--overrides/Endless.js2
-rw-r--r--overrides/Makefile.am.inc1
-rw-r--r--overrides/endless_private/injectable_webview.js105
3 files changed, 108 insertions, 0 deletions
diff --git a/overrides/Endless.js b/overrides/Endless.js
index 4049836..f3c2880 100644
--- a/overrides/Endless.js
+++ b/overrides/Endless.js
@@ -24,6 +24,7 @@ function getCurrentFileDir() {
imports.searchPath.unshift(getCurrentFileDir());
const AssetButton = imports.endless_private.asset_button;
+const InjectableWebview = imports.endless_private.injectable_webview;
const ConnectionTest = imports.endless_private.connection_test;
const SearchBox = imports.endless_private.search_box;
const TopbarNavButton = imports.endless_private.topbar_nav_button;
@@ -33,6 +34,7 @@ function _init() {
Endless = this;
Endless.getCurrentFileDir = getCurrentFileDir;
Endless.AssetButton = AssetButton.AssetButton;
+ Endless.InjectableWebview = InjectableWebview.InjectableWebview;
Endless.doConnectionTestAsync = ConnectionTest.doConnectionTestAsync;
Endless.SearchBox = SearchBox.SearchBox;
Endless.TopbarNavButton = TopbarNavButton.TopbarNavButton;
diff --git a/overrides/Makefile.am.inc b/overrides/Makefile.am.inc
index be0f9cd..8df8ceb 100644
--- a/overrides/Makefile.am.inc
+++ b/overrides/Makefile.am.inc
@@ -8,6 +8,7 @@ gjsdir = ${datadir}/gjs-1.0
nobase_dist_gjs_DATA = \
overrides/Endless.js \
overrides/endless_private/asset_button.js \
+ overrides/endless_private/injectable_webview.js \
overrides/endless_private/connection_test.js \
overrides/endless_private/search_box.js \
overrides/endless_private/topbar_nav_button.js \
diff --git a/overrides/endless_private/injectable_webview.js b/overrides/endless_private/injectable_webview.js
new file mode 100644
index 0000000..9cf30b5
--- /dev/null
+++ b/overrides/endless_private/injectable_webview.js
@@ -0,0 +1,105 @@
+const Gio = imports.gi.Gio;
+const Lang = imports.lang;
+const WebKit2 = imports.gi.WebKit2;
+
+/**
+ * Class: InjectableWebview
+ * WebKit WebView subclass which provides a clean interface for injecting
+ * custom JS and CSS from gresource files.
+ *
+ * Calling <inject_js_from_resource()> or <inject_css_from_resource()> will
+ * ensure that the current page (if any) as well as all subsequently loaded
+ * pages in this webview will have the given JS or CSS injected only when the
+ * HTML document has finished loading
+ *
+ * Parent class:
+ * WebKit2.WebView
+ */
+const InjectableWebview = new Lang.Class({
+ Name: 'InjectableWebview',
+ GTypeName: 'EknInjectableWebview',
+ Extends: WebKit2.WebView,
+
+ _init: function (params) {
+ this._injection_handlers = [];
+ this.parent(params);
+ },
+
+ /**
+ * Method: inject_js_from_resource
+ * Injects the given JS file into the current page, as well as all
+ * subsequent pages. Note that this will be an asynchronous call, and will
+ * not block on the injection/execution of the JS. If you want more control
+ * over the order in which JS files are injected, or want to inspect
+ * returned results, use <load_js_from_gresource> instead.
+ *
+ * Parameters:
+ * uri - the JS file's "resource://" URI
+ */
+ inject_js_from_resource: function (js_uri) {
+ let js_str = this._read_gresource_file(js_uri);
+ this._run_js_on_loaded_page(js_str);
+ },
+
+ /**
+ * Method: inject_css_from_resource
+ * Injects the given CSS file into the current page, as well as all
+ * subsequent pages
+ *
+ * Parameters:
+ * uri - the CSS file's "resource://" URI
+ */
+ inject_css_from_resource: function (css_uri) {
+ let css_str = this._read_gresource_file(css_uri);
+
+ // generate a javascript string which creates a CSS Style tag whose
+ // innerText is the same as the CSS file in the gresource
+ let inject_css_script = [
+ 'var link = document.createElement("style");',
+ 'link.type = "text/css";',
+ 'link.rel = "stylesheet";',
+ 'var css_text = CSS_TEXT',
+ 'link.innerText = css_text;',
+ 'document.getElementsByTagName("head")[0].appendChild(link);'
+ ].join('\n').replace('CSS_TEXT', css_str.toSource());
+
+ // exec the javascript
+ this._run_js_on_loaded_page(inject_css_script);
+ },
+
+ /**
+ * Method: clear_injections
+ * Clear all injection handlers from the webview. All future pages will not
+ * be affected by any injected documents prior to calling this.
+ */
+ clear_injections: function () {
+ this._injection_handlers.forEach(function (handler) {
+ this.disconnect(handler);
+ }.bind(this));
+ this._injection_handlers = [];
+ },
+
+ // just return the string contents of the file provided by the URI
+ _read_gresource_file: function (resource_uri) {
+ let file = Gio.file_new_for_uri(resource_uri);
+ let [success, resource_str] = file.load_contents(null);
+ return resource_str.toString();
+ },
+
+ // first, if the webview isn't loading something, attempt to run the
+ // javascript on the page. Also attach a handler to run the javascript
+ // whenever the webview's load-changed indicates it's finished loading
+ // something
+ _run_js_on_loaded_page: function (script) {
+ if (this.uri !== null && !this.is_loading) {
+ this.run_javascript(script, null, null);
+ }
+ let handler = this.connect('load-changed', function (webview, status) {
+ if (status == WebKit2.LoadEvent.FINISHED) {
+ this.run_javascript(script, null, null);
+ }
+ }.bind(this));
+
+ this._injection_handlers.push(handler);
+ }
+});