Merge fx-team to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2015-07-22 16:29:22 -04:00
commit 976febc5b0
48 changed files with 1014 additions and 428 deletions

View File

@ -724,6 +724,10 @@ input[type=button] {
color: #4A90E2;
}
#newtab-intro-footer > ul > li > a:hover {
color: #000000;
}
#newtab-intro-body {
position: relative;
display: block;

View File

@ -21,7 +21,6 @@
<script type="text/javascript" src="loop/js/otconfig.js"></script>
<script type="text/javascript" src="loop/libs/sdk.js"></script>
<script type="text/javascript" src="loop/shared/libs/react-0.12.2.js"></script>
<script type="text/javascript" src="loop/shared/libs/jquery-2.1.4.js"></script>
<script type="text/javascript" src="loop/shared/libs/lodash-3.9.3.js"></script>
<script type="text/javascript" src="loop/shared/libs/backbone-1.2.1.js"></script>

View File

@ -3,7 +3,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
var loop = loop || {};
loop.Client = (function($) {
loop.Client = (function() {
"use strict";
// THe expected properties to be returned from the POST /calls request.
@ -116,4 +116,4 @@ loop.Client = (function($) {
};
return Client;
})(jQuery);
})();

View File

@ -16,7 +16,6 @@
<script type="text/javascript" src="loop/shared/libs/react-0.12.2.js"></script>
<script type="text/javascript" src="loop/libs/l10n.js"></script>
<script type="text/javascript" src="loop/shared/libs/jquery-2.1.4.js"></script>
<script type="text/javascript" src="loop/shared/libs/lodash-3.9.3.js"></script>
<script type="text/javascript" src="loop/shared/libs/backbone-1.2.1.js"></script>

View File

@ -549,6 +549,9 @@ html[dir="rtl"] .context-wrapper > .context-preview {
flex: 0 1 auto;
display: block;
color: black;
/* 16px for the preview, plus its .8em margin */
max-width: calc(100% - 16px - .8em);
word-wrap: break-word;
}
.context-wrapper > .context-description > .context-url {

View File

@ -143,5 +143,11 @@ loop.store.StoreMixin = (function() {
StoreMixin.register = function(stores) {
_.extend(_stores, stores);
};
/**
* Used for test purposes, to clear the list of registered stores.
*/
StoreMixin.clearRegisteredStores = function() {
_stores = {};
};
return StoreMixin;
})();

View File

@ -944,6 +944,81 @@ loop.shared.views = (function(_, mozL10n) {
}
});
var MediaLayoutView = React.createClass({displayName: "MediaLayoutView",
propTypes: {
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
displayScreenShare: React.PropTypes.bool.isRequired,
isLocalLoading: React.PropTypes.bool.isRequired,
isRemoteLoading: React.PropTypes.bool.isRequired,
isScreenShareLoading: React.PropTypes.bool.isRequired,
// The poster URLs are for UI-showcase testing and development.
localPosterUrl: React.PropTypes.string,
localSrcVideoObject: React.PropTypes.object,
localVideoMuted: React.PropTypes.bool.isRequired,
remotePosterUrl: React.PropTypes.string,
remoteSrcVideoObject: React.PropTypes.object,
renderRemoteVideo: React.PropTypes.bool.isRequired,
screenSharePosterUrl: React.PropTypes.string,
screenShareVideoObject: React.PropTypes.object,
showContextRoomName: React.PropTypes.bool.isRequired,
useDesktopPaths: React.PropTypes.bool.isRequired
},
render: function() {
var remoteStreamClasses = React.addons.classSet({
"remote": true,
"focus-stream": !this.props.displayScreenShare
});
var screenShareStreamClasses = React.addons.classSet({
"screen": true,
"focus-stream": this.props.displayScreenShare
});
var mediaWrapperClasses = React.addons.classSet({
"media-wrapper": true,
"receiving-screen-share": this.props.displayScreenShare,
"showing-local-streams": this.props.localSrcVideoObject ||
this.props.localPosterUrl
});
return (
React.createElement("div", {className: "media-layout"},
React.createElement("div", {className: mediaWrapperClasses},
React.createElement("span", {className: "self-view-hidden-message"},
mozL10n.get("self_view_hidden_message")
),
React.createElement("div", {className: remoteStreamClasses},
React.createElement(MediaView, {displayAvatar: !this.props.renderRemoteVideo,
isLoading: this.props.isRemoteLoading,
mediaType: "remote",
posterUrl: this.props.remotePosterUrl,
srcVideoObject: this.props.remoteSrcVideoObject})
),
React.createElement("div", {className: screenShareStreamClasses},
React.createElement(MediaView, {displayAvatar: false,
isLoading: this.props.isScreenShareLoading,
mediaType: "screen-share",
posterUrl: this.props.screenSharePosterUrl,
srcVideoObject: this.props.screenShareVideoObject})
),
React.createElement(loop.shared.views.chat.TextChatView, {
dispatcher: this.props.dispatcher,
showRoomName: this.props.showContextRoomName,
useDesktopPaths: false}),
React.createElement("div", {className: "local"},
React.createElement(MediaView, {displayAvatar: this.props.localVideoMuted,
isLoading: this.props.isLocalLoading,
mediaType: "local",
posterUrl: this.props.localPosterUrl,
srcVideoObject: this.props.localSrcVideoObject})
)
)
)
);
}
});
return {
AvatarView: AvatarView,
Button: Button,
@ -953,6 +1028,7 @@ loop.shared.views = (function(_, mozL10n) {
ConversationView: ConversationView,
ConversationToolbar: ConversationToolbar,
MediaControlButton: MediaControlButton,
MediaLayoutView: MediaLayoutView,
MediaView: MediaView,
LoadingView: LoadingView,
ScreenShareControlButton: ScreenShareControlButton,

View File

@ -944,6 +944,81 @@ loop.shared.views = (function(_, mozL10n) {
}
});
var MediaLayoutView = React.createClass({
propTypes: {
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
displayScreenShare: React.PropTypes.bool.isRequired,
isLocalLoading: React.PropTypes.bool.isRequired,
isRemoteLoading: React.PropTypes.bool.isRequired,
isScreenShareLoading: React.PropTypes.bool.isRequired,
// The poster URLs are for UI-showcase testing and development.
localPosterUrl: React.PropTypes.string,
localSrcVideoObject: React.PropTypes.object,
localVideoMuted: React.PropTypes.bool.isRequired,
remotePosterUrl: React.PropTypes.string,
remoteSrcVideoObject: React.PropTypes.object,
renderRemoteVideo: React.PropTypes.bool.isRequired,
screenSharePosterUrl: React.PropTypes.string,
screenShareVideoObject: React.PropTypes.object,
showContextRoomName: React.PropTypes.bool.isRequired,
useDesktopPaths: React.PropTypes.bool.isRequired
},
render: function() {
var remoteStreamClasses = React.addons.classSet({
"remote": true,
"focus-stream": !this.props.displayScreenShare
});
var screenShareStreamClasses = React.addons.classSet({
"screen": true,
"focus-stream": this.props.displayScreenShare
});
var mediaWrapperClasses = React.addons.classSet({
"media-wrapper": true,
"receiving-screen-share": this.props.displayScreenShare,
"showing-local-streams": this.props.localSrcVideoObject ||
this.props.localPosterUrl
});
return (
<div className="media-layout">
<div className={mediaWrapperClasses}>
<span className="self-view-hidden-message">
{mozL10n.get("self_view_hidden_message")}
</span>
<div className={remoteStreamClasses}>
<MediaView displayAvatar={!this.props.renderRemoteVideo}
isLoading={this.props.isRemoteLoading}
mediaType="remote"
posterUrl={this.props.remotePosterUrl}
srcVideoObject={this.props.remoteSrcVideoObject} />
</div>
<div className={screenShareStreamClasses}>
<MediaView displayAvatar={false}
isLoading={this.props.isScreenShareLoading}
mediaType="screen-share"
posterUrl={this.props.screenSharePosterUrl}
srcVideoObject={this.props.screenShareVideoObject} />
</div>
<loop.shared.views.chat.TextChatView
dispatcher={this.props.dispatcher}
showRoomName={this.props.showContextRoomName}
useDesktopPaths={false} />
<div className="local">
<MediaView displayAvatar={this.props.localVideoMuted}
isLoading={this.props.isLocalLoading}
mediaType="local"
posterUrl={this.props.localPosterUrl}
srcVideoObject={this.props.localSrcVideoObject} />
</div>
</div>
</div>
);
}
});
return {
AvatarView: AvatarView,
Button: Button,
@ -953,6 +1028,7 @@ loop.shared.views = (function(_, mozL10n) {
ConversationView: ConversationView,
ConversationToolbar: ConversationToolbar,
MediaControlButton: MediaControlButton,
MediaLayoutView: MediaLayoutView,
MediaView: MediaView,
LoadingView: LoadingView,
ScreenShareControlButton: ScreenShareControlButton,

View File

@ -99,7 +99,6 @@ browser.jar:
content/browser/loop/shared/libs/react-0.12.2.js (content/shared/libs/react-0.12.2-prod.js)
#endif
content/browser/loop/shared/libs/lodash-3.9.3.js (content/shared/libs/lodash-3.9.3.js)
content/browser/loop/shared/libs/jquery-2.1.4.js (content/shared/libs/jquery-2.1.4.js)
content/browser/loop/shared/libs/backbone-1.2.1.js (content/shared/libs/backbone-1.2.1.js)
# Shared sounds

View File

@ -401,7 +401,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
* @returns {boolean}
* @private
*/
_shouldRenderLocalLoading: function () {
_isLocalLoading: function () {
return this.state.roomState === ROOM_STATES.MEDIA_WAIT &&
!this.state.localSrcVideoObject;
},
@ -413,7 +413,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
* @returns {boolean}
* @private
*/
_shouldRenderRemoteLoading: function() {
_isRemoteLoading: function() {
return !!(this.state.roomState === ROOM_STATES.HAS_PARTICIPANTS &&
!this.state.remoteSrcVideoObject &&
!this.state.mediaConnected);
@ -426,31 +426,14 @@ loop.standaloneRoomViews = (function(mozL10n) {
* @returns {boolean}
* @private
*/
_shouldRenderScreenShareLoading: function() {
_isScreenShareLoading: function() {
return this.state.receivingScreenShare &&
!this.state.screenShareVideoObject;
},
render: function() {
var displayScreenShare = this.state.receivingScreenShare ||
this.props.screenSharePosterUrl;
var remoteStreamClasses = React.addons.classSet({
"remote": true,
"focus-stream": !displayScreenShare
});
var screenShareStreamClasses = React.addons.classSet({
"screen": true,
"focus-stream": displayScreenShare
});
var mediaWrapperClasses = React.addons.classSet({
"media-wrapper": true,
"receiving-screen-share": displayScreenShare,
"showing-local-streams": this.state.localSrcVideoObject ||
this.props.localPosterUrl
});
var displayScreenShare = !!(this.state.receivingScreenShare ||
this.props.screenSharePosterUrl);
return (
React.createElement("div", {className: "room-conversation-wrapper standalone-room-wrapper"},
@ -463,38 +446,22 @@ loop.standaloneRoomViews = (function(mozL10n) {
joinRoom: this.joinRoom,
roomState: this.state.roomState,
roomUsed: this.state.used}),
React.createElement("div", {className: "media-layout"},
React.createElement("div", {className: mediaWrapperClasses},
React.createElement("span", {className: "self-view-hidden-message"},
mozL10n.get("self_view_hidden_message")
),
React.createElement("div", {className: remoteStreamClasses},
React.createElement(sharedViews.MediaView, {displayAvatar: !this.shouldRenderRemoteVideo(),
isLoading: this._shouldRenderRemoteLoading(),
mediaType: "remote",
posterUrl: this.props.remotePosterUrl,
srcVideoObject: this.state.remoteSrcVideoObject})
),
React.createElement("div", {className: screenShareStreamClasses},
React.createElement(sharedViews.MediaView, {displayAvatar: false,
isLoading: this._shouldRenderScreenShareLoading(),
mediaType: "screen-share",
posterUrl: this.props.screenSharePosterUrl,
srcVideoObject: this.state.screenShareVideoObject})
),
React.createElement(sharedViews.chat.TextChatView, {
dispatcher: this.props.dispatcher,
showRoomName: true,
useDesktopPaths: false}),
React.createElement("div", {className: "local"},
React.createElement(sharedViews.MediaView, {displayAvatar: this.state.videoMuted,
isLoading: this._shouldRenderLocalLoading(),
mediaType: "local",
posterUrl: this.props.localPosterUrl,
srcVideoObject: this.state.localSrcVideoObject})
)
)
),
React.createElement(sharedViews.MediaLayoutView, {
dispatcher: this.props.dispatcher,
displayScreenShare: displayScreenShare,
isLocalLoading: this._isLocalLoading(),
isRemoteLoading: this._isRemoteLoading(),
isScreenShareLoading: this._isScreenShareLoading(),
localPosterUrl: this.props.localPosterUrl,
localSrcVideoObject: this.state.localSrcVideoObject,
localVideoMuted: this.state.videoMuted,
remotePosterUrl: this.props.remotePosterUrl,
remoteSrcVideoObject: this.state.remoteSrcVideoObject,
renderRemoteVideo: this.shouldRenderRemoteVideo(),
screenSharePosterUrl: this.props.screenSharePosterUrl,
screenShareVideoObject: this.state.screenShareVideoObject,
showContextRoomName: true,
useDesktopPaths: false}),
React.createElement(sharedViews.ConversationToolbar, {
audio: {enabled: !this.state.audioMuted,
visible: this._roomIsActive()},

View File

@ -401,7 +401,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
* @returns {boolean}
* @private
*/
_shouldRenderLocalLoading: function () {
_isLocalLoading: function () {
return this.state.roomState === ROOM_STATES.MEDIA_WAIT &&
!this.state.localSrcVideoObject;
},
@ -413,7 +413,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
* @returns {boolean}
* @private
*/
_shouldRenderRemoteLoading: function() {
_isRemoteLoading: function() {
return !!(this.state.roomState === ROOM_STATES.HAS_PARTICIPANTS &&
!this.state.remoteSrcVideoObject &&
!this.state.mediaConnected);
@ -426,31 +426,14 @@ loop.standaloneRoomViews = (function(mozL10n) {
* @returns {boolean}
* @private
*/
_shouldRenderScreenShareLoading: function() {
_isScreenShareLoading: function() {
return this.state.receivingScreenShare &&
!this.state.screenShareVideoObject;
},
render: function() {
var displayScreenShare = this.state.receivingScreenShare ||
this.props.screenSharePosterUrl;
var remoteStreamClasses = React.addons.classSet({
"remote": true,
"focus-stream": !displayScreenShare
});
var screenShareStreamClasses = React.addons.classSet({
"screen": true,
"focus-stream": displayScreenShare
});
var mediaWrapperClasses = React.addons.classSet({
"media-wrapper": true,
"receiving-screen-share": displayScreenShare,
"showing-local-streams": this.state.localSrcVideoObject ||
this.props.localPosterUrl
});
var displayScreenShare = !!(this.state.receivingScreenShare ||
this.props.screenSharePosterUrl);
return (
<div className="room-conversation-wrapper standalone-room-wrapper">
@ -463,38 +446,22 @@ loop.standaloneRoomViews = (function(mozL10n) {
joinRoom={this.joinRoom}
roomState={this.state.roomState}
roomUsed={this.state.used} />
<div className="media-layout">
<div className={mediaWrapperClasses}>
<span className="self-view-hidden-message">
{mozL10n.get("self_view_hidden_message")}
</span>
<div className={remoteStreamClasses}>
<sharedViews.MediaView displayAvatar={!this.shouldRenderRemoteVideo()}
isLoading={this._shouldRenderRemoteLoading()}
mediaType="remote"
posterUrl={this.props.remotePosterUrl}
srcVideoObject={this.state.remoteSrcVideoObject} />
</div>
<div className={screenShareStreamClasses}>
<sharedViews.MediaView displayAvatar={false}
isLoading={this._shouldRenderScreenShareLoading()}
mediaType="screen-share"
posterUrl={this.props.screenSharePosterUrl}
srcVideoObject={this.state.screenShareVideoObject} />
</div>
<sharedViews.chat.TextChatView
dispatcher={this.props.dispatcher}
showRoomName={true}
useDesktopPaths={false} />
<div className="local">
<sharedViews.MediaView displayAvatar={this.state.videoMuted}
isLoading={this._shouldRenderLocalLoading()}
mediaType="local"
posterUrl={this.props.localPosterUrl}
srcVideoObject={this.state.localSrcVideoObject} />
</div>
</div>
</div>
<sharedViews.MediaLayoutView
dispatcher={this.props.dispatcher}
displayScreenShare={displayScreenShare}
isLocalLoading={this._isLocalLoading()}
isRemoteLoading={this._isRemoteLoading()}
isScreenShareLoading={this._isScreenShareLoading()}
localPosterUrl={this.props.localPosterUrl}
localSrcVideoObject={this.state.localSrcVideoObject}
localVideoMuted={this.state.videoMuted}
remotePosterUrl={this.props.remotePosterUrl}
remoteSrcVideoObject={this.state.remoteSrcVideoObject}
renderRemoteVideo={this.shouldRenderRemoteVideo()}
screenSharePosterUrl={this.props.screenSharePosterUrl}
screenShareVideoObject={this.state.screenShareVideoObject}
showContextRoomName={true}
useDesktopPaths={false} />
<sharedViews.ConversationToolbar
audio={{enabled: !this.state.audioMuted,
visible: this._roomIsActive()}}

View File

@ -31,7 +31,6 @@
<!-- libs -->
<script src="../../content/libs/l10n.js"></script>
<script src="../../content/shared/libs/react-0.12.2.js"></script>
<script src="../../content/shared/libs/jquery-2.1.4.js"></script>
<script src="../../content/shared/libs/lodash-3.9.3.js"></script>
<script src="../../content/shared/libs/backbone-1.2.1.js"></script>
@ -101,7 +100,10 @@
});
mocha.run(function () {
$("#mocha").append("<p id='complete'>Complete.</p>");
var completeNode = document.createElement("p");
completeNode.setAttribute("id", "complete");
completeNode.appendChild(document.createTextNode("Complete"));
document.getElementById("mocha").appendChild(completeNode);
});
</script>
</body>

View File

@ -30,7 +30,6 @@
<!-- libs -->
<script src="../../content/shared/libs/react-0.12.2.js"></script>
<script src="../../content/shared/libs/jquery-2.1.4.js"></script>
<script src="../../content/shared/libs/lodash-3.9.3.js"></script>
<script src="../../content/shared/libs/backbone-1.2.1.js"></script>
<script src="../../standalone/content/libs/l10n-gaia-02ca67948fe8.js"></script>
@ -95,7 +94,10 @@
});
mocha.run(function () {
$("#mocha").append("<p id='complete'>Complete.</p>");
var completeNode = document.createElement("p");
completeNode.setAttribute("id", "complete");
completeNode.appendChild(document.createTextNode("Complete"));
document.getElementById("mocha").appendChild(completeNode);
});
</script>
</body>

View File

@ -50,7 +50,7 @@ describe("loop.shared.views", function() {
});
afterEach(function() {
$("#fixtures").empty();
loop.store.StoreMixin.clearRegisteredStores();
sandbox.restore();
});
@ -1045,4 +1045,104 @@ describe("loop.shared.views", function() {
});
});
});
describe("MediaLayoutView", function() {
var textChatStore, view;
function mountTestComponent(extraProps) {
var defaultProps = {
dispatcher: dispatcher,
displayScreenShare: false,
isLocalLoading: false,
isRemoteLoading: false,
isScreenShareLoading: false,
localVideoMuted: false,
renderRemoteVideo: false,
showContextRoomName: false,
useDesktopPaths: false
};
return TestUtils.renderIntoDocument(
React.createElement(sharedViews.MediaLayoutView,
_.extend(defaultProps, extraProps)));
}
beforeEach(function() {
textChatStore = new loop.store.TextChatStore(dispatcher, {
sdkDriver: {}
});
loop.store.StoreMixin.register({textChatStore: textChatStore});
});
it("should mark the remote stream as the focus stream when not displaying screen share", function() {
view = mountTestComponent({
displayScreenShare: false
});
var node = view.getDOMNode();
expect(node.querySelector(".remote").classList.contains("focus-stream")).eql(true);
expect(node.querySelector(".screen").classList.contains("focus-stream")).eql(false);
});
it("should mark the screen share stream as the focus stream when displaying screen share", function() {
view = mountTestComponent({
displayScreenShare: true
});
var node = view.getDOMNode();
expect(node.querySelector(".remote").classList.contains("focus-stream")).eql(false);
expect(node.querySelector(".screen").classList.contains("focus-stream")).eql(true);
});
it("should not mark the wrapper as receiving screen share when not displaying a screen share", function() {
view = mountTestComponent({
displayScreenShare: false
});
expect(view.getDOMNode().querySelector(".media-wrapper")
.classList.contains("receiving-screen-share")).eql(false);
});
it("should mark the wrapper as receiving screen share when displaying a screen share", function() {
view = mountTestComponent({
displayScreenShare: true
});
expect(view.getDOMNode().querySelector(".media-wrapper")
.classList.contains("receiving-screen-share")).eql(true);
});
it("should not mark the wrapper as showing local streams when not displaying a stream", function() {
view = mountTestComponent({
localSrcVideoObject: null,
localPosterUrl: null
});
expect(view.getDOMNode().querySelector(".media-wrapper")
.classList.contains("showing-local-streams")).eql(false);
});
it("should mark the wrapper as showing local streams when displaying a stream", function() {
view = mountTestComponent({
localSrcVideoObject: {},
localPosterUrl: null
});
expect(view.getDOMNode().querySelector(".media-wrapper")
.classList.contains("showing-local-streams")).eql(true);
});
it("should mark the wrapper as showing local streams when displaying a poster url", function() {
view = mountTestComponent({
localSrcVideoObject: {},
localPosterUrl: "fake/url"
});
expect(view.getDOMNode().querySelector(".media-wrapper")
.classList.contains("showing-local-streams")).eql(true);
});
});
});

View File

@ -85,12 +85,15 @@
describe("Unexpected Warnings Check", function() {
it("should long only the warnings we expect", function() {
chai.expect(caughtWarnings.length).to.eql(11);
chai.expect(caughtWarnings.length).to.eql(10);
});
});
mocha.run(function () {
$("#mocha").append("<p id='complete'>Complete.</p>");
var completeNode = document.createElement("p");
completeNode.setAttribute("id", "complete");
completeNode.appendChild(document.createTextNode("Complete"));
document.getElementById("mocha").appendChild(completeNode);
});
</script>
</body>

View File

@ -431,7 +431,7 @@ describe("loop.standaloneRoomViews", function() {
"remoteSrcVideoObject is false, mediaConnected is true", function() {
activeRoomStore.setStoreState({
roomState: ROOM_STATES.HAS_PARTICIPANTS,
remoteSrcVideoObject: false,
remoteSrcVideoObject: null,
remoteVideoEnabled: false,
mediaConnected: true
});

View File

@ -18,6 +18,11 @@ var gContentPane = {
if (Services.prefs.getBoolPref(prefName)) {
let row = document.getElementById("translationBox");
row.removeAttribute("hidden");
// Showing attribution only for Bing Translator.
Components.utils.import("resource:///modules/translation/Translation.jsm");
if (Translation.translationEngine == "bing") {
document.getElementById("bingAttribution").removeAttribute("hidden");
}
}
let drmInfoURL =

View File

@ -163,11 +163,13 @@
label="&translateWebPages.label;." accesskey="&translateWebPages.accesskey;"
onsyncfrompreference="return gContentPane.updateButtons('translateButton',
'browser.translation.detectLanguage');"/>
<label>&translation.options.attribution.beforeLogo;</label>
<image id="translationAttributionImage" aria-label="Microsoft Translator"
onclick="gContentPane.openTranslationProviderAttribution()"
src="chrome://browser/content/microsoft-translator-attribution.png"/>
<label>&translation.options.attribution.afterLogo;</label>
<hbox id="bingAttribution" hidden="true">
<label>&translation.options.attribution.beforeLogo;</label>
<image id="translationAttributionImage" aria-label="Microsoft Translator"
onclick="gContentPane.openTranslationProviderAttribution()"
src="chrome://browser/content/microsoft-translator-attribution.png"/>
<label>&translation.options.attribution.afterLogo;</label>
</hbox>
</hbox>
<button id="translateButton" label="&translateExceptions.label;"
oncommand="gContentPane.showTranslationExceptions();"

View File

@ -23,6 +23,11 @@ var gContentPane = {
if (Services.prefs.getBoolPref(prefName)) {
let row = document.getElementById("translationBox");
row.removeAttribute("hidden");
// Showing attribution only for Bing Translator.
Components.utils.import("resource:///modules/translation/Translation.jsm");
if (Translation.translationEngine == "bing") {
document.getElementById("bingAttribution").removeAttribute("hidden");
}
}
setEventListener("font.language.group", "change",

View File

@ -160,12 +160,14 @@
label="&translateWebPages.label;." accesskey="&translateWebPages.accesskey;"
onsyncfrompreference="return gContentPane.updateButtons('translateButton',
'browser.translation.detectLanguage');"/>
<label>&translation.options.attribution.beforeLogo;</label>
<separator orient="vertical" class="thin"/>
<image id="translationAttributionImage" aria-label="Microsoft Translator"
src="chrome://browser/content/microsoft-translator-attribution.png"/>
<separator orient="vertical" class="thin"/>
<label>&translation.options.attribution.afterLogo;</label>
<hbox id="bingAttribution" hidden="true">
<label>&translation.options.attribution.beforeLogo;</label>
<separator orient="vertical" class="thin"/>
<image id="translationAttributionImage" aria-label="Microsoft Translator"
src="chrome://browser/content/microsoft-translator-attribution.png"/>
<separator orient="vertical" class="thin"/>
<label>&translation.options.attribution.afterLogo;</label>
</hbox>
</hbox>
<button id="translateButton" label="&translateExceptions.label;"
accesskey="&translateExceptions.accesskey;"/>

View File

@ -23,7 +23,6 @@ support-files =
[browser_privatebrowsing_certexceptionsui.js]
[browser_privatebrowsing_concurrent.js]
[browser_privatebrowsing_cookieacceptdialog.js]
skip-if = e10s # Bug 1139953 - Accept cookie dialog shown in private window when e10s enabled
[browser_privatebrowsing_crh.js]
[browser_privatebrowsing_downloadLastDir.js]
[browser_privatebrowsing_downloadLastDir_c.js]

View File

@ -40,33 +40,29 @@ add_task(function* () {
// Now we'll set a new unique value on 1 of the tabs
let newUniq = r();
ss.setTabValue(gBrowser.tabs[1], "uniq", newUniq);
yield promiseRemoveTab(gBrowser.tabs[1]);
let closedTabData = (JSON.parse(ss.getClosedTabData(window)))[0];
is(closedTabData.state.extData.uniq, newUniq,
let tabState = JSON.parse(ss.getTabState(gBrowser.tabs[1]));
is(tabState.extData.uniq, newUniq,
"(overwriting) new data is stored in extData");
// hide the next tab before closing it
gBrowser.hideTab(gBrowser.tabs[1]);
yield promiseRemoveTab(gBrowser.tabs[1]);
closedTabData = (JSON.parse(ss.getClosedTabData(window)))[0];
ok(closedTabData.state.hidden, "(hiding) tab data has hidden == true");
gBrowser.hideTab(gBrowser.tabs[2]);
tabState = JSON.parse(ss.getTabState(gBrowser.tabs[2]));
ok(tabState.hidden, "(hiding) tab data has hidden == true");
// set data that's not in a conflicting key
let stillUniq = r();
ss.setTabValue(gBrowser.tabs[1], "stillUniq", stillUniq);
yield promiseRemoveTab(gBrowser.tabs[1]);
closedTabData = (JSON.parse(ss.getClosedTabData(window)))[0];
is(closedTabData.state.extData.stillUniq, stillUniq,
ss.setTabValue(gBrowser.tabs[3], "stillUniq", stillUniq);
tabState = JSON.parse(ss.getTabState(gBrowser.tabs[3]));
is(tabState.extData.stillUniq, stillUniq,
"(adding) new data is stored in extData");
// remove the uniq value and make sure it's not there in the closed data
ss.deleteTabValue(gBrowser.tabs[1], "uniq");
yield promiseRemoveTab(gBrowser.tabs[1]);
closedTabData = (JSON.parse(ss.getClosedTabData(window)))[0];
ss.deleteTabValue(gBrowser.tabs[4], "uniq");
tabState = JSON.parse(ss.getTabState(gBrowser.tabs[4]));
// Since Panorama might have put data in, first check if there is extData.
// If there is explicitly check that "uniq" isn't in it. Otherwise, we're ok
if ("extData" in closedTabData.state) {
ok(!("uniq" in closedTabData.state.extData),
if ("extData" in tabState) {
ok(!("uniq" in tabState.extData),
"(deleting) uniq not in existing extData");
}
else {
@ -75,11 +71,14 @@ add_task(function* () {
// set unique data on the tab that never had any set, make sure that's saved
let newUniq2 = r();
ss.setTabValue(gBrowser.tabs[1], "uniq", newUniq2);
yield promiseRemoveTab(gBrowser.tabs[1]);
closedTabData = (JSON.parse(ss.getClosedTabData(window)))[0];
is(closedTabData.state.extData.uniq, newUniq2,
ss.setTabValue(gBrowser.tabs[5], "uniq", newUniq2);
tabState = JSON.parse(ss.getTabState(gBrowser.tabs[5]));
is(tabState.extData.uniq, newUniq2,
"(creating) new data is stored in extData where there was none");
while (gBrowser.tabs.length > 1) {
yield promiseRemoveTab(gBrowser.tabs[1]);
}
}
// Set the test state.

View File

@ -3,6 +3,8 @@
* 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/. */
#include "nsWindowsShellService.h"
#include "imgIContainer.h"
#include "imgIRequest.h"
#include "mozilla/gfx/2D.h"
@ -17,7 +19,6 @@
#include "nsNetUtil.h"
#include "nsServiceManagerUtils.h"
#include "nsShellService.h"
#include "nsWindowsShellService.h"
#include "nsIProcess.h"
#include "nsICategoryManager.h"
#include "nsBrowserCompsCID.h"
@ -85,6 +86,38 @@ OpenKeyForReading(HKEY aKeyRoot, const nsAString& aKeyName, HKEY* aKey)
return NS_OK;
}
static bool
GetPrefString(const nsCString& aPrefName, nsAString& aValue)
{
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
if (!prefs) {
return false;
}
nsAutoCString prefCStr;
nsresult rv = prefs->GetCharPref(aPrefName.get(),
getter_Copies(prefCStr));
if (NS_FAILED(rv)) {
return false;
}
CopyUTF8toUTF16(prefCStr, aValue);
return true;
}
static bool
SetPrefString(const nsCString& aPrefName, const nsString& aValue)
{
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
if (!prefs) {
return false;
}
nsresult rv = prefs->SetCharPref(aPrefName.get(),
NS_ConvertUTF16toUTF8(aValue).get());
return NS_SUCCEEDED(rv);
}
///////////////////////////////////////////////////////////////////////////////
// Default Browser Registry Settings
//
@ -322,38 +355,219 @@ nsWindowsShellService::ShortcutMaintenance()
}
static bool
IsAARDefaultHTTP(IApplicationAssociationRegistration* pAAR,
bool* aIsDefaultBrowser)
IsAARDefault(const nsRefPtr<IApplicationAssociationRegistration>& pAAR,
LPCWSTR aClassName)
{
// Make sure the Prog ID matches what we have
LPWSTR registeredApp;
HRESULT hr = pAAR->QueryCurrentDefault(L"http", AT_URLPROTOCOL, AL_EFFECTIVE,
bool isProtocol = *aClassName != L'.';
ASSOCIATIONTYPE queryType = isProtocol ? AT_URLPROTOCOL : AT_FILEEXTENSION;
HRESULT hr = pAAR->QueryCurrentDefault(aClassName, queryType, AL_EFFECTIVE,
&registeredApp);
if (SUCCEEDED(hr)) {
LPCWSTR firefoxHTTPProgID = L"FirefoxURL";
*aIsDefaultBrowser = !wcsicmp(registeredApp, firefoxHTTPProgID);
CoTaskMemFree(registeredApp);
} else {
*aIsDefaultBrowser = false;
if (FAILED(hr)) {
return false;
}
return SUCCEEDED(hr);
LPCWSTR progID = isProtocol ? L"FirefoxURL" : L"FirefoxHTML";
bool isDefault = !wcsicmp(registeredApp, progID);
CoTaskMemFree(registeredApp);
return isDefault;
}
static void
GetUserChoiceKeyName(LPCWSTR aClassName, bool aIsProtocol,
nsAString& aKeyName)
{
aKeyName.AssignLiteral(aIsProtocol
? "Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\"
: "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\");
aKeyName.Append(aClassName);
aKeyName.AppendLiteral("\\UserChoice");
}
static void
GetHashPrefName(LPCWSTR aClassName, nsACString& aPrefName)
{
aPrefName.AssignLiteral("browser.shell.associationHash.");
aPrefName.Append(NS_ConvertUTF16toUTF8(*aClassName == L'.' ? aClassName + 1
: aClassName));
}
static bool
IsAARDefaultHTML(IApplicationAssociationRegistration* pAAR,
bool* aIsDefaultBrowser)
SaveWin8RegistryHash(const nsRefPtr<IApplicationAssociationRegistration>& pAAR,
LPCWSTR aClassName)
{
LPWSTR registeredApp;
HRESULT hr = pAAR->QueryCurrentDefault(L".html", AT_FILEEXTENSION, AL_EFFECTIVE,
&registeredApp);
if (SUCCEEDED(hr)) {
LPCWSTR firefoxHTMLProgID = L"FirefoxHTML";
*aIsDefaultBrowser = !wcsicmp(registeredApp, firefoxHTMLProgID);
CoTaskMemFree(registeredApp);
} else {
*aIsDefaultBrowser = false;
bool isProtocol = *aClassName != L'.';
bool isDefault = IsAARDefault(pAAR, aClassName);
// We can save the value only if Firefox is the default.
if (!isDefault) {
return isDefault;
}
return SUCCEEDED(hr);
nsAutoString keyName;
GetUserChoiceKeyName(aClassName, isProtocol, keyName);
nsCOMPtr<nsIWindowsRegKey> regKey =
do_CreateInstance("@mozilla.org/windows-registry-key;1");
if (!regKey) {
return isDefault;
}
nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
keyName, nsIWindowsRegKey::ACCESS_READ);
if (NS_FAILED(rv)) {
return isDefault;
}
nsAutoString hash;
rv = regKey->ReadStringValue(NS_LITERAL_STRING("Hash"), hash);
if (NS_FAILED(rv)) {
return isDefault;
}
nsAutoCString prefName;
GetHashPrefName(aClassName, prefName);
SetPrefString(prefName, hash);
return isDefault;
}
static bool
RestoreWin8RegistryHash(const nsRefPtr<IApplicationAssociationRegistration>& pAAR,
LPCWSTR aClassName)
{
nsAutoCString prefName;
GetHashPrefName(aClassName, prefName);
nsAutoString hash;
if (!GetPrefString(prefName, hash)) {
return false;
}
bool isProtocol = *aClassName != L'.';
nsString progId = isProtocol ? NS_LITERAL_STRING("FirefoxURL")
: NS_LITERAL_STRING("FirefoxHTML");
nsAutoString keyName;
GetUserChoiceKeyName(aClassName, isProtocol, keyName);
nsCOMPtr<nsIWindowsRegKey> regKey =
do_CreateInstance("@mozilla.org/windows-registry-key;1");
if (!regKey) {
return false;
}
nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
keyName, nsIWindowsRegKey::ACCESS_READ);
if (NS_SUCCEEDED(rv)) {
nsAutoString currValue;
if (NS_SUCCEEDED(regKey->ReadStringValue(NS_LITERAL_STRING("Hash"),
currValue)) &&
currValue.Equals(hash) &&
NS_SUCCEEDED(regKey->ReadStringValue(NS_LITERAL_STRING("ProgId"),
currValue)) &&
currValue.Equals(progId)) {
// The value is already set.
return true;
}
// We need to close this explicitly because nsIWindowsRegKey::SetKey
// does not close the old key.
regKey->Close();
}
// We have to use the registry function directly because
// nsIWindowsRegKey::Create will only return NS_ERROR_FAILURE
// on failure.
HKEY theKey;
DWORD res = ::RegOpenKeyExW(HKEY_CURRENT_USER, keyName.get(), 0,
KEY_READ | KEY_SET_VALUE, &theKey);
if (REG_FAILED(res)) {
if (res != ERROR_ACCESS_DENIED && res != ERROR_FILE_NOT_FOUND) {
return false;
}
if (res == ERROR_ACCESS_DENIED) {
res = ::RegDeleteKeyW(HKEY_CURRENT_USER, keyName.get());
if (REG_FAILED(res)) {
return false;
}
}
res = ::RegCreateKeyExW(HKEY_CURRENT_USER, keyName.get(), 0,
nullptr, 0, KEY_READ | KEY_SET_VALUE,
nullptr, &theKey, nullptr);
if (REG_FAILED(res)) {
return false;
}
}
regKey->SetKey(theKey);
rv = regKey->WriteStringValue(NS_LITERAL_STRING("Hash"), hash);
if (NS_FAILED(rv)) {
return false;
}
rv = regKey->WriteStringValue(NS_LITERAL_STRING("ProgId"), progId);
if (NS_FAILED(rv)) {
return false;
}
return IsAARDefault(pAAR, aClassName);
}
static void
SaveWin8RegistryHashes(bool aCheckAllTypes, bool* aIsDefaultBrowser)
{
nsRefPtr<IApplicationAssociationRegistration> pAAR;
HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
nullptr,
CLSCTX_INPROC,
IID_IApplicationAssociationRegistration,
getter_AddRefs(pAAR));
if (FAILED(hr)) {
return;
}
bool res = SaveWin8RegistryHash(pAAR, L"http");
if (*aIsDefaultBrowser) {
*aIsDefaultBrowser = res;
}
SaveWin8RegistryHash(pAAR, L"https");
SaveWin8RegistryHash(pAAR, L"ftp");
res = SaveWin8RegistryHash(pAAR, L".html");
if (*aIsDefaultBrowser && aCheckAllTypes) {
*aIsDefaultBrowser = res;
}
SaveWin8RegistryHash(pAAR, L".htm");
SaveWin8RegistryHash(pAAR, L".shtml");
SaveWin8RegistryHash(pAAR, L".xhtml");
SaveWin8RegistryHash(pAAR, L".xht");
}
static bool
RestoreWin8RegistryHashes(bool aClaimAllTypes)
{
nsRefPtr<IApplicationAssociationRegistration> pAAR;
HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
nullptr,
CLSCTX_INPROC,
IID_IApplicationAssociationRegistration,
getter_AddRefs(pAAR));
if (FAILED(hr)) {
return false;
}
bool res = RestoreWin8RegistryHash(pAAR, L"http");
res = RestoreWin8RegistryHash(pAAR, L"https") && res;
RestoreWin8RegistryHash(pAAR, L"ftp");
bool res2 = RestoreWin8RegistryHash(pAAR, L".html");
res2 = RestoreWin8RegistryHash(pAAR, L".htm") && res2;
if (aClaimAllTypes) {
res = res && res2;
}
RestoreWin8RegistryHash(pAAR, L".shtml");
RestoreWin8RegistryHash(pAAR, L".xhtml");
RestoreWin8RegistryHash(pAAR, L".xht");
return res;
}
/*
@ -366,37 +580,27 @@ bool
nsWindowsShellService::IsDefaultBrowserVista(bool aCheckAllTypes,
bool* aIsDefaultBrowser)
{
IApplicationAssociationRegistration* pAAR;
nsRefPtr<IApplicationAssociationRegistration> pAAR;
HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
nullptr,
CLSCTX_INPROC,
IID_IApplicationAssociationRegistration,
(void**)&pAAR);
if (SUCCEEDED(hr)) {
if (aCheckAllTypes) {
BOOL res;
hr = pAAR->QueryAppIsDefaultAll(AL_EFFECTIVE,
APP_REG_NAME,
&res);
*aIsDefaultBrowser = res;
// If we have all defaults, let's make sure that our ProgID
// is explicitly returned as well. Needed only for Windows 8.
if (*aIsDefaultBrowser && IsWin8OrLater()) {
IsAARDefaultHTTP(pAAR, aIsDefaultBrowser);
if (*aIsDefaultBrowser) {
IsAARDefaultHTML(pAAR, aIsDefaultBrowser);
}
}
} else {
IsAARDefaultHTTP(pAAR, aIsDefaultBrowser);
}
pAAR->Release();
return true;
getter_AddRefs(pAAR));
if (FAILED(hr)) {
return false;
}
return false;
if (aCheckAllTypes) {
BOOL res;
hr = pAAR->QueryAppIsDefaultAll(AL_EFFECTIVE,
APP_REG_NAME,
&res);
*aIsDefaultBrowser = res;
} else if (!IsWin8OrLater()) {
*aIsDefaultBrowser = IsAARDefault(pAAR, L"http");
}
return true;
}
NS_IMETHODIMP
@ -496,6 +700,9 @@ nsWindowsShellService::IsDefaultBrowser(bool aStartupCheck,
// previous checks show that Firefox is the default browser.
if (*aIsDefaultBrowser) {
IsDefaultBrowserVista(aForAllTypes, aIsDefaultBrowser);
if (IsWin8OrLater()) {
SaveWin8RegistryHashes(aForAllTypes, aIsDefaultBrowser);
}
}
// To handle the case where DDE isn't disabled due for a user because there
@ -730,7 +937,8 @@ nsWindowsShellService::SetDefaultBrowser(bool aClaimAllTypes, bool aForAllUsers)
}
nsresult rv = LaunchHelper(appHelperPath);
if (NS_SUCCEEDED(rv) && IsWin8OrLater()) {
if (NS_SUCCEEDED(rv) && IsWin8OrLater() &&
!RestoreWin8RegistryHashes(aClaimAllTypes)) {
if (aClaimAllTypes) {
if (IsWin10OrLater()) {
rv = LaunchModernSettingsDialogDefaultApps();
@ -760,6 +968,8 @@ nsWindowsShellService::SetDefaultBrowser(bool aClaimAllTypes, bool aForAllUsers)
if (NS_FAILED(rv)) {
rv = LaunchControlPanelDefaultsSelectionUI();
}
bool isDefault;
SaveWin8RegistryHashes(aClaimAllTypes, &isDefault);
}
}

View File

@ -84,10 +84,34 @@ this.Translation = {
},
openProviderAttribution: function() {
let attribution = this.supportedEngines[this.translationEngine];
Cu.import("resource:///modules/RecentWindow.jsm");
RecentWindow.getMostRecentBrowserWindow().openUILinkIn(
"http://aka.ms/MicrosoftTranslatorAttribution", "tab");
}
RecentWindow.getMostRecentBrowserWindow().openUILinkIn(attribution, "tab");
},
/**
* The list of translation engines and their attributions.
*/
supportedEngines: {
"bing" : "http://aka.ms/MicrosoftTranslatorAttribution",
"yandex" : "http://translate.yandex.com/"
},
/**
* Fallback engine (currently Bing Translator) if the preferences seem
* confusing.
*/
get defaultEngine() {
return this.supportedEngines.keys[0];
},
/**
* Returns the name of the preferred translation engine.
*/
get translationEngine() {
let engine = Services.prefs.getCharPref("browser.translation.engine");
return Object.keys(this.supportedEngines).includes(engine) ? engine : this.defaultEngine;
},
};
/* TranslationUI objects keep the information related to translation for

View File

@ -8,18 +8,22 @@
const kEnginePref = "browser.translation.engine";
const kApiKeyPref = "browser.translation.yandex.apiKeyOverride";
const kShowUIPref = "browser.translation.ui.show";
const {YandexTranslator} = Cu.import("resource:///modules/translation/YandexTranslator.jsm", {});
const {TranslationDocument} = Cu.import("resource:///modules/translation/TranslationDocument.jsm", {});
const {Promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
const {Translation} = Cu.import("resource:///modules/translation/Translation.jsm", {});
add_task(function* setup() {
Services.prefs.setCharPref(kEnginePref, "yandex");
Services.prefs.setCharPref(kApiKeyPref, "yandexValidKey");
Services.prefs.setBoolPref(kShowUIPref, true);
registerCleanupFunction(function () {
Services.prefs.clearUserPref(kEnginePref);
Services.prefs.clearUserPref(kApiKeyPref);
Services.prefs.clearUserPref(kShowUIPref);
});
});
@ -45,6 +49,38 @@ add_task(function* test_yandex_translation() {
gBrowser.removeTab(tab);
});
/**
* Ensure that Yandex.Translate is propertly attributed.
*/
add_task(function* test_yandex_attribution() {
// Loading the fixture page.
let url = constructFixtureURL("bug1022725-fr.html");
let tab = yield promiseTestPageLoad(url);
info("Show an info bar saying the current page is in French");
let notif = showTranslationUI(tab, "fr");
let attribution = notif._getAnonElt("translationEngine").selectedIndex;
Assert.equal(attribution, 1, "Yandex attribution should be shown.");
gBrowser.removeTab(tab);
});
add_task(function* test_preference_attribution() {
let prefUrl = "about:preferences#content";
let tab = yield promiseTestPageLoad(prefUrl);
let browser = gBrowser.getBrowserForTab(tab);
let win = browser.contentWindow;
let bingAttribution = win.document.getElementById("bingAttribution");
ok(bingAttribution, "Bing attribution should exist.");
ok(bingAttribution.hidden, "Bing attribution should be hidden.");
gBrowser.removeTab(tab);
});
/**
* A helper function for constructing a URL to a page stored in the
* local fixture folder.
@ -79,3 +115,12 @@ function promiseTestPageLoad(url) {
}, true);
return deferred.promise;
}
function showTranslationUI(tab, aDetectedLanguage) {
let browser = gBrowser.selectedBrowser;
Translation.documentStateReceived(browser, {state: Translation.STATE_OFFER,
originalShown: true,
detectedLanguage: aDetectedLanguage});
let ui = browser.translationUI;
return ui.notificationBox.getNotificationWithValue("translation");
}

View File

@ -127,12 +127,17 @@
<xul:menuitem oncommand="openPreferences('paneContent');"
label="&translation.options.preferences.label;"
accesskey="&translation.options.preferences.accesskey;"/>
<xul:menuitem class="translation-attribution subviewbutton panel-subview-footer"
<xul:menuitem class="subviewbutton panel-subview-footer"
oncommand="document.getBindingParent(this).openProviderAttribution();">
<xul:label>&translation.options.attribution.beforeLogo;</xul:label>
<xul:image src="chrome://browser/content/microsoft-translator-attribution.png"
aria-label="Microsoft Translator"/>
<xul:label>&translation.options.attribution.afterLogo;</xul:label>
<xul:deck anonid="translationEngine" selectedIndex="0">
<xul:hbox class="translation-attribution">
<xul:label>&translation.options.attribution.beforeLogo;</xul:label>
<xul:image src="chrome://browser/content/microsoft-translator-attribution.png"
aria-label="Microsoft Translator"/>
<xul:label>&translation.options.attribution.afterLogo;</xul:label>
</xul:hbox>
<xul:label class="translation-attribution">&translation.options.attribution.yandexTranslate;</xul:label>
</xul:deck>
</xul:menuitem>
</xul:menupopup>
</xul:button>
@ -215,6 +220,13 @@
if (aTranslation.state)
this.state = aTranslation.state;
// Show attribution for the preferred translator.
let engineIndex = Object.keys(Translation.supportedEngines)
.indexOf(Translation.translationEngine);
if (engineIndex != -1) {
this._getAnonElt('translationEngine').selectedIndex = engineIndex;
}
const kWelcomePref = "browser.translation.ui.welcomeMessageShown";
if (Services.prefs.prefHasUserValue(kWelcomePref) ||
this.translation.browser != gBrowser.selectedBrowser)

View File

@ -1176,13 +1176,25 @@ InspectorPanel.prototype = {
/**
* This method is here for the benefit of the node-menu-link-follow menu item
* in the inspector contextual-menu. It's behavior depends on which node was
* right-clicked when the menu was opened.
* in the inspector contextual-menu.
*/
followAttributeLink: function(e) {
onFollowLink: function() {
let type = this.panelDoc.popupNode.dataset.type;
let link = this.panelDoc.popupNode.dataset.link;
this.followAttributeLink(type, link);
},
/**
* Given a type and link found in a node's attribute in the markup-view,
* attempt to follow that link (which may result in opening a new tab, the
* style editor or debugger).
*/
followAttributeLink: function(type, link) {
if (!type || !link) {
return;
}
if (type === "uri" || type === "cssresource" || type === "jsresource") {
// Open link in a new tab.
// When the inspector menu was setup on click (see _setupNodeLinkMenu), we
@ -1213,11 +1225,18 @@ InspectorPanel.prototype = {
/**
* This method is here for the benefit of the node-menu-link-copy menu item
* in the inspector contextual-menu. It's behavior depends on which node was
* right-clicked when the menu was opened.
* in the inspector contextual-menu.
*/
copyAttributeLink: function(e) {
onCopyLink: function() {
let link = this.panelDoc.popupNode.dataset.link;
this.copyAttributeLink(link);
},
/**
* This method is here for the benefit of copying links.
*/
copyAttributeLink: function(link) {
// When the inspector menu was setup on click (see _setupNodeLinkMenu), we
// already checked that resolveRelativeURL existed.
this.inspector.resolveRelativeURL(link, this.selection.nodeFront).then(url => {

View File

@ -106,9 +106,9 @@
oncommand="inspector.deleteNode()"/>
<menuseparator id="node-menu-link-separator"/>
<menuitem id="node-menu-link-follow"
oncommand="inspector.followAttributeLink()"/>
oncommand="inspector.onFollowLink()"/>
<menuitem id="node-menu-link-copy"
oncommand="inspector.copyAttributeLink()"/>
oncommand="inspector.onCopyLink()"/>
<menuseparator/>
<menuitem id="node-menu-pseudo-hover"
label=":hover" type="checkbox"

View File

@ -1933,6 +1933,15 @@ MarkupContainer.prototype = {
event.preventDefault();
}
let isMiddleClick = event.button === 1;
let isMetaClick = event.button === 0 && (event.metaKey || event.ctrlKey);
if (isMiddleClick || isMetaClick) {
let link = target.dataset.link;
let type = target.dataset.type;
this.markup._inspector.followAttributeLink(type, link);
}
// Start dragging the container after a delay.
this.markup._dragStartEl = target;
setTimeout(() => {

View File

@ -79,6 +79,7 @@ skip-if = e10s # Bug 1040751 - CodeMirror editor.destroy() isn't e10s compatible
[browser_markupview_links_04.js]
[browser_markupview_links_05.js]
[browser_markupview_links_06.js]
[browser_markupview_links_07.js]
[browser_markupview_load_01.js]
[browser_markupview_html_edit_01.js]
[browser_markupview_html_edit_02.js]

View File

@ -22,7 +22,7 @@ add_task(function*() {
info("Follow the link and wait for the new tab to open");
let onTabOpened = once(gBrowser.tabContainer, "TabOpen");
inspector.followAttributeLink();
inspector.onFollowLink();
let {target: tab} = yield onTabOpened;
yield waitForTabLoad(tab);
@ -41,7 +41,7 @@ add_task(function*() {
info("Follow the link and wait for the new node to be selected");
let onSelection = inspector.selection.once("new-node-front");
inspector.followAttributeLink();
inspector.onFollowLink();
yield onSelection;
ok(true, "A new node was selected");
@ -57,7 +57,7 @@ add_task(function*() {
info("Try to follow the link and check that no new node were selected");
let onFailed = inspector.once("idref-attribute-link-failed");
inspector.followAttributeLink();
inspector.onFollowLink();
yield onFailed;
ok(true, "The node selection failed");

View File

@ -22,7 +22,7 @@ add_task(function*() {
info("Follow the link and wait for the style-editor to open");
let onStyleEditorReady = toolbox.once("styleeditor-ready");
inspector.followAttributeLink();
inspector.onFollowLink();
yield onStyleEditorReady;
// No real need to test that the editor opened on the right file here as this
@ -42,7 +42,7 @@ add_task(function*() {
info("Follow the link and wait for the debugger to open");
let onDebuggerReady = toolbox.once("jsdebugger-ready");
inspector.followAttributeLink();
inspector.onFollowLink();
yield onDebuggerReady;
// No real need to test that the debugger opened on the right file here as

View File

@ -0,0 +1,118 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests that a middle-click or meta/ctrl-click on links in attributes actually
// do follows the link.
const TEST_URL = TEST_URL_ROOT + "doc_markup_links.html";
add_task(function*() {
let {inspector} = yield addTab(TEST_URL).then(openInspector);
info("Select a node with a URI attribute");
yield selectNode("video", inspector);
info("Find the link element from the markup-view");
let {editor} = yield getContainerForSelector("video", inspector);
let linkEl = editor.attrElements.get("poster").querySelector(".link");
info("Follow the link with middle-click and wait for the new tab to open");
yield followLinkWaitForTab(linkEl, false,
TEST_URL_ROOT + "doc_markup_tooltip.png");
info("Follow the link with meta/ctrl-click and wait for the new tab to open");
yield followLinkWaitForTab(linkEl, true,
TEST_URL_ROOT + "doc_markup_tooltip.png");
info("Select a node with a IDREF attribute");
yield selectNode("label", inspector);
info("Find the link element from the markup-view that contains the ref");
({editor} = yield getContainerForSelector("label", inspector));
linkEl = editor.attrElements.get("for").querySelector(".link");
info("Follow link with middle-click, wait for new node to be selected.");
yield followLinkWaitForNewNode(linkEl, false, inspector);
info("Follow link with ctrl/meta-click, wait for new node to be selected.");
yield followLinkWaitForNewNode(linkEl, true, inspector);
info("Select a node with an invalid IDREF attribute");
yield selectNode("output", inspector);
info("Find the link element from the markup-view that contains the ref");
({editor} = yield getContainerForSelector("output", inspector));
linkEl = editor.attrElements.get("for").querySelectorAll(".link")[2];
info("Try to follow link wiith middle-click, check no new node selected");
yield followLinkNoNewNode(linkEl, false, inspector);
info("Try to follow link wiith meta/ctrl-click, check no new node selected");
yield followLinkNoNewNode(linkEl, true, inspector);
});
function waitForTabLoad(tab) {
let def = promise.defer();
tab.addEventListener("load", function onLoad() {
// Skip load event for about:blank
if (tab.linkedBrowser.currentURI.spec === "about:blank") {
return;
}
tab.removeEventListener("load", onLoad);
def.resolve();
});
return def.promise;
}
function performMouseDown(linkEl, metactrl) {
let evt = linkEl.ownerDocument.createEvent("MouseEvents");
let button = -1;
if (metactrl) {
info("Performing Meta/Ctrl+Left Click");
button = 0;
} else {
info("Performing Middle Click");
button = 1;
}
evt.initMouseEvent("mousedown", true, true,
linkEl.ownerDocument.defaultView, 1, 0, 0, 0, 0, metactrl,
false, false, metactrl, button, null);
linkEl.dispatchEvent(evt);
}
function* followLinkWaitForTab(linkEl, isMetaClick, expectedTabURI) {
let onTabOpened = once(gBrowser.tabContainer, "TabOpen");
performMouseDown(linkEl, isMetaClick);
let {target} = yield onTabOpened;
yield waitForTabLoad(target);
ok(true, "A new tab opened");
is(target.linkedBrowser.currentURI.spec, expectedTabURI,
"The URL for the new tab is correct");
gBrowser.removeTab(target);
}
function* followLinkWaitForNewNode(linkEl, isMetaClick, inspector) {
let onSelection = inspector.selection.once("new-node-front");
performMouseDown(linkEl, isMetaClick);
yield onSelection;
ok(true, "A new node was selected");
is(inspector.selection.nodeFront.id, "name", "The right node was selected");
}
function* followLinkNoNewNode(linkEl, isMetaClick, inspector) {
let onFailed = inspector.once("idref-attribute-link-failed");
performMouseDown(linkEl, isMetaClick);
yield onFailed;
ok(true, "The node selection failed");
is(inspector.selection.nodeFront.tagName.toLowerCase(), "output",
"The <output> node is still selected");
}

View File

@ -35,7 +35,6 @@ label,
text-transform: uppercase;
line-height: 200%;
margin: 5px 5px 0 5px;
font-size: 10%;
font-weight: 700;
width: 100%;
}

View File

@ -64,3 +64,12 @@
-->
<!ENTITY translation.options.attribution.beforeLogo "Translations by">
<!ENTITY translation.options.attribution.afterLogo "">
<!-- LOCALIZATION NOTE (translation.options.attribution.poweredByYandex,
translation.options.attribution.beforeLogo,
- translation.options.attribution.afterLogo):
- translation.options.attribution.poweredByYandex is displayed instead of
- the other two strings when yandex translation engine is preferred by the
- user.
-->
<!ENTITY translation.options.attribution.yandexTranslate "Powered by Yandex.Translate">

View File

@ -19,6 +19,8 @@
%define conditionalForwardWithUrlbarWidth 30
:root {
--backbutton-urlbar-overlap: 5px;
--toolbarbutton-hover-background: hsla(0,0%,100%,.3) linear-gradient(hsla(0,0%,100%,.7), hsla(0,0%,100%,.2));
--toolbarbutton-hover-boxshadow: 0 1px 0 hsla(0,0%,100%,.3) inset, 0 0 0 1px hsla(0,0%,100%,.2) inset, 0 1px 0 hsla(0,0%,0%,.03);
--toolbarbutton-hover-bordercolor: rgb(154,154,154);
@ -846,7 +848,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
#urlbar,
.searchbar-textbox {
-moz-appearance: none;
padding: 1px;
padding: 0;
border: 1px solid ThreeDShadow;
border-radius: 2px;
margin: 0 3px;
@ -895,7 +897,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
@conditionalForwardWithUrlbar@ {
clip-path: url("chrome://browser/content/browser.xul#urlbar-back-button-clip-path");
-moz-margin-start: -5px;
margin-inline-start: calc(-1 * var(--backbutton-urlbar-overlap));
}
@conditionalForwardWithUrlbar@:-moz-locale-dir(rtl),
@ -973,14 +975,6 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
/* identity box */
#identity-box {
margin: -1px;
-moz-margin-end: 4px;
padding: 2px;
-moz-padding-end: 1px;
font-size: .9em;
}
#identity-box:-moz-locale-dir(ltr) {
border-top-left-radius: 1.5px;
border-bottom-left-radius: 1.5px;
@ -991,42 +985,6 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
border-bottom-right-radius: 1.5px;
}
#notification-popup-box:not([hidden]) + #identity-box {
-moz-padding-start: 10px;
border-radius: 0;
}
@conditionalForwardWithUrlbar@ > #urlbar > #identity-box {
border-radius: 0;
}
@conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar > #identity-box {
transition: padding-left, padding-right;
}
@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
padding-left: 5px;
}
@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
padding-right: 5px;
}
@conditionalForwardWithUrlbar@:hover:not([switchingtabs]) > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box {
/* forward button hiding is delayed when hovered */
transition-delay: 100s;
}
@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] + #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@:not(:hover) > #forward-button[disabled] + #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;
}
#identity-box.verifiedIdentity:not(:-moz-lwtheme):not(:hover):not([open=true]) {
background-color: var(--verified-identity-box-backgroundcolor);
}
@ -1036,20 +994,8 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
outline-offset: -3px;
}
#identity-icon-labels {
-moz-padding-start: 2px;
-moz-padding-end: 5px;
}
%include ../shared/identity-block/identity-block.inc.css
#page-proxy-favicon {
margin-top: 1px;
margin-bottom: 1px;
-moz-margin-start: 3px;
-moz-margin-end: 1px;
}
%include ../shared/notification-icons.inc.css
.popup-notification-body[popupid="addon-progress"],
@ -1065,8 +1011,6 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
/* Notification icon box */
#notification-popup-box {
border-radius: 2.5px 0 0 2.5px;
margin-top: -1px;
margin-bottom: -1px;
}
.notification-anchor-icon:-moz-focusring {

View File

@ -7,11 +7,6 @@
padding: 1px;
}
.searchbar-textbox {
min-height: 22px;
background-color: -moz-field;
}
.autocomplete-textbox-container {
-moz-box-align: stretch;
}
@ -81,6 +76,8 @@ menuitem[cmd="cmd_clearhistory"][disabled] {
.searchbar-search-button {
list-style-image: url("chrome://browser/skin/search-indicator.png");
-moz-image-region: rect(0, 20px, 20px, 0);
margin-top: 1px;
margin-bottom: 1px;
-moz-margin-start: 2px;
}

View File

@ -18,8 +18,10 @@
:root {
--space-above-tabbar: 9px;
--tabs-toolbar-color: #333;
--backbutton-urlbar-overlap: 6px;
--toolbarbutton-hover-background: hsla(0,0%,100%,.1) linear-gradient(hsla(0,0%,100%,.3), hsla(0,0%,100%,.1)) padding-box;
--toolbarbutton-hover-bordercolor: hsla(0,0%,0%,.2);
--toolbarbutton-hover-boxshadow: 0 1px 0 hsla(0,0%,100%,.5),
@ -1633,7 +1635,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
@conditionalForwardWithUrlbar@ {
clip-path: url("chrome://browser/content/browser.xul#urlbar-back-button-clip-path");
-moz-margin-start: -6px;
margin-inline-start: calc(-1 * var(--backbutton-urlbar-overlap));
}
@conditionalForwardWithUrlbar@:-moz-locale-dir(rtl),
@ -1646,24 +1648,19 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
-moz-box-direction: reverse;
}
#identity-box {
margin: 0;
-moz-margin-end: 3px;
padding: 1px 4px;
font-size: .9em;
}
#urlbar:not([focused="true"]) > #identity-box {
margin: -1px 0;
-moz-margin-end: 3px;
padding: 2px 4px;
margin-top: -1px;
margin-bottom: -1px;
padding-top: 3px;
padding-bottom: 3px;
}
@media (-moz-mac-yosemite-theme) {
#urlbar:not([focused="true"]):not(:-moz-window-inactive) > #identity-box {
margin: -2px 0;
-moz-margin-end: 3px;
padding: 3px 4px;
margin-top: -2px;
margin-bottom: -2px;
padding-top: 4px;
padding-bottom: 4px;
}
#identity-box {
--identity-box-selected-background-color: rgb(240,237,237);
@ -1680,40 +1677,6 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
border-bottom-right-radius: 2px;
}
#notification-popup-box:not([hidden]) + #identity-box {
-moz-padding-start: 10px !important;
border-radius: 0;
}
@conditionalForwardWithUrlbar@ > #urlbar > #identity-box {
border-radius: 0;
}
@conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar > #identity-box {
transition: padding-left, padding-right;
}
@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
padding-left: 10px;
}
@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
padding-right: 10px;
}
@conditionalForwardWithUrlbar@:hover:not([switchingtabs]) > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box {
/* forward button hiding is delayed when hovered */
transition-delay: 100s;
}
@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
padding-left: 10.01px;
}
@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
padding-right: 10.01px;
}
#identity-box:-moz-focusring {
box-shadow: 0 0 2px 1px -moz-mac-focusring inset,
0 0 2px 2px -moz-mac-focusring;
@ -1721,10 +1684,6 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
-moz-padding-end: 5px;
}
#identity-icon-labels {
-moz-margin-start: 4px;
}
.urlbar-input-box {
-moz-margin-start: 0;
padding: 3px 0 2px;
@ -1807,11 +1766,6 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
%include ../shared/identity-block/identity-block.inc.css
#page-proxy-favicon {
margin: 0px;
padding: 0px;
}
#wrapper-urlbar-container[place="palette"] {
max-width: 20em;
}

View File

@ -140,9 +140,10 @@
.identity-popup-expander[panel-multiview-anchor] {
transition: background-color 250ms ease-in;
background-color: #0069d9;
background-color: Highlight;
background-image: url("chrome://browser/skin/customizableui/subView-arrow-back-inverted.png"),
linear-gradient(rgba(255,255,255,0.3), transparent);
color: HighlightText;
}
@media (min-resolution: 1.1dppx) {

View File

@ -48,6 +48,9 @@
background-size: 1px;
background-repeat: no-repeat;
background-image: var(--identity-box-background-image);
font-size: .9em;
padding: 2px 5px;
margin-inline-end: 4px;
}
#identity-box:-moz-locale-dir(rtl) {
@ -69,11 +72,52 @@
background-image: var(--identity-box-chrome-background-image);
}
#identity-icon-labels {
padding-inline-start: 2px;
}
#notification-popup-box:not([hidden]) + #identity-box {
-moz-padding-start: 10px;
border-radius: 0;
}
@conditionalForwardWithUrlbar@ > #urlbar > #identity-box {
border-radius: 0;
}
@conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar > #identity-box {
transition: padding-left, padding-right;
}
@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
padding-left: calc(var(--backbutton-urlbar-overlap) + 4px);
}
@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
padding-right: calc(var(--backbutton-urlbar-overlap) + 4px);
}
@conditionalForwardWithUrlbar@:hover:not([switchingtabs]) > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box {
/* forward button hiding is delayed when hovered */
transition-delay: 100s;
}
@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] + #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: calc(var(--backbutton-urlbar-overlap) + 4.01px);
}
@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] + #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: calc(var(--backbutton-urlbar-overlap) + 4.01px);
}
/* TRACKING PROTECTION ICON */
#tracking-protection-icon {
width: 16px;
height: 16px;
margin-inline-end: 2px;
list-style-image: url(chrome://browser/skin/tracking-protection-16.svg);
}

View File

@ -20,6 +20,8 @@
:root {
--space-above-tabbar: 15px;
--backbutton-urlbar-overlap: 5px;
--toolbarbutton-vertical-inner-padding: 2px;
--toolbarbutton-vertical-outer-padding: 8px;
@ -1238,7 +1240,6 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
#urlbar:not(:-moz-lwtheme):hover,
.searchbar-textbox:not(:-moz-lwtheme):hover {
border-color: hsl(0,0%,80%);
box-shadow: 0 0 0 1px hsl(0,0%,80%) inset;
}
#urlbar:not(:-moz-lwtheme)[focused],
@ -1304,13 +1305,16 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
@conditionalForwardWithUrlbar@ {
clip-path: url("chrome://browser/content/browser.xul#urlbar-back-button-clip-path");
-moz-margin-start: -5px;
margin-inline-start: calc(-1 * var(--backbutton-urlbar-overlap));
}
@media (-moz-os-version: windows-win10) {
@conditionalForwardWithUrlbar@ {
clip-path: url("chrome://browser/content/browser.xul#urlbar-back-button-clip-path-win10");
-moz-margin-start: -8px;
}
:root {
--backbutton-urlbar-overlap: 8px;
}
}
@ -1420,12 +1424,6 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder,
/* identity box */
#identity-box {
padding: 2px;
font-size: .9em;
-moz-margin-end: 4px;
}
#identity-box:-moz-locale-dir(ltr) {
border-top-left-radius: 1.5px;
border-bottom-left-radius: 1.5px;
@ -1436,42 +1434,6 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder,
border-bottom-right-radius: 1.5px;
}
#notification-popup-box:not([hidden]) + #identity-box {
-moz-padding-start: 10px;
border-radius: 0;
}
@conditionalForwardWithUrlbar@ > #urlbar > #identity-box {
border-radius: 0;
}
@conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar > #identity-box {
transition: padding-left, padding-right;
}
@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
padding-left: 5px;
}
@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
padding-right: 5px;
}
@conditionalForwardWithUrlbar@:hover:not([switchingtabs]) > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box {
/* forward button hiding is delayed when hovered */
transition-delay: 100s;
}
@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] + #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@:not(:hover) > #forward-button[disabled] + #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;
}
#identity-box.verifiedIdentity:not(:-moz-lwtheme):not(:hover):not([open=true]) {
background-color: var(--verified-identity-box-backgroundcolor);
}
@ -1481,11 +1443,6 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder,
outline-offset: -3px;
}
#identity-icon-labels {
-moz-padding-start: 2px;
-moz-padding-end: 5px;
}
/* Location bar dropmarker */
.urlbar-history-dropmarker {
@ -1533,19 +1490,6 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder,
%include ../shared/identity-block/identity-block.inc.css
#page-proxy-favicon {
margin-top: 1px;
margin-bottom: 1px;
-moz-margin-start: 3px;
-moz-margin-end: 1px;
}
@media (-moz-os-version: windows-win10) {
#page-proxy-favicon {
-moz-margin-start: 6px;
}
}
/* autocomplete */
#treecolAutoCompleteImage {

