| Index: polyfill.js |
| =================================================================== |
| --- a/polyfill.js |
| +++ b/polyfill.js |
| @@ -47,16 +47,22 @@ |
| // Since we add a callback for all messaging API calls in our wrappers, |
| // Chrome assumes we're interested in the response; when there's no response, |
| // it sets runtime.lastError |
| const portClosedBeforeResponseError = |
| // Older versions of Chrome have a typo: |
| // https://crrev.com/c33f51726eacdcc1a487b21a13611f7eab580d6d |
| /^The message port closed before a res?ponse was received\.$/; |
| + // This is the error Firefox throws when a message listener is not a |
| + // function. |
| + const invalidMessageListenerError = "Invalid listener for runtime.onMessage."; |
| + |
| + let messageListeners = new WeakMap(); |
| + |
| function wrapAPI(api) |
|
kzar
2018/01/08 14:35:16
Since we're now wrapping the message APIs as well
Manish Jethani
2018/01/09 09:37:35
Done.
|
| { |
| let object = browser; |
| let path = api.split("."); |
| let name = path.pop(); |
| for (let node of path) |
| { |
| @@ -105,39 +111,105 @@ |
| { |
| resolve(result); |
| } |
| }); |
| }); |
| }; |
| } |
| + function wrapMessageAPIs() |
|
kzar
2018/01/08 14:35:16
Nit: `wrapRuntimeOnMessage`?
Manish Jethani
2018/01/09 09:37:35
Done.
|
| + { |
| + let {onMessage} = browser.runtime; |
| + let {addListener, removeListener, hasListener} = onMessage; |
| + |
| + onMessage.addListener = function(listener) |
| + { |
| + if (typeof listener != "function") |
|
Manish Jethani
2017/10/23 12:21:04
We must check the type here to be consistent with
kzar
2018/01/08 14:35:16
Acknowledged.
|
| + throw new Error(invalidMessageListenerError); |
| + |
| + // Don't add the same listener twice or we end up with multiple wrappers. |
| + if (messageListeners.has(listener)) |
| + return; |
| + |
| + let wrapper = (message, sender, sendResponse) => |
| + { |
| + let wait = listener(message, sender, sendResponse); |
| + |
| + if (wait instanceof Promise) |
| + { |
| + wait.then(sendResponse, reason => |
| + { |
| + try |
| + { |
| + sendResponse(); |
| + } |
| + finally |
| + { |
| + // sendResponse can throw if the internal port is closed; be sure |
|
Manish Jethani
2017/10/23 12:21:04
I haven't verified this, but in any case adding a
kzar
2018/01/08 14:35:16
Acknowledged.
|
| + // to throw the original error. |
| + throw reason; |
| + } |
| + }); |
| + } |
| + |
| + return !!wait; |
| + }; |
| + |
| + addListener.call(onMessage, wrapper); |
| + messageListeners.set(listener, wrapper); |
| + }; |
| + |
| + onMessage.removeListener = function(listener) |
| + { |
| + if (typeof listener != "function") |
| + throw new Error(invalidMessageListenerError); |
| + |
| + let wrapper = messageListeners.get(listener); |
| + if (wrapper) |
| + { |
| + removeListener.call(onMessage, wrapper); |
| + messageListeners.delete(listener); |
| + } |
| + }; |
| + |
| + onMessage.hasListener = function(listener) |
| + { |
| + if (typeof listener != "function") |
| + throw new Error(invalidMessageListenerError); |
| + |
| + return messageListeners.has(listener); |
| + }; |
| + } |
| + |
| function shouldWrapAPIs() |
| { |
| try |
| { |
| return !(browser.storage.local.get([]) instanceof Promise); |
| } |
| catch (error) |
| { |
| } |
| return true; |
| } |
| if (shouldWrapAPIs()) |
| { |
| - // Unlike Firefox and Microsoft Edge, Chrome doesn't have a "browser" object, |
| - // but provides the extension API through the "chrome" namespace |
| + // Unlike Firefox and Microsoft Edge, Chrome doesn't have a "browser" |
| + // object, but provides the extension API through the "chrome" namespace |
| // (non-standard). |
| if (typeof browser == "undefined") |
| window.browser = chrome; |
| for (let api of asyncAPIs) |
| wrapAPI(api); |
| + |
| + wrapMessageAPIs(); |
| } |
| // Workaround since HTMLCollection, NodeList, StyleSheetList, and CSSRuleList |
| // didn't have iterator support before Chrome 51. |
| // https://bugs.chromium.org/p/chromium/issues/detail?id=401699 |
| for (let object of [HTMLCollection, NodeList, StyleSheetList, CSSRuleList]) |
| { |
| if (!(Symbol.iterator in object.prototype)) |