mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1059360 - Highlight nodes that match selectors in the computed-view on mouse-over. r=miker
This commit is contained in:
parent
62e533ef60
commit
eb93385b5d
@ -324,38 +324,83 @@ CssHtmlTree.prototype = {
|
||||
* returns null of the node isn't anything we care about
|
||||
*/
|
||||
getNodeInfo: function(node) {
|
||||
let type, value;
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let classes = node.classList;
|
||||
|
||||
if (classes.contains("property-name") ||
|
||||
classes.contains("property-value") ||
|
||||
(classes.contains("theme-link") && !classes.contains("link"))) {
|
||||
// Go up to the common parent to find the property and value
|
||||
let parent = node.parentNode;
|
||||
while (!parent.classList.contains("property-view")) {
|
||||
parent = parent.parentNode;
|
||||
// Check if the node isn't a selector first since this doesn't require
|
||||
// walking the DOM
|
||||
if (classes.contains("matched") ||
|
||||
classes.contains("bestmatch") ||
|
||||
classes.contains("parentmatch")) {
|
||||
let selectorText = "";
|
||||
for (let child of node.childNodes) {
|
||||
if (child.nodeType === node.TEXT_NODE) {
|
||||
selectorText += child.textContent;
|
||||
}
|
||||
}
|
||||
return {
|
||||
type: overlays.VIEW_NODE_SELECTOR_TYPE,
|
||||
value: selectorText.trim()
|
||||
}
|
||||
}
|
||||
|
||||
// Walk up the nodes to find out where node is
|
||||
let propertyView;
|
||||
let propertyContent;
|
||||
let parent = node;
|
||||
while (parent.parentNode) {
|
||||
if (parent.classList.contains("property-view")) {
|
||||
propertyView = parent;
|
||||
break;
|
||||
}
|
||||
if (parent.classList.contains("property-content")) {
|
||||
propertyContent = parent;
|
||||
break;
|
||||
}
|
||||
parent = parent.parentNode;
|
||||
}
|
||||
if (!propertyView && !propertyContent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let value, type;
|
||||
|
||||
// Get the property and value for a node that's a property name or value
|
||||
let isHref = classes.contains("theme-link") && !classes.contains("link");
|
||||
if (propertyView && (classes.contains("property-name") ||
|
||||
classes.contains("property-value") ||
|
||||
isHref)) {
|
||||
value = {
|
||||
property: parent.querySelector(".property-name").textContent,
|
||||
value: parent.querySelector(".property-value").textContent
|
||||
};
|
||||
}
|
||||
if (propertyContent && (classes.contains("other-property-value") ||
|
||||
isHref)) {
|
||||
let view = propertyContent.previousSibling;
|
||||
value = {
|
||||
property: view.querySelector(".property-name").textContent,
|
||||
value: node.textContent
|
||||
};
|
||||
}
|
||||
|
||||
// Get the type
|
||||
if (classes.contains("property-name")) {
|
||||
type = overlays.VIEW_NODE_PROPERTY_TYPE;
|
||||
} else if (classes.contains("property-value")) {
|
||||
} else if (classes.contains("property-value") ||
|
||||
classes.contains("other-property-value")) {
|
||||
type = overlays.VIEW_NODE_VALUE_TYPE;
|
||||
} else if (classes.contains("theme-link")) {
|
||||
} else if (isHref) {
|
||||
type = overlays.VIEW_NODE_IMAGE_URL_TYPE;
|
||||
value.url = node.href;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
type: type,
|
||||
value: value
|
||||
};
|
||||
return {type, value};
|
||||
},
|
||||
|
||||
_createPropertyViews: function()
|
||||
|
@ -1248,6 +1248,10 @@ CssRuleView.prototype = {
|
||||
* returns null of the node isn't anything we care about
|
||||
*/
|
||||
getNodeInfo: function(node) {
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let type, value;
|
||||
let classes = node.classList;
|
||||
let prop = getParentTextProperty(node);
|
||||
|
@ -25,6 +25,7 @@ support-files =
|
||||
head.js
|
||||
|
||||
[browser_computedview_browser-styles.js]
|
||||
[browser_computedview_getNodeInfo.js]
|
||||
[browser_computedview_keybindings_01.js]
|
||||
[browser_computedview_keybindings_02.js]
|
||||
[browser_computedview_matched-selectors-toggle.js]
|
||||
|
@ -0,0 +1,177 @@
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test various output of the computed-view's getNodeInfo method.
|
||||
// This method is used by the style-inspector-overlay on mouseover to decide
|
||||
// which tooltip or highlighter to show when hovering over a value/name/selector
|
||||
// if any.
|
||||
// For instance, browser_ruleview_selector-highlighter_01.js and
|
||||
// browser_ruleview_selector-highlighter_02.js test that the selector
|
||||
// highlighter appear when hovering over a selector in the rule-view.
|
||||
// Since the code to make this work for the computed-view is 90% the same, there
|
||||
// is no need for testing it again here.
|
||||
// This test however serves as a unit test for getNodeInfo.
|
||||
|
||||
const {
|
||||
VIEW_NODE_SELECTOR_TYPE,
|
||||
VIEW_NODE_PROPERTY_TYPE,
|
||||
VIEW_NODE_VALUE_TYPE,
|
||||
VIEW_NODE_IMAGE_URL_TYPE
|
||||
} = devtools.require("devtools/styleinspector/style-inspector-overlays");
|
||||
|
||||
const PAGE_CONTENT = [
|
||||
'<style type="text/css">',
|
||||
' body {',
|
||||
' background: red;',
|
||||
' color: white;',
|
||||
' }',
|
||||
' div {',
|
||||
' background: green;',
|
||||
' }',
|
||||
' div div {',
|
||||
' background-color: yellow;',
|
||||
' background-image: url(chrome://global/skin/icons/warning-64.png);',
|
||||
' color: red;',
|
||||
' }',
|
||||
'</style>',
|
||||
'<div><div id="testElement">Test element</div></div>'
|
||||
].join("\n");
|
||||
|
||||
// Each item in this array must have the following properties:
|
||||
// - desc {String} will be logged for information
|
||||
// - getHoveredNode {Generator Function} received the computed-view instance as
|
||||
// argument and must return the node to be tested
|
||||
// - assertNodeInfo {Function} should check the validity of the nodeInfo
|
||||
// argument it receives
|
||||
const TEST_DATA = [
|
||||
{
|
||||
desc: "Testing a null node",
|
||||
getHoveredNode: function*() {
|
||||
return null;
|
||||
},
|
||||
assertNodeInfo: function(nodeInfo) {
|
||||
is(nodeInfo, null);
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Testing a useless node",
|
||||
getHoveredNode: function*(view) {
|
||||
return view.element;
|
||||
},
|
||||
assertNodeInfo: function(nodeInfo) {
|
||||
is(nodeInfo, null);
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Testing a property name",
|
||||
getHoveredNode: function*(view) {
|
||||
return getComputedViewProperty(view, "color").nameSpan;
|
||||
},
|
||||
assertNodeInfo: function(nodeInfo) {
|
||||
is(nodeInfo.type, VIEW_NODE_PROPERTY_TYPE);
|
||||
ok("property" in nodeInfo.value);
|
||||
ok("value" in nodeInfo.value);
|
||||
is(nodeInfo.value.property, "color");
|
||||
is(nodeInfo.value.value, "#F00");
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Testing a property value",
|
||||
getHoveredNode: function*(view) {
|
||||
return getComputedViewProperty(view, "color").valueSpan;
|
||||
},
|
||||
assertNodeInfo: function(nodeInfo) {
|
||||
is(nodeInfo.type, VIEW_NODE_VALUE_TYPE);
|
||||
ok("property" in nodeInfo.value);
|
||||
ok("value" in nodeInfo.value);
|
||||
is(nodeInfo.value.property, "color");
|
||||
is(nodeInfo.value.value, "#F00");
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Testing an image url",
|
||||
getHoveredNode: function*(view) {
|
||||
let {valueSpan} = getComputedViewProperty(view, "background-image");
|
||||
return valueSpan.querySelector(".theme-link");
|
||||
},
|
||||
assertNodeInfo: function(nodeInfo) {
|
||||
is(nodeInfo.type, VIEW_NODE_IMAGE_URL_TYPE);
|
||||
ok("property" in nodeInfo.value);
|
||||
ok("value" in nodeInfo.value);
|
||||
is(nodeInfo.value.property, "background-image");
|
||||
is(nodeInfo.value.value, "url(\"chrome://global/skin/icons/warning-64.png\")");
|
||||
is(nodeInfo.value.url, "chrome://global/skin/icons/warning-64.png");
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Testing a matched rule selector (bestmatch)",
|
||||
getHoveredNode: function*(view) {
|
||||
let content = yield getComputedViewMatchedRules(view, "background-color");
|
||||
return content.querySelector(".bestmatch");
|
||||
},
|
||||
assertNodeInfo: function(nodeInfo) {
|
||||
is(nodeInfo.type, VIEW_NODE_SELECTOR_TYPE);
|
||||
is(nodeInfo.value, "div div");
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Testing a matched rule selector (matched)",
|
||||
getHoveredNode: function*(view) {
|
||||
let content = yield getComputedViewMatchedRules(view, "background-color");
|
||||
return content.querySelector(".matched");
|
||||
},
|
||||
assertNodeInfo: function(nodeInfo) {
|
||||
is(nodeInfo.type, VIEW_NODE_SELECTOR_TYPE);
|
||||
is(nodeInfo.value, "div");
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Testing a matched rule selector (parentmatch)",
|
||||
getHoveredNode: function*(view) {
|
||||
let content = yield getComputedViewMatchedRules(view, "color");
|
||||
return content.querySelector(".parentmatch");
|
||||
},
|
||||
assertNodeInfo: function(nodeInfo) {
|
||||
is(nodeInfo.type, VIEW_NODE_SELECTOR_TYPE);
|
||||
is(nodeInfo.value, "body");
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Testing a matched rule value",
|
||||
getHoveredNode: function*(view) {
|
||||
let content = yield getComputedViewMatchedRules(view, "color");
|
||||
return content.querySelector(".other-property-value");
|
||||
},
|
||||
assertNodeInfo: function(nodeInfo) {
|
||||
is(nodeInfo.type, VIEW_NODE_VALUE_TYPE);
|
||||
is(nodeInfo.value.property, "color");
|
||||
is(nodeInfo.value.value, "#F00");
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Testing a matched rule stylesheet link",
|
||||
getHoveredNode: function*(view) {
|
||||
let content = yield getComputedViewMatchedRules(view, "color");
|
||||
return content.querySelector(".rule-link .theme-link");
|
||||
},
|
||||
assertNodeInfo: function(nodeInfo) {
|
||||
is(nodeInfo, null);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
let test = asyncTest(function*() {
|
||||
yield addTab("data:text/html;charset=utf-8," + PAGE_CONTENT);
|
||||
|
||||
let {inspector, view} = yield openComputedView();
|
||||
yield selectNode("#testElement", inspector);
|
||||
|
||||
for (let {desc, getHoveredNode, assertNodeInfo} of TEST_DATA) {
|
||||
info(desc);
|
||||
let nodeInfo = view.getNodeInfo(yield getHoveredNode(view));
|
||||
assertNodeInfo(nodeInfo);
|
||||
}
|
||||
});
|
@ -23,7 +23,7 @@ let test = asyncTest(function*() {
|
||||
yield selectNode("div", inspector);
|
||||
|
||||
info("Expanding the first property");
|
||||
yield expandComputedViewPropertyByIndex(view, inspector, 0);
|
||||
yield expandComputedViewPropertyByIndex(view, 0);
|
||||
|
||||
info("Verifying the link text");
|
||||
yield verifyLinkText(view, SCSS_LOC);
|
||||
|
@ -61,7 +61,7 @@ let test = asyncTest(function*() {
|
||||
function* testInlineStyle(view, inspector) {
|
||||
info("Testing inline style");
|
||||
|
||||
yield expandComputedViewPropertyByIndex(view, inspector, 0);
|
||||
yield expandComputedViewPropertyByIndex(view, 0);
|
||||
|
||||
let onWindow = waitForWindow();
|
||||
info("Clicking on the first rule-link in the computed-view");
|
||||
|
@ -35,6 +35,8 @@ let test = asyncTest(function*() {
|
||||
let {toolbox, inspector, view} = yield openComputedView();
|
||||
|
||||
yield testComputedView(view, inspector.selection.nodeFront);
|
||||
|
||||
yield testExpandedComputedViewProperty(view, inspector.selection.nodeFront);
|
||||
});
|
||||
|
||||
function* testRuleView(ruleView, nodeFront) {
|
||||
@ -77,3 +79,39 @@ function* testComputedView(computedView, nodeFront) {
|
||||
let dataURL = yield getFontFamilyDataURL(valueSpan.textContent, nodeFront);
|
||||
is(images[0].getAttribute("src"), dataURL, "Tooltip contains the correct data-uri image");
|
||||
}
|
||||
|
||||
function* testExpandedComputedViewProperty(computedView, nodeFront) {
|
||||
info("Testing font-family tooltips in expanded properties of the computed view");
|
||||
|
||||
info("Expanding the font-family property to reveal matched selectors");
|
||||
let propertyView = getPropertyView(computedView, "font-family");
|
||||
propertyView.matchedExpanded = true;
|
||||
yield propertyView.refreshMatchedSelectors();
|
||||
|
||||
let valueSpan = propertyView.matchedSelectorsContainer
|
||||
.querySelector(".bestmatch .other-property-value");
|
||||
|
||||
let tooltip = computedView.tooltips.previewTooltip;
|
||||
let panel = tooltip.panel;
|
||||
|
||||
yield assertHoverTooltipOn(tooltip, valueSpan);
|
||||
|
||||
let images = panel.getElementsByTagName("image");
|
||||
is(images.length, 1, "Tooltip contains an image");
|
||||
ok(images[0].getAttribute("src").startsWith("data:"), "Tooltip contains a data-uri image as expected");
|
||||
|
||||
let dataURL = yield getFontFamilyDataURL(valueSpan.textContent, nodeFront);
|
||||
is(images[0].getAttribute("src"), dataURL, "Tooltip contains the correct data-uri image");
|
||||
}
|
||||
|
||||
function getPropertyView(computedView, name) {
|
||||
let propertyView = null;
|
||||
computedView.propertyViews.some(function(view) {
|
||||
if (view.name == name) {
|
||||
propertyView = view;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return propertyView;
|
||||
}
|
||||
|
@ -28,11 +28,6 @@ let test = asyncTest(function*() {
|
||||
yield selectNode("#testElement", inspector);
|
||||
|
||||
yield testRuleView(view, inspector.selection.nodeFront);
|
||||
|
||||
info("Opening the computed view");
|
||||
let {toolbox, inspector, view} = yield openComputedView();
|
||||
|
||||
yield testComputedView(view, inspector.selection.nodeFront);
|
||||
});
|
||||
|
||||
function* testRuleView(ruleView, nodeFront) {
|
||||
@ -63,21 +58,3 @@ function* testRuleView(ruleView, nodeFront) {
|
||||
let dataURL = yield getFontFamilyDataURL(valueSpan.textContent, nodeFront);
|
||||
is(images[0].getAttribute("src"), dataURL, "Tooltip contains the correct data-uri image");
|
||||
}
|
||||
|
||||
function* testComputedView(computedView, nodeFront) {
|
||||
info("Testing font-family tooltips in the computed view");
|
||||
|
||||
let tooltip = computedView.tooltips.previewTooltip;
|
||||
let panel = tooltip.panel;
|
||||
|
||||
let {valueSpan} = getComputedViewProperty(computedView, "font-family");
|
||||
|
||||
yield assertHoverTooltipOn(tooltip, valueSpan);
|
||||
|
||||
let images = panel.getElementsByTagName("image");
|
||||
is(images.length, 1, "Tooltip contains an image");
|
||||
ok(images[0].getAttribute("src").startsWith("data:"), "Tooltip contains a data-uri image as expected");
|
||||
|
||||
let dataURL = yield getFontFamilyDataURL(valueSpan.textContent, nodeFront);
|
||||
is(images[0].getAttribute("src"), dataURL, "Tooltip contains the correct data-uri image");
|
||||
}
|
||||
|
@ -752,32 +752,6 @@ let createNewRuleViewProperty = Task.async(function*(ruleEditor, inputValue) {
|
||||
yield onFocus;
|
||||
});
|
||||
|
||||
// TO BE UNCOMMENTED WHEN THE EYEDROPPER FINALLY LANDS
|
||||
// /**
|
||||
// * Given a color swatch in the ruleview, click on it to open the color picker
|
||||
// * and then click on the eyedropper button to start the eyedropper tool
|
||||
// * @param {CssRuleView} view The instance of the rule-view panel
|
||||
// * @param {DOMNode} swatch The color swatch to be clicked on
|
||||
// * @return A promise that resolves when the dropper is opened
|
||||
// */
|
||||
// let openRuleViewEyeDropper = Task.async(function*(view, swatch) {
|
||||
// info("Opening the colorpicker tooltip on a colorswatch");
|
||||
// let tooltip = view.colorPicker.tooltip;
|
||||
// let onTooltipShown = tooltip.once("shown");
|
||||
// swatch.click();
|
||||
// yield onTooltipShown;
|
||||
|
||||
// info("Finding the eyedropper icon in the colorpicker document");
|
||||
// let tooltipDoc = tooltip.content.contentDocument;
|
||||
// let dropperButton = tooltipDoc.querySelector("#eyedropper-button");
|
||||
// ok(dropperButton, "Found the eyedropper icon");
|
||||
|
||||
// info("Opening the eyedropper");
|
||||
// let onOpen = tooltip.once("eyedropper-opened");
|
||||
// dropperButton.click();
|
||||
// return yield onOpen;
|
||||
// });
|
||||
|
||||
/* *********************************************
|
||||
* COMPUTED-VIEW
|
||||
* *********************************************
|
||||
@ -806,6 +780,40 @@ function getComputedViewProperty(view, name) {
|
||||
return prop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the property-content element for a given property name in
|
||||
* the computed-view.
|
||||
* A property-content element always follows (nextSibling) the property itself
|
||||
* and is only shown when the twisty icon is expanded on the property.
|
||||
* A property-content element contains matched rules, with selectors, properties,
|
||||
* values and stylesheet links
|
||||
* @param {CssHtmlTree} view The instance of the computed view panel
|
||||
* @param {String} name The name of the property to retrieve
|
||||
* @return {Promise} A promise that resolves to the property matched rules
|
||||
* container
|
||||
*/
|
||||
let getComputedViewMatchedRules = Task.async(function*(view, name) {
|
||||
let expander;
|
||||
let propertyContent;
|
||||
for (let property of view.styleDocument.querySelectorAll(".property-view")) {
|
||||
let nameSpan = property.querySelector(".property-name");
|
||||
if (nameSpan.textContent === name) {
|
||||
expander = property.querySelector(".expandable");
|
||||
propertyContent = property.nextSibling;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!expander.hasAttribute("open")) {
|
||||
// Need to expand the property
|
||||
let onExpand = view.inspector.once("computed-view-property-expanded");
|
||||
expander.click();
|
||||
yield onExpand;
|
||||
}
|
||||
|
||||
return propertyContent;
|
||||
});
|
||||
|
||||
/**
|
||||
* Get the text value of the property corresponding to a given name in the
|
||||
* computed-view
|
||||
@ -813,8 +821,8 @@ function getComputedViewProperty(view, name) {
|
||||
* @param {String} name The name of the property to retrieve
|
||||
* @return {String} The property value
|
||||
*/
|
||||
function getComputedViewPropertyValue(view, selectorText, propertyName) {
|
||||
return getComputedViewProperty(view, selectorText, propertyName)
|
||||
function getComputedViewPropertyValue(view, name, propertyName) {
|
||||
return getComputedViewProperty(view, name, propertyName)
|
||||
.valueSpan.textContent;
|
||||
}
|
||||
|
||||
@ -822,19 +830,18 @@ function getComputedViewPropertyValue(view, selectorText, propertyName) {
|
||||
* Expand a given property, given its index in the current property list of
|
||||
* the computed view
|
||||
* @param {CssHtmlTree} view The instance of the computed view panel
|
||||
* @param {InspectorPanel} inspector The instance of the inspector panel
|
||||
* @param {Number} index The index of the property to be expanded
|
||||
* @return a promise that resolves when the property has been expanded, or
|
||||
* rejects if the property was not found
|
||||
*/
|
||||
function expandComputedViewPropertyByIndex(view, inspector, index) {
|
||||
function expandComputedViewPropertyByIndex(view, index) {
|
||||
info("Expanding property " + index + " in the computed view");
|
||||
let expandos = view.styleDocument.querySelectorAll(".expandable");
|
||||
if (!expandos.length || !expandos[index]) {
|
||||
return promise.reject();
|
||||
}
|
||||
|
||||
let onExpand = inspector.once("computed-view-property-expanded");
|
||||
let onExpand = view.inspector.once("computed-view-property-expanded");
|
||||
expandos[index].click();
|
||||
return onExpand;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user