Bug 1399909 - Prevent the inspector resizing its left pane during load. r=gl draft
authorAlexandre Poirot <poirot.alex@gmail.com>
Mon, 18 Sep 2017 18:07:24 +0200
changeset 666357 b3cfc9fc81b479dc29e9f4ba43435b7229234bb6
parent 666127 ae39864562c6048fdc2950c5dfedb48e247c3300
child 732079 7fb4e64f9b8578b0d3289d7e757f1d11c3541c27
push id80380
push userbmo:poirot.alex@gmail.com
push dateMon, 18 Sep 2017 17:00:54 +0000
reviewersgl
bugs1399909
milestone57.0a1
Bug 1399909 - Prevent the inspector resizing its left pane during load. r=gl Today, inspector startup is clunky and is made is many steps in which the left pane with the markup view is loaded full width before the rule view is opened. It blinks and resize things. * display the left pane (inspector-main-content) only when the size of panels is set by the splitter. * fix markupbox hidding while loading as "collapsed" wasn't working * setup the splitter with the right size immediately * prevent unnecessary renders in split-box MozReview-Commit-ID: HvTnmzKpbjy
devtools/client/inspector/inspector.js
devtools/client/inspector/inspector.xhtml
devtools/client/shared/components/splitter/split-box.js
--- a/devtools/client/inspector/inspector.js
+++ b/devtools/client/inspector/inspector.js
@@ -273,16 +273,26 @@ Inspector.prototype = {
       this._toolbox.on("select", this.updateDebuggerPausedWarning);
       this.updateDebuggerPausedWarning();
     }
 
     this._initMarkup();
     this.isReady = false;
 
     this.setupSearchBox();
