diff options
author | Rory MacQueen <rorymacqueen@gmail.com> | 2014-07-08 17:08:23 -0700 |
---|---|---|
committer | Will Greenberg <will@endlessm.com> | 2014-07-10 12:28:05 -0700 |
commit | 5b2cc64e43d16d0ac54fd2def0c5a821bb7391ea (patch) | |
tree | fe197da1ddd2ad16a7f5a7698062525dc214d031 /overrides | |
parent | 651b0b051777137f5cf73d01016e3f665055e1f8 (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.js | 2 | ||||
-rw-r--r-- | overrides/Makefile.am.inc | 1 | ||||
-rw-r--r-- | overrides/endless_private/injectable_webview.js | 105 |
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); + } +}); |