зеркало из https://github.com/mozilla/gecko-dev.git
Bug 552965 and bug 553455: Display notifications for add-on download failures and prompt the user to restart after installation. r=gavin
This commit is contained in:
Родитель
4df955ab2a
Коммит
2f164a09a3
|
@ -323,6 +323,7 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
|
|||
display: none;
|
||||
}
|
||||
|
||||
#notification-popup-box[anchorid="geo-notification-icon"] > #geo-notification-icon {
|
||||
#notification-popup-box[anchorid="geo-notification-icon"] > #geo-notification-icon,
|
||||
#notification-popup-box[anchorid="addons-notification-icon"] > #addons-notification-icon {
|
||||
display: -moz-box;
|
||||
}
|
||||
|
|
|
@ -130,6 +130,15 @@ __defineGetter__("gPrefService", function() {
|
|||
return this.gPrefService = Services.prefs;
|
||||
});
|
||||
|
||||
__defineGetter__("AddonManager", function() {
|
||||
Cu.import("resource://gre/modules/AddonManager.jsm");
|
||||
return this.AddonManager;
|
||||
});
|
||||
__defineSetter__("AddonManager", function (val) {
|
||||
delete this.AddonManager;
|
||||
return this.AddonManager = val;
|
||||
});
|
||||
|
||||
__defineGetter__("PluralForm", function() {
|
||||
Cu.import("resource://gre/modules/PluralForm.jsm");
|
||||
return this.PluralForm;
|
||||
|
@ -623,26 +632,35 @@ const gXPInstallObserver = {
|
|||
observe: function (aSubject, aTopic, aData)
|
||||
{
|
||||
var brandBundle = document.getElementById("bundle_brand");
|
||||
switch (aTopic) {
|
||||
case "addon-install-blocked":
|
||||
var installInfo = aSubject.QueryInterface(Components.interfaces.amIWebInstallInfo);
|
||||
var win = installInfo.originatingWindow;
|
||||
var shell = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIWebNavigation)
|
||||
.QueryInterface(Components.interfaces.nsIDocShell);
|
||||
var browser = this._getBrowser(shell);
|
||||
if (browser) {
|
||||
var host = installInfo.originatingURI.host;
|
||||
if (!browser)
|
||||
return;
|
||||
const anchorID = "addons-notification-icon";
|
||||
var messageString, action;
|
||||
var brandShortName = brandBundle.getString("brandShortName");
|
||||
var notificationName, messageString, buttons;
|
||||
var host = installInfo.originatingURI ? installInfo.originatingURI.host : browser.currentURI.host;
|
||||
|
||||
var notificationID = aTopic;
|
||||
|
||||
switch (aTopic) {
|
||||
case "addon-install-blocked":
|
||||
var enabled = true;
|
||||
try {
|
||||
enabled = gPrefService.getBoolPref("xpinstall.enabled");
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
|
||||
if (!enabled) {
|
||||
notificationName = "xpinstall-disabled"
|
||||
notificationID = "xpinstall-disabled"
|
||||
if (PopupNotifications.getNotification(notificationID, browser))
|
||||
return;
|
||||
|
||||
if (gPrefService.prefIsLocked("xpinstall.enabled")) {
|
||||
messageString = gNavigatorBundle.getString("xpinstallDisabledMessageLocked");
|
||||
buttons = [];
|
||||
|
@ -651,41 +669,105 @@ const gXPInstallObserver = {
|
|||
messageString = gNavigatorBundle.getFormattedString("xpinstallDisabledMessage",
|
||||
[brandShortName, host]);
|
||||
|
||||
buttons = [{
|
||||
action = {
|
||||
label: gNavigatorBundle.getString("xpinstallDisabledButton"),
|
||||
accessKey: gNavigatorBundle.getString("xpinstallDisabledButton.accesskey"),
|
||||
popup: null,
|
||||
callback: function editPrefs() {
|
||||
gPrefService.setBoolPref("xpinstall.enabled", true);
|
||||
return false;
|
||||
}
|
||||
}];
|
||||
};
|
||||
}
|
||||
}
|
||||
else {
|
||||
notificationName = "xpinstall"
|
||||
if (PopupNotifications.getNotification(notificationID, browser))
|
||||
return;
|
||||
|
||||
messageString = gNavigatorBundle.getFormattedString("xpinstallPromptWarning",
|
||||
[brandShortName, host]);
|
||||
|
||||
buttons = [{
|
||||
action = {
|
||||
label: gNavigatorBundle.getString("xpinstallPromptAllowButton"),
|
||||
accessKey: gNavigatorBundle.getString("xpinstallPromptAllowButton.accesskey"),
|
||||
popup: null,
|
||||
callback: function() {
|
||||
installInfo.install();
|
||||
return false;
|
||||
}
|
||||
}];
|
||||
};
|
||||
}
|
||||
|
||||
var notificationBox = gBrowser.getNotificationBox(browser);
|
||||
if (!notificationBox.getNotificationWithValue(notificationName)) {
|
||||
const priority = notificationBox.PRIORITY_WARNING_MEDIUM;
|
||||
const iconURL = "chrome://mozapps/skin/update/update.png";
|
||||
notificationBox.appendNotification(messageString, notificationName,
|
||||
iconURL, priority, buttons);
|
||||
PopupNotifications.show(browser, notificationID, messageString, anchorID,
|
||||
action);
|
||||
break;
|
||||
case "addon-install-failed":
|
||||
// TODO This isn't terribly ideal for the multiple failure case
|
||||
installInfo.installs.forEach(function(aInstall) {
|
||||
var error = "addonError";
|
||||
if (aInstall.error != 0)
|
||||
error += aInstall.error;
|
||||
else if (aInstall.addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED)
|
||||
error += "Blocklisted";
|
||||
else
|
||||
error += "Incompatible";
|
||||
|
||||
messageString = gNavigatorBundle.getString(error);
|
||||
messageString = messageString.replace("#1", aInstall.name);
|
||||
messageString = messageString.replace("#2", host);
|
||||
messageString = messageString.replace("#3", brandShortName);
|
||||
messageString = messageString.replace("#4", Services.appinfo.version);
|
||||
|
||||
PopupNotifications.show(browser, notificationID, messageString, anchorID,
|
||||
action);
|
||||
});
|
||||
break;
|
||||
case "addon-install-complete":
|
||||
var notification = PopupNotifications.getNotification(notificationID, browser);
|
||||
if (notification)
|
||||
PopupNotifications.remove(notification);
|
||||
|
||||
var needsRestart = installInfo.installs.some(function(i) {
|
||||
return (i.addon.pendingOperations & AddonManager.PENDING_INSTALL) != 0;
|
||||
});
|
||||
|
||||
if (needsRestart) {
|
||||
messageString = gNavigatorBundle.getString("addonsInstalledNeedsRestart");
|
||||
action = {
|
||||
label: gNavigatorBundle.getString("addonInstallRestartButton"),
|
||||
accessKey: gNavigatorBundle.getString("addonInstallRestartButton.accesskey"),
|
||||
callback: function() {
|
||||
Application.restart();
|
||||
}
|
||||
};
|
||||
}
|
||||
else {
|
||||
messageString = gNavigatorBundle.getString("addonsInstalled");
|
||||
action = {
|
||||
label: gNavigatorBundle.getString("addonInstallManage"),
|
||||
accessKey: gNavigatorBundle.getString("addonInstallManage.accesskey"),
|
||||
callback: function() {
|
||||
// Calculate the add-on type that is most popular in the list of
|
||||
// installs
|
||||
var types = {};
|
||||
var bestType = null;
|
||||
installInfo.installs.forEach(function(aInstall) {
|
||||
if (aInstall.type in types)
|
||||
types[aInstall.type]++;
|
||||
else
|
||||
types[aInstall.type] = 1;
|
||||
if (!bestType || types[aInstall.type] > types[bestType])
|
||||
bestType = aInstall.type;
|
||||
});
|
||||
|
||||
BrowserOpenAddonsMgr("addons://list/" + bestType);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
messageString = PluralForm.get(installInfo.installs.length, messageString);
|
||||
messageString = messageString.replace("#1", installInfo.installs[0].name);
|
||||
messageString = messageString.replace("#2", installInfo.installs.length);
|
||||
messageString = messageString.replace("#3", brandShortName);
|
||||
|
||||
PopupNotifications.show(browser, notificationID, messageString, anchorID,
|
||||
action);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1218,6 +1300,8 @@ function prepareForStartup() {
|
|||
function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
||||
Services.obs.addObserver(gSessionHistoryObserver, "browser:purge-session-history", false);
|
||||
Services.obs.addObserver(gXPInstallObserver, "addon-install-blocked", false);
|
||||
Services.obs.addObserver(gXPInstallObserver, "addon-install-failed", false);
|
||||
Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false);
|
||||
|
||||
BrowserOffline.init();
|
||||
OfflineApps.init();
|
||||
|
@ -1438,6 +1522,8 @@ function BrowserShutdown()
|
|||
|
||||
Services.obs.removeObserver(gSessionHistoryObserver, "browser:purge-session-history");
|
||||
Services.obs.removeObserver(gXPInstallObserver, "addon-install-blocked");
|
||||
Services.obs.removeObserver(gXPInstallObserver, "addon-install-failed");
|
||||
Services.obs.removeObserver(gXPInstallObserver, "addon-install-complete");
|
||||
Services.obs.removeObserver(gPluginHandler.pluginCrashed, "plugin-crashed");
|
||||
|
||||
try {
|
||||
|
|
|
@ -608,6 +608,7 @@
|
|||
onblur="setTimeout(function() document.getElementById('identity-box').style.MozUserFocus = '', 0);">
|
||||
<box id="notification-popup-box" hidden="true" align="center">
|
||||
<image id="geo-notification-icon" class="notification-anchor-icon"/>
|
||||
<image id="addons-notification-icon" class="notification-anchor-icon"/>
|
||||
</box>
|
||||
<!-- Use onclick instead of normal popup= syntax since the popup
|
||||
code fires onmousedown, and hence eats our favicon drag events.
|
||||
|
|
|
@ -129,6 +129,7 @@ _BROWSER_FILES = \
|
|||
browser_bug521216.js \
|
||||
browser_bug537474.js \
|
||||
browser_bug550565.js \
|
||||
browser_bug553455.js \
|
||||
browser_bug555224.js \
|
||||
browser_bug555767.js \
|
||||
browser_bug556061.js \
|
||||
|
|
|
@ -0,0 +1,270 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
const TESTROOT = "http://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/";
|
||||
const XPINSTALL_URL = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul";
|
||||
|
||||
function wait_for_notification(aCallback) {
|
||||
PopupNotifications.panel.addEventListener("popupshown", function() {
|
||||
PopupNotifications.panel.removeEventListener("popupshown", arguments.callee, false);
|
||||
aCallback(PopupNotifications.panel);
|
||||
}, false);
|
||||
}
|
||||
|
||||
function wait_for_install_dialog(aCallback) {
|
||||
Services.wm.addListener({
|
||||
onOpenWindow: function(aXULWindow) {
|
||||
Services.wm.removeListener(this);
|
||||
|
||||
var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowInternal);
|
||||
domwindow.addEventListener("load", function() {
|
||||
domwindow.removeEventListener("load", arguments.callee, false);
|
||||
|
||||
is(domwindow.document.location.href, XPINSTALL_URL, "Should have seen the right window open");
|
||||
|
||||
// Allow other window load listeners to execute before passing to callback
|
||||
executeSoon(function() {
|
||||
// Override the countdown timer on the accept button
|
||||
var button = domwindow.document.documentElement.getButton("accept");
|
||||
button.disabled = false;
|
||||
|
||||
aCallback(domwindow);
|
||||
});
|
||||
}, false);
|
||||
},
|
||||
|
||||
onCloseWindow: function(aXULWindow) {
|
||||
},
|
||||
|
||||
onWindowTitleChange: function(aXULWindow, aNewTitle) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var TESTS = [
|
||||
function test_blocked_install() {
|
||||
var triggers = encodeURIComponent(JSON.stringify({
|
||||
"XPI": "unsigned.xpi"
|
||||
}));
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
|
||||
|
||||
// Wait for the blocked notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-blocked", "Should have seen the install blocked");
|
||||
is(notification.button.label, "Allow", "Should have seen the right button");
|
||||
|
||||
// Click on Allow
|
||||
EventUtils.synthesizeMouse(notification.button, 20, 10, {});
|
||||
|
||||
// Wait for the install confirmation dialog
|
||||
wait_for_install_dialog(function(aWindow) {
|
||||
aWindow.document.documentElement.acceptDialog();
|
||||
|
||||
// Wait for the complete notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-complete", "Should have seen the install complete");
|
||||
is(notification.button.label, "Restart Now", "Should have seen the right button");
|
||||
|
||||
AddonManager.getAllInstalls(function(aInstalls) {
|
||||
is(aInstalls.length, 1, "Should be one pending install");
|
||||
aInstalls[0].cancel();
|
||||
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
runNextTest();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
function test_whitelisted_install() {
|
||||
var pm = Services.perms;
|
||||
pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
|
||||
|
||||
var triggers = encodeURIComponent(JSON.stringify({
|
||||
"XPI": "unsigned.xpi"
|
||||
}));
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
|
||||
|
||||
// Wait for the install confirmation dialog
|
||||
wait_for_install_dialog(function(aWindow) {
|
||||
aWindow.document.documentElement.acceptDialog();
|
||||
|
||||
// Wait for the complete notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-complete", "Should have seen the install complete");
|
||||
is(notification.button.label, "Restart Now", "Should have seen the right button");
|
||||
|
||||
AddonManager.getAllInstalls(function(aInstalls) {
|
||||
is(aInstalls.length, 1, "Should be one pending install");
|
||||
aInstalls[0].cancel();
|
||||
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
Services.perms.remove("example.com", "install");
|
||||
runNextTest();
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
function test_failed_download() {
|
||||
var pm = Services.perms;
|
||||
pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
|
||||
|
||||
var triggers = encodeURIComponent(JSON.stringify({
|
||||
"XPI": "missing.xpi"
|
||||
}));
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
|
||||
|
||||
// Wait for the failed notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-failed", "Should have seen the install fail");
|
||||
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
Services.perms.remove("example.com", "install");
|
||||
runNextTest();
|
||||
});
|
||||
},
|
||||
|
||||
function test_corrupt_file() {
|
||||
var pm = Services.perms;
|
||||
pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
|
||||
|
||||
var triggers = encodeURIComponent(JSON.stringify({
|
||||
"XPI": "corrupt.xpi"
|
||||
}));
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
|
||||
|
||||
// Wait for the failed notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-failed", "Should have seen the install fail");
|
||||
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
Services.perms.remove("example.com", "install");
|
||||
runNextTest();
|
||||
});
|
||||
},
|
||||
|
||||
function test_incompatible() {
|
||||
var pm = Services.perms;
|
||||
pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
|
||||
|
||||
var triggers = encodeURIComponent(JSON.stringify({
|
||||
"XPI": "incompatible.xpi"
|
||||
}));
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
|
||||
|
||||
// Wait for the failed notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-failed", "Should have seen the install fail");
|
||||
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
Services.perms.remove("example.com", "install");
|
||||
runNextTest();
|
||||
});
|
||||
},
|
||||
|
||||
function test_restartless() {
|
||||
var pm = Services.perms;
|
||||
pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
|
||||
|
||||
var triggers = encodeURIComponent(JSON.stringify({
|
||||
"XPI": "restartless.xpi"
|
||||
}));
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
|
||||
|
||||
// Wait for the install confirmation dialog
|
||||
wait_for_install_dialog(function(aWindow) {
|
||||
aWindow.document.documentElement.acceptDialog();
|
||||
|
||||
// Wait for the complete notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-complete", "Should have seen the install complete");
|
||||
is(notification.button.label, "Open Add-ons Manager", "Should have seen the right button");
|
||||
|
||||
AddonManager.getAllInstalls(function(aInstalls) {
|
||||
is(aInstalls.length, 0, "Should be no pending installs");
|
||||
|
||||
AddonManager.getAddonByID("restartless-xpi@tests.mozilla.org", function(aAddon) {
|
||||
aAddon.uninstall();
|
||||
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
Services.perms.remove("example.com", "install");
|
||||
runNextTest();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
function test_multiple() {
|
||||
var pm = Services.perms;
|
||||
pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
|
||||
|
||||
var triggers = encodeURIComponent(JSON.stringify({
|
||||
"Unsigned XPI": "unsigned.xpi",
|
||||
"Restartless XPI": "restartless.xpi"
|
||||
}));
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
|
||||
|
||||
// Wait for the install confirmation dialog
|
||||
wait_for_install_dialog(function(aWindow) {
|
||||
aWindow.document.documentElement.acceptDialog();
|
||||
|
||||
// Wait for the complete notification
|
||||
wait_for_notification(function(aPanel) {
|
||||
let notification = aPanel.childNodes[0];
|
||||
is(notification.id, "addon-install-complete", "Should have seen the install complete");
|
||||
is(notification.button.label, "Restart Now", "Should have seen the right button");
|
||||
|
||||
AddonManager.getAllInstalls(function(aInstalls) {
|
||||
is(aInstalls.length, 1, "Should be one pending install");
|
||||
aInstalls[0].cancel();
|
||||
|
||||
AddonManager.getAddonByID("restartless-xpi@tests.mozilla.org", function(aAddon) {
|
||||
aAddon.uninstall();
|
||||
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
Services.perms.remove("example.com", "install");
|
||||
runNextTest();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
];
|
||||
|
||||
function runNextTest() {
|
||||
AddonManager.getAllInstalls(function(aInstalls) {
|
||||
is(aInstalls.length, 0, "Should be no active installs");
|
||||
|
||||
if (TESTS.length == 0) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
TESTS.shift()();
|
||||
});
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
runNextTest();
|
||||
}
|
|
@ -35,6 +35,27 @@ xpinstallDisabledMessage=Software installation is currently disabled. Click Enab
|
|||
xpinstallDisabledButton=Enable
|
||||
xpinstallDisabledButton.accesskey=n
|
||||
|
||||
# LOCALIZATION NOTE (addonsInstalled, addonsInstalledNeedsRestart):
|
||||
# Semi-colon list of plural forms. See:
|
||||
# http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
# #1 first add-on's name, #2 number of add-ons, #3 application name
|
||||
addonsInstalled=#1 has been installed successfully.;#2 add-ons have been installed successfully.
|
||||
addonsInstalledNeedsRestart=#1 will be installed after you restart #3.;#2 add-ons will be installed after you restart #3.
|
||||
addonInstallRestartButton=Restart Now
|
||||
addonInstallRestartButton.accesskey=R
|
||||
addonInstallManage=Open Add-ons Manager
|
||||
addonInstallManage.accesskey=O
|
||||
|
||||
# LOCALIZATION NOTE (addonError-1, addonError-2, addonError-3, addonError-4, addonErrorIncompatible, addonErrorBlocklisted):
|
||||
# #1 is the add-on name, #2 is the host name, #3 is the application name
|
||||
# #4 is the application version
|
||||
addonError-1=The add-on could not be downloaded because of a connection failure on #2.
|
||||
addonError-2=The add-on from #2 could not be installed because it does not match the add-on #3 expected.
|
||||
addonError-3=The add-on downloaded from #2 could not be installed because it appears to be corrupt.
|
||||
addonError-4=#1 could not be installed because Firefox cannot modify the needed file.
|
||||
addonErrorIncompatible=#1 could not be installed because it is not compatible with #3 #4.
|
||||
addonErrorBlocklisted=#1 could not be installed because it has a high risk of causing stability or security problems.
|
||||
|
||||
# LOCALIZATION NOTE (lwthemeInstallRequest.message): %S will be replaced with
|
||||
# the host name of the site.
|
||||
lwthemeInstallRequest.message=This site (%S) attempted to install a theme.
|
||||
|
|
|
@ -988,17 +988,33 @@ toolbar[iconsize="small"] #fullscreen-button {
|
|||
list-style-image: url(chrome://browser/skin/Geo.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="xpinstall-disabled"],
|
||||
.popup-notification-icon[popupid="addon-install-blocked"],
|
||||
.popup-notification-icon[popupid="addon-install-failed"],
|
||||
.popup-notification-icon[popupid="addon-install-complete"] {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
/* Notification icon box */
|
||||
#notification-popup-box {
|
||||
margin: 0 3px;
|
||||
}
|
||||
|
||||
#geo-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Geo.png);
|
||||
.notification-anchor-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
#geo-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Geo.png);
|
||||
}
|
||||
|
||||
#addons-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
|
||||
}
|
||||
|
||||
/* Feed icon */
|
||||
#feed-button,
|
||||
#feed-button > .button-box,
|
||||
|
|
|
@ -1822,13 +1822,20 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
|||
margin: 0 3px;
|
||||
}
|
||||
|
||||
#geo-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Geo.png);
|
||||
.notification-anchor-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
#geo-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Geo.png);
|
||||
}
|
||||
|
||||
#addons-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
|
||||
}
|
||||
|
||||
.popup-notification-description {
|
||||
color: #fff;
|
||||
}
|
||||
|
@ -1843,6 +1850,15 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
|||
list-style-image: url(chrome://browser/skin/Geo.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="xpinstall-disabled"],
|
||||
.popup-notification-icon[popupid="addon-install-blocked"],
|
||||
.popup-notification-icon[popupid="addon-install-failed"],
|
||||
.popup-notification-icon[popupid="addon-install-complete"] {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
#identity-popup-container,
|
||||
#identity-popup-notification-container {
|
||||
margin: 4px 3px 2px -30px;
|
||||
|
|
|
@ -1606,17 +1606,33 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
|||
list-style-image: url(chrome://browser/skin/Geo.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="xpinstall-disabled"],
|
||||
.popup-notification-icon[popupid="addon-install-blocked"],
|
||||
.popup-notification-icon[popupid="addon-install-failed"],
|
||||
.popup-notification-icon[popupid="addon-install-complete"] {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
/* Notification icon box */
|
||||
#notification-popup-box {
|
||||
margin: 0 3px;
|
||||
}
|
||||
|
||||
#geo-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Geo.png);
|
||||
.notification-anchor-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
#geo-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Geo.png);
|
||||
}
|
||||
|
||||
#addons-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
|
||||
}
|
||||
|
||||
#identity-popup-container {
|
||||
min-width: 280px;
|
||||
padding: 9px;
|
||||
|
|
Загрузка…
Ссылка в новой задаче