Bug 1269226 - Explicitly handle node deletion in inspector breadcrumbs. r=pbro

This commit is contained in:
Steve Melia 2016-05-25 00:06:28 +01:00
parent 970e9b8288
commit 32fa6f3a81
4 changed files with 111 additions and 24 deletions

View File

@ -584,6 +584,22 @@ HTMLBreadcrumbs.prototype = {
return;
}
// If this was an interesting deletion; then trim the breadcrumb trail
if (reason === "markupmutation") {
for (let {type, removed} of mutations) {
if (type !== "childList") {
continue;
}
for (let node of removed) {
let removedIndex = this.indexOf(node);
if (removedIndex > -1) {
this.cutAfter(removedIndex - 1);
}
}
}
}
if (!this.selection.isElementNode()) {
// no selection
this.setCursor(-1);

View File

@ -857,12 +857,26 @@ MarkupView.prototype = {
this.undo.do(() => {
this.walker.removeNode(node).then(siblings => {
nextSibling = siblings.nextSibling;
let focusNode = moveBackward ? siblings.previousSibling : nextSibling;
let prevSibling = siblings.previousSibling;
let focusNode = moveBackward ? prevSibling : nextSibling;
// If we can't move as the user wants, we move to the other direction.
// If there is no sibling elements anymore, move to the parent node.
if (!focusNode) {
focusNode = nextSibling || siblings.previousSibling || parent;
focusNode = nextSibling || prevSibling || parent;
}
let isNextSiblingText = nextSibling ?
nextSibling.nodeType === Ci.nsIDOMNode.TEXT_NODE : false;
let isPrevSiblingText = prevSibling ?
prevSibling.nodeType === Ci.nsIDOMNode.TEXT_NODE : false;
// If the parent had two children and the next or previous sibling
// is a text node, then it now has only a single text node, is about
// to be in-lined; and focus should move to the parent.
if (parent.numChildren === 2
&& (isNextSiblingText || isPrevSiblingText)) {
focusNode = parent;
}
if (container.selected) {

View File

@ -18,31 +18,15 @@ add_task(function* () {
yield testManuallyDeleteSelectedNode();
yield testAutomaticallyDeleteSelectedNode();
yield testDeleteSelectedNodeContainerFrame();
yield testDeleteWithNonElementNode();
function* testManuallyDeleteSelectedNode() {
info("Selecting a node, deleting it via context menu and checking that " +
"its parent node is selected and breadcrumbs are updated.");
"its parent node is selected and breadcrumbs are updated.");
yield selectNode("#deleteManually", inspector);
yield deleteNodeWithContextMenu("#deleteManually");
info("Getting the node container in the markup view.");
let container = yield getContainerForSelector("#deleteManually", inspector);
info("Simulating right-click on the markup view container.");
EventUtils.synthesizeMouse(container.tagLine, 2, 2,
{type: "contextmenu", button: 2}, inspector.panelWin);
info("Waiting for the context menu to open.");
yield once(inspector.panelDoc.getElementById("inspectorPopupSet"),
"popupshown");
info("Clicking 'Delete Node' in the context menu.");
inspector.panelDoc.getElementById("node-menu-delete").click();
info("Waiting for inspector to update.");
yield inspector.once("inspector-updated");
info("Inspector updated, performing checks.");
info("Performing checks.");
yield assertNodeSelectedAndPanelsUpdated("#selectedAfterDelete",
"li#selectedAfterDelete");
}
@ -85,12 +69,80 @@ add_task(function* () {
yield assertNodeSelectedAndPanelsUpdated("body", "body");
}
function* testDeleteWithNonElementNode() {
info("Selecting a node, deleting it via context menu and checking that " +
"its parent node is selected and breadcrumbs are updated " +
"when the node is followed by a non-element node");
yield deleteNodeWithContextMenu("#deleteWithNonElement");
let expectedCrumbs = ["html", "body", "div#deleteToMakeSingleTextNode"];
yield assertNodeSelectedAndCrumbsUpdated(expectedCrumbs,
Node.TEXT_NODE);
let div = yield getNodeFront("#deleteToMakeSingleTextNode", inspector);
let {nodes} = yield inspector.walker.children(div);
let secondTextNode = nodes[1];
yield deleteNodeWithKey(secondTextNode);
expectedCrumbs = ["html", "body", "div#deleteToMakeSingleTextNode"];
yield assertNodeSelectedAndCrumbsUpdated(expectedCrumbs,
Node.ELEMENT_NODE);
}
function* deleteNodeWithKey(selector) {
yield selectNode(selector, inspector);
info("Simulating delete keypress on the markup view container.");
EventUtils.synthesizeKey("VK_DELETE", {}, inspector.panelWin);
info("Waiting for inspector to update.");
yield inspector.once("inspector-updated");
}
function* deleteNodeWithContextMenu(selector) {
yield selectNode(selector, inspector);
info("Getting the node container in the markup view.");
let container = yield getContainerForSelector(selector, inspector);
info("Simulating right-click on the markup view container.");
EventUtils.synthesizeMouse(container.tagLine, 2, 2,
{type: "contextmenu", button: 2}, inspector.panelWin);
info("Waiting for the context menu to open.");
let popupSet = inspector.panelDoc.getElementById("inspectorPopupSet");
yield once(popupSet, "popupshown");
info("Clicking 'Delete Node' in the context menu.");
inspector.panelDoc.getElementById("node-menu-delete").click();
info("Waiting for inspector to update.");
yield inspector.once("inspector-updated");
}
function* assertNodeSelectedAndCrumbsUpdated(expectedCrumbs,
expectedNodeType) {
info("Performing checks");
let actualNodeType = inspector.selection.nodeFront.nodeType;
is(actualNodeType, expectedNodeType, "The node has the right type");
let breadcrumbs = inspector.panelDoc
.getElementById("inspector-breadcrumbs")
.childNodes;
is(breadcrumbs.length, expectedCrumbs.length,
"Have the correct number of breadcrumbs");
for (let i = 0; i < breadcrumbs.length; i++) {
is(breadcrumbs[i].textContent, expectedCrumbs[i],
"Text content for button " + i + " is correct");
}
}
function* assertNodeSelectedAndPanelsUpdated(selector, crumbLabel) {
let nodeFront = yield getNodeFront(selector, inspector);
is(inspector.selection.nodeFront, nodeFront, "The right node is selected");
let breadcrumbs = inspector.panelDoc.getElementById(
"inspector-breadcrumbs");
let breadcrumbs = inspector.panelDoc
.getElementById("inspector-breadcrumbs");
is(breadcrumbs.querySelector("button[checked=true]").textContent,
crumbLabel,
"The right breadcrumb is selected");

View File

@ -11,5 +11,10 @@
<li id="deleteAutomatically">Delete me via javascript</li>
</ul>
<iframe id="deleteIframe" src="data:text/html,%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D%22en%22%3E%3Cbody%3E%3Cp%20id%3D%22deleteInIframe%22%3EDelete my container iframe%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E"></iframe>
<div id="deleteToMakeSingleTextNode">
1
<b id="deleteWithNonElement">Delete me and select the non-element node</b>
2
</div>
</body>
</html>