1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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);
}
});
|