Bug 1249558 - Part 2: Display the grid info bar for a grid area highlight r=pbro

This commit is contained in:
Gabriel Luong 2016-09-07 15:41:51 -04:00
Родитель f4feee83f8
Коммит d0fec9eaf3
10 изменённых файлов: 282 добавлений и 131 удалений

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

@ -19,12 +19,12 @@ const ELEMENTS = ["box-model-root",
"box-model-guide-right",
"box-model-guide-bottom",
"box-model-guide-left",
"box-model-nodeinfobar-container",
"box-model-nodeinfobar-tagname",
"box-model-nodeinfobar-id",
"box-model-nodeinfobar-classes",
"box-model-nodeinfobar-pseudo-classes",
"box-model-nodeinfobar-dimensions"];
"box-model-infobar-container",
"box-model-infobar-tagname",
"box-model-infobar-id",
"box-model-infobar-classes",
"box-model-infobar-pseudo-classes",
"box-model-infobar-dimensions"];
add_task(function* () {
let {inspector, toolbox, testActor} = yield openInspectorForURL(TEST_URL);

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

@ -24,7 +24,7 @@ const TEST_DATA = [
options: {},
checkHighlighter: function* (testActor) {
let hidden = yield testActor.getHighlighterNodeAttribute(
"box-model-nodeinfobar-container", "hidden");
"box-model-infobar-container", "hidden");
ok(!hidden, "Node infobar is visible");
hidden = yield testActor.getHighlighterNodeAttribute(
@ -64,8 +64,8 @@ const TEST_DATA = [
options: {hideInfoBar: true},
checkHighlighter: function* (testActor) {
let hidden = yield testActor.getHighlighterNodeAttribute(
"box-model-nodeinfobar-container", "hidden");
is(hidden, "true", "nodeinfobar has been hidden");
"box-model-infobar-container", "hidden");
is(hidden, "true", "infobar has been hidden");
}
},
{

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

@ -64,26 +64,26 @@ function* testPosition(test, inspector, testActor) {
yield selectAndHighlightNode(test.selector, inspector);
let position = yield testActor.getHighlighterNodeAttribute(
"box-model-nodeinfobar-container", "position");
"box-model-infobar-container", "position");
is(position, test.position, "Node " + test.selector + ": position matches");
let tag = yield testActor.getHighlighterNodeTextContent(
"box-model-nodeinfobar-tagname");
"box-model-infobar-tagname");
is(tag, test.tag, "node " + test.selector + ": tagName matches.");
if (test.id) {
let id = yield testActor.getHighlighterNodeTextContent(
"box-model-nodeinfobar-id");
"box-model-infobar-id");
is(id, "#" + test.id, "node " + test.selector + ": id matches.");
}
let classes = yield testActor.getHighlighterNodeTextContent(
"box-model-nodeinfobar-classes");
"box-model-infobar-classes");
is(classes, test.classes, "node " + test.selector + ": classes match.");
if (test.dims) {
let dims = yield testActor.getHighlighterNodeTextContent(
"box-model-nodeinfobar-dimensions");
"box-model-infobar-dimensions");
is(dims, test.dims, "node " + test.selector + ": dims match.");
}
}

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

@ -45,6 +45,6 @@ function* testNode(test, inspector, testActor) {
yield selectAndHighlightNode(test.selector, inspector);
let tag = yield testActor.getHighlighterNodeTextContent(
"box-model-nodeinfobar-tagname");
"box-model-infobar-tagname");
is(tag, test.tag, "node " + test.selector + ": tagName matches.");
}

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

