mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
Bug 648675 - Allow comments and URL opt-in in content/plugin crash UI. r=dolske,ted
This commit is contained in:
parent
2d7aa1784a
commit
8715a08802
@ -8,6 +8,11 @@ var gPluginHandler = {
|
||||
PLUGIN_SCRIPTED_STATE_FIRED: 1,
|
||||
PLUGIN_SCRIPTED_STATE_DONE: 2,
|
||||
|
||||
getPluginUI: function (plugin, className) {
|
||||
return plugin.ownerDocument.
|
||||
getAnonymousElementByAttribute(plugin, "class", className);
|
||||
},
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
get CrashSubmit() {
|
||||
delete this.CrashSubmit;
|
||||
@ -409,11 +414,16 @@ var gPluginHandler = {
|
||||
},
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
// Callback for user clicking "submit a report" link
|
||||
submitReport : function(pluginDumpID, browserDumpID) {
|
||||
// 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(pluginDumpID);
|
||||
submitReport: function submitReport(pluginDumpID, browserDumpID, plugin) {
|
||||
let keyVals = {};
|
||||
if (plugin) {
|
||||
let userComment = this.getPluginUI(plugin, "submitComment").value.trim();
|
||||
if (userComment)
|
||||
keyVals.PluginUserComment = userComment;
|
||||
if (this.getPluginUI(plugin, "submitURLOptIn").checked)
|
||||
keyVals.PluginContentURL = plugin.ownerDocument.URL;
|
||||
}
|
||||
this.CrashSubmit.submit(pluginDumpID, { extraExtraKeyVals: keyVals });
|
||||
if (browserDumpID)
|
||||
this.CrashSubmit.submit(browserDumpID);
|
||||
},
|
||||
@ -937,11 +947,16 @@ var gPluginHandler = {
|
||||
}
|
||||
else { // doPrompt
|
||||
status = "please";
|
||||
// XXX can we make the link target actually be blank?
|
||||
let pleaseLink = doc.getAnonymousElementByAttribute(
|
||||
plugin, "class", "pleaseSubmitLink");
|
||||
this.addLinkClickCallback(pleaseLink, "submitReport",
|
||||
pluginDumpID, browserDumpID);
|
||||
this.getPluginUI(plugin, "submitButton").addEventListener("click",
|
||||
function (event) {
|
||||
if (event.button != 0 || !event.isTrusted)
|
||||
return;
|
||||
this.submitReport(pluginDumpID, browserDumpID, plugin);
|
||||
pref.setBoolPref("", optInCB.checked);
|
||||
}.bind(this));
|
||||
let optInCB = this.getPluginUI(plugin, "submitURLOptIn");
|
||||
let pref = Services.prefs.getBranch("dom.ipc.plugins.reportCrashURL");
|
||||
optInCB.checked = pref.getBoolPref("");
|
||||
}
|
||||
|
||||
// If we don't have a minidumpID, we can't (or didn't) submit anything.
|
||||
@ -952,8 +967,6 @@ var gPluginHandler = {
|
||||
|
||||
statusDiv.setAttribute("status", status);
|
||||
|
||||
let bottomLinks = doc.getAnonymousElementByAttribute(plugin, "class", "msg msgBottomLinks");
|
||||
bottomLinks.style.display = "block";
|
||||
let helpIcon = doc.getAnonymousElementByAttribute(plugin, "class", "helpIcon");
|
||||
this.addLinkClickCallback(helpIcon, "openHelpPage");
|
||||
|
||||
@ -990,7 +1003,7 @@ var gPluginHandler = {
|
||||
}
|
||||
#endif
|
||||
|
||||
let crashText = doc.getAnonymousElementByAttribute(plugin, "class", "msg msgCrashed");
|
||||
let crashText = doc.getAnonymousElementByAttribute(plugin, "class", "msgCrashedText");
|
||||
crashText.textContent = messageString;
|
||||
|
||||
let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
|
||||
@ -1000,21 +1013,32 @@ var gPluginHandler = {
|
||||
|
||||
let notificationBox = gBrowser.getNotificationBox(browser);
|
||||
|
||||
let isShowing = true;
|
||||
|
||||
// Is the <object>'s size too small to hold what we want to show?
|
||||
if (this.isTooSmall(plugin, overlay)) {
|
||||
// Hide the overlay's contents. Use visibility style, so that it
|
||||
// doesn't collapse down to 0x0.
|
||||
// First try hiding the crash report submission UI.
|
||||
statusDiv.removeAttribute("status");
|
||||
|
||||
if (this.isTooSmall(plugin, overlay)) {
|
||||
// Hide the overlay's contents. Use visibility style, so that it doesn't
|
||||
// collapse down to 0x0.
|
||||
overlay.style.visibility = "hidden";
|
||||
// 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(pluginDumpID, browserDumpID);
|
||||
isShowing = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isShowing) {
|
||||
// If a previous plugin on the page was too small and resulted in adding a
|
||||
// notification bar, then remove it because this plugin instance it big
|
||||
// enough to serve as in-content notification.
|
||||
hideNotificationBar();
|
||||
doc.mozNoPluginCrashedNotification = true;
|
||||
} else {
|
||||
// If a previous plugin on the page was too small and resulted in
|
||||
// adding a notification bar, then remove it because this plugin
|
||||
// instance it big enough to serve as in-content notification.
|
||||
hideNotificationBar();
|
||||
doc.mozNoPluginCrashedNotification = true;
|
||||
// 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(pluginDumpID, browserDumpID);
|
||||
}
|
||||
|
||||
function hideNotificationBar() {
|
||||
|
@ -302,6 +302,8 @@ _BROWSER_FILES = \
|
||||
browser_pageInfo_plugins.js \
|
||||
browser_pageInfo.js \
|
||||
feed_tab.html \
|
||||
browser_pluginCrashCommentAndURL.js \
|
||||
pluginCrashCommentAndURL.html \
|
||||
$(NULL)
|
||||
|
||||
ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))
|
||||
|
154
browser/base/content/test/browser_pluginCrashCommentAndURL.js
Normal file
154
browser/base/content/test/browser_pluginCrashCommentAndURL.js
Normal file
@ -0,0 +1,154 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const CRASH_URL = "http://example.com/browser/browser/base/content/test/pluginCrashCommentAndURL.html";
|
||||
|
||||
const SERVER_URL = "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs";
|
||||
|
||||
function test() {
|
||||
// Crashing the plugin takes up a lot of time, so extend the test timeout.
|
||||
requestLongerTimeout(runs.length);
|
||||
waitForExplicitFinish();
|
||||
|
||||
// The test harness sets MOZ_CRASHREPORTER_NO_REPORT, which disables plugin
|
||||
// crash reports. This test needs them enabled. The test also needs a mock
|
||||
// report server, and fortunately one is already set up by toolkit/
|
||||
// crashreporter/test/Makefile.in. Assign its URL to MOZ_CRASHREPORTER_URL,
|
||||
// which CrashSubmit.jsm uses as a server override.
|
||||
let env = Cc["@mozilla.org/process/environment;1"].
|
||||
getService(Components.interfaces.nsIEnvironment);
|
||||
let noReport = env.get("MOZ_CRASHREPORTER_NO_REPORT");
|
||||
let serverURL = env.get("MOZ_CRASHREPORTER_URL");
|
||||
env.set("MOZ_CRASHREPORTER_NO_REPORT", "");
|
||||
env.set("MOZ_CRASHREPORTER_URL", SERVER_URL);
|
||||
|
||||
let tab = gBrowser.loadOneTab("about:blank", { inBackground: false });
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
browser.addEventListener("PluginCrashed", onCrash, false);
|
||||
Services.obs.addObserver(onSubmitStatus, "crash-report-status", false);
|
||||
|
||||
registerCleanupFunction(function cleanUp() {
|
||||
env.set("MOZ_CRASHREPORTER_NO_REPORT", noReport);
|
||||
env.set("MOZ_CRASHREPORTER_URL", serverURL);
|
||||
gBrowser.selectedBrowser.removeEventListener("PluginCrashed", onCrash,
|
||||
false);
|
||||
Services.obs.removeObserver(onSubmitStatus, "crash-report-status");
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
doNextRun();
|
||||
}
|
||||
|
||||
let runs = [
|
||||
{
|
||||
shouldSubmissionUIBeVisible: true,
|
||||
comment: "",
|
||||
urlOptIn: false,
|
||||
},
|
||||
{
|
||||
shouldSubmissionUIBeVisible: true,
|
||||
comment: "a test comment",
|
||||
urlOptIn: true,
|
||||
},
|
||||
{
|
||||
width: 300,
|
||||
height: 300,
|
||||
shouldSubmissionUIBeVisible: false,
|
||||
},
|
||||
];
|
||||
|
||||
let currentRun = null;
|
||||
|
||||
function doNextRun() {
|
||||
try {
|
||||
if (!runs.length) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
currentRun = runs.shift();
|
||||
let args = ["width", "height"].reduce(function (memo, arg) {
|
||||
if (arg in currentRun)
|
||||
memo[arg] = currentRun[arg];
|
||||
return memo;
|
||||
}, {});
|
||||
gBrowser.loadURI(CRASH_URL + "?" +
|
||||
encodeURIComponent(JSON.stringify(args)));
|
||||
// And now wait for the crash.
|
||||
}
|
||||
catch (err) {
|
||||
failWithException(err);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
function onCrash() {
|
||||
try {
|
||||
let plugin = gBrowser.contentDocument.getElementById("plugin");
|
||||
let elt = gPluginHandler.getPluginUI.bind(gPluginHandler, plugin);
|
||||
let style =
|
||||
gBrowser.contentWindow.getComputedStyle(elt("msg msgPleaseSubmit"));
|
||||
is(style.display,
|
||||
currentRun.shouldSubmissionUIBeVisible ? "block" : "none",
|
||||
"Submission UI visibility should be correct");
|
||||
if (!currentRun.shouldSubmissionUIBeVisible) {
|
||||
// Done with this run.
|
||||
doNextRun();
|
||||
return;
|
||||
}
|
||||
elt("submitComment").value = currentRun.comment;
|
||||
elt("submitURLOptIn").checked = currentRun.urlOptIn;
|
||||
elt("submitButton").click();
|
||||
// And now wait for the submission status notification.
|
||||
}
|
||||
catch (err) {
|
||||
failWithException(err);
|
||||
doNextRun();
|
||||
}
|
||||
}
|
||||
|
||||
function onSubmitStatus(subj, topic, data) {
|
||||
try {
|
||||
// Wait for success or failed, doesn't matter which.
|
||||
if (data != "success" && data != "failed")
|
||||
return;
|
||||
|
||||
let extra = getPropertyBagValue(subj.QueryInterface(Ci.nsIPropertyBag),
|
||||
"extra");
|
||||
ok(extra instanceof Ci.nsIPropertyBag, "Extra data should be property bag");
|
||||
|
||||
let val = getPropertyBagValue(extra, "PluginUserComment");
|
||||
if (currentRun.comment)
|
||||
is(val, currentRun.comment,
|
||||
"Comment in extra data should match comment in textbox");
|
||||
else
|
||||
ok(val === undefined,
|
||||
"Comment should be absent from extra data when textbox is empty");
|
||||
|
||||
val = getPropertyBagValue(extra, "PluginContentURL");
|
||||
if (currentRun.urlOptIn)
|
||||
is(val, gBrowser.currentURI.spec,
|
||||
"URL in extra data should match browser URL when opt-in checked");
|
||||
else
|
||||
ok(val === undefined,
|
||||
"URL should be absent from extra data when opt-in not checked");
|
||||
}
|
||||
catch (err) {
|
||||
failWithException(err);
|
||||
}
|
||||
doNextRun();
|
||||
}
|
||||
|
||||
function getPropertyBagValue(bag, key) {
|
||||
try {
|
||||
var val = bag.getProperty(key);
|
||||
}
|
||||
catch (e if e.result == Cr.NS_ERROR_FAILURE) {}
|
||||
return val;
|
||||
}
|
||||
|
||||
function failWithException(err) {
|
||||
ok(false, "Uncaught exception: " + err + "\n" + err.stack);
|
||||
}
|
27
browser/base/content/test/pluginCrashCommentAndURL.html
Normal file
27
browser/base/content/test/pluginCrashCommentAndURL.html
Normal file
@ -0,0 +1,27 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<script type="text/javascript">
|
||||
function crash() {
|
||||
var plugin = document.getElementById("plugin");
|
||||
var argStr = decodeURIComponent(window.location.search.substr(1));
|
||||
if (argStr) {
|
||||
var args = JSON.parse(argStr);
|
||||
for (var key in args)
|
||||
plugin.setAttribute(key, args[key]);
|
||||
}
|
||||
try {
|
||||
plugin.crash();
|
||||
}
|
||||
catch (err) {}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="crash();">
|
||||
<embed id="plugin" type="application/x-test"
|
||||
width="400" height="400"
|
||||
drawmode="solid" color="FF00FFFF">
|
||||
</embed>
|
||||
</body>
|
||||
</html>
|
@ -86,10 +86,11 @@ function onPluginCrashed(aEvent) {
|
||||
ok(true, "Plugin crashed notification received");
|
||||
is(aEvent.type, "PluginCrashed", "event is correct type");
|
||||
|
||||
let pleaseLink = document.getAnonymousElementByAttribute(
|
||||
aEvent.target, "class", "pleaseSubmitLink");
|
||||
let submitButton = document.getAnonymousElementByAttribute(aEvent.target,
|
||||
"class",
|
||||
"submitButton");
|
||||
// try to submit this report
|
||||
sendMouseEvent({type:'click'}, pleaseLink, window);
|
||||
sendMouseEvent({type:'click'}, submitButton, window);
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
|
@ -112,10 +112,11 @@ function onPluginCrashed(aEvent) {
|
||||
ok(true, "Plugin crashed notification received");
|
||||
is(aEvent.type, "PluginCrashed", "event is correct type");
|
||||
|
||||
let pleaseLink = document.getAnonymousElementByAttribute(
|
||||
aEvent.target, "class", "pleaseSubmitLink");
|
||||
let submitButton = document.getAnonymousElementByAttribute(aEvent.target,
|
||||
"class",
|
||||
"submitButton");
|
||||
// try to submit this report
|
||||
sendMouseEvent({type:'click'}, pleaseLink, window);
|
||||
sendMouseEvent({type:'click'}, submitButton, window);
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
|
@ -1815,6 +1815,7 @@ pref("dom.ipc.plugins.java.enabled", false);
|
||||
#endif
|
||||
|
||||
pref("dom.ipc.plugins.flash.subprocess.crashreporter.enabled", true);
|
||||
pref("dom.ipc.plugins.reportCrashURL", true);
|
||||
|
||||
pref("dom.ipc.processCount", 1);
|
||||
|
||||
|
@ -186,12 +186,14 @@ function writeSubmittedReport(crashID, viewURL) {
|
||||
}
|
||||
|
||||
// the Submitter class represents an individual submission.
|
||||
function Submitter(id, submitSuccess, submitError, noThrottle) {
|
||||
function Submitter(id, submitSuccess, submitError, noThrottle,
|
||||
extraExtraKeyVals) {
|
||||
this.id = id;
|
||||
this.successCallback = submitSuccess;
|
||||
this.errorCallback = submitError;
|
||||
this.noThrottle = noThrottle;
|
||||
this.additionalDumps = [];
|
||||
this.extraKeyVals = extraExtraKeyVals || {};
|
||||
}
|
||||
|
||||
Submitter.prototype = {
|
||||
@ -238,13 +240,10 @@ Submitter.prototype = {
|
||||
|
||||
submitForm: function Submitter_submitForm()
|
||||
{
|
||||
let reportData = parseKeyValuePairsFromFile(this.extra);
|
||||
if (!('ServerURL' in reportData)) {
|
||||
if (!('ServerURL' in this.extraKeyVals)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let serverURL = reportData.ServerURL;
|
||||
delete reportData.ServerURL;
|
||||
let serverURL = this.extraKeyVals.ServerURL;
|
||||
|
||||
// Override the submission URL from the environment or prefs.
|
||||
|
||||
@ -253,7 +252,7 @@ Submitter.prototype = {
|
||||
if (envOverride != '') {
|
||||
serverURL = envOverride;
|
||||
}
|
||||
else if ('PluginHang' in reportData) {
|
||||
else if ('PluginHang' in this.extraKeyVals) {
|
||||
try {
|
||||
serverURL = Services.prefs.
|
||||
getCharPref("toolkit.crashreporter.pluginHangSubmitURL");
|
||||
@ -266,9 +265,11 @@ Submitter.prototype = {
|
||||
|
||||
let formData = Cc["@mozilla.org/files/formdata;1"]
|
||||
.createInstance(Ci.nsIDOMFormData);
|
||||
// add the other data
|
||||
for (let [name, value] in Iterator(reportData)) {
|
||||
formData.append(name, value);
|
||||
// add the data
|
||||
for (let [name, value] in Iterator(this.extraKeyVals)) {
|
||||
if (name != "ServerURL") {
|
||||
formData.append(name, value);
|
||||
}
|
||||
}
|
||||
if (this.noThrottle) {
|
||||
// tell the server not to throttle this, since it was manually submitted
|
||||
@ -311,6 +312,13 @@ Submitter.prototype = {
|
||||
propBag.setPropertyAsAString("serverCrashID", ret.CrashID);
|
||||
}
|
||||
|
||||
let extraKeyValsBag = Cc["@mozilla.org/hash-property-bag;1"].
|
||||
createInstance(Ci.nsIWritablePropertyBag2);
|
||||
for (let key in this.extraKeyVals) {
|
||||
extraKeyValsBag.setPropertyAsAString(key, this.extraKeyVals[key]);
|
||||
}
|
||||
propBag.setPropertyAsInterface("extra", extraKeyValsBag);
|
||||
|
||||
Services.obs.notifyObservers(propBag, "crash-report-status", status);
|
||||
|
||||
switch (status) {
|
||||
@ -336,10 +344,16 @@ Submitter.prototype = {
|
||||
return false;
|
||||
}
|
||||
|
||||
let reportData = parseKeyValuePairsFromFile(extra);
|
||||
let extraKeyVals = parseKeyValuePairsFromFile(extra);
|
||||
for (let key in extraKeyVals) {
|
||||
if (!(key in this.extraKeyVals)) {
|
||||
this.extraKeyVals[key] = extraKeyVals[key];
|
||||
}
|
||||
}
|
||||
|
||||
let additionalDumps = [];
|
||||
if ("additional_minidumps" in reportData) {
|
||||
let names = reportData.additional_minidumps.split(',');
|
||||
if ("additional_minidumps" in this.extraKeyVals) {
|
||||
let names = this.extraKeyVals.additional_minidumps.split(',');
|
||||
for (let name of names) {
|
||||
let [dump, extra] = getPendingMinidump(this.id + "-" + name);
|
||||
if (!dump.exists()) {
|
||||
@ -391,6 +405,11 @@ this.CrashSubmit = {
|
||||
* it should be processed right away. This should be set
|
||||
* when the report is being submitted and the user expects
|
||||
* to see the results immediately. Defaults to false.
|
||||
* - extraExtraKeyVals
|
||||
* An object whose key-value pairs will be merged with the data from
|
||||
* the ".extra" file submitted with the report. The properties of
|
||||
* this object will override properties of the same name in the
|
||||
* .extra file.
|
||||
*
|
||||
* @return true if the submission began successfully, or false if
|
||||
* it failed for some reason. (If the dump file does not
|
||||
@ -402,6 +421,7 @@ this.CrashSubmit = {
|
||||
let submitSuccess = null;
|
||||
let submitError = null;
|
||||
let noThrottle = false;
|
||||
let extraExtraKeyVals = null;
|
||||
|
||||
if ('submitSuccess' in params)
|
||||
submitSuccess = params.submitSuccess;
|
||||
@ -409,11 +429,14 @@ this.CrashSubmit = {
|
||||
submitError = params.submitError;
|
||||
if ('noThrottle' in params)
|
||||
noThrottle = params.noThrottle;
|
||||
if ('extraExtraKeyVals' in params)
|
||||
extraExtraKeyVals = params.extraExtraKeyVals;
|
||||
|
||||
let submitter = new Submitter(id,
|
||||
submitSuccess,
|
||||
submitError,
|
||||
noThrottle);
|
||||
noThrottle,
|
||||
extraExtraKeyVals);
|
||||
CrashSubmit._activeSubmissions.push(submitter);
|
||||
return submitter.submit();
|
||||
},
|
||||
|
@ -56,6 +56,8 @@
|
||||
<!ENTITY report.disabled "Crash reporting disabled.">
|
||||
<!ENTITY report.failed "Submission failed.">
|
||||
<!ENTITY report.unavailable "No report available.">
|
||||
<!ENTITY report.comment "Add a comment (comments are publicly visible)">
|
||||
<!ENTITY report.pageURL "Include the page's URL">
|
||||
|
||||
<!ENTITY plugin.file "File">
|
||||
<!ENTITY plugin.mimeTypes "MIME Types">
|
||||
|
@ -37,27 +37,36 @@
|
||||
<html:div class="msg msgClickToPlay">&clickToActivatePlugin;</html:div>
|
||||
<html:div class="msg msgDisabled">&disabledPlugin;</html:div>
|
||||
<html:div class="msg msgBlocked">&blockedPlugin.label;</html:div>
|
||||
<html:div class="msg msgCrashed"><!-- set at runtime --></html:div>
|
||||
<html:div class="msg msgCrashed">
|
||||
<html:div class="msgCrashedText"><!-- set at runtime --></html:div>
|
||||
<!-- link href set at runtime -->
|
||||
<html:div class="msgReload">&reloadPlugin.pre;<html:a class="reloadLink" href="">&reloadPlugin.middle;</html:a>&reloadPlugin.post;</html:div>
|
||||
</html:div>
|
||||
|
||||
<html:div class="installStatus">
|
||||
<html:div class="msg msgInstallPlugin"><html:a class="installPluginLink" href="">&installPlugin;</html:a></html:div>
|
||||
</html:div>
|
||||
<html:div class="msg msgManagePlugins"><html:a class="managePluginsLink" href="">&managePlugins;</html:a></html:div>
|
||||
<html:div class="submitStatus">
|
||||
<!-- links set at runtime -->
|
||||
<html:div class="msg msgPleaseSubmit"><html:a class="pleaseSubmitLink" href="">&report.please;</html:a></html:div>
|
||||
<html:div class="msg msgPleaseSubmit">
|
||||
<html:textarea class="submitComment"
|
||||
placeholder="&report.comment;"/>
|
||||
<html:div class="submitURLOptInBox">
|
||||
<html:label><html:input class="submitURLOptIn" type="checkbox"/> &report.pageURL;</html:label>
|
||||
</html:div>
|
||||
<html:div class="submitButtonBox">
|
||||
<html:span class="helpIcon" role="link"/>
|
||||
<html:input class="submitButton" type="button"
|
||||
value="&report.please;"/>
|
||||
</html:div>
|
||||
</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:div class="msg msgReload">&reloadPlugin.pre;<html:a class="reloadLink" href="">&reloadPlugin.middle;</html:a>&reloadPlugin.post;</html:div>
|
||||
</html:div>
|
||||
<xul:spacer flex="1"/>
|
||||
<html:div class="msg msgBottomLinks">
|
||||
<html:span class="helpIcon" role="link"/>
|
||||
</html:div>
|
||||
</xul:vbox>
|
||||
</xul:vbox>
|
||||
<html:div class="previewPluginContent"><!-- iframe and its src will be set at runtime --></html:div>
|
||||
|
@ -104,21 +104,18 @@ html|applet:not([height]), html|applet[height=""] {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.submitStatus[status] {
|
||||
display: -moz-box;
|
||||
-moz-box-align: center;
|
||||
-moz-box-pack: center;
|
||||
height: 160px;
|
||||
}
|
||||
|
||||
.submitStatus[status="noReport"] .msgNoCrashReport,
|
||||
.submitStatus[status="please"] .msgPleaseSubmit,
|
||||
.submitStatus[status="noSubmit"] .msgNotSubmitted,
|
||||
.submitStatus[status="submitting"] .msgSubmitting,
|
||||
.submitStatus[status="success"] .msgSubmitted,
|
||||
.submitStatus[status="failed"] .msgSubmitFailed,
|
||||
.submitStatus[status]:not([status="please"]) .msgReload {
|
||||
.submitStatus[status="failed"] .msgSubmitFailed {
|
||||
display: block;
|
||||
}
|
||||
.submitStatus[status="please"] .msgReload {
|
||||
/* Take up space when invisible, so stuff doesn't shift upon reveal. */
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.helpIcon {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@ -100,17 +100,53 @@ html|a {
|
||||
min-height: 19px; /* height of biggest line (with throbber) */
|
||||
}
|
||||
|
||||
.msgBottomLinks {
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
.submitComment {
|
||||
width: 340px;
|
||||
height: 70px;
|
||||
padding: 5px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
resize: none;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.submitURLOptInBox {
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.submitURLOptIn {
|
||||
margin-left: -1px;
|
||||
}
|
||||
|
||||
.mainBox[chromedir="rtl"] .submitURLOptIn {
|
||||
margin-left: 0;
|
||||
margin-right: -1px;
|
||||
}
|
||||
|
||||
.submitButtonBox {
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.submitButton {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.mainBox[chromedir="rtl"] .submitButton {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.helpIcon {
|
||||
float: left;
|
||||
display: inline-block;
|
||||
min-width: 16px;
|
||||
min-height: 16px;
|
||||
background: url(chrome://mozapps/skin/plugins/pluginHelp-16.png) no-repeat;
|
||||
cursor: pointer;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.mainBox[chromedir="rtl"] .helpIcon {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.closeIcon {
|
||||
|
@ -109,17 +109,53 @@ html|a {
|
||||
min-height: 19px; /* height of biggest line (with throbber) */
|
||||
}
|
||||
|
||||
.msgBottomLinks {
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
.submitComment {
|
||||
width: 340px;
|
||||
height: 70px;
|
||||
padding: 5px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
resize: none;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.submitURLOptInBox {
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.submitURLOptIn {
|
||||
margin-left: -1px;
|
||||
}
|
||||
|
||||
.mainBox[chromedir="rtl"] .submitURLOptIn {
|
||||
margin-left: 0;
|
||||
margin-right: -1px;
|
||||
}
|
||||
|
||||
.submitButtonBox {
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.submitButton {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.mainBox[chromedir="rtl"] .submitButton {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.helpIcon {
|
||||
float: left;
|
||||
display: inline-block;
|
||||
min-width: 16px;
|
||||
min-height: 16px;
|
||||
background: url(chrome://mozapps/skin/plugins/pluginHelp-16.png) no-repeat;
|
||||
cursor: pointer;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.mainBox[chromedir="rtl"] .helpIcon {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.closeIcon {
|
||||
|
Loading…
Reference in New Issue
Block a user