зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to m-i
This commit is contained in:
Коммит
07d954a9e8
|
@ -118,6 +118,7 @@ tabbrowser {
|
|||
visibility: hidden;
|
||||
}
|
||||
|
||||
.tab-close-button,
|
||||
.tab-background {
|
||||
/* Explicitly set the visibility to override the value (collapsed)
|
||||
* we inherit from #TabsToolbar[collapsed] upon opening a browser window. */
|
||||
|
@ -126,6 +127,7 @@ tabbrowser {
|
|||
transition: visibility 0ms 25ms;
|
||||
}
|
||||
|
||||
.tab-close-button:not([fadein]):not([pinned]),
|
||||
.tab-background:not([fadein]):not([pinned]) {
|
||||
visibility: hidden;
|
||||
/* Closing tabs are hidden without a delay. */
|
||||
|
@ -134,8 +136,7 @@ tabbrowser {
|
|||
|
||||
.tab-throbber:not([fadein]):not([pinned]),
|
||||
.tab-label:not([fadein]):not([pinned]),
|
||||
.tab-icon-image:not([fadein]):not([pinned]),
|
||||
.tab-close-button:not([fadein]):not([pinned]) {
|
||||
.tab-icon-image:not([fadein]):not([pinned]) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -1163,14 +1163,15 @@
|
|||
<svg:svg height="0">
|
||||
#include tab-shape.inc.svg
|
||||
|
||||
#ifndef XP_MACOSX
|
||||
<svg:clipPath id="keyhole-forward-clip-path" clipPathUnits="objectBoundingBox">
|
||||
#ifndef XP_UNIX
|
||||
<svg:clipPath id="windows-keyhole-forward-clip-path" clipPathUnits="objectBoundingBox">
|
||||
<svg:path d="m 0,0 c .3,.25 .3,.75, 0,1 l 1,0 0,-1 z"/>
|
||||
</svg:clipPath>
|
||||
<svg:clipPath id="urlbar-back-button-clip-path" clipPathUnits="userSpaceOnUse">
|
||||
<svg:clipPath id="windows-urlbar-back-button-clip-path" clipPathUnits="userSpaceOnUse">
|
||||
<svg:path d="m 0,-5 l 0,7.8 c 2.5,3.2 4,6.2 4,10.2 c 0,4 -1.5,7 -4,10 l 0,22l10000,0 l 0,-50 l -10000,0 z"/>
|
||||
</svg:clipPath>
|
||||
#else
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
<svg:clipPath id="osx-keyhole-forward-clip-path" clipPathUnits="objectBoundingBox">
|
||||
<svg:path d="M 0,0 C 0.15,0.12 0.25,0.3 0.25,0.5 0.25,0.7 0.15,0.88 0,1 L 1,1 1,0 0,0 z"/>
|
||||
</svg:clipPath>
|
||||
|
|
|
@ -331,6 +331,7 @@ const PanelUI = {
|
|||
viewNode.querySelector(".panel-subview-footer"));
|
||||
|
||||
let multiView = document.createElement("panelmultiview");
|
||||
multiView.setAttribute("nosubviews", "true");
|
||||
tempPanel.appendChild(multiView);
|
||||
multiView.setAttribute("mainViewIsSubView", "true");
|
||||
multiView.setMainView(viewNode);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
background-color: transparent;
|
||||
background-image: @fgTabTextureLWT@;/*, lwtHeader;*/
|
||||
background-position: 0 0, right top;
|
||||
background-repeat: repeat-x, no-repeat;
|
||||
}
|
||||
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
|
||||
|
@ -26,4 +27,5 @@
|
|||
@fgTabTextureLWT@;/*,
|
||||
lwtHeader;*/
|
||||
background-position: 0 0, 0 0, right top;
|
||||
background-repeat: repeat-x, repeat-x, no-repeat;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
%define forwardTransitionLength 150ms
|
||||
%define conditionalForwardWithUrlbar window:not([chromehidden~="toolbar"]) #urlbar-container
|
||||
%define conditionalForwardWithUrlbarWidth 27
|
||||
%define conditionalForwardWithUrlbarWidth 40
|
||||
|
||||
#menubar-items {
|
||||
-moz-box-orient: vertical; /* for flex hack */
|
||||
|
@ -653,96 +653,19 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
-moz-margin-start: -4px;
|
||||
}
|
||||
|
||||
#back-button {
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
-moz-padding-start: 5px;
|
||||
-moz-padding-end: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
border-radius: 0 10000px 10000px 0;
|
||||
}
|
||||
|
||||
#back-button:-moz-locale-dir(rtl) {
|
||||
border-radius: 10000px 0 0 10000px;
|
||||
}
|
||||
|
||||
#back-button > menupopup {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
#back-button > .toolbarbutton-icon {
|
||||
border-radius: 10000px;
|
||||
padding: 5px;
|
||||
margin-top: -5px;
|
||||
margin-bottom: -5px;
|
||||
border: none;
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(210,54%,20%,.25),
|
||||
0 1px 0 hsla(210,54%,20%,.35);
|
||||
background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
|
||||
transition-property: background-color, box-shadow;
|
||||
transition-duration: 250ms;
|
||||
}
|
||||
|
||||
#back-button:not([disabled="true"]):not([open="true"]):not(:active):hover > .toolbarbutton-icon {
|
||||
background-color: hsla(210,48%,96%,.75);
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(210,54%,20%,.3),
|
||||
0 1px 0 hsla(210,54%,20%,.4),
|
||||
0 0 4px hsla(210,54%,20%,.2);
|
||||
}
|
||||
|
||||
#back-button:not([disabled="true"]):hover:active > .toolbarbutton-icon,
|
||||
#back-button[open="true"] > .toolbarbutton-icon {
|
||||
background-color: hsla(210,54%,20%,.15);
|
||||
box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset,
|
||||
0 0 1px hsla(210,54%,20%,.2) inset,
|
||||
0 0 0 1px hsla(210,54%,20%,.4),
|
||||
0 1px 0 hsla(210,54%,20%,.2);
|
||||
transition: none;
|
||||
}
|
||||
|
||||
#main-window:not([customizing]) #back-button[disabled] > .toolbarbutton-icon {
|
||||
box-shadow: 0 0 0 1px hsla(210,54%,20%,.55),
|
||||
0 1px 0 hsla(210,54%,20%,.65) !important;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
|
||||
#forward-button:-moz-locale-dir(rtl) {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] {
|
||||
#forward-button[disabled] {
|
||||
transform: scale(0);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
|
||||
transition: opacity @forwardTransitionLength@ ease-out;
|
||||
transition: @forwardTransitionLength@ ease-out;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #forward-button[occluded-by-urlbar] {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#forward-button {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#forward-button > .toolbarbutton-icon {
|
||||
background-clip: padding-box;
|
||||
clip-path: url("chrome://browser/content/browser.xul#keyhole-forward-clip-path");
|
||||
margin-left: -7px;
|
||||
border-left-style: none;
|
||||
border-radius: 0;
|
||||
padding-left: 7px;
|
||||
padding-right: 3px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
border: 1px solid #9a9a9a;
|
||||
#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
|
||||
#forward-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
/* tabview menu item */
|
||||
|
@ -853,21 +776,9 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
}
|
||||
|
||||
/* Location bar */
|
||||
#urlbar,
|
||||
.searchbar-textbox {
|
||||
-moz-appearance: none;
|
||||
padding: 1px;
|
||||
border: 1px solid ThreeDShadow;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
#urlbar[focused],
|
||||
.searchbar-textbox[focused] {
|
||||
border-color: Highlight;
|
||||
}
|
||||
|
||||
#urlbar {
|
||||
background-color: -moz-field;
|
||||
-moz-appearance: textfield;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.urlbar-textbox-container {
|
||||
|
@ -889,56 +800,26 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #urlbar-wrapper {
|
||||
padding-left: @conditionalForwardWithUrlbarWidth@px;
|
||||
-moz-padding-start: @conditionalForwardWithUrlbarWidth@px;
|
||||
-moz-margin-start: -@conditionalForwardWithUrlbarWidth@px;
|
||||
position: relative;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar {
|
||||
-moz-border-start: none;
|
||||
margin-left: 0;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar-wrapper > #urlbar {
|
||||
transition: margin-left @forwardTransitionLength@ ease-out;
|
||||
transition: margin-left @forwardTransitionLength@ ease-out,
|
||||
margin-right @forwardTransitionLength@ ease-out;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(ltr) {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper {
|
||||
clip-path: url("chrome://browser/content/browser.xul#urlbar-back-button-clip-path");
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar {
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar:-moz-locale-dir(ltr) {
|
||||
margin-left: -@conditionalForwardWithUrlbarWidth@px;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar {
|
||||
/* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
|
||||
transition-delay: 100s;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled][switchingtabs] + #urlbar-container > #urlbar,
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar {
|
||||
/* when switching tabs, or when not hovered anymore, trigger a new transition
|
||||
* to hide the forward button immediately */
|
||||
margin-left: -@conditionalForwardWithUrlbarWidth@.01px;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #urlbar-wrapper:-moz-locale-dir(rtl),
|
||||
@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
|
||||
/* let windows-urlbar-back-button-mask clip the urlbar's right side for RTL */
|
||||
transform: scaleX(-1);
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
|
||||
margin-right: -@conditionalForwardWithUrlbarWidth@px;
|
||||
}
|
||||
|
||||
#urlbar-icons {
|
||||
|
@ -978,66 +859,41 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
min-width: calc(54px + 11ch);
|
||||
}
|
||||
|
||||
/* identity box */
|
||||
%include ../shared/identity-block.inc.css
|
||||
|
||||
#page-proxy-favicon {
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
-moz-margin-start: 4px;
|
||||
-moz-margin-end: 3px;
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
}
|
||||
|
||||
#identity-box:hover > #page-proxy-favicon {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
}
|
||||
|
||||
#identity-box:hover:active > #page-proxy-favicon,
|
||||
#identity-box[open=true] > #page-proxy-favicon {
|
||||
-moz-image-region: rect(0, 48px, 16px, 32px);
|
||||
}
|
||||
|
||||
/* Identity indicator */
|
||||
#identity-box {
|
||||
padding: 1px;
|
||||
margin: -1px;
|
||||
-moz-margin-end: 0;
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
#identity-box:-moz-locale-dir(ltr) {
|
||||
border-top-left-radius: 1.5px;
|
||||
border-bottom-left-radius: 1.5px;
|
||||
border-top-left-radius: 2.5px;
|
||||
border-bottom-left-radius: 2.5px;
|
||||
}
|
||||
|
||||
#identity-box:-moz-locale-dir(rtl) {
|
||||
border-top-right-radius: 1.5px;
|
||||
border-bottom-right-radius: 1.5px;
|
||||
}
|
||||
|
||||
#notification-popup-box:not([hidden]) + #identity-box {
|
||||
-moz-padding-start: 10px;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar > #identity-box {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
|
||||
padding-left: 5px;
|
||||
transition: padding-left;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
|
||||
padding-right: 5px;
|
||||
transition: padding-right;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box {
|
||||
/* forward button hiding is delayed when hovered */
|
||||
transition-delay: 100s;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled][switchingtabs] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr),
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
|
||||
/* when not hovered anymore, trigger a new non-delayed transition to react to the forward button hiding */
|
||||
padding-left: 5.01px;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled][switchingtabs] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl),
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
|
||||
/* when not hovered anymore, trigger a new non-delayed transition to react to the forward button hiding */
|
||||
padding-right: 5.01px;
|
||||
}
|
||||
|
||||
#urlbar[pageproxystate="valid"] > #identity-box.chromeUI,
|
||||
#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity {
|
||||
-moz-margin-end: 4px;
|
||||
}
|
||||
|
||||
#identity-box.verifiedIdentity:not(:-moz-lwtheme) {
|
||||
background-color: #fff;
|
||||
border-top-right-radius: 2.5px;
|
||||
border-bottom-right-radius: 2.5px;
|
||||
}
|
||||
|
||||
#identity-box:-moz-focusring {
|
||||
|
@ -1050,27 +906,10 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
-moz-padding-end: 5px;
|
||||
}
|
||||
|
||||
%include ../shared/identity-block.inc.css
|
||||
|
||||
#page-proxy-favicon {
|
||||
margin-top: 1px;
|
||||
margin-bottom: 1px;
|
||||
-moz-margin-start: 3px;
|
||||
-moz-margin-end: 2px;
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar > #identity-box > #page-proxy-favicon {
|
||||
-moz-margin-end: 1px;
|
||||
}
|
||||
|
||||
#identity-box:hover > #page-proxy-favicon {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
}
|
||||
|
||||
#identity-box:hover:active > #page-proxy-favicon,
|
||||
#identity-box[open=true] > #page-proxy-favicon {
|
||||
-moz-image-region: rect(0, 48px, 16px, 32px);
|
||||
#urlbar[pageproxystate="valid"] > #identity-box.chromeUI,
|
||||
#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity {
|
||||
background-color: #fff;
|
||||
-moz-margin-end: 4px;
|
||||
}
|
||||
|
||||
/* Identity popup icons */
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
background-color: transparent;
|
||||
background-image: @fgTabTextureLWT@;/*, lwtHeader;*/
|
||||
background-position: 0 0, right top;
|
||||
background-repeat: repeat-x, no-repeat;
|
||||
}
|
||||
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
|
||||
|
@ -25,6 +26,7 @@
|
|||
@fgTabTextureLWT@;/*,
|
||||
lwtHeader;*/
|
||||
background-position: 0 0, 0 0, right top;
|
||||
background-repeat: repeat-x, repeat-x, no-repeat;
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
%filter substitution
|
||||
|
||||
%define menuPanelWidth 22.35em
|
||||
%define standaloneSubviewWidth 30em
|
||||
% XXXgijs This is the ugliest bit of code I think I've ever written for Mozilla.
|
||||
% Basically, the 0.1px is there to avoid CSS rounding errors causing buttons to wrap.
|
||||
% For gory details, refer to https://bugzilla.mozilla.org/show_bug.cgi?id=963365#c11
|
||||
|
@ -89,6 +90,10 @@
|
|||
transform: translateX(-@menuPanelWidth@);
|
||||
}
|
||||
|
||||
panelmultiview[nosubviews=true] > .panel-viewcontainer > .panel-viewstack > .panel-subviews {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.panel-viewstack:not([viewtype="main"]) > .panel-mainview > #PanelUI-mainView {
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
@ -186,10 +191,13 @@
|
|||
-moz-margin-start: 0;
|
||||
}
|
||||
|
||||
#PanelUI-contents,
|
||||
#PanelUI-contents {
|
||||
max-width: @menuPanelWidth@;
|
||||
}
|
||||
|
||||
#BMB_bookmarksPopup,
|
||||
.panel-mainview:not([panelid="PanelUI-popup"]) {
|
||||
max-width: @menuPanelWidth@;
|
||||
max-width: @standaloneSubviewWidth@;
|
||||
}
|
||||
|
||||
panelview:not([mainview]) .toolbarbutton-text,
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
background-color: transparent;
|
||||
background-image: @fgTabTextureLWT@;/*, lwtHeader;*/
|
||||
background-position: 0 0, right top;
|
||||
background-repeat: repeat-x, no-repeat;
|
||||
}
|
||||
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
|
||||
|
@ -26,4 +27,5 @@
|
|||
@fgTabTextureLWT@;/*,
|
||||
lwtHeader;*/
|
||||
background-position: 0 0, 0 0, right top;
|
||||
background-repeat: repeat-x, repeat-x, no-repeat;
|
||||
}
|
||||
|
|
|
@ -764,7 +764,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4);
|
||||
box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset,
|
||||
0 0 1px hsla(210,54%,20%,.2) inset,
|
||||
/* allows keyhole-forward-clip-path to be used for non-hover as well as hover: */
|
||||
/* allows windows-keyhole-forward-clip-path to be used for non-hover as well as hover: */
|
||||
0 1px 0 hsla(210,54%,20%,0),
|
||||
0 0 2px hsla(210,54%,20%,0);
|
||||
text-shadow: none;
|
||||
|
@ -818,7 +818,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
#forward-button > .toolbarbutton-icon {
|
||||
background-clip: padding-box !important;
|
||||
/*mask: url(keyhole-forward-mask.svg#mask); XXX: this regresses twinopen */
|
||||
clip-path: url(chrome://browser/content/browser.xul#keyhole-forward-clip-path) !important;
|
||||
clip-path: url(chrome://browser/content/browser.xul#windows-keyhole-forward-clip-path) !important;
|
||||
margin-left: -7px !important;
|
||||
border-left-style: none !important;
|
||||
border-radius: 0 !important;
|
||||
|
@ -1123,7 +1123,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper {
|
||||
clip-path: url("chrome://browser/content/browser.xul#urlbar-back-button-clip-path");
|
||||
clip-path: url("chrome://browser/content/browser.xul#windows-urlbar-back-button-clip-path");
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar {
|
||||
|
|
|
@ -59,6 +59,7 @@ sync_testing_modules := \
|
|||
fakeservices.js \
|
||||
rotaryengine.js \
|
||||
utils.js \
|
||||
fxa_utils.js \
|
||||
$(NULL)
|
||||
|
||||
PREF_JS_EXPORTS := $(srcdir)/services-sync.js
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"Assert_rejects",
|
||||
"initializeIdentityWithTokenServerResponse",
|
||||
];
|
||||
|
||||
const {utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-sync/main.js");
|
||||
Cu.import("resource://services-sync/browserid_identity.js");
|
||||
Cu.import("resource://services-common/tokenserverclient.js");
|
||||
Cu.import("resource://testing-common/services-common/logging.js");
|
||||
Cu.import("resource://testing-common/services/sync/utils.js");
|
||||
|
||||
// This shouldn't be here - it should be part of the xpcshell harness.
|
||||
// Maybe as Assert.rejects - so we name it like that.
|
||||
function Assert_rejects(promise, message) {
|
||||
let deferred = Promise.defer();
|
||||
promise.then(
|
||||
() => deferred.reject(message || "Expected the promise to be rejected"),
|
||||
deferred.resolve
|
||||
);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
// Create a new browserid_identity object and initialize it with a
|
||||
// mocked TokenServerClient which always receives the specified response.
|
||||
this.initializeIdentityWithTokenServerResponse = function(response) {
|
||||
// First create a mock "request" object that well' hack into the token server.
|
||||
// A log for it
|
||||
let requestLog = Log.repository.getLogger("testing.mock-rest");
|
||||
if (!requestLog.appenders.length) { // might as well see what it says :)
|
||||
requestLog.addAppender(new Log.DumpAppender());
|
||||
requestLog.level = Log.Level.Trace;
|
||||
}
|
||||
|
||||
// A mock request object.
|
||||
function MockRESTRequest(url) {};
|
||||
MockRESTRequest.prototype = {
|
||||
_log: requestLog,
|
||||
setHeader: function() {},
|
||||
get: function(callback) {
|
||||
this.response = response;
|
||||
callback.call(this);
|
||||
}
|
||||
}
|
||||
// The mocked TokenServer client which will get the response.
|
||||
function MockTSC() { }
|
||||
MockTSC.prototype = new TokenServerClient();
|
||||
MockTSC.prototype.constructor = MockTSC;
|
||||
MockTSC.prototype.newRESTRequest = function(url) {
|
||||
return new MockRESTRequest(url);
|
||||
}
|
||||
// tie it all together.
|
||||
Weave.Status.__authManager = Weave.Service.identity = new BrowserIDManager();
|
||||
Weave.Service._clusterManager = Weave.Service.identity.createClusterManager(Weave.Service);
|
||||
let browseridManager = Weave.Service.identity;
|
||||
// a sanity check
|
||||
if (!(browseridManager instanceof BrowserIDManager)) {
|
||||
throw new Error("sync isn't configured for browserid_identity");
|
||||
}
|
||||
let mockTSC = new MockTSC()
|
||||
configureFxAccountIdentity(browseridManager);
|
||||
browseridManager._tokenServerClient = mockTSC;
|
||||
}
|
|
@ -634,7 +634,28 @@ BrowserIDClusterManager.prototype = {
|
|||
let cb = Async.makeSpinningCallback();
|
||||
promiseClusterURL().then(function (clusterURL) {
|
||||
cb(null, clusterURL);
|
||||
}).then(null, cb);
|
||||
}).then(
|
||||
null, err => {
|
||||
// service.js's verifyLogin() method will attempt to fetch a cluster
|
||||
// URL when it sees a 401. If it gets null, it treats it as a "real"
|
||||
// auth error and sets Status.login to LOGIN_FAILED_LOGIN_REJECTED, which
|
||||
// in turn causes a notification bar to appear informing the user they
|
||||
// need to re-authenticate.
|
||||
// On the other hand, if fetching the cluster URL fails with an exception,
|
||||
// verifyLogin() assumes it is a transient error, and thus doesn't show
|
||||
// the notification bar under the assumption the issue will resolve
|
||||
// itself.
|
||||
// Thus:
|
||||
// * On a real 401, we must return null.
|
||||
// * On any other problem we must let an exception bubble up.
|
||||
if (err instanceof AuthenticationError) {
|
||||
// callback with no error and a null result - cb.wait() returns null.
|
||||
cb(null, null);
|
||||
} else {
|
||||
// callback with an error - cb.wait() completes by raising an exception.
|
||||
cb(err);
|
||||
}
|
||||
});
|
||||
return cb.wait();
|
||||
},
|
||||
|
||||
|
|
|
@ -8,11 +8,11 @@ Cu.import("resource://services-sync/util.js");
|
|||
Cu.import("resource://services-common/utils.js");
|
||||
Cu.import("resource://services-crypto/utils.js");
|
||||
Cu.import("resource://testing-common/services/sync/utils.js");
|
||||
Cu.import("resource://testing-common/services/sync/fxa_utils.js");
|
||||
Cu.import("resource://services-common/hawkclient.js");
|
||||
Cu.import("resource://gre/modules/FxAccounts.jsm");
|
||||
Cu.import("resource://gre/modules/FxAccountsClient.jsm");
|
||||
Cu.import("resource://gre/modules/FxAccountsCommon.js");
|
||||
Cu.import("resource://services-common/tokenserverclient.js");
|
||||
Cu.import("resource://services-sync/service.js");
|
||||
Cu.import("resource://services-sync/status.js");
|
||||
Cu.import("resource://services-sync/constants.js");
|
||||
|
@ -21,17 +21,6 @@ const SECOND_MS = 1000;
|
|||
const MINUTE_MS = SECOND_MS * 60;
|
||||
const HOUR_MS = MINUTE_MS * 60;
|
||||
|
||||
// This shouldn't be here - it should be part of the xpcshell harness.
|
||||
// Maybe as Assert.rejects - so we name it like that.
|
||||
function Assert_rejects(promise, message) {
|
||||
let deferred = Promise.defer();
|
||||
promise.then(
|
||||
() => deferred.reject(message || "Expected the promise to be rejected"),
|
||||
deferred.resolve
|
||||
);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
let identityConfig = makeIdentityConfig();
|
||||
let browseridManager = new BrowserIDManager();
|
||||
configureFxAccountIdentity(browseridManager, identityConfig);
|
||||
|
@ -348,11 +337,16 @@ add_task(function test_getTokenErrors() {
|
|||
_("BrowserIDManager correctly handles various failures to get a token.");
|
||||
|
||||
_("Arrange for a 401 - Sync should reflect an auth error.");
|
||||
yield initializeIdentityWithTokenServerFailure({
|
||||
initializeIdentityWithTokenServerResponse({
|
||||
status: 401,
|
||||
headers: {"content-type": "application/json"},
|
||||
body: JSON.stringify({}),
|
||||
});
|
||||
let browseridManager = Service.identity;
|
||||
|
||||
yield browseridManager.initializeWithCurrentIdentity();
|
||||
yield Assert_rejects(browseridManager.whenReadyToAuthenticate.promise,
|
||||
"should reject due to 401");
|
||||
Assert.equal(Status.login, LOGIN_FAILED_LOGIN_REJECTED, "login was rejected");
|
||||
|
||||
// XXX - other interesting responses to return?
|
||||
|
@ -360,11 +354,15 @@ add_task(function test_getTokenErrors() {
|
|||
// And for good measure, some totally "unexpected" errors - we generally
|
||||
// assume these problems are going to magically go away at some point.
|
||||
_("Arrange for an empty body with a 200 response - should reflect a network error.");
|
||||
yield initializeIdentityWithTokenServerFailure({
|
||||
initializeIdentityWithTokenServerResponse({
|
||||
status: 200,
|
||||
headers: [],
|
||||
body: "",
|
||||
});
|
||||
browseridManager = Service.identity;
|
||||
yield browseridManager.initializeWithCurrentIdentity();
|
||||
yield Assert_rejects(browseridManager.whenReadyToAuthenticate.promise,
|
||||
"should reject due to non-JSON response");
|
||||
Assert.equal(Status.login, LOGIN_FAILED_NETWORK_ERROR, "login state is LOGIN_FAILED_NETWORK_ERROR");
|
||||
});
|
||||
|
||||
|
@ -375,12 +373,18 @@ add_task(function test_getTokenErrorWithRetry() {
|
|||
// it should reflect the value we sent.
|
||||
Status.backoffInterval = 0;
|
||||
_("Arrange for a 503 with a Retry-After header.");
|
||||
yield initializeIdentityWithTokenServerFailure({
|
||||
initializeIdentityWithTokenServerResponse({
|
||||
status: 503,
|
||||
headers: {"content-type": "application/json",
|
||||
"retry-after": "100"},
|
||||
body: JSON.stringify({}),
|
||||
});
|
||||
let browseridManager = Service.identity;
|
||||
|
||||
yield browseridManager.initializeWithCurrentIdentity();
|
||||
yield Assert_rejects(browseridManager.whenReadyToAuthenticate.promise,
|
||||
"should reject due to 503");
|
||||
|
||||
// The observer should have fired - check it got the value in the response.
|
||||
Assert.equal(Status.login, LOGIN_FAILED_NETWORK_ERROR, "login was rejected");
|
||||
// Sync will have the value in ms with some slop - so check it is at least that.
|
||||
|
@ -388,12 +392,18 @@ add_task(function test_getTokenErrorWithRetry() {
|
|||
|
||||
_("Arrange for a 200 with an X-Backoff header.");
|
||||
Status.backoffInterval = 0;
|
||||
yield initializeIdentityWithTokenServerFailure({
|
||||
initializeIdentityWithTokenServerResponse({
|
||||
status: 503,
|
||||
headers: {"content-type": "application/json",
|
||||
"x-backoff": "200"},
|
||||
body: JSON.stringify({}),
|
||||
});
|
||||
browseridManager = Service.identity;
|
||||
|
||||
yield browseridManager.initializeWithCurrentIdentity();
|
||||
yield Assert_rejects(browseridManager.whenReadyToAuthenticate.promise,
|
||||
"should reject due to no token in response");
|
||||
|
||||
// The observer should have fired - check it got the value in the response.
|
||||
Assert.ok(Status.backoffInterval >= 200000);
|
||||
});
|
||||
|
@ -471,45 +481,6 @@ add_task(function test_getKeysError() {
|
|||
// End of tests
|
||||
// Utility functions follow
|
||||
|
||||
// Create a new browserid_identity object and initialize it with a
|
||||
// mocked TokenServerClient which always gets the specified response.
|
||||
function* initializeIdentityWithTokenServerFailure(response) {
|
||||
// First create a mock "request" object that well' hack into the token server.
|
||||
// A log for it
|
||||
let requestLog = Log.repository.getLogger("testing.mock-rest");
|
||||
if (!requestLog.appenders.length) { // might as well see what it says :)
|
||||
requestLog.addAppender(new Log.DumpAppender());
|
||||
requestLog.level = Log.Level.Trace;
|
||||
}
|
||||
|
||||
// A mock request object.
|
||||
function MockRESTRequest(url) {};
|
||||
MockRESTRequest.prototype = {
|
||||
_log: requestLog,
|
||||
setHeader: function() {},
|
||||
get: function(callback) {
|
||||
this.response = response;
|
||||
callback.call(this);
|
||||
}
|
||||
}
|
||||
// The mocked TokenServer client which will get the response.
|
||||
function MockTSC() { }
|
||||
MockTSC.prototype = new TokenServerClient();
|
||||
MockTSC.prototype.constructor = MockTSC;
|
||||
MockTSC.prototype.newRESTRequest = function(url) {
|
||||
return new MockRESTRequest(url);
|
||||
}
|
||||
// tie it all together.
|
||||
let mockTSC = new MockTSC()
|
||||
configureFxAccountIdentity(browseridManager);
|
||||
browseridManager._tokenServerClient = mockTSC;
|
||||
|
||||
yield browseridManager.initializeWithCurrentIdentity();
|
||||
yield Assert_rejects(browseridManager.whenReadyToAuthenticate.promise,
|
||||
"expecting rejection due to tokenserver error");
|
||||
}
|
||||
|
||||
|
||||
// Create a new browserid_identity object and initialize it with a
|
||||
// hawk mock that simulates a failure.
|
||||
// A token server mock will be used that doesn't hit a server, so we move
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Cu.import("resource://services-sync/service.js");
|
||||
Cu.import("resource://services-sync/util.js");
|
||||
Cu.import("resource://testing-common/services/sync/fxa_utils.js");
|
||||
Cu.import("resource://testing-common/services/sync/utils.js");
|
||||
|
||||
add_task(function test_findCluster() {
|
||||
_("Test FxA _findCluster()");
|
||||
|
||||
_("_findCluster() throws on 500 errors.");
|
||||
initializeIdentityWithTokenServerResponse({
|
||||
status: 500,
|
||||
headers: [],
|
||||
body: "",
|
||||
});
|
||||
|
||||
yield Service.identity.initializeWithCurrentIdentity();
|
||||
yield Assert_rejects(Service.identity.whenReadyToAuthenticate.promise,
|
||||
"should reject due to 500");
|
||||
|
||||
Assert.throws(function() {
|
||||
Service._clusterManager._findCluster();
|
||||
});
|
||||
|
||||
_("_findCluster() returns null on authentication errors.");
|
||||
initializeIdentityWithTokenServerResponse({
|
||||
status: 401,
|
||||
headers: {"content-type": "application/json"},
|
||||
body: "{}",
|
||||
});
|
||||
|
||||
yield Service.identity.initializeWithCurrentIdentity();
|
||||
yield Assert_rejects(Service.identity.whenReadyToAuthenticate.promise,
|
||||
"should reject due to 401");
|
||||
|
||||
cluster = Service._clusterManager._findCluster();
|
||||
Assert.strictEqual(cluster, null);
|
||||
|
||||
_("_findCluster() works with correct tokenserver response.");
|
||||
let endpoint = "http://example.com/something";
|
||||
initializeIdentityWithTokenServerResponse({
|
||||
status: 200,
|
||||
headers: {"content-type": "application/json"},
|
||||
body:
|
||||
JSON.stringify({
|
||||
api_endpoint: endpoint,
|
||||
duration: 300,
|
||||
id: "id",
|
||||
key: "key",
|
||||
uid: "uid",
|
||||
})
|
||||
});
|
||||
|
||||
yield Service.identity.initializeWithCurrentIdentity();
|
||||
yield Service.identity.whenReadyToAuthenticate.promise;
|
||||
cluster = Service._clusterManager._findCluster();
|
||||
// The cluster manager ensures a trailing "/"
|
||||
Assert.strictEqual(cluster, endpoint + "/");
|
||||
|
||||
Svc.Prefs.resetBranch("");
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
initTestLogging();
|
||||
run_next_test();
|
||||
}
|
|
@ -37,6 +37,7 @@ const testingModules = [
|
|||
"fakeservices.js",
|
||||
"rotaryengine.js",
|
||||
"utils.js",
|
||||
"fxa_utils.js",
|
||||
];
|
||||
|
||||
function run_test() {
|
||||
|
|
|
@ -124,6 +124,7 @@ skip-if = os == "android"
|
|||
|
||||
# Firefox Accounts specific tests
|
||||
[test_fxa_startOver.js]
|
||||
[test_fxa_service_cluster.js]
|
||||
|
||||
# Finally, we test each engine.
|
||||
[test_addons_engine.js]
|
||||
|
|
Загрузка…
Ссылка в новой задаче