Title: [211057] trunk/Source/WebInspectorUI
Revision
211057
Author
[email protected]
Date
2017-01-23 13:27:26 -0800 (Mon, 23 Jan 2017)

Log Message

Web Inspector: color picker should feature an editable CSS value
https://bugs.webkit.org/show_bug.cgi?id=124356

Patch by Devin Rousso <[email protected]> on 2017-01-23
Reviewed by Timothy Hatcher.

* UserInterface/Views/ColorPicker.css:
(.color-picker):
(.color-picker.hide-inputs):
(.color-picker > .color-inputs):
(.color-picker > .color-inputs > div):
(.color-picker > .color-inputs > div[hidden]):
(.color-picker > .color-inputs input):

* UserInterface/Views/ColorPicker.js:
(WebInspector.ColorPicker.createColorInput):
(WebInspector.ColorPicker):
(WebInspector.ColorPicker.prototype.set color):
(WebInspector.ColorPicker.prototype.set enableColorComponentInputs):
(WebInspector.ColorPicker.prototype._updateColor):
(WebInspector.ColorPicker.prototype._handleFormatChange):
(WebInspector.ColorPicker.prototype._showColorComponentInputs.updateColorInput):
(WebInspector.ColorPicker.prototype._showColorComponentInputs):
(WebInspector.ColorPicker.prototype._handleColorInputInput):
Add an input element (with a label for the component name and its units) for each component
as part of the current color format (e.g. R, G, B, A).  If any of these inputs are changed
then the color is also changed and the "ColorChanged" event is fired.

* UserInterface/Controllers/CodeMirrorColorEditingController.js:
(WebInspector.CodeMirrorColorEditingController.prototype.popoverWillPresent):
* UserInterface/Views/InlineSwatch.js:
(WebInspector.InlineSwatch.prototype._swatchElementClicked):
Add FormatChanged event that fires whenever a new color is set with a different format or
the color value is set for the first time (there is no old format to compare to).  This is
needed because if the format becomes RGB, RGBA, HSL, or HSLA from something not in that list
then the size of the containing popover needs to change since the newly added color inputs
will be displayed.

* UserInterface/Views/GradientEditor.js:
(WebInspector.GradientEditor):
Prevent the color inputs from displaying at all, since there aren't individual swatches for
each color in a gradient.

Modified Paths

Diff

Modified: trunk/Source/WebInspectorUI/ChangeLog (211056 => 211057)


--- trunk/Source/WebInspectorUI/ChangeLog	2017-01-23 21:22:13 UTC (rev 211056)
+++ trunk/Source/WebInspectorUI/ChangeLog	2017-01-23 21:27:26 UTC (rev 211057)
@@ -1,3 +1,47 @@
+2017-01-23  Devin Rousso  <[email protected]>
+
+        Web Inspector: color picker should feature an editable CSS value
+        https://bugs.webkit.org/show_bug.cgi?id=124356
+
+        Reviewed by Timothy Hatcher.
+
+        * UserInterface/Views/ColorPicker.css:
+        (.color-picker):
+        (.color-picker.hide-inputs):
+        (.color-picker > .color-inputs):
+        (.color-picker > .color-inputs > div):
+        (.color-picker > .color-inputs > div[hidden]):
+        (.color-picker > .color-inputs input):
+
+        * UserInterface/Views/ColorPicker.js:
+        (WebInspector.ColorPicker.createColorInput):
+        (WebInspector.ColorPicker):
+        (WebInspector.ColorPicker.prototype.set color):
+        (WebInspector.ColorPicker.prototype.set enableColorComponentInputs):
+        (WebInspector.ColorPicker.prototype._updateColor):
+        (WebInspector.ColorPicker.prototype._handleFormatChange):
+        (WebInspector.ColorPicker.prototype._showColorComponentInputs.updateColorInput):
+        (WebInspector.ColorPicker.prototype._showColorComponentInputs):
+        (WebInspector.ColorPicker.prototype._handleColorInputInput):
+        Add an input element (with a label for the component name and its units) for each component
+        as part of the current color format (e.g. R, G, B, A).  If any of these inputs are changed
+        then the color is also changed and the "ColorChanged" event is fired.
+
+        * UserInterface/Controllers/CodeMirrorColorEditingController.js:
+        (WebInspector.CodeMirrorColorEditingController.prototype.popoverWillPresent):
+        * UserInterface/Views/InlineSwatch.js:
+        (WebInspector.InlineSwatch.prototype._swatchElementClicked):
+        Add FormatChanged event that fires whenever a new color is set with a different format or 
+        the color value is set for the first time (there is no old format to compare to).  This is
+        needed because if the format becomes RGB, RGBA, HSL, or HSLA from something not in that list
+        then the size of the containing popover needs to change since the newly added color inputs
+        will be displayed.
+
+        * UserInterface/Views/GradientEditor.js:
+        (WebInspector.GradientEditor):
+        Prevent the color inputs from displaying at all, since there aren't individual swatches for
+        each color in a gradient.
+
 2017-01-20  Devin Rousso  <[email protected]>
 
         Web Inspector: Search Tab should display search results immediately when closing and reopening Inspector

Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/CodeMirrorColorEditingController.js (211056 => 211057)


