Web Inspector: [PARITY] Styles Redesign: Add color gradient, bezier curve, and spring...
authornvasilyev@apple.com <nvasilyev@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 25 Oct 2017 21:09:45 +0000 (21:09 +0000)
committernvasilyev@apple.com <nvasilyev@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 25 Oct 2017 21:09:45 +0000 (21:09 +0000)
https://bugs.webkit.org/show_bug.cgi?id=178404
<rdar://problem/35035992>

Reviewed by Devin Rousso.

Add inline widgets for the following CSS values:
- Gradients, e.g. `background-image: linear-gradient(yellow, orange)`
- Bezier curves, e.g. `transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55)`
- Spring functions, e.g. `transition-timing-function: spring(1, 2, 2, 4)`

* UserInterface/Models/Color.js:
(WI.Color.prototype.toString):
Don't throw. The are never try/catch blocks on the callsites.

* UserInterface/Views/SpreadsheetStyleProperty.js:
(WI.SpreadsheetStyleProperty.prototype._renderValue):
(WI.SpreadsheetStyleProperty.prototype._createInlineSwatch):
(WI.SpreadsheetStyleProperty.prototype._addGradientTokens):
(WI.SpreadsheetStyleProperty.prototype._addColorTokens):
(WI.SpreadsheetStyleProperty.prototype._addTimingFunctionTokens):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@223978 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Models/Color.js
Source/WebInspectorUI/UserInterface/Views/SpreadsheetStyleProperty.js

index 456f7b3..296c339 100644 (file)
@@ -1,5 +1,29 @@
 2017-10-25  Nikita Vasilyev  <nvasilyev@apple.com>
 
+        Web Inspector: [PARITY] Styles Redesign: Add color gradient, bezier curve, and spring inline widgets
+        https://bugs.webkit.org/show_bug.cgi?id=178404
+        <rdar://problem/35035992>
+
+        Reviewed by Devin Rousso.
+
+        Add inline widgets for the following CSS values:
+        - Gradients, e.g. `background-image: linear-gradient(yellow, orange)`
+        - Bezier curves, e.g. `transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55)`
+        - Spring functions, e.g. `transition-timing-function: spring(1, 2, 2, 4)`
+
+        * UserInterface/Models/Color.js:
+        (WI.Color.prototype.toString):
+        Don't throw. The are never try/catch blocks on the callsites.
+
+        * UserInterface/Views/SpreadsheetStyleProperty.js:
+        (WI.SpreadsheetStyleProperty.prototype._renderValue):
+        (WI.SpreadsheetStyleProperty.prototype._createInlineSwatch):
+        (WI.SpreadsheetStyleProperty.prototype._addGradientTokens):
+        (WI.SpreadsheetStyleProperty.prototype._addColorTokens):
+        (WI.SpreadsheetStyleProperty.prototype._addTimingFunctionTokens):
+
+2017-10-25  Nikita Vasilyev  <nvasilyev@apple.com>
+
         Web Inspector: Styles Redesign: Newly added invalid property isn't immediately shown as invalid
         https://bugs.webkit.org/show_bug.cgi?id=178488
 
index 8ad5794..6889489 100644 (file)
@@ -379,7 +379,8 @@ WI.Color = class Color
             return this._toKeywordString();
         }
 
-        throw "invalid color format";
+        console.error("Invalid color format: " + format);
+        return "";
     }
 
     isKeyword()
