From 33d66676c9521e3a70b25d093f2c865999e9d652 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Mon, 1 Jan 2018 16:10:20 +1300 Subject: [PATCH] Greasemonkey: mock the new GM4 promises based API. Based on the gm4-polyfill.js script from the greasemonkey devs. But not the same because that script doesn't work for us for a couple of reasons: * It assumes all GM_* functions are attributes of `this` which in this case is the global window object. Which breaks it out of our iife. It is possible to change what `this` is within the iife but then we would have to do something weird to ensure the functions were available with the leading `this.`. And I don't think user javascripts tend to call GM functions like that anyway, that polyfill script is just making weird assumptions and then claiming it'll work for "any user script engine". * It tries to provide implementations of GM_registerMenuCommand and GM_getResource text which do unexpected thins or implement a circular dependency on the new version, respectively. --- .../javascript/greasemonkey_wrapper.js | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/qutebrowser/javascript/greasemonkey_wrapper.js b/qutebrowser/javascript/greasemonkey_wrapper.js index 2d36220dc..d9ea736df 100644 --- a/qutebrowser/javascript/greasemonkey_wrapper.js +++ b/qutebrowser/javascript/greasemonkey_wrapper.js @@ -110,6 +110,42 @@ } } + // Stub these two so that the gm4 polyfill script doesn't try to + // create broken versions as attributes of window. + function GM_getResourceText(caption, commandFunc, accessKey) { + console.error(`${GM_info.script.name} called unimplemented GM_getResourceText`); + } + + function GM_registerMenuCommand(caption, commandFunc, accessKey) { + console.error(`${GM_info.script.name} called unimplemented GM_registerMenuCommand`); + } + + // Mock the greasemonkey 4.0 async API. + const GM = {}; + GM.info = GM_info; + Object.entries({ + 'log': GM_log, + 'addStyle': GM_addStyle, + 'deleteValue': GM_deleteValue, + 'getValue': GM_getValue, + 'listValues': GM_listValues, + 'openInTab': GM_openInTab, + 'setValue': GM_setValue, + 'xmlHttpRequest': GM_xmlhttpRequest, + }).forEach(([newKey, old]) => { + if (old && (typeof GM[newKey] == 'undefined')) { + GM[newKey] = function(...args) { + return new Promise((resolve, reject) => { + try { + resolve(old(...args)); + } catch (e) { + reject(e); + } + }); + }; + } + }); + const unsafeWindow = window; // ====== The actual user script source ====== //