Bug 1112304: Update about:tabcrashed to match the new UX spec. r=dao

Uses in-content styles for the tab crash page and adds an overlay to the favicon
for crashed tabs. Adds support for closing the crashed tab. The strings here
also refer to being able to restore all tabs, that will be implemented and
landed at the same time in bug 1109650 to avoid l10n churn.
This commit is contained in:
Dave Townsend 2015-01-13 12:33:26 -08:00
parent feb66be0d1
commit 9ddcb19cae
25 changed files with 250 additions and 162 deletions

View File

@ -0,0 +1,8 @@
/* 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/. */
html:not(.crashDumpSubmitted) #reportSent,
html:not(.crashDumpAvailable) #report-box {
display: none;
}

View File

@ -12,21 +12,31 @@ function parseQueryString() {
document.title = parseQueryString();
addEventListener("DOMContentLoaded", () => {
let tryAgain = document.getElementById("tryAgain");
let sendCrashReport = document.getElementById("checkSendReport");
function shouldSendReport() {
if (!document.documentElement.classList.contains("crashDumpAvailable"))
return false;
return document.getElementById("sendReport").checked;
}
tryAgain.addEventListener("click", () => {
let event = new CustomEvent("AboutTabCrashedTryAgain", {
bubbles: true,
detail: {
sendCrashReport: sendCrashReport.checked,
},
});
document.dispatchEvent(event);
function sendEvent(message) {
let event = new CustomEvent("AboutTabCrashedMessage", {
bubbles: true,
detail: {
message,
sendCrashReport: shouldSendReport(),
},
});
});
document.dispatchEvent(event);
}
function closeTab() {
sendEvent("closeTab");
}
function restoreTab() {
sendEvent("restoreTab");
}
// Error pages are loaded as LOAD_BACKGROUND, so they don't get load events.
var event = new CustomEvent("AboutTabCrashedLoad", {bubbles:true});

View File

@ -12,18 +12,19 @@
<!ENTITY % globalDTD
SYSTEM "chrome://global/locale/global.dtd">
%globalDTD;
<!ENTITY % browserDTD
SYSTEM "chrome://browser/locale/browser.dtd">
%browserDTD;
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
%brandDTD;
<!ENTITY % tabCrashedDTD
SYSTEM "chrome://browser/locale/aboutTabCrashed.dtd">
%tabCrashedDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="stylesheet" type="text/css" media="all"
href="chrome://global/skin/in-content/info-pages.css"/>
<link rel="stylesheet" type="text/css" media="all"
href="chrome://browser/content/aboutTabCrashed.css"/>
<link rel="stylesheet" type="text/css" media="all"
href="chrome://browser/skin/aboutTabCrashed.css"/>
</head>
@ -36,12 +37,17 @@
<p>&tabCrashed.message;</p>
<div id="report-box">
<input type="checkbox" id="checkSendReport" checked="checked"/>
<label for="checkSendReport">&tabCrashed.checkSendReport;</label>
<input type="checkbox" id="sendReport" checked="checked"/>
<label for="sendReport">&tabCrashed.sendReport;</label>
</div>
<p id="reportSent">&tabCrashed.reportSent;</p>
<div class="button-container">
<button id="tryAgain">&tabCrashed.tryAgain;</button>
<button id="closeTab" onclick="closeTab()">
&tabCrashed.closeTab;</button>
<button id="restoreTab" onclick="restoreTab()">
&tabCrashed.restoreTab;</button>
</div>
</div>
</body>

View File

@ -1116,7 +1116,7 @@ var gBrowserInit = {
#endif
}, false, true);
gBrowser.addEventListener("AboutTabCrashedTryAgain", function(event) {
gBrowser.addEventListener("AboutTabCrashedMessage", function(event) {
let ownerDoc = event.originalTarget;
if (!ownerDoc.documentURI.startsWith("about:tabcrashed")) {
@ -1134,8 +1134,16 @@ var gBrowserInit = {
TabCrashReporter.submitCrashReport(browser);
}
#endif
let tab = gBrowser.getTabForBrowser(browser);
SessionStore.reviveCrashedTab(tab);
switch (event.detail.message) {
case "closeTab":
gBrowser.removeTab(tab, { animate: true });
break;
case "restoreTab":
SessionStore.reviveCrashedTab(tab);
break;
}
}, false, true);
let uriToLoad = this._getUriToLoad();

View File

@ -51,9 +51,10 @@ tabpanels {
}
}
.tab-icon-image:not([src]):not([pinned]),
.tab-icon-image:not([src]):not([pinned]):not([crashed]),
.tab-throbber:not([busy]),
.tab-throbber[busy] + .tab-icon-image {
.tab-icon-image[busy],
.tab-icon-overlay[busy] {
display: none;
}

View File

@ -664,9 +664,13 @@
// We need to add 2 because loadURIWithFlags may have
// cancelled a pending load which would have cleared
// its anchor scroll detection temporary increment.
if (aWebProgress.isTopLevel)
if (aWebProgress.isTopLevel) {
this.mBrowser.userTypedClear += 2;
// If the browser is loading it must not be crashed anymore
this.mTab.removeAttribute("crashed");
}
if (this._shouldShowProgress(aRequest)) {
if (!(aStateFlags & nsIWebProgressListener.STATE_RESTORING)) {
this.mTab.setAttribute("busy", "true");
@ -3579,6 +3583,7 @@
browser.docShell.displayLoadError(Cr.NS_ERROR_CONTENT_CRASHED, uri, null);
browser.removeAttribute("crashedPageTitle");
let tab = this.getTabForBrowser(browser);
tab.setAttribute("crashed", true);
this.setIcon(tab, icon);
]]>
</handler>
@ -4980,11 +4985,14 @@
class="tab-throbber"
role="presentation"
layer="true" />
<xul:image xbl:inherits="src=image,fadein,pinned,selected"
<xul:image xbl:inherits="src=image,fadein,pinned,selected,busy,crashed"
anonid="tab-icon-image"
class="tab-icon-image"
validate="never"
role="presentation"/>
<xul:image xbl:inherits="crashed,busy"
class="tab-icon-overlay"
role="presentation"/>
<xul:label flex="1"
anonid="tab-label"
xbl:inherits="value=visibleLabel,crop,accesskey,fadein,pinned,selected"

View File

@ -69,6 +69,7 @@ browser.jar:
content/browser/aboutRobots-widget-left.png (content/aboutRobots-widget-left.png)
content/browser/aboutSocialError.xhtml (content/aboutSocialError.xhtml)
content/browser/aboutProviderDirectory.xhtml (content/aboutProviderDirectory.xhtml)
content/browser/aboutTabCrashed.css (content/aboutTabCrashed.css)
content/browser/aboutTabCrashed.js (content/aboutTabCrashed.js)
content/browser/aboutTabCrashed.xhtml (content/aboutTabCrashed.xhtml)
* content/browser/browser.css (content/browser.css)

View File

@ -6,6 +6,12 @@
const PAGE_1 = "data:text/html,<html><body>A%20regular,%20everyday,%20normal%20page.";
const PAGE_2 = "data:text/html,<html><body>Another%20regular,%20everyday,%20normal%20page.";
// Turn off tab animations for testing
Services.prefs.setBoolPref("browser.tabs.animate", false);
registerCleanupFunction(() => {
Services.prefs.clearUserPref("browser.tabs.animate");
});
/**
* Returns a Promise that resolves once a remote <xul:browser> has experienced
* a crash. Also does the job of cleaning up the minidump of the crash.
@ -58,6 +64,7 @@ function crashBrowser(browser) {
}
Services.obs.removeObserver(observer, 'ipc:content-shutdown');
info("Crash cleaned up");
resolve();
};
@ -67,6 +74,7 @@ function crashBrowser(browser) {
let aboutTabCrashedLoadPromise = new Promise((resolve, reject) => {
browser.addEventListener("AboutTabCrashedLoad", function onCrash() {
browser.removeEventListener("AboutTabCrashedLoad", onCrash, false);
info("about:tabcrashed loaded");
resolve();
}, false, true);
});
@ -75,7 +83,22 @@ function crashBrowser(browser) {
// evaluated.
let mm = browser.messageManager;
mm.loadFrameScript("data:,(" + frame_script.toString() + ")();", false);
return Promise.all([crashCleanupPromise, aboutTabCrashedLoadPromise]);
return Promise.all([crashCleanupPromise, aboutTabCrashedLoadPromise]).then(() => {
let tab = gBrowser.getTabForBrowser(browser);
is(tab.getAttribute("crashed"), "true", "Tab should be marked as crashed");
});
}
function clickButton(browser, id) {
info("Clicking " + id);
let frame_script = (id) => {
let button = content.document.getElementById(id);
button.click();
};
let mm = browser.messageManager;
mm.loadFrameScript("data:,(" + frame_script.toString() + ")('" + id + "');", false);
}
/**
@ -232,6 +255,7 @@ add_task(function test_revived_history_from_remote() {
// become remote again.
browser.loadURI(PAGE_2);
yield promiseTabRestored(newTab);
ok(!newTab.hasAttribute("crashed"), "Tab shouldn't be marked as crashed anymore.");
ok(browser.isRemoteBrowser, "Should be a remote browser");
TabState.flush(browser);
@ -272,6 +296,7 @@ add_task(function test_revived_history_from_non_remote() {
// become remote again.
browser.loadURI("about:mozilla");
yield promiseBrowserLoaded(browser);
ok(!newTab.hasAttribute("crashed"), "Tab shouldn't be marked as crashed anymore.");
ok(!browser.isRemoteBrowser, "Should not be a remote browser");
TabState.flush(browser);
@ -301,6 +326,14 @@ add_task(function test_revive_tab_from_session_store() {
browser.loadURI(PAGE_1);
yield promiseBrowserLoaded(browser);
let newTab2 = gBrowser.addTab();
let browser2 = newTab2.linkedBrowser;
ok(browser2.isRemoteBrowser, "Should be a remote browser");
yield promiseBrowserLoaded(browser2);
browser.loadURI(PAGE_1);
yield promiseBrowserLoaded(browser);
browser.loadURI(PAGE_2);
yield promiseBrowserLoaded(browser);
@ -308,12 +341,17 @@ add_task(function test_revive_tab_from_session_store() {
// Crash the tab
yield crashBrowser(browser);
is(newTab2.getAttribute("crashed"), "true", "Second tab should be crashed too.");
// Flush out any notifications from the crashed browser.
TabState.flush(browser);
// Use SessionStore to revive the tab
SessionStore.reviveCrashedTab(newTab);
clickButton(browser, "restoreTab");
yield promiseBrowserLoaded(browser);
ok(!newTab.hasAttribute("crashed"), "Tab shouldn't be marked as crashed anymore.");
is(newTab2.getAttribute("crashed"), "true", "Second tab should still be crashed though.");
// We can't just check browser.currentURI.spec, because from
// the outside, a crashed tab has the same URI as the page
@ -325,4 +363,35 @@ add_task(function test_revive_tab_from_session_store() {
yield promiseHistoryLength(browser, 2);
gBrowser.removeTab(newTab);
});
gBrowser.removeTab(newTab2);
});
/**
* Checks that about:tabcrashed can close the current tab
*/
add_task(function test_close_tab_after_crash() {
let newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
let browser = newTab.linkedBrowser;
ok(browser.isRemoteBrowser, "Should be a remote browser");
yield promiseBrowserLoaded(browser);
browser.loadURI(PAGE_1);
yield promiseBrowserLoaded(browser);
TabState.flush(browser);
// Crash the tab
yield crashBrowser(browser);
// Flush out any notifications from the crashed browser.
TabState.flush(browser);
let promise = promiseEvent(gBrowser.tabContainer, "TabClose");
// Click the close tab button
clickButton(browser, "closeTab");
yield promise;
is(gBrowser.tabs.length, 1, "Should have closed the tab");
});

View File

@ -488,15 +488,19 @@ function promiseDelayedStartupFinished(aWindow) {
return new Promise(resolve => whenDelayedStartupFinished(aWindow, resolve));
}
function promiseTabRestored(tab) {
function promiseEvent(element, eventType, isCapturing = false) {
return new Promise(resolve => {
tab.addEventListener("SSTabRestored", function onRestored() {
tab.removeEventListener("SSTabRestored", onRestored);
resolve();
});
element.addEventListener(eventType, function listener(event) {
element.removeEventListener(eventType, listener, isCapturing);
resolve(event);
}, isCapturing);
});
}
function promiseTabRestored(tab) {
return promiseEvent(tab, "SSTabRestored");
}
function sendMessage(browser, name, data = {}) {
browser.messageManager.sendAsyncMessage(name, data);
return promiseContentMessage(browser, name);

View File

@ -0,0 +1,10 @@
<!-- 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/. -->
<!ENTITY tabCrashed.header "Bad news first: This tab has crashed">
<!ENTITY tabCrashed.message "Now for the good news: You can just close this tab, restore it or restore all your crashed tabs.">
<!ENTITY tabCrashed.sendReport "Submit a crash report to help prevent more bad news">
<!ENTITY tabCrashed.reportSent "Crash report already submitted; thank you for helping make &brandShortName; better!">
<!ENTITY tabCrashed.closeTab "Close This Tab">
<!ENTITY tabCrashed.restoreTab "Restore This Tab">

View File

@ -795,11 +795,6 @@ just addresses the organization to follow, e.g. "This site is run by " -->
a CSS length value. -->
<!ENTITY pluginNotification.width "28em">
<!ENTITY tabCrashed.header "Tab crashed">
<!ENTITY tabCrashed.message "Well, this is embarrassing. We tried to display this Web page, but it's not responding.">
<!ENTITY tabCrashed.checkSendReport "Tell &vendorShortName; about this crash so they can fix it.">
<!ENTITY tabCrashed.tryAgain "Try Again">
<!ENTITY uiTour.infoPanel.close "Close">
<!ENTITY appMenuSidebars.label "Sidebars">

View File

@ -18,6 +18,7 @@
locale/browser/aboutHealthReport.dtd (%chrome/browser/aboutHealthReport.dtd)
#endif
locale/browser/aboutSessionRestore.dtd (%chrome/browser/aboutSessionRestore.dtd)
locale/browser/aboutTabCrashed.dtd (%chrome/browser/aboutTabCrashed.dtd)
#ifdef MOZ_SERVICES_SYNC
locale/browser/syncProgress.dtd (%chrome/browser/syncProgress.dtd)
locale/browser/syncCustomize.dtd (%chrome/browser/syncCustomize.dtd)

View File

@ -82,6 +82,7 @@ this.TabCrashReporter = {
if (this.browserMap.get(browser) == childID) {
this.browserMap.delete(browser);
browser.contentDocument.documentElement.classList.remove("crashDumpAvailable");
browser.contentDocument.documentElement.classList.add("crashDumpSubmitted");
}
}
}

View File

@ -1,108 +0,0 @@
body {
background-color: rgb(241, 244, 248);
margin-top: 2em;
font: message-box;
font-size: 100%;
}
p {
font-size: .8em;
}
#error-box {
background: url('chrome://global/skin/icons/information-24.png') no-repeat left 4px;
-moz-padding-start: 30px;
}
#error-box:-moz-locale-dir(rtl) {
background-position: right 4px;
}
#main-error-msg {
color: #4b4b4b;
font-weight: bold;
}
#report-box {
text-align: center;
width: 75%;
margin: 0 auto;
display: none;
}
.crashDumpAvailable #report-box {
display: block
}
#button-box {
text-align: center;
width: 75%;
margin: 0 auto;
}
@media all and (min-width: 300px) {
#error-box {
max-width: 50%;
margin: 0 auto;
background-image: url('chrome://global/skin/icons/information-32.png');
min-height: 36px;
-moz-padding-start: 38px;
}
button {
width: auto !important;
min-width: 150px;
}
}
@media all and (min-width: 780px) {
#error-box {
max-width: 30%;
}
}
button {
font: message-box;
font-size: 0.6875em;
-moz-appearance: none;
-moz-user-select: none;
width: 100%;
margin: 2px 0;
padding: 2px 6px;
line-height: 1.2;
background-color: hsla(210,30%,95%,.1);
background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
background-clip: padding-box;
border: 1px solid hsla(210,15%,25%,.4);
border-color: hsla(210,15%,25%,.3) hsla(210,15%,25%,.35) hsla(210,15%,25%,.4);
border-radius: 3px;
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
0 0 0 1px hsla(0,0%,100%,.3) inset,
0 1px 0 hsla(0,0%,100%,.1);
transition-property: background-color, border-color, box-shadow;
transition-duration: 150ms;
transition-timing-function: ease;
}
button:hover {
background-color: hsla(210,30%,95%,.8);
border-color: hsla(210,15%,25%,.45) hsla(210,15%,25%,.5) hsla(210,15%,25%,.55);
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
0 0 0 1px hsla(0,0%,100%,.3) inset,
0 1px 0 hsla(0,0%,100%,.1),
0 0 3px hsla(210,15%,25%,.1);
transition-property: background-color, border-color, box-shadow;
transition-duration: 150ms;
transition-timing-function: ease;
}
button:hover:active {
background-color: hsla(210,15%,25%,.2);
box-shadow: 0 1px 1px hsla(210,15%,25%,.2) inset,
0 0 2px hsla(210,15%,25%,.4) inset;
transition-property: background-color, border-color, box-shadow;
transition-duration: 10ms;
transition-timing-function: linear;
}