--- trunk/Source/WebInspectorUI/UserInterface/Controllers/CodeMirrorColorEditingController.js	2017-01-23 21:22:13 UTC (rev 211056)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/CodeMirrorColorEditingController.js	2017-01-23 21:27:26 UTC (rev 211057)
@@ -46,6 +46,7 @@
     {
         this._colorPicker = new WebInspector.ColorPicker;
         this._colorPicker.addEventListener(WebInspector.ColorPicker.Event.ColorChanged, this._colorPickerColorChanged, this);
+        this._colorPicker.addEventListener(WebInspector.ColorPicker.Event.FormatChanged, (event) => popover.update());
         popover.content = this._colorPicker.element;
     }
 

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ColorPicker.css (211056 => 211057)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ColorPicker.css	2017-01-23 21:22:13 UTC (rev 211056)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ColorPicker.css	2017-01-23 21:27:26 UTC (rev 211057)
@@ -26,10 +26,14 @@
 .color-picker {
     position: relative;
     width: 256px;
-    height: 210px;
+    height: 236px;
     padding: 5px;
 }
 
+.color-picker.hide-inputs {
+    height: 210px;
+}
+
 .color-picker > * {
     position: absolute;
 }
@@ -53,3 +57,27 @@
 .color-picker > .opacity {
     left: 238px;
 }
+
+.color-picker > .color-inputs {
+    display: flex;
+    justify-content: space-between;
+    top: 212px;
+    right: 0;
+    left: 0;
+}
+
+.color-picker > .color-inputs > div {
+    display: flex;
+    align-items: center;
+    width: 100%;
+    margin: 0 4px;
+}
+
+.color-picker > .color-inputs > div[hidden] {
+    display: none;
+}
+
+.color-picker > .color-inputs input {
+    width: 100%;
+    margin: 0 0.25em;
+}

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ColorPicker.js (211056 => 211057)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ColorPicker.js	2017-01-23 21:22:13 UTC (rev 211056)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ColorPicker.js	2017-01-23 21:27:26 UTC (rev 211057)
@@ -41,19 +41,53 @@
         this._opacitySlider.delegate = this;
         this._opacitySlider.element.classList.add("opacity");
 
+        let colorInputsContainerElement = document.createElement("div");
+        colorInputsContainerElement.classList.add("color-inputs");
+
+        function createColorInput(label, {min: min = 0, max: max = 100, step: step = 1, units} = {}) {
+            let containerElement = colorInputsContainerElement.createChild("div");
+
+            containerElement.append(label);
+
+            let numberInputElement = containerElement.createChild("input");
+            numberInputElement.type = "number";
+            numberInputElement.min = min;
+            numberInputElement.max = max;
+            numberInputElement.step = step;
+            numberInputElement.addEventListener("input", this._handleColorInputInput.bind(this));
+
+            if (units && units.length)
+                containerElement.append(units);
+
+            return {containerElement, numberInputElement};
+        }
+
+        this._colorInputs = new Map([
+            ["R", createColorInput.call(this, "R", {max: 255})],
+            ["G", createColorInput.call(this, "G", {max: 255})],
+            ["B", createColorInput.call(this, "B", {max: 255})],
+            ["H", createColorInput.call(this, "H", {max: 360})],
+            ["S", createColorInput.call(this, "S", {units: "%"})],
+            ["L", createColorInput.call(this, "L", {units: "%"})],
+            ["A", createColorInput.call(this, "A"), {max: 1, step: 0.01}]
+        ]);
+
         this._element = document.createElement("div");
-        this._element.className = "color-picker";
+        this._element.classList.add("color-picker");
 
         this._element.appendChild(this._colorWheel.element);
         this._element.appendChild(this._brightnessSlider.element);
         this._element.appendChild(this._opacitySlider.element);
+        this._element.appendChild(colorInputsContainerElement);
 
         this._opacity = 0;
         this._opacityPattern = "url(Images/Checkers.svg)";
 
-        this._color = "white";
+        this._color = WebInspector.Color.fromString("white");
 
         this._dontUpdateColor = false;
