Index: ext/common.js |
=================================================================== |
--- a/ext/common.js |
+++ b/ext/common.js |
@@ -20,16 +20,85 @@ |
(function() |
{ |
// Both Edge and Mozilla Web Extensions use the namespace |
// 'browser' instead of 'chrome'. Edge has chrome namespace defined, |
// in some cases, but only with one property: 'app'. |
if (typeof chrome == "undefined" || typeof chrome.extension == "undefined") |
window.chrome = window.browser; |
+ const asyncAPIs = [ |
Manish Jethani
2017/10/11 19:23:51
This is the list of async APIs we actually use.
I
|
+ "contextMenus.removeAll", |
+ "devtools.panels.create", |
+ "notifications.clear", |
+ "notifications.create", |
+ "runtime.openOptionsPage", |
+ "runtime.sendMessage", |
+ "runtime.setUninstallURL", |
+ "storage.local.get", |
+ "storage.local.remove", |
+ "storage.local.set", |
+ "storage.managed.get", |
+ "tabs.create", |
+ "tabs.get", |
+ "tabs.insertCSS", |
+ "tabs.query", |
+ "tabs.reload", |
+ "tabs.sendMessage", |
+ "tabs.update", |
+ "webNavigation.getAllFrames", |
+ "webRequest.handlerBehaviorChanged", |
+ "windows.create", |
+ "windows.update" |
+ ]; |
+ |
+ function wrapAPI(api, object) |
+ { |
+ if (!object) |
+ return; |
+ |
+ let [root, ...subPath] = api.split("."); |
+ |
+ if (subPath.length > 0) |
+ { |
+ wrapAPI(subPath.join("."), object[root]); |
+ return; |
+ } |
+ |
+ let func = object[root]; |
+ object[root] = function(...args) |
+ { |
+ if (typeof args[args.length - 1] == "function") |
+ return func.apply(object, args); |
+ |
+ // If the last argument is undefined, we drop it from the list assuming |
+ // it stands for the optional callback. We must do this, because we have |
+ // to replace it with our own callback. If we simply append our own |
+ // callback to the list, it won't match the signature of the function and |
+ // will cause an exception. |
+ if (typeof args[args.length - 1] == "undefined") |
Manish Jethani
2017/10/11 19:23:51
This should work, but if it doesn't we can always
|
+ args.pop(); |
+ |
+ return new Promise((resolve, reject) => |
+ { |
+ func.call(object, ...args, result => |
+ { |
+ let error = chrome.runtime.lastError; |
Manish Jethani
2017/10/11 19:23:51
It's OK to refer to chrome directly here. It will
|
+ if (error) |
+ reject(error); |
+ else |
+ resolve(result); |
+ }); |
+ }); |
+ }; |
+ } |
+ |
+ for (let api of asyncAPIs) |
+ wrapAPI(api, chrome); |
+ |
window.ext = {}; |
let EventTarget = ext._EventTarget = function() |
{ |
this._listeners = new Set(); |
}; |
EventTarget.prototype = { |
addListener(listener) |