Bug 663833 - [highlighter] Add a floating toolbar next to the selected node; r=msucan,dao

This commit is contained in:
Paul Rouget 2011-09-27 17:01:24 -03:00
Родитель abd693bedd
Коммит 4775bcf504
7 изменённых файлов: 508 добавлений и 7 удалений

Просмотреть файл

@ -35,3 +35,52 @@
pointer-events: auto;
z-index: 1;
}
/*
* Node Infobar
*/
#highlighter-nodeinfobar-container {
position: absolute;
-moz-transition-property: top, left;
-moz-transition-duration: 0.1s;
-moz-transition-timing-function: linear;
}
#highlighter-nodeinfobar {
display: block;
white-space: nowrap;
direction: ltr;
}
.highlighter-nodeinfobar-arrow {
display: none;
}
#highlighter-nodeinfobar-container[position="top"]:not([hide-arrow]) > #highlighter-nodeinfobar-arrow-bottom {
display: block;
}
#highlighter-nodeinfobar-container[position="bottom"]:not([hide-arrow]) > #highlighter-nodeinfobar-arrow-top {
display: block;
}
#highlighter-nodeinfobar-container[disabled] {
visibility: hidden;
}
#highlighter-nodeinfobar-id:empty {
display: none;
}
#highlighter-nodeinfobar-id::before {
content: "#";
}
.highlighter-nodeinfobar-class::before {
content: ".";
}
#highlighter-nodeinfobar-tagname {
text-transform: lowercase;
}

Просмотреть файл