View File

@ -106,13 +106,13 @@
/* Tab styling - make sure to use an inverted icon for the selected tab
(brighttext only covers the unselected tabs) */
.tab-close-button[visuallyselected=true]:not(:hover) {
-moz-image-region: rect(0, 64px, 16px, 48px);
.tab-close-button[visuallyselected=true] {
list-style-image: url("chrome://global/skin/icons/close-inverted.png");
}
@media (min-resolution: 1.1dppx) {
.tab-close-button[visuallyselected=true]:not(:hover) {
-moz-image-region: rect(0, 128px, 32px, 96px);
.tab-close-button[visuallyselected=true] {
list-style-image: url("chrome://global/skin/icons/close-inverted@2x.png");
}
}

View File

@ -181,7 +181,7 @@ public class RestrictedProfiles {
return isUserRestricted(GeckoAppShell.getContext());
}
private static boolean isUserRestricted(final Context context) {
public static boolean isUserRestricted(final Context context) {
// Guest mode is supported in all Android versions.
if (getInGuest()) {
return true;

View File

@ -32,7 +32,7 @@ import java.util.zip.ZipFile;
import javax.net.ssl.SSLException;
import org.apache.http.protocol.HTTP;
import ch.boye.httpclientandroidlib.protocol.HTTP;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

View File

@ -8,13 +8,13 @@ package org.mozilla.gecko.favicons;
import android.content.ContentResolver;
import android.content.Context;
import android.graphics.Bitmap;
import android.net.http.AndroidHttpClient;
import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
import android.text.TextUtils;
import android.util.Log;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import ch.boye.httpclientandroidlib.Header;
import ch.boye.httpclientandroidlib.HttpEntity;
import ch.boye.httpclientandroidlib.HttpResponse;
import ch.boye.httpclientandroidlib.client.methods.HttpGet;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.db.BrowserDB;
@ -72,7 +72,7 @@ public class LoadFaviconTask {
private LinkedList<LoadFaviconTask> chainees;
private boolean isChaining;
static AndroidHttpClient httpClient = AndroidHttpClient.newInstance(GeckoAppShell.getGeckoInterface().getDefaultUAString());
static DefaultHttpClient httpClient = new DefaultHttpClient();
public LoadFaviconTask(Context context, String pageURL, String faviconURL, int flags, OnFaviconLoadedListener listener) {
this(context, pageURL, faviconURL, flags, listener, -1, false);
@ -128,6 +128,7 @@ public class LoadFaviconTask {
}
HttpGet request = new HttpGet(faviconURI);
request.setHeader("User-Agent", GeckoAppShell.getGeckoInterface().getDefaultUAString());
HttpResponse response = httpClient.execute(request);
if (response == null) {
return null;

View File

@ -697,7 +697,7 @@ OnSharedPreferenceChangeListener
}
}
if (PREFS_DEVTOOLS.equals(key) &&
RestrictedProfiles.isUserRestricted()) {
RestrictedProfiles.isUserRestricted(this)) {
preferences.removePreference(pref);
i--;
continue;

View File

@ -9,6 +9,8 @@
#include "mozilla/ipc/URIUtils.h"
#include "nsCookieService.h"
#include "nsIScriptSecurityManager.h"
#include "nsIPrivateBrowsingChannel.h"
#include "nsNetCID.h"
#include "nsPrintfCString.h"
#include "SerializedLoadContext.h"
@ -17,6 +19,33 @@ using namespace mozilla::ipc;
using mozilla::dom::PContentParent;
using mozilla::net::NeckoParent;
namespace {
bool
CreateDummyChannel(nsIURI* aHostURI, bool aIsPrivate, nsIChannel **aChannel)
{
nsCOMPtr<nsIPrincipal> principal;
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
nsresult rv = ssm->GetNoAppCodebasePrincipal(aHostURI, getter_AddRefs(principal));
if (NS_FAILED(rv)) {
return false;
}
nsCOMPtr<nsIChannel> dummyChannel;
NS_NewChannel(getter_AddRefs(dummyChannel), aHostURI, principal,
nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_INVALID);
nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryInterface(dummyChannel);
if (!pbChannel) {
return false;
}
pbChannel->SetPrivate(aIsPrivate);
dummyChannel.forget(aChannel);
return true;
}
}
namespace mozilla {
namespace net {
@ -126,11 +155,22 @@ CookieServiceParent::RecvSetCookieString(const URIParams& aHost,
return false;
}
// This is a gross hack. We've already computed everything we need to know
// for whether to set this cookie or not, but we need to communicate all of
// this information through to nsICookiePermission, which indirectly
// computes the information from the channel. We only care about the
// aIsPrivate argument as nsCookieService::SetCookieStringInternal deals
// with aIsForeign before we have to worry about nsCookiePermission trying
// to use the channel to inspect it.
nsCOMPtr<nsIChannel> dummyChannel;
if (!CreateDummyChannel(hostURI, isPrivate, getter_AddRefs(dummyChannel))) {
return false;
}
nsDependentCString cookieString(aCookieString, 0);
//TODO: bug 812475, pass a real channel object
mCookieService->SetCookieStringInternal(hostURI, aIsForeign, cookieString,
aServerTime, aFromHttp, appId,
isInBrowserElement, isPrivate, nullptr);
isInBrowserElement, isPrivate, dummyChannel);
return true;
}

View File

@ -7,7 +7,7 @@ support-files =
[browser_DOMInputPasswordAdded.js]
[browser_filldoorhanger.js]
[browser_notifications.js]
skip-if = os != "win" # Intermittent failures: Bug 1182296
skip-if = true # Intermittent failures: Bug 1182296, bug 1148771
[browser_passwordmgr_fields.js]
[browser_passwordmgr_observers.js]
[browser_passwordmgr_sort.js]