Bug 1342310 - remember selected grid container on navigate;r=gl draft
authorJulian Descottes <jdescottes@mozilla.com>
Thu, 02 Mar 2017 18:16:47 +0100
changeset 494696 e6a74f6cf53db2b46ac8dad4e1655e4e88ccd975
parent 494679 a8d5f142c025a938b6af1656443b9eac20020e94
child 494697 ed3ccedd8f65d745c036b361c005087ca21da8de
child 495545 3ed0ae3cbed63cd86f3d089e7c406d0298f6a333
child 495547 47cbfa55cfb6a67f40dbf1f9802894c971a4b097
push id48099
push userjdescottes@mozilla.com
push dateTue, 07 Mar 2017 17:35:50 +0000
reviewersgl
bugs1342310
milestone55.0a1
Bug 1342310 - remember selected grid container on navigate;r=gl The highlighters-overlay now keep the state of the grid highlighter in memory. On "navigate", the state is restored. MozReview-Commit-ID: 7KNhxHs3L5G
devtools/client/inspector/rules/test/browser.ini
devtools/client/inspector/rules/test/browser_rules_grid-highlighter-restored-after-reload.js
devtools/client/inspector/shared/highlighters-overlay.js
--- a/devtools/client/inspector/rules/test/browser.ini
+++ b/devtools/client/inspector/rules/test/browser.ini
@@ -140,16 +140,17 @@ skip-if = os == "mac" # Bug 1245996 : cl
 [browser_rules_editable-field-focus_02.js]
 [browser_rules_eyedropper.js]
 [browser_rules_filtereditor-appears-on-swatch-click.js]
 [browser_rules_filtereditor-commit-on-ENTER.js]
 [browser_rules_filtereditor-revert-on-ESC.js]
 skip-if = (os == "win" && debug) # bug 963492: win.
 [browser_rules_grid-highlighter-on-navigate.js]
 [browser_rules_grid-highlighter-on-reload.js]
+[browser_rules_grid-highlighter-restored-after-reload.js]
 [browser_rules_grid-toggle_01.js]
 [browser_rules_grid-toggle_01b.js]
 [browser_rules_grid-toggle_02.js]
 [browser_rules_grid-toggle_03.js]
 [browser_rules_guessIndentation.js]
 [browser_rules_inherited-properties_01.js]
 [browser_rules_inherited-properties_02.js]
 [browser_rules_inherited-properties_03.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/test/browser_rules_grid-highlighter-restored-after-reload.js
@@ -0,0 +1,46 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid highlighter is re-displayed after reloading a page.
+
+const TEST_URI = `
+  <style type='text/css'>
+    #grid {
+      display: grid;
+    }
+  </style>
+  <div id="grid">
+    <div id="cell1">cell1</div>
+    <div id="cell2">cell2</div>
+  </div>
+`;
+
+add_task(function* () {
+  yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+
+  info("Check that the grid highlighter can be displayed");
+  let {inspector, view} = yield openRuleView();
+  let {highlighters} = view;
+
+  yield selectNode("#grid", inspector);
+  let container = getRuleViewProperty(view, "#grid", "display").valueSpan;
+  let gridToggle = container.querySelector(".ruleview-grid");
+
+  info("Toggling ON the CSS grid highlighter from the rule-view.");
+  let onHighlighterShown = highlighters.once("grid-highlighter-shown");
+  gridToggle.click();
+  yield onHighlighterShown;
+
+  ok(highlighters.gridHighlighterShown, "CSS grid highlighter is shown.");
+
+  info("Reload the page, expect the highlighter to be displayed once again");
+  onHighlighterShown = highlighters.once("grid-highlighter-shown");
+  yield refreshTab(gBrowser.selectedTab);
+  yield onHighlighterShown;
+
+  info("Check that the grid highlighter can be displayed after reloading the page");
+  ok(highlighters.gridHighlighterShown, "CSS grid highlighter is shown.");
+});
--- a/devtools/client/inspector/shared/highlighters-overlay.js
+++ b/devtools/client/inspector/shared/highlighters-overlay.js
@@ -26,21 +26,28 @@ function HighlightersOverlay(inspector) 
   this.supportsHighlighters = this.highlighterUtils.supportsCustomHighlighters();
 
   // NodeFront of the grid container that is highlighted.
   this.gridHighlighterShown = null;
   // Name of the highlighter shown on mouse hover.
   this.hoveredHighlighterShown = null;
   // Name of the selector highlighter shown.
   this.selectorHighlighterShown = null;
+  // Saved state to be restore on page navigation.
+  this.state = {
+    // Only the grid highlighter state is saved at the moment.
+    grid: {}
+  };
 
   this.onClick = this.onClick.bind(this);
   this.onMouseMove = this.onMouseMove.bind(this);
   this.onMouseOut = this.onMouseOut.bind(this);
   this.onWillNavigate = this.onWillNavigate.bind(this);
+  this.onNavigate = this.onNavigate.bind(this);
+  this._handleRejection = this._handleRejection.bind(this);
 
   EventEmitter.decorate(this);
 }
 
 HighlightersOverlay.prototype = {
   get isRuleView() {
     return this.inspector.sidebar.getCurrentTabID() == "ruleview";
   },
@@ -59,16 +66,17 @@ HighlightersOverlay.prototype = {
     }
 
     let el = view.element;
     el.addEventListener("click", this.onClick, true);
     el.addEventListener("mousemove", this.onMouseMove);
     el.addEventListener("mouseout", this.onMouseOut);
     el.ownerDocument.defaultView.addEventListener("mouseout", this.onMouseOut);
 
+    this.inspector.target.on("navigate", this.onNavigate);
     this.inspector.target.on("will-navigate", this.onWillNavigate);
   },
 
   /**
    * Remove the overlay from the given view. This will stop tracking mouse movement and
    * showing highlighters.
    *
    * @param  {CssRuleView|CssComputedView|LayoutView} view
@@ -80,16 +88,17 @@ HighlightersOverlay.prototype = {
       return;
     }
 
     let el = view.element;
     el.removeEventListener("click", this.onClick, true);
     el.removeEventListener("mousemove", this.onMouseMove);
     el.removeEventListener("mouseout", this.onMouseOut);
 
+    this.inspector.target.off("navigate", this.onNavigate);
     this.inspector.target.off("will-navigate", this.onWillNavigate);
   },
 
   /**
    * Toggle the grid highlighter for the given grid container element.
    *
    * @param  {NodeFront} node
    *         The NodeFront of the grid container element to highlight.
@@ -121,20 +130,24 @@ HighlightersOverlay.prototype = {
 
     let isShown = yield highlighter.show(node, options);
     if (!isShown) {
       return;
     }
 
     this._toggleRuleViewGridIcon(node, true);
 
-    // Emit the NodeFront of the grid container element that the grid highlighter was
-    // shown for.
-    this.emit("grid-highlighter-shown", node);
-    this.gridHighlighterShown = node;
+    node.getUniqueSelector().then(selector => {
+      // Save grid highlighter state.
+      this.state.grid = { selector, options };
+      this.gridHighlighterShown = node;
+      // Emit the NodeFront of the grid container element that the grid highlighter was
+      // shown for.
+      this.emit("grid-highlighter-shown", node);
+    }).catch(this._handleRejection);
   }),
 
   /**
    * Hide the grid highlighter for the given grid container element.
    *
    * @param  {NodeFront} node
    *         The NodeFront of the grid container element to unhighlight.
    */
