Merge f-t to m-c, a=merge

This commit is contained in:
Phil Ringnalda 2014-11-28 14:52:29 -08:00
commit a9f8d89c2f
26 changed files with 507 additions and 88 deletions

View File

@ -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.

View File

@ -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);
});

View File

@ -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]

View File

@ -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);
}

View File

@ -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);

View File

@ -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":

View File

@ -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":

View File

@ -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))
)
);
}

View File

@ -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>
);
}

View File

@ -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 {

View File

@ -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() {

View File

@ -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(){},

View File

@ -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",

View File

@ -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();

View File

@ -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]

View 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");
});

View File

@ -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]

View File

@ -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;
}

View File

@ -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;
},
};

View File

@ -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"

View File

@ -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"

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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() {

View File

@ -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({