+
+        this._enableColorComponentInputs = true;
     }
 
     // Public
@@ -95,19 +129,35 @@
 
     set color(color)
     {
+        console.assert(color instanceof WebInspector.Color);
+
         this._dontUpdateColor = true;
 
-        this._colorFormat = color.format;
+        let formatChanged = !this._color || this._color.format !== color.format;
 
-        this._colorWheel.tintedColor = color;
+        this._color = color;
+
+        this._colorWheel.tintedColor = this._color;
         this._brightnessSlider.value = this._colorWheel.brightness;
 
-        this._opacitySlider.value = color.alpha;
-        this._updateSliders(this._colorWheel.rawColor, color);
+        this._opacitySlider.value = this._color.alpha;
+        this._updateSliders(this._colorWheel.rawColor, this._color);
 
+        this._showColorComponentInputs();
+
+        if (formatChanged)
+            this._handleFormatChange();
+
         this._dontUpdateColor = false;
     }
 
+    set enableColorComponentInputs(value)
+    {
+        this._enableColorComponentInputs = value;
+
+        this._showColorComponentInputs();
+    }
+
     colorWheelColorDidChange(colorWheel)
     {
         this._updateColor();
@@ -129,16 +179,30 @@
         if (this._dontUpdateColor)
             return;
 
-        var opacity = Math.round(this._opacity * 100) / 100;
+        let opacity = Math.round(this._opacity * 100) / 100;
 
-        var components;
-        if (this._colorFormat === WebInspector.Color.Format.HSL || this._colorFormat === WebInspector.Color.Format.HSLA)
+        let format = this._color.format;
+        let components = null;
+        if (format === WebInspector.Color.Format.HSL || format === WebInspector.Color.Format.HSLA) {
             components = this._colorWheel.tintedColor.hsl.concat(opacity);
-        else
+            if (opacity !== 1)
+                format = WebInspector.Color.Format.HSLA;
+        } else {
             components = this._colorWheel.tintedColor.rgb.concat(opacity);
+            if (opacity !== 1 && format === WebInspector.Color.Format.RGB)
+                format = WebInspector.Color.Format.RGBA;
+        }
 
-        this._color = new WebInspector.Color(this._colorFormat, components);
+        let formatChanged = this._color.format === format;
+
+        this._color = new WebInspector.Color(format, components);
+
+        this._showColorComponentInputs();
+
         this.dispatchEventToListeners(WebInspector.ColorPicker.Event.ColorChanged, {color: this._color});
+
+        if (formatChanged)
+            this._handleFormatChange();
     }
 
     _updateSliders(rawColor, tintedColor)
@@ -150,8 +214,124 @@
         this._opacitySlider.element.style.backgroundImage = "linear-gradient(90deg, " + transparent + ", " + opaque + "), " + this._opacityPattern;
         this._brightnessSlider.element.style.backgroundImage = "linear-gradient(90deg, black, " + rawColor + ")";
     }