@@ -146,16 +159,44 @@ HighlightersOverlay.prototype = {
     this._toggleRuleViewGridIcon(node, false);
 
     yield this.highlighters.CssGridHighlighter.hide();
 
     // Emit the NodeFront of the grid container element that the grid highlighter was
     // hidden for.
     this.emit("grid-highlighter-hidden", this.gridHighlighterShown);
     this.gridHighlighterShown = null;
+
+    // Erase grid highlighter state.
+    this.state.grid = {};
+  }),
+
+  /**
+   * Restore the saved highlighter states.
+   *
+   * @return {Promise} that resolves when the highlighter state was restored, and the
+   *          expected highlighters are displayed.
+   */
+  restoreState: Task.async(function* () {
+    let { selector, options } = this.state.grid;
+
+    if (!selector) {
+      return;
+    }
+
+    // Wait for the new root to be ready in the inspector.
+    yield this.onInspectorNewRoot;
+
+    let walker = this.inspector.walker;
+    let rootNode = yield walker.getRootNode();
+    let nodeFront = yield walker.querySelector(rootNode, selector);
+
+    if (nodeFront) {
+      yield this.showGridHighlighter(nodeFront, options);
+    }
   }),
 
   /**
    * Get a highlighter front given a type. It will only be initialized once.
    *
    * @param  {String} type
    *         The highlighter type. One of this.highlighters.
    * @return {Promise} that resolves to the highlighter
@@ -168,16 +209,22 @@ HighlightersOverlay.prototype = {
     }
 
     return utils.getHighlighterByType(type).then(highlighter => {
       this.highlighters[type] = highlighter;
       return highlighter;
     });
   },
 
+  _handleRejection: function (error) {
+    if (!this.destroyed) {
+      console.error(error);
+    }
+  },
+
   /**
    * Toggle all the grid icons in the rule view if the current inspector selection is the
    * highlighted node.
    *
    * @param  {NodeFront} node
    *         The NodeFront of the grid container element to highlight.
    * @param  {Boolean} active
    *         Whether or not the grid icon should be active.
@@ -311,22 +358,32 @@ HighlightersOverlay.prototype = {
     }
 
     // Otherwise, hide the highlighter.
     this._lastHovered = null;
     this._hideHoveredHighlighter();
   },
 
   /**
+   * Restore saved highlighter state after navigate.
+   */
+  onNavigate: function () {
+    this.restoreState().catch(this._handleRejection);
+  },
+
+  /**
    * Clear saved highlighter shown properties on will-navigate.
    */
   onWillNavigate: function () {
     this.gridHighlighterShown = null;
     this.hoveredHighlighterShown = null;
     this.selectorHighlighterShown = null;
+
+    // The inspector panel should emit the new-root event when it is ready after navigate.
+    this.onInspectorNewRoot = this.inspector.once("new-root");
   },
 
   /**
    * Destroy this overlay instance, removing it from the view and destroying
    * all initialized highlighters.
    */
   destroy: function () {
     for (let type in this.highlighters) {
@@ -340,12 +397,13 @@ HighlightersOverlay.prototype = {
 
     this.inspector = null;
     this.highlighters = null;
     this.highlighterUtils = null;
     this.supportsHighlighters = null;
     this.gridHighlighterShown = null;
     this.hoveredHighlighterShown = null;
     this.selectorHighlighterShown = null;
+    this.destroyed = true;
   }
 };
 
 module.exports = HighlightersOverlay;