View File

@ -191,6 +191,7 @@ browser.jar:
skin/classic/browser/tabbrowser/alltabs.png (tabbrowser/alltabs.png)
skin/classic/browser/tabbrowser/alltabs-inverted.png (tabbrowser/alltabs-inverted.png)
skin/classic/browser/tabbrowser/connecting.png (tabbrowser/connecting.png)
skin/classic/browser/tabbrowser/crashed.svg (../shared/tabbrowser/crashed.svg)
skin/classic/browser/tabbrowser/loading.png (tabbrowser/loading.png)
skin/classic/browser/tabbrowser/tab-active-middle.png (tabbrowser/tab-active-middle.png)
skin/classic/browser/tabbrowser/tab-arrow-left.png (tabbrowser/tab-arrow-left.png)

View File

@ -3092,6 +3092,14 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
opacity: .9;
}
/*
* Force the overlay to create a new stacking context so it always appears on
* top of the icon.
*/
.tab-icon-overlay {
opacity: 0.9999;
}
.tab-label:not([selected="true"]) {
opacity: .7;
}

View File

@ -301,6 +301,7 @@ browser.jar:
skin/classic/browser/tabbrowser/alltabs-box-bkgnd-icon.png (tabbrowser/alltabs-box-bkgnd-icon.png)
skin/classic/browser/tabbrowser/alltabs-box-bkgnd-icon-inverted.png (tabbrowser/alltabs-box-bkgnd-icon-inverted.png)
skin/classic/browser/tabbrowser/alltabs-box-bkgnd-icon-inverted@2x.png (tabbrowser/alltabs-box-bkgnd-icon-inverted@2x.png)
skin/classic/browser/tabbrowser/crashed.svg (../shared/tabbrowser/crashed.svg)
skin/classic/browser/tabbrowser/newtab.png (tabbrowser/newtab.png)
skin/classic/browser/tabbrowser/newtab@2x.png (tabbrowser/newtab@2x.png)
skin/classic/browser/tabbrowser/newtab-inverted.png (tabbrowser/newtab-inverted.png)

