Title: [283723] trunk
Revision
283723
Author
nvasil...@apple.com
Date
2021-10-07 11:15:14 -0700 (Thu, 07 Oct 2021)

Log Message

Web Inspector: Styles: format style declarations after editing
https://bugs.webkit.org/show_bug.cgi?id=178835
<rdar://problem/35185060>

Reviewed by Devin Rousso.

Source/WebInspectorUI:

Indent CSS properties with spaces/tabs set in Web Inspector settings. Increse indentation level when CSS rules are
inside of at-rules (e.g. @media, @keyframes, @supports).

Don't indent CSS properties in style attributes. Keep them on the single line, separated by a space character:

    style="font-size: 12px; color: black;"

* UserInterface/Models/CSSProperty.js:
(WI.CSSProperty.prototype.set text):
Introduce `_isTextPendingSave` flag. It's needed when saving pasted text, and saving commented out or uncommented CSS properties.

(WI.CSSProperty.prototype.get formattedText):

(WI.CSSProperty.prototype.replaceWithText): Deleted.
This is redundant - setting `text` works the same.

(WI.CSSProperty.prototype._updateStyleText):
(WI.CSSProperty.prototype._updateOwnerStyleText):
(WI.CSSProperty.prototype._prependSemicolonIfNeeded): Deleted.
Greatly simplify the logic now that we save formatted text and don't modify styleText.

* UserInterface/Models/CSSStyleDeclaration.js:
(WI.CSSStyleDeclaration.prototype.removeProperty):
Remode unnecessary code that modifies `_styleSheetTextRange`. The backend sends new `_styleSheetTextRange` data
upon a change.

(WI.CSSStyleDeclaration.prototype.generateFormattedText): Renamed from 'generateCSSRuleString'.

* UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.js:
(WI.SpreadsheetCSSStyleDeclarationSection.prototype._populateIconElementContextMenu):
* UserInterface/Views/SpreadsheetStyleProperty.js:
(WI.SpreadsheetStyleProperty.prototype.remove):

LayoutTests:

- Indent text of expected CSS properties.
- Test generateFormattedText with all permutations of its options.
- Add a basic test ensuring styleSheetTextRange updates correctly from the backend.

* inspector/css/add-css-property.html:
* inspector/css/generateCSSRuleString-expected.txt: Removed.
* inspector/css/generateCSSRuleString.html: Removed.
* inspector/css/generateFormattedText-expected.txt: Added.
* inspector/css/generateFormattedText.html: Added.
* inspector/css/modify-css-property-expected.txt:
* inspector/css/modify-css-property.html:
* inspector/css/modify-inline-style-expected.txt:
* inspector/css/resources/modify-css-property.css: Added.
(.rule-a):
(.rule-b):
(.rule-c):
(.rule-d):

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (283722 => 283723)


--- trunk/LayoutTests/ChangeLog	2021-10-07 18:08:53 UTC (rev 283722)
+++ trunk/LayoutTests/ChangeLog	2021-10-07 18:15:14 UTC (rev 283723)
@@ -1,3 +1,29 @@
+2021-10-07  Nikita Vasilyev  <nvasil...@apple.com>
+
+        Web Inspector: Styles: format style declarations after editing
+        https://bugs.webkit.org/show_bug.cgi?id=178835
+        <rdar://problem/35185060>
+
+        Reviewed by Devin Rousso.
+
+        - Indent text of expected CSS properties.
+        - Test generateFormattedText with all permutations of its options.
+        - Add a basic test ensuring styleSheetTextRange updates correctly from the backend.
+
+        * inspector/css/add-css-property.html:
+        * inspector/css/generateCSSRuleString-expected.txt: Removed.
+        * inspector/css/generateCSSRuleString.html: Removed.
+        * inspector/css/generateFormattedText-expected.txt: Added.
+        * inspector/css/generateFormattedText.html: Added.
+        * inspector/css/modify-css-property-expected.txt:
+        * inspector/css/modify-css-property.html:
+        * inspector/css/modify-inline-style-expected.txt:
+        * inspector/css/resources/modify-css-property.css: Added.
+        (.rule-a):
+        (.rule-b):
+        (.rule-c):
+        (.rule-d):
+
 2021-10-07  Ayumi Kojima  <ayumi_koj...@apple.com>
 
         [ BigSur AS EWS ] http/tests/xmlhttprequest/access-control-response-with-body.html is flaky crashing.

Modified: trunk/LayoutTests/inspector/css/add-css-property.html (283722 => 283723)


--- trunk/LayoutTests/inspector/css/add-css-property.html	2021-10-07 18:08:53 UTC (rev 283722)
+++ trunk/LayoutTests/inspector/css/add-css-property.html	2021-10-07 18:15:14 UTC (rev 283723)
@@ -27,7 +27,7 @@
             newProperty.name = "color";
             newProperty.rawValue = "green";
 
-            InspectorTest.expectEqual(styleDeclaration.text, `font-size: 14px;color: green;`, "`color: green` property should be appended.");
+            InspectorTest.expectEqual(styleDeclaration.text, `\n    font-size: 14px;\n    color: green;\n`, "`color: green` property should be appended.");
 
             styleDeclaration.locked = false;
             resolve();
@@ -43,7 +43,7 @@
             newProperty.name = "color";
             newProperty.rawValue = "green";
 
-            let expected = `color: green;\n    outline: 2px solid brown;\n`;
+            let expected = `\n    color: green;\n    outline: 2px solid brown;\n`;
             InspectorTest.expectEqual(styleDeclaration.text, expected, "`color: green` property should be inserted before the first property.");
 
             styleDeclaration = getMatchedStyle(".rule-b", resolve);
@@ -51,7 +51,7 @@
             newProperty.name = "display";
             newProperty.rawValue = "block";
 
-            expected = `color: green;\n    outline: 2px solid brown;display: block;\n`;
+            expected = `\n    color: green;\n    outline: 2px solid brown;\n    display: block;\n`;
             InspectorTest.expectEqual(styleDeclaration.text, expected, "`display: block` property should be appended at the end.");
 
             styleDeclaration.locked = false;
