diff --git a/index.js b/index.js index 4f5f739..bf70a1c 100644 --- a/index.js +++ b/index.js @@ -122,7 +122,7 @@ const ContainerService = { _containerWasEnabled: false, _onBackgroundConnectCallback: null, - init(installation, reason) { + async init(installation, reason) { // If we are just been installed, we must store some information for the // uninstallation. This object contains also a version number, in case we // need to implement a migration in the future. @@ -267,7 +267,8 @@ const ContainerService = { // WebExtension startup - webExtension.startup().then(api => { + try { + const api = await webExtension.startup(); api.browser.runtime.onMessage.addListener((message, sender, sendReply) => { if ("method" in message && methods.indexOf(message.method) !== -1) { sendReply(this[message.method](message)); @@ -275,9 +276,9 @@ const ContainerService = { }); this.registerBackgroundConnection(api); - }).catch(() => { + } catch (e) { throw new Error("WebExtension startup failed. Unable to continue."); - }); + } this._sendEvent = new Metrics({ type: "sdk", @@ -339,13 +340,14 @@ const ContainerService = { } }, - observe(subject, topic) { + async observe(subject, topic) { if (topic === "lightweight-theme-changed") { - this.getTheme().then((theme) => { + try { + const theme = await this.getTheme(); this.triggerBackgroundCallback(theme, topic); - }).catch(() => { + } catch (e) { throw new Error("Unable to get theme"); - }); + } } }, @@ -454,22 +456,31 @@ const ContainerService = { return parseInt(viewFor(tab).getAttribute("usercontextid") || 0, 10); }, - _createTabObject(tab) { + async _createTabObject(tab) { + let url; + try { + url = await getFavicon(tab.url); + } catch (e) { + url = ""; + } return { title: tab.title, url: tab.url, + favicon: url, id: tab.id, active: true, pinned: tabsUtils.isPinned(viewFor(tab)) }; }, - _containerTabIterator(userContextId, cb) { - for (let tab of tabs) { // eslint-disable-line prefer-const + _matchTabsByContainer(userContextId) { + const matchedTabs = []; + for (const tab of tabs) { if (userContextId === this._getUserContextIdFromTab(tab)) { - cb(tab); + matchedTabs.push(tab); } } + return matchedTabs; }, _createIdentityState() { @@ -490,10 +501,7 @@ const ContainerService = { }, _remapTabsFromUserContextId(userContextId) { - this._identitiesState[userContextId].openTabs = 0; - this._containerTabIterator(userContextId, () => { - ++this._identitiesState[userContextId].openTabs; - }); + this._identitiesState[userContextId].openTabs = this._matchTabsByContainer(userContextId).length; }, _remapTab(tab) { @@ -507,30 +515,25 @@ const ContainerService = { return userContextId in this._identitiesState; }, - _closeTabs(tabsToClose) { + async _closeTabs(tabsToClose) { // We create a new tab only if the current operation closes all the // existing ones. - let promise; - if (tabs.length !== tabsToClose.length) { - promise = Promise.resolve(null); - } else { - promise = this.openTab({}); + if (tabs.length === tabsToClose.length) { + await this.openTab({}); } - return promise.then(() => { - for (let tab of tabsToClose) { // eslint-disable-line prefer-const - // after .close() window is null. Let's take it now. - const window = viewFor(tab.window); + for (const tab of tabsToClose) { + // after .close() window is null. Let's take it now. + const window = viewFor(tab.window); - tab.close(); + tab.close(); - // forget about this tab. 0 is the index of the forgotten tab and 0 - // means the last one. - try { - SessionStore.forgetClosedTab(window, 0); - } catch(e) {} // eslint-disable-line no-empty - } - }).catch(() => null); + // forget about this tab. 0 is the index of the forgotten tab and 0 + // means the last one. + try { + SessionStore.forgetClosedTab(window, 0); + } catch (e) {} // eslint-disable-line no-empty + } }, _recentBrowserWindow() { @@ -563,18 +566,18 @@ const ContainerService = { let value = payload[keyName]; if (value === LOOKUP_KEY) { switch (keyName) { - case "clickedContainerTabCount": - value = this._containerTabCount(payload.userContextId); - break; - case "shownContainersCount": - value = containersCounts.shown; - break; - case "hiddenContainersCount": - value = containersCounts.hidden; - break; - case "totalContainersCount": - value = containersCounts.total; - break; + case "clickedContainerTabCount": + value = this._containerTabCount(payload.userContextId); + break; + case "shownContainersCount": + value = containersCounts.shown; + break; + case "hiddenContainersCount": + value = containersCounts.hidden; + break; + case "totalContainersCount": + value = containersCounts.total; + break; } } payload[keyName] = value; @@ -600,17 +603,16 @@ const ContainerService = { // Tabs management - hideTabs(args) { + async hideTabs(args) { if (!("userContextId" in args)) { - return Promise.reject("hideTabs must be called with userContextId argument."); + return new Error("hideTabs must be called with userContextId argument."); } this._remapTabsIfMissing(args.userContextId); if (!this._isKnownContainer(args.userContextId)) { - return Promise.resolve(null); + return null; } - const containersCounts = this._containersCounts(); this.sendTelemetryPayload({ "event": "hide-tabs", "userContextId": args.userContextId, @@ -622,29 +624,25 @@ const ContainerService = { const tabsToClose = []; - this._containerTabIterator(args.userContextId, tab => { - const object = this._createTabObject(tab); + const tabObjects = await Promise.all(this._matchTabsByContainer(args.userContextId).map((tab) => { + tabsToClose.push(tab); + return this._createTabObject(tab); + })); + tabObjects.forEach((object) => { // This tab is going to be closed. Let's mark this tabObject as // non-active. object.active = false; - getFavicon(object.url).then(url => { - object.favicon = url; - }).catch(() => { - object.favicon = ""; - }); - this._identitiesState[args.userContextId].hiddenTabs.push(object); - tabsToClose.push(tab); }); - return this._closeTabs(tabsToClose).then(() => { - return this._syncTabs(); - }); + await this._closeTabs(tabsToClose); + + return this._syncTabs(); }, - showTabs(args) { + async showTabs(args) { if (!("userContextId" in args)) { return Promise.reject("showTabs must be called with userContextId argument."); } @@ -679,9 +677,8 @@ const ContainerService = { this._identitiesState[args.userContextId].hiddenTabs = []; - return Promise.all(promises).then(() => { - return this._syncTabs(); - }); + await Promise.all(promises); + return this._syncTabs(); }, sortTabs() { @@ -711,7 +708,7 @@ const ContainerService = { // Let's collect UCIs/tabs for this window. const map = new Map; - for (let tab of tabs) { // eslint-disable-line prefer-const + for (const tab of tabs) { if (pinnedTabs && !tabsUtils.isPinned(tab)) { // We don't have, or we already handled all the pinned tabs. break; @@ -735,44 +732,29 @@ const ContainerService = { // Let's move tabs. sortMap.forEach(tabs => { - for (let tab of tabs) { // eslint-disable-line prefer-const + for (const tab of tabs) { xulWindow.gBrowser.moveTabTo(tab, pos++); } }); }, - getTabs(args) { + async getTabs(args) { if (!("userContextId" in args)) { - return Promise.reject("getTabs must be called with userContextId argument."); + return new Error("getTabs must be called with userContextId argument."); } this._remapTabsIfMissing(args.userContextId); if (!this._isKnownContainer(args.userContextId)) { - return Promise.resolve([]); + return []; } - return new Promise((resolve, reject) => { - const list = []; - this._containerTabIterator(args.userContextId, tab => { - list.push(this._createTabObject(tab)); - }); - - const promises = []; - - for (let object of list) { // eslint-disable-line prefer-const - promises.push(getFavicon(object.url).then(url => { - object.favicon = url; - }).catch(() => { - object.favicon = ""; - })); - } - - Promise.all(promises).then(() => { - resolve(list.concat(this._identitiesState[args.userContextId].hiddenTabs)); - }).catch((e) => { - reject(e); - }); + const promises = []; + this._matchTabsByContainer(args.userContextId).forEach((tab) => { + promises.push(this._createTabObject(tab)); }); + + const list = await Promise.all(promises); + return list.concat(this._identitiesState[args.userContextId].hiddenTabs); }, showTab(args) { @@ -782,7 +764,7 @@ const ContainerService = { return; } - for (let tab of tabs) { // eslint-disable-line prefer-const + for (const tab of tabs) { if (tab.id === args.tabId) { tab.window.activate(); tab.activate(); @@ -812,11 +794,7 @@ const ContainerService = { "clickedContainerTabCount": this._containerTabCount(args.userContextId), }); - // Let's create a list of the tabs. - const list = []; - this._containerTabIterator(args.userContextId, tab => { - list.push(tab); - }); + const list = this._matchTabsByContainer(args.userContextId); // Nothing to do if (list.length === 0 && @@ -1183,7 +1161,7 @@ ContainerWindow.prototype = { } }, - _configurePlusButtonMenu() { + async _configurePlusButtonMenu() { const mainPopupSetElement = this._window.document.getElementById("mainPopupSet"); // Let's remove all the previous panels. @@ -1210,7 +1188,8 @@ ContainerWindow.prototype = { this._cleanAllTimeouts(); }); - return ContainerService.queryIdentities().then(identities => { + try { + const identities = await ContainerService.queryIdentities(); identities.forEach(identity => { const menuItemElement = this._window.document.createElementNS(XUL_NS, "menuitem"); this._panelElement.appendChild(menuItemElement); @@ -1236,9 +1215,9 @@ ContainerWindow.prototype = { this._panelElement.appendChild(menuItemElement); }); - }).catch(() => { + } catch (e) { this.hidePanel(); - }); + } }, _configureTabStyle() {