@ -125,6 +125,10 @@ Highlighter.prototype = {
let controlsBox = this.chromeDoc.createElement("box");
controlsBox.id = "highlighter-controls";
this.highlighterContainer.appendChild(this.veilContainer);
this.highlighterContainer.appendChild(controlsBox);
stack.appendChild(this.highlighterContainer);
// The veil will make the whole page darker except
// for the region of the selected box.
@ -134,11 +138,6 @@ Highlighter.prototype = {
// elements of the highlighter (buttons, toolbars, ...).
this.buildControls(controlsBox);
this.highlighterContainer.appendChild(this.veilContainer);
this.highlighterContainer.appendChild(controlsBox);
stack.appendChild(this.highlighterContainer);
this.browser.addEventListener("resize", this, true);
this.browser.addEventListener("scroll", this, true);
@ -158,7 +157,8 @@ Highlighter.prototype = {
* <box id="highlighter-veil-bottombox" class="highlighter-veil"/>
* </vbox>
*
* @param nsIDOMNode aParent
* @param nsIDOMElement aParent
* The container of the veil boxes.
*/
buildVeil: function Highlighter_buildVeil(aParent)
{
@ -204,9 +204,87 @@ Highlighter.prototype = {
*
* <box id="highlighter-close-button"/>
*
* @param nsIDOMNode aParent
* @param nsIDOMElement aParent
* The container of the controls elements.
*/
buildControls: function Highlighter_buildControls(aParent)
{
this.buildCloseButton(aParent);
this.buildInfobar(aParent);
},
/**
* Build the node Infobar.
*
* <box id="highlighter-nodeinfobar-container">
* <box id="Highlighter-nodeinfobar-arrow-top"/>
* <vbox id="highlighter-nodeinfobar">
* <label id="highlighter-nodeinfobar-tagname"/>
* <label id="highlighter-nodeinfobar-id"/>
* <vbox id="highlighter-nodeinfobar-classes"/>
* </vbox>
* <box id="Highlighter-nodeinfobar-arrow-bottom"/>
* </box>
*
* @param nsIDOMElement aParent
* The container of the infobar.
*/
buildInfobar: function Highlighter_buildInfobar(aParent)
{
let container = this.chromeDoc.createElement("box");
container.id = "highlighter-nodeinfobar-container";
container.setAttribute("position", "top");
container.setAttribute("disabled", "true");
let nodeInfobar = this.chromeDoc.createElement("hbox");
nodeInfobar.id = "highlighter-nodeinfobar";
let arrowBoxTop = this.chromeDoc.createElement("box");
arrowBoxTop.className = "highlighter-nodeinfobar-arrow";
arrowBoxTop.id = "highlighter-nodeinfobar-arrow-top";
let arrowBoxBottom = this.chromeDoc.createElement("box");
arrowBoxBottom.className = "highlighter-nodeinfobar-arrow";
arrowBoxBottom.id = "highlighter-nodeinfobar-arrow-bottom";
let tagNameLabel = this.chromeDoc.createElement("label");
tagNameLabel.id = "highlighter-nodeinfobar-tagname";
tagNameLabel.className = "plain";
let idLabel = this.chromeDoc.createElement("label");
idLabel.id = "highlighter-nodeinfobar-id";
idLabel.className = "plain";
let classesBox = this.chromeDoc.createElement("hbox");
classesBox.id = "highlighter-nodeinfobar-classes";
nodeInfobar.appendChild(tagNameLabel);
nodeInfobar.appendChild(idLabel);
nodeInfobar.appendChild(classesBox);
container.appendChild(arrowBoxTop);
container.appendChild(nodeInfobar);
container.appendChild(arrowBoxBottom);
aParent.appendChild(container);
let barHeight = container.getBoundingClientRect().height;
this.nodeInfo = {
tagNameLabel: tagNameLabel,
idLabel: idLabel,
classesBox: classesBox,
container: container,
barHeight: barHeight,
};
},
/**
* Build the close button.
*
* @param nsIDOMElement aParent
* The container of the close-button.
*/
buildCloseButton: function Highlighter_buildCloseButton(aParent)
{
let closeButton = this.chromeDoc.createElement("box");
closeButton.id = "highlighter-close-button";
@ -233,6 +311,7 @@ Highlighter.prototype = {
this.veilTransparentBox = null;
this.veilContainer = null;
this.node = null;
this.nodeInfo = null;
this.highlighterContainer.parentNode.removeChild(this.highlighterContainer);
this.highlighterContainer = null;
this.win = null
@ -327,6 +406,8 @@ Highlighter.prototype = {
this.highlightRectangle(rect);
this.moveInfobar();
if (this._highlighting) {
Services.obs.notifyObservers(null,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, null);
@ -344,6 +425,7 @@ Highlighter.prototype = {
highlightNode: function Highlighter_highlightNode(aNode, aParams)
{
this.node = aNode;
this.updateInfobar();
this.highlight(aParams && aParams.scroll);
},
@ -395,6 +477,87 @@ Highlighter.prototype = {
INSPECTOR_NOTIFICATIONS.UNHIGHLIGHTING, null);
},
/**
* Update node information (tagName#id.class)
*/
updateInfobar: function Highlighter_updateInfobar()
{
// Tag name
this.nodeInfo.tagNameLabel.textContent = this.node.tagName;
// ID
this.nodeInfo.idLabel.textContent = this.node.id;
// Classes
let classes = this.nodeInfo.classesBox;
while (classes.hasChildNodes()) {
classes.removeChild(classes.firstChild);
}
if (this.node.className) {
let fragment = this.chromeDoc.createDocumentFragment();
for (let i = 0; i < this.node.classList.length; i++) {
let classLabel = this.chromeDoc.createElement("label");
classLabel.className = "highlighter-nodeinfobar-class plain";
classLabel.textContent = this.node.classList[i];
fragment.appendChild(classLabel);
}
classes.appendChild(fragment);
}
},
/**
* Move the Infobar to the right place in the highlighter.
*/
moveInfobar: function Highlighter_moveInfobar()
{
let rect = this._highlightRect;
if (rect && this._highlighting) {
this.nodeInfo.container.removeAttribute("disabled");
// Can the bar be above the node?
if (rect.top < this.nodeInfo.barHeight) {
// No. Can we move the toolbar under the node?
if (rect.top + rect.height +
this.nodeInfo.barHeight > this.win.innerHeight) {
// No. Let's move it inside.
this.nodeInfo.container.style.top = rect.top + "px";
this.nodeInfo.container.setAttribute("position", "overlap");
} else {
// Yes. Let's move it under the node.
this.nodeInfo.container.style.top = rect.top + rect.height + "px";
this.nodeInfo.container.setAttribute("position", "bottom");
}
} else {
// Yes. Let's move it on top of the node.
this.nodeInfo.container.style.top =
rect.top - this.nodeInfo.barHeight + "px";
this.nodeInfo.container.setAttribute("position", "top");
}
let barWidth = this.nodeInfo.container.getBoundingClientRect().width;
let left = rect.left + rect.width / 2 - barWidth / 2;
// Make sure the whole infobar is visible
if (left < 0) {
left = 0;
this.nodeInfo.container.setAttribute("hide-arrow", "true");
} else {
if (left + barWidth > this.win.innerWidth) {
left = this.win.innerWidth - barWidth;
this.nodeInfo.container.setAttribute("hide-arrow", "true");
} else {
this.nodeInfo.container.removeAttribute("hide-arrow");
}
}
this.nodeInfo.container.style.left = left + "px";
} else {
this.nodeInfo.container.style.left = "0";
this.nodeInfo.container.style.top = "0";
this.nodeInfo.container.setAttribute("position", "top");
this.nodeInfo.container.setAttribute("hide-arrow", "true");
}
},
/**
* Return the midpoint of a line from pointA to pointB.
*

Просмотреть файл

@ -59,6 +59,7 @@ _BROWSER_FILES = \
browser_inspector_bug_674871.js \
browser_inspector_editor.js \
browser_inspector_bug_566084_location_changed.js \
browser_inspector_infobar.js \
$(NULL)
# Disabled due to constant failures

Просмотреть файл

@ -0,0 +1,107 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test()
{
waitForExplicitFinish();
let doc;
let nodes;
let cursor;
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
doc = content.document;
waitForFocus(setupInfobarTest, content);
}, true);
let style = "body{width:100%;height: 100%} div {position: absolute;height: 100px;width: 500px}#bottom {bottom: 0px}#vertical {height: 100%}";
let html = "<style>" + style + "</style><div id=vertical></div><div id=top class='class1 class2'></div><div id=bottom></div>"
content.location = "data:text/html," + encodeURIComponent(html);
function setupInfobarTest()
{
nodes = [
{node: doc.querySelector("#top"), position: "bottom", tag: "DIV", id: "top", classes: "class1 class2"},
{node: doc.querySelector("#vertical"), position: "overlap", tag: "DIV", id: "vertical", classes: ""},
{node: doc.querySelector("#bottom"), position: "top", tag: "DIV", id: "bottom", classes: ""},
{node: doc.querySelector("body"), position: "overlap", tag: "BODY", id: "", classes: ""},
]
for (let i = 0; i < nodes.length; i++) {
ok(nodes[i].node, "node " + i + " found");
}
Services.obs.addObserver(runTests,
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.toggleInspectorUI();
}
function runTests()
{
Services.obs.removeObserver(runTests,
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
cursor = 0;
executeSoon(function() {
Services.obs.addObserver(nodeSelected,
InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
InspectorUI.inspectNode(nodes[0].node);
});
}
function nodeSelected()
{
executeSoon(function() {
performTest();
cursor++;
if (cursor >= nodes.length) {
Services.obs.removeObserver(nodeSelected,
InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
Services.obs.addObserver(finishUp,
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
executeSoon(function() {
InspectorUI.closeInspectorUI();
});
} else {
let node = nodes[cursor].node;
InspectorUI.inspectNode(node);
}
});
}
function performTest()
{
let container = document.getElementById("highlighter-nodeinfobar-container");
is(container.getAttribute("position"), nodes[cursor].position, "node " + cursor + ": position matches.");
let tagNameLabel = document.getElementById("highlighter-nodeinfobar-tagname");
is(tagNameLabel.textContent, nodes[cursor].tag, "node " + cursor + ": tagName matches.");
let idLabel = document.getElementById("highlighter-nodeinfobar-id");
is(idLabel.textContent, nodes[cursor].id, "node " + cursor + ": id matches.");
let classesBox = document.getElementById("highlighter-nodeinfobar-classes");
let displayedClasses = [];
for (let i = 0; i < classesBox.childNodes.length; i++) {
displayedClasses.push(classesBox.childNodes[i].textContent);
}
displayedClasses = displayedClasses.join(" ");
is(displayedClasses, nodes[cursor].classes, "node " + cursor + ": classes match.");
}
function finishUp() {
Services.obs.removeObserver(finishUp, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
doc = nodes = null;
gBrowser.removeCurrentTab();
finish();
}
}

Просмотреть файл

@ -28,6 +28,7 @@
* Pamela Greene (pamg.bugs@gmail.com)
* Dão Gottwald (dao@mozilla.com)
* Drew Willcoxon (adw@mozilla.com)
* Paul Rouget (paul@mozilla.com)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -1951,3 +1952,63 @@ panel[dimmed="true"] {
-moz-appearance: none;
cursor: n-resize;
}
/* Highlighter - Node Infobar */
/* Highlighter - Node Infobar - text */
#highlighter-nodeinfobar-tagname {
color: white;
}
#highlighter-nodeinfobar-id {
color: hsl(90, 79%, 52%);
}
.highlighter-nodeinfobar-class {
color: hsl(200, 100%, 65%);
}
/* Highlighter - Node Infobar - box & arrow */
#highlighter-nodeinfobar {
border: 1px solid hsla(210, 19%, 63%, .5);
border-radius: 3px;
padding: 8px 16px;
background: -moz-linear-gradient(hsl(209, 18%, 30%), hsl(210, 24%, 16%)) no-repeat padding-box;
}
.highlighter-nodeinfobar-arrow {
width: 14px;
height: 14px;
-moz-margin-start: -moz-calc(50% - 7px);
-moz-transform: rotate(-45deg);
border: 1px solid transparent;
background-clip: padding-box;
background-repeat: no-repeat;
}
#highlighter-nodeinfobar-arrow-top {
margin-bottom: -8px;
margin-top: 8px;
border-right-color: hsla(210, 19%, 63%, .5);
border-top-color: hsla(210, 19%, 63%, .5);
background-image: -moz-linear-gradient(bottom left, transparent 50%, hsl(209, 18%, 30%) 50%);
}
#highlighter-nodeinfobar-arrow-bottom {
margin-top: -8px;
margin-bottom: 8px;
border-left-color: hsla(210, 19%, 63%, .5);
border-bottom-color: hsla(210, 19%, 63%, .5);
background-image: -moz-linear-gradient(top right, transparent 50%, hsl(210, 24%, 16%) 50%);
}
#highlighter-nodeinfobar-container[position="top"] > #highlighter-nodeinfobar,
#highlighter-nodeinfobar-container[position="overlap"] > #highlighter-nodeinfobar {
box-shadow: 0 1px 0 hsla(0, 0%, 100%, .1) inset;
}
#highlighter-nodeinfobar-container[hide-arrow] > #highlighter-nodeinfobar {
margin: 7px 0;
}

Просмотреть файл

@ -27,6 +27,7 @@
* Dão Gottwald (dao@mozilla.com)
* Stephen Horlander (stephen@noved.org)
* Drew Willcoxon (adw@mozilla.com)
* Paul Rouget (paul@mozilla.com)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -2612,3 +2613,62 @@ panel[dimmed="true"] {
cursor: n-resize;
}
/* Highlighter - Node Infobar */
/* Highlighter - Node Infobar - text */
#highlighter-nodeinfobar-tagname {
color: white;
}
#highlighter-nodeinfobar-id {
color: hsl(90, 79%, 52%);
}
.highlighter-nodeinfobar-class {
color: hsl(200, 100%, 65%);
}
/* Highlighter - Node Infobar - box & arrow */
#highlighter-nodeinfobar {
border: 1px solid hsla(210, 19%, 63%, .5);
border-radius: 3px;
padding: 8px 16px;
background: -moz-linear-gradient(hsl(209, 18%, 30%), hsl(210, 24%, 16%)) no-repeat padding-box;
}
.highlighter-nodeinfobar-arrow {
width: 14px;
height: 14px;
-moz-margin-start: -moz-calc(50% - 7px);
-moz-transform: rotate(-45deg);
border: 1px solid transparent;
background-clip: padding-box;
background-repeat: no-repeat;
}
#highlighter-nodeinfobar-arrow-top {
margin-bottom: -8px;
margin-top: 8px;
border-right-color: hsla(210, 19%, 63%, .5);
border-top-color: hsla(210, 19%, 63%, .5);
background-image: -moz-linear-gradient(bottom left, transparent 50%, hsl(209, 18%, 30%) 50%);
}
#highlighter-nodeinfobar-arrow-bottom {
margin-top: -8px;
margin-bottom: 8px;
border-left-color: hsla(210, 19%, 63%, .5);
border-bottom-color: hsla(210, 19%, 63%, .5);
background-image: -moz-linear-gradient(top right, transparent 50%, hsl(210, 24%, 16%) 50%);
}
#highlighter-nodeinfobar-container[position="top"] > #highlighter-nodeinfobar,
#highlighter-nodeinfobar-container[position="overlap"] > #highlighter-nodeinfobar {
box-shadow: 0 1px 0 hsla(0, 0%, 100%, .1) inset;
}
#highlighter-nodeinfobar-container[hide-arrow] > #highlighter-nodeinfobar {
margin: 7px 0;
}

