Bug 985517 - Only allow one node to be pseudo class locked per pseudo. r=pbro draft
authorAlexandre Poirot <poirot.alex@gmail.com>
Wed, 02 Nov 2016 04:49:06 -0700
changeset 435042 45cede998137263fbcba72e34d28c1f84057b1ef
parent 435041 68d13aa818492c0594e956d30812b83bd1da5307
child 435043 e8871dc37652747ce318d5f2446472c6d76de8f0
push id34913
push userbmo:poirot.alex@gmail.com
push dateMon, 07 Nov 2016 22:46:48 +0000
reviewerspbro
bugs985517
milestone52.0a1
Bug 985517 - Only allow one node to be pseudo class locked per pseudo. r=pbro MozReview-Commit-ID: HF7Thklh0bZ
devtools/client/inspector/test/browser_inspector_pseudoclass-lock.js
devtools/server/actors/inspector.js
--- a/devtools/client/inspector/test/browser_inspector_pseudoclass-lock.js
+++ b/devtools/client/inspector/test/browser_inspector_pseudoclass-lock.js
@@ -26,33 +26,48 @@ add_task(function* () {
   inspector.sidebar.select("ruleview");
 
   let view = inspector.ruleview.view;
 
   info("Selecting the test node");
   yield selectNode("#div-1", inspector);
 
   yield togglePseudoClass(inspector);
-  yield assertPseudoAddedToNode(inspector, testActor, view);
+  yield assertPseudoAddedToNode(inspector, testActor, view, "#div-1");
 
   yield togglePseudoClass(inspector);
-  yield assertPseudoRemovedFromNode(testActor);
-  yield assertPseudoRemovedFromView(inspector, testActor, view);
+  yield assertPseudoRemovedFromNode(testActor, "#div-1");
+  yield assertPseudoRemovedFromView(inspector, testActor, view, "#div-1");
 
   yield togglePseudoClass(inspector);
   yield testNavigate(inspector, testActor, view);
 
+  info("Toggle pseudo on the parent and ensure everything is toggled off");
+  yield selectNode("#parent-div", inspector);
+  yield togglePseudoClass(inspector);
+  yield assertPseudoRemovedFromNode(testActor, "#div-1");
+  yield assertPseudoRemovedFromView(inspector, testActor, view, "#div-1");
+
+  yield togglePseudoClass(inspector);
+  info("Assert pseudo is dismissed when toggling it on a sibling node");
+  yield selectNode("#div-2", inspector);
+  yield togglePseudoClass(inspector);
+  yield assertPseudoAddedToNode(inspector, testActor, view, "#div-2");
+  let hasLock = yield testActor.hasPseudoClassLock("#div-1", PSEUDO);
+  ok(!hasLock, "pseudo-class lock has been removed for the previous locked node");
+
   info("Destroying the toolbox");
   let tab = toolbox.target.tab;
   yield toolbox.destroy();
 
   // As the toolbox get detroyed, we need to fetch a new test-actor
   testActor = yield getTestActorWithoutToolbox(tab);
 
-  yield assertPseudoRemovedFromNode(testActor);
+  yield assertPseudoRemovedFromNode(testActor, "#div-1");
+  yield assertPseudoRemovedFromNode(testActor, "#div-2");
 });
 
 function* togglePseudoClass(inspector) {
   info("Toggle the pseudoclass, wait for it to be applied");
 
   // Give the inspector panels a chance to update when the pseudoclass changes
   let onPseudo = inspector.selection.once("pseudoclass");
   let onRefresh = inspector.once("rule-view-refreshed");
@@ -85,61 +100,61 @@ function* testNavigate(inspector, testAc
   yield selectNode("#div-1", inspector);
 }
 
 function* showPickerOn(selector, inspector) {
   let nodeFront = yield getNodeFront(selector, inspector);
   yield inspector.highlighter.showBoxModel(nodeFront);
 }
 
-function* assertPseudoAddedToNode(inspector, testActor, ruleview) {
-  info("Make sure the pseudoclass lock is applied to #div-1 and its ancestors");
+function* assertPseudoAddedToNode(inspector, testActor, ruleview, selector) {
+  info("Make sure the pseudoclass lock is applied to " + selector + " and its ancestors");
 
-  let hasLock = yield testActor.hasPseudoClassLock("#div-1", PSEUDO);
+  let hasLock = yield testActor.hasPseudoClassLock(selector, PSEUDO);
   ok(hasLock, "pseudo-class lock has been applied");
   hasLock = yield testActor.hasPseudoClassLock("#parent-div", PSEUDO);
   ok(hasLock, "pseudo-class lock has been applied");
   hasLock = yield testActor.hasPseudoClassLock("body", PSEUDO);
   ok(hasLock, "pseudo-class lock has been applied");
 
   info("Check that the ruleview contains the pseudo-class rule");
   let rules = ruleview.element.querySelectorAll(
     ".ruleview-rule.theme-separator");
   is(rules.length, 3,
      "rule view is showing 3 rules for pseudo-class locked div");
   is(rules[1]._ruleEditor.rule.selectorText, "div:hover",
      "rule view is showing " + PSEUDO + " rule");
 
-  info("Show the highlighter on #div-1");
-  yield showPickerOn("#div-1", inspector);
+  info("Show the highlighter on " + selector);
+  yield showPickerOn(selector, inspector);
 
   info("Check that the infobar selector contains the pseudo-class");
   let value = yield testActor.getHighlighterNodeTextContent(
     "box-model-infobar-pseudo-classes");
   is(value, PSEUDO, "pseudo-class in infobar selector");
   yield inspector.highlighter.hideBoxModel();
 }
 
-function* assertPseudoRemovedFromNode(testActor) {
+function* assertPseudoRemovedFromNode(testActor, selector) {
   info("Make sure the pseudoclass lock is removed from #div-1 and its " +
        "ancestors");
 
-  let hasLock = yield testActor.hasPseudoClassLock("#div-1", PSEUDO);
+  let hasLock = yield testActor.hasPseudoClassLock(selector, PSEUDO);
   ok(!hasLock, "pseudo-class lock has been removed");
   hasLock = yield testActor.hasPseudoClassLock("#parent-div", PSEUDO);
   ok(!hasLock, "pseudo-class lock has been removed");
   hasLock = yield testActor.hasPseudoClassLock("body", PSEUDO);
   ok(!hasLock, "pseudo-class lock has been removed");
 }
 
-function* assertPseudoRemovedFromView(inspector, testActor, ruleview) {
+function* assertPseudoRemovedFromView(inspector, testActor, ruleview, selector) {
   info("Check that the ruleview no longer contains the pseudo-class rule");
   let rules = ruleview.element.querySelectorAll(
     ".ruleview-rule.theme-separator");
   is(rules.length, 2, "rule view is showing 2 rules after removing lock");
 
-  yield showPickerOn("#div-1", inspector);
+  yield showPickerOn(selector, inspector);
 
   let value = yield testActor.getHighlighterNodeTextContent(
     "box-model-infobar-pseudo-classes");
   is(value, "", "pseudo-class removed from infobar selector");
   yield inspector.highlighter.hideBoxModel();
 }
--- a/devtools/server/actors/inspector.js
+++ b/devtools/server/actors/inspector.js
@@ -1747,16 +1747,24 @@ var WalkerActor = protocol.ActorClassWit
    * @returns An empty packet.  A "pseudoClassLock" mutation will
    *    be queued for any changed nodes.
    */
   addPseudoClassLock: function (node, pseudo, options = {}) {
     if (isNodeDead(node)) {
       return;
     }
 
+    // There can be only one node locked per pseudo, so dismiss all existing
+    // ones
+    for (let locked of this._activePseudoClassLocks) {
+      if (DOMUtils.hasPseudoClassLock(locked.rawNode, pseudo)) {
+        this._removePseudoClassLock(locked, pseudo);
+      }
+    }
+
     this._addPseudoClassLock(node, pseudo);
 
     if (!options.parents) {
       return;
     }
 
     let walker = this.getDocumentWalker(node.rawNode);
     let cur;