зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1390158 - Notify user of extension controlling New Tab on first access r=aswan,jaws
MozReview-Commit-ID: 1g9d4UTuOgr --HG-- extra : rebase_source : 29e07cff103e7751bf4ca414a88f89136d3ac237
This commit is contained in:
Родитель
04dd99c30f
Коммит
8a1f9ea7ae
|
@ -466,7 +466,8 @@ function openLinkIn(url, where, params) {
|
|||
loadInBackground = !loadInBackground;
|
||||
// fall through
|
||||
case "tab":
|
||||
focusUrlBar = !loadInBackground && w.isBlankPageURL(url);
|
||||
focusUrlBar = !loadInBackground && w.isBlankPageURL(url)
|
||||
&& !aboutNewTabService.willNotifyUser;
|
||||
|
||||
let tabUsedForLoad = w.gBrowser.loadOneTab(url, {
|
||||
referrerURI: aReferrerURI,
|
||||
|
|
|
@ -683,3 +683,28 @@
|
|||
label="&customizeMode.autoHideDownloadsButton.label;" checked="true"
|
||||
oncommand="gCustomizeMode.onDownloadsAutoHideChange(event)"/>
|
||||
</panel>
|
||||
|
||||
<panel id="extension-notification-panel"
|
||||
role="group"
|
||||
type="arrow"
|
||||
hidden="true"
|
||||
flip="slide"
|
||||
position="bottomcenter topright"
|
||||
tabspecific="true">
|
||||
<popupnotification id="extension-new-tab-notification"
|
||||
popupid="extension-new-tab"
|
||||
label="&newTabControlled.header.message;"
|
||||
buttonlabel="&newTabControlled.keepButton.label;"
|
||||
buttonaccesskey="&newTabControlled.keepButton.accesskey;"
|
||||
secondarybuttonlabel="&newTabControlled.restoreButton.label;"
|
||||
secondarybuttonaccesskey="&newTabControlled.restoreButton.accesskey;"
|
||||
closebuttonhidden="true"
|
||||
dropmarkerhidden="true"
|
||||
checkboxhidden="true">
|
||||
<popupnotificationcontent orient="vertical">
|
||||
<description id="extension-new-tab-notification-description">
|
||||
&newTabControlled.message;
|
||||
</description>
|
||||
</popupnotificationcontent>
|
||||
</popupnotification>
|
||||
</panel>
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
/* 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";
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionSettingsStore",
|
||||
"resource://gre/modules/ExtensionSettingsStore.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
|
||||
"resource://gre/modules/AddonManager.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
|
||||
"resource:///modules/CustomizableUI.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
|
||||
"@mozilla.org/browser/aboutnewtab-service;1",
|
||||
|
@ -13,13 +18,102 @@ XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
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.
|
||||
ExtensionSettingsStore.removeSetting(NEW_TAB_CONFIRMED_TYPE, item.id);
|
||||
let addon = await AddonManager.getAddonByID(item.id);
|
||||
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) {
|
||||
aboutNewTabService.newTabURL = url;
|
||||
if (aboutNewTabService.overridden) {
|
||||
addNewTabObserver(extensionId);
|
||||
} else {
|
||||
removeNewTabObserver();
|
||||
}
|
||||
}
|
||||
|
||||
this.urlOverrides = class extends ExtensionAPI {
|
||||
processNewTabSetting(action) {
|
||||
let {extension} = this;
|
||||
let item = ExtensionSettingsStore[action](extension.id, STORE_TYPE, NEW_TAB_SETTING_NAME);
|
||||
if (item) {
|
||||
aboutNewTabService.newTabURL = item.value || item.initialValue;
|
||||
setNewTabURL(item.id, item.value || item.initialValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,6 +127,11 @@ this.urlOverrides = class extends ExtensionAPI {
|
|||
// 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");
|
||||
|
@ -65,7 +164,7 @@ this.urlOverrides = class extends ExtensionAPI {
|
|||
|
||||
// Set the newTabURL to the current value of the setting.
|
||||
if (item) {
|
||||
aboutNewTabService.newTabURL = item.value || item.initialValue;
|
||||
setNewTabURL(extension.id, item.value || item.initialValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,44 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionSettingsStore",
|
||||
"resource://gre/modules/ExtensionSettingsStore.jsm");
|
||||
|
||||
const NEWTAB_URI_1 = "webext-newtab-1.html";
|
||||
|
||||
add_task(async function test_sending_message_from_newtab_page() {
|
||||
function getNotificationSetting(extensionId) {
|
||||
return ExtensionSettingsStore.getSetting("newTabNotification", extensionId);
|
||||
}
|
||||
|
||||
function getNewTabDoorhanger() {
|
||||
return document.getElementById("extension-new-tab-notification");
|
||||
}
|
||||
|
||||
function clickKeepChanges(notification) {
|
||||
let button = document.getAnonymousElementByAttribute(
|
||||
notification, "anonid", "button");
|
||||
button.click();
|
||||
}
|
||||
|
||||
function clickRestoreSettings(notification) {
|
||||
let button = document.getAnonymousElementByAttribute(
|
||||
notification, "anonid", "secondarybutton");
|
||||
button.click();
|
||||
}
|
||||
|
||||
function waitForNewTab() {
|
||||
let eventName = "browser-open-newtab-start";
|
||||
return new Promise(resolve => {
|
||||
function observer() {
|
||||
Services.obs.removeObserver(observer, eventName);
|
||||
resolve();
|
||||
}
|
||||
Services.obs.addObserver(observer, eventName);
|
||||
});
|
||||
}
|
||||
|
||||
add_task(async function test_new_tab_opens() {
|
||||
let panel = getNewTabDoorhanger().closest("panel");
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"chrome_url_overrides": {
|
||||
|
@ -36,28 +71,266 @@ add_task(async function test_sending_message_from_newtab_page() {
|
|||
await extension.startup();
|
||||
|
||||
// Simulate opening the newtab open as a user would.
|
||||
let popupShown = promisePopupShown(panel);
|
||||
BrowserOpenTab();
|
||||
await popupShown;
|
||||
|
||||
let url = await extension.awaitMessage("from-newtab-page");
|
||||
ok(url.endsWith(NEWTAB_URI_1),
|
||||
"Newtab url is overriden by the extension.");
|
||||
"Newtab url is overridden by the extension.");
|
||||
|
||||
// This will show a confirmation doorhanger, make sure we don't leave it open.
|
||||
let popupHidden = promisePopupHidden(panel);
|
||||
panel.hidePopup();
|
||||
await popupHidden;
|
||||
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(async function test_new_tab_ignore_settings() {
|
||||
await ExtensionSettingsStore.initialize();
|
||||
let notification = getNewTabDoorhanger();
|
||||
let panel = notification.closest("panel");
|
||||
let extensionId = "newtabignore@mochi.test";
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
applications: {gecko: {id: extensionId}},
|
||||
browser_action: {default_popup: "ignore.html"},
|
||||
chrome_url_overrides: {newtab: "ignore.html"},
|
||||
},
|
||||
files: {"ignore.html": '<h1 id="extension-new-tab">New Tab!</h1>'},
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
|
||||
ok(panel.getAttribute("panelopen") != "true",
|
||||
"The notification panel is initially closed");
|
||||
|
||||
await extension.startup();
|
||||
|
||||
// Simulate opening the New Tab as a user would.
|
||||
let popupShown = promisePopupShown(panel);
|
||||
BrowserOpenTab();
|
||||
await popupShown;
|
||||
|
||||
// Ensure the doorhanger is shown and the setting isn't set yet.
|
||||
is(panel.getAttribute("panelopen"), "true",
|
||||
"The notification panel is open after opening New Tab");
|
||||
is(gURLBar.focused, false, "The URL bar is not focused with a doorhanger");
|
||||
is(getNotificationSetting(extensionId), null,
|
||||
"The New Tab notification is not set for this extension");
|
||||
is(panel.anchorNode.closest("toolbarbutton").id,
|
||||
"newtabignore_mochi_test-browser-action",
|
||||
"The doorhanger is anchored to the browser action");
|
||||
|
||||
// Manually close the panel, as if the user ignored it.
|
||||
let popupHidden = promisePopupHidden(panel);
|
||||
panel.hidePopup();
|
||||
await popupHidden;
|
||||
|
||||
// Ensure panel is closed and the setting still isn't set.
|
||||
ok(panel.getAttribute("panelopen") != "true",
|
||||
"The notification panel is closed");
|
||||
is(getNotificationSetting(extensionId), null,
|
||||
"The New Tab notification is not set after ignoring the doorhanger");
|
||||
|
||||
// Close the first tab and open another new tab.
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
let newTabOpened = waitForNewTab();
|
||||
BrowserOpenTab();
|
||||
await newTabOpened;
|
||||
|
||||
// Verify the doorhanger is not shown a second time.
|
||||
ok(panel.getAttribute("panelopen") != "true",
|
||||
"The notification panel doesn't open after ignoring the doorhanger");
|
||||
is(gURLBar.focused, true, "The URL bar is focused with no doorhanger");
|
||||
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(async function test_new_tab_keep_settings() {
|
||||
await ExtensionSettingsStore.initialize();
|
||||
let notification = getNewTabDoorhanger();
|
||||
let panel = notification.closest("panel");
|
||||
let extensionId = "newtabkeep@mochi.test";
|
||||
let manifest = {
|
||||
version: "1.0",
|
||||
applications: {gecko: {id: extensionId}},
|
||||
chrome_url_overrides: {newtab: "keep.html"},
|
||||
};
|
||||
let files = {
|
||||
"keep.html": '<script src="newtab.js"></script><h1 id="extension-new-tab">New Tab!</h1>',
|
||||
"newtab.js": () => { window.onload = browser.test.sendMessage("newtab"); },
|
||||
};
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest,
|
||||
files,
|
||||
useAddonManager: "permanent",
|
||||
});
|
||||
|
||||
ok(panel.getAttribute("panelopen") != "true",
|
||||
"The notification panel is initially closed");
|
||||
|
||||
await extension.startup();
|
||||
|
||||
// Simulate opening the New Tab as a user would.
|
||||
let popupShown = promisePopupShown(panel);
|
||||
BrowserOpenTab();
|
||||
await extension.awaitMessage("newtab");
|
||||
await popupShown;
|
||||
|
||||
// Ensure the panel is open and the setting isn't saved yet.
|
||||
is(panel.getAttribute("panelopen"), "true",
|
||||
"The notification panel is open after opening New Tab");
|
||||
is(getNotificationSetting(extensionId), null,
|
||||
"The New Tab notification is not set for this extension");
|
||||
is(panel.anchorNode.closest("toolbarbutton").id, "PanelUI-menu-button",
|
||||
"The doorhanger is anchored to the menu icon");
|
||||
|
||||
// Click the Keep Changes button.
|
||||
let popupHidden = promisePopupHidden(panel);
|
||||
clickKeepChanges(notification);
|
||||
await popupHidden;
|
||||
|
||||
// Ensure panel is closed and setting is updated.
|
||||
ok(panel.getAttribute("panelopen") != "true",
|
||||
"The notification panel is closed after click");
|
||||
is(getNotificationSetting(extensionId).value, true,
|
||||
"The New Tab notification is set after keeping the changes");
|
||||
|
||||
// Close the first tab and open another new tab.
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
BrowserOpenTab();
|
||||
await extension.awaitMessage("newtab");
|
||||
|
||||
// Verify the doorhanger is not shown a second time.
|
||||
ok(panel.getAttribute("panelopen") != "true",
|
||||
"The notification panel is not opened after keeping the changes");
|
||||
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
|
||||
let upgradedExtension = ExtensionTestUtils.loadExtension({
|
||||
manifest: Object.assign({}, manifest, {version: "2.0"}),
|
||||
files,
|
||||
useAddonManager: "permanent",
|
||||
});
|
||||
|
||||
await upgradedExtension.startup();
|
||||
|
||||
BrowserOpenTab();
|
||||
await upgradedExtension.awaitMessage("newtab");
|
||||
|
||||
// Ensure panel is closed and setting is still set.
|
||||
ok(panel.getAttribute("panelopen") != "true",
|
||||
"The notification panel is closed after click");
|
||||
is(getNotificationSetting(extensionId).value, true,
|
||||
"The New Tab notification is set after keeping the changes");
|
||||
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
await extension.unload();
|
||||
await upgradedExtension.unload();
|
||||
});
|
||||
|
||||
add_task(async function test_new_tab_restore_settings() {
|
||||
await ExtensionSettingsStore.initialize();
|
||||
let notification = getNewTabDoorhanger();
|
||||
let panel = notification.closest("panel");
|
||||
let extensionId = "newtabrestore@mochi.test";
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
applications: {gecko: {id: extensionId}},
|
||||
chrome_url_overrides: {newtab: "restore.html"},
|
||||
},
|
||||
files: {"restore.html": '<h1 id="extension-new-tab">New Tab!</h1>'},
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
|
||||
ok(panel.getAttribute("panelopen") != "true",
|
||||
"The notification panel is initially closed");
|
||||
is(getNotificationSetting(extensionId), null,
|
||||
"The New Tab notification is not initially set for this extension");
|
||||
|
||||
await extension.startup();
|
||||
|
||||
// Simulate opening the newtab open as a user would.
|
||||
let popupShown = promisePopupShown(panel);
|
||||
BrowserOpenTab();
|
||||
await popupShown;
|
||||
|
||||
// Verify that the panel is open and add-on is enabled.
|
||||
let addon = await AddonManager.getAddonByID(extensionId);
|
||||
is(addon.userDisabled, false, "The add-on is enabled at first");
|
||||
is(panel.getAttribute("panelopen"), "true",
|
||||
"The notification panel is open after opening New Tab");
|
||||
is(getNotificationSetting(extensionId), null,
|
||||
"The New Tab notification is not set for this extension");
|
||||
|
||||
// Click the Restore Changes button.
|
||||
let addonDisabled = new Promise(resolve => {
|
||||
let listener = {
|
||||
onDisabled(disabledAddon) {
|
||||
if (disabledAddon.id == addon.id) {
|
||||
resolve();
|
||||
AddonManager.removeAddonListener(listener);
|
||||
}
|
||||
},
|
||||
};
|
||||
AddonManager.addAddonListener(listener);
|
||||
});
|
||||
let popupHidden = promisePopupHidden(panel);
|
||||
clickRestoreSettings(notification);
|
||||
await popupHidden;
|
||||
await addonDisabled;
|
||||
|
||||
// Ensure panel is closed, settings haven't changed and add-on is disabled.
|
||||
ok(panel.getAttribute("panelopen") != "true",
|
||||
"The notification panel is closed after click");
|
||||
is(getNotificationSetting(extensionId), null,
|
||||
"The New Tab notification is not set after resorting the settings");
|
||||
is(addon.userDisabled, true, "The extension is now disabled");
|
||||
|
||||
// Reopen a browser tab and verify that there's no doorhanger.
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
let newTabOpened = waitForNewTab();
|
||||
BrowserOpenTab();
|
||||
await newTabOpened;
|
||||
|
||||
ok(panel.getAttribute("panelopen") != "true",
|
||||
"The notification panel is not opened after keeping the changes");
|
||||
|
||||
// FIXME: We need to enable the add-on so it gets cleared from the
|
||||
// ExtensionSettingsStore for now. See bug 1408226.
|
||||
let addonEnabled = new Promise(resolve => {
|
||||
let listener = {
|
||||
onEnabled(enabledAddon) {
|
||||
if (enabledAddon.id == addon.id) {
|
||||
AddonManager.removeAddonListener(listener);
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
};
|
||||
AddonManager.addAddonListener(listener);
|
||||
});
|
||||
addon.userDisabled = false;
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
await addonEnabled;
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
/**
|
||||
* Ensure we don't show the extension URL in the URL bar temporarily in new tabs
|
||||
* while we're switching remoteness (when the URL we're loading and the
|
||||
* default content principal are different).
|
||||
*/
|
||||
add_task(async function dontTemporarilyShowAboutExtensionPath() {
|
||||
await ExtensionSettingsStore.initialize();
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
name: "Test Extension",
|
||||
applications: {
|
||||
gecko: {
|
||||
id: "newtab@mochi.test",
|
||||
id: "newtaburl@mochi.test",
|
||||
},
|
||||
},
|
||||
chrome_url_overrides: {
|
||||
|
|
|
@ -95,6 +95,7 @@ AboutNewTabService.prototype = {
|
|||
_activityStreamPath: "",
|
||||
_activityStreamDebug: false,
|
||||
_overridden: false,
|
||||
willNotifyUser: false,
|
||||
|
||||
classID: Components.ID("{dfcd2adc-7867-4d3a-ba70-17501f208142}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
|
|
|
@ -23,6 +23,11 @@ interface nsIAboutNewTabService : nsISupports
|
|||
*/
|
||||
attribute ACString defaultURL;
|
||||
|
||||
/**
|
||||
* Returns true if opening the New Tab page will notify the user of a change.
|
||||
*/
|
||||
attribute bool willNotifyUser;
|
||||
|
||||
/**
|
||||
* Returns true if the default resource got overridden.
|
||||
*/
|
||||
|
|
|
@ -967,6 +967,13 @@ you can use these alternative items. Otherwise, their values should be empty. -
|
|||
<!ENTITY updateRestart.cancelButton.accesskey "N">
|
||||
<!ENTITY updateRestart.panelUI.label2 "Restart to update &brandShorterName;">
|
||||
|
||||
<!ENTITY newTabControlled.message "An extension has changed the page you see when you open a New Tab. You can restore your settings if you do not want this change.">
|
||||
<!ENTITY newTabControlled.header.message "Your New Tab has changed.">
|
||||
<!ENTITY newTabControlled.keepButton.label "Keep Changes">
|
||||
<!ENTITY newTabControlled.keepButton.accesskey "K">
|
||||
<!ENTITY newTabControlled.restoreButton.label "Restore Settings">
|
||||
<!ENTITY newTabControlled.restoreButton.accesskey "R">
|
||||
|
||||
<!ENTITY pageActionButton.tooltip "Page actions">
|
||||
<!ENTITY pageAction.addToUrlbar.label "Add to Address Bar">
|
||||
<!ENTITY pageAction.removeFromUrlbar.label "Remove from Address Bar">
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
border: none;
|
||||
}
|
||||
|
||||
#PanelUI-menu-button[badge-status="extension-new-tab"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
|
||||
#PanelUI-menu-button[badge-status="download-success"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
|
||||
display: none;
|
||||
}
|
||||
|
@ -326,6 +327,30 @@ panelview:not([mainview]) .toolbarbutton-text,
|
|||
padding: 4px 0;
|
||||
}
|
||||
|
||||
/* START notification popups for extension controlled content */
|
||||
#extension-notification-panel > .panel-arrowcontainer > .panel-arrowcontent {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#extension-new-tab-notification > .popup-notification-body-container > .popup-notification-body {
|
||||
width: 30em;
|
||||
}
|
||||
|
||||
#extension-new-tab-notification > .popup-notification-body-container > .popup-notification-body > hbox > vbox > .popup-notification-description {
|
||||
font-size: 1.3em;
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
#extension-new-tab-notification-description {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#extension-new-tab-notification > .popup-notification-body-container > .popup-notification-body > .popup-notification-warning,
|
||||
#extension-new-tab-notification > .popup-notification-body-container > .popup-notification-icon {
|
||||
display: none;
|
||||
}
|
||||
/* END notification popups for extension controlled content */
|
||||
|
||||
#appMenu-popup > .panel-arrowcontainer > .panel-arrowcontent,
|
||||
panel[photon] > .panel-arrowcontainer > .panel-arrowcontent {
|
||||
padding: 0;
|
||||
|
|
Загрузка…
Ссылка в новой задаче