Title: [128746] trunk
Revision
128746
Author
[email protected]
Date
2012-09-17 05:46:57 -0700 (Mon, 17 Sep 2012)

Log Message

Web Inspector: Group selectors to highlight matched selector in the Styles pane of Elements Panel
https://bugs.webkit.org/show_bug.cgi?id=96626

Reviewed by Vsevolod Vlasov.

Source/WebCore:

Introduced evaluation of element.webkitMatchesSelector() for every part of a selector group (delimited by commas).
Non-matching selectors in groups are dimmed. If element styles have changed so that the element matches none of the selectors,
the entire group is rendered as matched.

* inspector/front-end/StylesSidebarPane.js:
(WebInspector.StylesSidebarPane.prototype._innerRebuildUpdate.markCallback):
(WebInspector.StylesSidebarPane.prototype._innerRebuildUpdate):
(WebInspector.StylesSidebarPane.prototype._rebuildStyleRules):
(WebInspector.StylePropertiesSection):
(WebInspector.StylePropertiesSection.prototype._markMatchedSelectorsInGroup.mycallback):
(WebInspector.StylePropertiesSection.prototype._markMatchedSelectorsInGroup.trim):
(WebInspector.StylePropertiesSection.prototype._markMatchedSelectorsInGroup.resolvedCallback):
(WebInspector.StylePropertiesSection.prototype._markMatchedSelectorsInGroup):
(WebInspector.StylePropertiesSection.prototype._markMatchedSelectorsInGroup.matchesCallback):
(WebInspector.StylePropertiesSection.prototype.startEditingSelector):
(WebInspector.StylePropertiesSection.prototype._moveEditorFromSelector.markCallback):
(WebInspector.StylePropertiesSection.prototype._moveEditorFromSelector):
(WebInspector.StylePropertiesSection.prototype.editingSelectorCancelled):
* inspector/front-end/elementsPanel.css:
(.styles-section .selector):
(.styles-section .selector-matches):

LayoutTests:

* http/tests/inspector/elements-test.js:
(initialize_ElementTest.InspectorTest.dumpSelectedElementStyles.buildMarkedSelectors):
(initialize_ElementTest.InspectorTest.dumpSelectedElementStyles): Let tests get matched selector markings in dumped data
* inspector/styles/styles-add-new-rule-expected.txt:
* inspector/styles/styles-add-new-rule.html:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (128745 => 128746)


--- trunk/LayoutTests/ChangeLog	2012-09-17 12:45:44 UTC (rev 128745)
+++ trunk/LayoutTests/ChangeLog	2012-09-17 12:46:57 UTC (rev 128746)
@@ -1,3 +1,16 @@
+2012-09-14  Alexander Pavlov  <[email protected]>
+
+        Web Inspector: Group selectors to highlight matched selector in the Styles pane of Elements Panel
+        https://bugs.webkit.org/show_bug.cgi?id=96626
+
+        Reviewed by Vsevolod Vlasov.
+
+        * http/tests/inspector/elements-test.js:
+        (initialize_ElementTest.InspectorTest.dumpSelectedElementStyles.buildMarkedSelectors):
+        (initialize_ElementTest.InspectorTest.dumpSelectedElementStyles): Let tests get matched selector markings in dumped data
+        * inspector/styles/styles-add-new-rule-expected.txt:
+        * inspector/styles/styles-add-new-rule.html:
+
 2012-09-17  Christophe Dumez  <[email protected]>
 
         [EFL] Unskip css3/flexbox/anonymous-block.html test case

Modified: trunk/LayoutTests/http/tests/inspector/elements-test.js (128745 => 128746)


--- trunk/LayoutTests/http/tests/inspector/elements-test.js	2012-09-17 12:45:44 UTC (rev 128745)
+++ trunk/LayoutTests/http/tests/inspector/elements-test.js	2012-09-17 12:46:57 UTC (rev 128746)
@@ -118,7 +118,7 @@
     InspectorTest.selectNodeAndWaitForStyles(idValue, stylesCallback);
 }
 
