Bug 734934 - [rule view] ability to disable a rule r=gl draft
authorLiam <canada8715@gmail.com>
Mon, 30 Oct 2017 23:02:10 -0600
changeset 694658 20fc539150f5eb8a1dfbb05d8554816093cf33a0
parent 688228 ed73b55a33120d27efc862eb87d332e167c026f4
child 739386 ed299abe2e3c345b5ec45a2be75110d0d5b8c602
push id88187
push userbmo:hodginsl2@mymacewan.ca
push dateWed, 08 Nov 2017 01:29:06 +0000
reviewersgl
bugs734934
milestone58.0a1
Bug 734934 - [rule view] ability to disable a rule r=gl MozReview-Commit-ID: 7CA0aGF4R4Y
devtools/client/inspector/rules/rules.js
devtools/client/inspector/rules/test/browser.ini
devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js
devtools/client/inspector/rules/test/browser_rules_uncheck_all_rules.js
devtools/client/inspector/rules/views/rule-editor.js
devtools/client/themes/rules.css
--- a/devtools/client/inspector/rules/rules.js
+++ b/devtools/client/inspector/rules/rules.js
@@ -973,17 +973,17 @@ CssRuleView.prototype = {
    * @return {DOMNode} The container element
    */
   createExpandableContainer: function (label, isPseudo = false) {
     let header = this.styleDocument.createElementNS(HTML_NS, "div");
     header.className = this._getRuleViewHeaderClassName(true);
     header.textContent = label;
 
     let twisty = this.styleDocument.createElementNS(HTML_NS, "span");
-    twisty.className = "ruleview-expander theme-twisty";
+    twisty.className = "theme-twisty";
     twisty.setAttribute("open", "true");
 
     header.insertBefore(twisty, header.firstChild);
     this.element.appendChild(header);
 
     let container = this.styleDocument.createElementNS(HTML_NS, "div");
     container.classList.add("ruleview-expandable-container");
     container.hidden = false;
--- a/devtools/client/inspector/rules/test/browser.ini
+++ b/devtools/client/inspector/rules/test/browser.ini
@@ -243,14 +243,15 @@ skip-if = (os == 'linux' && bits == 32 &
 [browser_rules_shapes-toggle_05.js]
 [browser_rules_shapes-toggle_06.js]
 [browser_rules_shorthand-overridden-lists.js]
 [browser_rules_strict-search-filter-computed-list_01.js]
 [browser_rules_strict-search-filter_01.js]
 [browser_rules_strict-search-filter_02.js]
 [browser_rules_strict-search-filter_03.js]
 [browser_rules_style-editor-link.js]
+[browser_rules_uncheck_all_rules.js]
 skip-if = true # Bug 1309759
 [browser_rules_url-click-opens-new-tab.js]
 [browser_rules_urls-clickable.js]
 [browser_rules_user-agent-styles.js]
 [browser_rules_user-agent-styles-uneditable.js]
 [browser_rules_user-property-reset.js]
--- a/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js
+++ b/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js
@@ -34,17 +34,17 @@ function* testTopLeft(inspector, view) {
       afterRulesNb: 1,
       beforeRulesNb: 2
     }
   );
 
   let gutters = assertGutters(view);
 
   info("Make sure that clicking on the twisty hides pseudo elements");
-  let expander = gutters[0].querySelector(".ruleview-expander");
+  let expander = gutters[0].querySelector(".theme-twisty");
   ok(!view.element.children[1].hidden, "Pseudo Elements are expanded");
 
   expander.click();
   ok(view.element.children[1].hidden,
     "Pseudo Elements are collapsed by twisty");
 
   expander.click();
   ok(!view.element.children[1].hidden, "Pseudo Elements are expanded again");
@@ -124,17 +124,17 @@ function* testTopRight(inspector, view) 
     firstLetterRulesNb: 1,
     selectionRulesNb: 0,
     beforeRulesNb: 2,
     afterRulesNb: 1
   });
 
   let gutters = assertGutters(view);
 
