Greasemonkey: move GM_* template into seperate file.

Also ported it to jinja rather than str.format().

Also ran the js through jslint and fixed up a few very minor things.
This commit is contained in:
Jimmy 2017-10-04 22:39:32 +13:00
parent c1b912f567
commit fd5d44182b
4 changed files with 128 additions and 116 deletions

View File

@ -29,7 +29,7 @@ import glob
import attr import attr
from PyQt5.QtCore import pyqtSignal, QObject from PyQt5.QtCore import pyqtSignal, QObject
from qutebrowser.utils import log, standarddir from qutebrowser.utils import log, standarddir, jinja
from qutebrowser.commands import cmdutils from qutebrowser.commands import cmdutils
@ -41,115 +41,6 @@ def _scripts_dir():
class GreasemonkeyScript: class GreasemonkeyScript:
"""Container class for userscripts, parses metadata blocks.""" """Container class for userscripts, parses metadata blocks."""
GM_BOOTSTRAP_TEMPLATE = r"""var _qute_script_id = "__gm_{scriptName}";
function GM_log(text) {{
console.log(text);
}}
GM_info = (function() {{
return {{
'script': {scriptInfo},
'scriptMetaStr': {scriptMeta},
'scriptWillUpdate': false,
'version': '0.0.1',
'scriptHandler': 'Tampermonkey' //so scripts don't expect exportFunction
}};
}}());
function GM_setValue(key, value) {{
if (localStorage !== null &&
typeof key === "string" &&
(typeof value === "string" ||
typeof value === "number" ||
typeof value == "boolean")) {{
localStorage.setItem(_qute_script_id + key, value);
}}
}}
function GM_getValue(key, default_) {{
if (localStorage !== null && typeof key === "string") {{
return localStorage.getItem(_qute_script_id + key) || default_;
}}
}}
function GM_deleteValue(key) {{
if (localStorage !== null && typeof key === "string") {{
localStorage.removeItem(_qute_script_id + key);
}}
}}
function GM_listValues() {{
var i;
var keys = [];
for (i = 0; i < localStorage.length; ++i) {{
if (localStorage.key(i).startsWith(_qute_script_id)) {{
keys.push(localStorage.key(i));
}}
}}
return keys;
}}
function GM_openInTab(url) {{
window.open(url);
}}
// Almost verbatim copy from Eric
function GM_xmlhttpRequest(/* object */ details) {{
details.method = details.method.toUpperCase() || "GET";
if(!details.url) {{
throw("GM_xmlhttpRequest requires an URL.");
}}
// build XMLHttpRequest object
var oXhr = new XMLHttpRequest;
// run it
if("onreadystatechange" in details)
oXhr.onreadystatechange = function() {{
details.onreadystatechange(oXhr)
}};
if("onload" in details)
oXhr.onload = function() {{ details.onload(oXhr) }};
if("onerror" in details)
oXhr.onerror = function() {{ details.onerror(oXhr) }};
oXhr.open(details.method, details.url, true);
if("headers" in details)
for(var header in details.headers)
oXhr.setRequestHeader(header, details.headers[header]);
if("data" in details)
oXhr.send(details.data);
else
oXhr.send();
}}
function GM_addStyle(/* String */ styles) {{
var head = document.getElementsByTagName("head")[0];
if (head === undefined) {{
document.onreadystatechange = function() {{
if (document.readyState == "interactive") {{
var oStyle = document.createElement("style");
oStyle.setAttribute("type", "text/css");
oStyle.appendChild(document.createTextNode(styles));
document.getElementsByTagName("head")[0].appendChild(oStyle);
}}
}}
}}
else {{
var oStyle = document.createElement("style");
oStyle.setAttribute("type", "text/css");
oStyle.appendChild(document.createTextNode(styles));
head.appendChild(oStyle);
}}
}}
unsafeWindow = window;
"""
def __init__(self, properties, code): def __init__(self, properties, code):
self._code = code self._code = code
self.includes = [] self.includes = []
@ -200,12 +91,12 @@ unsafeWindow = window;
browser's debugger/inspector will not match up to the line browser's debugger/inspector will not match up to the line
numbers in the source script directly. numbers in the source script directly.
""" """
gm_bootstrap = self.GM_BOOTSTRAP_TEMPLATE.format( return jinja.js_environment.get_template(
scriptName=self.name, 'greasemonkey_wrapper.js').render(
scriptInfo=self._meta_json(), scriptName=self.name,
scriptMeta=self.script_meta) scriptInfo=self._meta_json(),
return '\n'.join( scriptMeta=self.script_meta,
["(function(){", gm_bootstrap, self._code, "})();"]) scriptSource=self._code)
def _meta_json(self): def _meta_json(self):
return json.dumps({ return json.dumps({

View File

@ -1,2 +1,4 @@
# Upstream Mozilla's code # Upstream Mozilla's code
pac_utils.js pac_utils.js
# Actually a jinja template so eslint chokes on the {{}} syntax.
greasemonkey_wrapper.js

View File

@ -0,0 +1,118 @@
(function () {
var _qute_script_id = "__gm_{{ scriptName }}";
function GM_log(text) {
console.log(text);
}
var GM_info = (function () {
return {
'script': {{ scriptInfo }},
'scriptMetaStr': {{ scriptMeta }},
'scriptWillUpdate': false,
'version': '0.0.1',
'scriptHandler': 'Tampermonkey' // so scripts don't expect exportFunction
};
}());
function GM_setValue(key, value) {
if (localStorage !== null &&
typeof key === "string" &&
(typeof value === "string" ||
typeof value === "number" ||
typeof value === "boolean")) {
localStorage.setItem(_qute_script_id + key, value);
}
}
function GM_getValue(key, default_) {
if (localStorage !== null && typeof key === "string") {
return localStorage.getItem(_qute_script_id + key) || default_;
}
}
function GM_deleteValue(key) {
if (localStorage !== null && typeof key === "string") {
localStorage.removeItem(_qute_script_id + key);
}
}
function GM_listValues() {
var i, keys = [];
for (i = 0; i < localStorage.length; i = i + 1) {
if (localStorage.key(i).startsWith(_qute_script_id)) {
keys.push(localStorage.key(i));
}
}
return keys;
}
function GM_openInTab(url) {
window.open(url);
}
// Almost verbatim copy from Eric
function GM_xmlhttpRequest(/* object */ details) {
details.method = details.method.toUpperCase() || "GET";
if (!details.url) {
throw ("GM_xmlhttpRequest requires an URL.");
}
// build XMLHttpRequest object
var oXhr = new XMLHttpRequest();
// run it
if ("onreadystatechange" in details) {
oXhr.onreadystatechange = function () {
details.onreadystatechange(oXhr);
};
}
if ("onload" in details) {
oXhr.onload = function () { details.onload(oXhr) };
}
if ("onerror" in details) {
oXhr.onerror = function () { details.onerror(oXhr) };
}
oXhr.open(details.method, details.url, true);
if ("headers" in details) {
for (var header in details.headers) {
oXhr.setRequestHeader(header, details.headers[header]);
}
}
if ("data" in details) {
oXhr.send(details.data);
} else {
oXhr.send();
}
}
function GM_addStyle(/* String */ styles) {
var head = document.getElementsByTagName("head")[0];
if (head === undefined) {
document.onreadystatechange = function () {
if (document.readyState == "interactive") {
var oStyle = document.createElement("style");
oStyle.setAttribute("type", "text/css");
oStyle.appendChild(document.createTextNode(styles));
document.getElementsByTagName("head")[0].appendChild(oStyle);
}
}
}
else {
var oStyle = document.createElement("style");
oStyle.setAttribute("type", "text/css");
oStyle.appendChild(document.createTextNode(styles));
head.appendChild(oStyle);
}
}
unsafeWindow = window;
//====== The actual user script source ======//
{{ scriptSource }}
//====== End User Script ======//
})();

View File

@ -136,3 +136,4 @@ def render(template, **kwargs):
environment = Environment() environment = Environment()
js_environment = jinja2.Environment(loader=Loader('javascript'))