forked from mirrors/gecko-dev
This was done using the following script:
37e3803c7a/processors/chromeutils-import.jsm
MozReview-Commit-ID: 1Nc3XDu0wGl
--HG--
extra : source : 12fc4dee861c812fd2bd032c63ef17af61800c70
extra : intermediate-source : 34c999fa006bffe8705cf50c54708aa21a962e62
extra : histedit_source : b2be2c5e5d226e6c347312456a6ae339c1e634b0
204 lines
7.3 KiB
JavaScript
204 lines
7.3 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/. */
|
|
/* import-globals-from ext-browser.js */
|
|
|
|
"use strict";
|
|
|
|
ChromeUtils.defineModuleGetter(this, "ExtensionSettingsStore",
|
|
"resource://gre/modules/ExtensionSettingsStore.jsm");
|
|
ChromeUtils.defineModuleGetter(this, "AddonManager",
|
|
"resource://gre/modules/AddonManager.jsm");
|
|
ChromeUtils.defineModuleGetter(this, "CustomizableUI",
|
|
"resource:///modules/CustomizableUI.jsm");
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
|
|
"@mozilla.org/browser/aboutnewtab-service;1",
|
|
"nsIAboutNewTabService");
|
|
|
|
const STORE_TYPE = "url_overrides";
|
|
const NEW_TAB_SETTING_NAME = "newTabURL";
|
|
const NEW_TAB_CONFIRMED_TYPE = "newTabNotification";
|
|
|
|
function userWasNotified(extensionId) {
|
|
let setting = ExtensionSettingsStore.getSetting(NEW_TAB_CONFIRMED_TYPE, extensionId);
|
|
return setting && setting.value;
|
|
}
|
|
|
|
function replaceUrlInTab(gBrowser, tab, url) {
|
|
let loaded = new Promise(resolve => {
|
|
windowTracker.addListener("progress", {
|
|
onLocationChange(browser, webProgress, request, locationURI, flags) {
|
|
if (webProgress.isTopLevel
|
|
&& browser.ownerGlobal.gBrowser.getTabForBrowser(browser) == tab
|
|
&& locationURI.spec == url) {
|
|
windowTracker.removeListener(this);
|
|
resolve();
|
|
}
|
|
},
|
|
});
|
|
});
|
|
gBrowser.loadURIWithFlags(
|
|
url, {flags: Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY});
|
|
return loaded;
|
|
}
|
|
|
|
async function handleNewTabOpened() {
|
|
// We don't need to open the doorhanger again until the controlling add-on changes.
|
|
// eslint-disable-next-line no-use-before-define
|
|
removeNewTabObserver();
|
|
|
|
let item = ExtensionSettingsStore.getSetting(STORE_TYPE, NEW_TAB_SETTING_NAME);
|
|
|
|
if (!item || !item.id || userWasNotified(item.id)) {
|
|
return;
|
|
}
|
|
|
|
// Find the elements we need.
|
|
let win = windowTracker.getCurrentWindow({});
|
|
let doc = win.document;
|
|
let panel = doc.getElementById("extension-notification-panel");
|
|
|
|
// Setup the command handler.
|
|
let handleCommand = async (event) => {
|
|
if (event.originalTarget.getAttribute("anonid") == "button") {
|
|
// Main action is to keep changes.
|
|
await ExtensionSettingsStore.addSetting(
|
|
item.id, NEW_TAB_CONFIRMED_TYPE, item.id, true, () => false);
|
|
} else {
|
|
// Secondary action is to restore settings. Disabling an add-on should remove
|
|
// the tabs that it has open, but we want to open the new New Tab in this tab.
|
|
// 1. Replace the tab's URL with about:blank, wait for it to change
|
|
// 2. Now that this tab isn't associated with the add-on, disable the add-on
|
|
// 3. Replace the tab's URL with the new New Tab URL
|
|
ExtensionSettingsStore.removeSetting(NEW_TAB_CONFIRMED_TYPE, item.id);
|
|
let addon = await AddonManager.getAddonByID(item.id);
|
|
let gBrowser = win.gBrowser;
|
|
let tab = gBrowser.selectedTab;
|
|
await replaceUrlInTab(gBrowser, tab, "about:blank");
|
|
Services.obs.addObserver({
|
|
async observe() {
|
|
await replaceUrlInTab(gBrowser, tab, aboutNewTabService.newTabURL);
|
|
handleNewTabOpened();
|
|
Services.obs.removeObserver(this, "newtab-url-changed");
|
|
},
|
|
}, "newtab-url-changed");
|
|
|
|
addon.userDisabled = true;
|
|
}
|
|
panel.hidePopup();
|
|
win.gURLBar.focus();
|
|
};
|
|
panel.addEventListener("command", handleCommand);
|
|
panel.addEventListener("popuphidden", () => {
|
|
panel.removeEventListener("command", handleCommand);
|
|
}, {once: true});
|
|
|
|
// Look for a browserAction on the toolbar.
|
|
let action = CustomizableUI.getWidget(
|
|
`${global.makeWidgetId(item.id)}-browser-action`);
|
|
if (action) {
|
|
action = action.areaType == "toolbar" && action.forWindow(win).node;
|
|
}
|
|
|
|
// Anchor to a toolbar browserAction if found, otherwise use the menu button.
|
|
let anchor = doc.getAnonymousElementByAttribute(
|
|
action || doc.getElementById("PanelUI-menu-button"),
|
|
"class", "toolbarbutton-icon");
|
|
panel.hidden = false;
|
|
panel.openPopup(anchor);
|
|
}
|
|
|
|
let newTabOpenedListener = {
|
|
observe(subject, topic, data) {
|
|
// Do this work in an idle callback to avoid interfering with new tab performance tracking.
|
|
windowTracker
|
|
.getCurrentWindow({})
|
|
.requestIdleCallback(handleNewTabOpened);
|
|
},
|
|
};
|
|
|
|
function removeNewTabObserver() {
|
|
if (aboutNewTabService.willNotifyUser) {
|
|
Services.obs.removeObserver(newTabOpenedListener, "browser-open-newtab-start");
|
|
aboutNewTabService.willNotifyUser = false;
|
|
}
|
|
}
|
|
|
|
function addNewTabObserver(extensionId) {
|
|
if (!aboutNewTabService.willNotifyUser && extensionId && !userWasNotified(extensionId)) {
|
|
Services.obs.addObserver(newTabOpenedListener, "browser-open-newtab-start");
|
|
aboutNewTabService.willNotifyUser = true;
|
|
}
|
|
}
|
|
|
|
function setNewTabURL(extensionId, url) {
|
|
if (extensionId) {
|
|
addNewTabObserver(extensionId);
|
|
} else {
|
|
removeNewTabObserver();
|
|
}
|
|
aboutNewTabService.newTabURL = url;
|
|
}
|
|
|
|
this.urlOverrides = class extends ExtensionAPI {
|
|
processNewTabSetting(action) {
|
|
let {extension} = this;
|
|
let item = ExtensionSettingsStore[action](extension.id, STORE_TYPE, NEW_TAB_SETTING_NAME);
|
|
if (item) {
|
|
setNewTabURL(item.id, item.value || item.initialValue);
|
|
}
|
|
}
|
|
|
|
async onManifestEntry(entryName) {
|
|
let {extension} = this;
|
|
let {manifest} = extension;
|
|
|
|
await ExtensionSettingsStore.initialize();
|
|
|
|
if (manifest.chrome_url_overrides.newtab) {
|
|
// Set up the shutdown code for the setting.
|
|
extension.callOnClose({
|
|
close: () => {
|
|
if (extension.shutdownReason == "ADDON_DISABLE"
|
|
|| extension.shutdownReason == "ADDON_UNINSTALL") {
|
|
ExtensionSettingsStore.removeSetting(
|
|
extension.id, NEW_TAB_CONFIRMED_TYPE, extension.id);
|
|
}
|
|
switch (extension.shutdownReason) {
|
|
case "ADDON_DISABLE":
|
|
this.processNewTabSetting("disable");
|
|
break;
|
|
|
|
// We can remove the setting on upgrade or downgrade because it will be
|
|
// added back in when the manifest is re-read. This will cover the case
|
|
// where a new version of an add-on removes the manifest key.
|
|
case "ADDON_DOWNGRADE":
|
|
case "ADDON_UPGRADE":
|
|
case "ADDON_UNINSTALL":
|
|
this.processNewTabSetting("removeSetting");
|
|
break;
|
|
}
|
|
},
|
|
});
|
|
|
|
let url = extension.baseURI.resolve(manifest.chrome_url_overrides.newtab);
|
|
|
|
let item = await ExtensionSettingsStore.addSetting(
|
|
extension.id, STORE_TYPE, NEW_TAB_SETTING_NAME, url,
|
|
() => aboutNewTabService.newTabURL);
|
|
|
|
// If the extension was just re-enabled, change the setting to enabled.
|
|
// This is required because addSetting above is used for both add and update.
|
|
if (["ADDON_ENABLE", "ADDON_UPGRADE", "ADDON_DOWNGRADE"]
|
|
.includes(extension.startupReason)) {
|
|
item = ExtensionSettingsStore.enable(extension.id, STORE_TYPE, NEW_TAB_SETTING_NAME);
|
|
}
|
|
|
|
// Set the newTabURL to the current value of the setting.
|
|
if (item) {
|
|
setNewTabURL(item.id, item.value || item.initialValue);
|
|
}
|
|
}
|
|
}
|
|
};
|