@ -26,7 +26,7 @@ function* testPositionAndStyle(test, inspector, testActor) {
yield selectAndHighlightNode(test.selector, inspector);
let style = yield testActor.getHighlighterNodeAttribute(
"box-model-nodeinfobar-container", "style");
"box-model-infobar-container", "style");
is(style.split(";")[0], test.style,
"Infobar shows on top of the page when page isn't scrolled");
@ -34,7 +34,7 @@ function* testPositionAndStyle(test, inspector, testActor) {
yield testActor.scrollWindow(0, 500);
style = yield testActor.getHighlighterNodeAttribute(
"box-model-nodeinfobar-container", "style");
"box-model-infobar-container", "style");
is(style.split(";")[0], test.style,
"Infobar shows on top of the page even if the page is scrolled");

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

@ -117,7 +117,7 @@ function* assertPseudoAddedToNode(inspector, testActor, ruleview) {
info("Check that the infobar selector contains the pseudo-class");
let value = yield testActor.getHighlighterNodeTextContent(
"box-model-nodeinfobar-pseudo-classes");
"box-model-infobar-pseudo-classes");
is(value, PSEUDO, "pseudo-class in infobar selector");
yield inspector.toolbox.highlighter.hideBoxModel();
}
@ -143,7 +143,7 @@ function* assertPseudoRemovedFromView(inspector, testActor, ruleview) {
yield showPickerOn("#div-1", inspector);
let value = yield testActor.getHighlighterNodeTextContent(
"box-model-nodeinfobar-pseudo-classes");
"box-model-infobar-pseudo-classes");
is(value, "", "pseudo-class removed from infobar selector");
yield inspector.toolbox.highlighter.hideBoxModel();
}

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