@@ -68,7 +68,7 @@
             newProperty.name = "font-family";
             newProperty.rawValue = "fantasy";
 
-            let expected = `\n    background-color: peachpuff;font-family: fantasy;\n    color: burlywood\n`;
+            let expected = `\n    background-color: peachpuff;\n    font-family: fantasy;\n    color: burlywood;\n`;
             InspectorTest.expectEqual(styleDeclaration.text, expected, "`font-family: fantasy` property should be inserted after the first property.");
 
             styleDeclaration.locked = false;
@@ -85,7 +85,7 @@
             newProperty.name = "display";
             newProperty.rawValue = "inline";
 
-            const expected = `\n    font-size: 14px;\n    /* color: red; */display: inline;\n`;
+            const expected = `\n    font-size: 14px;\n    /* color: red; */\n    display: inline;\n`;
             InspectorTest.expectEqual(styleDeclaration.text, expected, "`display: inline` property should be appended.");
 
             styleDeclaration.locked = false;
@@ -102,7 +102,7 @@
             newProperty.name = "display";
             newProperty.rawValue = "inline";
 
-            const expected = `\n    font-size: 14px;\n    /* color: red */display: inline;\n`;
+            const expected = `\n    font-size: 14px;\n    /* color: red; */\n    display: inline;\n`;
             InspectorTest.expectEqual(styleDeclaration.text, expected, "`display: inline` property should be appended.");
 
             styleDeclaration.locked = false;

Deleted: trunk/LayoutTests/inspector/css/generateCSSRuleString-expected.txt (283722 => 283723)


--- trunk/LayoutTests/inspector/css/generateCSSRuleString-expected.txt	2021-10-07 18:08:53 UTC (rev 283722)
+++ trunk/LayoutTests/inspector/css/generateCSSRuleString-expected.txt	2021-10-07 18:15:14 UTC (rev 283723)
@@ -1,87 +0,0 @@
-Testing that generated CSS rule strings have proper formatting.
-
-
-== Running test suite: CSS.generateCSSRuleString
--- Running test case: CSS.generateCSSRuleString.InlineStyle
-#test-node {
-    a: 1;
-    b: 2;
-    c: 3;
-}
-
--- Running test case: CSS.generateCSSRuleString.InlineStyle.WithCommentedProperty
-#test-node {
-    a: 1;
-    /* b: 2; */
-    c: 3;
-}
-
--- Running test case: CSS.generateCSSRuleString.MatchedRules
-@media only screen and (min-width: 0px) {
-    @media only screen and (min-height: 0px) {
-        body > div#test-node {
-            a: 1;
-            b: 2;
-            c: 3;
-        }
-    }
-}
-@media only screen and (min-width: 0px) {
-    body > #test-node {
-        a: 1;
-        b: 2;
-        c: 3;
-    }
-}
-body > div {
-    a: 1;
-    b: 2;
-    c: 3;
-}
-body > * {
-    a: 1;
-    b: 2;
-    c: 3;
-}
-* {
-    a: 1;
-    b: 2;
-    c: 3;
-}
-address, article, aside, div, footer, header, hgroup, layer, main, nav, section {
-    display: block;
-}
-
--- Running test case: CSS.generateCSSRuleString.MatchedRules.WithCommentedProperties
-@media only screen and (min-width: 0px) {
-    @media only screen and (min-height: 0px) {
-        body > div#test-node {
-            a: 1;
-            /* b: 2; */
-            c: 3;
-        }
-    }
-}
-@media only screen and (min-width: 0px) {
-    body > #test-node {
-        a: 1;
-        /* b: 2; */
-        c: 3;
-    }
-}
-body > div {
-    a: 1;
-    /* b: 2; */
-    c: 3;
-}
-body > * {
-    a: 1;
-    /* b: 2; */
-    c: 3;
-}
-* {
-    a: 1;
-    /* b: 2; */
-    c: 3;
-}
-

Deleted: trunk/LayoutTests/inspector/css/generateCSSRuleString.html (283722 => 283723)