View File

@ -1,11 +1,11 @@
/* 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/. */
.title {
background-image: url("chrome://browser/skin/tab-crashed.svg");
}
#report-box {
display: none;
#reportSent {
font-weight: bold;
}
.crashDumpAvailable #report-box {
display: block
}

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="22 22 16 16" enable-background="new 22 22 16 16" xml:space="preserve">
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="30" y1="23" x2="30" y2="37">
<stop offset="0" style="stop-color:#E63B2E"/>
<stop offset="1" style="stop-color:#C33931"/>
</linearGradient>
<circle fill="url(#SVGID_1_)" cx="30" cy="30" r="7"/>
<g>
<path fill="#FFFFFF" d="M31.03,33.304c0,0.6-0.479,1.092-1.091,1.092c-0.6,0-1.079-0.492-1.079-1.092
c0-0.588,0.479-1.079,1.079-1.079C30.551,32.225,31.03,32.716,31.03,33.304z M29.171,31.133l-0.24-5.253h2.015l-0.24,5.253H29.171z
"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 970 B

View File

@ -65,6 +65,10 @@
-moz-padding-start: 9px;
}
.tab-content[pinned] {
-moz-padding-end: 3px;
}
.tab-throbber,
.tab-icon-image,
.tab-close-button {
@ -75,12 +79,26 @@
.tab-icon-image {
height: 16px;
width: 16px;
-moz-margin-end: 6px;
}
.tab-icon-image {
list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
}
.tab-icon-overlay {
width: 16px;
height: 16px;
margin-top: 10px;
-moz-margin-start: -16px;
display: none;
}
.tab-icon-overlay[crashed] {
display: -moz-box;
list-style-image: url("chrome://browser/skin/tabbrowser/crashed.svg");
}
.tab-throbber[busy] {
list-style-image: url("chrome://browser/skin/tabbrowser/connecting.png");
}
@ -89,11 +107,6 @@
list-style-image: url("chrome://browser/skin/tabbrowser/loading.png");
}
.tab-throbber:not([pinned]),
.tab-icon-image:not([pinned]) {
-moz-margin-end: 6px;
}
.tab-label {
-moz-margin-end: 0;
-moz-margin-start: 0;

View File

@ -219,6 +219,7 @@ browser.jar:
skin/classic/browser/tabbrowser/newtab.png (tabbrowser/newtab-XPVista7.png)
skin/classic/browser/tabbrowser/newtab-inverted.png (tabbrowser/newtab-inverted.png)
skin/classic/browser/tabbrowser/connecting.png (tabbrowser/connecting.png)
skin/classic/browser/tabbrowser/crashed.svg (../shared/tabbrowser/crashed.svg)
skin/classic/browser/tabbrowser/loading.png (tabbrowser/loading.png)
skin/classic/browser/tabbrowser/tab-active-middle.png (tabbrowser/tab-active-middle.png)
skin/classic/browser/tabbrowser/tab-active-middle@2x.png (tabbrowser/tab-active-middle@2x.png)
@ -689,6 +690,7 @@ browser.jar:
skin/classic/aero/browser/tabbrowser/newtab-XPVista7.png (tabbrowser/newtab-XPVista7.png)
skin/classic/aero/browser/tabbrowser/newtab-inverted.png (tabbrowser/newtab-inverted.png)
skin/classic/aero/browser/tabbrowser/connecting.png (tabbrowser/connecting.png)
skin/classic/aero/browser/tabbrowser/crashed.svg (../shared/tabbrowser/crashed.svg)
skin/classic/aero/browser/tabbrowser/loading.png (tabbrowser/loading.png)
skin/classic/aero/browser/tabbrowser/tab-active-middle.png (tabbrowser/tab-active-middle.png)
skin/classic/aero/browser/tabbrowser/tab-active-middle@2x.png (tabbrowser/tab-active-middle@2x.png)

View File

@ -13,6 +13,7 @@ xul|tab[selected] {
}
xul|button,
html|button,
xul|colorpicker[type="button"],
xul|menulist {
margin: 2px 4px;

View File

@ -15,12 +15,14 @@ xul|tab[selected] {
}
xul|button,
html|button,
xul|colorpicker[type="button"],
xul|menulist {
margin-top: 3px;
}
xul|button {
xul|button,
html|button {
/* use the same margin of other elements for the alignment */
margin-left: 4px;
margin-right: 4px;

View File

@ -29,6 +29,11 @@ html|h1 {
margin-bottom: .5em;
}
html|hr {
border-style: solid none none none;
border-color: #c1c1c1;
}
xul|caption {
-moz-appearance: none;
margin: 0;
@ -406,11 +411,29 @@ html|a:hover:active,
/* Checkboxes and radio buttons */
/* Hide the actual checkbox */
html|input[type="checkbox"] {
opacity: 0;
position: absolute;
}
/* Create a box to style as the checkbox */
html|input[type="checkbox"] + html|label:before {
display: inline-block;
content: "";
vertical-align: middle;
}
html|input[type="checkbox"] + html|label {
line-height: 0px;
}
xul|checkbox {
-moz-margin-start: 0;
}
xul|*.checkbox-check {
xul|*.checkbox-check,
html|input[type="checkbox"] + html|label:before {
-moz-appearance: none;
width: 23px;
height: 23px;
@ -425,7 +448,8 @@ xul|*.checkbox-check {
box-shadow: 0 1px 1px 0 #fff, inset 0 2px 0 0 rgba(0,0,0,0.03);
}
xul|checkbox:not([disabled="true"]):hover > xul|*.checkbox-check {
xul|checkbox:not([disabled="true"]):hover > xul|*.checkbox-check,
html|input[type="checkbox"]:not(:disabled) + html|label:hover:before {
border-color: #0095dd;
}
@ -433,7 +457,12 @@ xul|*.checkbox-check[checked] {
list-style-image: url("chrome://global/skin/in-content/check.svg#check");
}
xul|checkbox[disabled="true"] > xul|*.checkbox-check {
html|input[type="checkbox"]:checked + html|label:before {
background-image: url("chrome://global/skin/in-content/check.svg#check"), linear-gradient(#fff, rgba(255,255,255,0.8)) !important;
}
xul|checkbox[disabled="true"] > xul|*.checkbox-check,
html|input[type="checkbox"]:disabled + html|label {
opacity: 0.5;
}

View File

@ -9,6 +9,7 @@ xul|caption {
}
xul|button,
html|button,
xul|colorpicker[type="button"],
xul|menulist {
margin: 2px 4px;