-  let expander = gutters[0].querySelector(".ruleview-expander");
+  let expander = gutters[0].querySelector(".theme-twisty");
   ok(!view.element.firstChild.classList.contains("show-expandable-container"),
      "Pseudo Elements remain collapsed after switching element");
 
   expander.scrollIntoView();
   expander.click();
   ok(!view.element.children[1].hidden,
     "Pseudo Elements are shown again after clicking twisty");
 }
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/test/browser_rules_uncheck_all_rules.js
@@ -0,0 +1,80 @@
+/* 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";
+
+// Tests unnchecking and rechecking all rules using select all checkbox
+
+const TEST_URI = `
+  <style type="text/css">
+  #testid {
+    background-color: blue;
+    margin-left: 3px;
+    margin-right: 4px;
+    border-color: black;
+  }
+  .testclass, .unmatched {
+    background-color: green;
+  }
+  </style>
+  <div id="testid" class="testclass">Styled Node</div>
+`;
+
+add_task(function* () {
+  yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+  let {inspector, view} = yield openRuleView();
+  yield selectNode("#testid", inspector);
+  yield testDisableProperty(inspector, view);
+});
+
+function* testDisableProperty(inspector, ruleView) {
+  let enableRule = getRuleViewRuleEditor(ruleView, 1);
+
+  info("Disabling the whole rule");
+  let onRuleViewRefreshed = ruleView.once("ruleview-changed");
+  enableRule.enable.click();
+  yield onRuleViewRefreshed;
+  let newValue = yield executeInContent("Test:GetRulePropertyValue", {
+    styleSheetIndex: 0,
+    ruleIndex: 0,
+    name: "background-color"
+  });
+  is(newValue, "", "background-color should have been unset.");
+  let newValue2 = yield executeInContent("Test:GetRulePropertyValue", {
+    styleSheetIndex: 0,
+    ruleIndex: 0,
+    name: "border-color"
+  });
+  is(newValue2, "", "border-color should have been unset.");
+
+  info("Enabling the whole rule again");
+  onRuleViewRefreshed = ruleView.once("ruleview-changed");
+  enableRule.enable.click();
+  yield onRuleViewRefreshed;
+  newValue = yield executeInContent("Test:GetRulePropertyValue", {
+    styleSheetIndex: 0,
+    ruleIndex: 0,
+    name: "background-color"
+  });
+  is(newValue, "blue", "background-color should have been reset.");
+  newValue2 = yield executeInContent("Test:GetRulePropertyValue", {
+    styleSheetIndex: 0,
+    ruleIndex: 0,
+    name: "border-color"
+  });
+  is(newValue2, "black", "border-color should have been reset.");
+
+  info("Disabling the whole rule again");
+  onRuleViewRefreshed = ruleView.once("ruleview-changed");
+  enableRule.enable.click();
+  yield onRuleViewRefreshed;
+  let idRule = enableRule.rule;
+  let prop = idRule.textProps[0];
+
+  info("Reenabling an individual property");
+  yield togglePropStatus(ruleView, prop);
+
+  let checked = enableRule.enable.hasAttribute("checked");
+  is(checked, false, "Making sure rule checkbox is still unchecked");
+}
--- a/devtools/client/inspector/rules/views/rule-editor.js
+++ b/devtools/client/inspector/rules/views/rule-editor.js
@@ -57,16 +57,17 @@ function RuleEditor(ruleView, rule) {
   this.sourceMapURLService = this.toolbox.sourceMapURLService;
   this.rule = rule;
 
   this.isEditable = !rule.isSystem;
   // Flag that blocks updates of the selector and properties when it is
   // being edited
   this.isEditing = false;
 
+  this._onEnableClicked = this._onEnableClicked.bind(this);
   this._onNewProperty = this._onNewProperty.bind(this);
   this._newPropertyDestroy = this._newPropertyDestroy.bind(this);
   this._onSelectorDone = this._onSelectorDone.bind(this);
   this._locationChanged = this._locationChanged.bind(this);
   this.updateSourceLink = this.updateSourceLink.bind(this);
   this._onToolChanged = this._onToolChanged.bind(this);
   this._updateLocation = this._updateLocation.bind(this);
   this._onSourceClick = this._onSourceClick.bind(this);
@@ -133,16 +134,22 @@ RuleEditor.prototype = {
     this.updateSourceLink();
 
     let code = createChild(this.element, "div", {
       class: "ruleview-code"
     });
 
     let header = createChild(code, "div", {});
 
+    this.enable = createChild(header, "div", {
+      class: "ruleview-enablerule theme-checkbox"
+    });
+
+    this.enable.setAttribute("checked", "");
+
     this.selectorText = createChild(header, "span", {
       class: "ruleview-selectorcontainer",
       tabindex: this.isSelectorEditable ? "0" : "-1",
     });
 
     if (this.isSelectorEditable) {
       this.selectorText.addEventListener("click", event => {
         // Clicks within the selector shouldn't propagate any further.
@@ -205,16 +212,18 @@ RuleEditor.prototype = {
     });
 
     if (this.isEditable) {
       // A newProperty editor should only be created when no editor was
       // previously displayed. Since the editors are cleared on blur,
       // check this.ruleview.isEditing on mousedown
       this._ruleViewIsEditing = false;
 
+      this.enable.addEventListener("click", this._onEnableClicked, true);
+
       code.addEventListener("mousedown", () => {
         this._ruleViewIsEditing = this.ruleView.isEditing;
       });
 
       code.addEventListener("click", () => {
         let selection = this.doc.defaultView.getSelection();
         if (selection.isCollapsed && !this._ruleViewIsEditing) {
           this.newProperty();
@@ -595,16 +604,34 @@ RuleEditor.prototype = {
     // If the last new property has no value, focus the value on it.
     // Otherwise, start a new property and focus that field.
     if (this.multipleAddedProperties && this.multipleAddedProperties.length) {
       this.addProperties(this.multipleAddedProperties);
     }
   },
 
   /**
+   * Handles clicks on the disabled property.
+   */
+  _onEnableClicked: function (event) {
+    let checked = this.enable.hasAttribute("checked");
+    if (checked) {
+      this.enable.removeAttribute("checked");
+      this.enable.style.visibility = "visible";
+    } else {
+      this.enable.setAttribute("checked", "");
+      this.enable.style.removeProperty("visibility");
+    }
+    for (let prop of this.rule.textProps) {
+      prop.setEnabled(!checked);
+    }
+    event.stopPropagation();
+  },
+
+  /**
    * Called when the selector's inplace editor is closed.
    * Ignores the change if the user pressed escape, otherwise
    * commits it.
    *
    * @param {String} value
    *        The value contained in the editor.
    * @param {Boolean} commit
    *        True if the change should be applied.
--- a/devtools/client/themes/rules.css
+++ b/devtools/client/themes/rules.css
@@ -140,16 +140,20 @@
   visibility: collapse;
   transition: visibility 0.25s;
 }
 
 .ruleview-code {
   direction: ltr;
 }
 
+.ruleview-enablerule:not(:hover) > .ruleview-enablerule {
+  pointer-events: none;
+}
+
 .ruleview-property:not(:hover) > .ruleview-enableproperty {
   pointer-events: none;
 }
 
 .ruleview-expandable-container {
   display: block;
 }
 
@@ -241,30 +245,24 @@
   color: inherit;
   border: none;
   margin: 4px 0;
   padding: 3px 4px 2px 4px;
   line-height: inherit;
   min-height: 0;
 }
 
-:root[platform="win"] .ruleview-header,
-:root[platform="linux"] .ruleview-header {
-  margin-top: 4px;
-}
-
 .ruleview-expandable-header {
   cursor: pointer;
 }
 
 .ruleview-expandable-header:hover {
   background-color: var(--theme-toolbar-background-hover);
 }
 
-
 .ruleview-rule-pseudo-element {
   padding-left:20px;
   border-left: solid 10px;
 }
 
 .ruleview-rule {
   border-bottom: 1px solid var(--theme-splitter-color);
   padding: 2px 4px;
@@ -378,49 +376,62 @@
   padding: 0;
   margin: 0;
 }
 
 .ruleview-rule:not(:hover) .ruleview-enableproperty {
   visibility: hidden;
 }
 
+.ruleview-rule:not(:hover) .ruleview-enablerule {
+  visibility: hidden;
+}
+
 .ruleview-expander {
-  vertical-align: middle;
-  display: inline-block;
+  position: relative;
+  float: left;
+  left: -26px;
+  top: 1px;
 }
 
 .ruleview-rule .ruleview-expander.theme-twisty:dir(rtl) {
   /* for preventing .theme-twisty's wrong direction in rtl; Bug 1296648 */
   transform: none;
 }
 
 .ruleview-newproperty {
-  /* (enable checkbox width: 12px) + (expander width: 15px) */
-  margin-inline-start: 27px;
+  margin-inline-start: 2px;
+}
+
+.ruleview-enableproperty {
+  position: relative;
+  float: left;
+  left: -26px;
+  top: 1px;
+}
+
+.ruleview-namecontainer {
+  margin-left: -26px;
 }
 
 .ruleview-namecontainer,
 .ruleview-propertyvaluecontainer,
 .ruleview-propertyname,
 .ruleview-propertyvalue {
   text-decoration: inherit;
 }
 
 .ruleview-computedlist {
+  margin: 0px 0px 0px 10px;
   list-style: none;
   padding: 0;
 }
 
