Bug 971662 - part 1 - GCLI command that highlights all nodes that match a selector; r=jwalker

This commit is contained in:
Patrick Brosset 2014-06-25 16:40:43 +02:00
parent 2073828ccc
commit 657f763085
7 changed files with 565 additions and 0 deletions

View File

@ -15,6 +15,7 @@ const commandModules = [
"gcli/commands/cookie",
"gcli/commands/csscoverage",
"gcli/commands/folder",
"gcli/commands/highlight",
"gcli/commands/inject",
"gcli/commands/jsb",
"gcli/commands/listen",

View File

@ -51,6 +51,8 @@ support-files =
browser_cmd_csscoverage_sheetC.css
browser_cmd_csscoverage_sheetD.css
[browser_cmd_folder.js]
[browser_cmd_highlight_01.js]
[browser_cmd_highlight_02.js]
[browser_cmd_inject.js]
support-files =
browser_cmd_inject.html

View File

@ -0,0 +1,257 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests the various highlight command parameters and options
// Creating a test page with many elements to test the --showall option
let TEST_PAGE = "data:text/html;charset=utf-8,<body><ul>";
for (let i = 0; i < 200; i ++) {
TEST_PAGE += "<li class='item'>" + i + "</li>";
}
TEST_PAGE += "</ul></body>";
function test() {
return Task.spawn(spawnTest).then(finish, helpers.handleError);
}
function* spawnTest() {
let options = yield helpers.openTab(TEST_PAGE);
yield helpers.openToolbar(options);
yield helpers.audit(options, [
{
setup: 'highlight',
check: {
input: 'highlight',
hints: ' [selector] [options]',
markup: 'VVVVVVVVV',
status: 'VALID'
},
exec: {
output: '0 nodes highlighted'
}
},
{
setup: 'highlight bo',
check: {
input: 'highlight bo',
hints: ' [options]',
markup: 'VVVVVVVVVVII',
status: 'ERROR'
},
exec: {
output: 'Error: No matches'
}
},
{
setup: 'highlight body',
check: {
input: 'highlight body',
hints: ' [options]',
markup: 'VVVVVVVVVVVVVV',
status: 'VALID'
},
exec: {
output: '1 nodes highlighted'
}
},
{
setup: 'highlight body --hide',
check: {
input: 'highlight body --hide',
hints: 'guides [options]',
markup: 'VVVVVVVVVVVVVVVIIIIII',
status: 'ERROR'
},
exec: {
output: 'Error: Too many arguments'
}
},
{
setup: 'highlight body --hideguides',
check: {
input: 'highlight body --hideguides',
hints: ' [options]',
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVV',
status: 'VALID'
},
exec: {
output: '1 nodes highlighted'
}
},
{
setup: 'highlight body --show',
check: {
input: 'highlight body --show',
hints: 'infobar [options]',
markup: 'VVVVVVVVVVVVVVVIIIIII',
status: 'ERROR'
},
exec: {
output: 'Error: Too many arguments'
}
},
{
setup: 'highlight body --showinfobar',
check: {
input: 'highlight body --showinfobar',
hints: ' [options]',
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVV',
status: 'VALID'
},
exec: {
output: '1 nodes highlighted'
}
},
{
setup: 'highlight body --showa',
check: {
input: 'highlight body --showa',
hints: 'll [options]',
markup: 'VVVVVVVVVVVVVVVIIIIIII',
status: 'ERROR'
},
exec: {
output: 'Error: Too many arguments'
}
},
{
setup: 'highlight body --showall',
check: {
input: 'highlight body --showall',
hints: ' [options]',
markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
status: 'VALID'
},
exec: {
output: '1 nodes highlighted'
}
},
{
setup: 'highlight body --r',
check: {
input: 'highlight body --r',
hints: 'egion [options]',
markup: 'VVVVVVVVVVVVVVVIII',
status: 'ERROR'
},
exec: {
output: 'Error: Too many arguments'
}
},
{
setup: 'highlight body --region',
check: {
input: 'highlight body --region',
hints: ' <selection> [options]',
markup: 'VVVVVVVVVVVVVVVIIIIIIII',
status: 'ERROR'
},
exec: {
output: 'Error: Value required for \'region\'.'
}
},
{
setup: 'highlight body --fi',
check: {
input: 'highlight body --fi',
hints: 'll [options]',
markup: 'VVVVVVVVVVVVVVVIIII',
status: 'ERROR'
},
exec: {
output: 'Error: Too many arguments'
}
},
{
setup: 'highlight body --fill',
check: {
input: 'highlight body --fill',
hints: ' <string> [options]',
markup: 'VVVVVVVVVVVVVVVIIIIII',
status: 'ERROR'
},
exec: {
output: 'Error: Value required for \'fill\'.'
}
},
{
setup: 'highlight body --ke',
check: {
input: 'highlight body --ke',
hints: 'ep [options]',
markup: 'VVVVVVVVVVVVVVVIIII',
status: 'ERROR'
},
exec: {
output: 'Error: Too many arguments'
}
},
{
setup: 'highlight body --keep',
check: {
input: 'highlight body --keep',
hints: ' [options]',
markup: 'VVVVVVVVVVVVVVVVVVVVV',
status: 'VALID'
},
exec: {
output: '1 nodes highlighted'
}
},
{
setup: 'highlight body --hideguides --showinfobar --showall --region ' +
'content --fill red --keep',
check: {
input: 'highlight body --hideguides --showinfobar --showall --region ' +
'content --fill red --keep',
hints: '',
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV' +
'VVVVVVVVVVVVVVVVVVVVVVVVV',
status: 'VALID'
},
exec: {
output: '1 nodes highlighted'
}
},
{
setup: 'highlight .item',
check: {
input: 'highlight .item',
hints: ' [options]',
markup: 'VVVVVVVVVVVVVVV',
status: 'VALID'
},
exec: {
output: '200 nodes matched, but only 100 nodes highlighted. Use ' +
'\'--showall\' to show all'
}
},
{
setup: 'highlight .item --showall',
check: {
input: 'highlight .item --showall',
hints: ' [options]',
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVV',
status: 'VALID'
},
exec: {
output: '200 nodes highlighted'
}
},
{
setup: 'unhighlight',
check: {
input: 'unhighlight',
hints: '',
markup: 'VVVVVVVVVVV',
status: 'VALID'
}
}
]);
yield helpers.closeToolbar(options);
yield helpers.closeTab(options);
}

View File

@ -0,0 +1,43 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests that the highlight command actually creates a highlighter
const TEST_PAGE = "data:text/html;charset=utf-8,<div></div>";
function test() {
return Task.spawn(function*() {
let options = yield helpers.openTab(TEST_PAGE);
yield helpers.openToolbar(options);
info("highlighting the body node");
yield runCommand("highlight body", options);
is(getHighlighters().length, 1, "The highlighter element exists for body");
info("highlighting the div node");
yield runCommand("highlight div", options);
is(getHighlighters().length, 1, "The highlighter element exists for div");
info("highlighting the body node again, asking to keep the div");
yield runCommand("highlight body --keep", options);
is(getHighlighters().length, 2, "2 highlighter elements have been created");
info("unhighlighting all nodes");
yield runCommand("unhighlight", options);
is(getHighlighters().length, 0, "All highlighters have been removed");
yield helpers.closeToolbar(options);
yield helpers.closeTab(options);
}).then(finish, helpers.handleError);
}
function getHighlighters() {
return gBrowser.selectedBrowser.parentNode
.querySelectorAll(".highlighter-container");
}
function* runCommand(cmd, options) {
yield helpers.audit(options, [{ setup: cmd, exec: {} }]);
}

View File

@ -128,6 +128,113 @@ screenshotCopied=Copied to clipboard.
# LOCALIZATION NOTE (screenshotTooltip) Text displayed as tooltip for screenshot button in devtools ToolBox.
screenshotTooltip=Take a fullpage screenshot
# LOCALIZATION NOTE (highlightDesc) A very short description of the
# 'highlight' command. See highlightManual for a fuller description of what
# it does. This string is designed to be shown in a menu alongside the
# command name, which is why it should be as short as possible.
highlightDesc=Highlight nodes
# LOCALIZATION NOTE (highlightManual) A fuller description of the 'highlight'
# command, displayed when the user asks for help on what it does.
highlightManual=Highlight nodes that match a selector on the page
# LOCALIZATION NOTE (highlightSelectorDesc) A very short string to describe
# the 'selector' parameter to the 'highlight' command, which is displayed in
# a dialog when the user is using this command.
highlightSelectorDesc=CSS selector
# LOCALIZATION NOTE (highlightSelectorManual) A fuller description of the
# 'selector' parameter to the 'highlight' command, displayed when the user
# asks for help on what it does.
highlightSelectorManual=The CSS selector used to match nodes in the page
# LOCALIZATION NOTE (highlightOptionsDesc) The title of a set of options to
# the 'highlight' command, displayed as a heading to the list of option.
highlightOptionsDesc=Options
# LOCALIZATION NOTE (highlightHideGuidesDesc) A very short string to describe
# the 'hideguides' option parameter to the 'highlight' command, which is
# displayed in a dialog when the user is using this command.
highlightHideGuidesDesc=Hide guides
# LOCALIZATION NOTE (highlightHideGuidesManual) A fuller description of the
# 'hideguides' option parameter to the 'highlight' command, displayed when the
# user asks for help on what it does.
highlightHideGuidesManual=Hide the guides around the highlighted node
# LOCALIZATION NOTE (highlightShowInfoBarDesc) A very short string to describe
# the 'showinfobar' option parameter to the 'highlight' command, which is
# displayed in a dialog when the user is using this command.
highlightShowInfoBarDesc=Show the node infobar
# LOCALIZATION NOTE (highlightShowInfoBarManual) A fuller description of the
# 'showinfobar' option parameter to the 'highlight' command, displayed when the
# user asks for help on what it does.
highlightShowInfoBarManual=Show the infobar above the highlighted node (the infobar displays the tagname, attributes and dimension)
# LOCALIZATION NOTE (highlightShowAllDesc) A very short string to describe
# the 'showall' option parameter to the 'highlight' command, which is
# displayed in a dialog when the user is using this command.
highlightShowAllDesc=Show all matches
# LOCALIZATION NOTE (highlightShowAllManual) A fuller description of the
# 'showall' option parameter to the 'highlight' command, displayed when the
# user asks for help on what it does.
highlightShowAllManual=If too many nodes match the selector, only the first 100 will be shown to avoid slowing down the page too much. Use this option to show all matches instead
# LOCALIZATION NOTE (highlightRegionDesc) A very short string to describe the
# 'region' option parameter to the 'highlight' command, which is displayed in a
# dialog when the user is using this command.
highlightRegionDesc=Box model region
# LOCALIZATION NOTE (highlightRegionManual) A fuller description of the 'region'
# option parameter to the 'highlight' command, displayed when the user asks for
# help on what it does.
highlightRegionManual=Which box model region should be highlighted: 'content', 'padding', 'border' or 'margin'
# LOCALIZATION NOTE (highlightFillDesc) A very short string to describe the
# 'fill' option parameter to the 'highlight' command, which is displayed in a
# dialog when the user is using this command.
highlightFillDesc=Fill style
# LOCALIZATION NOTE (highlightFillManual) A fuller description of the 'fill'
# option parameter to the 'highlight' command, displayed when the user asks for
# help on what it does.
highlightFillManual=Override the default region fill style with a custom color
# LOCALIZATION NOTE (highlightKeepDesc) A very short string to describe the
# 'keep' option parameter to the 'highlight' command, which is displayed in a
# dialog when the user is using this command.
highlightKeepDesc=Keep existing highlighters
# LOCALIZATION NOTE (highlightKeepManual) A fuller description of the 'keep'
# option parameter to the 'highlight' command, displayed when the user asks for
# help on what it does.
highlightKeepManual=By default, existing highlighters are hidden when running the command, unless this option is set
# LOCALIZATION NOTE (highlightOutputConfirm) A confirmation message for the
# 'highlight' command, displayed to the user once the command has been entered,
# informing the user how many nodes have been highlighted successfully and how
# to turn highlighting off
highlightOutputConfirm=%1$S nodes highlighted
# LOCALIZATION NOTE (highlightOutputMaxReached) A confirmation message for the
# 'highlight' command, displayed to the user once the command has been entered,
# informing the user how many nodes have been highlighted successfully and that
# some nodes could not be highlighted due to the maximum number of nodes being
# reached, and how to turn highlighting off
highlightOutputMaxReached=%1$S nodes matched, but only %2$S nodes highlighted. Use '--showall' to show all
# LOCALIZATION NOTE (unhighlightDesc) A very short description of the
# 'unhighlight' command. See unhighlightManual for a fuller description of what
# it does. This string is designed to be shown in a menu alongside the
# command name, which is why it should be as short as possible.
unhighlightDesc=Unhighlight all nodes
# LOCALIZATION NOTE (unhighlightManual) A fuller description of the 'unhighlight'
# command, displayed when the user asks for help on what it does.
unhighlightManual=Unhighlight all nodes previously highlighted with the 'highlight' command
# LOCALIZATION NOTE (restartBrowserDesc) A very short description of the
# 'restart' command. This string is designed to be shown in a menu alongside the
# command name, which is why it should be as short as possible.

View File

@ -0,0 +1,142 @@
/* 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/. */
"use strict";
const {Cc, Ci, Cu} = require("chrome");
const gcli = require("gcli/index");
require("devtools/server/actors/inspector");
const {HIGHLIGHTER_CLASSES} = require("devtools/server/actors/highlighter");
const {BoxModelHighlighter} = HIGHLIGHTER_CLASSES;
// How many maximum nodes can be highlighted in parallel
const MAX_HIGHLIGHTED_ELEMENTS = 100;
// Stores the highlighters instances so they can be destroyed
let highlighters = [];
/**
* Destroy all existing highlighters
*/
function unhighlightAll() {
for (let highlighter of highlighters) {
highlighter.destroy();
}
highlighters = [];
}
exports.items = [
{
name: "highlight",
description: gcli.lookup("highlightDesc"),
manual: gcli.lookup("highlightManual"),
params: [
{
name: "selector",
type: "nodelist",
description: gcli.lookup("highlightSelectorDesc"),
manual: gcli.lookup("highlightSelectorManual")
},
{
group: gcli.lookup("highlightOptionsDesc"),
params: [
{
name: "hideguides",
type: "boolean",
description: gcli.lookup("highlightHideGuidesDesc"),
manual: gcli.lookup("highlightHideGuidesManual")
},
{
name: "showinfobar",
type: "boolean",
description: gcli.lookup("highlightShowInfoBarDesc"),
manual: gcli.lookup("highlightShowInfoBarManual")
},
{
name: "showall",
type: "boolean",
description: gcli.lookup("highlightShowAllDesc"),
manual: gcli.lookup("highlightShowAllManual")
},
{
name: "region",
type: {
name: "selection",
data: ["content", "padding", "border", "margin"]
},
description: gcli.lookup("highlightRegionDesc"),
manual: gcli.lookup("highlightRegionManual"),
defaultValue: "border"
},
{
name: "fill",
type: "string",
description: gcli.lookup("highlightFillDesc"),
manual: gcli.lookup("highlightFillManual"),
defaultValue: null
},
{
name: "keep",
type: "boolean",
description: gcli.lookup("highlightKeepDesc"),
manual: gcli.lookup("highlightKeepManual"),
}
]
}
],
exec: function(args, context) {
// Remove all existing highlighters unless told otherwise
if (!args.keep) {
unhighlightAll();
}
let env = context.environment;
// Unhighlight on navigate
env.target.once("navigate", unhighlightAll);
// Build a tab context for the highlighter (which normally takes a
// TabActor as parameter to its constructor)
let tabContext = {
browser: env.chromeWindow.gBrowser.getBrowserForDocument(env.document),
window: env.window
};
let i = 0;
for (let node of args.selector) {
if (!args.showall && i >= MAX_HIGHLIGHTED_ELEMENTS) {
break;
}
let highlighter = new BoxModelHighlighter(tabContext);
if (args.fill) {
highlighter.regionFill[args.region] = args.fill;
}
highlighter.show(node, {
region: args.region,
hideInfoBar: !args.showinfobar,
hideGuides: args.hideguides,
showOnly: args.region
});
highlighters.push(highlighter);
i ++;
}
let output = gcli.lookupFormat("highlightOutputConfirm",
["" + args.selector.length]);
if (args.selector.length > i) {
output = gcli.lookupFormat("highlightOutputMaxReached",
["" + args.selector.length, "" + i]);
}
return output;
}
},
{
name: "unhighlight",
description: gcli.lookup("unhighlightDesc"),
manual: gcli.lookup("unhighlightManual"),
exec: unhighlightAll
}
];

View File

@ -502,6 +502,12 @@ function BoxModelHighlighter(tabActor) {
this._initMarkup();
EventEmitter.decorate(this);
/**
* Optionally customize each region's fill color by adding an entry to the
* regionFill property: `highlighter.regionFill.margin = "red";
*/
this.regionFill = {};
this._currentNode = null;
}
@ -774,6 +780,13 @@ BoxModelHighlighter.prototype = Heritage.extend(XULBasedHighlighter.prototype, {
this.layoutHelpers.getAdjustedQuads(this.currentNode, boxType);
let boxNode = this._boxModelNodes[boxType];
if (this.regionFill[boxType]) {
boxNode.setAttribute("style", "fill:" + this.regionFill[boxType]);
} else {
boxNode.removeAttribute("style");
}
if (!this.options.showOnly || this.options.showOnly === boxType) {
boxNode.setAttribute("points",
p1.x + "," + p1.y + " " +