@ -99,9 +99,9 @@
shape-rendering: crispEdges;
}
/* Highlighter - Node Infobar */
/* Highlighter - Infobar */
:-moz-native-anonymous .box-model-nodeinfobar-container {
:-moz-native-anonymous [class$=infobar-container] {
position: absolute;
max-width: 95%;
@ -109,10 +109,10 @@
font-size: 11px;
}
:-moz-native-anonymous .box-model-nodeinfobar {
:-moz-native-anonymous [class$=infobar] {
position: relative;
/* Centering the nodeinfobar in the container */
/* Centering the infobar in the container */
left: -50%;
padding: 5px;
@ -127,24 +127,24 @@
border: 1px solid var(--highlighter-bubble-border-color);
}
:-moz-native-anonymous .box-model-nodeinfobar-container[hide-arrow] > .box-model-nodeinfobar {
:-moz-native-anonymous [class$=infobar-container][hide-arrow] > [class$=infobar] {
margin: 7px 0;
}
/* Arrows */
:-moz-native-anonymous .box-model-nodeinfobar-container > .box-model-nodeinfobar:before {
:-moz-native-anonymous [class$=infobar-container] > [class$=infobar]:before {
left: calc(50% - 8px);
border: 8px solid var(--highlighter-bubble-border-color);
}
:-moz-native-anonymous .box-model-nodeinfobar-container > .box-model-nodeinfobar:after {
:-moz-native-anonymous [class$=infobar-container] > [class$=infobar]:after {
left: calc(50% - 7px);
border: 7px solid var(--highlighter-bubble-background-color);
}
:-moz-native-anonymous .box-model-nodeinfobar-container > .box-model-nodeinfobar:before,
:-moz-native-anonymous .box-model-nodeinfobar-container > .box-model-nodeinfobar:after {
:-moz-native-anonymous [class$=infobar-container] > [class$=infobar]:before,
:-moz-native-anonymous [class$=infobar-container] > [class$=infobar]:after {
content: "";
display: none;
position: absolute;
@ -154,23 +154,23 @@
border-right-color: transparent;
}
:-moz-native-anonymous .box-model-nodeinfobar-container[position="top"]:not([hide-arrow]) > .box-model-nodeinfobar:before,
:-moz-native-anonymous .box-model-nodeinfobar-container[position="top"]:not([hide-arrow]) > .box-model-nodeinfobar:after {
:-moz-native-anonymous [class$=infobar-container][position="top"]:not([hide-arrow]) > [class$=infobar]:before,
:-moz-native-anonymous [class$=infobar-container][position="top"]:not([hide-arrow]) > [class$=infobar]:after {
border-bottom: 0;
top: 100%;
display: block;
}
:-moz-native-anonymous .box-model-nodeinfobar-container[position="bottom"]:not([hide-arrow]) > .box-model-nodeinfobar:before,
:-moz-native-anonymous .box-model-nodeinfobar-container[position="bottom"]:not([hide-arrow]) > .box-model-nodeinfobar:after {
:-moz-native-anonymous [class$=infobar-container][position="bottom"]:not([hide-arrow]) > [class$=infobar]:before,
:-moz-native-anonymous [class$=infobar-container][position="bottom"]:not([hide-arrow]) > [class$=infobar]:after {
border-top: 0;
bottom: 100%;
display: block;
}
/* Text container */
/* Text Container */
:-moz-native-anonymous .box-model-nodeinfobar-text {
:-moz-native-anonymous [class$=infobar-text] {
overflow: hidden;
white-space: nowrap;
direction: ltr;
@ -178,24 +178,24 @@
display: flex;
}
:-moz-native-anonymous .box-model-nodeinfobar-tagname {
:-moz-native-anonymous .box-model-infobar-tagname {
color: hsl(285,100%, 75%);
}
:-moz-native-anonymous .box-model-nodeinfobar-id {
:-moz-native-anonymous .box-model-infobar-id {
color: hsl(103, 46%, 54%);
overflow: hidden;
text-overflow: ellipsis;
}
:-moz-native-anonymous .box-model-nodeinfobar-classes,
:-moz-native-anonymous .box-model-nodeinfobar-pseudo-classes {
:-moz-native-anonymous .box-model-infobar-classes,
:-moz-native-anonymous .box-model-infobar-pseudo-classes {
color: hsl(200, 74%, 57%);
overflow: hidden;
text-overflow: ellipsis;
}
:-moz-native-anonymous .box-model-nodeinfobar-dimensions {
:-moz-native-anonymous [class$=infobar-dimensions] {
color: hsl(210, 30%, 85%);
border-inline-start: 1px solid #5a6169;
margin-inline-start: 6px;
@ -221,6 +221,10 @@
stroke: none;
}
:-moz-native-anonymous .css-grid-infobar-areaname {
color: hsl(285,100%, 75%);
}
/* CSS Transform Highlighter */
:-moz-native-anonymous .css-transform-transformed {

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

@ -7,11 +7,10 @@
const { extend } = require("sdk/core/heritage");
const { AutoRefreshHighlighter } = require("./auto-refresh");
const {
CanvasFrameAnonymousContentHelper,
CanvasFrameAnonymousContentHelper, moveInfobar,
getBindingElementAndPseudo, hasPseudoClassLock, getComputedStyle,
createSVGNode, createNode, isNodeValid } = require("./utils/markup");
const { getCurrentZoom,
setIgnoreLayoutChanges } = require("devtools/shared/layout/utils");
const { setIgnoreLayoutChanges } = require("devtools/shared/layout/utils");
const inspector = require("devtools/server/actors/inspector");
// Note that the order of items in this array is important because it is used
@ -20,10 +19,6 @@ const BOX_MODEL_REGIONS = ["margin", "border", "padding", "content"];
const BOX_MODEL_SIDES = ["top", "right", "bottom", "left"];
// Width of boxmodelhighlighter guides
const GUIDE_STROKE_WIDTH = 1;
// How high is the nodeinfobar (px).
const NODE_INFOBAR_HEIGHT = 34;
// What's the size of the nodeinfobar arrow (px).
const NODE_INFOBAR_ARROW_SIZE = 9;
// FIXME: add ":visited" and ":link" after bug 713106 is fixed
const PSEUDO_CLASSES = [":hover", ":active", ":focus"];
@ -73,17 +68,17 @@ const PSEUDO_CLASSES = [":hover", ":active", ":focus"];
* <line class="box-model-guide-bottom" x1="..." y1="..." x2="..." y2="..." />
* <line class="box-model-guide-left" x1="..." y1="..." x2="..." y2="..." />
* </svg>
* <div class="box-model-nodeinfobar-container">
* <div class="box-model-nodeinfobar-arrow highlighter-nodeinfobar-arrow-top" />
* <div class="box-model-nodeinfobar">
* <div class="box-model-nodeinfobar-text" align="center">
* <span class="box-model-nodeinfobar-tagname">Node name</span>
* <span class="box-model-nodeinfobar-id">Node id</span>
* <span class="box-model-nodeinfobar-classes">.someClass</span>
* <span class="box-model-nodeinfobar-pseudo-classes">:hover</span>
* <div class="box-model-infobar-container">
* <div class="box-model-infobar-arrow highlighter-infobar-arrow-top" />
* <div class="box-model-infobar">
* <div class="box-model-infobar-text" align="center">
* <span class="box-model-infobar-tagname">Node name</span>
* <span class="box-model-infobar-id">Node id</span>
* <span class="box-model-infobar-classes">.someClass</span>
* <span class="box-model-infobar-pseudo-classes">:hover</span>
* </div>
* </div>
* <div class="box-model-nodeinfobar-arrow box-model-nodeinfobar-arrow-bottom"/>
* <div class="box-model-infobar-arrow box-model-infobar-arrow-bottom"/>
* </div>
* </div>
* </div>
@ -186,26 +181,26 @@ BoxModelHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
let infobarContainer = createNode(this.win, {
parent: rootWrapper,
attributes: {
"class": "nodeinfobar-container",
"id": "nodeinfobar-container",
"class": "infobar-container",
"id": "infobar-container",
"position": "top",
"hidden": "true"
},
prefix: this.ID_CLASS_PREFIX
});
let nodeInfobar = createNode(this.win, {
let infobar = createNode(this.win, {
parent: infobarContainer,
attributes: {
"class": "nodeinfobar"
"class": "infobar"
},
prefix: this.ID_CLASS_PREFIX
});
let texthbox = createNode(this.win, {
parent: nodeInfobar,
parent: infobar,
attributes: {
"class": "nodeinfobar-text"
"class": "infobar-text"
},
prefix: this.ID_CLASS_PREFIX
});
@ -213,8 +208,8 @@ BoxModelHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
nodeType: "span",
parent: texthbox,
attributes: {
"class": "nodeinfobar-tagname",
"id": "nodeinfobar-tagname"
"class": "infobar-tagname",
"id": "infobar-tagname"
},
prefix: this.ID_CLASS_PREFIX
});
@ -222,8 +217,8 @@ BoxModelHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
nodeType: "span",
parent: texthbox,
attributes: {
"class": "nodeinfobar-id",
"id": "nodeinfobar-id"
"class": "infobar-id",
"id": "infobar-id"
},
prefix: this.ID_CLASS_PREFIX
});
@ -231,8 +226,8 @@ BoxModelHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
nodeType: "span",
parent: texthbox,
attributes: {
"class": "nodeinfobar-classes",
"id": "nodeinfobar-classes"
"class": "infobar-classes",
"id": "infobar-classes"
},
prefix: this.ID_CLASS_PREFIX
});
@ -240,8 +235,8 @@ BoxModelHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
nodeType: "span",
parent: texthbox,
attributes: {
"class": "nodeinfobar-pseudo-classes",
"id": "nodeinfobar-pseudo-classes"
"class": "infobar-pseudo-classes",
"id": "infobar-pseudo-classes"
},
prefix: this.ID_CLASS_PREFIX
});
@ -249,8 +244,8 @@ BoxModelHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
nodeType: "span",
parent: texthbox,
attributes: {
"class": "nodeinfobar-dimensions",
"id": "nodeinfobar-dimensions"
"class": "infobar-dimensions",
"id": "infobar-dimensions"
},
prefix: this.ID_CLASS_PREFIX
});
@ -350,14 +345,14 @@ BoxModelHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
* Hide the infobar
*/
_hideInfobar: function () {
this.getElement("nodeinfobar-container").setAttribute("hidden", "true");
this.getElement("infobar-container").setAttribute("hidden", "true");
},
/**
* Show the infobar
*/
_showInfobar: function () {
this.getElement("nodeinfobar-container").removeAttribute("hidden");
this.getElement("infobar-container").removeAttribute("hidden");
this._updateInfobar();
},
@ -379,7 +374,7 @@ BoxModelHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
* Calculate an outer quad based on the quads returned by getAdjustedQuads.
* The BoxModelHighlighter may highlight more than one boxes, so in this case
* create a new quad that "contains" all of these quads.
* This is useful to position the guides and nodeinfobar.
* This is useful to position the guides and infobar.
* This may happen if the BoxModelHighlighter is used to highlight an inline
* element that spans line breaks.
* @param {String} region The box-model region to get the outer quad for.
@ -676,11 +671,11 @@ BoxModelHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
" \u00D7 " +
parseFloat(rect.height.toPrecision(6));
this.getElement("nodeinfobar-tagname").setTextContent(displayName);
this.getElement("nodeinfobar-id").setTextContent(id);
this.getElement("nodeinfobar-classes").setTextContent(classList);
this.getElement("nodeinfobar-pseudo-classes").setTextContent(pseudos);
this.getElement("nodeinfobar-dimensions").setTextContent(dim);
this.getElement("infobar-tagname").setTextContent(displayName);
this.getElement("infobar-id").setTextContent(id);
this.getElement("infobar-classes").setTextContent(classList);
this.getElement("infobar-pseudo-classes").setTextContent(pseudos);
this.getElement("infobar-dimensions").setTextContent(dim);
this._moveInfobar();
},
@ -690,57 +685,9 @@ BoxModelHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
*/
_moveInfobar: function () {
let bounds = this._getOuterBounds();
let winHeight = this.win.innerHeight * getCurrentZoom(this.win);
let winWidth = this.win.innerWidth * getCurrentZoom(this.win);
let winScrollY = this.win.scrollY;
let container = this.getElement("infobar-container");
// Ensure that containerBottom and containerTop are at least zero to avoid
// showing tooltips outside the viewport.
let containerBottom = Math.max(0, bounds.bottom) + NODE_INFOBAR_ARROW_SIZE;
let containerTop = Math.min(winHeight, bounds.top);
let container = this.getElement("nodeinfobar-container");
// Can the bar be above the node?
let top;
if (containerTop < NODE_INFOBAR_HEIGHT) {
// No. Can we move the bar under the node?
if (containerBottom + NODE_INFOBAR_HEIGHT > winHeight) {
// No. Let's move it inside. Can we show it at the top of the element?
if (containerTop < winScrollY) {
// No. Window is scrolled past the top of the element.
top = 0;
} else {
// Yes. Show it at the top of the element
top = containerTop;
}
container.setAttribute("position", "overlap");
} else {
// Yes. Let's move it under the node.
top = containerBottom;
container.setAttribute("position", "bottom");
}
} else {
// Yes. Let's move it on top of the node.
top = containerTop - NODE_INFOBAR_HEIGHT;
container.setAttribute("position", "top");
}
// Align the bar with the box's center if possible.
let left = bounds.right - bounds.width / 2;
// Make sure the while infobar is visible.
let buffer = 100;
if (left < buffer) {
left = buffer;
container.setAttribute("hide-arrow", "true");
} else if (left > winWidth - buffer) {
left = winWidth - buffer;
container.setAttribute("hide-arrow", "true");
} else {
container.removeAttribute("hide-arrow");
}
let style = "top:" + top + "px;left:" + left + "px;";
container.setAttribute("style", style);
moveInfobar(container, bounds, this.win);
}
});
exports.BoxModelHighlighter = BoxModelHighlighter;

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

@ -9,7 +9,8 @@ const { AutoRefreshHighlighter } = require("./auto-refresh");
const {
CanvasFrameAnonymousContentHelper,
createNode,
createSVGNode
createSVGNode,
moveInfobar,
} = require("./utils/markup");
const {
getCurrentZoom,
@ -66,6 +67,14 @@ const GRID_LINES_PROPERTIES = {
* <path class="css-grid-areas" points="..." />
* </g>
* </svg>
* <div class="css-grid-infobar-container">
* <div class="css-grid-infobar">
* <div class="css-grid-infobar-text">
* <span class="css-grid-infobar-areaname">Grid Area Name</span>
* <span class="css-grid-infobar-dimensions"Grid Area Dimensions></span>
* </div>
* </div>
* </div>
* </div>
*/
function CssGridHighlighter(highlighterEnv) {
@ -133,6 +142,52 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
prefix: this.ID_CLASS_PREFIX
});
// Building the grid infobar markup
let infobarContainer = createNode(this.win, {
parent: container,
attributes: {
"class": "infobar-container",
"id": "infobar-container",
"position": "top",
"hidden": "true"
},
prefix: this.ID_CLASS_PREFIX
});
let infobar = createNode(this.win, {
parent: infobarContainer,
attributes: {
"class": "infobar"
},
prefix: this.ID_CLASS_PREFIX
});
let textbox = createNode(this.win, {
parent: infobar,
attributes: {
"class": "infobar-text"
},
prefix: this.ID_CLASS_PREFIX
});
createNode(this.win, {
nodeType: "span",
parent: textbox,
attributes: {
"class": "infobar-areaname",
"id": "infobar-areaname"
},
prefix: this.ID_CLASS_PREFIX
});
createNode(this.win, {
nodeType: "span",
parent: textbox,
attributes: {
"class": "infobar-dimensions",
"id": "infobar-dimensions"
},
prefix: this.ID_CLASS_PREFIX
});
return container;
},
@ -246,6 +301,61 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
return true;
},
/**
* Update the grid information displayed in the grid info bar.
*
* @param {GridArea} area
* The grid area object.
* @param {Number} x1
* The first x-coordinate of the grid area rectangle.
* @param {Number} x2
* The second x-coordinate of the grid area rectangle.
* @param {Number} y1
* The first y-coordinate of the grid area rectangle.
* @param {Number} y2
* The second y-coordinate of the grid area rectangle.
*/
_updateInfobar(area, x1, x2, y1, y2) {
let width = x2 - x1;
let height = y2 - y1;
let dim = parseFloat(width.toPrecision(6)) +
" \u00D7 " +
parseFloat(height.toPrecision(6));
this.getElement("infobar-areaname").setTextContent(area.name);
this.getElement("infobar-dimensions").setTextContent(dim);
this._moveInfobar(x1, x2, y1, y2);
},
/**
* Move the grid infobar to the right place in the highlighter.
*
* @param {Number} x1
* The first x-coordinate of the grid area rectangle.
* @param {Number} x2
* The second x-coordinate of the grid area rectangle.
* @param {Number} y1
* The first y-coordinate of the grid area rectangle.
* @param {Number} y2
* The second y-coordinate of the grid area rectangle.
*/
_moveInfobar(x1, x2, y1, y2) {
let bounds = {
bottom: y2,
height: y2 - y1,
left: x1,
right: x2,
top: y1,
width: x2 - x1,
x: x1,
y: y1,
};
let container = this.getElement("infobar-container");
moveInfobar(container, bounds, this.win);
},
clearCanvas() {
let ratio = parseFloat((this.win.devicePixelRatio || 1).toFixed(2));
let width = this.win.innerWidth;
@ -457,6 +567,12 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
"L" + x2 + "," + y2 + " " +
"L" + x1 + "," + y2;
paths.push(path);
// Update and show the info bar when only displaying a single grid area.
if (!renderAllGridAreas) {
this._updateInfobar(area, x1, x2, y1, y2);
this._showInfoBar();
}
}
}
@ -465,12 +581,13 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
},
/**
* Hide the highlighter and the canvas.
* Hide the highlighter, the canvas and the infobar.
*/
_hide() {
setIgnoreLayoutChanges(true);
this._hideGrid();
this._hideGridArea();
this._hideInfoBar();
setIgnoreLayoutChanges(false, this.currentNode.ownerDocument.documentElement);
},
@ -490,6 +607,14 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
this.getElement("elements").removeAttribute("hidden");
},
_hideInfoBar() {
this.getElement("infobar-container").setAttribute("hidden", "true");
},
_showInfoBar() {
this.getElement("infobar-container").removeAttribute("hidden");
},
});
exports.CssGridHighlighter = CssGridHighlighter;

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