+
+    _handleFormatChange()
+    {
+        this._element.classList.toggle("hide-inputs", this._color.format !== WebInspector.Color.Format.Keyword
+            && this._color.format !== WebInspector.Color.Format.RGB
+            && this._color.format !== WebInspector.Color.Format.RGBA
+            && this._color.format !== WebInspector.Color.Format.HEX
+            && this._color.format !== WebInspector.Color.Format.ShortHEX
+            && this._color.format !== WebInspector.Color.Format.HEXAlpha
+            && this._color.format !== WebInspector.Color.Format.ShortHEXAlpha
+            && this._color.format !== WebInspector.Color.Format.HSL
+            && this._color.format !== WebInspector.Color.Format.HSLA);
+
+        this.dispatchEventToListeners(WebInspector.ColorPicker.Event.FormatChanged);
+    }
+
+    _showColorComponentInputs()
+    {
+        for (let {containerElement} of this._colorInputs.values())
+            containerElement.hidden = true;
+
+        if (!this._enableColorComponentInputs)
+            return;
+
+        function updateColorInput(key, value) {
+            let {containerElement, numberInputElement} = this._colorInputs.get(key);
+            numberInputElement.value = value;
+            containerElement.hidden = false;
+        }
+
+        switch (this._color.format) {
+        case WebInspector.Color.Format.RGB:
+        case WebInspector.Color.Format.RGBA:
+        case WebInspector.Color.Format.HEX:
+        case WebInspector.Color.Format.ShortHEX:
+        case WebInspector.Color.Format.HEXAlpha:
+        case WebInspector.Color.Format.ShortHEXAlpha:
+        case WebInspector.Color.Format.Keyword:
+            var [r, g, b] = this._color.rgb;
+            updateColorInput.call(this, "R", r);
+            updateColorInput.call(this, "G", g);
+            updateColorInput.call(this, "B", b);
+            break;
+
+        case WebInspector.Color.Format.HSL:
+        case WebInspector.Color.Format.HSLA:
+            var [h, s, l] = this._color.hsl;
+            updateColorInput.call(this, "H", h);
+            updateColorInput.call(this, "S", s);
+            updateColorInput.call(this, "L", l);
+            break;
+
+        default:
+            return;
+        }
+
+        if ((this._color.format === WebInspector.Color.Format.Keyword && this._color.alpha !== 1)
+            || this._color.format === WebInspector.Color.Format.RGBA
+            || this._color.format === WebInspector.Color.Format.HSLA
+            || this._color.format === WebInspector.Color.Format.HEXAlpha
+            || this._color.format === WebInspector.Color.Format.ShortHEXAlpha) {
+            updateColorInput.call(this, "A", this._color.alpha);
+        }
+    }
+
+    _handleColorInputInput(event)
+    {
+        if (!this._enableColorComponentInputs) {
+            WebInspector.reportInternalError("Input event fired for disabled color component input");
+            return;
+        }
+
+        let r = this._colorInputs.get("R").numberInputElement.value;
+        let g = this._colorInputs.get("G").numberInputElement.value;
+        let b = this._colorInputs.get("B").numberInputElement.value;
+        let h = this._colorInputs.get("H").numberInputElement.value;
+        let s = this._colorInputs.get("S").numberInputElement.value;
+        let l = this._colorInputs.get("L").numberInputElement.value;
+        let a = this._colorInputs.get("A").numberInputElement.value;
+
+        let colorString = "";
+        let oldFormat = this._color.format;
+
+        switch (oldFormat) {
+        case WebInspector.Color.Format.RGB:
+        case WebInspector.Color.Format.HEX:
+        case WebInspector.Color.Format.ShortHEX:
+        case WebInspector.Color.Format.Keyword:
+            colorString = `rgb(${r}, ${g}, ${b})`;
+            break;
+
+        case WebInspector.Color.Format.RGBA:
+        case WebInspector.Color.Format.HEXAlpha:
+        case WebInspector.Color.Format.ShortHEXAlpha:
+            colorString = `rgba(${r}, ${g}, ${b}, ${a})`;
+            break;
+
+        case WebInspector.Color.Format.HSL:
+            colorString = `hsl(${h}, ${s}%, ${l}%)`;
+            break;
+
+        case WebInspector.Color.Format.HSLA:
+            colorString = `hsla(${h}, ${s}%, ${l}%, ${a})`;
+            break;
+
+        default:
+            WebInspector.reportInternalError(`Input event fired for invalid color format "${this._color.format}"`);
+            return;
+        }
+
+        this.color = WebInspector.Color.fromString(colorString);
+        this._color.format = oldFormat;
+
+        this.dispatchEventToListeners(WebInspector.ColorPicker.Event.ColorChanged, {color: this._color});
+    }
 };
 
 WebInspector.ColorPicker.Event = {
-    ColorChanged: "css-color-picker-color-changed"
+    ColorChanged: "css-color-picker-color-changed",
+    FormatChanged: "css-color-picker-format-changed",
 };

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/GradientEditor.js (211056 => 211057)


--- trunk/Source/WebInspectorUI/UserInterface/Views/GradientEditor.js	2017-01-23 21:22:13 UTC (rev 211056)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/GradientEditor.js	2017-01-23 21:27:26 UTC (rev 211057)
@@ -72,6 +72,7 @@
 
         this._colorPicker = new WebInspector.ColorPicker;
         this._colorPicker.colorWheel.dimension = 190;
+        this._colorPicker.enableColorComponentInputs = false;
         this._colorPicker.addEventListener(WebInspector.ColorPicker.Event.ColorChanged, this._colorPickerColorChanged, this);
 
         let angleLabel = this._element.appendChild(document.createElement("label"));

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/InlineSwatch.js (211056 => 211057)


--- trunk/Source/WebInspectorUI/UserInterface/Views/InlineSwatch.js	2017-01-23 21:22:13 UTC (rev 211056)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/InlineSwatch.js	2017-01-23 21:27:26 UTC (rev 211057)
@@ -165,6 +165,7 @@
         } else {
             this._valueEditor = new WebInspector.ColorPicker;
             this._valueEditor.addEventListener(WebInspector.ColorPicker.Event.ColorChanged, this._valueEditorValueDidChange, this);
+            this._valueEditor.addEventListener(WebInspector.ColorPicker.Event.FormatChanged, (event) => popover.update());
         }
 
         popover.content = this._valueEditor.element;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to