Bug 940275 - Part 1: Add positioning properties to box model r?gl draft
authorStanford Lockhart <lockhart@cs.dal.ca>
Tue, 28 Feb 2017 18:18:28 -0400
changeset 498323 d2f402ae804cf4f952734887a6d4d2d4f052a9f0
parent 490623 2639190c0e56b8fccf14b9132a9dd48a240ae136
child 498324 9faec0407e18f5ffd8b4a4691f3fd86755873209
push id49143
push userbmo:lockhart@cs.dal.ca
push dateTue, 14 Mar 2017 14:49:09 +0000
reviewersgl
bugs940275
milestone54.0a1
Bug 940275 - Part 1: Add positioning properties to box model r?gl MozReview-Commit-ID: AB5fREjDhsD
devtools/client/inspector/boxmodel/box-model.js
devtools/client/inspector/boxmodel/components/BoxModelMain.js
devtools/client/locales/en-US/boxmodel.properties
devtools/client/themes/boxmodel.css
devtools/client/themes/layout.css
devtools/server/actors/styles.js
--- a/devtools/client/inspector/boxmodel/box-model.js
+++ b/devtools/client/inspector/boxmodel/box-model.js
@@ -235,16 +235,20 @@ BoxModel.prototype = {
         if (property.substring(0, 7) == "border-") {
           let bprop = property.substring(0, property.length - 5) + "style";
           let style = session.getProperty(bprop);
           if (!style || style == "none" || style == "hidden") {
             properties.push({ name: bprop, value: "solid" });
           }
         }
 
+        if (property.substring(0, 9) == "position-") {
+          properties[0].name = property.substring(9);
+        }
+
         session.setProperties(properties).catch(e => console.error(e));
       },
       done: (value, commit) => {
         editor.elt.parentNode.classList.remove("boxmodel-editing");
         if (!commit) {
           session.revert().then(() => {
             session.destroy();
           }, e => console.error(e));
--- a/devtools/client/inspector/boxmodel/components/BoxModelMain.js
+++ b/devtools/client/inspector/boxmodel/components/BoxModelMain.js
@@ -78,108 +78,179 @@ module.exports = createClass({
       value = "auto";
     } else if (layout[property]) {
       value = parseFloat(layout[property]);
     }
 
     return value;
   },
 
+  getPositionValue(property) {
+    let { layout } = this.props.boxModel;
+
+    if (layout.position === "static") {
+      return "-";
+    }
+    return layout[property] ? parseFloat(layout[property]) : "-";
+  },
+
   onHighlightMouseOver(event) {
     let region = event.target.getAttribute("data-box");
     if (!region) {
       this.props.onHideBoxModelHighlighter();
     }
 
     this.props.onShowBoxModelHighlighter({
       region,
       showOnly: region,
       onlyRegionArea: true,
     });
   },
 
   render() {
     let { boxModel, onShowBoxModelEditor } = this.props;
     let { layout } = boxModel;
-    let { height, width } = layout;
+    let { height, width, position } = layout;
 
     let borderTop = this.getBorderOrPaddingValue("border-top-width");
     let borderRight = this.getBorderOrPaddingValue("border-right-width");
     let borderBottom = this.getBorderOrPaddingValue("border-bottom-width");
     let borderLeft = this.getBorderOrPaddingValue("border-left-width");
 
     let paddingTop = this.getBorderOrPaddingValue("padding-top");
     let paddingRight = this.getBorderOrPaddingValue("padding-right");
     let paddingBottom = this.getBorderOrPaddingValue("padding-bottom");
     let paddingLeft = this.getBorderOrPaddingValue("padding-left");
 
+    let displayPosition = layout.position && layout.position != "static";
+    let positionTop = this.getPositionValue("top");
+    let positionRight = this.getPositionValue("right");
+    let positionBottom = this.getPositionValue("bottom");
+    let positionLeft = this.getPositionValue("left");
+
     let marginTop = this.getMarginValue("margin-top", "top");
     let marginRight = this.getMarginValue("margin-right", "right");
     let marginBottom = this.getMarginValue("margin-bottom", "bottom");
     let marginLeft = this.getMarginValue("margin-left", "left");
 
     height = this.getHeightValue(height);
     width = this.getWidthValue(width);
 
     return dom.div(
       {
         className: "boxmodel-main",
         onMouseOver: this.onHighlightMouseOver,
         onMouseOut: this.props.onHideBoxModelHighlighter,
       },
-      dom.span(
-        {
-          className: "boxmodel-legend",
-          "data-box": "margin",
-          title: BOXMODEL_L10N.getStr("boxmodel.margin"),
-        },
-        BOXMODEL_L10N.getStr("boxmodel.margin")
-      ),
+      displayPosition ?
+        dom.span(
+          {
+            className: "boxmodel-legend",
+            "data-box": "position",
+            title: BOXMODEL_L10N.getFormatStr("boxmodel.position", position),
+          },
+          BOXMODEL_L10N.getFormatStr("boxmodel.position", position)
+        )
+        :
+        null,
       dom.div(
         {
-          className: "boxmodel-margins",
-          "data-box": "margin",
-          title: BOXMODEL_L10N.getStr("boxmodel.margin"),
+          className: "boxmodel-box"
         },
         dom.span(
           {
             className: "boxmodel-legend",
-            "data-box": "border",
-            title: BOXMODEL_L10N.getStr("boxmodel.border"),
+            "data-box": "margin",
+            title: BOXMODEL_L10N.getStr("boxmodel.margin"),
           },
-          BOXMODEL_L10N.getStr("boxmodel.border")
+          BOXMODEL_L10N.getStr("boxmodel.margin")
         ),
         dom.div(
           {
-            className: "boxmodel-borders",
-            "data-box": "border",
-            title: BOXMODEL_L10N.getStr("boxmodel.border"),
+            className: "boxmodel-margins",
+            "data-box": "margin",
+            title: BOXMODEL_L10N.getStr("boxmodel.margin"),
           },
           dom.span(
             {
               className: "boxmodel-legend",
-              "data-box": "padding",
-              title: BOXMODEL_L10N.getStr("boxmodel.padding"),
+              "data-box": "border",
+              title: BOXMODEL_L10N.getStr("boxmodel.border"),
             },
-            BOXMODEL_L10N.getStr("boxmodel.padding")
+            BOXMODEL_L10N.getStr("boxmodel.border")
           ),
           dom.div(
             {
-              className: "boxmodel-paddings",
-              "data-box": "padding",
-              title: BOXMODEL_L10N.getStr("boxmodel.padding"),
+              className: "boxmodel-borders",
+              "data-box": "border",
+              title: BOXMODEL_L10N.getStr("boxmodel.border"),
             },
-            dom.div({
-              className: "boxmodel-content",
-              "data-box": "content",
-              title: BOXMODEL_L10N.getStr("boxmodel.content"),
-            })
+            dom.span(
+              {
+                className: "boxmodel-legend",
+                "data-box": "padding",
+                title: BOXMODEL_L10N.getStr("boxmodel.padding"),
+              },
+              BOXMODEL_L10N.getStr("boxmodel.padding")
+            ),
+            dom.div(
+              {
+                className: "boxmodel-paddings",
+                "data-box": "padding",
+                title: BOXMODEL_L10N.getStr("boxmodel.padding"),
+              },
+              dom.div({
+                className: "boxmodel-content",
+                "data-box": "content",
+                title: BOXMODEL_L10N.getStr("boxmodel.content"),
+              })
+            )
           )
         )
       ),
+      displayPosition ?
+        BoxModelEditable({
+          box: "position",
+          direction: "top",
+          property: "position-top",
+          textContent: positionTop,
+          onShowBoxModelEditor,
+        })
+        :
+        null,
+      displayPosition ?
+        BoxModelEditable({
+          box: "position",
+          direction: "right",
+          property: "position-right",
+          textContent: positionRight,
+          onShowBoxModelEditor,
+        })
+        :
+        null,
+      displayPosition ?
+        BoxModelEditable({
+          box: "position",
+          direction: "bottom",
+          property: "position-bottom",
+          textContent: positionBottom,
+          onShowBoxModelEditor,
+        })
+        :
+        null,
+      displayPosition ?
+        BoxModelEditable({
+          box: "position",
+          direction: "left",
+          property: "position-left",
+          textContent: positionLeft,
+          onShowBoxModelEditor,
+        })
+        :
+        null,
       BoxModelEditable({
         box: "margin",
         direction: "top",
         property: "margin-top",
         textContent: marginTop,
         onShowBoxModelEditor,
       }),
       BoxModelEditable({
--- a/devtools/client/locales/en-US/boxmodel.properties
+++ b/devtools/client/locales/en-US/boxmodel.properties
@@ -10,16 +10,20 @@
 # You want to make that choice consistent across the developer tools.
 # A good criteria is the language in which you'd find the best
 # documentation on web development on the web.
 
 # LOCALIZATION NOTE (boxmodel.title) This is the title of the box model panel and is
 # displayed as a label.
 boxmodel.title=Box Model
 
+# LOCALIZATION NOTE (boxmodel.position) This refers to the position in the box model and
+# might be displayed as a label or as a tooltip.
+boxmodel.position=position: %S
+
 # LOCALIZATION NOTE (boxmodel.margin) This refers to the margin in the box model and
 # might be displayed as a label or as a tooltip.
 boxmodel.margin=margin
 
 # LOCALIZATION NOTE (boxmodel.border) This refers to the border in the box model and
 # might be displayed as a label or as a tooltip.
 boxmodel.border=border
 
--- a/devtools/client/themes/boxmodel.css
+++ b/devtools/client/themes/boxmodel.css
@@ -30,25 +30,29 @@
   background: url(images/geometry-editor.svg) no-repeat center center / 16px 16px;
 }
 
 /* Main: contains the box-model regions */
 
 .boxmodel-main {
   position: relative;
   box-sizing: border-box;
-  /* The regions are semi-transparent, so the white background is partly
-     visible */
-  background-color: white;
   color: var(--theme-selection-color);
   /* Make sure there is some space between the window's edges and the regions */
   margin: 14px 14px 4px 14px;
   width: calc(100% - 2 * 14px);
 }
 
+.boxmodel-box {
+  margin: 0 25px;
+  /* The regions are semi-transparent, so the white background is partly
+     visible */
+  background-color: white;
+}
+
 .boxmodel-margin,
 .boxmodel-size {
   color: var(--theme-highlight-blue);
 }
 
 /* Regions are 3 nested elements with wide borders and outlines */
 
 .boxmodel-content {
@@ -68,37 +72,32 @@
   /* This opacity applies to all of the regions, since they are nested */
   opacity: .8;
 }
 
 /* Regions colors */
 
 .boxmodel-margins {
   border-color: #edff64;
+  margin: 25px 0;
 }
 
 .boxmodel-borders {
   border-color: #444444;
 }
 
 .boxmodel-paddings {
   border-color: #6a5acd;
 }
 
 .boxmodel-content {
   background-color: #87ceeb;
 }
 
 .theme-firebug .boxmodel-main,
-.theme-firebug .boxmodel-borders,
-.theme-firebug .boxmodel-content {
-  border-style: solid;
-}
-
-.theme-firebug .boxmodel-main,
 .theme-firebug .boxmodel-header {
   font-family: var(--proportional-font-family);
 }
 
 .theme-firebug .boxmodel-main {
   color: var(--theme-body-color);
   font-size: var(--theme-toolbar-font-size);
 }
@@ -150,81 +149,147 @@
   top: 1px;
 }
 
 .boxmodel-margin.boxmodel-bottom {
   bottom: 2px;
 }
 
 .boxmodel-size,
+.boxmodel-position.boxmodel-left,
+.boxmodel-position.boxmodel-right,
 .boxmodel-margin.boxmodel-left,
 .boxmodel-margin.boxmodel-right,
 .boxmodel-border.boxmodel-left,
 .boxmodel-border.boxmodel-right,
 .boxmodel-padding.boxmodel-left,
 .boxmodel-padding.boxmodel-right {
   top: 22px;
   line-height: 80px;
 }
 
 .boxmodel-size {
   width: calc(100% - 2px);
 }
 
+.boxmodel-position.boxmodel-top,
+.boxmodel-position.boxmodel-bottom,
+.boxmodel-position.boxmodel-left,
+.boxmodel-position.boxmodel-right,
 .boxmodel-margin.boxmodel-right,
 .boxmodel-margin.boxmodel-left,
 .boxmodel-border.boxmodel-left,
 .boxmodel-border.boxmodel-right,
 .boxmodel-padding.boxmodel-right,
 .boxmodel-padding.boxmodel-left {
   width: 21px;
 }
 
 .boxmodel-padding.boxmodel-left {
-  left: 35px;
+  left: 60px;
 }
 
 .boxmodel-padding.boxmodel-right {
-  right: 35px;
+  right: 60px;
 }
 
 .boxmodel-border.boxmodel-left {
-  left: 16px;
+  left: 41px;
 }
 
 .boxmodel-border.boxmodel-right {
-  right: 17px;
+  right: 42px;
 }
 
 .boxmodel-margin.boxmodel-right {
-  right: 0;
+  right: 25px;
 }
 
 .boxmodel-margin.boxmodel-left {
-  left: 0;
+  left: 25px;
 }
 
 .boxmodel-rotate.boxmodel-left:not(.boxmodel-editing) {
   transform: rotate(-90deg);
 }
 
 .boxmodel-rotate.boxmodel-right:not(.boxmodel-editing) {
   transform: rotate(90deg);
 }
 
+.boxmodel-rotate.boxmodel-left.boxmodel-position:not(.boxmodel-editing) {
+  border-top: none;
+  border-right: 1px solid var(--theme-highlight-purple);
+  width: auto;
+  height: 30px;
+}
+
+.boxmodel-rotate.boxmodel-right.boxmodel-position:not(.boxmodel-editing) {
+  border-top: none;
+  border-left: 1px solid var(--theme-highlight-purple);
+  width: auto;
+  height: 30px;
+}
+
+/* Box Model Positioning: contains top, right, bottom, left */
+
+.boxmodel-position {
+  color: var(--theme-highlight-purple);
+}
+
+.boxmodel-position.boxmodel-top,
+.boxmodel-position.boxmodel-bottom {
+  border-left: 1px solid var(--theme-highlight-purple);
+  left: 50%;
+  padding-left: 1px;
+}
+
+.boxmodel-position.boxmodel-right,
+.boxmodel-position.boxmodel-left {
+  border-top: 1px solid var(--theme-highlight-purple);
+  line-height: 15px;
+  top: 50%;
+  width: 30px;
+}
+
+.boxmodel-position.boxmodel-top {
+  top: -18px;
+}
+
+.boxmodel-position.boxmodel-right {
+  right: -9px;
+}
+
+.boxmodel-position.boxmodel-bottom {
+  bottom: -18px;
+}
+
+.boxmodel-position.boxmodel-left {
+  left: -9px;
+}
+
 /* Legend: displayed inside regions */
 
 .boxmodel-legend {
   position: absolute;
   margin: 2px 6px;
   z-index: 1;
 }
 
 .boxmodel-legend[data-box="margin"] {
-  color: var(--theme-highlight-blue);
+  color: var(--theme-highlight-purple);
+}
+
+.boxmodel-legend[data-box="position"] {
+  color: var(--theme-highlight-purple);
+  margin: -18px -9px;
+}
+
+.boxmodel-legend .boxmodel-element-position {
+  margin-left: 5px
 }
 
 /* Editable fields */
 
 .boxmodel-editable {
   border: 1px dashed transparent;
   -moz-user-select: none;
 }
@@ -240,21 +305,16 @@
 }
 
 /* Box Model Info: contains the position and size of the element */
 
 .boxmodel-element-size {
   flex: 1;
 }
 
-.boxmodel-position-group {
-  display: flex;
-  align-items: center;
-}
-
 /* Box Model Properties: contains a list of relevant box model properties */
 
 .boxmodel-properties-header {
   display: flex;
   padding: 2px 0;
 }
 
 .boxmodel-properties-wrapper {
--- a/devtools/client/themes/layout.css
+++ b/devtools/client/themes/layout.css
@@ -1,16 +1,17 @@
 /* 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/. */
 
 #layout-container {
   height: 100%;
   width: 100%;
   overflow: auto;
+  min-width: 200px;
 }
 
 /**
  * Common styles for shared components
  */
 
 .grid-container {
   display: flex;
--- a/devtools/server/actors/styles.js
+++ b/devtools/server/actors/styles.js
@@ -766,16 +766,20 @@ var PageStyleActor = protocol.ActorClass
     let clientRect = node.rawNode.getBoundingClientRect();
     layout.width = parseFloat(clientRect.width.toPrecision(6));
     layout.height = parseFloat(clientRect.height.toPrecision(6));
 
     // We compute and update the values of margins & co.
     let style = CssLogic.getComputedStyle(node.rawNode);
     for (let prop of [
       "position",
+      "top",
+      "right",
+      "bottom",
+      "left",
       "margin-top",
       "margin-right",
       "margin-bottom",
       "margin-left",
       "padding-top",
       "padding-right",
       "padding-bottom",
       "padding-left",