-.ruleview-computed {
-  margin-inline-start: 35px;
-}
-
 .ruleview-overridden-items {
-  margin: 0px 0px 0px 5px;
+  margin: 0px 0px 0px -21px;
   list-style: none;
   line-height: 1.5em;
 }
 
 .ruleview-overridden-item {
   position: relative;
 }
 
@@ -533,16 +544,17 @@
 }
 
 .theme-firebug .styleinspector-propertyeditor {
   border: 1px solid var(--theme-splitter-color);
   box-shadow: 0 2px 6px rgba(0, 0, 0, 0.5);
 }
 
 .ruleview-property {
+  padding-left: 38px;
   border-left: 3px solid transparent;
   clear: right;
 }
 
 .ruleview-propertycontainer  > * {
   vertical-align: middle;
 }
 
@@ -560,16 +572,22 @@
   border-bottom: 1px dashed transparent;
 }
 
 .ruleview-namecontainer:hover > .ruleview-propertyname,
 .ruleview-propertyvaluecontainer:hover > .ruleview-propertyvalue {
   border-bottom-color: hsl(0,0%,50%);
 }
 
+.ruleview-enablerule {
+  margin-right: 5px;
+  margin-left: 2px;
+  vertical-align: middle;
+}
+
 .ruleview-selectorcontainer {
   word-wrap: break-word;
   cursor: text;
 }
 
 .ruleview-selector-separator,
 .ruleview-selector-unmatched,
 .ruleview-variable-unmatched {