Просмотреть файл

@ -28,6 +28,7 @@
* Dão Gottwald (dao@mozilla.com)
* Jim Mathies (jmathies@mozilla.com)
* Drew Willcoxon (adw@mozilla.com)
* Paul Rouget (paul@mozilla.com)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -2568,3 +2569,62 @@ panel[dimmed="true"] {
cursor: n-resize;
}
/* Highlighter - Node Infobar */
/* Highlighter - Node Infobar - text */
#highlighter-nodeinfobar-tagname {
color: white;
}
#highlighter-nodeinfobar-id {
color: hsl(90, 79%, 52%);
}
.highlighter-nodeinfobar-class {
color: hsl(200, 100%, 65%);
}
/* Highlighter - Node Infobar - box & arrow */
#highlighter-nodeinfobar {
border: 1px solid hsla(210, 19%, 63%, .5);
border-radius: 3px;
padding: 8px 16px;
background: -moz-linear-gradient(hsl(209, 18%, 30%), hsl(210, 24%, 16%)) no-repeat padding-box;
}
.highlighter-nodeinfobar-arrow {
width: 14px;
height: 14px;
-moz-margin-start: -moz-calc(50% - 7px);
-moz-transform: rotate(-45deg);
border: 1px solid transparent;
background-clip: padding-box;
background-repeat: no-repeat;
}
#highlighter-nodeinfobar-arrow-top {
margin-bottom: -8px;
margin-top: 8px;
border-right-color: hsla(210, 19%, 63%, .5);
border-top-color: hsla(210, 19%, 63%, .5);
background-image: -moz-linear-gradient(bottom left, transparent 50%, hsl(209, 18%, 30%) 50%);
}
#highlighter-nodeinfobar-arrow-bottom {
margin-top: -8px;
margin-bottom: 8px;
border-left-color: hsla(210, 19%, 63%, .5);
border-bottom-color: hsla(210, 19%, 63%, .5);
background-image: -moz-linear-gradient(top right, transparent 50%, hsl(210, 24%, 16%) 50%);
}
#highlighter-nodeinfobar-container[position="top"] > #highlighter-nodeinfobar,
#highlighter-nodeinfobar-container[position="overlap"] > #highlighter-nodeinfobar {
box-shadow: 0 1px 0 hsla(0, 0%, 100%, .1) inset;
}
#highlighter-nodeinfobar-container[hide-arrow] > #highlighter-nodeinfobar {
margin: 7px 0;
}