-InspectorTest.dumpSelectedElementStyles = function(excludeComputed, excludeMatched, omitLonghands)
+InspectorTest.dumpSelectedElementStyles = function(excludeComputed, excludeMatched, omitLonghands, includeSelectorGroupMarks)
 {
     function extractText(element)
     {
@@ -129,6 +129,18 @@
         return element ? element.getAttribute("data-uncopyable") : "";
     }
 
+    function buildMarkedSelectors(element)
+    {
+        var result = "";
+        for (var node = element.firstChild; node; node = node.nextSibling) {
+            if (node.nodeType === Node.ELEMENT_NODE && node.className === "selector-matches")
+                result += "[$" + node.textContent + "$]";
+            else
+                result += node.textContent;
+        }
+        return result;
+    }
+
     var styleSections = WebInspector.panels.elements.sidebarPanes.styles.sections;
     for (var pseudoId in styleSections) {
         var pseudoName = WebInspector.StylesSidebarPane.PseudoIdNames[pseudoId];
@@ -145,7 +157,7 @@
             var chainEntries = section.titleElement.children;
             for (var j = 0; j < chainEntries.length; ++j) {
                 var chainEntry = chainEntries[j];
-                var entryLine = chainEntry.children[1].textContent;
+                var entryLine = includeSelectorGroupMarks ? buildMarkedSelectors(chainEntry.children[1]) : chainEntry.children[1].textContent;
                 if (chainEntry.children[2])
                     entryLine += " " + chainEntry.children[2].textContent;
                 entryLine += " (" + extractText(chainEntry.children[0]) + ")";

Modified: trunk/LayoutTests/inspector/styles/styles-add-new-rule-expected.txt (128745 => 128746)


--- trunk/LayoutTests/inspector/styles/styles-add-new-rule-expected.txt	2012-09-17 12:45:44 UTC (rev 128745)
+++ trunk/LayoutTests/inspector/styles/styles-add-new-rule-expected.txt	2012-09-17 12:46:57 UTC (rev 128746)
@@ -9,7 +9,7 @@
 
 ======== Matched CSS Rules ========
 [expanded] 
-#inspected  { (inspector-stylesheet:1)
+foo, [$#inspected$], bar  { (inspector-stylesheet:1)
 color: maroon;
 
 [expanded] 

Modified: trunk/LayoutTests/inspector/styles/styles-add-new-rule.html (128745 => 128746)


--- trunk/LayoutTests/inspector/styles/styles-add-new-rule.html	2012-09-17 12:45:44 UTC (rev 128745)
+++ trunk/LayoutTests/inspector/styles/styles-add-new-rule.html	2012-09-17 12:46:57 UTC (rev 128746)
@@ -18,6 +18,7 @@
         // Click "Add new rule".
         document.getElementById("add-style-button-test-id").click();
         var section = WebInspector.panels.elements.sidebarPanes.styles.sections[0][2];
+        section._selectorElement.textContent = "foo, " + section._selectorElement.textContent + ", bar";
         section._selectorElement.dispatchEvent(InspectorTest.createKeyEvent("Enter"));
         InspectorTest.runAfterPendingDispatches(step2);
     }
@@ -44,7 +45,7 @@
     function step4()
     {
         InspectorTest.addResult("After adding new rule (inspected):");
-        InspectorTest.dumpSelectedElementStyles(true, false, true);
+        InspectorTest.dumpSelectedElementStyles(true, false, true, true);
         InspectorTest.selectNodeAndWaitForStyles("other", step5);
     }
 

Modified: trunk/Source/WebCore/ChangeLog (128745 => 128746)


--- trunk/Source/WebCore/ChangeLog	2012-09-17 12:45:44 UTC (rev 128745)
+++ trunk/Source/WebCore/ChangeLog	2012-09-17 12:46:57 UTC (rev 128746)
@@ -1,3 +1,32 @@
+2012-09-14  Alexander Pavlov  <[email protected]>
+
+        Web Inspector: Group selectors to highlight matched selector in the Styles pane of Elements Panel
+        https://bugs.webkit.org/show_bug.cgi?id=96626
+
+        Reviewed by Vsevolod Vlasov.
+
+        Introduced evaluation of element.webkitMatchesSelector() for every part of a selector group (delimited by commas).
+        Non-matching selectors in groups are dimmed. If element styles have changed so that the element matches none of the selectors,
+        the entire group is rendered as matched.
+
+        * inspector/front-end/StylesSidebarPane.js:
+        (WebInspector.StylesSidebarPane.prototype._innerRebuildUpdate.markCallback):
+        (WebInspector.StylesSidebarPane.prototype._innerRebuildUpdate):
+        (WebInspector.StylesSidebarPane.prototype._rebuildStyleRules):
+        (WebInspector.StylePropertiesSection):
+        (WebInspector.StylePropertiesSection.prototype._markMatchedSelectorsInGroup.mycallback):
+        (WebInspector.StylePropertiesSection.prototype._markMatchedSelectorsInGroup.trim):
+        (WebInspector.StylePropertiesSection.prototype._markMatchedSelectorsInGroup.resolvedCallback):
+        (WebInspector.StylePropertiesSection.prototype._markMatchedSelectorsInGroup):
+        (WebInspector.StylePropertiesSection.prototype._markMatchedSelectorsInGroup.matchesCallback):
+        (WebInspector.StylePropertiesSection.prototype.startEditingSelector):
+        (WebInspector.StylePropertiesSection.prototype._moveEditorFromSelector.markCallback):
+        (WebInspector.StylePropertiesSection.prototype._moveEditorFromSelector):
+        (WebInspector.StylePropertiesSection.prototype.editingSelectorCancelled):
+        * inspector/front-end/elementsPanel.css:
+        (.styles-section .selector):
+        (.styles-section .selector-matches):
+
 2012-09-17  Mike West  <[email protected]>
 
         Don't GC img elements blocked by CSP until error events fire.

Modified: trunk/Source/WebCore/inspector/front-end/StylesSidebarPane.js (128745 => 128746)


--- trunk/Source/WebCore/inspector/front-end/StylesSidebarPane.js	2012-09-17 12:45:44 UTC (rev 128745)
+++ trunk/Source/WebCore/inspector/front-end/StylesSidebarPane.js	2012-09-17 12:46:57 UTC (rev 128746)
@@ -358,6 +358,7 @@
         var usedProperties = {};
         this._markUsedProperties(styleRules, usedProperties);
         this.sections[0] = this._rebuildSectionsForStyleRules(styleRules, usedProperties, 0, null);
+        var responsesLeft = this.sections[0].length;
         var anchorElement = this.sections[0].inheritedPropertiesSeparatorElement;
 
         if (styles.computedStyle)        
@@ -380,9 +381,28 @@
             usedProperties = {};
             this._markUsedProperties(styleRules, usedProperties);
             this.sections[pseudoId] = this._rebuildSectionsForStyleRules(styleRules, usedProperties, pseudoId, anchorElement);
+            responsesLeft += this.sections[pseudoId].length;
         }
 
-        this._nodeStylesUpdatedForTest(node, true);
+        // Mark matching selectors in comma-delimited selector groups.
+        var boundMarkCallback = markCallback.bind(this);
+        for (var id in this.sections) {
+            var sectionsForPseudoId = this.sections[id].slice();
+            for (var j = 0; j < sectionsForPseudoId.length; ++j) {
+                var section = sectionsForPseudoId[j];
+                if (!section.styleRule || section.isBlank || section.styleRule.computedStyle || section.styleRule.isAttribute) {
+                    boundMarkCallback();
+                    continue;
+                }
+                section._markMatchedSelectorsInGroup(boundMarkCallback);
+            }
+        }
+
+        function markCallback()
+        {
+            if (!(--responsesLeft))
+                this._nodeStylesUpdatedForTest(node, true);
+        }
     },
 
     _nodeStylesUpdatedForTest: function(node, rebuild)
@@ -464,7 +484,7 @@
             var separatorInserted = false;
             if (parentStyles.inlineStyle) {
                 if (this._containsInherited(parentStyles.inlineStyle)) {
-                    var inlineStyle = { selectorText: WebInspector.UIString("Style Attribute"), style: parentStyles.inlineStyle, isAttribute: true, isInherited: true };
+                    var inlineStyle = { selectorText: WebInspector.UIString("Style Attribute"), style: parentStyles.inlineStyle, isAttribute: true, isInherited: true, parentNode: parentNode };
                     if (!separatorInserted) {
                         insertInheritedNodeSeparator(parentNode);
                         separatorInserted = true;
@@ -485,7 +505,7 @@
                     insertInheritedNodeSeparator(parentNode);
                     separatorInserted = true;
                 }
-                styleRules.push({ style: rule.style, selectorText: rule.selectorText, media: rule.media, sourceURL: rule.sourceURL, rule: rule, isInherited: true, editable: !!(rule.style && rule.style.id) });
+                styleRules.push({ style: rule.style, selectorText: rule.selectorText, media: rule.media, sourceURL: rule.sourceURL, rule: rule, isInherited: true, parentNode: parentNode, editable: !!(rule.style && rule.style.id) });
             }
             parentNode = parentNode.parentNode;
         }
@@ -873,6 +893,7 @@
 
     var selectorContainer = document.createElement("div");
     this._selectorElement = document.createElement("span");
+    this._selectorElement.addStyleClass("selector-matches");
     this._selectorElement.textContent = styleRule.selectorText;
     selectorContainer.appendChild(this._selectorElement);
 
@@ -913,7 +934,7 @@
     this._selectorContainer = selectorContainer;
 
     if (isInherited)
-        this.element.addStyleClass("show-inherited"); // This one is related to inherited rules, not compted style.
+        this.element.addStyleClass("show-inherited"); // This one is related to inherited rules, not computed style.
 
     if (!this.editable)
         this.element.addStyleClass("read-only");
@@ -1103,6 +1124,91 @@
         return null;
     },
 
