1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 ChromeUtils.defineESModuleGetters(lazy, {
8 AboutNewTab: "resource:///modules/AboutNewTab.sys.mjs",
9 ASRouter: "resource:///modules/asrouter/ASRouter.sys.mjs",
12 // A mapping of loaded new tab pages, where the mapping is:
13 // browser -> { actor, browser, browsingContext, portID, url, loaded }
14 let gLoadedTabs = new Map();
16 export class AboutNewTabParent extends JSWindowActorParent {
17 static get loadedTabs() {
22 let browser = this.browsingContext.top.embedderElement;
23 return browser ? gLoadedTabs.get(browser) : null;
27 if (event.type == "SwapDocShells") {
28 let oldBrowser = this.browsingContext.top.embedderElement;
29 let newBrowser = event.detail;
31 let tabDetails = gLoadedTabs.get(oldBrowser);
33 tabDetails.browser = newBrowser;
34 gLoadedTabs.delete(oldBrowser);
35 gLoadedTabs.set(newBrowser, tabDetails);
37 oldBrowser.removeEventListener("SwapDocShells", this);
38 newBrowser.addEventListener("SwapDocShells", this);
43 async receiveMessage(message) {
44 switch (message.name) {
45 case "AboutNewTabVisible":
46 await lazy.ASRouter.waitForInitialized;
47 lazy.ASRouter.sendTriggerMessage({
48 browser: this.browsingContext.top.embedderElement,
49 // triggerId and triggerContext
50 id: "defaultBrowserCheck",
51 context: { source: "newtab" },
56 let browsingContext = this.browsingContext;
57 let browser = browsingContext.top.embedderElement;
66 portID: message.data.portID,
67 url: message.data.url,
69 gLoadedTabs.set(browser, tabDetails);
71 browser.addEventListener("SwapDocShells", this);
72 browser.addEventListener("EndSwapDocShells", this);
74 this.notifyActivityStreamChannel("onNewTabInit", message, tabDetails);
79 this.notifyActivityStreamChannel("onNewTabLoad", message);
83 let tabDetails = this.getTabDetails();
85 // When closing a tab, the embedderElement can already be disconnected, so
86 // as a backup, look up the tab details by browsing context.
87 tabDetails = this.getByBrowsingContext(this.browsingContext);
94 tabDetails.browser.removeEventListener("EndSwapDocShells", this);
96 gLoadedTabs.delete(tabDetails.browser);
98 this.notifyActivityStreamChannel("onNewTabUnload", message, tabDetails);
102 case "ActivityStream:ContentToMain":
103 this.notifyActivityStreamChannel("onMessage", message);
108 notifyActivityStreamChannel(name, message, tabDetails) {
110 tabDetails = this.getTabDetails();
116 let channel = this.getChannel();
118 // We're not yet ready to deal with these messages. We'll queue
119 // them for now, and then dispatch them once the channel has finished
121 AboutNewTabParent.#queuedMessages.push({
130 let messageToSend = {
132 data: message.data || {},
135 channel[name](messageToSend, tabDetails);
138 getByBrowsingContext(expectedBrowsingContext) {
139 for (let tabDetails of AboutNewTabParent.loadedTabs.values()) {
140 if (tabDetails.browsingContext === expectedBrowsingContext) {
149 return lazy.AboutNewTab.activityStream?.store?.getMessageChannel();
152 // Queued messages sent from the content process. These are only queued
153 // if an AboutNewTabParent receives them before the
154 // ActivityStreamMessageChannel exists.
155 static #queuedMessages = [];
158 * If there were any messages sent from content before the
159 * ActivityStreamMessageChannel was set up, dispatch them now.
161 static flushQueuedMessagesFromContent() {
162 for (let messageData of AboutNewTabParent.#queuedMessages) {
163 let { actor, name, message, tabDetails } = messageData;
164 actor.notifyActivityStreamChannel(name, message, tabDetails);
166 AboutNewTabParent.#queuedMessages = [];