Bug 880735 part D - New doorhanger frontend code. Removes all logic which shows the plugin doorhanger automatically, including on scripting. Always show the doorhanger when there is a plugin present on the page, even if that plugin is currently enabled. Make the "always" choices clear to the user. r=jaws

This commit is contained in:
Benjamin Smedberg 2013-06-24 08:51:07 -04:00
parent fd595f38a6
commit b02c781c12
11 changed files with 704 additions and 448 deletions

View File

@ -4,6 +4,8 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
const kPrefNotifyMissingFlash = "plugins.notifyMissingFlash";
const kPrefSessionPersistMinutes = "plugin.sessionPermissionNow.intervalInMinutes";
const kPrefPersistentDays = "plugin.persistentPermissionAlways.intervalInDays";
var gPluginHandler = {
PLUGIN_SCRIPTED_STATE_NONE: 0,
@ -24,48 +26,49 @@ var gPluginHandler = {
#endif
_getPluginInfo: function (pluginElement) {
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
pluginElement.QueryInterface(Ci.nsIObjectLoadingContent);
let tagMimetype;
let pluginsPage;
let pluginName = gNavigatorBundle.getString("pluginInfo.unknownPlugin");
let pluginTag = null;
let permissionString = null;
let fallbackType = null;
let blocklistState = null;
if (pluginElement instanceof HTMLAppletElement) {
tagMimetype = "application/x-java-vm";
} else {
if (pluginElement instanceof HTMLObjectElement) {
pluginsPage = pluginElement.getAttribute("codebase");
} else {
pluginsPage = pluginElement.getAttribute("pluginspage");
}
// only attempt if a pluginsPage is defined.
if (pluginsPage) {
let doc = pluginElement.ownerDocument;
let docShell = findChildShell(doc, gBrowser.docShell, null);
try {
pluginsPage = makeURI(pluginsPage, doc.characterSet, docShell.currentURI).spec;
} catch (ex) {
pluginsPage = "";
}
}
tagMimetype = pluginElement.QueryInterface(Ci.nsIObjectLoadingContent)
.actualType;
tagMimetype = pluginElement.actualType;
if (tagMimetype == "") {
tagMimetype = pluginElement.type;
}
}
if (tagMimetype) {
let navMimeType = navigator.mimeTypes.namedItem(tagMimetype);
if (navMimeType && navMimeType.enabledPlugin) {
pluginName = navMimeType.enabledPlugin.name;
pluginName = gPluginHandler.makeNicePluginName(pluginName);
if (gPluginHandler.isKnownPlugin(pluginElement)) {
pluginTag = pluginHost.getPluginTagForType(pluginElement.actualType);
pluginName = gPluginHandler.makeNicePluginName(pluginTag.name);
permissionString = pluginHost.getPermissionStringForType(pluginElement.actualType);
fallbackType = pluginElement.defaultFallbackType;
blocklistState = pluginHost.getBlocklistStateForType(pluginElement.actualType);
// Make state-softblocked == state-notblocked for our purposes,
// they have the same UI. STATE_OUTDATED should not exist for plugin
// items, but let's alias it anyway, just in case.
if (blocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED ||
blocklistState == Ci.nsIBlocklistService.STATE_OUTDATED) {
blocklistState = Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
}
}
return { mimetype: tagMimetype,
pluginsPage: pluginsPage,
pluginName: pluginName };
pluginName: pluginName,
pluginTag: pluginTag,
permissionString: permissionString,
fallbackType: fallbackType,
blocklistState: blocklistState,
};
},
// Map the plugin's name to a filtered version more suitable for user UI.
@ -240,6 +243,8 @@ var gPluginHandler = {
}
}
let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
switch (eventType) {
case "PluginCrashed":
this.pluginInstanceCrashed(plugin, event);
@ -263,7 +268,7 @@ var gPluginHandler = {
case "PluginBlocklisted":
case "PluginOutdated":
this.pluginUnavailable(plugin, eventType);
this._showClickToPlayNotification(browser);
break;
case "PluginVulnerableUpdatable":
@ -285,6 +290,7 @@ var gPluginHandler = {
let vulnerabilityText = doc.getAnonymousElementByAttribute(plugin, "anonid", "vulnerabilityStatus");
vulnerabilityText.textContent = vulnerabilityString;
}
this._showClickToPlayNotification(browser);
break;
case "PluginPlayPreview":
@ -294,16 +300,11 @@ var gPluginHandler = {
case "PluginDisabled":
let manageLink = doc.getAnonymousElementByAttribute(plugin, "class", "managePluginsLink");
this.addLinkClickCallback(manageLink, "managePlugins");
this._showClickToPlayNotification(browser);
break;
case "PluginScripted":
let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
if (browser._pluginScriptedState == this.PLUGIN_SCRIPTED_STATE_NONE) {
browser._pluginScriptedState = this.PLUGIN_SCRIPTED_STATE_FIRED;
setTimeout(function() {
gPluginHandler.handlePluginScripted(this);
}.bind(browser), 500);
}
case "PluginInstantiated":
this._showClickToPlayNotification(browser);
break;
}
@ -315,45 +316,6 @@ var gPluginHandler = {
}
},
_notificationDisplayedOnce: false,
handlePluginScripted: function PH_handlePluginScripted(aBrowser) {
let contentWindow = aBrowser.contentWindow;
if (!contentWindow)
return;
let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let plugins = cwu.plugins.filter(function(plugin) {
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
return gPluginHandler.canActivatePlugin(objLoadingContent);
});
let haveVisibleCTPPlugin = plugins.some(function(plugin) {
let doc = plugin.ownerDocument;
let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
if (!overlay)
return false;
// if the plugin's style is 240x200, it's a good bet we set that in
// toolkit/mozapps/plugins/content/pluginProblemContent.css
// (meaning this plugin was never actually given a size, so it's really
// not part of visible content)
let computedStyle = contentWindow.getComputedStyle(plugin);
let isInvisible = ((computedStyle.width == "240px" &&
computedStyle.height == "200px") ||
gPluginHandler.isTooSmall(plugin, overlay));
return !isInvisible;
});
let notification = PopupNotifications.getNotification("click-to-play-plugins", aBrowser);
if (notification && plugins.length > 0 && !haveVisibleCTPPlugin && !this._notificationDisplayedOnce) {
notification.reshow();
this._notificationDisplayedOnce = true;
}
aBrowser._pluginScriptedState = this.PLUGIN_SCRIPTED_STATE_DONE;
},
isKnownPlugin: function PH_isKnownPlugin(objLoadingContent) {
return (objLoadingContent.getContentTypeForMIMEType(objLoadingContent.actualType) ==
Ci.nsIObjectLoadingContent.TYPE_PLUGIN);
@ -386,40 +348,6 @@ var gPluginHandler = {
isFallbackTypeValid;
},
activatePlugins: function PH_activatePlugins(aContentWindow) {
let browser = gBrowser.getBrowserForDocument(aContentWindow.document);
browser._clickToPlayAllPluginsActivated = true;
let cwu = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let plugins = cwu.plugins;
for (let plugin of plugins) {
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
if (gPluginHandler.canActivatePlugin(objLoadingContent))
objLoadingContent.playPlugin();
}
let notification = PopupNotifications.getNotification("click-to-play-plugins", browser);
if (notification)
notification.remove();
},
activateSinglePlugin: function PH_activateSinglePlugin(aContentWindow, aPlugin) {
let objLoadingContent = aPlugin.QueryInterface(Ci.nsIObjectLoadingContent);
if (gPluginHandler.canActivatePlugin(objLoadingContent))
objLoadingContent.playPlugin();
let cwu = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let pluginNeedsActivation = gPluginHandler._pluginNeedsActivationExceptThese([aPlugin]);
let browser = gBrowser.getBrowserForDocument(aContentWindow.document);
let notification = PopupNotifications.getNotification("click-to-play-plugins", browser);
if (notification) {
notification.remove();
}
if (pluginNeedsActivation) {
gPluginHandler._showClickToPlayNotification(browser);
}
},
hideClickToPlayOverlay: function(aPlugin) {
let overlay = aPlugin.ownerDocument.getAnonymousElementByAttribute(aPlugin, "class", "mainBox");
if (overlay)
@ -577,13 +505,6 @@ var gPluginHandler = {
return;
}
let pluginInfo = this._getPluginInfo(aPlugin);
if (browser._clickToPlayAllPluginsActivated ||
browser._clickToPlayPluginsActivated.get(pluginInfo.pluginName)) {
objLoadingContent.playPlugin();
return;
}
if (overlay) {
overlay.addEventListener("click", gPluginHandler._overlayClickListener, true);
let closeIcon = doc.getAnonymousElementByAttribute(aPlugin, "anonid", "closeIcon");
@ -592,8 +513,6 @@ var gPluginHandler = {
gPluginHandler.hideClickToPlayOverlay(aPlugin);
}, true);
}
gPluginHandler._showClickToPlayNotification(browser);
},
_overlayClickListener: {
@ -617,13 +536,7 @@ var gPluginHandler = {
if (!(aEvent.originalTarget instanceof HTMLAnchorElement) &&
(aEvent.originalTarget.getAttribute('anonid') != 'closeIcon') &&
aEvent.button == 0 && aEvent.isTrusted) {
if (objLoadingContent.pluginFallbackType ==
Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE ||
objLoadingContent.pluginFallbackType ==
Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE)
gPluginHandler._showClickToPlayNotification(browser, true);
else
gPluginHandler.activateSinglePlugin(contentWindow, plugin);
gPluginHandler._showClickToPlayNotification(browser, plugin);
aEvent.stopPropagation();
aEvent.preventDefault();
}
@ -637,16 +550,6 @@ var gPluginHandler = {
let pluginInfo = this._getPluginInfo(aPlugin);
let playPreviewInfo = pluginHost.getPlayPreviewInfo(pluginInfo.mimetype);
if (!playPreviewInfo.ignoreCTP) {
// if click-to-play rules used, play plugin at once if plugins were
// activated for this window
if (browser._clickToPlayAllPluginsActivated ||
browser._clickToPlayPluginsActivated.get(pluginInfo.pluginName)) {
objLoadingContent.playPlugin();
return;
}
}
let previewContent = doc.getAnonymousElementByAttribute(aPlugin, "class", "previewPluginContent");
let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
if (!iframe) {
@ -684,10 +587,6 @@ var gPluginHandler = {
reshowClickToPlayNotification: function PH_reshowClickToPlayNotification() {
let browser = gBrowser.selectedBrowser;
if (!browser._clickToPlayPluginsActivated)
browser._clickToPlayPluginsActivated = new Map();
if (!browser._pluginScriptedState)
browser._pluginScriptedState = gPluginHandler.PLUGIN_SCRIPTED_STATE_NONE;
let contentWindow = browser.contentWindow;
let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
@ -701,6 +600,7 @@ var gPluginHandler = {
if (gPluginHandler.canActivatePlugin(objLoadingContent))
gPluginHandler._handleClickToPlayEvent(plugin);
}
gPluginHandler._showClickToPlayNotification(browser);
},
// returns true if there is a plugin on this page that needs activation
@ -718,242 +618,186 @@ var gPluginHandler = {
return pluginNeedsActivation;
},
/* Gets all plugins currently in the page of the given name */
_getPluginsByName: function PH_getPluginsByName(aDOMWindowUtils, aName) {
let plugins = [];
for (let plugin of aDOMWindowUtils.plugins) {
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
if (gPluginHandler.canActivatePlugin(objLoadingContent)) {
let pluginName = this._getPluginInfo(plugin).pluginName;
if (aName == pluginName) {
plugins.push(objLoadingContent);
}
}
_clickToPlayNotificationEventCallback: function PH_ctpEventCallback(event) {
if (event == "showing") {
gPluginHandler._makeCenterActions(this);
}
else if (event == "dismissed") {
// Once the popup is dismissed, clicking the icon should show the full
// list again
this.options.primaryPlugin = null;
}
return plugins;
},
_makeCenterActions: function PH_makeCenterActions(aBrowser) {
let contentWindow = aBrowser.contentWindow;
_makeCenterActions: function PH_makeCenterActions(notification) {
let browser = notification.browser;
let contentWindow = browser.contentWindow;
let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let pluginsDictionary = new Map();
for (let plugin of cwu.plugins) {
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
if (gPluginHandler.canActivatePlugin(objLoadingContent)) {
let pluginName = this._getPluginInfo(plugin).pluginName;
if (!pluginsDictionary.has(pluginName))
pluginsDictionary.set(pluginName, []);
pluginsDictionary.get(pluginName).push(objLoadingContent);
}
}
let principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(browser.currentURI);
let centerActions = [];
for (let [pluginName, namedPluginArray] of pluginsDictionary) {
let plugin = namedPluginArray[0];
let warn = false;
let warningText = "";
let updateLink = Services.urlFormatter.formatURLPref("plugins.update.url");
if (plugin.pluginFallbackType) {
if (plugin.pluginFallbackType ==
Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE) {
warn = true;
warningText = gNavigatorBundle.getString("vulnerableUpdatablePluginWarning");
}
else if (plugin.pluginFallbackType ==
Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE) {
warn = true;
warningText = gNavigatorBundle.getString("vulnerableNoUpdatePluginWarning");
updateLink = "";
}
let pluginsFound = new Set();
for (let plugin of cwu.plugins) {
plugin.QueryInterface(Ci.nsIObjectLoadingContent);
if (plugin.getContentTypeForMIMEType(plugin.actualType) != Ci.nsIObjectLoadingContent.TYPE_PLUGIN) {
continue;
}
let action = {
message: pluginName,
warn: warn,
warningText: warningText,
updateLink: updateLink,
label: gNavigatorBundle.getString("activateSinglePlugin"),
callback: function() {
let plugins = gPluginHandler._getPluginsByName(cwu, this.message);
for (let objLoadingContent of plugins) {
objLoadingContent.playPlugin();
}
aBrowser._clickToPlayPluginsActivated.set(this.message, true);
let notification = PopupNotifications.getNotification("click-to-play-plugins", aBrowser);
if (notification &&
!gPluginHandler._pluginNeedsActivationExceptThese(plugins)) {
notification.remove();
}
}
};
centerActions.push(action);
}
return centerActions;
},
_setPermissionForPlugins: function PH_setPermissionForPlugins(aBrowser, aPermission, aPluginList) {
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
for (let plugin of aPluginList) {
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
// canActivatePlugin will return false if this isn't a known plugin type,
// so the pluginHost.getPermissionStringForType call is protected
if (gPluginHandler.canActivatePlugin(objLoadingContent)) {
let permissionString = pluginHost.getPermissionStringForType(objLoadingContent.actualType);
Services.perms.add(aBrowser.currentURI, permissionString, aPermission);
let pluginInfo = this._getPluginInfo(plugin);
if (pluginInfo.permissionString === null) {
Components.utils.reportError("No permission string for active plugin.");
continue;
}
if (pluginsFound.has(pluginInfo.permissionString)) {
continue;
}
pluginsFound.add(pluginInfo.permissionString);
// Add the per-site permissions and details URLs to pluginInfo here
// because they are more expensive to compute and so we avoid it in
// the tighter loop above.
let permissionObj = Services.perms.
getPermissionObject(principal, pluginInfo.permissionString, false);
if (permissionObj) {
pluginInfo.pluginPermissionHost = permissionObj.host;
pluginInfo.pluginPermissionType = permissionObj.expireType;
}
else {
pluginInfo.pluginPermissionHost = browser.currentURI.host;
pluginInfo.pluginPermissionType = undefined;
}
let url;
// TODO: allow the blocklist to specify a better link, bug 873093
if (pluginInfo.blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE) {
url = Services.urlFormatter.formatURLPref("plugins.update.url");
}
else if (pluginInfo.blocklistState != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
url = Services.blocklist.getPluginBlocklistURL(pluginInfo.pluginTag);
}
pluginInfo.detailsLink = url;
centerActions.push(pluginInfo);
}
centerActions.sort(function(a, b) {
return a.pluginName.localeCompare(b.pluginName);
});
notification.options.centerActions = centerActions;
},
_showClickToPlayNotification: function PH_showClickToPlayNotification(aBrowser, aForceOpenNotification) {
let contentWindow = aBrowser.contentWindow;
let messageString = gNavigatorBundle.getString("activatePluginsMessage.message");
let mainAction = {
label: gNavigatorBundle.getString("activateAllPluginsMessage.label"),
accessKey: gNavigatorBundle.getString("activatePluginsMessage.accesskey"),
callback: function() { gPluginHandler.activatePlugins(contentWindow); }
};
let centerActions = gPluginHandler._makeCenterActions(aBrowser);
/**
* Called from the plugin doorhanger to set the new permissions for a plugin
* and activate plugins if necessary.
* aNewState should be either "allownow" "allowalways" or "block"
*/
_updatePluginPermission: function PH_setPermissionForPlugins(aNotification, aPluginInfo, aNewState) {
let permission;
let expireType;
let expireTime;
switch (aNewState) {
case "allownow":
if (aPluginInfo.fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE) {
return;
}
permission = Ci.nsIPermissionManager.ALLOW_ACTION;
expireType = Ci.nsIPermissionManager.EXPIRE_SESSION;
expireTime = Date.now() + Services.prefs.getIntPref(kPrefSessionPersistMinutes) * 60 * 1000;
break;
case "allowalways":
if (aPluginInfo.fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE) {
return;
}
permission = Ci.nsIPermissionManager.ALLOW_ACTION;
expireType = Ci.nsIPermissionManager.EXPIRE_TIME;
expireTime = Date.now() +
Services.prefs.getIntPref(kPrefPersistentDays) * 24 * 60 * 60 * 1000;
break;
case "block":
if (aPluginInfo.fallbackType != Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE) {
return;
}
permission = Ci.nsIPermissionManager.PROMPT_ACTION;
expireType = Ci.nsIPermissionManager.EXPIRE_NEVER;
expireTime = 0;
break;
default:
Cu.reportError(Error("Unexpected plugin state: " + aNewState));
return;
}
let browser = aNotification.browser;
Services.perms.add(browser.currentURI, aPluginInfo.permissionString,
permission, expireType, expireTime);
if (aNewState == "block") {
return;
}
// Manually activate the plugins that would have been automatically
// activated.
let contentWindow = browser.contentWindow;
let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let haveVulnerablePlugin = cwu.plugins.some(function(plugin) {
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
return (gPluginHandler.canActivatePlugin(objLoadingContent) &&
(objLoadingContent.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE ||
objLoadingContent.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE));
});
if (haveVulnerablePlugin) {
messageString = gNavigatorBundle.getString("vulnerablePluginsMessage");
let plugins = cwu.plugins;
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
for (let plugin of plugins) {
plugin.QueryInterface(Ci.nsIObjectLoadingContent);
// canActivatePlugin will return false if this isn't a known plugin type,
// so the pluginHost.getPermissionStringForType call is protected
if (gPluginHandler.canActivatePlugin(plugin) &&
aPluginInfo.permissionString == pluginHost.getPermissionStringForType(plugin.actualType)) {
plugin.playPlugin();
}
}
let secondaryActions = [{
label: gNavigatorBundle.getString("activatePluginsMessage.always"),
accessKey: gNavigatorBundle.getString("activatePluginsMessage.always.accesskey"),
callback: function () {
gPluginHandler._setPermissionForPlugins(aBrowser, Ci.nsIPermissionManager.ALLOW_ACTION, cwu.plugins);
gPluginHandler.activatePlugins(contentWindow);
}
},{
label: gNavigatorBundle.getString("activatePluginsMessage.never"),
accessKey: gNavigatorBundle.getString("activatePluginsMessage.never.accesskey"),
callback: function () {
gPluginHandler._setPermissionForPlugins(aBrowser, Ci.nsIPermissionManager.DENY_ACTION, cwu.plugins);
let notification = PopupNotifications.getNotification("click-to-play-plugins", aBrowser);
if (notification)
notification.remove();
gPluginHandler._removeClickToPlayOverlays(contentWindow);
}
}];
},
_showClickToPlayNotification: function PH_showClickToPlayNotification(aBrowser, aPrimaryPlugin) {
let notification = PopupNotifications.getNotification("click-to-play-plugins", aBrowser);
let contentWindow = aBrowser.contentWindow;
let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let plugins = cwu.plugins;
if (plugins.length == 0) {
if (notification) {
PopupNotifications.remove(notification);
}
return;
}
let haveVulnerablePlugin = plugins.some(function(plugin) {
let fallbackType = plugin.pluginFallbackType;
return fallbackType == plugin.PLUGIN_VULNERABLE_UPDATABLE ||
fallbackType == plugin.PLUGIN_VULNERABLE_NO_UPDATE ||
fallbackType == plugin.PLUGIN_BLOCKLISTED;
});
let dismissed = notification ? notification.dismissed : true;
// Always show the doorhanger if the anchor is not available.
if (!isElementVisible(gURLBar) || aForceOpenNotification)
if (!isElementVisible(gURLBar) || aPrimaryPlugin)
dismissed = false;
let options = { dismissed: dismissed, centerActions: centerActions };
let icon = haveVulnerablePlugin ? "blocked-plugins-notification-icon" : "plugins-notification-icon"
PopupNotifications.show(aBrowser, "click-to-play-plugins",
messageString, icon,
mainAction, secondaryActions, options);
},
_removeClickToPlayOverlays: function PH_removeClickToPlayOverlays(aContentWindow) {
let doc = aContentWindow.document;
let cwu = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
for (let plugin of cwu.plugins) {
let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
// for already activated plugins, there will be no overlay
if (overlay)
overlay.style.visibility = "hidden";
}
},
// event listener for blocklisted/outdated plugins.
pluginUnavailable: function (plugin, eventType) {
let browser = gBrowser.getBrowserForDocument(plugin.ownerDocument
.defaultView.top.document);
if (!browser.missingPlugins)
browser.missingPlugins = new Map();
var pluginInfo = this._getPluginInfo(plugin);
browser.missingPlugins.set(pluginInfo.mimetype, pluginInfo);
var notificationBox = gBrowser.getNotificationBox(browser);
// Should only display one of these warnings per page.
// In order of priority, they are: outdated > missing > blocklisted
let outdatedNotification = notificationBox.getNotificationWithValue("outdated-plugins");
let blockedNotification = notificationBox.getNotificationWithValue("blocked-plugins");
function showBlocklistInfo() {
var url = formatURL("extensions.blocklist.detailsURL", true);
gBrowser.loadOneTab(url, {inBackground: false});
return true;
let primaryPluginPermission = null;
if (aPrimaryPlugin) {
primaryPluginPermission = this._getPluginInfo(aPrimaryPlugin).permissionString;
}
function showOutdatedPluginsInfo() {
gPrefService.setBoolPref("plugins.update.notifyUser", false);
var url = formatURL("plugins.update.url", true);
gBrowser.loadOneTab(url, {inBackground: false});
return true;
}
let notifications = {
PluginBlocklisted : {
barID : "blocked-plugins",
iconURL : "chrome://mozapps/skin/plugins/notifyPluginBlocked.png",
message : gNavigatorBundle.getString("blockedpluginsMessage.title"),
buttons : [{
label : gNavigatorBundle.getString("blockedpluginsMessage.infoButton.label"),
accessKey : gNavigatorBundle.getString("blockedpluginsMessage.infoButton.accesskey"),
popup : null,
callback : showBlocklistInfo
},
{
label : gNavigatorBundle.getString("blockedpluginsMessage.searchButton.label"),
accessKey : gNavigatorBundle.getString("blockedpluginsMessage.searchButton.accesskey"),
popup : null,
callback : showOutdatedPluginsInfo
}],
},
PluginOutdated : {
barID : "outdated-plugins",
iconURL : "chrome://mozapps/skin/plugins/notifyPluginOutdated.png",
message : gNavigatorBundle.getString("outdatedpluginsMessage.title"),
buttons : [{
label : gNavigatorBundle.getString("outdatedpluginsMessage.updateButton.label"),
accessKey : gNavigatorBundle.getString("outdatedpluginsMessage.updateButton.accesskey"),
popup : null,
callback : showOutdatedPluginsInfo
}],
},
let options = {
dismissed: dismissed,
eventCallback: this._clickToPlayNotificationEventCallback,
primaryPlugin: primaryPluginPermission
};
// If there is already an outdated plugin notification then do nothing
if (outdatedNotification)
return;
if (eventType == "PluginBlocklisted") {
if (gPrefService.getBoolPref("plugins.hide_infobar_for_blocked_plugin"))
return;
if (blockedNotification)
return;
}
else if (eventType == "PluginOutdated") {
if (gPrefService.getBoolPref("plugins.hide_infobar_for_outdated_plugin"))
return;
// Cancel any notification about blocklisting/missing plugins
if (blockedNotification)
blockedNotification.close();
}
let notify = notifications[eventType];
notificationBox.appendNotification(notify.message, notify.barID, notify.iconURL,
notificationBox.PRIORITY_WARNING_MEDIUM,
notify.buttons);
let icon = haveVulnerablePlugin ? "blocked-plugins-notification-icon" : "plugins-notification-icon";
PopupNotifications.show(aBrowser, "click-to-play-plugins",
"", icon,
null, null, options);
},
// Crashed-plugin observer. Notified once per plugin crash, before events

View File

@ -506,8 +506,8 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#click-to-play-plugins-notification");
}
popupnotification-centeritem {
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#center-item");
.plugin-popupnotification-centeritem {
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#plugin-popupnotification-center-item");
}
/* override hidden="true" for the status bar compatibility shim

View File

@ -752,9 +752,9 @@ var gBrowserInit = {
// Note that the XBL binding is untrusted
gBrowser.addEventListener("PluginBindingAttached", gPluginHandler, true, true);
gBrowser.addEventListener("PluginScripted", gPluginHandler, true);
gBrowser.addEventListener("PluginCrashed", gPluginHandler, true);
gBrowser.addEventListener("PluginOutdated", gPluginHandler, true);
gBrowser.addEventListener("PluginInstantiated", gPluginHandler, true);
gBrowser.addEventListener("NewPluginInstalled", gPluginHandler.newPluginInstalled, true);

View File

@ -299,7 +299,7 @@ function clearPluginPermissionTemplate() {
}
function initPluginsRow() {
var vulnerableLabel = document.getElementById("browserBundle").getString("vulnerableNoUpdatePluginWarning");
let vulnerableLabel = document.getElementById("browserBundle").getString("pluginActivateVulnerable.label");
let pluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
let permissionMap = Map();

View File

@ -8,6 +8,8 @@
<!DOCTYPE bindings [
<!ENTITY % notificationDTD SYSTEM "chrome://global/locale/notification.dtd">
%notificationDTD;
<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
%browserDTD;
]>
<bindings id="urlbarBindings" xmlns="http://www.mozilla.org/xbl"
@ -1376,122 +1378,471 @@
</implementation>
</binding>
<binding id="center-item">
<binding id="plugin-popupnotification-center-item">
<content align="center">
<xul:vbox flex="1" class="center-item-box"
xbl:inherits="warn,showseparator,padbottom">
<xul:hbox flex="1" align="center">
<xul:image class="center-item-icon"
xbl:inherits="src=itemicon"/>
<xul:description class="center-item-label"
xbl:inherits="xbl:text=itemtext"/>
<xul:spacer flex="1"/>
<xul:button class="popup-notification-menubutton center-item-button"
oncommand="document.getBindingParent(this).runCallback();"
xbl:inherits="label=buttonlabel"/>
</xul:hbox>
<xul:hbox flex="1" align="center" class="center-item-warning">
<xul:image class="center-item-warning-icon"/>
<xul:label class="center-item-warning-description" xbl:inherits="xbl:text=warningText"/>
<xul:label xbl:inherits="href=updateLink" value="&checkForUpdates;" class="text-link"/>
<xul:spacer flex="1"/>
<xul:vbox pack="center" anonid="itemBox" class="itemBox">
<xul:description anonid="center-item-label" />
<xul:hbox flex="1" pack="start" align="center" anonid="center-item-warning">
<xul:image anonid="center-item-warning-icon" class="center-item-warning-icon"/>
<xul:label anonid="center-item-warning-label"/>
<xul:label anonid="center-item-link" value="&checkForUpdates;" class="text-link"/>
</xul:hbox>
</xul:vbox>
<xul:vbox pack="center">
<xul:menulist class="center-item-menulist"
anonid="center-item-menulist">
<xul:menupopup>
<xul:menuitem anonid="allownow" value="allownow"
label="&pluginActivateNow.label;" />
<xul:menuitem anonid="allowalways" value="allowalways"
label="&pluginActivateAlways.label;" />
<xul:menuitem anonid="block" value="block"
label="&pluginBlockNow.label;" />
</xul:menupopup>
</xul:menulist>
</xul:vbox>
</content>
<resources>
<stylesheet src="chrome://global/skin/notification.css"/>
</resources>
<implementation>
<field name="action"></field>
<method name="runCallback">
<body><![CDATA[
let action = this.action;
action.callback();
let cas = action.popupnotification.notification.options.centerActions;
cas.splice(cas.indexOf(action), 1);
PopupNotifications._dismiss();
]]></body>
</method>
<constructor><![CDATA[
document.getAnonymousElementByAttribute(this, "anonid", "center-item-label").value = this.action.pluginName;
let curState = "block";
if (this.action.fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE) {
if (this.action.pluginPermissionType == Ci.nsIPermissionManager.EXPIRE_SESSION) {
curState = "allownow";
}
else {
curState = "allowalways";
}
}
document.getAnonymousElementByAttribute(this, "anonid", "center-item-menulist").value = curState;
let warningString = "";
let linkString = "";
let link = document.getAnonymousElementByAttribute(this, "anonid", "center-item-link");
let url;
let linkHandler;
if (this.action.pluginTag.enabledState == Ci.nsIPluginTag.STATE_DISABLED) {
document.getAnonymousElementByAttribute(this, "anonid", "center-item-menulist").hidden = true;
warningString = gNavigatorBundle.getString("pluginActivateDisabled.label");
linkString = gNavigatorBundle.getString("pluginActivateDisabled.manage");
linkHandler = function(event) {
event.preventDefault();
gPluginHandler.managePlugins();
};
document.getAnonymousElementByAttribute(this, "anonid", "center-item-warning-icon").hidden = true;
}
else {
url = this.action.detailsLink;
switch (this.action.blocklistState) {
case Ci.nsIBlocklistService.STATE_NOT_BLOCKED:
document.getAnonymousElementByAttribute(this, "anonid", "center-item-warning").hidden = true;
break;
case Ci.nsIBlocklistService.STATE_BLOCKED:
document.getAnonymousElementByAttribute(this, "anonid", "center-item-menulist").hidden = true;
warningString = gNavigatorBundle.getString("pluginActivateBlocked.label");
linkString = gNavigatorBundle.getString("pluginActivate.learnMore");
break;
case Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE:
warningString = gNavigatorBundle.getString("pluginActivateOutdated.label");
linkString = gNavigatorBundle.getString("pluginActivate.updateLabel");
break;
case Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE:
warningString = gNavigatorBundle.getString("pluginActivateVulnerable.label");
linkString = gNavigatorBundle.getString("pluginActivate.riskLabel");
break;
}
}
document.getAnonymousElementByAttribute(this, "anonid", "center-item-warning-label").value = warningString;
if (url || linkHandler) {
link.value = linkString;
if (url) {
link.href = url;
}
if (linkHandler) {
link.addEventListener("click", linkHandler, false);
}
}
else {
link.hidden = true;
}
]]></constructor>
<property name="value">
<getter>
return document.getAnonymousElementByAttribute(this, "anonid",
"center-item-menulist").value;
</getter>
</property>
</implementation>
</binding>
<binding id="click-to-play-plugins-notification" extends="chrome://global/content/bindings/notification.xml#popup-notification">
<content align="start" class="click-to-play-plugins-notification-content">
<xul:hbox flex="1">
<xul:vbox class="click-to-play-plugins-notification-icon-box" flex="1">
<xul:image class="popup-notification-icon"
xbl:inherits="popupid,src=icon"/>
<xul:spacer flex="1"/>
</xul:vbox>
<xul:spacer class="click-to-play-plugins-notification-separator"/>
<xul:vbox flex="1" class="popup-notification-main-box"
xbl:inherits="popupid">
<xul:box class="click-to-play-plugins-notification-description-box" flex="1">
<xul:description xbl:inherits="xbl:text=label"/>
</xul:box>
<xul:spacer class="click-to-play-plugins-notification-separator"/>
<xul:vbox class="click-to-play-plugins-notification-center-box">
<children includes="popupnotification-centeritem"/>
</xul:vbox>
<xul:spacer class="click-to-play-plugins-notification-separator"/>
<xul:hbox class="click-to-play-plugins-notification-button-container"
pack="end" align="center">
<xul:button anonid="button"
class="popup-notification-menubutton"
type="menu-button"
xbl:inherits="oncommand=buttoncommand,label=buttonlabel,accesskey=buttonaccesskey">
<xul:menupopup anonid="menupopup"
xbl:inherits="oncommand=menucommand">
<children/>
<xul:menuitem class="menuitem-iconic popup-notification-closeitem"
label="&closeNotificationItem.label;"
xbl:inherits="oncommand=closeitemcommand"/>
</xul:menupopup>
</xul:button>
</xul:hbox>
</xul:vbox>
</xul:hbox>
<xul:vbox flex="1" align="stretch" class="popup-notification-main-box"
xbl:inherits="popupid">
<xul:hbox class="click-to-play-plugins-notification-description-box" flex="1" align="start">
<xul:description flex="1">
<html:span anonid="click-to-play-plugins-notification-description" />
&#32;
<xul:label class="text-link" anonid="click-to-play-plugins-notification-link" />
</xul:description>
<xul:toolbarbutton anonid="closebutton"
class="messageCloseButton popup-notification-closebutton tabbable"
xbl:inherits="oncommand=closebuttoncommand"
tooltiptext="&closeNotification.tooltip;"/>
</xul:hbox>
<xul:grid anonid="click-to-play-plugins-notification-center-box">
<xul:columns>
<xul:column flex="1"/>
<xul:column/>
</xul:columns>
<xul:rows>
<children includes="row"/>
<xul:hbox pack="start" anonid="plugin-notification-showbox">
<xul:button label="&pluginNotification.showAll.label;"
accesskey="&pluginNotification.showAll.accesskey;"
class="plugin-notification-showbutton"
oncommand="document.getBindingParent(this)._setState(2)"/>
</xul:hbox>
</xul:rows>
</xul:grid>
<xul:hbox anonid="button-container"
class="click-to-play-plugins-notification-button-container"
pack="center" align="center">
<xul:button anonid="primarybutton"
class="popup-notification-menubutton"
oncommand="document.getBindingParent(this)._onButton(this)"/>
<xul:button anonid="secondarybutton"
class="popup-notification-menubutton"
oncommand="document.getBindingParent(this)._onButton(this);"/>
</xul:hbox>
<xul:box hidden="true">
<children/>
</xul:box>
</xul:vbox>
</content>
<resources>
<stylesheet src="chrome://global/skin/notification.css"/>
</resources>
<implementation>
<field name="button" readonly="true">
document.getAnonymousElementByAttribute(this, "anonid", "button");
<field name="_states">
({SINGLE: 0, MULTI_COLLAPSED: 1, MULTI_EXPANDED: 2})
</field>
<field name="menupopup" readonly="true">
document.getAnonymousElementByAttribute(this, "anonid", "menupopup");
<field name="_primaryButton">
document.getAnonymousElementByAttribute(this, "anonid", "primarybutton");
</field>
<field name="_secondaryButton">
document.getAnonymousElementByAttribute(this, "anonid", "secondarybutton")
</field>
<field name="_buttonContainer">
document.getAnonymousElementByAttribute(this, "anonid", "button-container")
</field>
<field name="_brandShortName">
document.getElementById("bundle_brand").getString("brandShortName")
</field>
<field name="_items">[]</field>
<constructor><![CDATA[
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
let popupnotification = this;
let item = null;
let prev = null;
this.notification.options.centerActions.forEach(function(action) {
action.popupnotification = popupnotification;
item = document.createElementNS(XUL_NS, "popupnotification-centeritem");
for (let action of this.notification.options.centerActions) {
let item = document.createElementNS(XUL_NS, "row");
item.setAttribute("class", "plugin-popupnotification-centeritem");
item.action = action;
item.setAttribute("itemtext", action.message);
item.setAttribute("buttonlabel", action.label);
item.setAttribute("warn", action.warn);
item.setAttribute("warningText", action.warningText);
item.setAttribute("updateLink", action.updateLink);
if (prev &&
(prev.getAttribute("warn") == "true" ||
item.getAttribute("warn") == "true")) {
item.setAttribute("showseparator", true);
if (prev.getAttribute("warn") != "true") {
prev.setAttribute("padbottom", true);
}
}
popupnotification.appendChild(item);
prev = item;
});
if (item != null) {
item.setAttribute("padbottom", "true");
this.appendChild(item);
this._items.push(item);
}
if (this.notification.options.centerActions.length == 1) {
this._setState(this._states.SINGLE);
} else if (this.notification.options.primaryPlugin) {
this._setState(this._states.MULTI_COLLAPSED);
} else {
this._setState(this._states.MULTI_EXPANDED);
}
]]></constructor>
<method name="_setState">
<parameter name="state" />
<body><![CDATA[
var grid = document.getAnonymousElementByAttribute(this, "anonid", "click-to-play-plugins-notification-center-box");
if (this._states.SINGLE == state) {
grid.hidden = true;
this._setupSingleState();
return;
}
this._setupDescription("pluginActivateMultiple.message");
var showBox = document.getAnonymousElementByAttribute(this, "anonid", "plugin-notification-showbox");
var dialogStrings = Services.strings.createBundle("chrome://global/locale/dialog.properties");
this._primaryButton.label = dialogStrings.GetStringFromName("button-accept");
this._primaryButton.setAttribute("default", "true");
this._secondaryButton.label = dialogStrings.GetStringFromName("button-cancel");
this._primaryButton.setAttribute("action", "_multiAccept");
this._secondaryButton.setAttribute("action", "_cancel");
grid.hidden = false;
if (this._states.MULTI_COLLAPSED == state) {
for (let child of this.childNodes) {
if (child.tagName != "row") {
continue;
}
child.hidden = this.notification.options.primaryPlugin !=
child.action.permissionString;
}
showBox.hidden = false;
}
else {
for (let child of this.childNodes) {
if (child.tagName != "row") {
continue;
}
child.hidden = false;
}
showBox.hidden = true;
}
this._setupLink(null);
]]></body>
</method>
<method name="_setupSingleState">
<body><![CDATA[
var action = this.notification.options.centerActions[0];
var host = action.pluginPermissionHost;
let label, linkLabel, linkUrl, button1, button2;
if (action.fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE) {
button1 = {
label: "pluginBlockNow.label",
accesskey: "pluginBlockNow.accesskey",
action: "_singleBlock"
};
button2 = {
label: "pluginContinue.label",
accesskey: "pluginContinue.accesskey",
action: "_cancel",
default: true
};
switch (action.blocklistState) {
case Ci.nsIBlocklistService.STATE_NOT_BLOCKED:
label = "pluginEnabled.message";
linkLabel = "pluginActivate.learnMore";
break;
case Ci.nsIBlocklistService.STATE_BLOCKED:
Cu.reportError(Error("Cannot happen!"));
break;
case Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE:
label = "pluginEnabledOutdated.message";
linkLabel = "pluginActivate.updateLabel";
break;
case Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE:
label = "pluginEnabledVulnerable.message";
linkLabel = "pluginActivate.riskLabel"
break;
default:
Cu.reportError(Error("Unexpected blocklist state"));
}
}
else if (action.pluginTag.enabledState == Ci.nsIPluginTag.STATE_DISABLED) {
let linkElement =
document.getAnonymousElementByAttribute(
this, "anonid", "click-to-play-plugins-notification-link");
linkElement.value = gNavigatorBundle.getString("pluginActivateDisabled.manage");
linkElement.setAttribute("onclick", "gPluginHandler.managePlugins()");
let descElement = document.getAnonymousElementByAttribute(this, "anonid", "click-to-play-plugins-notification-description");
descElement.textContent = gNavigatorBundle.getFormattedString(
"pluginActivateDisabled.message", [action.pluginName, this._brandShortName]);
this._buttonContainer.hidden = true;
return;
}
else if (action.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED) {
let descElement = document.getAnonymousElementByAttribute(this, "anonid", "click-to-play-plugins-notification-description");
descElement.textContent = gNavigatorBundle.getFormattedString(
"pluginActivateBlocked.message", [action.pluginName, this._brandShortName]);
this._setupLink("pluginActivate.learnMore", action.detailsLink);
this._buttonContainer.hidden = true;
return;
}
else {
button1 = {
label: "pluginActivateNow.label",
accesskey: "pluginActivateNow.accesskey",
action: "_singleActivateNow"
};
button2 = {
label: "pluginActivateAlways.label",
accesskey: "pluginActivateAlways.accesskey",
action: "_singleActivateAlways"
};
switch (action.blocklistState) {
case Ci.nsIBlocklistService.STATE_NOT_BLOCKED:
label = "pluginActivateNew.message";
linkLabel = "pluginActivate.learnMore";
button2.default = true;
break;
case Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE:
label = "pluginActivateOutdated.label";
linkLabel = "pluginActivate.updateLabel";
button1.default = true;
break;
case Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE:
label = "pluginActivateVulnerable.message";
linkLabel = "pluginActivate.riskLabel"
button1.default = true;
break;
default:
Cu.reportError(Error("Unexpected blocklist state"));
}
}
this._setupDescription(label, action.pluginName, host);
this._setupLink(linkLabel, action.detailsLink);
this._primaryButton.label = gNavigatorBundle.getString(button1.label);
this._primaryButton.accesskey = gNavigatorBundle.getString(button1.accesskey);
this._primaryButton.setAttribute("action", button1.action);
this._secondaryButton.label = gNavigatorBundle.getString(button2.label);
this._secondaryButton.accesskey = gNavigatorBundle.getString(button2.accesskey);
this._secondaryButton.setAttribute("action", button2.action);
if (button1.default) {
this._primaryButton.setAttribute("default", "true");
}
else if (button2.default) {
this._secondaryButton.setAttribute("default", "true");
}
]]></body>
</method>
<method name="_setupDescription">
<parameter name="baseString" />
<parameter name="pluginName" /> <!-- null for the multiple-plugin case -->
<parameter name="host" />
<body><![CDATA[
var bsn = this._brandShortName;
var span = document.getAnonymousElementByAttribute(this, "anonid", "click-to-play-plugins-notification-description");
while (span.lastChild) {
span.removeChild(span.lastChild);
}
if (!host) {
host = this.notification.browser.currentURI.host;
}
var args = ["__host__", this._brandShortName];
if (pluginName) {
args.unshift(pluginName);
}
var bases = gNavigatorBundle.getFormattedString(baseString, args).
split("__host__", 2);
span.appendChild(document.createTextNode(bases[0]));
var hostSpan = document.createElementNS("http://www.w3.org/1999/xhtml", "em");
hostSpan.appendChild(document.createTextNode(host));
span.appendChild(hostSpan);
span.appendChild(document.createTextNode(bases[1]));
]]></body>
</method>
<method name="_setupLink">
<parameter name="linkString"/>
<parameter name="linkUrl" />
<body><![CDATA[
var link = document.getAnonymousElementByAttribute(this, "anonid", "click-to-play-plugins-notification-link");
if (!linkString || !linkUrl) {
link.hidden = true;
return;
}
link.hidden = false;
link.value = gNavigatorBundle.getString(linkString);
link.href = linkUrl;
]]></body>
</method>
<method name="_onButton">
<parameter name="aButton" />
<body><![CDATA[
let methodName = aButton.getAttribute("action");
this[methodName]();
]]></body>
</method>
<method name="_singleActivateNow">
<body><![CDATA[
gPluginHandler._updatePluginPermission(this.notification,
this.notification.options.centerActions[0],
"allownow");
this._cancel();
]]></body>
</method>
<method name="_singleBlock">
<body><![CDATA[
gPluginHandler._updatePluginPermission(this.notification,
this.notification.options.centerActions[0],
"block");
this._cancel();
]]></body>
</method>
<method name="_singleActivateAlways">
<body><![CDATA[
gPluginHandler._updatePluginPermission(this.notification,
this.notification.options.centerActions[0],
"allowalways");
this._cancel();
]]></body>
</method>
<method name="_multiAccept">
<body><![CDATA[
for (let item of this._items) {
let action = item.action;
if (action.pluginTag.enabledState == Ci.nsIPluginTag.STATE_DISABLED ||
action.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED) {
continue;
}
gPluginHandler._updatePluginPermission(this.notification,
item.action, item.value);
}
this._cancel();
]]></body>
</method>
<method name="_cancel">
<body><![CDATA[
PopupNotifications._dismiss();
]]></body>
</method>
<method name="_accept">
<parameter name="aEvent" />
<body><![CDATA[
if (aEvent.defaultPrevented)
return;
aEvent.preventDefault();
if (this._primaryButton.getAttribute("default") == "true") {
this._primaryButton.click();
}
else if (this._secondaryButton.getAttribute("default") == "true") {
this._secondaryButton.click();
}
]]></body>
</method>
</implementation>
<handlers>
<!-- The _accept method checks for .defaultPrevented so that if focus is in a button,
enter activates the button and not this default action -->
<handler event="keypress" keycode="VK_ENTER" group="system" action="this._accept(event);"/>
<handler event="keypress" keycode="VK_RETURN" group="system" action="this._accept(event);"/>
</handlers>
</binding>
<binding id="splitmenu">

View File

@ -681,3 +681,11 @@ just addresses the organization to follow, e.g. "This site is run by " -->
<!ENTITY mixedContentBlocked.moreinfo "Most websites will still work properly even when this content is blocked.">
<!ENTITY pointerLock.notification.message "Press ESC at any time to show it again.">
<!ENTITY pluginNotification.showAll.label "Show All">
<!ENTITY pluginNotification.showAll.accesskey "S">
<!-- LOCALIZATION NOTE (pluginActivateNow.label, pluginActivateAlways.label, pluginBlockNow.label): These should be the same as the matching strings in browser.properties -->
<!ENTITY pluginActivateNow.label "Allow Now">
<!ENTITY pluginActivateAlways.label "Allow and Remember">
<!ENTITY pluginBlockNow.label "Block Plugin">

View File

@ -118,6 +118,52 @@ crashedpluginsMessage.reloadButton.accesskey=R
crashedpluginsMessage.submitButton.label=Submit a crash report
crashedpluginsMessage.submitButton.accesskey=S
crashedpluginsMessage.learnMore=Learn More…
## Plugin doorhanger strings
# LOCALIZATION NOTE (pluginActivateNw.message): Used for newly-installed
# plugins which are not known to be unsafe. %1$S is the plugin name and %2$S
# is the site domain.
pluginActivateNew.message=Allow %2$S to run "%1$S"?
pluginActivateMultiple.message=Allow %S to run plugins?
pluginActivate.learnMore=Learn More…
# LOCALIZATION NOTE (pluginActivateOutdated.message, pluginActivateOutdated.label):
# These strings are used when an unsafe plugin has an update available.
# %1$S is the plugin name, %2$S is the domain, and %3$S is brandShortName.
pluginActivateOutdated.message=%3$S has prevented the outdated plugin "%1$S" from running on %2$S.
pluginActivateOutdated.label=Outdated plugin
pluginActivate.updateLabel=Update now…
# LOCALIZATION NOTE (pluginActivateVulnerable.message, pluginActivateVulnerable.label):
# These strings are used when an unsafe plugin has no update available.
# %1$S is the plugin name, %2$S is the domain, and %3$S is brandShortName.
pluginActivateVulnerable.message=%3$S has prevented the unsafe plugin "%1$S" from running on %2$S.
pluginActivateVulnerable.label=Vulnerable plugin!
pluginActivate.riskLabel=What's the risk?
# LOCALIZATION NOTE (pluginActivateBlocked.message): %1$S is the plugin name, %2$S is brandShortName
pluginActivateBlocked.message=%2$S has blocked "%1$S" for your protection.
pluginActivateBlocked.label=Blocked for your protection
pluginActivateDisabled.message="%S" is disabled.
pluginActivateDisabled.label=Disabled
pluginActivateDisabled.manage=Manage plugins…
pluginEnabled.message="%S" is enabled on %S.
pluginEnabledOutdated.message=Outdated plugin "%S" is enabled on %S.
pluginEnabledVulnerable.message=Insecure plugin "%S" is enabled on %S.
# LOCALIZATION NOTE (pluginActivateNow.label, pluginActivateAlways.label, pluginBlockNow.label): These should be the same as the matching strings in browser.dtd
# LOCALIZATION NOTE (pluginActivateNow.label): This button will enable the
# plugin in the current session for an short time (about an hour), auto-renewed
# if the site keeps using the plugin.
pluginActivateNow.label=Allow Now
pluginActivateNow.accesskey=N
# LOCALIZATION NOTE (pluginActivateAlways.label): This button will enable the
# plugin for a long while (90 days), auto-renewed if the site keeps using the
# plugin.
pluginActivateAlways.label=Allow and Remember
pluginActivateAlways.accesskey=R
pluginBlockNow.label=Block Plugin
pluginBlockNow.accesskey=B
pluginContinue.label=Continue Allowing
pluginContinue.accesskey=C
activatePluginsMessage.message=Would you like to activate the plugins on this page?
activateAllPluginsMessage.label=Activate All Plugins
activatePluginsMessage.accesskey=A

View File

@ -2246,7 +2246,7 @@ chatbox {
border-top: 1px solid hsla(0,0%,100%,.2);
-moz-border-start: 1px solid hsla(0,0%,100%,.2);
margin: 0px;
padding: 15px 11px 14px 11px;
padding: 2px;
}
.center-item-box {

View File

@ -3912,7 +3912,7 @@ panel[type="arrow"][popupid="click-to-play-plugins"] > .panel-arrowcontainer > .
border-top: 1px solid hsla(0,0%,100%,.2);
-moz-border-start: 1px solid hsla(0,0%,100%,.2);
margin: 0px;
padding: 16px 16px 17px 16px;
padding: 2px;
}
.center-item-box {

View File

@ -3037,7 +3037,7 @@ chatbox {
border-top: 1px solid hsla(0,0%,100%,.2);
-moz-border-start: 1px solid hsla(0,0%,100%,.2);
margin: 0px;
padding: 16px;
padding: 2px;
}
.center-item-box {

View File

@ -1855,6 +1855,13 @@ pref("plugins.click_to_play", false);
// The default value for nsIPluginTag.enabledState (STATE_ENABLED = 2)
pref("plugin.default.state", 2);
// How long in minutes we will allow a plugin to work after the user has chosen
// to allow it "now"
pref("plugin.sessionPermissionNow.intervalInMinutes", 60);
// How long in days we will allow a plugin to work after the user has chosen
// to allow it persistently.
pref("plugin.persistentPermissionAlways.intervalInDays", 90);
#ifndef DEBUG
// How long a plugin is allowed to process a synchronous IPC message
// before we consider it "hung".