diff --git a/browser/devtools/markupview/markup-view.js b/browser/devtools/markupview/markup-view.js index 828510db87c..bd89d407a1d 100644 --- a/browser/devtools/markupview/markup-view.js +++ b/browser/devtools/markupview/markup-view.js @@ -166,6 +166,7 @@ MarkupView.prototype = { _onMouseLeave: function() { this._hideBoxModel(); + this._hoveredNode = null; }, _showBoxModel: function(nodeFront, options={}) { @@ -257,11 +258,14 @@ MarkupView.prototype = { * - if it's "test" (this is a special case for mochitest. In tests, we often * need to select elements but don't necessarily want the highlighter to come * and go after a delay as this might break test scenarios) + * We also do not want to start a brief highlight timeout if the node is already + * being hovered over, since in that case it will already be highlighted. */ _shouldNewSelectionBeHighlighted: function() { let reason = this._inspector.selection.reason; let unwantedReasons = ["inspector-open", "navigateaway", "test"]; - return reason && unwantedReasons.indexOf(reason) === -1; + let isHighlitNode = this._hoveredNode === this._inspector.selection.nodeFront; + return !isHighlitNode && reason && unwantedReasons.indexOf(reason) === -1; }, /** diff --git a/browser/devtools/markupview/test/browser.ini b/browser/devtools/markupview/test/browser.ini index f7e35ffed83..a71a2f06ebd 100644 --- a/browser/devtools/markupview/test/browser.ini +++ b/browser/devtools/markupview/test/browser.ini @@ -24,3 +24,5 @@ skip-if = os == "linux" [browser_inspector_markup_765105_tooltip.js] [browser_inspector_markup_950732.js] [browser_inspector_markup_964014_copy_image_data.js] +[browser_inspector_markup_968316_highlit_node_on_hover_then_select.js] +[browser_inspector_markup_968316_highlight_node_after_mouseleave_mousemove.js] diff --git a/browser/devtools/markupview/test/browser_inspector_markup_964014_copy_image_data.js b/browser/devtools/markupview/test/browser_inspector_markup_964014_copy_image_data.js index 9a1ee01ca08..e7d730ff7e3 100644 --- a/browser/devtools/markupview/test/browser_inspector_markup_964014_copy_image_data.js +++ b/browser/devtools/markupview/test/browser_inspector_markup_964014_copy_image_data.js @@ -42,7 +42,7 @@ function createDocument() { openInspector().then(startTests); } -function startTests(aInspector, aToolbox) { +function startTests({inspector: aInspector, toolbox: aToolbox}) { inspector = aInspector; markup = inspector.markup; diff --git a/browser/devtools/markupview/test/browser_inspector_markup_968316_highlight_node_after_mouseleave_mousemove.js b/browser/devtools/markupview/test/browser_inspector_markup_968316_highlight_node_after_mouseleave_mousemove.js new file mode 100644 index 00000000000..19879c0b57e --- /dev/null +++ b/browser/devtools/markupview/test/browser_inspector_markup_968316_highlight_node_after_mouseleave_mousemove.js @@ -0,0 +1,47 @@ +/* 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 when after an element is selected and highlighted on hover, if the +// mouse leaves the markup-view and comes back again on the same element, that +// the highlighter is shown again on the node + +function test() { + waitForExplicitFinish(); + + gBrowser.selectedTab = gBrowser.addTab(); + gBrowser.selectedBrowser.addEventListener("load", function onload(evt) { + gBrowser.selectedBrowser.removeEventListener("load", onload, true); + waitForFocus(startTests, content); + }, true); + + content.location = "data:text/html,

Select me!

"; +} + +function startTests(aInspector, aToolbox) { + let p = content.document.querySelector("p"); + Task.spawn(function() { + info("opening the inspector tool"); + let {inspector, toolbox} = yield openInspector(); + + info("hover over the

line in the markup-view so that it's the currently hovered node"); + yield hoverContainer(p, inspector); + + info("select the

markup-container line by clicking"); + yield clickContainer(p, inspector); + ok(isHighlighterVisible(), "the highlighter is shown"); + + info("mouse-leave the markup-view"); + yield mouseLeaveMarkupView(inspector); + ok(!isHighlighterVisible(), "the highlighter is hidden after mouseleave"); + + info("hover over the

line again, which is still selected"); + yield hoverContainer(p, inspector); + ok(isHighlighterVisible(), "the highlighter is visible again"); + }).then(null, ok.bind(null, false)).then(endTests); +} + +function endTests() { + gBrowser.removeCurrentTab(); + finish(); +} diff --git a/browser/devtools/markupview/test/browser_inspector_markup_968316_highlit_node_on_hover_then_select.js b/browser/devtools/markupview/test/browser_inspector_markup_968316_highlit_node_on_hover_then_select.js new file mode 100644 index 00000000000..0256cc57b0f --- /dev/null +++ b/browser/devtools/markupview/test/browser_inspector_markup_968316_highlit_node_on_hover_then_select.js @@ -0,0 +1,54 @@ +/* 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 when first hovering over a node and immediately after selecting it +// by clicking on it leaves the highlighter visible for as long as the mouse is +// over the node + +function test() { + waitForExplicitFinish(); + + gBrowser.selectedTab = gBrowser.addTab(); + gBrowser.selectedBrowser.addEventListener("load", function onload(evt) { + gBrowser.selectedBrowser.removeEventListener("load", onload, true); + waitForFocus(startTests, content); + }, true); + + content.location = "data:text/html,

It's going to be legen....

"; +} + +function startTests(aInspector, aToolbox) { + let p = content.document.querySelector("p"); + Task.spawn(function() { + info("opening the inspector tool"); + let {inspector, toolbox} = yield openInspector(); + + info("hovering over the

line in the markup-view"); + yield hoverContainer(p, inspector); + ok(isHighlighterVisible(), "the highlighter is still visible"); + + info("selecting the

line by clicking in the markup-view"); + yield clickContainer(p, inspector); + + p.textContent = "wait for it ...."; + info("wait and see if the highlighter stays visible even after the node was selected"); + yield waitForTheBrieflyShowBoxModelTimeout(); + + p.textContent = "dary!!!!"; + ok(isHighlighterVisible(), "the highlighter is still visible"); + }).then(null, ok.bind(null, false)).then(endTests); +} + +function endTests() { + gBrowser.removeCurrentTab(); + finish(); +} + +function waitForTheBrieflyShowBoxModelTimeout() { + let deferred = promise.defer(); + // Note that the current timeout is 1 sec and is neither configurable nor + // exported anywhere we can access, so hard-coding the timeout + content.setTimeout(deferred.resolve, 1500); + return deferred.promise; +} diff --git a/browser/devtools/markupview/test/head.js b/browser/devtools/markupview/test/head.js index 74aaf1365f7..7e37250834c 100644 --- a/browser/devtools/markupview/test/head.js +++ b/browser/devtools/markupview/test/head.js @@ -40,26 +40,88 @@ function openInspector() { gDevTools.showToolbox(target, "inspector").then(function(toolbox) { let inspector = toolbox.getCurrentPanel(); inspector.once("inspector-updated", () => { - deferred.resolve(inspector, toolbox); + deferred.resolve({toolbox: toolbox, inspector: inspector}); }); }).then(null, console.error); return deferred.promise; } +function getNode(nodeOrSelector) { + let node = nodeOrSelector; + + if (typeof nodeOrSelector === "string") { + node = content.document.querySelector(nodeOrSelector); + ok(node, "A node was found for selector " + nodeOrSelector); + } + + return node; +} + /** - * Set the inspector's current selection to the first match of the given css - * selector + * Set the inspector's current selection to a node or to the first match of the + * given css selector * @return a promise that resolves when the inspector is updated with the new * node */ -function selectNode(selector, inspector) { - let deferred = promise.defer(); - let node = content.document.querySelector(selector); - ok(node, "A node was found for selector " + selector + ". Selecting it now"); +function selectNode(nodeOrSelector, inspector) { + let node = getNode(nodeOrSelector); + let updated = inspector.once("inspector-updated"); inspector.selection.setNode(node, "test"); - inspector.once("inspector-updated", () => { - deferred.resolve(node); - }); + return updated; +} + +/** + * Simulate a mouse-over on the markup-container (a line in the markup-view) + * that corresponds to the node or selector passed. + * @return a promise that resolves when the container is hovered and the higlighter + * is shown on the corresponding node + */ +function hoverContainer(nodeOrSelector, inspector) { + let highlit = inspector.toolbox.once("node-highlight"); + let container = getContainerForRawNode(inspector.markup, getNode(nodeOrSelector)); + EventUtils.synthesizeMouse(container.tagLine, 2, 2, {type: "mousemove"}, + inspector.markup.doc.defaultView); + return highlit; +} + +/** + * Simulate a click on the markup-container (a line in the markup-view) + * that corresponds to the node or selector passed. + * @return a promise that resolves when the node has been selected. + */ +function clickContainer(nodeOrSelector, inspector) { + let updated = inspector.once("inspector-updated"); + let container = getContainerForRawNode(inspector.markup, getNode(nodeOrSelector)); + EventUtils.synthesizeMouseAtCenter(container.tagLine, {type: "mousedown"}, + inspector.markup.doc.defaultView); + EventUtils.synthesizeMouseAtCenter(container.tagLine, {type: "mouseup"}, + inspector.markup.doc.defaultView); + return updated; +} + +/** + * Checks if the highlighter is visible currently + */ +function isHighlighterVisible() { + let outline = gBrowser.selectedBrowser.parentNode.querySelector(".highlighter-container .highlighter-outline"); + return outline && !outline.hasAttribute("hidden"); +} + +/** + * Simulate the mouse leaving the markup-view area + * @return a promise when done + */ +function mouseLeaveMarkupView(inspector) { + let deferred = promise.defer(); + + // Find another element to mouseover over in order to leave the markup-view + let btn = inspector.toolbox.doc.querySelector(".toolbox-dock-button"); + + EventUtils.synthesizeMouse(btn, 2, 2, {type: "mousemove"}, + inspector.toolbox.doc.defaultView); + executeSoon(deferred.resolve); + return deferred.promise; } +