+
+    // Setup the splitter before the sidebar is displayed so,
+    // we don't miss any events.
+    this.setupSplitter();
+
+    // We can display right panel with: tab bar, markup view and breadbrumb. Right after
+    // the splitter set the right and left panel sizes, in order to avoid resizing it
+    // during load of the inspector.
+    this.panelDoc.getElementById("inspector-main-content").style.visibility = "visible";
+
     this.setupSidebar();
     this.setupExtensionSidebars();
 
     await this.once("markuploaded");
     this.isReady = true;
 
     // All the components are initialized. Let's select a node.
     if (defaultSelection) {
@@ -472,40 +482,36 @@ Inspector.prototype = {
   /**
    * Build Splitter located between the main and side area of
    * the Inspector panel.
    */
   setupSplitter: function () {
     let SplitBox = this.React.createFactory(this.browserRequire(
       "devtools/client/shared/components/splitter/split-box"));
 
+    let { width, height } = this.getSidebarSize();
     let splitter = SplitBox({
       className: "inspector-sidebar-splitter",
-      initialWidth: INITIAL_SIDEBAR_SIZE,
-      initialHeight: INITIAL_SIDEBAR_SIZE,
+      initialWidth: width,
+      initialHeight: height,
       splitterSize: 1,
       endPanelControl: true,
       startPanel: this.InspectorTabPanel({
         id: "inspector-main-content"
       }),
       endPanel: this.InspectorTabPanel({
         id: "inspector-sidebar-container"
       }),
       vert: this.useLandscapeMode(),
     });
 
     this._splitter = this.ReactDOM.render(splitter,
       this.panelDoc.getElementById("inspector-splitter-box"));
 
     this.panelWin.addEventListener("resize", this.onPanelWindowResize, true);
-
-    // Persist splitter state in preferences.
-    this.sidebar.on("show", this.onSidebarShown);
-    this.sidebar.on("hide", this.onSidebarHidden);
-    this.sidebar.on("destroy", this.onSidebarHidden);
   },
 
   /**
    * Splitter clean up.
    */
   teardownSplitter: function () {
     this.panelWin.removeEventListener("resize", this.onPanelWindowResize, true);
 
@@ -519,34 +525,37 @@ Inspector.prototype = {
    * to `horizontal` to support portrait view.
    */
   onPanelWindowResize: function () {
     this._splitter.setState({
       vert: this.useLandscapeMode(),
     });
   },
 
-  onSidebarShown: function () {
+  getSidebarSize: function () {
     let width;
     let height;
 
     // Initialize splitter size from preferences.
     try {
       width = Services.prefs.getIntPref("devtools.toolsidebar-width.inspector");
       height = Services.prefs.getIntPref("devtools.toolsidebar-height.inspector");
     } catch (e) {
       // Set width and height of the splitter. Only one
       // value is really useful at a time depending on the current
       // orientation (vertical/horizontal).
       // Having both is supported by the splitter component.
       width = INITIAL_SIDEBAR_SIZE;
       height = INITIAL_SIDEBAR_SIZE;
     }
+    return { width, height };
+  },
 
-    this._splitter.setState({width, height});
+  onSidebarShown: function () {
+    this._splitter.setState(this.getSidebarSize());
   },
 
   onSidebarHidden: function () {
     // Store the current splitter size to preferences.
     let state = this._splitter.state;
     Services.prefs.setIntPref("devtools.toolsidebar-width.inspector", state.width);
     Services.prefs.setIntPref("devtools.toolsidebar-height.inspector", state.height);
   },
@@ -661,19 +670,20 @@ Inspector.prototype = {
         this.canGetUsedFontFaces) {
       const FontInspector = this.browserRequire("devtools/client/inspector/fonts/fonts");
       this.fontinspector = new FontInspector(this, this.panelWin);
       this.fontinspector.init();
 
       this.sidebar.toggleTab(true, "fontinspector");
     }
 
-    // Setup the splitter before the sidebar is displayed so,
-    // we don't miss any events.
-    this.setupSplitter();
+    // Persist splitter state in preferences.
+    this.sidebar.on("show", this.onSidebarShown);
+    this.sidebar.on("hide", this.onSidebarHidden);
+    this.sidebar.on("destroy", this.onSidebarHidden);
 
     this.sidebar.show(defaultTab);
   },
 
   /**
    * Setup any extension sidebar already registered to the toolbox when the inspector.
    * has been created for the first time.
    */
@@ -1513,34 +1523,33 @@ Inspector.prototype = {
 
     // create tool iframe
     this._markupFrame = doc.createElement("iframe");
     this._markupFrame.setAttribute("flex", "1");
     // This is needed to enable tooltips inside the iframe document.
     this._markupFrame.setAttribute("tooltip", "aHTMLTooltip");
     this._markupFrame.addEventListener("contextmenu", this._onContextMenu);
 
-    this._markupBox.setAttribute("collapsed", true);
+    this._markupBox.style.visibility = "hidden";
     this._markupBox.appendChild(this._markupFrame);
 
     this._markupFrame.addEventListener("load", this._onMarkupFrameLoad, true);
     this._markupFrame.setAttribute("src", "markup/markup.xhtml");
     this._markupFrame.setAttribute("aria-label",
       INSPECTOR_L10N.getStr("inspector.panelLabel.markupView"));
   },
 
   _onMarkupFrameLoad: function () {
     this._markupFrame.removeEventListener("load", this._onMarkupFrameLoad, true);
 
     this._markupFrame.contentWindow.focus();
 
-    this._markupBox.removeAttribute("collapsed");
-
     this.markup = new MarkupView(this, this._markupFrame, this._toolbox.win);
 
+    this._markupBox.style.visibility = "visible";
     this.emit("markuploaded");
   },
 
   _destroyMarkup: function () {
     let destroyPromise;
 
     if (this._markupFrame) {
       this._markupFrame.removeEventListener("load", this._onMarkupFrameLoad, true);
--- a/devtools/client/inspector/inspector.xhtml
+++ b/devtools/client/inspector/inspector.xhtml
@@ -40,17 +40,17 @@
 
   <!-- in content, inspector.js is mapped to the dynamically generated webpack bundle -->
   <script type="application/javascript" src="inspector.js" defer="true"></script>
 </head>
 <body class="theme-body" role="application">
   <div class="inspector-responsive-container theme-body inspector">
 
     <!-- Main Panel Content -->
-    <div id="inspector-main-content" class="devtools-main-content">
+    <div id="inspector-main-content" class="devtools-main-content" style="visibility: hidden;">
       <div id="inspector-toolbar" class="devtools-toolbar" nowindowdrag="true"
            data-localization-bundle="devtools/client/locales/inspector.properties">
         <button id="inspector-element-add-button" class="devtools-button"
                 data-localization="title=inspectorAddNode.label"></button>
         <div class="devtools-toolbar-spacer"></div>
         <span id="inspector-searchlabel"></span>
         <div id="inspector-search" class="devtools-searchbox has-clear-btn">
           <input id="inspector-searchbox" class="devtools-searchinput"
--- a/devtools/client/shared/components/splitter/split-box.js
+++ b/devtools/client/shared/components/splitter/split-box.js
@@ -67,16 +67,28 @@ const SplitBox = React.createClass({
   componentWillReceiveProps(nextProps) {
     let { vert } = nextProps;
 
     if (vert !== this.props.vert) {
       this.setState({ vert });
     }
   },
 
+  shouldComponentUpdate(nextProps, nextState) {
+    return nextState.width != this.state.width ||
+      nextState.height != this.state.height ||
+      nextState.vert != this.state.vert ||
+      nextProps.startPanel != this.props.startPanel ||
+      nextProps.endPanel != this.props.endPanel ||
+      nextProps.endPanelControl != this.props.endPanelControl ||
+      nextProps.minSize != this.props.minSize ||
+      nextProps.maxSize != this.props.maxSize ||
+      nextProps.splitterSize != this.props.splitterSize;
+  },
+
   // Dragging Events
 
   /**
    * Set 'resizing' cursor on entire document during splitter dragging.
    * This avoids cursor-flickering that happens when the mouse leaves
    * the splitter bar area (happens frequently).
    */
   onStartMove() {