@ -37,6 +37,10 @@ const SVG_NS = "http://www.w3.org/2000/svg";
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const STYLESHEET_URI = "resource://devtools/server/actors/" +
"highlighters.css";
// How high is the infobar (px).
const INFOBAR_HEIGHT = 34;
// What's the size of the infobar arrow (px).
const INFOBAR_ARROW_SIZE = 9;
const _tokens = Symbol("classList/tokens");
@ -517,3 +521,74 @@ CanvasFrameAnonymousContentHelper.prototype = {
}
};
exports.CanvasFrameAnonymousContentHelper = CanvasFrameAnonymousContentHelper;
/**
* Move the infobar to the right place in the highlighter. This helper method is utilized
* in both css-grid.js and box-model.js to help position the infobar in an appropriate
* space over the highlighted node element or grid area. The infobar is used to display
* relevant information about the highlighted item (ex, node or grid name and dimensions).
*
* This method will first try to position the infobar to top or bottom of the container
* such that it has enough space for the height of the infobar. Afterwards, it will try
* to horizontally center align with the container element if possible.
*
* @param {DOMNode} container
* The container element which will be used to position the infobar.
* @param {Object} bounds
* The content bounds of the container element.
* @param {Window} win
* The window object.
*/
function moveInfobar(container, bounds, win) {
let winHeight = win.innerHeight * getCurrentZoom(win);
let winWidth = win.innerWidth * getCurrentZoom(win);
let winScrollY = win.scrollY;
// Ensure that containerBottom and containerTop are at least zero to avoid
// showing tooltips outside the viewport.
let containerBottom = Math.max(0, bounds.bottom) + INFOBAR_ARROW_SIZE;
let containerTop = Math.min(winHeight, bounds.top);
// Can the bar be above the node?
let top;
if (containerTop < INFOBAR_HEIGHT) {
// No. Can we move the bar under the node?
if (containerBottom + INFOBAR_HEIGHT > winHeight) {
// No. Let's move it inside. Can we show it at the top of the element?
if (containerTop < winScrollY) {
// No. Window is scrolled past the top of the element.
top = 0;
} else {
// Yes. Show it at the top of the element
top = containerTop;
}
container.setAttribute("position", "overlap");
} else {
// Yes. Let's move it under the node.
top = containerBottom;
container.setAttribute("position", "bottom");
}
} else {
// Yes. Let's move it on top of the node.
top = containerTop - INFOBAR_HEIGHT;
container.setAttribute("position", "top");
}
// Align the bar with the box's center if possible.
let left = bounds.right - bounds.width / 2;
// Make sure the while infobar is visible.
let buffer = 100;
if (left < buffer) {
left = buffer;
container.setAttribute("hide-arrow", "true");
} else if (left > winWidth - buffer) {
left = winWidth - buffer;
container.setAttribute("hide-arrow", "true");
} else {
container.removeAttribute("hide-arrow");
}
let style = "top:" + top + "px;left:" + left + "px;";
container.setAttribute("style", style);
}
exports.moveInfobar = moveInfobar;