gecko-dev/dom/manifest/ManifestObtainer.jsm

86 строки
2.7 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ManifestObtainer is an implementation of:
* http://w3c.github.io/manifest/#obtaining
*
* Exposes public method `.obtainManifest(browserWindow)`, which returns
* a promise. If successful, you get back a manifest (string).
*
* For e10s compat, this JSM relies on the following to do
* the nessesary IPC:
* dom/ipc/manifestMessages.js
*
* whose internal URL is:
* 'chrome://global/content/manifestMessages.js'
*
* Which is injected into every browser instance via browser.js.
*
* BUG: https://bugzilla.mozilla.org/show_bug.cgi?id=1083410
* exported ManifestObtainer
*/
'use strict';
this.EXPORTED_SYMBOLS = ['ManifestObtainer'];
const MSG_KEY = 'DOM:ManifestObtainer:Obtain';
let messageCounter = 0;
// FIXME: Ideally, we would store a reference to the
// message manager in a weakmap instead of needing a
// browserMap. However, trying to store a messageManager
// results in a TypeError because of:
// https://bugzilla.mozilla.org/show_bug.cgi?id=888600
const browsersMap = new WeakMap();
function ManifestObtainer() {}
ManifestObtainer.prototype = {
obtainManifest(aBrowserWindow) {
if (!aBrowserWindow) {
const err = new TypeError('Invalid input. Expected xul browser.');
return Promise.reject(err);
}
const mm = aBrowserWindow.messageManager;
const onMessage = function(aMsg) {
const msgId = aMsg.data.msgId;
const {
resolve, reject
} = browsersMap.get(aBrowserWindow).get(msgId);
browsersMap.get(aBrowserWindow).delete(msgId);
// If we we've processed all messages,
// stop listening.
if (!browsersMap.get(aBrowserWindow).size) {
browsersMap.delete(aBrowserWindow);
mm.removeMessageListener(MSG_KEY, onMessage);
}
if (aMsg.data.success) {
return resolve(aMsg.data.result);
}
reject(toError(aMsg.data.result));
};
// If we are not already listening for messages
// start listening.
if (!browsersMap.has(aBrowserWindow)) {
browsersMap.set(aBrowserWindow, new Map());
mm.addMessageListener(MSG_KEY, onMessage);
}
return new Promise((resolve, reject) => {
const msgId = messageCounter++;
browsersMap.get(aBrowserWindow).set(msgId, {
resolve: resolve,
reject: reject
});
mm.sendAsyncMessage(MSG_KEY, {
msgId: msgId
});
});
function toError(aErrorClone) {
const error = new Error();
Object.getOwnPropertyNames(aErrorClone)
.forEach(name => error[name] = aErrorClone[name]);
return error;
}
}
};