--- trunk/LayoutTests/inspector/css/generateCSSRuleString.html	2021-10-07 18:08:53 UTC (rev 283722)
+++ trunk/LayoutTests/inspector/css/generateCSSRuleString.html	2021-10-07 18:15:14 UTC (rev 283723)
@@ -1,81 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-*{a:1;b:2;c:3}
-body>*{a:1;b:2;c:3}
-@media all {body>div{a:1;b:2;c:3}}
-@media only screen and (min-width:0px) {body>#test-node{a:1;b:2;c:3}}
-@media only screen and (min-width:0px) {@media only screen and (min-height:0px) {body>div#test-node{a:1;b:2;c:3}}}
-</style>
-<script src=""
-<script>
-function test() {
-    let nodeStyles = null;
-
-    let suite = InspectorTest.createSyncSuite("CSS.generateCSSRuleString");
-
-    suite.addTestCase({
-        name: "CSS.generateCSSRuleString.InlineStyle",
-        description: "Check the formatting of the generated inline style string.",
-        test() {
-            InspectorTest.log(nodeStyles.inlineStyle.generateCSSRuleString());
-        }
-    });
-
-    suite.addTestCase({
-        name: "CSS.generateCSSRuleString.InlineStyle.WithCommentedProperty",
-        description: "Check the formatting of the generated inline style string if a property is commented out.",
-        test() {
-            nodeStyles.inlineStyle.properties[1].commentOut(true);
-            InspectorTest.log(nodeStyles.inlineStyle.generateCSSRuleString());
-        },
-    });
-
-    suite.addTestCase({
-        name: "CSS.generateCSSRuleString.MatchedRules",
-        description: "Check the formatting of the generated string for all matched CSS rules.",
-        test() {
-            for (let rule of nodeStyles.matchedRules)
-                InspectorTest.log(rule.style.generateCSSRuleString());
-        }
-    });
-
-    suite.addTestCase({
-        name: "CSS.generateCSSRuleString.MatchedRules.WithCommentedProperties",
-        description: "Check the formatting of the generated string for all matched CSS rules if a property is commented out in each.",
-        test() {
-            for (let rule of nodeStyles.matchedRules) {
-                if (!rule.style.editable)
-                    continue;
-
-                rule.style.properties[1].commentOut(true);
-                InspectorTest.log(rule.style.generateCSSRuleString());
-            }
-        }
-    });
-
-    WI.domManager.requestDocument((documentNode) => {
-        documentNode.querySelector("#test-node", async (contentNodeId) => {
-            if (!contentNodeId) {
-                InspectorTest.log("DOM node not found.");
-                InspectorTest.completeTest();
-                return;
-            }
-
-            let domNode = WI.domManager.nodeForId(contentNodeId);
-            nodeStyles = WI.cssManager.stylesForNode(domNode);
-            if (nodeStyles.needsRefresh)
-                await nodeStyles.awaitEvent(WI.DOMNodeStyles.Event.Refreshed);
-
-            suite.runTestCasesAndFinish();
-        });
-    });
-}
-</script>
-</head>
-<body _onload_="runTest()">
-    <p>Testing that generated CSS rule strings have proper formatting.</p>
-    <div id="test-node" style="a:1;b:2;c:3"></div>
-</body>
-</html>

Added: trunk/LayoutTests/inspector/css/generateFormattedText-expected.txt (0 => 283723)


--- trunk/LayoutTests/inspector/css/generateFormattedText-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/inspector/css/generateFormattedText-expected.txt	2021-10-07 18:15:14 UTC (rev 283723)
@@ -0,0 +1,192 @@
+Testing that generated CSS rule strings have proper formatting.
+
+
+== Running test suite: WI.CSSStyelDeclaration.prototype.generateFormattedText
+-- Running test case: CSS.generateFormattedText.InlineStyle
+a: 1; b: 2; c: 3;
+
+-- Running test case: CSS.generateFormattedText.InlineStyle.includeGroupingsAndSelectors
+#test-node {a: 1; b: 2; c: 3;}
+
+-- Running test case: CSS.generateFormattedText.InlineStyle.Multiline
+
+    a: 1;
+    b: 2;
+    c: 3;
+
+
+-- Running test case: CSS.generateFormattedText.InlineStyle.Multiline.includeGroupingsAndSelectors
+#test-node {
+    a: 1;
+    b: 2;
+    c: 3;
+}
+
+-- Running test case: CSS.generateFormattedText.InlineStyle.WithCommentedProperty
+a: 1; /* b: 2; */ c: 3;
+
+-- Running test case: CSS.generateFormattedText.InlineStyle.WithCommentedProperty.includeGroupingsAndSelectors
+#test-node {a: 1; /* b: 2; */ c: 3;}
+
+-- Running test case: CSS.generateFormattedText.InlineStyle.WithCommentedProperty.Multiline
+
+    a: 1;
+    /* b: 2; */
+    c: 3;
+
+
+-- Running test case: CSS.generateFormattedText.InlineStyle.WithCommentedProperty.includeGroupingsAndSelectors.Multiline
+#test-node {
+    a: 1;
+    /* b: 2; */
+    c: 3;
+}
+
+-- Running test case: CSS.generateFormattedText.MatchedRules
+a: 1; b: 2; c: 3;
+a: 1; b: 2; c: 3;
+a: 1; b: 2; c: 3;
+a: 1; b: 2; c: 3;
+a: 1; b: 2; c: 3;
+
+-- Running test case: CSS.generateFormattedText.MatchedRules.includeGroupingsAndSelectors
+@media only screen and (min-width: 0px) {@media only screen and (min-height: 0px) {body > div#test-node {a: 1; b: 2; c: 3;}}}
+@media only screen and (min-width: 0px) {body > #test-node {a: 1; b: 2; c: 3;}}
+body > div {a: 1; b: 2; c: 3;}
+body > * {a: 1; b: 2; c: 3;}
+* {a: 1; b: 2; c: 3;}
+
+-- Running test case: CSS.generateFormattedText.MatchedRules.Multiline
+
+            a: 1;
+            b: 2;
+            c: 3;
+
+
+        a: 1;
+        b: 2;
+        c: 3;
+
+
+    a: 1;
+    b: 2;
+    c: 3;
+
+
+    a: 1;
+    b: 2;
+    c: 3;
+
+
+    a: 1;
+    b: 2;
+    c: 3;
+
+
+-- Running test case: CSS.generateFormattedText.MatchedRules.includeGroupingsAndSelectors.Multiline
+@media only screen and (min-width: 0px) {
+    @media only screen and (min-height: 0px) {
+        body > div#test-node {
+            a: 1;
+            b: 2;
+            c: 3;
+        }
+    }
+}
+@media only screen and (min-width: 0px) {
+    body > #test-node {
+        a: 1;
+        b: 2;
+        c: 3;
+    }
+}
+body > div {
+    a: 1;
+    b: 2;
+    c: 3;
+}
+body > * {
+    a: 1;
+    b: 2;
+    c: 3;
+}
+* {
+    a: 1;
+    b: 2;
+    c: 3;
+}
+
+-- Running test case: CSS.generateFormattedText.MatchedRules.WithCommentedProperties
+a: 1; /* b: 2; */ c: 3;
+a: 1; /* b: 2; */ c: 3;
+a: 1; /* b: 2; */ c: 3;
+a: 1; /* b: 2; */ c: 3;
+a: 1; /* b: 2; */ c: 3;
+
+-- Running test case: CSS.generateFormattedText.MatchedRules.WithCommentedProperties.includeGroupingsAndSelectors
+@media only screen and (min-width: 0px) {@media only screen and (min-height: 0px) {body > div#test-node {a: 1; /* b: 2; */ c: 3;}}}
+@media only screen and (min-width: 0px) {body > #test-node {a: 1; /* b: 2; */ c: 3;}}
+body > div {a: 1; /* b: 2; */ c: 3;}
+body > * {a: 1; /* b: 2; */ c: 3;}
+* {a: 1; /* b: 2; */ c: 3;}
+
+-- Running test case: CSS.generateFormattedText.MatchedRules.WithCommentedProperties.Multiline
+
+            a: 1;
+            /* b: 2; */
+            c: 3;
+
+
+        a: 1;
+        /* b: 2; */
+        c: 3;
+
+
+    a: 1;
+    /* b: 2; */
+    c: 3;
+
+
+    a: 1;
+    /* b: 2; */
+    c: 3;
+
+
+    a: 1;
+    /* b: 2; */
+    c: 3;
+
+
+-- Running test case: CSS.generateFormattedText.MatchedRules.WithCommentedProperties.includeGroupingsAndSelectors.Multiline
+@media only screen and (min-width: 0px) {
+    @media only screen and (min-height: 0px) {
+        body > div#test-node {
+            a: 1;
+            /* b: 2; */
+            c: 3;
+        }
+    }
+}
+@media only screen and (min-width: 0px) {
+    body > #test-node {
+        a: 1;
+        /* b: 2; */
+        c: 3;
+    }
+}
+body > div {
+    a: 1;
+    /* b: 2; */
+    c: 3;
+}
+body > * {
+    a: 1;
+    /* b: 2; */
+    c: 3;
+}
+* {
+    a: 1;
+    /* b: 2; */
+    c: 3;
+}
+

Added: trunk/LayoutTests/inspector/css/generateFormattedText.html (0 => 283723)


--- trunk/LayoutTests/inspector/css/generateFormattedText.html	                        (rev 0)
+++ trunk/LayoutTests/inspector/css/generateFormattedText.html	2021-10-07 18:15:14 UTC (rev 283723)
@@ -0,0 +1,209 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+*{a:1;b:2;c:3}
+body>*{a:1;b:2;c:3}
+@media all {body>div{a:1;b:2;c:3}}
+@media only screen and (min-width:0px) {body>#test-node{a:1;b:2;c:3}}
+@media only screen and (min-width:0px) {@media only screen and (min-height:0px) {body>div#test-node{a:1;b:2;c:3}}}
+</style>
+<script src=""
+<script>
+function test() {
+    let nodeStyles = null;
+
+    let suite = InspectorTest.createSyncSuite("WI.CSSStyelDeclaration.prototype.generateFormattedText");
+
+    suite.addTestCase({
+        name: "CSS.generateFormattedText.InlineStyle",
+        description: "Check the formatting of the generated inline style string.",
+        test() {
+            InspectorTest.log(nodeStyles.inlineStyle.generateFormattedText());
+        }
+    });
+
+    suite.addTestCase({
+        name: "CSS.generateFormattedText.InlineStyle.includeGroupingsAndSelectors",
+        description: "Check the formatting of the generated inline style string (including groupings and selectors).",
+        test() {
+            InspectorTest.log(nodeStyles.inlineStyle.generateFormattedText({includeGroupingsAndSelectors: true}));
+        }
+    });
+
+    suite.addTestCase({
+        name: "CSS.generateFormattedText.InlineStyle.Multiline",
+        description: "Check the formatting of the generated inline style string (multiline).",
+        test() {
+            InspectorTest.log(nodeStyles.inlineStyle.generateFormattedText({multiline: true}));
+        }
+    });
+
+    suite.addTestCase({
+        name: "CSS.generateFormattedText.InlineStyle.Multiline.includeGroupingsAndSelectors",
+        description: "Check the formatting of the generated inline style string (multiline, and including groupings and selectors).",
+        test() {
+            InspectorTest.log(nodeStyles.inlineStyle.generateFormattedText({multiline: true, includeGroupingsAndSelectors: true}));
+        }
+    });
+
+    suite.addTestCase({
+        name: "CSS.generateFormattedText.InlineStyle.WithCommentedProperty",
+        description: "Check the formatting of the generated inline style string if a property is commented out.",
+        test() {
+            nodeStyles.inlineStyle.properties[1].commentOut(true);
+            InspectorTest.log(nodeStyles.inlineStyle.generateFormattedText());
+        },
+    });
+
+    suite.addTestCase({
+        name: "CSS.generateFormattedText.InlineStyle.WithCommentedProperty.includeGroupingsAndSelectors",
+        description: "Check the formatting of the generated inline style string (including groupings and selectors) if a property is commented out.",
+        test() {
+            nodeStyles.inlineStyle.properties[1].commentOut(true);
+            InspectorTest.log(nodeStyles.inlineStyle.generateFormattedText({includeGroupingsAndSelectors: true}));
+        },
+    });
+
+    suite.addTestCase({
+        name: "CSS.generateFormattedText.InlineStyle.WithCommentedProperty.Multiline",
+        description: "Check the formatting of the generated inline style string (multiline) if a property is commented out.",
+        test() {
+            nodeStyles.inlineStyle.properties[1].commentOut(true);
+            InspectorTest.log(nodeStyles.inlineStyle.generateFormattedText({multiline: true}));
+        },
+    });
+
+    suite.addTestCase({
+        name: "CSS.generateFormattedText.InlineStyle.WithCommentedProperty.includeGroupingsAndSelectors.Multiline",
+        description: "Check the formatting of the generated inline style string (multiline, and including groupings and selectors) if a property is commented out.",
+        test() {
+            nodeStyles.inlineStyle.properties[1].commentOut(true);
+            InspectorTest.log(nodeStyles.inlineStyle.generateFormattedText({includeGroupingsAndSelectors: true, multiline: true}));
+        },
+    });
+
+    suite.addTestCase({
+        name: "CSS.generateFormattedText.MatchedRules",
+        description: "Check the formatting of the generated string for all matched CSS rules.",
+        test() {
+            for (let rule of nodeStyles.matchedRules) {
+                if (!rule.style.editable)
+                    continue;
+                InspectorTest.log(rule.style.generateFormattedText());
+            }
+        }
+    });
+
+    suite.addTestCase({
+        name: "CSS.generateFormattedText.MatchedRules.includeGroupingsAndSelectors",
+        description: "Check the formatting of the generated string (including groupings and selectors) for all matched CSS rules.",
+        test() {
+            for (let rule of nodeStyles.matchedRules) {
+                if (!rule.style.editable)
+                    continue;
+                InspectorTest.log(rule.style.generateFormattedText({includeGroupingsAndSelectors: true}));
+            }
+        }
+    });
+
+    suite.addTestCase({
+        name: "CSS.generateFormattedText.MatchedRules.Multiline",
+        description: "Check the formatting of the generated string (multiline) for all matched CSS rules.",
+        test() {
+            for (let rule of nodeStyles.matchedRules) {
+                if (!rule.style.editable)
+                    continue;
+                InspectorTest.log(rule.style.generateFormattedText({multiline: true}));
+            }
+        }
+    });
+
+    suite.addTestCase({
+        name: "CSS.generateFormattedText.MatchedRules.includeGroupingsAndSelectors.Multiline",
+        description: "Check the formatting of the generated string (multiline, and including groupings and selectors) for all matched CSS rules.",
+        test() {
+            for (let rule of nodeStyles.matchedRules) {
+                if (!rule.style.editable)
+                    continue;
+                InspectorTest.log(rule.style.generateFormattedText({includeGroupingsAndSelectors: true, multiline: true}));
+            }
+        }
+    });
+
+    suite.addTestCase({
+        name: "CSS.generateFormattedText.MatchedRules.WithCommentedProperties",
+        description: "Check the formatting of the generated string for all matched CSS rules if a property is commented out in each.",
+        test() {
+            for (let rule of nodeStyles.matchedRules) {
+                if (!rule.style.editable)
+                    continue;
+                rule.style.properties[1].commentOut(true);
+                InspectorTest.log(rule.style.generateFormattedText());
+            }
+        }
+    });
+
+    suite.addTestCase({
+        name: "CSS.generateFormattedText.MatchedRules.WithCommentedProperties.includeGroupingsAndSelectors",
+        description: "Check the formatting of the generated string (including groupings and selectors) for all matched CSS rules if a property is commented out in each.",
+        test() {
+            for (let rule of nodeStyles.matchedRules) {
+                if (!rule.style.editable)
+                    continue;
+                rule.style.properties[1].commentOut(true);
+                InspectorTest.log(rule.style.generateFormattedText({includeGroupingsAndSelectors: true}));
+            }
+        }
+    });
+
+    suite.addTestCase({
+        name: "CSS.generateFormattedText.MatchedRules.WithCommentedProperties.Multiline",
+        description: "Check the formatting of the generated string (multiline) for all matched CSS rules if a property is commented out in each.",
+        test() {
+            for (let rule of nodeStyles.matchedRules) {
+                if (!rule.style.editable)
+                    continue;
+                rule.style.properties[1].commentOut(true);
+                InspectorTest.log(rule.style.generateFormattedText({multiline: true}));
+            }
+        }
+    });
+
+    suite.addTestCase({
+        name: "CSS.generateFormattedText.MatchedRules.WithCommentedProperties.includeGroupingsAndSelectors.Multiline",
+        description: "Check the formatting of the generated string (multiline, and including groupings and selectors) for all matched CSS rules if a property is commented out in each.",
+        test() {
+            for (let rule of nodeStyles.matchedRules) {
+                if (!rule.style.editable)
+                    continue;
+                rule.style.properties[1].commentOut(true);
+                InspectorTest.log(rule.style.generateFormattedText({includeGroupingsAndSelectors: true, multiline: true}));
+            }
+        }
+    });
+
+    WI.domManager.requestDocument((documentNode) => {
+        documentNode.querySelector("#test-node", async (contentNodeId) => {
+            if (!contentNodeId) {
+                InspectorTest.log("DOM node not found.");
+                InspectorTest.completeTest();
+                return;
+            }
+
+            let domNode = WI.domManager.nodeForId(contentNodeId);
+            nodeStyles = WI.cssManager.stylesForNode(domNode);
+            if (nodeStyles.needsRefresh)
+                await nodeStyles.awaitEvent(WI.DOMNodeStyles.Event.Refreshed);
+
+            suite.runTestCasesAndFinish();
+        });
+    });
+}
+</script>
+</head>
+<body _onload_="runTest()">
+    <p>Testing that generated CSS rule strings have proper formatting.</p>
+    <div id="test-node" style="a:1;b:2;c:3"></div>
+</body>
+</html>

Modified: trunk/LayoutTests/inspector/css/modify-css-property-expected.txt (283722 => 283723)


--- trunk/LayoutTests/inspector/css/modify-css-property-expected.txt	2021-10-07 18:08:53 UTC (rev 283722)
+++ trunk/LayoutTests/inspector/css/modify-css-property-expected.txt	2021-10-07 18:15:14 UTC (rev 283723)
@@ -5,6 +5,7 @@
 -- Running test case: Update value when CSSStyleDeclaration is not locked
 PASS: "font-size" property value should update immediately.
 PASS: Style declaration text should update immediately.
+PASS: styleSheetTextRange should correspond to "font-size: 10px;"
 
 -- Running test case: Update value when CSSStyleDeclaration is locked
 PASS: "font-size" property value should update immediately.

Modified: trunk/LayoutTests/inspector/css/modify-css-property.html (283722 => 283723)


--- trunk/LayoutTests/inspector/css/modify-css-property.html	2021-10-07 18:08:53 UTC (rev 283722)
+++ trunk/LayoutTests/inspector/css/modify-css-property.html	2021-10-07 18:15:14 UTC (rev 283723)
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
+<link rel="stylesheet" href=""
 <script src=""
 <script>
 function makeNarrow() {
@@ -39,14 +40,22 @@
 
             let styleDeclaration = getMatchedStyleDeclaration();
             styleDeclaration.locked = false;
+
+            styleDeclaration.singleFireEventListener(WI.CSSStyleDeclaration.Event.PropertiesChanged, function(event) {
+                let fontProperty = getProperty("font-size");
+                let relativeRange = fontProperty.styleSheetTextRange.relativeTo(fontProperty.ownerStyle.styleSheetTextRange.startLine, fontProperty.ownerStyle.styleSheetTextRange.startOffset);
+                relativeRange.resolveOffsets(fontProperty.ownerStyle.text);
+                let propertyText = fontProperty.ownerStyle.text.slice(relativeRange.startOffset, relativeRange.endOffset);
+                InspectorTest.expectEqual(propertyText, "font-size: 10px;", `styleSheetTextRange should correspond to "font-size: 10px;"`);
+                resolve();
+            });
+
             getProperty("font-size").rawValue = "11px";
             getProperty("font-size").rawValue = "10px";
 
             InspectorTest.expectEqual(getProperty("font-size").rawValue, "10px", `"font-size" property value should update immediately.`);
 
-            InspectorTest.expectEqual(styleDeclaration.text, `font-size: 10px; color: antiquewhite`, `Style declaration text should update immediately.`);
-
-            resolve();
+            InspectorTest.expectEqual(styleDeclaration.text, `\n    font-size: 10px;\n    color: antiquewhite;\n`, `Style declaration text should update immediately.`);
         }
     });
 
@@ -80,13 +89,12 @@
             InspectorTest.expectEqual(getProperty("font-size").rawValue, "16px", `"font-size" property value should update immediately.`);
 
             InspectorTest.expectEqual(styleDeclaration.text, `
-        font-size: 16px;
-        color: #333;
+    font-size: 16px;
+    color: #333;
+    margin-left: 0;
+    margin-top: 1em;
+`, `Style declaration text should update immediately.`);
 
-        margin-left: 0;
-        margin-top: 1em;
-    `, `Style declaration text should update immediately.`);
-
             styleDeclaration.locked = false;
 
             resolve();
@@ -243,7 +251,7 @@
             let disabled = false;
             getProperty("padding-right").commentOut(disabled);
 
-            let expectedStyleText = `\n        /* padding-left: 2em; */\n        padding-right: 0px;\n    `;
+            let expectedStyleText = `\n    /* padding-left: 2em; */\n    padding-right: 0px;\n`;
             InspectorTest.expectEqual(styleDeclaration.text, expectedStyleText, `Style declaration text should update immediately with uncommented property.`);
 
             InspectorTest.expectThat(getProperty("padding-right").enabled, `Uncommented property should be enabled.`);
@@ -251,7 +259,7 @@
             disabled = true;
             getProperty("padding-right").commentOut(disabled);
 
-            expectedStyleText = `\n        /* padding-left: 2em; */\n        /* padding-right: 0px; */\n    `;
+            expectedStyleText = `\n    /* padding-left: 2em; */\n    /* padding-right: 0px; */\n`;
             InspectorTest.expectEqual(styleDeclaration.text, expectedStyleText, `Style declaration text should update immediately with commented out property.`);
 
             InspectorTest.expectThat(!getProperty("padding-right").enabled, `Commented out property should be disabled.`);
@@ -290,7 +298,7 @@
             let disabled = false;
             getProperty("font-size").commentOut(disabled);
 
-            let expectedStyleText = `font-size: 13px;/*border: 2px solid brown*/`;
+            let expectedStyleText = `\n    font-size: 13px;\n    /* border: 2px solid brown; */\n`;
             InspectorTest.expectEqual(styleDeclaration.text, expectedStyleText, `Style declaration text should update immediately with uncommented property.`);
 
             InspectorTest.expectThat(getProperty("font-size").enabled, `Uncommented property should be enabled.`);
@@ -299,7 +307,7 @@
             disabled = false;
             getProperty("border").commentOut(disabled);
 
-            expectedStyleText = `font-size: 13px;border: 2px solid brown`;
+            expectedStyleText = `\n    font-size: 13px;\n    border: 2px solid brown\n`;
             InspectorTest.expectEqual(styleDeclaration.text, expectedStyleText, `Style declaration text should update immediately with commented out property.`);
 
             InspectorTest.expectThat(getProperty("border").enabled, `Uncommented property should be enabled.`);
@@ -331,22 +339,6 @@
 </head>
 <body _onload_="runTest()">
     <p>Testing that CSSStyleDeclaration update immediately after modifying its properties when it is not locked.</p>
-
-    <style>
-    .rule-a {
-        font-size: 14px;
-        color: #333;
-
-        margin-left: 0;
-        margin-top: 1em;
-    }
-    .rule-b {font-size: 12px; color: antiquewhite}
-    .rule-c {
-        /* padding-left: 2em; */
-        /* padding-right: 0px; */
-    }
-    .rule-d {/*font-size: 13px;*//*border: 2px solid brown*/}
-    </style>
     <div id="x" class="test-node rule-a rule-b rule-c rule-d" style="width: 100px"></div>
 </body>
 </html>

Modified: trunk/LayoutTests/inspector/css/modify-inline-style-expected.txt (283722 => 283723)


--- trunk/LayoutTests/inspector/css/modify-inline-style-expected.txt	2021-10-07 18:08:53 UTC (rev 283722)
+++ trunk/LayoutTests/inspector/css/modify-inline-style-expected.txt	2021-10-07 18:15:14 UTC (rev 283723)
@@ -7,12 +7,12 @@
 font: 12px normal sans-serif!important;
 
 CSSProperty changed to "color: red;".
-font: 12px normal sans-serif!important;color: red;
+font: 12px normal sans-serif!important; color: red;
 
 CSSProperty changed to "font: 12px sans-serif;".
-font: 12px sans-serif;color: red;
+font: 12px sans-serif; color: red;
 
 CSSProperty changed to "color: invalid_c010r;".
-font: 12px sans-serif;color: invalid_c010r;
+font: 12px sans-serif; color: invalid_c010r;
 
 

Added: trunk/LayoutTests/inspector/css/resources/modify-css-property.css (0 => 283723)


--- trunk/LayoutTests/inspector/css/resources/modify-css-property.css	                        (rev 0)
+++ trunk/LayoutTests/inspector/css/resources/modify-css-property.css	2021-10-07 18:15:14 UTC (rev 283723)
@@ -0,0 +1,15 @@
+/* A comment. */
+
+.rule-a {
+    font-size: 14px;
+    color: #333;
+
+    margin-left: 0;
+    margin-top: 1em;
+}
+.rule-b {font-size: 12px; color: antiquewhite}
+.rule-c {
+    /* padding-left: 2em; */
+    /* padding-right: 0px; */
+}
+.rule-d {/*font-size: 13px;*//*border: 2px solid brown*/}

Modified: trunk/Source/WebInspectorUI/ChangeLog (283722 => 283723)


--- trunk/Source/WebInspectorUI/ChangeLog	2021-10-07 18:08:53 UTC (rev 283722)
+++ trunk/Source/WebInspectorUI/ChangeLog	2021-10-07 18:15:14 UTC (rev 283723)
@@ -1,3 +1,44 @@
+2021-10-07  Nikita Vasilyev  <nvasil...@apple.com>
+
+        Web Inspector: Styles: format style declarations after editing
+        https://bugs.webkit.org/show_bug.cgi?id=178835
+        <rdar://problem/35185060>
+
+        Reviewed by Devin Rousso.
+
+        Indent CSS properties with spaces/tabs set in Web Inspector settings. Increse indentation level when CSS rules are
+        inside of at-rules (e.g. @media, @keyframes, @supports).
+
+        Don't indent CSS properties in style attributes. Keep them on the single line, separated by a space character:
+
+            style="font-size: 12px; color: black;"
+
+        * UserInterface/Models/CSSProperty.js:
+        (WI.CSSProperty.prototype.set text):
+        Introduce `_isTextPendingSave` flag. It's needed when saving pasted text, and saving commented out or uncommented CSS properties.
+
+        (WI.CSSProperty.prototype.get formattedText):
+
+        (WI.CSSProperty.prototype.replaceWithText): Deleted.
+        This is redundant - setting `text` works the same.
+
+        (WI.CSSProperty.prototype._updateStyleText):
+        (WI.CSSProperty.prototype._updateOwnerStyleText):
+        (WI.CSSProperty.prototype._prependSemicolonIfNeeded): Deleted.
+        Greatly simplify the logic now that we save formatted text and don't modify styleText.
+
+        * UserInterface/Models/CSSStyleDeclaration.js:
+        (WI.CSSStyleDeclaration.prototype.removeProperty):
+        Remode unnecessary code that modifies `_styleSheetTextRange`. The backend sends new `_styleSheetTextRange` data
+        upon a change.
+
+        (WI.CSSStyleDeclaration.prototype.generateFormattedText): Renamed from 'generateCSSRuleString'.
+
+        * UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.js:
+        (WI.SpreadsheetCSSStyleDeclarationSection.prototype._populateIconElementContextMenu):
+        * UserInterface/Views/SpreadsheetStyleProperty.js:
+        (WI.SpreadsheetStyleProperty.prototype.remove):
+
 2021-10-05  Patrick Angle  <pan...@apple.com>
 
         Web Inspector: Show color space for canvases in the Graphics tab on the overview cards

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/CSSProperty.js (283722 => 283723)


--- trunk/Source/WebInspectorUI/UserInterface/Models/CSSProperty.js	2021-10-07 18:08:53 UTC (rev 283722)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/CSSProperty.js	2021-10-07 18:15:14 UTC (rev 283723)
@@ -34,6 +34,7 @@
         this._overridingProperty = null;
         this._initialState = null;
         this._modified = false;
+        this._isUpdatingText = false;
 
         this.update(text, name, value, priority, enabled, overridden, implicit, anonymous, valid, styleSheetTextRange, true);
     }
@@ -184,13 +185,6 @@
         this._updateStyleText(forceRemove);
     }
 
-    replaceWithText(text)
-    {
-        this._markModified();
-
-        this._updateOwnerStyleText(this._text, text, true);
-    }
-
     commentOut(disabled)
     {
         console.assert(this.editable);
@@ -213,16 +207,22 @@
 
     set text(newText)
     {
+        newText = newText.trim();
         if (this._text === newText)
             return;
 
         this._markModified();
-        this._updateOwnerStyleText(this._text, newText);
         this._text = newText;
+        this._isUpdatingText = true;
+        this._updateOwnerStyleText();
+        this._isUpdatingText = false;
     }
 
     get formattedText()
     {
+        if (this._isUpdatingText)
+            return this._text;
+
         if (!this._name)
             return "";
 
@@ -501,74 +501,24 @@
             text = this._name + ": " + value + ";";
         }
 
-        let oldText = this._text;
         this._text = text;
-        this._updateOwnerStyleText(oldText, this._text, forceRemove);
+
+        if (forceRemove)
+            this._ownerStyle.removeProperty(this);
+
+        this._updateOwnerStyleText();
     }
 
-    _updateOwnerStyleText(oldText, newText, forceRemove = false)
+    _updateOwnerStyleText()
     {
-        if (oldText === newText) {
-            if (forceRemove) {
-                const lineDelta = 0;
-                const columnDelta = 0;
-                this._ownerStyle.shiftPropertiesAfter(this, lineDelta, columnDelta, forceRemove);
-                this._ownerStyle.updatePropertiesModifiedState();
-            }
-            return;
-        }
-
         console.assert(this._ownerStyle);
         if (!this._ownerStyle)
             return;
 
-        this._prependSemicolonIfNeeded();
-
-        let styleText = this._ownerStyle.text || "";
-
-        // _styleSheetTextRange is the position of the property within the stylesheet.
-        // range is the position of the property within the rule.
-        let range = this._styleSheetTextRange.relativeTo(this._ownerStyle.styleSheetTextRange.startLine, this._ownerStyle.styleSheetTextRange.startColumn);
-
-        // Append a line break to count the last line of styleText towards endOffset.
-        range.resolveOffsets(styleText + "\n");
-
-        console.assert(oldText === styleText.slice(range.startOffset, range.endOffset), "_styleSheetTextRange data is invalid.");
-
-        if (WI.settings.debugEnableStyleEditingDebugMode.value) {
-            let prefix = styleText.slice(0, range.startOffset);
-            let postfix = styleText.slice(range.endOffset);
-            console.info(`${prefix}%c${oldText}%c${newText}%c${postfix}`, `background: hsl(356, 100%, 90%); color: black`, `background: hsl(100, 100%, 91%); color: black`, `background: transparent`);
-        }
-
-        let newStyleText = styleText.slice(0, range.startOffset) + newText + styleText.slice(range.endOffset);
-
-        let lineDelta = newText.lineCount - oldText.lineCount;
-        let columnDelta = newText.lastLine.length - oldText.lastLine.length;
-        this._styleSheetTextRange = this._styleSheetTextRange.cloneAndModify(0, 0, lineDelta, columnDelta);
-
-        this._ownerStyle.text = newStyleText;
-
-        let propertyWasRemoved = !newText;
-        this._ownerStyle.shiftPropertiesAfter(this, lineDelta, columnDelta, propertyWasRemoved);
+        this._ownerStyle.text = this._ownerStyle.generateFormattedText({multiline: this._ownerStyle.type === WI.CSSStyleDeclaration.Type.Rule});
         this._ownerStyle.updatePropertiesModifiedState();
     }
 
-    _prependSemicolonIfNeeded()
-    {
-        for (let i = this.index - 1; i >= 0; --i) {
-            let property = this._ownerStyle.properties[i];
-            if (!property.enabled)
-                continue;
-
-            let match = property.text.match(/[^;\s](\s*)$/);
-            if (match)
-                property.text = property.text.trimRight() + ";" + match[1];
-
-            break;
-        }
-    }
-
     _markModified()
     {
         if (this._ownerStyle)

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js (283722 => 283723)


--- trunk/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js	2021-10-07 18:08:53 UTC (rev 283722)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js	2021-10-07 18:15:14 UTC (rev 283723)
@@ -445,7 +445,7 @@
         WI.cssManager.addModifiedStyle(this);
     }
 
-    shiftPropertiesAfter(cssProperty, lineDelta, columnDelta, propertyWasRemoved)
+    removeProperty(cssProperty)
     {
         // cssProperty.index could be set to NaN by WI.CSSStyleDeclaration.prototype.update.
         let realIndex = this._properties.indexOf(cssProperty);
@@ -452,26 +452,8 @@
         if (realIndex === -1)
             return;
 
-        let endLine = cssProperty.styleSheetTextRange.endLine;
+        this._properties.splice(realIndex, 1);
 
-        for (let i = realIndex + 1; i < this._properties.length; i++) {
-            let property = this._properties[i];
-
-            if (property._styleSheetTextRange) {
-                if (property.styleSheetTextRange.startLine === endLine) {
-                    // Only update column data if it's on the same line.
-                    property._styleSheetTextRange = property._styleSheetTextRange.cloneAndModify(lineDelta, columnDelta, lineDelta, columnDelta);
-                } else
-                    property._styleSheetTextRange = property._styleSheetTextRange.cloneAndModify(lineDelta, 0, lineDelta, 0);
-            }
-
-            if (propertyWasRemoved && !isNaN(property._index))
-                property._index--;
-        }
-
-        if (propertyWasRemoved)
-            this._properties.splice(realIndex, 1);
-
         // Invalidate cached properties.
         this._enabledProperties = null;
         this._visibleProperties = null;
@@ -507,25 +489,60 @@
             WI.cssManager.removeModifiedStyle(this);
     }
 
-    generateCSSRuleString()
+    generateFormattedText(options = {})
     {
         let indentString = WI.indentString();
         let styleText = "";
         let groupings = this.groupings.filter((grouping) => grouping.text !== "all");
         let groupingsCount = groupings.length;
-        for (let i = groupingsCount - 1; i >= 0; --i)
-            styleText += indentString.repeat(groupingsCount - i - 1) + groupings[i].prefix + " " + groupings[i].text + " {\n";
 
-        styleText += indentString.repeat(groupingsCount) + this.selectorText + " {\n";
+        if (options.includeGroupingsAndSelectors) {
+            for (let i = groupingsCount - 1; i >= 0; --i) {
+                if (options.multiline)
+                    styleText += indentString.repeat(groupingsCount - i - 1);
 
-        for (let property of (this._styleSheetTextRange ? this.visibleProperties : this._properties))
-            styleText += indentString.repeat(groupingsCount + 1) + property.formattedText + "\n";
+                styleText += groupings[i].prefix + " " + groupings[i].text + " {";
 
-        for (let i = groupingsCount; i > 0; --i)
-            styleText += indentString.repeat(i) + "}\n";
+                if (options.multiline)
+                    styleText += "\n";
+            }
 
-        styleText += "}";
+            if (options.multiline)
+                styleText += indentString.repeat(groupingsCount);
 
+            styleText += this.selectorText + " {";
+        }
+
+        let properties = this._styleSheetTextRange ? this.visibleProperties : this._properties;
+        if (properties.length) {
+            if (options.multiline) {
+                let propertyIndent = indentString.repeat(groupingsCount + 1);
+                for (let property of properties)
+                    styleText += "\n" + propertyIndent + property.formattedText;
+
+                styleText += "\n";
+                if (!options.includeGroupingsAndSelectors) {
+                    // Indent the closing "}" for nested rules.
+                    styleText += indentString.repeat(groupingsCount);
+                }
+            } else
+                styleText += properties.map((property) => property.formattedText).join(" ");
+        }
+
+        if (options.includeGroupingsAndSelectors) {
+            for (let i = groupingsCount; i > 0; --i) {
+                if (options.multiline)
+                    styleText += indentString.repeat(i);
+
+                styleText += "}";
+
+                if (options.multiline)
+                    styleText += "\n";
+            }
+
+            styleText += "}";
+        }
+
         return styleText;
     }
 

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.js (283722 => 283723)


--- trunk/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.js	2021-10-07 18:08:53 UTC (rev 283722)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.js	2021-10-07 18:15:14 UTC (rev 283723)
@@ -481,7 +481,7 @@
     _populateIconElementContextMenu(contextMenu)
     {
         contextMenu.appendItem(WI.UIString("Copy Rule"), () => {
-            InspectorFrontendHost.copyText(this._style.generateCSSRuleString());
+            InspectorFrontendHost.copyText(this._style.generateFormattedText({includeGroupingsAndSelectors: true, multiline: true}));
         });
 
         if (this._style.editable && this._style.properties.length) {

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/SpreadsheetStyleProperty.js (283722 => 283723)


--- trunk/Source/WebInspectorUI/UserInterface/Views/SpreadsheetStyleProperty.js	2021-10-07 18:08:53 UTC (rev 283722)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/SpreadsheetStyleProperty.js	2021-10-07 18:15:14 UTC (rev 283723)
@@ -144,7 +144,7 @@
         this.element.remove();
 
         if (replacement)
-            this._property.replaceWithText(replacement);
+            this._property.text = replacement;
         else
             this._property.remove();
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to