Bug 1508394 - Clicking a flex item in the flex item list should scroll the layout pane to the top. r=mtigley
authorGabriel Luong <gabriel.luong@gmail.com>
Wed, 28 Nov 2018 11:25:56 -0500
changeset 505038 25e1436ae7e8d405bde04fd23fba5cc1757d4e67
parent 504953 8d0013f9a06dc1a374e5725876ff24aa880f8978
child 505039 dd6283d8f201df1bd344d05ccc7b6c0c2903826e
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmtigley
bugs1508394
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1508394 - Clicking a flex item in the flex item list should scroll the layout pane to the top. r=mtigley
devtools/client/inspector/flexbox/components/FlexItem.js
devtools/client/inspector/flexbox/components/FlexItemList.js
devtools/client/inspector/flexbox/components/Flexbox.js
devtools/client/inspector/layout/components/LayoutApp.js
--- a/devtools/client/inspector/flexbox/components/FlexItem.js
+++ b/devtools/client/inspector/flexbox/components/FlexItem.js
@@ -17,36 +17,39 @@ const Types = require("../types");
 
 class FlexItem extends PureComponent {
   static get propTypes() {
     return {
       flexItem: PropTypes.shape(Types.flexItem).isRequired,
       index: PropTypes.number.isRequired,
       onHideBoxModelHighlighter: PropTypes.func.isRequired,
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
+      scrollToTop: PropTypes.func.isRequired,
       setSelectedNode: PropTypes.func.isRequired,
     };
   }
 
   render() {
     const {
       flexItem,
       index,
       onHideBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
+      scrollToTop,
       setSelectedNode,
     } = this.props;
     const { nodeFront } = flexItem;
 
     return (
       dom.button(
         {
           className: "devtools-button devtools-monospace",
           onClick: e => {
             e.stopPropagation();
+            scrollToTop();
             setSelectedNode(nodeFront);
             onHideBoxModelHighlighter();
           },
           onMouseOut: () => onHideBoxModelHighlighter(),
           onMouseOver: () => onShowBoxModelHighlighterForNode(nodeFront),
         },
         dom.span({ className: "flex-item-index" }, index),
         Rep({
--- a/devtools/client/inspector/flexbox/components/FlexItemList.js
+++ b/devtools/client/inspector/flexbox/components/FlexItemList.js
@@ -14,38 +14,41 @@ const FlexItem = createFactory(require((
 const Types = require("../types");
 
 class FlexItemList extends PureComponent {
   static get propTypes() {
     return {
       flexItems: PropTypes.arrayOf(PropTypes.shape(Types.flexItem)).isRequired,
       onHideBoxModelHighlighter: PropTypes.func.isRequired,
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
+      scrollToTop: PropTypes.func.isRequired,
       setSelectedNode: PropTypes.func.isRequired,
     };
   }
 
   render() {
     const {
       flexItems,
       onHideBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
+      scrollToTop,
       setSelectedNode,
     } = this.props;
 
     return (
       dom.div(
         { className: "flex-item-list" },
         dom.div({ className: "flex-item-list-header" }, getStr("flexbox.flexItems")),
         flexItems.map((flexItem, index) => FlexItem({
           key: flexItem.actorID,
           flexItem,
           index: index + 1,
           onHideBoxModelHighlighter,
           onShowBoxModelHighlighterForNode,
+          scrollToTop,
           setSelectedNode,
         }))
       )
     );
   }
 }
 
 module.exports = FlexItemList;
--- a/devtools/client/inspector/flexbox/components/Flexbox.js
+++ b/devtools/client/inspector/flexbox/components/Flexbox.js
@@ -34,32 +34,35 @@ class Flexbox extends PureComponent {
     return {
       flexbox: PropTypes.shape(Types.flexbox).isRequired,
       flexContainer: PropTypes.shape(Types.flexContainer).isRequired,
       getSwatchColorPickerTooltip: PropTypes.func.isRequired,
       onHideBoxModelHighlighter: PropTypes.func.isRequired,
       onSetFlexboxOverlayColor: PropTypes.func.isRequired,
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
       onToggleFlexboxHighlighter: PropTypes.func.isRequired,
+      scrollToTop: PropTypes.func.isRequired,
       setSelectedNode: PropTypes.func.isRequired,
     };
   }
 
   renderFlexItemList() {
     const {
       onHideBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
+      scrollToTop,
       setSelectedNode,
     } = this.props;
     const { flexItems } = this.props.flexContainer;
 
     return FlexItemList({
       flexItems,
       onHideBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
+      scrollToTop,
       setSelectedNode,
     });
   }
 
   renderFlexItemSizing() {
     const {
       color,
     } = this.props.flexbox;
--- a/devtools/client/inspector/layout/components/LayoutApp.js
+++ b/devtools/client/inspector/layout/components/LayoutApp.js
@@ -1,16 +1,16 @@
 /* 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 Services = require("Services");
-const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
+const { createFactory, createRef, PureComponent } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 const {
   getSelectorFromGrip,
   translateNodeFrontToGrip,
 } = require("devtools/client/inspector/shared/utils");
 const { LocalizationHelper } = require("devtools/shared/l10n");
@@ -56,29 +56,43 @@ class LayoutApp extends PureComponent {
       onToggleShowGridAreas: PropTypes.func.isRequired,
       onToggleShowGridLineNumbers: PropTypes.func.isRequired,
       onToggleShowInfiniteLines: PropTypes.func.isRequired,
       setSelectedNode: PropTypes.func.isRequired,
       showBoxModelProperties: PropTypes.bool.isRequired,
     };
   }
 
+  constructor(props) {
+    super(props);
+    this.containerRef = createRef();
+
+    this.scrollToTop = this.scrollToTop.bind(this);
+  }
+
   getFlexboxHeader(flexContainer) {
     if (!flexContainer.actorID) {
       // No flex container or flex item selected.
       return LAYOUT_L10N.getStr("flexbox.header");
     } else if (!flexContainer.flexItemShown) {
       // No flex item selected.
       return LAYOUT_L10N.getStr("flexbox.flexContainer");
     }
 
     const grip = translateNodeFrontToGrip(flexContainer.nodeFront);
     return LAYOUT_L10N.getFormatStr("flexbox.flexItemOf", getSelectorFromGrip(grip));
   }
 
+  /**
+   * Scrolls to top of the layout container.
+   */
+  scrollToTop() {
+    this.containerRef.current.scrollTop = 0;
+  }
+
   render() {
     const items = [
       {
         component: Grid,
         componentProps: this.props,
         header: LAYOUT_L10N.getStr("layout.header"),
         opened: Services.prefs.getBoolPref(GRID_OPENED_PREF),
         onToggled: () => {
@@ -101,16 +115,17 @@ class LayoutApp extends PureComponent {
     if (Services.prefs.getBoolPref(FLEXBOX_ENABLED_PREF)) {
       // Since the flexbox panel is hidden behind a pref. We insert the flexbox container
       // to the first index of the accordion item list.
       items.splice(0, 0, {
         component: Flexbox,
         componentProps: {
           ...this.props,
           flexContainer: this.props.flexbox.flexContainer,
+          scrollToTop: this.scrollToTop,
         },
         header: this.getFlexboxHeader(this.props.flexbox.flexContainer),
         opened: Services.prefs.getBoolPref(FLEXBOX_OPENED_PREF),
         onToggled: () => {
           const opened =  Services.prefs.getBoolPref(FLEXBOX_OPENED_PREF);
           Services.prefs.setBoolPref(FLEXBOX_OPENED_PREF, !opened);
         },
       });
@@ -122,28 +137,29 @@ class LayoutApp extends PureComponent {
           this.props.flexbox.flexItemContainer.actorID) {
         // Insert the parent flex container to the first index of the accordion item
         // list.
         items.splice(0, 0, {
           component: Flexbox,
           componentProps: {
             ...this.props,
             flexContainer: this.props.flexbox.flexItemContainer,
+            scrollToTop: this.scrollToTop,
           },
           header: this.getFlexboxHeader(this.props.flexbox.flexItemContainer),
           opened: Services.prefs.getBoolPref(FLEXBOX_OPENED_PREF),
           onToggled: () => {
             const opened =  Services.prefs.getBoolPref(FLEXBOX_OPENED_PREF);
             Services.prefs.setBoolPref(FLEXBOX_OPENED_PREF, !opened);
           },
         });
       }
     }
 
     return (
-      dom.div({ className: "layout-container" },
+      dom.div({ className: "layout-container", ref: this.containerRef },
         Accordion({ items })
       )
     );
   }
 }
 
 module.exports = connect(state => state)(LayoutApp);