Bug 550293 - plugin-crashed UI needs more user opt-in. r=vlad, ui-r=faaborg

This commit is contained in:
Justin Dolske 2010-03-16 22:10:08 -07:00
parent 8bcfd80422
commit 1ab06617a3
16 changed files with 341 additions and 94 deletions

View File

@ -5944,30 +5944,72 @@ var gMissingPluginInstaller = {
return this.crashReportHelpURL;
},
addLinkClickCallback: function (linkNode, callbackName, callbackArg) {
// XXX just doing (callback)(arg) was giving a same-origin error. bug?
let self = this;
linkNode.addEventListener("click",
function(evt) {
if (!evt.isTrusted)
return;
evt.preventDefault();
if (callbackArg == undefined)
callbackArg = evt;
(self[callbackName])(callbackArg);
},
true);
linkNode.addEventListener("keydown",
function(evt) {
if (!evt.isTrusted)
return;
if (evt.keyCode == evt.DOM_VK_RETURN) {
evt.preventDefault();
if (callbackArg == undefined)
callbackArg = evt;
evt.preventDefault();
(self[callbackName])(callbackArg);
}
},
true);
},
// Callback for user clicking on a missing (unsupported) plugin.
installSinglePlugin: function (aEvent) {
if (!aEvent.isTrusted)
return;
var missingPluginsArray = {};
var pluginInfo = getPluginInfo(aEvent.target);
missingPluginsArray[pluginInfo.mimetype] = pluginInfo;
if (missingPluginsArray) {
openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul",
"PFSWindow", "chrome,centerscreen,resizable=yes",
{plugins: missingPluginsArray, browser: gBrowser.selectedBrowser});
}
aEvent.stopPropagation();
openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul",
"PFSWindow", "chrome,centerscreen,resizable=yes",
{plugins: missingPluginsArray, browser: gBrowser.selectedBrowser});
},
// Callback for user clicking on a disabled plugin
managePlugins: function (aEvent) {
if (!aEvent.isTrusted)
return;
BrowserOpenAddonsMgr("plugins");
aEvent.stopPropagation();
},
// Callback for user clicking "submit a report" link
submitReport : function(minidumpID) {
// The crash reporter wants a DOM element it can append an IFRAME to,
// which it uses to submit a form. Let's just give it gBrowser.
this.CrashSubmit.submit(minidumpID, gBrowser, null, null);
},
// Callback for user clicking a "reload page" link
reloadPage: function (browser) {
browser.reload();
},
// Callback for user clicking the help icon
openHelpPage: function () {
openHelpLink("plugin-crashed", false);
},
// event listener for missing/blocklisted/outdated plugins.
newMissingPlugin: function (aEvent) {
// Since we are expecting also untrusted events, make sure
// that the target is a plugin
@ -5982,14 +6024,7 @@ var gMissingPluginInstaller = {
if (aEvent.type != "PluginBlocklisted" &&
aEvent.type != "PluginOutdated" &&
!(aEvent.target instanceof HTMLObjectElement)) {
aEvent.target.addEventListener("click",
gMissingPluginInstaller.installSinglePlugin,
true);
aEvent.target.addEventListener("keydown",
function(evt) { if (evt.keyCode == evt.DOM_VK_RETURN)
gMissingPluginInstaller.installSinglePlugin(evt) },
true);
gMissingPluginInstaller.addLinkClickCallback(aEvent.target, "installSinglePlugin");
}
let hideBarPrefName = aEvent.type == "PluginOutdated" ?
@ -6110,13 +6145,7 @@ var gMissingPluginInstaller = {
if (!(aEvent.target instanceof Ci.nsIObjectLoadingContent))
return;
aEvent.target.addEventListener("click",
gMissingPluginInstaller.managePlugins,
true);
aEvent.target.addEventListener("keydown",
function(evt) { if (evt.keyCode == evt.DOM_VK_RETURN)
gMissingPluginInstaller.managePlugins(evt) },
true);
gMissingPluginInstaller.addLinkClickCallback(aEvent.target, "managePlugins");
},
// Crashed-plugin observer. Notified once per plugin crash, before events
@ -6128,17 +6157,24 @@ var gMissingPluginInstaller = {
return;
#ifdef MOZ_CRASHREPORTER
let minidumpID = subject.getPropertyAsAString("minidumpID");
let submitted = gCrashReporter.submitReports && minidumpID.length;
// The crash reporter wants a DOM element it can append an IFRAME to,
// which it uses to submit a form. Let's just give it gBrowser.
if (submitted)
submitted = gMissingPluginInstaller.CrashSubmit.submit(minidumpID, gBrowser, null, null);
propertyBag.setPropertyAsBool("submittedCrashReport", submitted);
let minidumpID = propertyBag.getPropertyAsAString("minidumpID");
let shouldSubmit = gCrashReporter.submitReports;
let doPrompt = true; // XXX followup to get via gCrashReporter
// Submit automatically when appropriate.
if (minidumpID && shouldSubmit && !doPrompt) {
this.submitReport(minidumpID);
// Submission is async, so we can't easily show failure UI.
propertyBag.setPropertyAsBool("submittedCrashReport", true);
}
#endif
},
// Crashed-plugin event listener. Called for every instance of a
// plugin in content.
pluginInstanceCrashed: function (aEvent) {
let self = gMissingPluginInstaller;
// Evil content could fire a fake event at us, ignore them.
if (!aEvent.isTrusted)
return;
@ -6147,7 +6183,10 @@ var gMissingPluginInstaller = {
return;
let submittedReport = aEvent.getData("submittedCrashReport");
let doPrompt = true; // XXX followup for .getData("doPrompt");
let submitReports = true; // XXX followup for .getData("submitReports");
let pluginName = aEvent.getData("pluginName");
let minidumpID = aEvent.getData("minidumpID");
// We're expecting this to be a plugin.
let plugin = aEvent.target;
@ -6171,36 +6210,77 @@ var gMissingPluginInstaller = {
overlay.removeAttribute("role");
#ifdef MOZ_CRASHREPORTER
// Determine which message to show regarding crash reports.
let helpClass, showClass;
// If we didn't submit a report but don't have submission disabled,
// we probably just didn't collect a crash report; don't put up any
// special crashing text.
if (submittedReport) {
helpClass = "submitLink";
if (submittedReport) { // submitReports && !doPrompt, handled in observer
showClass = "msg msgSubmitted";
}
else if (!gCrashReporter.submitReports) {
helpClass = "notSubmitLink";
else if (!submitReports && !doPrompt) {
showClass = "msg msgNotSubmitted";
}
else { // doPrompt
showClass = "msg msgPleaseSubmit";
// XXX can we make the link target actually be blank?
let pleaseLink = doc.getAnonymousElementByAttribute(
plugin, "class", "pleaseSubmitLink");
self.addLinkClickCallback(pleaseLink, "submitReport", minidumpID);
}
if (helpClass) {
let helpLink = doc.getAnonymousElementByAttribute(plugin, "class", helpClass);
helpLink.href = gMissingPluginInstaller.crashReportHelpURL;
let textToShow = doc.getAnonymousElementByAttribute(plugin, "class", showClass);
textToShow.style.display = "block";
// If we don't have a minidumpID, we can't (or didn't) submit anything.
// This can happen if the plugin is killed from the task manager.
if (!minidumpID) {
showClass = "msg msgNoCrashReport";
}
let textToShow = doc.getAnonymousElementByAttribute(plugin, "class", showClass);
textToShow.style.display = "block";
let bottomLinks = doc.getAnonymousElementByAttribute(plugin, "class", "msg msgBottomLinks");
bottomLinks.style.display = "block";
let helpIcon = doc.getAnonymousElementByAttribute(plugin, "class", "helpIcon");
self.addLinkClickCallback(helpIcon, "openHelpPage");
// If we're showing the link to manually trigger report submission, we'll
// want to be able to update all the instances of the UI for this crash to
// show an updated message when a report is submitted.
if (doPrompt) {
let observer = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference]),
observe : function(subject, topic, data) {
let propertyBag = subject;
if (!(propertyBag instanceof Ci.nsIPropertyBag2))
return;
// Ignore notifications for other crashes.
if (propertyBag.get("minidumpID") != minidumpID)
return;
self.updateSubmissionStatus(plugin, propertyBag, data);
},
handleEvent : function(event) {
// Not expected to be called, just here for the closure.
}
}
// Use a weak reference, so we don't have to remove it...
Services.obs.addObserver(observer, "crash-report-status", true);
// ...alas, now we need something to hold a strong reference to prevent
// it from being GC. But I don't want to manually manage the reference's
// lifetime (which should be no greater than the page).
// Clever solution? Use a closue with an event listener on the document.
// When the doc goes away, so do the listener references and the closure.
doc.addEventListener("mozCleverClosureHack", observer, false);
}
#endif
let crashText = doc.getAnonymousElementByAttribute(plugin, "class", "msg msgCrashed");
crashText.textContent = messageString;
let link = doc.getAnonymousElementByAttribute(plugin, "class", "reloadLink");
link.addEventListener("click", function(e) { if (e.isTrusted) browser.reload(); }, true);
let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
let link = doc.getAnonymousElementByAttribute(plugin, "class", "reloadLink");
self.addLinkClickCallback(link, "reloadPage", browser);
let browser = gBrowser.getBrowserForDocument(plugin.ownerDocument
.defaultView.top.document);
let notificationBox = gBrowser.getNotificationBox(browser);
// Is the <object>'s size too small to hold what we want to show?
@ -6216,7 +6296,7 @@ var gMissingPluginInstaller = {
// If another plugin on the page was large enough to show our UI, we
// don't want to show a notification bar.
if (!doc.mozNoPluginCrashedNotification)
showNotificationBar();
showNotificationBar(minidumpID);
} else {
// If a previous plugin on the page was too small and resulted in
// adding a notification bar, then remove it because this plugin
@ -6231,7 +6311,7 @@ var gMissingPluginInstaller = {
notificationBox.removeNotification(notification, true);
}
function showNotificationBar() {
function showNotificationBar(minidumpID) {
// If there's already an existing notification bar, don't do anything.
let notification = notificationBox.getNotificationWithValue("plugin-crashed");
if (notification)
@ -6240,22 +6320,68 @@ var gMissingPluginInstaller = {
// Configure the notification bar
let priority = notificationBox.PRIORITY_WARNING_MEDIUM;
let iconURL = "chrome://mozapps/skin/plugins/pluginGeneric-16.png";
let label = gNavigatorBundle.getString("crashedpluginsMessage.reloadButton.label");
let accessKey = gNavigatorBundle.getString("crashedpluginsMessage.reloadButton.accesskey");
let reloadLabel = gNavigatorBundle.getString("crashedpluginsMessage.reloadButton.label");
let reloadKey = gNavigatorBundle.getString("crashedpluginsMessage.reloadButton.accesskey");
let submitLabel = gNavigatorBundle.getString("crashedpluginsMessage.submitButton.label");
let submitKey = gNavigatorBundle.getString("crashedpluginsMessage.submitButton.accesskey");
let buttons = [{
label: label,
accessKey: accessKey,
popup: null,
callback: function() { browser.reload(); },
}];
let buttons = [
#ifdef MOZ_CRASHREPORTER
{
label: submitLabel,
accessKey: submitKey,
popup: null,
callback: function() { gMissingPluginInstaller.submitReport(minidumpID); },
},
#endif
{
label: reloadLabel,
accessKey: reloadKey,
popup: null,
callback: function() { browser.reload(); },
}];
let notification = notificationBox.appendNotification(messageString, "plugin-crashed",
iconURL, priority, buttons);
// Add the "learn more" link.
let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
let link = notification.ownerDocument.createElementNS(XULNS, "label");
link.className = "text-link";
link.setAttribute("value", gNavigatorBundle.getString("crashedpluginsMessage.learnMore"));
link.href = gMissingPluginInstaller.crashReportHelpURL;
let description = notification.ownerDocument.getAnonymousElementByAttribute(notification, "anonid", "messageText");
description.appendChild(link);
}
},
updateSubmissionStatus : function (plugin, propBag, status) {
let doc = plugin.ownerDocument;
// One of these two may already be visible, reset them to be hidden.
let pleaseText = doc.getAnonymousElementByAttribute(plugin, "class", "msg msgPleaseSubmit");
let submittingText = doc.getAnonymousElementByAttribute(plugin, "class", "msg msgSubmitting");
pleaseText.style.display = "";
submittingText.style.display = "";
let msgClass;
switch (status) {
case "submitting":
msgClass = "msg msgSubmitting";
break;
case "success":
msgClass = "msg msgSubmitted";
break;
case "failed":
msgClass = "msg msgSubmitFailed";
break;
}
let textToShow = doc.getAnonymousElementByAttribute(plugin, "class", msgClass);
textToShow.style.display = "block";
},
refreshBrowser: function (aEvent) {
// browser elements are anonymous so we can't just use target.
var browser = aEvent.originalTarget;

View File

@ -77,6 +77,9 @@ blockedpluginsMessage.searchButton.accesskey=U
crashedpluginsMessage.title=The %S plugin has crashed.
crashedpluginsMessage.reloadButton.label=Reload page
crashedpluginsMessage.reloadButton.accesskey=R
crashedpluginsMessage.submitButton.label=Submit a crash report
crashedpluginsMessage.submitButton.accesskey=S
crashedpluginsMessage.learnMore=Learn More…
# Sanitize
# LOCALIZATION NOTE (sanitizeDialog2.everything.title): When "Time range to

View File

@ -40,6 +40,7 @@
interface nsIFrame;
interface nsIObjectFrame;
interface nsIPluginInstance;
interface nsIPluginTag;
interface nsIDOMElement;
interface nsIDOMClientRect;
@ -124,6 +125,7 @@ interface nsIObjectLoadingContent : nsISupports
*/
[noscript] nsIFrame getPrintFrame();
[noscript] void pluginCrashed(in AString pluginName,
[noscript] void pluginCrashed(in nsIPluginTag pluginTag,
in AString minidumpID,
in boolean submittedCrashReport);
};

View File

@ -221,13 +221,16 @@ nsPluginErrorEvent::Run()
class nsPluginCrashedEvent : public nsRunnable {
public:
nsCOMPtr<nsIContent> mContent;
nsString mMinidumpID;
nsString mPluginName;
PRBool mSubmittedCrashReport;
nsPluginCrashedEvent(nsIContent* aContent,
const nsAString& aMinidumpID,
const nsAString& aPluginName,
PRBool submittedCrashReport)
: mContent(aContent),
mMinidumpID(aMinidumpID),
mPluginName(aPluginName),
mSubmittedCrashReport(submittedCrashReport)
{}
@ -266,6 +269,15 @@ nsPluginCrashedEvent::Run()
nsCOMPtr<nsIWritableVariant> variant;
// add a "minidumpID" property to this event
variant = do_CreateInstance("@mozilla.org/variant;1");
if (!variant) {
NS_WARNING("Couldn't create minidumpID variant for PluginCrashed event!");
return NS_OK;
}
variant->SetAsAString(mMinidumpID);
containerEvent->SetData(NS_LITERAL_STRING("minidumpID"), variant);
// add a "pluginName" property to this event
variant = do_CreateInstance("@mozilla.org/variant;1");
if (!variant) {
@ -2008,15 +2020,23 @@ nsObjectLoadingContent::SetAbsoluteScreenPosition(nsIDOMElement* element,
}
NS_IMETHODIMP
nsObjectLoadingContent::PluginCrashed(const nsAString& pluginName,
nsObjectLoadingContent::PluginCrashed(nsIPluginTag* aPluginTag,
const nsAString& minidumpID,
PRBool submittedCrashReport)
{
AutoNotifier notifier(this, PR_TRUE);
UnloadContent();
mFallbackReason = ePluginCrashed;
nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
// Note that aPluginTag in invalidated after we're called, so copy
// out any data we need now.
nsCAutoString pluginName;
aPluginTag->GetName(pluginName);
nsCOMPtr<nsIRunnable> ev = new nsPluginCrashedEvent(thisContent,
pluginName,
minidumpID,
NS_ConvertUTF8toUTF16(pluginName),
submittedCrashReport);
nsresult rv = NS_DispatchToCurrentThread(ev);
if (NS_FAILED(rv)) {

View File

@ -5035,6 +5035,7 @@ nsPluginHost::PluginCrashed(nsNPAPIPlugin* aPlugin, const nsAString& dumpID)
nsCOMPtr<nsIWritablePropertyBag2> propbag = do_CreateInstance("@mozilla.org/hash-property-bag;1");
if (obsService && propbag) {
propbag->SetPropertyAsAString(NS_LITERAL_STRING("minidumpID"), dumpID);
propbag->SetPropertyAsBool(NS_LITERAL_STRING("submittedCrashReport"), submittedCrashReport);
obsService->NotifyObservers(propbag, "plugin-crashed", nsnull);
// see if an observer submitted a crash report.
propbag->GetPropertyAsBool(NS_LITERAL_STRING("submittedCrashReport"), &submittedCrashReport);
@ -5050,8 +5051,7 @@ nsPluginHost::PluginCrashed(nsNPAPIPlugin* aPlugin, const nsAString& dumpID)
instanceTag->mInstance->GetDOMElement(getter_AddRefs(domElement));
nsCOMPtr<nsIObjectLoadingContent> objectContent(do_QueryInterface(domElement));
if (objectContent) {
objectContent->PluginCrashed(NS_ConvertUTF8toUTF16(pluginTag->mName),
submittedCrashReport);
objectContent->PluginCrashed(pluginTag, dumpID, submittedCrashReport);
}
instanceTag->mInstance->Stop();

View File

@ -35,6 +35,8 @@
*
* ***** END LICENSE BLOCK ***** */
Components.utils.import("resource://gre/modules/Services.jsm");
let EXPORTED_SYMBOLS = [
"CrashSubmit"
];
@ -44,6 +46,10 @@ const Ci = Components.interfaces;
const STATE_START = Ci.nsIWebProgressListener.STATE_START;
const STATE_STOP = Ci.nsIWebProgressListener.STATE_STOP;
const SUCCESS = "success";
const FAILED = "failed";
const SUBMITTING = "submitting";
let reportURL = null;
let strings = null;
let myListener = null;
@ -191,6 +197,7 @@ Submitter.prototype = {
submitSuccess: function Submitter_submitSuccess(ret)
{
if (!ret.CrashID) {
this.notifyStatus(FAILED);
this.cleanup();
return;
}
@ -207,8 +214,7 @@ Submitter.prototype = {
// report an error? not much the user can do here.
}
if (this.successCallback)
this.successCallback(this.id, ret);
this.notifyStatus(SUCCESS, ret);
this.cleanup();
},
@ -272,9 +278,7 @@ Submitter.prototype = {
// check general request status first
if (!Components.isSuccessCode(aStatus)) {
this.element.removeChild(this.iframe);
if (this.errorCallback) {
this.errorCallback(this.id);
}
this.notifyStatus(FAILED);
this.cleanup();
return 0;
}
@ -282,9 +286,7 @@ Submitter.prototype = {
if (aRequest instanceof Ci.nsIHttpChannel &&
aRequest.responseStatus != 200) {
this.element.removeChild(this.iframe);
if (this.errorCallback) {
this.errorCallback(this.id);
}
this.notifyStatus(FAILED);
this.cleanup();
return 0;
}
@ -301,13 +303,39 @@ Submitter.prototype = {
onStatusChange: function() {return 0;},
onSecurityChange: function() {return 0;},
notifyStatus: function Submitter_notify(status, ret)
{
let propBag = Cc["@mozilla.org/hash-property-bag;1"].
createInstance(Ci.nsIWritablePropertyBag2);
propBag.setPropertyAsAString("minidumpID", this.id);
Services.obs.notifyObservers(propBag, "crash-report-status", status);
switch (status) {
case SUCCESS:
if (this.successCallback)
this.successCallback(this.id, ret);
break;
case FAILED:
if (this.errorCallback)
this.errorCallback(this.id);
break;
default:
// no callbacks invoked.
}
},
submit: function Submitter_submit()
{
let [dump, extra] = getPendingMinidump(this.id);
if (!dump.exists() || !extra.exists()) {
this.notifyStatus(FAILED);
this.cleanup();
return false;
}
this.notifyStatus(SUBMITTING);
this.dump = dump;
this.extra = extra;
let iframe = this.document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "iframe");
@ -320,8 +348,10 @@ Submitter.prototype = {
if (iframe.contentWindow.location == "about:blank")
return;
iframe.removeEventListener("load", loadHandler, true);
if (!self.submitForm())
if (!self.submitForm()) {
this.notifyStatus(FAILED);
self.cleanup();
}
}
iframe.addEventListener("load", loadHandler, true);

View File

@ -29,15 +29,10 @@
<!ENTITY reloadPlugin.pre "">
<!ENTITY reloadPlugin.middle "Reload the page">
<!ENTITY reloadPlugin.post " to try again.">
<!-- LOCALIZATION NOTE (submittedCrashReport.pre): include a trailing space as needed -->
<!-- LOCALIZATION NOTE (submittedCrashReport.middle): avoid leading/trailing spaces, this text is a link -->
<!-- LOCALIZATION NOTE (submittedCrashReport.post): include a starting space as needed -->
<!ENTITY submittedCrashReport.pre "A ">
<!ENTITY submittedCrashReport.middle "crash report">
<!ENTITY submittedCrashReport.post " was submitted.">
<!-- LOCALIZATION NOTE (notSubmittedCrashReport.pre): include a trailing space as needed -->
<!-- LOCALIZATION NOTE (notSubmittedCrashReport.middle): avoid leading/trailing spaces, this text is a link -->
<!-- LOCALIZATION NOTE (notSubmittedCrashReport.post): include a starting space as needed -->
<!ENTITY notSubmittedCrashReport.pre "You have disabled ">
<!ENTITY notSubmittedCrashReport.middle "crash report">
<!ENTITY notSubmittedCrashReport.post " submission.">
<!-- LOCALIZATION NOTE (report.please): This and the other report.* strings should be as short as possible, ideally 2-3 words. -->
<!ENTITY report.please "Send crash report">
<!ENTITY report.submitting "Sending report…">
<!ENTITY report.submitted "Crash report sent.">
<!ENTITY report.disabled "Crash reporting disabled.">
<!ENTITY report.failed "Submission failed.">
<!ENTITY report.unavailable "No report available.">

View File

@ -58,9 +58,17 @@
<html:div class="msg msgCrashed"><!-- set at runtime --></html:div>
<html:div class="msg msgReload">&reloadPlugin.pre;<html:a class="reloadLink" href="">&reloadPlugin.middle;</html:a>&reloadPlugin.post;</html:div>
<xul:spacer flex="1"/>
<!-- link hrefs set at runtime -->
<html:div class="msg msgSubmitted">&submittedCrashReport.pre;<html:a class="submitLink" href="">&submittedCrashReport.middle;</html:a>&submittedCrashReport.post;</html:div>
<html:div class="msg msgNotSubmitted">&notSubmittedCrashReport.pre;<html:a class="notSubmitLink" href="">&notSubmittedCrashReport.middle;</html:a>&notSubmittedCrashReport.post;</html:div>
<html:div class="msg msgBottomLinks">
<!-- link href set at runtime -->
<html:div class="msg msgPleaseSubmit"><html:a class="pleaseSubmitLink" href="">&report.please;</html:a></html:div>
<html:div class="msg msgSubmitting">&report.submitting;<html:span class="throbber"> </html:span></html:div>
<html:div class="msg msgSubmitted">&report.submitted;</html:div>
<html:div class="msg msgNotSubmitted">&report.disabled;</html:div>
<html:div class="msg msgSubmitFailed">&report.failed;</html:div>
<html:div class="msg msgNoCrashReport">&report.unavailable;</html:div>
<!-- link href set at runtime -->
<html:span class="helpIcon" role="link"/>
</html:div>
</xul:vbox>
<html:div style="display:none;"><children/></html:div>
</content>

View File

@ -12,6 +12,10 @@ html|applet:not([height]), html|applet[height=""] {
height: 200px;
}
:-moz-type-unsupported .mainBox {
cursor: pointer;
}
:-moz-type-unsupported .mainBox,
:-moz-handler-disabled .mainBox,
:-moz-handler-blocked .mainBox {
@ -40,3 +44,7 @@ html|applet:not([height]), html|applet[height=""] {
:-moz-handler-crashed .msgReload {
display: block;
}
.helpIcon {
cursor: pointer;
}

View File

@ -27,6 +27,7 @@ toolkit.jar:
skin/classic/mozapps/plugins/pluginGeneric-16.png (plugins/pluginGeneric-16.png)
skin/classic/mozapps/plugins/pluginBlocked-16.png (plugins/pluginBlocked-16.png)
skin/classic/mozapps/plugins/pluginOutdated-16.png (plugins/pluginOutdated-16.png)
skin/classic/mozapps/plugins/pluginHelp-16.png (plugins/pluginHelp-16.png)
skin/classic/mozapps/profile/profileicon.png (profile/profileicon.png)
skin/classic/mozapps/profile/profileicon-selected.png (profile/profileicon-selected.png)
skin/classic/mozapps/profile/profileSelection.css (profile/profileSelection.css)

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 B

View File

@ -41,9 +41,35 @@ html|a {
background-image: url(chrome://mozapps/skin/plugins/pluginCrashed.png);
}
.throbber {
padding-left: 16px; /* width of the background image */
background: url(chrome://global/skin/icons/loading_16.png) no-repeat;
margin-left: 5px;
}
.msg {
font: 12px sans-serif;
font-weight: bold;
font: message-box;
font-size: 12px;
cursor: default;
text-shadow: rgba(0,0,0,0.8) 0 0 5px;
}
.msgBottomLinks {
padding-left: 2px;
padding-right: 2px;
}
.msgBottomLinks div {
text-align: right;
margin-right: 4px;
margin-bottom: -19px;
min-height: 19px; /* height of biggest line (with throbber) */
}
.helpIcon {
float: left;
display: inline-block;
min-width: 16px;
min-height: 16px;
background: url(chrome://mozapps/skin/plugins/pluginHelp-16.png) no-repeat;
}

View File

@ -33,6 +33,7 @@ toolkit.jar:
skin/classic/mozapps/plugins/pluginGeneric-16.png (plugins/pluginGeneric-16.png)
skin/classic/mozapps/plugins/pluginBlocked-16.png (plugins/pluginBlocked-16.png)
skin/classic/mozapps/plugins/pluginOutdated-16.png (plugins/pluginOutdated-16.png)
skin/classic/mozapps/plugins/pluginHelp-16.png (plugins/pluginHelp-16.png)
skin/classic/mozapps/plugins/pluginInstallerWizard.css (plugins/pluginInstallerWizard.css)
skin/classic/mozapps/profile/profileicon.png (profile/profileicon.png)
skin/classic/mozapps/profile/profileSelection.css (profile/profileSelection.css)
@ -75,6 +76,7 @@ toolkit.jar:
skin/classic/aero/mozapps/plugins/pluginGeneric-16.png (plugins/pluginGeneric-16-aero.png)
skin/classic/aero/mozapps/plugins/pluginBlocked-16.png (plugins/pluginBlocked-16-aero.png)
skin/classic/aero/mozapps/plugins/pluginOutdated-16.png (plugins/pluginOutdated-16-aero.png)
skin/classic/aero/mozapps/plugins/pluginHelp-16.png (plugins/pluginHelp-16-aero.png)
skin/classic/aero/mozapps/plugins/pluginInstallerWizard.css (plugins/pluginInstallerWizard.css)
skin/classic/aero/mozapps/profile/profileicon.png (profile/profileicon-aero.png)
skin/classic/aero/mozapps/profile/profileSelection.css (profile/profileSelection.css)

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 B

View File

@ -41,9 +41,35 @@ html|a {
background-image: url(chrome://mozapps/skin/plugins/pluginCrashed.png);
}
.throbber {
padding-left: 16px; /* width of the background image */
background: url(chrome://global/skin/icons/loading_16.png) no-repeat;
margin-left: 5px;
}
.msg {
font: 12px sans-serif;
font-weight: bold;
font: message-box;
font-size: 12px;
cursor: default;
text-shadow: rgba(0,0,0,0.8) 0 0 5px;
}
.msgBottomLinks {
padding-left: 2px;
padding-right: 2px;
}
.msgBottomLinks div {
text-align: right;
margin-right: 4px;
margin-bottom: -19px;
min-height: 19px; /* height of biggest line (with throbber) */
}
.helpIcon {
float: left;
display: inline-block;
min-width: 16px;
min-height: 16px;
background: url(chrome://mozapps/skin/plugins/pluginHelp-16.png) no-repeat;
}