Web Inspector: add context menu items to switch CSS color property value syntax betwe...
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 5 Jan 2016 01:48:00 +0000 (01:48 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 5 Jan 2016 01:48:00 +0000 (01:48 +0000)
https://bugs.webkit.org/show_bug.cgi?id=151918

Patch by Devin Rousso <dcrousso+webkit@gmail.com> on 2016-01-04
Reviewed by Timothy Hatcher.

Source/WebInspectorUI:

Created a ColorSwatch class to hold all functionality for color swatches,
allowing all context menu and popover events to be centralized.

* Localizations/en.lproj/localizedStrings.js:
* UserInterface/Main.html:

* UserInterface/Models/Color.js:
Changed all 'var' to 'let' and 'nickname' to 'keyword' as per the spec.
Mostly mechanical changes.

(WebInspector.Color.prototype.isKeyword):
Looks at the RGB values of each keyword to see if the current color
matches any of them.

(WebInspector.Color.prototype.canBeSerializedAsShortHEX):
Fixed to account for alpha values, since HEXAlpha is now supported.

* UserInterface/Views/CSSStyleDeclarationTextEditor.css:
(.css-style-text-editor > .CodeMirror .CodeMirror-lines .color-swatch): Deleted.
(@media (-webkit-max-device-pixel-ratio: 1)): Deleted.
(.css-style-text-editor > .CodeMirror .CodeMirror-lines .color-swatch > span): Deleted.
(.css-style-text-editor > .CodeMirror .CodeMirror-lines .color-swatch:hover > span): Deleted.
(.css-style-text-editor > .CodeMirror .CodeMirror-lines .color-swatch:active > span): Deleted.

* UserInterface/Views/CSSStyleDeclarationTextEditor.js:
(WebInspector.CSSStyleDeclarationTextEditor.prototype._createColorSwatches.update):
(WebInspector.CSSStyleDeclarationTextEditor.prototype._createColorSwatches):
(WebInspector.CSSStyleDeclarationTextEditor.prototype._colorSwatchColorChanged.update):
(WebInspector.CSSStyleDeclarationTextEditor.prototype._colorSwatchColorChanged):
(WebInspector.CSSStyleDeclarationTextEditor.prototype._colorSwatchClicked.updateCodeMirror.update): Deleted.
(WebInspector.CSSStyleDeclarationTextEditor.prototype._colorSwatchClicked.updateCodeMirror): Deleted.
(WebInspector.CSSStyleDeclarationTextEditor.prototype._colorSwatchClicked): Deleted.

* UserInterface/Views/ColorSwatch.css: Copied from Source/WebInspectorUI/UserInterface/Views/VisualStyleColorPicker.css.
(.color-swatch):
(@media (-webkit-max-device-pixel-ratio: 1)):
(.color-swatch > span):
(.color-swatch:hover > span):
(.color-swatch:active > span):

* UserInterface/Views/ColorSwatch.js: Added.
(WebInspector.ColorSwatch):
(WebInspector.ColorSwatch.prototype.get element):
(WebInspector.ColorSwatch.prototype.set color):
(WebInspector.ColorSwatch.prototype.get color):
(WebInspector.ColorSwatch.prototype._colorSwatchClicked):
(WebInspector.ColorSwatch.prototype._colorPickerColorDidChange):
(WebInspector.ColorSwatch.prototype._handleContextMenuEvent):
(WebInspector.ColorSwatch.prototype._getNextValidHEXFormat.hexMatchesCurrentColor):
(WebInspector.ColorSwatch.prototype._getNextValidHEXFormat):
Loops through the list of HEX formats to find the first format that is valid
for the current color in the list after the current format.

(WebInspector.ColorSwatch.prototype._updateSwatch):

* UserInterface/Views/VisualStyleColorPicker.css:
(.visual-style-property-container.input-color-picker > .visual-style-property-value-container > .color-swatch):
(.visual-style-property-container.input-color-picker > .visual-style-property-value-container > .color-swatch > span):

* UserInterface/Views/VisualStyleColorPicker.js:
(WebInspector.VisualStyleColorPicker):
(WebInspector.VisualStyleColorPicker.prototype._colorSwatchColorChanged):
(WebInspector.VisualStyleColorPicker.prototype._updateColorSwatch):
(WebInspector.VisualStyleColorPicker.prototype._colorSwatchClicked): Deleted.
(WebInspector.VisualStyleColorPicker.prototype._colorPickerColorDidChange): Deleted.

LayoutTests:

* inspector/model/color-expected.html:
* inspector/model/color.html:
Changed "nickname" to "keyword".

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

13 files changed:
LayoutTests/ChangeLog
LayoutTests/inspector/model/color-expected.txt
LayoutTests/inspector/model/color.html
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
Source/WebInspectorUI/UserInterface/Main.html
Source/WebInspectorUI/UserInterface/Models/Color.js
Source/WebInspectorUI/UserInterface/Views/CSSStyleDeclarationTextEditor.css
Source/WebInspectorUI/UserInterface/Views/CSSStyleDeclarationTextEditor.js
Source/WebInspectorUI/UserInterface/Views/ColorSwatch.css [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Views/ColorSwatch.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Views/VisualStyleColorPicker.css
Source/WebInspectorUI/UserInterface/Views/VisualStyleColorPicker.js

index 6e83ab6..2d9afb9 100644 (file)
@@ -1,3 +1,14 @@
+2016-01-04  Devin Rousso  <dcrousso+webkit@gmail.com>
+
+        Web Inspector: add context menu items to switch CSS color property value syntax between RGB, HSL, etc
+        https://bugs.webkit.org/show_bug.cgi?id=151918
+
+        Reviewed by Timothy Hatcher.
+
+        * inspector/model/color-expected.html:
+        * inspector/model/color.html:
+        Changed "nickname" to "keyword".
+
 2016-01-04  Brady Eidson  <beidson@apple.com>
 
         Modern IDB: Memory indexes aren't deleted when their owning memory object stores are deleted.
index f872309..62d973c 100644 (file)
@@ -52,17 +52,17 @@ PASS: 'hsla(999, 999%, 999%, 999)' was the expected 'HSLA' format
 PASS: 'hsla( 0 , 0% , 50% , 0.5 )' should be detected
 PASS: 'hsla( 0 , 0% , 50% , 0.5 )' was the expected 'HSLA' format
 PASS: 'blue' should be detected
-PASS: 'blue' was the expected 'Nickname' format
+PASS: 'blue' was the expected 'Keyword' format
 PASS: 'BLuE' should be detected
-PASS: 'BLuE' was the expected 'Nickname' format
+PASS: 'BLuE' was the expected 'Keyword' format
 PASS: 'midnightblue' should be detected
-PASS: 'midnightblue' was the expected 'Nickname' format
+PASS: 'midnightblue' was the expected 'Keyword' format
 PASS: 'royalblue' should be detected
-PASS: 'royalblue' was the expected 'Nickname' format
+PASS: 'royalblue' was the expected 'Keyword' format
 PASS: 'steelblue' should be detected
-PASS: 'steelblue' was the expected 'Nickname' format
+PASS: 'steelblue' was the expected 'Keyword' format
 PASS: 'transparent' should be detected
-PASS: 'transparent' was the expected 'Nickname' format
+PASS: 'transparent' was the expected 'Keyword' format
 
 PASS: ' #000 ' should not be detected
 PASS: '#rgb' should not be detected
@@ -80,16 +80,26 @@ PASS: 'superblue' should not be detected
 -- Running test case: WebInspector.Color properties
 PASS: 'red' should have alpha of 1.
 PASS: 'red' should be simple.
+PASS: 'red' should be a keyword.
 PASS: 'red' has rgb of [255, 0, 0].
 PASS: 'red' has rgba of [255, 0, 0, 1].
 PASS: 'red' has hsl of [0, 100, 50].
 PASS: 'red' has hsla of [0, 100, 50, 1].
+PASS: 'red' should be serializable as a short Hex
 PASS: 'transparent' should have alpha of 0.
-PASS: 'transparent' should be not be simple.
+PASS: 'transparent' should not be simple.
+PASS: 'transparent' should be a keyword.
 PASS: 'transparent' has rgb of [0, 0, 0].
 PASS: 'transparent' has rgba of [0, 0, 0, 0].
 PASS: 'transparent' has hsl of [0, 0, 0].
 PASS: 'transparent' has hsla of [0, 0, 0, 0].
+PASS: 'transparent' should be serializable as a short Hex
+PASS: '#11122233' should not have alpha of 0.
+PASS: '#11122233' should be not be simple.
+PASS: '#11122233' should not be a keyword.
+PASS: '#11122233' has rgba of [17, 18, 34, 0.2].
+PASS: '#11122233' has hsla of [236, 33, 10, 0.2].
+PASS: '#11122233' should not be serializable as a short Hex
 
 -- Running test case: WebInspector.Color.prototype.nextFormat
 PASS: All format phases of 'transparent' should be as expected.
@@ -99,7 +109,7 @@ PASS: All format phases of 'rgba(100, 150, 200, 0.5)' should be as expected.
 
 -- Running test case: WebInspector.Color.prototype.toString
 PASS: Color as 'Original' should be 'RED'
-PASS: Color as 'Nickname' should be 'red'
+PASS: Color as 'Keyword' should be 'red'
 PASS: Color as 'Short HEX' should be '#f00'
 PASS: Color as 'HEX' should be '#ff0000'
 PASS: Color as 'Short HEX with Alpha' should be '#f00f'
@@ -109,7 +119,7 @@ PASS: Color as 'RGBA' should be 'rgba(255, 0, 0, 1)'
 PASS: Color as 'HSL' should be 'hsl(0, 100%, 50%)'
 PASS: Color as 'HSLA' should be 'hsla(0, 100%, 50%, 1)'
 PASS: Color as 'Original' should be 'rgba(100, 200, 255, 0.5)'
-PASS: Color as 'Nickname' should be 'rgba(100, 200, 255, 0.5)'
+PASS: Color as 'Keyword' should be 'rgba(100, 200, 255, 0.5)'
 PASS: Color as 'Short HEX' should be 'rgba(100, 200, 255, 0.5)'
 PASS: Color as 'HEX' should be 'rgba(100, 200, 255, 0.5)'
 PASS: Color as 'Short HEX with Alpha' should be '#64c8ff80'
index c0b0796..9a107ae 100644 (file)
@@ -9,8 +9,8 @@ function test()
         switch (format) {
         case WebInspector.Color.Format.Original:
             return "Original";
-        case WebInspector.Color.Format.Nickname:
-            return "Nickname";
+        case WebInspector.Color.Format.Keyword:
+            return "Keyword";
         case WebInspector.Color.Format.HEX:
             return "HEX";
         case WebInspector.Color.Format.ShortHEX:
@@ -80,12 +80,12 @@ function test()
             testGood("hsla(999, 999%, 999%, 999)", WebInspector.Color.Format.HSLA);
             testGood("hsla( 0 , 0% , 50% , 0.5 )", WebInspector.Color.Format.HSLA);
 
-            testGood("blue", WebInspector.Color.Format.Nickname);
-            testGood("BLuE", WebInspector.Color.Format.Nickname);
-            testGood("midnightblue", WebInspector.Color.Format.Nickname);
-            testGood("royalblue", WebInspector.Color.Format.Nickname);
-            testGood("steelblue", WebInspector.Color.Format.Nickname);
-            testGood("transparent", WebInspector.Color.Format.Nickname);
+            testGood("blue", WebInspector.Color.Format.Keyword);
+            testGood("BLuE", WebInspector.Color.Format.Keyword);
+            testGood("midnightblue", WebInspector.Color.Format.Keyword);
+            testGood("royalblue", WebInspector.Color.Format.Keyword);
+            testGood("steelblue", WebInspector.Color.Format.Keyword);
+            testGood("transparent", WebInspector.Color.Format.Keyword);
 
             InspectorTest.log("");
 
@@ -100,7 +100,7 @@ function test()
             testBad("rgba(255, 255, 255, 0.5, 1)"); // extra values
             testBad("hsl(0, 0%, 50%, 1)"); // extra value
             testBad("hsla(0, 0%, 50%, 1, 2)"); // extra values
-            testBad("superblue"); // not a nickname
+            testBad("superblue"); // not a keyword
 
             // FIXME: currentColor?
             // FIXME: Should we consider missing %s as bad? Currently we just strip them.
@@ -132,18 +132,30 @@ function test()
             color = WebInspector.Color.fromString("red");
             InspectorTest.expectThat(color.alpha === 1, "'red' should have alpha of 1.");
             InspectorTest.expectThat(color.simple === true, "'red' should be simple.");
+            InspectorTest.expectThat(color.isKeyword() === true, "'red' should be a keyword.");
             InspectorTest.expectThat(shallowEqual(color.rgb, [255, 0, 0]), "'red' has rgb of [255, 0, 0].");
             InspectorTest.expectThat(shallowEqual(color.rgba, [255, 0, 0, 1]), "'red' has rgba of [255, 0, 0, 1].");
             InspectorTest.expectThat(shallowEqual(color.hsl, [0, 100, 50]), "'red' has hsl of [0, 100, 50].");
             InspectorTest.expectThat(shallowEqual(color.hsla, [0, 100, 50, 1]), "'red' has hsla of [0, 100, 50, 1].");
+            InspectorTest.expectThat(color.canBeSerializedAsShortHEX() === true, "'red' should be serializable as a short Hex");
 
             color = WebInspector.Color.fromString("transparent");
             InspectorTest.expectThat(color.alpha === 0, "'transparent' should have alpha of 0.");
-            InspectorTest.expectThat(color.simple === false, "'transparent' should be not be simple.");
+            InspectorTest.expectThat(color.simple === false, "'transparent' should not be simple.");
+            InspectorTest.expectThat(color.isKeyword() === true, "'transparent' should be a keyword.");
             InspectorTest.expectThat(shallowEqual(color.rgb, [0, 0, 0]), "'transparent' has rgb of [0, 0, 0].");
             InspectorTest.expectThat(shallowEqual(color.rgba, [0, 0, 0, 0]), "'transparent' has rgba of [0, 0, 0, 0].");
             InspectorTest.expectThat(shallowEqual(color.hsl, [0, 0, 0]), "'transparent' has hsl of [0, 0, 0].");
             InspectorTest.expectThat(shallowEqual(color.hsla, [0, 0, 0, 0]), "'transparent' has hsla of [0, 0, 0, 0].");
+            InspectorTest.expectThat(color.canBeSerializedAsShortHEX() === true, "'transparent' should be serializable as a short Hex");
+
+            color = WebInspector.Color.fromString("#11122233");
+            InspectorTest.expectThat(color.alpha !== 0, "'#11122233' should not have alpha of 0.");
+            InspectorTest.expectThat(color.simple === false, "'#11122233' should be not be simple.");
+            InspectorTest.expectThat(color.isKeyword() === false, "'#11122233' should not be a keyword.");
+            InspectorTest.expectThat(shallowEqual(color.rgba, [17, 18, 34, 0.2]), "'#11122233' has rgba of [17, 18, 34, 0.2].");
+            InspectorTest.expectThat(shallowEqual(color.hsla, [236, 33, 10, 0.2]), "'#11122233' has hsla of [236, 33, 10, 0.2].");
+            InspectorTest.expectThat(color.canBeSerializedAsShortHEX() === false, "'#11122233' should not be serializable as a short Hex");
 
             resolve();
         }
@@ -172,7 +184,7 @@ function test()
             test("transparent", [
                 WebInspector.Color.Format.RGBA,
                 WebInspector.Color.Format.HSLA,
-                WebInspector.Color.Format.Nickname,
+                WebInspector.Color.Format.Keyword,
                 WebInspector.Color.Format.ShortHEXAlpha,
                 WebInspector.Color.Format.HEXAlpha,
                 WebInspector.Color.Format.Original,
@@ -182,13 +194,13 @@ function test()
             test("red", [
                 WebInspector.Color.Format.RGB,
                 WebInspector.Color.Format.HSL,
-                WebInspector.Color.Format.Nickname,
+                WebInspector.Color.Format.Keyword,
                 WebInspector.Color.Format.ShortHEX,
                 WebInspector.Color.Format.HEX,
                 WebInspector.Color.Format.Original,
             ]);
 
-            // No short hex or nickname.
+            // No short hex or keyword.
             test("rgb(100, 150, 200)", [
                 WebInspector.Color.Format.RGB,
                 WebInspector.Color.Format.HSL,
@@ -196,7 +208,7 @@ function test()
                 WebInspector.Color.Format.Original,
             ]);
 
-            // No short hex alpha or nickname.
+            // No short hex alpha or keyword.
             test("rgba(100, 150, 200, 0.5)", [
                 WebInspector.Color.Format.RGBA,
                 WebInspector.Color.Format.HSLA,
@@ -222,7 +234,7 @@ function test()
             // A color with all formats.
             color = WebInspector.Color.fromString("RED");
             test("RED", WebInspector.Color.Format.Original);
-            test("red", WebInspector.Color.Format.Nickname);
+            test("red", WebInspector.Color.Format.Keyword);
             test("#f00", WebInspector.Color.Format.ShortHEX);
             test("#ff0000", WebInspector.Color.Format.HEX);
             test("#f00f", WebInspector.Color.Format.ShortHEXAlpha);
@@ -235,7 +247,7 @@ function test()
             // A color which cannot be some formats, those fallback to something else.
             color = WebInspector.Color.fromString("rGbA(  100, 200, 255, 0.5  )");
             test("rgba(100, 200, 255, 0.5)", WebInspector.Color.Format.Original); // Original text ignored for some formats.
-            test("rgba(100, 200, 255, 0.5)", WebInspector.Color.Format.Nickname); // fallback (rgba)
+            test("rgba(100, 200, 255, 0.5)", WebInspector.Color.Format.Keyword); // fallback (rgba)
             test("rgba(100, 200, 255, 0.5)", WebInspector.Color.Format.ShortHEX); // fallback (rgba)
             test("rgba(100, 200, 255, 0.5)", WebInspector.Color.Format.HEX); // fallback (rgba)
             test("#64c8ff80", WebInspector.Color.Format.ShortHEXAlpha); // fallback (hex alpha)
index 5c34d90..608fa80 100644 (file)
@@ -1,3 +1,76 @@
+2016-01-04  Devin Rousso  <dcrousso+webkit@gmail.com>
+
+        Web Inspector: add context menu items to switch CSS color property value syntax between RGB, HSL, etc
+        https://bugs.webkit.org/show_bug.cgi?id=151918
+
+        Reviewed by Timothy Hatcher.
+
+        Created a ColorSwatch class to hold all functionality for color swatches,
+        allowing all context menu and popover events to be centralized.
+
+        * Localizations/en.lproj/localizedStrings.js:
+        * UserInterface/Main.html:
+
+        * UserInterface/Models/Color.js:
+        Changed all 'var' to 'let' and 'nickname' to 'keyword' as per the spec.
+        Mostly mechanical changes.
+
+        (WebInspector.Color.prototype.isKeyword):
+        Looks at the RGB values of each keyword to see if the current color
+        matches any of them.
+
+        (WebInspector.Color.prototype.canBeSerializedAsShortHEX):
+        Fixed to account for alpha values, since HEXAlpha is now supported.
+
+        * UserInterface/Views/CSSStyleDeclarationTextEditor.css:
+        (.css-style-text-editor > .CodeMirror .CodeMirror-lines .color-swatch): Deleted.
+        (@media (-webkit-max-device-pixel-ratio: 1)): Deleted.
+        (.css-style-text-editor > .CodeMirror .CodeMirror-lines .color-swatch > span): Deleted.
+        (.css-style-text-editor > .CodeMirror .CodeMirror-lines .color-swatch:hover > span): Deleted.
+        (.css-style-text-editor > .CodeMirror .CodeMirror-lines .color-swatch:active > span): Deleted.
+
+        * UserInterface/Views/CSSStyleDeclarationTextEditor.js:
+        (WebInspector.CSSStyleDeclarationTextEditor.prototype._createColorSwatches.update):
+        (WebInspector.CSSStyleDeclarationTextEditor.prototype._createColorSwatches):
+        (WebInspector.CSSStyleDeclarationTextEditor.prototype._colorSwatchColorChanged.update):
+        (WebInspector.CSSStyleDeclarationTextEditor.prototype._colorSwatchColorChanged):
+        (WebInspector.CSSStyleDeclarationTextEditor.prototype._colorSwatchClicked.updateCodeMirror.update): Deleted.
+        (WebInspector.CSSStyleDeclarationTextEditor.prototype._colorSwatchClicked.updateCodeMirror): Deleted.
+        (WebInspector.CSSStyleDeclarationTextEditor.prototype._colorSwatchClicked): Deleted.
+
+        * UserInterface/Views/ColorSwatch.css: Copied from Source/WebInspectorUI/UserInterface/Views/VisualStyleColorPicker.css.
+        (.color-swatch):
+        (@media (-webkit-max-device-pixel-ratio: 1)):
+        (.color-swatch > span):
+        (.color-swatch:hover > span):
+        (.color-swatch:active > span):
+
+        * UserInterface/Views/ColorSwatch.js: Added.
+        (WebInspector.ColorSwatch):
+        (WebInspector.ColorSwatch.prototype.get element):
+        (WebInspector.ColorSwatch.prototype.set color):
+        (WebInspector.ColorSwatch.prototype.get color):
+        (WebInspector.ColorSwatch.prototype._colorSwatchClicked):
+        (WebInspector.ColorSwatch.prototype._colorPickerColorDidChange):
+        (WebInspector.ColorSwatch.prototype._handleContextMenuEvent):
+        (WebInspector.ColorSwatch.prototype._getNextValidHEXFormat.hexMatchesCurrentColor):
+        (WebInspector.ColorSwatch.prototype._getNextValidHEXFormat):
+        Loops through the list of HEX formats to find the first format that is valid
+        for the current color in the list after the current format.
+
+        (WebInspector.ColorSwatch.prototype._updateSwatch):
+
+        * UserInterface/Views/VisualStyleColorPicker.css:
+        (.visual-style-property-container.input-color-picker > .visual-style-property-value-container > .color-swatch):
+        (.visual-style-property-container.input-color-picker > .visual-style-property-value-container > .color-swatch > span):
+
+        * UserInterface/Views/VisualStyleColorPicker.js:
+        (WebInspector.VisualStyleColorPicker):
+        (WebInspector.VisualStyleColorPicker.prototype._colorSwatchColorChanged):
+        (WebInspector.VisualStyleColorPicker.prototype._updateColorSwatch):
+        (WebInspector.VisualStyleColorPicker.prototype._colorSwatchClicked): Deleted.
+        (WebInspector.VisualStyleColorPicker.prototype._colorPickerColorDidChange): Deleted.
+
 2016-01-04  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Mark last parameter of webkitGetUserMedia as non-optional to match updated IDL
index 31e0288..67386f0 100644 (file)
Binary files a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js and b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js differ
index b9e5d35..f26e8cc 100644 (file)
@@ -48,6 +48,7 @@
     <link rel="stylesheet" href="Views/ClusterContentView.css">
     <link rel="stylesheet" href="Views/CodeMirrorOverrides.css">
     <link rel="stylesheet" href="Views/ColorPicker.css">
+    <link rel="stylesheet" href="Views/ColorSwatch.css">
     <link rel="stylesheet" href="Views/ColorWheel.css">
     <link rel="stylesheet" href="Views/CompletionSuggestionsView.css">
     <link rel="stylesheet" href="Views/ComputedStyleDetailsPanel.css">
     <script src="Views/CodeMirrorFormatters.js"></script>
     <script src="Views/CodeMirrorTextMarkers.js"></script>
     <script src="Views/ColorPicker.js"></script>
+    <script src="Views/ColorSwatch.js"></script>
     <script src="Views/ColorWheel.js"></script>
     <script src="Views/CompletionSuggestionsView.js"></script>
     <script src="Views/ComputedStyleDetailsPanel.js"></script>
index 68619e3..3755a40 100644 (file)
@@ -45,22 +45,22 @@ WebInspector.Color = class Color
 
     static fromString(colorString)
     {
-        var value = colorString.toLowerCase().replace(/%|\s+/g, "");
-        var transparentNicknames = ["transparent", "rgba(0,0,0,0)", "hsla(0,0,0,0)"];
-        if (transparentNicknames.includes(value)) {
-            var color = new WebInspector.Color(WebInspector.Color.Format.Nickname, [0, 0, 0, 0]);
-            color.nickname = "transparent";
+        let value = colorString.toLowerCase().replace(/%|\s+/g, "");
+        let transparentKeywords = ["transparent", "rgba(0,0,0,0)", "hsla(0,0,0,0)"];
+        if (transparentKeywords.includes(value)) {
+            let color = new WebInspector.Color(WebInspector.Color.Format.Keyword, [0, 0, 0, 0]);
+            color.keyword = "transparent";
             color.original = colorString;
             return color;
         }
 
-        // Simple - #hex, rgb(), nickname, hsl()
-        var simple = /^(?:#([0-9a-f]{3,8})|rgb\(([^)]+)\)|(\w+)|hsl\(([^)]+)\))$/i;
-        var match = colorString.match(simple);
+        // Simple - #hex, rgb(), keyword, hsl()
+        let simple = /^(?:#([0-9a-f]{3,8})|rgb\(([^)]+)\)|(\w+)|hsl\(([^)]+)\))$/i;
+        let match = colorString.match(simple);
         if (match) {
             if (match[1]) { // hex
-                var hex = match[1].toUpperCase();
-                var len = hex.length;
+                let hex = match[1].toUpperCase();
+                let len = hex.length;
                 if (len === 3) {
                     return new WebInspector.Color(WebInspector.Color.Format.ShortHEX, [
                         parseInt(hex.charAt(0) + hex.charAt(0), 16),
@@ -92,7 +92,7 @@ WebInspector.Color = class Color
                 } else
                     return null;
             } else if (match[2]) { // rgb
-                var rgb = match[2].split(/\s*,\s*/);
+                let rgb = match[2].split(/\s*,\s*/);
                 if (rgb.length !== 3)
                     return null;
                 return new WebInspector.Color(WebInspector.Color.Format.RGB, [
@@ -101,17 +101,16 @@ WebInspector.Color = class Color
                     parseInt(rgb[2]),
                     1
                 ]);
-            } else if (match[3]) { // nickname
-                var nickname = match[3].toLowerCase();
-                if (WebInspector.Color.Nicknames.hasOwnProperty(nickname)) {
-                    var color = new WebInspector.Color(WebInspector.Color.Format.Nickname, WebInspector.Color.Nicknames[nickname].concat(1));
-                    color.nickname = nickname;
-                    color.original = colorString;
-                    return color;
-                } else
+            } else if (match[3]) { // keyword
+                let keyword = match[3].toLowerCase();
+                if (!WebInspector.Color.Keywords[keyword])
                     return null;
+                let color = new WebInspector.Color(WebInspector.Color.Format.Keyword, WebInspector.Color.Keywords[keyword].concat(1));
+                color.keyword = keyword;
+                color.original = colorString;
+                return color;
             } else if (match[4]) { // hsl
-                var hsl = match[4].replace(/%/g, "").split(/\s*,\s*/);
+                let hsl = match[4].replace(/%/g, "").split(/\s*,\s*/);
                 if (hsl.length !== 3)
                     return null;
                 return new WebInspector.Color(WebInspector.Color.Format.HSL, [
@@ -124,11 +123,11 @@ WebInspector.Color = class Color
         }
 
         // Advanced - rgba(), hsla()
-        var advanced = /^(?:rgba\(([^)]+)\)|hsla\(([^)]+)\))$/i;
+        let advanced = /^(?:rgba\(([^)]+)\)|hsla\(([^)]+)\))$/i;
         match = colorString.match(advanced);
         if (match) {
             if (match[1]) { // rgba
-                var rgba = match[1].split(/\s*,\s*/);
+                let rgba = match[1].split(/\s*,\s*/);
                 if (rgba.length !== 4)
                     return null;
                 return new WebInspector.Color(WebInspector.Color.Format.RGBA, [
@@ -138,7 +137,7 @@ WebInspector.Color = class Color
                     Number.constrain(parseFloat(rgba[3]), 0, 1)
                 ]);
             } else if (match[2]) { // hsla
-                var hsla = match[2].replace(/%/g, "").split(/\s*,\s*/);
+                let hsla = match[2].replace(/%/g, "").split(/\s*,\s*/);
                 if (hsla.length !== 4)
                     return null;
                 return new WebInspector.Color(WebInspector.Color.Format.HSLA, [
@@ -159,14 +158,15 @@ WebInspector.Color = class Color
         g /= 255;
         b /= 255;
 
-        var min = Math.min(Math.min(r, g), b);
-        var max = Math.max(Math.max(r, g), b);
-        var delta = max - min;
+        let min = Math.min(Math.min(r, g), b);
+        let max = Math.max(Math.max(r, g), b);
+        let delta = max - min;
 
-        var v = max;
-        var s, h;
+        let h;
+        let s;
+        let v = max;
 
-        if (max === min)
+        if (delta === 0)
             h = 0;
         else if (max === r)
             h = (60 * ((g - b) / delta)) % 360;
@@ -193,13 +193,13 @@ WebInspector.Color = class Color
             return [v, v, v];
 
         h /= 60;
-        var i = Math.floor(h);
-        var data = [
+        let i = Math.floor(h);
+        let data = [
             v * (1 - s),
             v * (1 - s * (h - i)),
             v * (1 - s * (1 - (h - i)))
         ];
-        var rgb;
+        let rgb;
 
         switch (i) {
         case 0:
@@ -242,11 +242,11 @@ WebInspector.Color = class Color
 
         case WebInspector.Color.Format.HSL:
         case WebInspector.Color.Format.HSLA:
-            if (this.nickname)
-                return WebInspector.Color.Format.Nickname;
+            if (this.keyword)
+                return WebInspector.Color.Format.Keyword;
             if (this.simple)
-                return this._canBeSerializedAsShortHEX() ? WebInspector.Color.Format.ShortHEX : WebInspector.Color.Format.HEX;
-            return this._canBeSerializedAsShortHEX() ? WebInspector.Color.Format.ShortHEXAlpha : WebInspector.Color.Format.HEXAlpha;
+                return this.canBeSerializedAsShortHEX() ? WebInspector.Color.Format.ShortHEX : WebInspector.Color.Format.HEX;
+            return this.canBeSerializedAsShortHEX() ? WebInspector.Color.Format.ShortHEXAlpha : WebInspector.Color.Format.HEXAlpha;
 
         case WebInspector.Color.Format.ShortHEX:
             return WebInspector.Color.Format.HEX;
@@ -258,10 +258,10 @@ WebInspector.Color = class Color
         case WebInspector.Color.Format.HEXAlpha:
             return WebInspector.Color.Format.Original;
 
-        case WebInspector.Color.Format.Nickname:
+        case WebInspector.Color.Format.Keyword:
             if (this.simple)
-                return this._canBeSerializedAsShortHEX() ? WebInspector.Color.Format.ShortHEX : WebInspector.Color.Format.HEX;
-            return this._canBeSerializedAsShortHEX() ? WebInspector.Color.Format.ShortHEXAlpha : WebInspector.Color.Format.HEXAlpha;
+                return this.canBeSerializedAsShortHEX() ? WebInspector.Color.Format.ShortHEX : WebInspector.Color.Format.HEX;
+            return this.canBeSerializedAsShortHEX() ? WebInspector.Color.Format.ShortHEXAlpha : WebInspector.Color.Format.HEXAlpha;
 
         default:
             console.error("Unknown color format.");
@@ -281,14 +281,14 @@ WebInspector.Color = class Color
 
     get rgb()
     {
-        var rgb = this.rgba.slice();
+        let rgb = this.rgba.slice();
         rgb.pop();
         return rgb;
     }
 
     get hsl()
     {
-        var hsl = this.hsla.slice();
+        let hsl = this.hsla.slice();
         hsl.pop();
         return hsl;
     }
@@ -315,7 +315,7 @@ WebInspector.Color = class Color
         case WebInspector.Color.Format.ShortHEX:
         case WebInspector.Color.Format.HEXAlpha:
         case WebInspector.Color.Format.ShortHEXAlpha:
-        case WebInspector.Color.Format.Nickname:
+        case WebInspector.Color.Format.Keyword:
         case WebInspector.Color.Format.RGBA:
             return new WebInspector.Color(this.format, this.rgba);
         case WebInspector.Color.Format.HSL:
@@ -348,40 +348,77 @@ WebInspector.Color = class Color
             return this._toHEXAlphaString();
         case WebInspector.Color.Format.ShortHEXAlpha:
             return this._toShortHEXAlphaString();
-        case WebInspector.Color.Format.Nickname:
-            return this._toNicknameString();
+        case WebInspector.Color.Format.Keyword:
+            return this._toKeywordString();
         }
 
         throw "invalid color format";
     }
 
+    isKeyword()
+    {
+        if (this.keyword)
+            return true;
+
+        if (!this.simple)
+            return Object.shallowEqual(this._rgba, [0, 0, 0, 0]) || Object.shallowEqual(this._hsla, [0, 0, 0, 0]);
+
+        let rgb = (this._rgba && this._rgba.slice(0, 3)) || this._hslToRGB(this._hsla);
+        return Object.keys(WebInspector.Color.Keywords).some(key => Object.shallowEqual(WebInspector.Color.Keywords[key], rgb));
+    }
+
+    canBeSerializedAsShortHEX()
+    {
+        let rgba = this.rgba || this._hslaToRGBA(this._hsla);
+
+        let r = this._componentToHexValue(rgba[0]);
+        if (r[0] !== r[1])
+            return false;
+
+        let g = this._componentToHexValue(rgba[1]);
+        if (g[0] !== g[1])
+            return false;
+
+        let b = this._componentToHexValue(rgba[2]);
+        if (b[0] !== b[1])
+            return false;
+
+        if (!this.simple) {
+            let a = this._componentToHexValue(Math.round(rgba[3] * 255));
+            if (a[0] !== a[1])
+                return false;
+        }
+
+        return true;
+    }
+
     // Private
 
     _toOriginalString()
     {
-        return this.original || this._toNicknameString();
+        return this.original || this._toKeywordString();
     }
 
-    _toNicknameString()
+    _toKeywordString()
     {
-        if (this.nickname)
-            return this.nickname;
+        if (this.keyword)
+            return this.keyword;
 
-        var rgba = this.rgba;
+        let rgba = this.rgba;
         if (!this.simple) {
             if (rgba[0] === 0 && rgba[1] === 0 && rgba[2] === 0 && rgba[3] === 0)
                 return "transparent";
             return this._toRGBAString();
         }
 
-        var nicknames = WebInspector.Color.Nicknames;
-        for (var nickname in nicknames) {
-            if (!nicknames.hasOwnProperty(nickname))
+        let keywords = WebInspector.Color.Keywords;
+        for (let keyword in keywords) {
+            if (!keywords.hasOwnProperty(keyword))
                 continue;
 
-            var nicknameRGB = nicknames[nickname];
-            if (nicknameRGB[0] === rgba[0] && nicknameRGB[1] === rgba[1] && nicknameRGB[2] === rgba[2])
-                return nickname;
+            let keywordRGB = keywords[keyword];
+            if (keywordRGB[0] === rgba[0] && keywordRGB[1] === rgba[1] && keywordRGB[2] === rgba[2])
+                return keyword;
         }
 
         return this._toRGBString();
@@ -392,10 +429,10 @@ WebInspector.Color = class Color
         if (!this.simple)
             return this._toRGBAString();
 
-        var rgba = this.rgba;
-        var r = this._componentToHexValue(rgba[0]);
-        var g = this._componentToHexValue(rgba[1]);
-        var b = this._componentToHexValue(rgba[2]);
+        let rgba = this.rgba;
+        let r = this._componentToHexValue(rgba[0]);
+        let g = this._componentToHexValue(rgba[1]);
+        let b = this._componentToHexValue(rgba[2]);
 
         if (r[0] === r[1] && g[0] === g[1] && b[0] === b[1])
             return "#" + r[0] + g[0] + b[0];
@@ -408,10 +445,10 @@ WebInspector.Color = class Color
         if (!this.simple)
             return this._toRGBAString();
 
-        var rgba = this.rgba;
-        var r = this._componentToHexValue(rgba[0]);
-        var g = this._componentToHexValue(rgba[1]);
-        var b = this._componentToHexValue(rgba[2]);
+        let rgba = this.rgba;
+        let r = this._componentToHexValue(rgba[0]);
+        let g = this._componentToHexValue(rgba[1]);
+        let b = this._componentToHexValue(rgba[2]);
 
         return "#" + r + g + b;
     }
@@ -446,8 +483,8 @@ WebInspector.Color = class Color
         if (!this.simple)
             return this._toRGBAString();
 
-        var rgba = this.rgba;
-        return "rgb(" + [rgba[0], rgba[1], rgba[2]].join(", ") + ")";
+        let rgba = this.rgba.slice(0, -1);
+        return "rgb(" + rgba.join(", ") + ")";
     }
 
     _toRGBAString()
@@ -460,35 +497,16 @@ WebInspector.Color = class Color
         if (!this.simple)
             return this._toHSLAString();
 
-        var hsla = this.hsla;
+        let hsla = this.hsla;
         return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)";
     }
 
     _toHSLAString()
     {
-        var hsla = this.hsla;
+        let hsla = this.hsla;
         return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, " + hsla[3] + ")";
     }
 
-    _canBeSerializedAsShortHEX()
-    {
-        var rgba = this.rgba;
-
-        var r = this._componentToHexValue(rgba[0]);
-        if (r[0] !== r[1])
-            return false;
-
-        var g = this._componentToHexValue(rgba[1]);
-        if (g[0] !== g[1])
-            return false;
-
-        var b = this._componentToHexValue(rgba[2]);
-        if (b[0] !== b[1])
-            return false;
-
-        return true;
-    }
-
     _componentToNumber(value)
     {
         return Number.constrain(value, 0, 255);
@@ -496,7 +514,7 @@ WebInspector.Color = class Color
 
     _componentToHexValue(value)
     {
-        var hex = this._componentToNumber(value).toString(16);
+        let hex = this._componentToNumber(value).toString(16);
         if (hex.length === 1)
             hex = "0" + hex;
         return hex;
@@ -504,49 +522,51 @@ WebInspector.Color = class Color
 
     _rgbToHSL(rgb)
     {
-        var r = this._componentToNumber(rgb[0]) / 255;
-        var g = this._componentToNumber(rgb[1]) / 255;
-        var b = this._componentToNumber(rgb[2]) / 255;
-        var max = Math.max(r, g, b);
-        var min = Math.min(r, g, b);
-        var diff = max - min;
-        var add = max + min;
+        let r = this._componentToNumber(rgb[0]) / 255;
+        let g = this._componentToNumber(rgb[1]) / 255;
+        let b = this._componentToNumber(rgb[2]) / 255;
+        let max = Math.max(r, g, b);
+        let min = Math.min(r, g, b);
+        let diff = max - min;
+        let add = max + min;
+
+        let h;
+        let s;
+        let l = 0.5 * add;
 
         if (min === max)
-            var h = 0;
+            h = 0;
         else if (r === max)
-            var h = ((60 * (g - b) / diff) + 360) % 360;
+            h = ((60 * (g - b) / diff) + 360) % 360;
         else if (g === max)
-            var h = (60 * (b - r) / diff) + 120;
+            h = (60 * (b - r) / diff) + 120;
         else
-            var h = (60 * (r - g) / diff) + 240;
-
-        var l = 0.5 * add;
+            h = (60 * (r - g) / diff) + 240;
 
         if (l === 0)
-            var s = 0;
+            s = 0;
         else if (l === 1)
-            var s = 1;
+            s = 1;
         else if (l <= 0.5)
-            var s = diff / add;
+            s = diff / add;
         else
-            var s = diff / (2 - add);
+            s = diff / (2 - add);
 
-        h = Math.round(h);
-        s = Math.round(s * 100);
-        l = Math.round(l * 100);
-
-        return [h, s, l];
+        return [
+            Math.round(h),
+            Math.round(s * 100),
+            Math.round(l * 100)
+        ];
     }
 
     _hslToRGB(hsl)
     {
-        var h = parseFloat(hsl[0]) / 360;
-        var s = parseFloat(hsl[1]) / 100;
-        var l = parseFloat(hsl[2]) / 100;
+        let h = parseFloat(hsl[0]) / 360;
+        let s = parseFloat(hsl[1]) / 100;
+        let l = parseFloat(hsl[2]) / 100;
 
         h *= 6;
-        var sArray = [
+        let sArray = [
             l += s *= l < .5 ? l : 1 - l,
             l - h % 1 * s * 2,
             l -= s *= 2,
@@ -563,14 +583,14 @@ WebInspector.Color = class Color
 
     _rgbaToHSLA(rgba)
     {
-        var hsl = this._rgbToHSL(rgba);
+        let hsl = this._rgbToHSL(rgba);
         hsl.push(rgba[3]);
         return hsl;
     }
 
     _hslaToRGBA(hsla)
     {
-        var rgba = this._hslToRGB(hsla);
+        let rgba = this._hslToRGB(hsla);
         rgba.push(hsla[3]);
         return rgba;
     }
@@ -578,7 +598,7 @@ WebInspector.Color = class Color
 
 WebInspector.Color.Format = {
     Original: "color-format-original",
-    Nickname: "color-format-nickname",
+    Keyword: "color-format-keyword",
     HEX: "color-format-hex",
     ShortHEX: "color-format-short-hex",
     HEXAlpha: "color-format-hex-alpha",
@@ -589,7 +609,7 @@ WebInspector.Color.Format = {
     HSLA: "color-format-hsla"
 };
 
-WebInspector.Color.Nicknames = {
+WebInspector.Color.Keywords = {
     "aliceblue": [240, 248, 255],
     "antiquewhite": [250, 235, 215],
     "aquamarine": [127, 255, 212],
index 4087a0e..fc129ab 100644 (file)
     visibility: visible;
 }
 
-.css-style-text-editor > .CodeMirror .CodeMirror-lines .color-swatch {
-    display: inline-block;
-
-    margin-right: 3px;
-    vertical-align: -2px;
-
-    width: 1em;
-    height: 1em;
-
-    position: relative;
-
-    /* Make a checkered background for transparent colors to show against. */
-    background-image: linear-gradient(to bottom, hsl(0, 0%, 80%), hsl(0, 0%, 80%)),
-        linear-gradient(to bottom, hsl(0, 0%, 80%), hsl(0, 0%, 80%));
-    background-color: white;
-    background-size: calc(50%);
-    background-position: top left, bottom right;
-    background-repeat: no-repeat;
-
-    cursor: default;
-}
-
-@media (-webkit-max-device-pixel-ratio: 1) {
-    /* Ensure the color swatch is even by even so that it looks okay checkered. */
-    .css-style-text-editor > .CodeMirror .CodeMirror-lines .color-swatch {
-        vertical-align: -1px;
-        width: 10px;
-        height: 10px;
-    }
-}
-
-.css-style-text-editor > .CodeMirror .CodeMirror-lines .color-swatch > span {
-    position: absolute;
-    top: 0;
-    left: 0;
-    right: 0;
-    bottom: 0;
-
-    border: 1px solid hsla(0, 0%, 25%, 0.4);
-}
-
-.css-style-text-editor > .CodeMirror .CodeMirror-lines .color-swatch:hover > span {
-    border: 1px solid hsla(0, 0%, 25%, 0.8);
-}
-
-.css-style-text-editor > .CodeMirror .CodeMirror-lines .color-swatch:active > span {
-    border: 1px solid hsl(0, 0%, 25%);
-}
-
 .css-style-text-editor > .CodeMirror .cm-link {
     /* Style url(...) links as if they are strings. */
     color: var(--syntax-highlight-string-color);
index 91e243f..42e5402 100644 (file)
@@ -876,24 +876,19 @@ WebInspector.CSSStyleDeclarationTextEditor = class CSSStyleDeclarationTextEditor
     {
         function update()
         {
-            var range = typeof lineNumber === "number" ? new WebInspector.TextRange(lineNumber, 0, lineNumber + 1, 0) : null;
+            let range = typeof lineNumber === "number" ? new WebInspector.TextRange(lineNumber, 0, lineNumber + 1, 0) : null;
 
             // Look for color strings and add swatches in front of them.
             createCodeMirrorColorTextMarkers(this._codeMirror, range, function(marker, color, colorString) {
-                var swatchElement = document.createElement("span");
-                swatchElement.title = WebInspector.UIString("Click to select a color. Shift-click to switch color formats.");
-                swatchElement.className = WebInspector.CSSStyleDeclarationTextEditor.ColorSwatchElementStyleClassName;
-                swatchElement.addEventListener("click", this._colorSwatchClicked.bind(this));
-
-                var swatchInnerElement = document.createElement("span");
-                swatchInnerElement.style.backgroundColor = colorString;
-                swatchElement.appendChild(swatchInnerElement);
+                let swatch = new WebInspector.ColorSwatch(color, this._codeMirror.getOption("readOnly"));
+                swatch.addEventListener(WebInspector.ColorSwatch.Event.ColorChanged, this._colorSwatchColorChanged, this);
 
-                var codeMirrorTextMarker = marker.codeMirrorTextMarker;
-                this._codeMirror.setUniqueBookmark(codeMirrorTextMarker.find().from, swatchElement);
+                let codeMirrorTextMarker = marker.codeMirrorTextMarker;
+                let codeMirrorTextMarkerRange = codeMirrorTextMarker.find();
+                this._codeMirror.setUniqueBookmark(codeMirrorTextMarkerRange.from, swatch.element);
 
-                swatchInnerElement.__colorTextMarker = codeMirrorTextMarker;
-                swatchInnerElement.__color = color;
+                swatch.__colorTextMarker = codeMirrorTextMarker;
+                swatch.__colorTextMarkerRange = codeMirrorTextMarkerRange;
             }.bind(this));
         }
 
@@ -1324,107 +1319,68 @@ WebInspector.CSSStyleDeclarationTextEditor = class CSSStyleDeclarationTextEditor
         this._codeMirror.operation(update.bind(this));
     }
 
-    _colorSwatchClicked(event)
+    _colorSwatchColorChanged(event)
     {
-        if (this._colorPickerPopover)
-            return;
-
-        var swatch = event.target;
-
-        var color = swatch.__color;
-        console.assert(color);
-        if (!color)
+        let swatch = event && event.target;
+        console.assert(swatch);
+        if (!swatch)
             return;
 
-        var colorTextMarker = swatch.__colorTextMarker;
-        console.assert(colorTextMarker);
-        if (!colorTextMarker)
+        let colorString = event && event.data && event.data.color && event.data.color.toString();
+        console.assert(colorString);
+        if (!colorString)
             return;
 
-        var range = colorTextMarker.find();
+        let colorTextMarker = swatch.__colorTextMarker;
+        let range = swatch.__colorTextMarkerRange;
         console.assert(range);
         if (!range)
             return;
 
-        function updateCodeMirror(newColorText)
+        function update()
         {
-            function update()
-            {
-                // The original text marker might have been cleared by a style update,
-                // in this case we need to find the new color text marker so we know
-                // the right range for the new style color text.
-                if (!colorTextMarker || !colorTextMarker.find()) {
-                    colorTextMarker = null;
-
-                    var marks = this._codeMirror.findMarksAt(range.from);
-                    if (!marks.length)
-                        return;
-
-                    for (var i = 0; i < marks.length; ++i) {
-                        var mark = marks[i];
-                        if (WebInspector.TextMarker.textMarkerForCodeMirrorTextMarker(mark).type !== WebInspector.TextMarker.Type.Color)
-                            continue;
-                        colorTextMarker = mark;
-                        break;
-                    }
-                }
-
-                if (!colorTextMarker)
+            // The original text marker might have been cleared by a style update,
+            // in this case we need to find the new color text marker so we know
+            // the right range for the new style color text.
+            if (!colorTextMarker || !colorTextMarker.find()) {
+                colorTextMarker = null;
+
+                let marks = this._codeMirror.findMarksAt(range.from);
+                if (!marks.length)
                     return;
 
-                // Sometimes we still might find a stale text marker with findMarksAt.
-                var newRange = colorTextMarker.find();
-                if (!newRange)
-                    return;
-
-                range = newRange;
-
-                colorTextMarker.clear();
-
-                this._codeMirror.replaceRange(newColorText, range.from, range.to);
-
-                // The color's text format could have changed, so we need to update the "range"
-                // variable to anticipate a different "range.to" property.
-                range.to.ch = range.from.ch + newColorText.length;
-
-                colorTextMarker = this._codeMirror.markText(range.from, range.to);
-
-                swatch.__colorTextMarker = colorTextMarker;
+                for (let mark of marks) {
+                    if (WebInspector.TextMarker.textMarkerForCodeMirrorTextMarker(mark).type !== WebInspector.TextMarker.Type.Color)
+                        continue;
+                    colorTextMarker = mark;
+                    break;
+                }
             }
 
-            this._codeMirror.operation(update.bind(this));
-        }
+            if (!colorTextMarker)
+                return;
 
-        if (event.shiftKey || this._codeMirror.getOption("readOnly")) {
-            var nextFormat = color.nextFormat();
-            console.assert(nextFormat);
-            if (!nextFormat)
+            // Sometimes we still might find a stale text marker with findMarksAt.
+            let newRange = colorTextMarker.find();
+            if (!newRange)
                 return;
-            color.format = nextFormat;
 
-            var newColorText = color.toString();
+            range = newRange;
 
-            // Ignore the change so we don't commit the format change. However, any future user
-            // edits will commit the color format.
-            this._ignoreCodeMirrorContentDidChangeEvent = true;
-            updateCodeMirror.call(this, newColorText);
-            delete this._ignoreCodeMirrorContentDidChangeEvent;
-        } else {
-            this._colorPickerPopover = new WebInspector.Popover(this);
-
-            var colorPicker = new WebInspector.ColorPicker;
+            colorTextMarker.clear();
 
-            colorPicker.addEventListener(WebInspector.ColorPicker.Event.ColorChanged, function(event) {
-                updateCodeMirror.call(this, event.data.color.toString());
-            }.bind(this));
+            this._codeMirror.replaceRange(colorString, range.from, range.to);
 
-            var bounds = WebInspector.Rect.rectFromClientRect(swatch.getBoundingClientRect());
+            // The color's text format could have changed, so we need to update the "range"
+            // variable to anticipate a different "range.to" property.
+            range.to.ch = range.from.ch + colorString.length;
 
-            this._colorPickerPopover.content = colorPicker.element;
-            this._colorPickerPopover.present(bounds.pad(2), [WebInspector.RectEdge.MIN_X]);
+            colorTextMarker = this._codeMirror.markText(range.from, range.to);
 
-            colorPicker.color = color;
+            swatch.__colorTextMarker = colorTextMarker;
         }
+
+        this._codeMirror.operation(update.bind(this));
     }
 
     _cubicBezierMarkerClicked(event)
@@ -1815,7 +1771,6 @@ WebInspector.CSSStyleDeclarationTextEditor.Event = {
 
 WebInspector.CSSStyleDeclarationTextEditor.StyleClassName = "css-style-text-editor";
 WebInspector.CSSStyleDeclarationTextEditor.ReadOnlyStyleClassName = "read-only";
-WebInspector.CSSStyleDeclarationTextEditor.ColorSwatchElementStyleClassName = "color-swatch";
 WebInspector.CSSStyleDeclarationTextEditor.BezierEditorClassName = "cubic-bezier-marker";
 WebInspector.CSSStyleDeclarationTextEditor.CheckboxPlaceholderElementStyleClassName = "checkbox-placeholder";
 WebInspector.CSSStyleDeclarationTextEditor.EditingLineStyleClassName = "editing-line";
diff --git a/Source/WebInspectorUI/UserInterface/Views/ColorSwatch.css b/Source/WebInspectorUI/UserInterface/Views/ColorSwatch.css
new file mode 100644 (file)
index 0000000..ae6d078
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015 Devin Rousso <dcrousso+webkit@gmail.com>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.color-swatch {
+    display: inline-block;
+    position: relative;
+    width: 1em;
+    height: 1em;
+    margin-right: 3px;
+    vertical-align: -2px;
+    /* Make a checkered background for transparent colors to show against. */
+    background-image: linear-gradient(to bottom, hsl(0, 0%, 80%), hsl(0, 0%, 80%)),
+                      linear-gradient(to bottom, hsl(0, 0%, 80%), hsl(0, 0%, 80%));
+    background-color: white;
+    background-size: 50%;
+    background-position: top left, bottom right;
+    background-repeat: no-repeat;
+    cursor: default;
+    overflow: hidden;
+}
+
+@media (-webkit-max-device-pixel-ratio: 1) {
+    /* Ensure the color swatch is even by even so that it looks okay checkered. */
+    .color-swatch {
+        vertical-align: -1px;
+        width: 10px;
+        height: 10px;
+    }
+}
+
+.color-swatch > span {
+    position: absolute;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    left: 0;
+    border: 1px solid hsla(0, 0%, 25%, 0.4);
+}
+
+.color-swatch:hover > span {
+    border-color: hsla(0, 0%, 25%, 0.8);
+}
+
+.color-swatch:active > span {
+    border-color: hsl(0, 0%, 25%);
+}
+
diff --git a/Source/WebInspectorUI/UserInterface/Views/ColorSwatch.js b/Source/WebInspectorUI/UserInterface/Views/ColorSwatch.js
new file mode 100644 (file)
index 0000000..6dbf36c
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2016 Devin Rousso <dcrousso+webkit@gmail.com>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.ColorSwatch = class ColorSwatch extends WebInspector.Object
+{
+    constructor(color, readOnly)
+    {
+        super();
+
+        this._swatchElement = document.createElement("span");
+        this._swatchElement.classList.add("color-swatch");
+        this._swatchElement.title = WebInspector.UIString("Click to select a color. Shift-click to switch color formats.");
+        if (!readOnly) {
+            this._swatchElement.addEventListener("click", this._colorSwatchClicked.bind(this));
+            this._swatchElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this));
+        }
+
+        this._swatchInnerElement = document.createElement("span");
+        this._swatchElement.appendChild(this._swatchInnerElement);
+
+        this._color = color || WebInspector.Color.fromString("transparent");
+
+        this._updateSwatch();
+    }
+
+    // Public
+
+    get element()
+    {
+        return this._swatchElement;
+    }
+
+    set color(color)
+    {
+        this._color = color || WebInspector.Color.fromString("transparent");
+        this._updateSwatch(true);
+    }
+
+    get color()
+    {
+        return this._color;
+    }
+
+    // Private
+
+    _colorSwatchClicked(event)
+    {
+        if (event.shiftKey) {
+            let nextFormat = this._color.nextFormat();
+            console.assert(nextFormat);
+            if (!nextFormat)
+                return;
+
+            this._color.format = nextFormat;
+            this._updateSwatch();
+            return;
+        }
+
+        let bounds = WebInspector.Rect.rectFromClientRect(this._swatchElement.getBoundingClientRect());
+
+        let colorPicker = new WebInspector.ColorPicker;
+        colorPicker.addEventListener(WebInspector.ColorPicker.Event.ColorChanged, this._colorPickerColorDidChange, this);
+
+        let popover = new WebInspector.Popover(this);
+        popover.content = colorPicker.element;
+        popover.present(bounds.pad(2), [WebInspector.RectEdge.MIN_X]);
+
+        colorPicker.color = this._color;
+    }
+
+    _colorPickerColorDidChange(event)
+    {
+        this._color = event.data.color;
+        this._updateSwatch();
+    }
+
+    _handleContextMenuEvent(event)
+    {
+        let contextMenu = WebInspector.ContextMenu.createFromEvent(event);
+
+        if (this._color.isKeyword() && this._color.format !== WebInspector.Color.Format.Keyword) {
+            contextMenu.appendItem(WebInspector.UIString("Format: Keyword"), () => {
+                this._color.format = WebInspector.Color.Format.Keyword;
+                this._updateSwatch();
+            });
+        }
+
+        let hexInfo = this._getNextValidHEXFormat();
+        if (hexInfo) {
+            contextMenu.appendItem(hexInfo.title, () => {
+                this._color.format = hexInfo.format;
+                this._updateSwatch();
+            });
+        }
+
+        if (this._color.simple && this._color.format !== WebInspector.Color.Format.HSL) {
+            contextMenu.appendItem(WebInspector.UIString("Format: HSL"), () => {
+                this._color.format = WebInspector.Color.Format.HSL;
+                this._updateSwatch();
+            });
+        } else if (this._color.format !== WebInspector.Color.Format.HSLA) {
+            contextMenu.appendItem(WebInspector.UIString("Format: HSLA"), () => {
+                this._color.format = WebInspector.Color.Format.HSLA;
+                this._updateSwatch();
+            });
+        }
+
+        if (this._color.simple && this._color.format !== WebInspector.Color.Format.RGB) {
+            contextMenu.appendItem(WebInspector.UIString("Format: RGB"), () => {
+                this._color.format = WebInspector.Color.Format.RGB;
+                this._updateSwatch();
+            });
+        } else if (this._color.format !== WebInspector.Color.Format.RGBA) {
+            contextMenu.appendItem(WebInspector.UIString("Format: RGBA"), () => {
+                this._color.format = WebInspector.Color.Format.RGBA;
+                this._updateSwatch();
+            });
+        }
+    }
+
+    _getNextValidHEXFormat()
+    {
+        function hexMatchesCurrentColor(hexInfo) {
+            let nextIsSimple = hexInfo.format === WebInspector.Color.Format.ShortHEX || hexInfo.format === WebInspector.Color.Format.HEX;
+            if (nextIsSimple && !this._color.simple)
+                return false;
+
+            let nextIsShort = hexInfo.format === WebInspector.Color.Format.ShortHEX || hexInfo.format === WebInspector.Color.Format.ShortHEXAlpha;
+            if (nextIsShort && !this._color.canBeSerializedAsShortHEX())
+                return false;
+
+            return true;
+        }
+
+        const hexFormats = [
+            {
+                format: WebInspector.Color.Format.ShortHEX,
+                title: WebInspector.UIString("Format: Short Hex")
+            },
+            {
+                format: WebInspector.Color.Format.ShortHEXAlpha,
+                title: WebInspector.UIString("Format: Short Hex with Alpha")
+            },
+            {
+                format: WebInspector.Color.Format.HEX,
+                title: WebInspector.UIString("Format: Hex")
+            },
+            {
+                format: WebInspector.Color.Format.HEXAlpha,
+                title: WebInspector.UIString("Format: Hex with Alpha")
+            }
+        ];
+
+        // FIXME: <https://webkit.org/b/152497> Arrow functions: "this" isn't lexically bound
+        let currentColorIsHEX = hexFormats.some(function(info) {
+            return info.format === this._color.format;
+        }.bind(this));
+
+        for (let i = 0; i < hexFormats.length; ++i) {
+            if (currentColorIsHEX && this._color.format !== hexFormats[i].format)
+                continue;
+
+            for (let j = ~~currentColorIsHEX; j < hexFormats.length; ++j) {
+                let nextIndex = (i + j) % hexFormats.length;
+                if (hexMatchesCurrentColor.call(this, hexFormats[nextIndex]))
+                    return hexFormats[nextIndex];
+            }
+            return null;
+        }
+        return hexFormats[0];
+    }
+
+    _updateSwatch(dontFireEvents)
+    {
+        this._swatchInnerElement.style.backgroundColor = this._color.toString() || null;
+        if (!dontFireEvents)
+            this.dispatchEventToListeners(WebInspector.ColorSwatch.Event.ColorChanged, {color: this._color});
+    }
+};
+
+WebInspector.ColorSwatch.Event = {
+    ColorChanged: "color-swatch-color-changed"
+};
index 9aa728c..0120046 100644 (file)
 }
 
 .visual-style-property-container.input-color-picker > .visual-style-property-value-container > .color-swatch {
-    display: block;
-    position: relative;
     width: 22px;
     height: 18px;
     margin-top: 1px;
-    /* Make a checkered background for transparent colors to show against. */
-    background-image: linear-gradient(to bottom, hsl(0, 0%, 80%), hsl(0, 0%, 80%)),
-        linear-gradient(to bottom, hsl(0, 0%, 80%), hsl(0, 0%, 80%));
-    background-color: white;
-    background-size: 50%;
-    background-position: top left, bottom right;
-    background-repeat: no-repeat;
+    margin-right: 0;
     border: 1px solid hsla(0, 0%, 25%, 0.4);
     border-radius: 4px;
-    overflow: hidden;
-    cursor: default;
 }
 
 .visual-style-property-container.input-color-picker > .visual-style-property-value-container > .color-swatch:hover {
 }
 
 .visual-style-property-container.input-color-picker > .visual-style-property-value-container > .color-swatch > span {
-    position: absolute;
-    top: 0;
-    right: 0;
-    bottom: 0;
-    left: 0;
+    border: none;
 }
 
 .visual-style-property-container.input-color-picker > .visual-style-property-value-container > input {
index ada6669..2244ee6 100644 (file)
@@ -29,15 +29,9 @@ WebInspector.VisualStyleColorPicker = class VisualStyleColorPicker extends WebIn
     {
         super(propertyNames, text, null, null, "input-color-picker", layoutReversed);
 
-        this._swatchElement = document.createElement("span");
-        this._swatchElement.classList.add("color-swatch");
-        this._swatchElement.title = WebInspector.UIString("Click to select a color. Shift-click to switch color formats.");
-        this._swatchElement.addEventListener("click", this._colorSwatchClicked.bind(this));
-
-        this._swatchInnerElement = document.createElement("span");
-        this._swatchElement.appendChild(this._swatchInnerElement);
-
-        this.contentElement.appendChild(this._swatchElement);
+        this._colorSwatch = new WebInspector.ColorSwatch;
+        this._colorSwatch.addEventListener(WebInspector.ColorSwatch.Event.ColorChanged, this._colorSwatchColorChanged, this);
+        this.contentElement.appendChild(this._colorSwatch.element);
 
         this._textInputElement = document.createElement("input");
         this._textInputElement.spellcheck = false;
@@ -103,48 +97,20 @@ WebInspector.VisualStyleColorPicker = class VisualStyleColorPicker extends WebIn
 
     // Private
 
-    _updateColorSwatch()
-    {
-        let value = this._textInputElement.value;
-        this._color = WebInspector.Color.fromString(value || "transparent");
-        this._swatchInnerElement.style.backgroundColor = this._color ? value : null;
-    }
-
-    _colorSwatchClicked(event)
+    _colorSwatchColorChanged(event)
     {
-        let color = this._color;
-        if (event.shiftKey) {
-            let nextFormat = color.nextFormat();
-
-            console.assert(nextFormat);
-            if (!nextFormat)
-                return;
-
-            color.format = nextFormat;
-            this.value = color.toString();
-
-            this._formatChanged = true;
-            this._valueDidChange();
+        let colorString = event && event.data && event.data.color && event.data.color.toString();
+        if (!colorString)
             return;
-        }
-
-        let bounds = WebInspector.Rect.rectFromClientRect(this._swatchElement.getBoundingClientRect());
-
-        let colorPicker = new WebInspector.ColorPicker;
-        colorPicker.addEventListener(WebInspector.ColorPicker.Event.ColorChanged, this._colorPickerColorDidChange, this);
 
-        let popover = new WebInspector.Popover(this);
-        popover.content = colorPicker.element;
-        popover.present(bounds.pad(2), [WebInspector.RectEdge.MIN_X]);
-
-        colorPicker.color = color;
+        this.value = colorString;
+        this._valueDidChange();
     }
 
-    _colorPickerColorDidChange(event)
+    _updateColorSwatch()
     {
-        let format = !this._formatChanged ? WebInspector.Color.Format.HEX : null;
-        this.value = event.data.color.toString(format);
-        this._valueDidChange();
+        let value = this._textInputElement.value;
+        this._colorSwatch.color = WebInspector.Color.fromString(value || "transparent");
     }
 
     _completionClicked(event)