Bug 1222774 - Part 1: Add swatches for CSS variables r?gl draft
authorDarren Hobin <darrenhobin@live.com>
Sat, 23 Sep 2017 12:26:26 -0400
changeset 682899 df40e0d1500c48f3630e8e78762c4b3c719a2028
parent 682898 a04860cd9c8895aaaadaa32efec5e8b2cdcd24e8
child 736473 e4076e205aab3f6a944f99f1dedf5e7b907618ec
push id85191
push userbmo:darrenhobin@live.com
push dateWed, 18 Oct 2017 22:30:39 +0000
reviewersgl
bugs1222774
milestone58.0a1
Bug 1222774 - Part 1: Add swatches for CSS variables r?gl MozReview-Commit-ID: 6Z5vqbYiCWq
devtools/client/shared/output-parser.js
devtools/client/themes/rules.css
--- a/devtools/client/shared/output-parser.js
+++ b/devtools/client/shared/output-parser.js
@@ -58,16 +58,17 @@ const CSS_SHAPE_OUTSIDE_ENABLED_PREF = "
 function OutputParser(document,
                       {supportsType, isValidOnClient, supportsCssColor4ColorFunction}) {
   this.parsed = [];
   this.doc = document;
   this.supportsType = supportsType;
   this.isValidOnClient = isValidOnClient;
   this.colorSwatches = new WeakMap();
   this.angleSwatches = new WeakMap();
+  this._computedVariable = null;
   this._onColorSwatchMouseDown = this._onColorSwatchMouseDown.bind(this);
   this._onAngleSwatchMouseDown = this._onAngleSwatchMouseDown.bind(this);
 
   this.cssColor4 = supportsCssColor4ColorFunction();
 }
 
 OutputParser.prototype = {
   /**
@@ -198,17 +199,17 @@ OutputParser.prototype = {
    *         title. Eg. a span with "var(--var1)" as the textContent
    *         and a title for --var1 like "--var1 = 10" or
    *         "--var1 is not set".
    */
   _parseVariable: function (initialToken, text, tokenStream, options) {
     // Handle the "var(".
     let varText = text.substring(initialToken.startOffset,
                                  initialToken.endOffset);
-    let variableNode = this._createNode("span", {}, varText);
+    let variableNode = this._createNode("span", {});
 
     // Parse the first variable name within the parens of var().
     let {tokens, functionData, sawComma, sawVariable} =
         this._parseMatchingParens(text, tokenStream, options, true);
 
     let result = sawVariable ? "" : functionData.join("");
 
     // Display options for the first and second argument in the var().
@@ -220,49 +221,58 @@ OutputParser.prototype = {
     // Get the variable value if it is in use.
     if (tokens && tokens.length === 1) {
       varValue = options.isVariableInUse(tokens[0].text);
     }
 
     // Get the variable name.
     let varName = text.substring(tokens[0].startOffset, tokens[0].endOffset);
 
+    // Reset swatch variable
+    this._computedVariable = null;
+
+    // If we saw a ",", get the remainder with the correct highlighting.
+    let rest;
+    if (sawComma) {
+      // Parse the text up until the close paren, being sure to
+      // disable the special case for filter.
+      let subOptions = Object.assign({}, options);
+      subOptions.expectFilter = false;
+      let saveParsed = this.parsed;
+      this.parsed = [];
+      subOptions.expectVar = true;
+      rest = this._doParse(text, subOptions, tokenStream, true);
+      this.parsed = saveParsed;
+    }
+
     if (typeof varValue === "string") {
       // The variable value is valid, set the variable name's title of the first argument
       // in var() to display the variable name and value.
       firstOpts.title =
         STYLE_INSPECTOR_L10N.getFormatStr("rule.variableValue", varName, varValue);
+      this._computedVariable = varValue;
       secondOpts.class = options.unmatchedVariableClass;
     } else {
       // The variable name is not valid, mark it unmatched.
       firstOpts.class = options.unmatchedVariableClass;
       firstOpts.title = STYLE_INSPECTOR_L10N.getFormatStr("rule.variableUnset",
                                                           varName);
     }
 
+    this._appendVariable(this._computedVariable, variableNode, options);
+    appendText(variableNode, varText);
     variableNode.appendChild(this._createNode("span", firstOpts, result));
 
-    // If we saw a ",", then append it and show the remainder using
-    // the correct highlighting.
     if (sawComma) {
       variableNode.appendChild(this.doc.createTextNode(","));
-
-      // Parse the text up until the close paren, being sure to
-      // disable the special case for filter.
-      let subOptions = Object.assign({}, options);
-      subOptions.expectFilter = false;
-      let saveParsed = this.parsed;
-      this.parsed = [];
-      let rest = this._doParse(text, subOptions, tokenStream, true);
-      this.parsed = saveParsed;
-
       let span = this._createNode("span", secondOpts);
       span.appendChild(rest);
       variableNode.appendChild(span);
     }
+
     variableNode.appendChild(this.doc.createTextNode(")"));
 
     return variableNode;
   },
 
   /* eslint-disable complexity */
   /**
    * The workhorse for @see _parse. This parses some CSS text,
@@ -375,16 +385,29 @@ OutputParser.prototype = {
                      this._isDisplayGrid(text, token, options)) {
             this._appendGrid(token.text, options);
           } else if (colorOK() &&
                      colorUtils.isValidCSSColor(token.text, this.cssColor4)) {
             this._appendColor(token.text, options);
           } else if (angleOK(token.text)) {
             this._appendAngle(token.text, options);
           } else {
+            if (options.expectVar) {
+              let variableNode = this._createNode("span", {});
+              if (text.substring(token.startOffset, token.endOffset).startsWith("--")) {
+                let val = options.isVariableInUse(text.substring(token.startOffset,
+                                                  token.endOffset)) || null;
+                this._appendVariable(val, variableNode);
+                this.parsed.push(variableNode);
+                this._computedVariable = val;
+              } else {
+                this._computedVariable = text.substring(token.startOffset,
+                                                        token.endOffset);
+              }
+            }
             this._appendTextNode(text.substring(token.startOffset,
                                                 token.endOffset));
           }
           break;
 
         case "id":
         case "hash": {
           let original = text.substring(token.startOffset, token.endOffset);
@@ -1178,16 +1201,33 @@ OutputParser.prototype = {
 
       container.appendChild(value);
       this.parsed.push(container);
     } else {
       this._appendTextNode(color);
     }
   },
 
+  _appendVariable: function (variable, node) {
+    let swatch;
+    if (variable === null) {
+      swatch = this._createNode("span", {
+        class: "ruleview-swatch ruleview-variableswatch-unmatched",
+        title: "Cannot be resolved"
+      });
+    } else {
+      swatch = this._createNode("span", {
+        class: "ruleview-swatch ruleview-variableswatch-matched",
+        title: variable
+      });
+    }
+    node.appendChild(swatch);
+    return node;
+  },
+
   /**
    * Wrap some existing nodes in a filter editor.
    *
    * @param {String} filters
    *        The full text of the "filter" property.
    * @param {object} options
    *        The options object passed to parseCssProperty().
    * @param {object} nodes
--- a/devtools/client/themes/rules.css
+++ b/devtools/client/themes/rules.css
@@ -471,16 +471,29 @@
 }
 
 .ruleview-shape {
   background: url("chrome://devtools/skin/images/tool-shadereditor.svg");
   border-radius: 0;
   background-size: 1em;
 }
 
+/* Temporarily use meaningless svg, replace in future */
+.ruleview-variableswatch-matched {
+  background: url("chrome://devtools/skin/images/grid.svg");
+  border-radius: 0;
+}
+
+/* Temporarily use meaningless svg, replace in future */
+.ruleview-variableswatch-unmatched {
+  background: url("chrome://devtools/skin/images/tool-shadereditor.svg");
+  border-radius: 0;
+  background-size: 1em;
+}
+
 .ruleview-shape-point.active {
   background-color: var(--rule-highlight-background-color);
 }
 
 .ruleview-colorswatch::before {
   content: '';
   background-color: #eee;
   background-image: linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%, #ccc),