+    /**
+     * @param {function()=} callback
+     */
+    _markMatchedSelectorsInGroup: function(callback)
+    {
+        var self = this;
+        function mycallback()
+        {
+            if (callback)
+                callback();
+        }
+
+        var selectorText = this._selectorElement.textContent;
+        if (!selectorText || selectorText.indexOf(",") === -1) {
+            mycallback();
+            return;
+        }
+
+        var paneNode = this._parentPane.node;
+        var relatedNode = this.styleRule.parentNode || paneNode;
+        if (!relatedNode) {
+            mycallback();
+            return;
+        }
+
+        function trim(text)
+        {
+            return text.trim();
+        }
+        var selectors = selectorText.split(",").map(trim);
+
+        WebInspector.RemoteObject.resolveNode(relatedNode, "", resolvedCallback);
+        function resolvedCallback(object)
+        {
+            if (!object) {
+                mycallback();
+                return;
+            }
+
+            for (var i = 0, size = selectors.length; i < size; ++i) {
+                var selector = selectors[i];
+                object.callFunctionJSON(matchesSelector, [{ value: selectors[i] }], matchesCallback.bind(this, i));
+            }
+        }
+
+        function matchesSelector(selector)
+        {
+            return this.webkitMatchesSelector(selector);
+        }
+
+        var result = [];
+        var matchFound;
+        function matchesCallback(selectorIndex, matches)
+        {
+            var isLast = selectorIndex === selectors.length - 1;
+            var fragment = document.createDocumentFragment();
+            result[selectorIndex] = fragment;
+
+            var selectorNode;
+            if (matches && paneNode === self._parentPane.node) {
+                selectorNode = document.createElement("span");
+                selectorNode.className = "selector-matches";
+                selectorNode.appendChild(document.createTextNode(selectors[selectorIndex]));
+                matchFound = true;
+            } else
+                selectorNode = document.createTextNode(selectors[selectorIndex]);
+
+            fragment.appendChild(selectorNode);
+            if (!isLast) {
+                fragment.appendChild(document.createTextNode(", "));
+                return;
+            }
+
+            // This check is here in case the element class has been changed from JS during the roundtrip,
+            // so the element matches none of the distinct selectors. Fall back to "all selectors match".
+            if (matchFound) {
+                self._selectorElement.className = "selector";
+                self._selectorElement.removeChildren();
+                for (var i = 0; i < result.length; ++i)
+                    self._selectorElement.appendChild(result[i]);
+            }
+            mycallback();
+        }
+    },
+
     _checkWillCancelEditing: function()
     {
         var willCauseCancelEditing = this._willCauseCancelEditing;
@@ -1233,7 +1339,8 @@
         if (WebInspector.isBeingEdited(element))
             return;
 
-        this._selectorElement.scrollIntoViewIfNeeded(false);
+        element.scrollIntoViewIfNeeded(false);
+        element.textContent = element.textContent; // Reset selector marks in group.
 
         var config = new WebInspector.EditingConfig(this.editingSelectorCommitted.bind(this), this.editingSelectorCancelled.bind(this));
         WebInspector.startEditing(this._selectorElement, config);
@@ -1243,25 +1350,32 @@
 
     _moveEditorFromSelector: function(moveDirection)
     {
-        if (!moveDirection)
+
+        if (!moveDirection) {
+            this._markMatchedSelectorsInGroup();
             return;
+        }
 
-        if (moveDirection === "forward") {
-            this.expand();
-            var firstChild = this.propertiesTreeOutline.children[0];
-            while (firstChild && firstChild.inherited)
-                firstChild = firstChild.nextSibling;
-            if (!firstChild)
-                this.addNewBlankProperty().startEditing();
-            else
-                firstChild.startEditing(firstChild.nameElement);
-        } else {
-            var previousSection = this.previousEditableSibling();
-            if (!previousSection)
-                return;
+        this._markMatchedSelectorsInGroup(markCallback.bind(this));
 
-            previousSection.expand();
-            previousSection.addNewBlankProperty().startEditing();
+        function markCallback() {
+            if (moveDirection === "forward") {
+                this.expand();
+                var firstChild = this.propertiesTreeOutline.children[0];
+                while (firstChild && firstChild.inherited)
+                    firstChild = firstChild.nextSibling;
+                if (!firstChild)
+                    this.addNewBlankProperty().startEditing();
+                else
+                    firstChild.startEditing(firstChild.nameElement);
+            } else {
+                var previousSection = this.previousEditableSibling();
+                if (!previousSection)
+                    return;
+
+                previousSection.expand();
+                previousSection.addNewBlankProperty().startEditing();
+            }
         }
     },
 
@@ -1299,7 +1413,9 @@
 
     editingSelectorCancelled: function()
     {
-        // Do nothing, this is overridden by BlankStylePropertiesSection.
+        // Do nothing but mark the selectors in group if necessary.
+        // This is overridden by BlankStylePropertiesSection.
+        this._markMatchedSelectorsInGroup();
     }
 }
 

Modified: trunk/Source/WebCore/inspector/front-end/elementsPanel.css (128745 => 128746)


--- trunk/Source/WebCore/inspector/front-end/elementsPanel.css	2012-09-17 12:45:44 UTC (rev 128745)
+++ trunk/Source/WebCore/inspector/front-end/elementsPanel.css	2012-09-17 12:46:57 UTC (rev 128746)
@@ -223,6 +223,14 @@
     color: inherit;
 }
 
+.styles-section .selector {
+    color: #777;
+}
+
+.styles-section .selector-matches {
+    color: black;
+}
+
 .styles-section a[data-uncopyable] {
     display: inline-block;
 }
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to