index fc1a446..0d0f840 100644 (file)
@@ -253,9 +253,11 @@ WI.SpreadsheetStyleProperty = class SpreadsheetStyleProperty extends WI.Object
         let tokens = WI.tokenizeCSSValue(value);
 
         if (this._property.enabled) {
-            // Don't show color widgets for CSS gradients, show dedicated gradient widgets instead.
-            // FIXME: <https://webkit.org/b/178404> Web Inspector: [PARITY] Styles Redesign: Add bezier curve, color gradient, and CSS variable inline widgets
+            // FIXME: <https://webkit.org/b/178636> Web Inspector: Styles: Make inline widgets work with CSS functions (var(), calc(), etc.)
+            tokens = this._addGradientTokens(tokens);
             tokens = this._addColorTokens(tokens);
+            tokens = this._addTimingFunctionTokens(tokens, "cubic-bezier");
+            tokens = this._addTimingFunctionTokens(tokens, "spring");
         }
 
         tokens = tokens.map((token) => {
@@ -287,48 +289,79 @@ WI.SpreadsheetStyleProperty = class SpreadsheetStyleProperty extends WI.Object
         this._valueElement.append(...tokens);
     }
 
-    _addColorTokens(tokens)
+    _createInlineSwatch(type, text, valueObject)
     {
-        let newTokens = [];
+        let tokenElement = document.createElement("span");
+        let innerElement = document.createElement("span");
+        innerElement.textContent = text;
 
-        let createColorTokenElement = (colorString, color) => {
-            let colorTokenElement = document.createElement("span");
-            colorTokenElement.className = "token-color";
+        let readOnly = !this._property.editable;
+        let swatch = new WI.InlineSwatch(type, valueObject, readOnly);
 
-            let innerElement = document.createElement("span");
-            innerElement.className = "token-color-value";
-            innerElement.textContent = colorString;
+        swatch.addEventListener(WI.InlineSwatch.Event.ValueChanged, (event) => {
+            let value = event.data.value && event.data.value.toString();
+            if (!value)
+                return;
 
-            if (color) {
-                let readOnly = !this._property.editable;
-                let swatch = new WI.InlineSwatch(WI.InlineSwatch.Type.Color, color, readOnly);
+            innerElement.textContent = value;
+            this._handleValueChange();
+        }, this);
 
-                swatch.addEventListener(WI.InlineSwatch.Event.ValueChanged, (event) => {
-                    let value = event.data && event.data.value && event.data.value.toString();
-                    console.assert(value, "Color value is empty.");
-                    if (!value)
-                        return;
+        tokenElement.append(swatch.element, innerElement);
 
-                    innerElement.textContent = value;
-                    this._handleValueChange();
-                }, this);
+        // Prevent the value from editing when clicking on the swatch.
+        swatch.element.addEventListener("mousedown", (event) => { event.stop(); });
 
-                colorTokenElement.append(swatch.element);
+        return tokenElement;
+    }
 
-                // Prevent the value from editing when clicking on the swatch.
-                swatch.element.addEventListener("mousedown", (event) => { event.stop(); });
-            }
+    _addGradientTokens(tokens)
+    {
+        let gradientRegex = /^(repeating-)?(linear|radial)-gradient$/i;
+        let newTokens = [];
+        let gradientStartIndex = NaN;
+        let openParenthesis = 0;
 
-            colorTokenElement.append(innerElement);
-            return colorTokenElement;
-        };
+        for (let i = 0; i < tokens.length; i++) {
+            let token = tokens[i];
+            if (token.type && token.type.includes("atom") && gradientRegex.test(token.value)) {
+                gradientStartIndex = i;
+                openParenthesis = 0;
+            } else if (token.value === "(" && !isNaN(gradientStartIndex))
+                openParenthesis++;
+            else if (token.value === ")" && !isNaN(gradientStartIndex)) {
+                openParenthesis--;
+                if (openParenthesis > 0) {
+                    // Matched a CSS function inside of the gradient.
+                    continue;
+                }
+
+                let rawTokens = tokens.slice(gradientStartIndex, i + 1);
+                let text = rawTokens.map((token) => token.value).join("");
+                let gradient = WI.Gradient.fromString(text);
+                if (gradient)
+                    newTokens.push(this._createInlineSwatch(WI.InlineSwatch.Type.Gradient, text, gradient));
+                else
+                    newTokens.push(...rawTokens);
+
+                gradientStartIndex = NaN;
+            } else if (isNaN(gradientStartIndex))
+                newTokens.push(token);
+        }
 
-        let pushPossibleColorToken = (text, ...tokens) => {
+        return newTokens;
+    }
+
+    _addColorTokens(tokens)
+    {
+        let newTokens = [];
+
+        let pushPossibleColorToken = (text, ...rawTokens) => {
             let color = WI.Color.fromString(text);
             if (color)
-                newTokens.push(createColorTokenElement(text, color));
+                newTokens.push(this._createInlineSwatch(WI.InlineSwatch.Type.Color, text, color));
             else
-                newTokens.push(...tokens);
+                newTokens.push(...rawTokens);
         };
 
         let colorFunctionStartIndex = NaN;
@@ -360,6 +393,51 @@ WI.SpreadsheetStyleProperty = class SpreadsheetStyleProperty extends WI.Object
         return newTokens;
     }
 
+    _addTimingFunctionTokens(tokens, tokenType)
+    {
+        let newTokens = [];
+        let startIndex = NaN;
+        let openParenthesis = 0;
+
+        for (let i = 0; i < tokens.length; i++) {
+            let token = tokens[i];
+            if (token.value === tokenType && token.type && token.type.includes("atom")) {
+                startIndex = i;
+                openParenthesis = 0;
+            } else if (token.value === "(" && !isNaN(startIndex))
+                openParenthesis++;
+            else if (token.value === ")" && !isNaN(startIndex)) {
+
+                openParenthesis--;
+                if (openParenthesis > 0)
+                    continue;
+
+                let rawTokens = tokens.slice(startIndex, i + 1);
+                let text = rawTokens.map((token) => token.value).join("");
+
+                let valueObject;
+                let inlineSwatchType;
+                if (tokenType === "cubic-bezier") {
+                    valueObject = WI.CubicBezier.fromString(text);
+                    inlineSwatchType = WI.InlineSwatch.Type.Bezier;
+                } else if (tokenType === "spring") {
+                    valueObject = WI.Spring.fromString(text);
+                    inlineSwatchType = WI.InlineSwatch.Type.Spring;
+                }
+
+                if (valueObject)
+                    newTokens.push(this._createInlineSwatch(inlineSwatchType, text, valueObject));
+                else
+                    newTokens.push(...rawTokens);
+
+                startIndex = NaN;
+            } else if (isNaN(startIndex))
+                newTokens.push(token);
+        }
+
+        return newTokens;
+    }
+
     _handleNameChange()
     {
         this._property.name = this._nameElement.textContent.trim();