mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-23 13:04:28 +00:00
Merge f-t to m-c, a=merge
This commit is contained in:
commit
a9f8d89c2f
@ -1825,7 +1825,7 @@ pref("privacy.trackingprotection.ui.enabled", false);
|
||||
#endif
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
pref("browser.tabs.remote.autostart.1", false);
|
||||
pref("browser.tabs.remote.autostart.1", true);
|
||||
#endif
|
||||
|
||||
// Temporary pref to allow printing in e10s windows on some platforms.
|
||||
|
@ -3310,7 +3310,11 @@
|
||||
|
||||
let timeoutPromise = new Promise((aResolve, aReject) => {
|
||||
timeoutId = setTimeout(() => {
|
||||
this._showBusySpinnerRemoteBrowser(toBrowser);
|
||||
if (toBrowser.isRemoteBrowser) {
|
||||
// The browser's remoteness could have changed since we
|
||||
// setTimeout so only show the spinner if it's still remote.
|
||||
this._showBusySpinnerRemoteBrowser(toBrowser);
|
||||
}
|
||||
attemptTabSwitch(aResolve, aReject);
|
||||
}, kTabSwitchTimeout);
|
||||
});
|
||||
|
@ -415,7 +415,7 @@ skip-if = buildapp == 'mulet' || e10s
|
||||
[browser_tabMatchesInAwesomebar.js]
|
||||
skip-if = e10s # Bug 1093206 - need to re-enable tests relying on swapFrameLoaders et al for e10s (test calls gBrowser.swapBrowsersAndCloseOther)
|
||||
[browser_tabMatchesInAwesomebar_perwindowpb.js]
|
||||
skip-if = e10s || true # Bug 1093373, Bug 1104755
|
||||
skip-if = e10s # Bug 1093373
|
||||
[browser_tab_drag_drop_perwindow.js]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[browser_tab_dragdrop.js]
|
||||
|
@ -80,7 +80,8 @@ function test() {
|
||||
controller.startSearch(testURL);
|
||||
|
||||
// Wait for the Awesomebar popup to appear.
|
||||
promisePopupShown(aDestWindow.gURLBar.popup).then(() => {
|
||||
let popup = aDestWindow.gURLBar.popup;
|
||||
promisePopupShown(popup).then(() => {
|
||||
function searchIsComplete() {
|
||||
return controller.searchStatus ==
|
||||
Ci.nsIAutoCompleteController.STATUS_COMPLETE_MATCH;
|
||||
@ -106,8 +107,8 @@ function test() {
|
||||
}, true);
|
||||
}
|
||||
|
||||
// Select the second match, if any.
|
||||
if (controller.matchCount > 1) {
|
||||
// Make sure the last match is selected.
|
||||
while (popup.selectedIndex < controller.matchCount - 1) {
|
||||
controller.handleKeyNavigation(KeyEvent.DOM_VK_DOWN);
|
||||
}
|
||||
|
||||
|
@ -365,21 +365,31 @@ function injectLoopAPI(targetWindow) {
|
||||
/**
|
||||
* Displays a confirmation dialog using the specified strings.
|
||||
*
|
||||
* Callback parameters:
|
||||
* - err null on success, non-null on unexpected failure to show the prompt.
|
||||
* - {Boolean} True if the user chose the OK button.
|
||||
* @param {Object} options Confirm dialog options
|
||||
* @param {Function} callback Function that will be invoked once the operation
|
||||
* finished. The first argument passed will be an
|
||||
* `Error` object or `null`. The second argument
|
||||
* will be the result of the operation, TRUE if
|
||||
* the user chose the OK button.
|
||||
*/
|
||||
confirm: {
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
value: function(bodyMessage, okButtonMessage, cancelButtonMessage, callback) {
|
||||
try {
|
||||
let buttonFlags =
|
||||
value: function(options, callback) {
|
||||
let buttonFlags;
|
||||
if (options.okButton && options.cancelButton) {
|
||||
buttonFlags =
|
||||
(Ci.nsIPrompt.BUTTON_POS_0 * Ci.nsIPrompt.BUTTON_TITLE_IS_STRING) +
|
||||
(Ci.nsIPrompt.BUTTON_POS_1 * Ci.nsIPrompt.BUTTON_TITLE_IS_STRING);
|
||||
} else if (!options.okButton && !options.cancelButton) {
|
||||
buttonFlags = Services.prompt.STD_YES_NO_BUTTONS;
|
||||
} else {
|
||||
callback(cloneValueInto(new Error("confirm: missing button options"), targetWindow));
|
||||
}
|
||||
|
||||
try {
|
||||
let chosenButton = Services.prompt.confirmEx(null, "",
|
||||
bodyMessage, buttonFlags, okButtonMessage, cancelButtonMessage,
|
||||
options.message, buttonFlags, options.okButton, options.cancelButton,
|
||||
null, null, {});
|
||||
|
||||
callback(null, chosenButton == 0);
|
||||
|
@ -403,25 +403,25 @@ loop.contacts = (function(_, mozL10n) {
|
||||
this.props.startForm("contacts_edit", contact);
|
||||
break;
|
||||
case "remove":
|
||||
navigator.mozLoop.confirm(
|
||||
mozL10n.get("confirm_delete_contact_alert"),
|
||||
mozL10n.get("confirm_delete_contact_remove_button"),
|
||||
mozL10n.get("confirm_delete_contact_cancel_button"),
|
||||
(err, result) => {
|
||||
navigator.mozLoop.confirm({
|
||||
message: mozL10n.get("confirm_delete_contact_alert"),
|
||||
okButton: mozL10n.get("confirm_delete_contact_remove_button"),
|
||||
cancelButton: mozL10n.get("confirm_delete_contact_cancel_button")
|
||||
}, (err, result) => {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
navigator.mozLoop.contacts.remove(contact._guid, err => {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
navigator.mozLoop.contacts.remove(contact._guid, err => {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
break;
|
||||
case "block":
|
||||
case "unblock":
|
||||
|
@ -403,25 +403,25 @@ loop.contacts = (function(_, mozL10n) {
|
||||
this.props.startForm("contacts_edit", contact);
|
||||
break;
|
||||
case "remove":
|
||||
navigator.mozLoop.confirm(
|
||||
mozL10n.get("confirm_delete_contact_alert"),
|
||||
mozL10n.get("confirm_delete_contact_remove_button"),
|
||||
mozL10n.get("confirm_delete_contact_cancel_button"),
|
||||
(err, result) => {
|
||||
navigator.mozLoop.confirm({
|
||||
message: mozL10n.get("confirm_delete_contact_alert"),
|
||||
okButton: mozL10n.get("confirm_delete_contact_remove_button"),
|
||||
cancelButton: mozL10n.get("confirm_delete_contact_cancel_button")
|
||||
}, (err, result) => {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
navigator.mozLoop.contacts.remove(contact._guid, err => {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
navigator.mozLoop.contacts.remove(contact._guid, err => {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
break;
|
||||
case "block":
|
||||
case "unblock":
|
||||
|
@ -521,6 +521,65 @@ loop.panel = (function(_, mozL10n) {
|
||||
}
|
||||
});
|
||||
|
||||
var EditInPlace = React.createClass({displayName: 'EditInPlace',
|
||||
mixins: [React.addons.LinkedStateMixin],
|
||||
|
||||
propTypes: {
|
||||
onChange: React.PropTypes.func.isRequired,
|
||||
text: React.PropTypes.string,
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {text: ""};
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {edit: false, text: this.props.text};
|
||||
},
|
||||
|
||||
handleTextClick: function(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
this.setState({edit: true}, function() {
|
||||
this.getDOMNode().querySelector("input").select();
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
handleInputClick: function(event) {
|
||||
event.stopPropagation();
|
||||
},
|
||||
|
||||
handleFormSubmit: function(event) {
|
||||
event.preventDefault();
|
||||
this.props.onChange(this.state.text);
|
||||
this.setState({edit: false});
|
||||
},
|
||||
|
||||
cancelEdit: function(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
this.setState({edit: false, text: this.props.text});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (!this.state.edit) {
|
||||
return (
|
||||
React.DOM.span({className: "edit-in-place", onClick: this.handleTextClick,
|
||||
title: mozL10n.get("rooms_name_this_room_tooltip2")},
|
||||
this.state.text
|
||||
)
|
||||
);
|
||||
}
|
||||
return (
|
||||
React.DOM.form({onSubmit: this.handleFormSubmit},
|
||||
React.DOM.input({type: "text", valueLink: this.linkState("text"),
|
||||
onClick: this.handleInputClick,
|
||||
onBlur: this.cancelEdit})
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Room list entry.
|
||||
*/
|
||||
@ -539,7 +598,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
(nextState.urlCopied !== this.state.urlCopied);
|
||||
},
|
||||
|
||||
handleClickRoomUrl: function(event) {
|
||||
handleClickEntry: function(event) {
|
||||
event.preventDefault();
|
||||
this.props.dispatcher.dispatch(new sharedActions.OpenRoom({
|
||||
roomToken: this.props.room.roomToken
|
||||
@ -547,6 +606,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
},
|
||||
|
||||
handleCopyButtonClick: function(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
this.props.dispatcher.dispatch(new sharedActions.CopyRoomUrl({
|
||||
roomUrl: this.props.room.roomUrl
|
||||
@ -555,10 +615,31 @@ loop.panel = (function(_, mozL10n) {
|
||||
},
|
||||
|
||||
handleDeleteButtonClick: function(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
// XXX We should prompt end user for confirmation; see bug 1092953.
|
||||
this.props.dispatcher.dispatch(new sharedActions.DeleteRoom({
|
||||
roomToken: this.props.room.roomToken
|
||||
navigator.mozLoop.confirm({
|
||||
message: mozL10n.get("rooms_list_deleteConfirmation_label"),
|
||||
okButton: null,
|
||||
cancelButton: null
|
||||
}, function(err, result) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.dispatcher.dispatch(new sharedActions.DeleteRoom({
|
||||
roomToken: this.props.room.roomToken
|
||||
}));
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
renameRoom: function(newRoomName) {
|
||||
this.props.dispatcher.dispatch(new sharedActions.RenameRoom({
|
||||
roomToken: this.props.room.roomToken,
|
||||
newRoomName: newRoomName
|
||||
}));
|
||||
},
|
||||
|
||||
@ -582,10 +663,11 @@ loop.panel = (function(_, mozL10n) {
|
||||
});
|
||||
|
||||
return (
|
||||
React.DOM.div({className: roomClasses, onMouseLeave: this.handleMouseLeave},
|
||||
React.DOM.div({className: roomClasses, onMouseLeave: this.handleMouseLeave,
|
||||
onClick: this.handleClickEntry},
|
||||
React.DOM.h2(null,
|
||||
React.DOM.span({className: "room-notification"}),
|
||||
room.roomName,
|
||||
EditInPlace({text: room.roomName, onChange: this.renameRoom}),
|
||||
React.DOM.button({className: copyButtonClasses,
|
||||
title: mozL10n.get("rooms_list_copy_url_tooltip"),
|
||||
onClick: this.handleCopyButtonClick}),
|
||||
@ -593,11 +675,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
title: mozL10n.get("rooms_list_delete_tooltip"),
|
||||
onClick: this.handleDeleteButtonClick})
|
||||
),
|
||||
React.DOM.p(null,
|
||||
React.DOM.a({href: "#", onClick: this.handleClickRoomUrl},
|
||||
room.roomUrl
|
||||
)
|
||||
)
|
||||
React.DOM.p(null, React.DOM.a({href: "#"}, room.roomUrl))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -521,6 +521,65 @@ loop.panel = (function(_, mozL10n) {
|
||||
}
|
||||
});
|
||||
|
||||
var EditInPlace = React.createClass({
|
||||
mixins: [React.addons.LinkedStateMixin],
|
||||
|
||||
propTypes: {
|
||||
onChange: React.PropTypes.func.isRequired,
|
||||
text: React.PropTypes.string,
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {text: ""};
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {edit: false, text: this.props.text};
|
||||
},
|
||||
|
||||
handleTextClick: function(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
this.setState({edit: true}, function() {
|
||||
this.getDOMNode().querySelector("input").select();
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
handleInputClick: function(event) {
|
||||
event.stopPropagation();
|
||||
},
|
||||
|
||||
handleFormSubmit: function(event) {
|
||||
event.preventDefault();
|
||||
this.props.onChange(this.state.text);
|
||||
this.setState({edit: false});
|
||||
},
|
||||
|
||||
cancelEdit: function(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
this.setState({edit: false, text: this.props.text});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (!this.state.edit) {
|
||||
return (
|
||||
<span className="edit-in-place" onClick={this.handleTextClick}
|
||||
title={mozL10n.get("rooms_name_this_room_tooltip2")}>
|
||||
{this.state.text}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<form onSubmit={this.handleFormSubmit}>
|
||||
<input type="text" valueLink={this.linkState("text")}
|
||||
onClick={this.handleInputClick}
|
||||
onBlur={this.cancelEdit} />
|
||||
</form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Room list entry.
|
||||
*/
|
||||
@ -539,7 +598,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
(nextState.urlCopied !== this.state.urlCopied);
|
||||
},
|
||||
|
||||
handleClickRoomUrl: function(event) {
|
||||
handleClickEntry: function(event) {
|
||||
event.preventDefault();
|
||||
this.props.dispatcher.dispatch(new sharedActions.OpenRoom({
|
||||
roomToken: this.props.room.roomToken
|
||||
@ -547,6 +606,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
},
|
||||
|
||||
handleCopyButtonClick: function(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
this.props.dispatcher.dispatch(new sharedActions.CopyRoomUrl({
|
||||
roomUrl: this.props.room.roomUrl
|
||||
@ -555,10 +615,31 @@ loop.panel = (function(_, mozL10n) {
|
||||
},
|
||||
|
||||
handleDeleteButtonClick: function(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
// XXX We should prompt end user for confirmation; see bug 1092953.
|
||||
this.props.dispatcher.dispatch(new sharedActions.DeleteRoom({
|
||||
roomToken: this.props.room.roomToken
|
||||
navigator.mozLoop.confirm({
|
||||
message: mozL10n.get("rooms_list_deleteConfirmation_label"),
|
||||
okButton: null,
|
||||
cancelButton: null
|
||||
}, function(err, result) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.dispatcher.dispatch(new sharedActions.DeleteRoom({
|
||||
roomToken: this.props.room.roomToken
|
||||
}));
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
renameRoom: function(newRoomName) {
|
||||
this.props.dispatcher.dispatch(new sharedActions.RenameRoom({
|
||||
roomToken: this.props.room.roomToken,
|
||||
newRoomName: newRoomName
|
||||
}));
|
||||
},
|
||||
|
||||
@ -582,10 +663,11 @@ loop.panel = (function(_, mozL10n) {
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={roomClasses} onMouseLeave={this.handleMouseLeave}>
|
||||
<div className={roomClasses} onMouseLeave={this.handleMouseLeave}
|
||||
onClick={this.handleClickEntry}>
|
||||
<h2>
|
||||
<span className="room-notification" />
|
||||
{room.roomName}
|
||||
<EditInPlace text={room.roomName} onChange={this.renameRoom} />
|
||||
<button className={copyButtonClasses}
|
||||
title={mozL10n.get("rooms_list_copy_url_tooltip")}
|
||||
onClick={this.handleCopyButtonClick} />
|
||||
@ -593,11 +675,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
title={mozL10n.get("rooms_list_delete_tooltip")}
|
||||
onClick={this.handleDeleteButtonClick} />
|
||||
</h2>
|
||||
<p>
|
||||
<a href="#" onClick={this.handleClickRoomUrl}>
|
||||
{room.roomUrl}
|
||||
</a>
|
||||
</p>
|
||||
<p><a href="#">{room.roomUrl}</a></p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -204,9 +204,11 @@ body {
|
||||
|
||||
.room-list > .room-entry {
|
||||
padding: .5rem 1rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.room-list > .room-entry > h2 {
|
||||
display: inline-block;
|
||||
font-size: .85rem;
|
||||
color: #777;
|
||||
}
|
||||
@ -298,16 +300,33 @@ body {
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
.room-list > .room-entry > h2 {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* keep the various room-entry row pieces aligned with each other */
|
||||
.room-list > .room-entry > h2 > button,
|
||||
.room-list > .room-entry > h2 > span {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Edit in place */
|
||||
|
||||
.room-list > .room-entry > h2 > .edit-in-place {
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.room-list > .room-entry > h2 > .edit-in-place:hover {
|
||||
background: #fefbc4;
|
||||
}
|
||||
|
||||
.room-list > .room-entry > h2 > form {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.room-list > .room-entry > h2 > form > input {
|
||||
border: none;
|
||||
background: #fefbc4;
|
||||
font-size: 13.6px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
|
||||
.button-group {
|
||||
|
@ -54,7 +54,8 @@ describe("loop.panel", function() {
|
||||
callback(null, []);
|
||||
},
|
||||
on: sandbox.stub()
|
||||
}
|
||||
},
|
||||
confirm: sandbox.stub()
|
||||
};
|
||||
|
||||
document.mozL10n.initialize(navigator.mozLoop);
|
||||
@ -714,6 +715,42 @@ describe("loop.panel", function() {
|
||||
return TestUtils.renderIntoDocument(loop.panel.RoomEntry(props));
|
||||
}
|
||||
|
||||
describe("Edit room name", function() {
|
||||
var roomEntry, domNode;
|
||||
|
||||
beforeEach(function() {
|
||||
roomEntry = mountRoomEntry({
|
||||
dispatcher: dispatcher,
|
||||
deleteRoom: sandbox.stub(),
|
||||
room: new loop.store.Room(roomData)
|
||||
});
|
||||
domNode = roomEntry.getDOMNode();
|
||||
|
||||
TestUtils.Simulate.click(domNode.querySelector(".edit-in-place"));
|
||||
});
|
||||
|
||||
it("should render an edit form on room name click", function() {
|
||||
expect(domNode.querySelector("form")).not.eql(null);
|
||||
expect(domNode.querySelector("input").value).eql(roomData.roomName);
|
||||
});
|
||||
|
||||
it("should dispatch a RenameRoom action when submitting the form",
|
||||
function() {
|
||||
var dispatch = sandbox.stub(dispatcher, "dispatch");
|
||||
|
||||
TestUtils.Simulate.change(domNode.querySelector("input"), {
|
||||
target: {value: "New name"}
|
||||
});
|
||||
TestUtils.Simulate.submit(domNode.querySelector("form"));
|
||||
|
||||
sinon.assert.calledOnce(dispatch);
|
||||
sinon.assert.calledWithExactly(dispatch, new sharedActions.RenameRoom({
|
||||
roomToken: roomData.roomToken,
|
||||
newRoomName: "New name"
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("Copy button", function() {
|
||||
var roomEntry, copyButton;
|
||||
|
||||
@ -779,15 +816,27 @@ describe("loop.panel", function() {
|
||||
expect(deleteButton).to.not.equal(null);
|
||||
});
|
||||
|
||||
it("should call the delete function when clicked", function() {
|
||||
it("should dispatch a delete action when confirmation is granted", function() {
|
||||
sandbox.stub(dispatcher, "dispatch");
|
||||
|
||||
navigator.mozLoop.confirm.callsArgWith(1, null, true);
|
||||
TestUtils.Simulate.click(deleteButton);
|
||||
|
||||
sinon.assert.calledOnce(navigator.mozLoop.confirm);
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
new sharedActions.DeleteRoom({roomToken: roomData.roomToken}));
|
||||
});
|
||||
|
||||
it("should not dispatch an action when the confirmation is cancelled", function() {
|
||||
sandbox.stub(dispatcher, "dispatch");
|
||||
|
||||
navigator.mozLoop.confirm.callsArgWith(1, null, false);
|
||||
TestUtils.Simulate.click(deleteButton);
|
||||
|
||||
sinon.assert.calledOnce(navigator.mozLoop.confirm);
|
||||
sinon.assert.notCalled(dispatcher.dispatch);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Room URL click", function() {
|
||||
|
@ -51,9 +51,12 @@ navigator.mozLoop = {
|
||||
ensureRegistered: function() {},
|
||||
getAudioBlob: function(){},
|
||||
getLoopPref: function(pref) {
|
||||
// Ensure UI for rooms is displayed in the showcase.
|
||||
if (pref === "rooms.enabled") {
|
||||
return true;
|
||||
switch(pref) {
|
||||
// Ensure UI for rooms is displayed in the showcase.
|
||||
case "rooms.enabled":
|
||||
// Ensure we skip FTE completely.
|
||||
case "gettingStarted.seen":
|
||||
return true;
|
||||
}
|
||||
},
|
||||
setLoopPref: function(){},
|
||||
|
@ -2469,7 +2469,7 @@ let DefaultBrowserCheck = {
|
||||
let E10SUINotification = {
|
||||
// Increase this number each time we want to roll out an
|
||||
// e10s testing period to Nightly users.
|
||||
CURRENT_NOTICE_COUNT: 2,
|
||||
CURRENT_NOTICE_COUNT: 3,
|
||||
CURRENT_PROMPT_PREF: "browser.displayedE10SPrompt.1",
|
||||
PREVIOUS_PROMPT_PREF: "browser.displayedE10SPrompt",
|
||||
|
||||
|
@ -123,8 +123,15 @@ StyleEditorUI.prototype = {
|
||||
|
||||
let hUtils = toolbox.highlighterUtils;
|
||||
if (hUtils.hasCustomHighlighter(SELECTOR_HIGHLIGHTER_TYPE)) {
|
||||
this._highlighter =
|
||||
yield hUtils.getHighlighterByType(SELECTOR_HIGHLIGHTER_TYPE);
|
||||
try {
|
||||
this._highlighter =
|
||||
yield hUtils.getHighlighterByType(SELECTOR_HIGHLIGHTER_TYPE);
|
||||
} catch (e) {
|
||||
// The selectorHighlighter can't always be instantiated, for example
|
||||
// it doesn't work with XUL windows (until bug 1094959 gets fixed).
|
||||
console.warn("The selectorHighlighter couldn't be instantiated, " +
|
||||
"elements matching hovered selectors will not be highlighted");
|
||||
}
|
||||
}
|
||||
}.bind(this)).then(() => {
|
||||
this.createUI();
|
||||
|
@ -73,3 +73,4 @@ skip-if = e10s # Bug 1055333 - style editor tests disabled with e10s
|
||||
[browser_styleeditor_sourcemap_watching.js]
|
||||
skip-if = e10s # Bug 1055333 - style editor tests disabled with e10s
|
||||
[browser_styleeditor_transition_rule.js]
|
||||
[browser_styleeditor_xul.js]
|
||||
|
20
browser/devtools/styleeditor/test/browser_styleeditor_xul.js
Normal file
20
browser/devtools/styleeditor/test/browser_styleeditor_xul.js
Normal file
@ -0,0 +1,20 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that the style-editor initializes correctly for XUL windows.
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
const TEST_URL = "about:config";
|
||||
|
||||
let test = asyncTest(function*() {
|
||||
let tab = yield addTab(TEST_URL);
|
||||
let target = TargetFactory.forTab(tab);
|
||||
|
||||
let toolbox = yield gDevTools.showToolbox(target, "styleeditor");
|
||||
let panel = toolbox.getCurrentPanel();
|
||||
yield panel.UI.once("editor-added");
|
||||
|
||||
ok(panel, "The style-editor panel did initialize correctly for the XUL window");
|
||||
});
|
@ -265,6 +265,7 @@ skip-if = buildapp == 'mulet'
|
||||
[browser_webconsole_bug_846918_hsts_invalid-headers.js]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[browser_webconsole_bug_915141_toggle_response_logging_with_keyboard.js]
|
||||
[browser_webconsole_filter_buttons_contextmenu.js]
|
||||
[browser_webconsole_bug_1006027_message_timestamps_incorrect.js]
|
||||
[browser_webconsole_bug_1010953_cspro.js]
|
||||
[browser_webconsole_certificate_messages.js]
|
||||
|
@ -0,0 +1,93 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that the filter button context menu logic works correctly.
|
||||
|
||||
const TEST_URI = "http://example.com/";
|
||||
|
||||
function test() {
|
||||
addTab(TEST_URI);
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
openConsole(null, testFilterButtons);
|
||||
}, true);
|
||||
}
|
||||
|
||||
function testFilterButtons(aHud) {
|
||||
let hudBox = aHud.ui.rootElement;
|
||||
|
||||
testRightClick("net", hudBox, aHud)
|
||||
.then(() => testRightClick("css", hudBox, aHud))
|
||||
.then(() => testRightClick("js", hudBox, aHud))
|
||||
.then(() => testRightClick("logging", hudBox, aHud))
|
||||
.then(() => testRightClick("security", hudBox, aHud))
|
||||
.then(finishTest);
|
||||
}
|
||||
|
||||
function testRightClick(aCategory, hudBox, aHud) {
|
||||
let deferred = promise.defer();
|
||||
let selector = ".webconsole-filter-button[category=\"" + aCategory + "\"]";
|
||||
let button = hudBox.querySelector(selector);
|
||||
let mainButton = getMainButton(button, aHud);
|
||||
let origCheckedState = button.getAttribute("aria-pressed");
|
||||
let contextMenu = aHud.iframeWindow.document.getElementById(aCategory + "-contextmenu");
|
||||
|
||||
function verifyContextMenuIsClosed() {
|
||||
info("verify the context menu is closed");
|
||||
is(button.getAttribute("open"), false, "The context menu for the \"" + aCategory +
|
||||
"\" button is closed");
|
||||
}
|
||||
|
||||
function verifyOriginalCheckedState() {
|
||||
info("verify the button has the original checked state");
|
||||
is(button.getAttribute("aria-pressed"), origCheckedState,
|
||||
"The button state should not have changed");
|
||||
};
|
||||
|
||||
function verifyNewCheckedState() {
|
||||
info("verify the button's checked state has changed");
|
||||
isnot(button.getAttribute("aria-pressed"), origCheckedState,
|
||||
"The button state should have changed");
|
||||
};
|
||||
|
||||
function leftClickToClose() {
|
||||
info("left click the button to close the contextMenu");
|
||||
EventUtils.sendMouseEvent({type: "click"}, button);
|
||||
executeSoon(() => {
|
||||
verifyContextMenuIsClosed();
|
||||
verifyOriginalCheckedState();
|
||||
leftClickToChangeCheckedState();
|
||||
});
|
||||
}
|
||||
|
||||
function leftClickToChangeCheckedState() {
|
||||
info("left click the mainbutton to change checked state");
|
||||
EventUtils.sendMouseEvent({type: "click"}, mainButton);
|
||||
executeSoon(() => {
|
||||
verifyContextMenuIsClosed();
|
||||
verifyNewCheckedState();
|
||||
deferred.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
verifyContextMenuIsClosed();
|
||||
info("right click the button to open the context menu");
|
||||
waitForContextMenu(contextMenu, mainButton, verifyOriginalCheckedState,
|
||||
leftClickToClose);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function getMainButton(aTargetButton, aHud) {
|
||||
let anonymousNodes = aHud.ui.document.getAnonymousNodes(aTargetButton);
|
||||
let subbutton;
|
||||
|
||||
for (let i = 0; i < anonymousNodes.length; i++) {
|
||||
let node = anonymousNodes[i];
|
||||
if (node.classList.contains("toolbarbutton-menubutton-button")) {
|
||||
subbutton = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return subbutton;
|
||||
}
|
@ -690,6 +690,9 @@ WebConsoleFrame.prototype = {
|
||||
let categories = this.document
|
||||
.querySelectorAll(".webconsole-filter-button[category]");
|
||||
Array.forEach(categories, function(aButton) {
|
||||
aButton.addEventListener("contextmenu", (aEvent) => {
|
||||
aButton.open = true;
|
||||
}, false);
|
||||
aButton.addEventListener("click", this._toggleFilter, false);
|
||||
|
||||
let someChecked = false;
|
||||
@ -811,7 +814,9 @@ WebConsoleFrame.prototype = {
|
||||
{
|
||||
let target = aEvent.target;
|
||||
let tagName = target.tagName;
|
||||
if (tagName != aEvent.currentTarget.tagName) {
|
||||
// Prevent toggle if generated from a contextmenu event (right click)
|
||||
let isRightClick = (aEvent.button === 2); // right click is button 2;
|
||||
if (tagName != aEvent.currentTarget.tagName || isRightClick) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -5395,4 +5400,3 @@ ConsoleContextMenu.prototype = {
|
||||
this.lastClickedMessage = null;
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -93,7 +93,7 @@ function goUpdateConsoleCommands() {
|
||||
accesskeyMacOSX="&btnPageNet.accesskeyMacOSX;"
|
||||
accesskey="&btnPageNet.accesskey;"
|
||||
tabindex="3">
|
||||
<menupopup>
|
||||
<menupopup id="net-contextmenu">
|
||||
<menuitem label="&btnConsoleErrors;" type="checkbox" autocheck="false"
|
||||
prefKey="network"/>
|
||||
<menuitem label="&btnConsoleWarnings;" type="checkbox" autocheck="false"
|
||||
@ -110,7 +110,7 @@ function goUpdateConsoleCommands() {
|
||||
tooltiptext="&btnPageCSS.tooltip2;"
|
||||
accesskey="&btnPageCSS.accesskey;"
|
||||
tabindex="4">
|
||||
<menupopup>
|
||||
<menupopup id="css-contextmenu">
|
||||
<menuitem label="&btnConsoleErrors;" type="checkbox" autocheck="false"
|
||||
prefKey="csserror"/>
|
||||
<menuitem label="&btnConsoleWarnings;" type="checkbox"
|
||||
@ -124,7 +124,7 @@ function goUpdateConsoleCommands() {
|
||||
tooltiptext="&btnPageJS.tooltip;"
|
||||
accesskey="&btnPageJS.accesskey;"
|
||||
tabindex="5">
|
||||
<menupopup>
|
||||
<menupopup id="js-contextmenu">
|
||||
<menuitem label="&btnConsoleErrors;" type="checkbox"
|
||||
autocheck="false" prefKey="exception"/>
|
||||
<menuitem label="&btnConsoleWarnings;" type="checkbox"
|
||||
@ -138,7 +138,7 @@ function goUpdateConsoleCommands() {
|
||||
tooltiptext="&btnPageSecurity.tooltip;"
|
||||
accesskey="&btnPageSecurity.accesskey;"
|
||||
tabindex="6">
|
||||
<menupopup>
|
||||
<menupopup id="security-contextmenu">
|
||||
<menuitem label="&btnConsoleErrors;" type="checkbox"
|
||||
autocheck="false" prefKey="secerror"/>
|
||||
<menuitem label="&btnConsoleWarnings;" type="checkbox"
|
||||
@ -150,7 +150,7 @@ function goUpdateConsoleCommands() {
|
||||
tooltiptext="&btnPageLogging.tooltip;"
|
||||
accesskey="&btnPageLogging.accesskey3;"
|
||||
tabindex="7">
|
||||
<menupopup>
|
||||
<menupopup id="logging-contextmenu">
|
||||
<menuitem label="&btnConsoleErrors;" type="checkbox"
|
||||
autocheck="false" prefKey="error"/>
|
||||
<menuitem label="&btnConsoleWarnings;" type="checkbox"
|
||||
|
@ -11,8 +11,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/new_tablet_tab_panel_grid_padding">
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<resources>
|
||||
|
||||
<dimen name="new_tablet_tab_panel_grid_padding">64dp</dimen>
|
||||
|
||||
</resources>
|
@ -12,5 +12,6 @@
|
||||
<dimen name="tabs_panel_indicator_width">60dp</dimen>
|
||||
<dimen name="tabs_panel_list_padding">8dip</dimen>
|
||||
<dimen name="panel_grid_view_column_width">250dp</dimen>
|
||||
<dimen name="new_tablet_tab_panel_grid_padding">48dp</dimen>
|
||||
|
||||
</resources>
|
||||
|
@ -202,7 +202,7 @@
|
||||
<item name="android:numColumns">auto_fit</item>
|
||||
<item name="android:columnWidth">@dimen/tabs_grid_view_column_width</item>
|
||||
<item name="android:horizontalSpacing">2dp</item>
|
||||
<item name="android:verticalSpacing">2dp</item>
|
||||
<item name="android:verticalSpacing">21dp</item>
|
||||
<item name="android:drawSelectorOnTop">true</item>
|
||||
<item name="android:clipToPadding">false</item>
|
||||
</style>
|
||||
|
@ -12,6 +12,7 @@ const events = require("sdk/event/core");
|
||||
const Heritage = require("sdk/core/heritage");
|
||||
const {CssLogic} = require("devtools/styleinspector/css-logic");
|
||||
const EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
const {setIgnoreLayoutChanges} = require("devtools/server/actors/layout");
|
||||
|
||||
Cu.import("resource://gre/modules/devtools/LayoutHelpers.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
@ -984,6 +985,8 @@ BoxModelHighlighter.prototype = Heritage.extend(AutoRefreshHighlighter.prototype
|
||||
* Should be called whenever node size or attributes change
|
||||
*/
|
||||
_update: function() {
|
||||
setIgnoreLayoutChanges(true);
|
||||
|
||||
if (this._updateBoxModel()) {
|
||||
if (!this.options.hideInfoBar) {
|
||||
this._showInfobar();
|
||||
@ -995,15 +998,21 @@ BoxModelHighlighter.prototype = Heritage.extend(AutoRefreshHighlighter.prototype
|
||||
// Nothing to highlight (0px rectangle like a <script> tag for instance)
|
||||
this._hide();
|
||||
}
|
||||
|
||||
setIgnoreLayoutChanges(false, this.currentNode.ownerDocument.documentElement);
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide the highlighter, the outline and the infobar.
|
||||
*/
|
||||
_hide: function() {
|
||||
setIgnoreLayoutChanges(true);
|
||||
|
||||
this._untrackMutations();
|
||||
this._hideBoxModel();
|
||||
this._hideInfobar();
|
||||
|
||||
setIgnoreLayoutChanges(false, this.currentNode.ownerDocument.documentElement);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1249,7 +1258,7 @@ BoxModelHighlighter.prototype = Heritage.extend(AutoRefreshHighlighter.prototype
|
||||
pseudos += ":" + pseudo;
|
||||
}
|
||||
|
||||
let rect = node.getBoundingClientRect();
|
||||
let rect = this.currentQuads.border.bounds;
|
||||
let dim = Math.ceil(rect.width) + " x " + Math.ceil(rect.height);
|
||||
|
||||
let elementId = this.ID_CLASS_PREFIX + "nodeinfobar-";
|
||||
@ -1491,6 +1500,8 @@ CssTransformHighlighter.prototype = Heritage.extend(AutoRefreshHighlighter.proto
|
||||
* Should be called whenever node size or attributes change
|
||||
*/
|
||||
_update: function() {
|
||||
setIgnoreLayoutChanges(true);
|
||||
|
||||
// Getting the points for the transformed shape
|
||||
let quad = this.currentQuads.border;
|
||||
if (!quad || quad.bounds.width <= 0 || quad.bounds.height <= 0) {
|
||||
@ -1511,13 +1522,17 @@ CssTransformHighlighter.prototype = Heritage.extend(AutoRefreshHighlighter.proto
|
||||
this.markup.scaleRootElement(this.currentNode, this.ID_CLASS_PREFIX + "root");
|
||||
|
||||
this._showShapes();
|
||||
|
||||
setIgnoreLayoutChanges(false, this.currentNode.ownerDocument.documentElement);
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide the highlighter, the outline and the infobar.
|
||||
*/
|
||||
_hide: function() {
|
||||
setIgnoreLayoutChanges(true);
|
||||
this._hideShapes();
|
||||
setIgnoreLayoutChanges(false, this.currentNode.ownerDocument.documentElement);
|
||||
},
|
||||
|
||||
_hideShapes: function() {
|
||||
|
@ -192,6 +192,28 @@ Observable.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The LayouChangesObserver will observe reflows as soon as it is started.
|
||||
* Some devtools actors may cause reflows and it may be wanted to "hide" these
|
||||
* reflows from the LayouChangesObserver consumers.
|
||||
* If this is the case, such actors should require this module and use this
|
||||
* global function to turn the ignore mode on and off temporarily.
|
||||
*
|
||||
* Note that if a node is provided, it will be used to force a sync reflow to
|
||||
* make sure all reflows which occurred before switching the mode on or off are
|
||||
* either observed or ignored depending on the current mode.
|
||||
*
|
||||
* @param {Boolean} ignore
|
||||
* @param {DOMNode} syncReflowNode The node to use to force a sync reflow
|
||||
*/
|
||||
let gIgnoreLayoutChanges = false;
|
||||
exports.setIgnoreLayoutChanges = function(ignore, syncReflowNode) {
|
||||
if (syncReflowNode) {
|
||||
let forceSyncReflow = syncReflowNode.offsetWidth;
|
||||
}
|
||||
gIgnoreLayoutChanges = ignore;
|
||||
}
|
||||
|
||||
/**
|
||||
* The LayoutChangesObserver class is instantiated only once per given tab
|
||||
* and is used to track reflows and dom and style changes in that tab.
|
||||
@ -302,6 +324,10 @@ LayoutChangesObserver.prototype = Heritage.extend(Observable.prototype, {
|
||||
* @param {Boolean} isInterruptible
|
||||
*/
|
||||
_onReflow: function(start, end, isInterruptible) {
|
||||
if (gIgnoreLayoutChanges) {
|
||||
return;
|
||||
}
|
||||
|
||||
// XXX: when/if bug 997092 gets fixed, we will be able to know which
|
||||
// elements have been reflowed, which would be a nice thing to add here.
|
||||
this.reflows.push({
|
||||
|
Loading…
x
Reference in New Issue
Block a user