Web Inspector: Show Selector's Specificity
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 3 Nov 2014 20:03:57 +0000 (20:03 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 3 Nov 2014 20:03:57 +0000 (20:03 +0000)
https://bugs.webkit.org/show_bug.cgi?id=138189

Patch by Joseph Pecoraro <pecoraro@apple.com> on 2014-11-03
Reviewed by Timothy Hatcher.

Source/JavaScriptCore:

* inspector/protocol/CSS.json:
Create a new named type CSSSelector to include a selector's text and specificity.
The specificity tuple is optional as it may soon be made dynamic in some cases.

Source/WebCore:

Test: inspector/css/selector-specificity.html

* css/CSSSelector.h:
Remove very stale comment. '*' is a starAtom now instead of a special -1 tag.
Made the specificity masks public class constants.

* inspector/InspectorStyleSheet.h:
* inspector/InspectorStyleSheet.cpp:
(WebCore::InspectorStyle::buildArrayForComputedStyle):
(WebCore::InspectorStyle::styleWithProperties):
(WebCore::InspectorStyleSheet::buildObjectForStyleSheetInfo):
Drive by use release() in some cases to reduce ref count churn.

(WebCore::buildObjectForSelectorHelper):
(WebCore::selectorsFromSource):
(WebCore::InspectorStyleSheet::buildObjectForSelector):
(WebCore::InspectorStyleSheet::buildObjectForSelectorList):
Build CSSSelector objects for SelectorLists.

Source/WebInspectorUI:

* Localizations/en.lproj/localizedStrings.js:
* UserInterface/Main.html:
* UserInterface/Test.html:
Add new files and strings.

* UserInterface/Models/CSSMedia.js:
Constructor functions are not needed, remove unnecessary code.

* UserInterface/Models/CSSRule.js:
(WebInspector.CSSRule.prototype.set selectors): Deleted.
This was unused and is no longer correct.

(WebInspector.CSSRule.prototype.get matchedSelectorText):
Update now that selectors are a list of objects, not just strings.

* UserInterface/Models/CSSSelector.js:
(WebInspector.CSSSelector):
(WebInspector.CSSSelector.prototype.get specificity):
New model object for protocol type CSS.CSSSelector.

* UserInterface/Models/DOMNodeStyles.js:
(WebInspector.DOMNodeStyles.prototype._parseSelectorListPayload.return):
(WebInspector.DOMNodeStyles.prototype._parseSelectorListPayload):
(WebInspector.DOMNodeStyles.prototype._parseRulePayload):
Handle parsing old and new SelectorLists.

* UserInterface/Views/CSSStyleDeclarationSection.js:
(WebInspector.CSSStyleDeclarationSection.prototype.refresh.appendSelector):
(WebInspector.CSSStyleDeclarationSection.prototype.refresh.appendSelectorText):
(WebInspector.CSSStyleDeclarationSection.prototype.refresh):
Update the code now that the list of selectors are model objects instead
of just selector text strings.

LayoutTests:

* inspector/css/matched-style-properties.html:
* inspector/css/selector-specificity-expected.txt: Added.
* inspector/css/selector-specificity.html: Copied from LayoutTests/inspector/css/matched-style-properties.html.

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

20 files changed:
LayoutTests/ChangeLog
LayoutTests/inspector/css/matched-style-properties.html
LayoutTests/inspector/css/selector-specificity-expected.txt [new file with mode: 0644]
LayoutTests/inspector/css/selector-specificity.html [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/inspector/protocol/CSS.json
Source/WebCore/ChangeLog
Source/WebCore/css/CSSSelector.cpp
Source/WebCore/css/CSSSelector.h
Source/WebCore/inspector/InspectorStyleSheet.cpp
Source/WebCore/inspector/InspectorStyleSheet.h
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
Source/WebInspectorUI/UserInterface/Main.html
Source/WebInspectorUI/UserInterface/Models/CSSMedia.js
Source/WebInspectorUI/UserInterface/Models/CSSRule.js
Source/WebInspectorUI/UserInterface/Models/CSSSelector.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Models/DOMNodeStyles.js
Source/WebInspectorUI/UserInterface/Test.html
Source/WebInspectorUI/UserInterface/Views/CSSStyleDeclarationSection.js

index e446310..b78bdaf 100644 (file)
@@ -1,3 +1,14 @@
+2014-11-03  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Show Selector's Specificity
+        https://bugs.webkit.org/show_bug.cgi?id=138189
+
+        Reviewed by Timothy Hatcher.
+
+        * inspector/css/matched-style-properties.html:
+        * inspector/css/selector-specificity-expected.txt: Added.
+        * inspector/css/selector-specificity.html: Copied from LayoutTests/inspector/css/matched-style-properties.html.
+
 2014-11-03  Lorenzo Tilve  <ltilve@igalia.com>
 
         [GTK] Unreviewed gardening. Rebaseline after r175259.
index fae20fe..5562298 100644 (file)
@@ -35,7 +35,7 @@ function test() {
     {
         for (var i = 0; i < nodeStyles.matchedRules.length; ++i) {
             var rule = nodeStyles.matchedRules[i];
-            if (rule.type != WebInspector.CSSRule.Type.Author)
+            if (rule.type !== WebInspector.CSSRule.Type.Author)
                 continue;
 
             for (var j = 0; j < rule.style.properties.length; ++j) {
diff --git a/LayoutTests/inspector/css/selector-specificity-expected.txt b/LayoutTests/inspector/css/selector-specificity-expected.txt
new file mode 100644 (file)
index 0000000..b10ba64
--- /dev/null
@@ -0,0 +1,14 @@
+Testing that selectors have expected specificity values.
+
+* (0, 0, 0)
+h1 (0, 0, 1)
+.class (0, 1, 0)
+#id (1, 0, 0)
+body h1.class-one.class-two (0, 2, 2)
+body #foo (1, 0, 1)
+body > #foo (1, 0, 1)
+body > #foo.a.b (1, 2, 1)
+h1::before (0, 1, 1)
+body h1::before (0, 1, 2)
+body.a h1.b::before (0, 3, 2)
+
diff --git a/LayoutTests/inspector/css/selector-specificity.html b/LayoutTests/inspector/css/selector-specificity.html
new file mode 100644 (file)
index 0000000..0a6fbfb
--- /dev/null
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+*,
+h1,
+.class,
+#id,
+body h1.class-one.class-two,
+body #foo,
+body > #foo,
+body > #foo.a.b,
+h1::before,
+body h1::before,
+body.a h1.b::before {
+    color: green;
+}
+</style>
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script>
+function test() {
+    var nodeStyles;
+
+    function validateSelectors()
+    {
+        for (var i = 0; i < nodeStyles.matchedRules.length; ++i) {
+            var rule = nodeStyles.matchedRules[i];
+            if (rule.type !== WebInspector.CSSRule.Type.Author)
+                continue;
+
+            for (var selector of rule.selectors)
+                InspectorTest.log(selector.text + " (" + selector.specificity.join(", ") + ")");
+        }
+
+        InspectorTest.completeTest();
+    }
+
+    function onStylesRefreshed()
+    {
+        nodeStyles.removeEventListener(WebInspector.DOMNodeStyles.Event.Refreshed, onStylesRefreshed, this);
+        validateSelectors();
+    }
+
+    WebInspector.domTreeManager.requestDocument(function(documentNode) {
+        WebInspector.domTreeManager.querySelector(documentNode.id, "#node1", function(contentNodeId) {
+            if (contentNodeId) {
+                var domNode = WebInspector.domTreeManager.nodeForId(contentNodeId);
+                nodeStyles = WebInspector.cssStyleManager.stylesForNode(domNode);
+
+                if (nodeStyles.needsRefresh)
+                    nodeStyles.addEventListener(WebInspector.DOMNodeStyles.Event.Refreshed, onStylesRefreshed, this);
+                else
+                    validateSelectors();
+            } else {
+                InspectorTest.log("DOM node not found.");
+                InspectorTest.completeTest();
+            }
+        });
+    });
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Testing that selectors have expected specificity values.</p>
+
+    <div id="node1"></div>
+</body>
+</html>
index 3f8f8bf..7dd1f5c 100644 (file)
@@ -1,5 +1,16 @@
 2014-11-03  Joseph Pecoraro  <pecoraro@apple.com>
 
+        Web Inspector: Show Selector's Specificity
+        https://bugs.webkit.org/show_bug.cgi?id=138189
+
+        Reviewed by Timothy Hatcher.
+
+        * inspector/protocol/CSS.json:
+        Create a new named type CSSSelector to include a selector's text and specificity.
+        The specificity tuple is optional as it may soon be made dynamic in some cases.
+
+2014-11-03  Joseph Pecoraro  <pecoraro@apple.com>
+
         Web Inspector: ObjC Protocol Interfaces should throw exceptions for nil arguments
         https://bugs.webkit.org/show_bug.cgi?id=138221
 
index 224e175..01587b0 100644 (file)
             "description": "Match data for a CSS rule."
         },
         {
+            "id": "CSSSelector",
+            "type": "object",
+            "properties": [
+                { "name": "text", "type": "string", "description": "Canonicalized selector text." },
+                { "name": "specificity", "optional": true, "type": "array", "items": { "type": "integer" }, "description": "Specificity (a, b, c) tuple. If missing the specificity is not known statically and may be dynamic." }
+            ],
+            "description": "CSS selector."
+        },
+        {
             "id": "SelectorList",
             "type": "object",
             "properties": [
-                { "name": "selectors", "type": "array", "items": { "type": "string" }, "description": "Selectors in the list." },
+                { "name": "selectors", "type": "array", "items": { "$ref": "CSSSelector" }, "description": "Selectors in the list." },
                 { "name": "text", "type": "string", "description": "Rule selector text." },
                 { "name": "range", "$ref": "SourceRange", "optional": true, "description": "Rule selector range in the underlying resource (if available)." }
             ],
index 40932a6..b4f5709 100644 (file)
@@ -1,3 +1,29 @@
+2014-11-03  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Show Selector's Specificity
+        https://bugs.webkit.org/show_bug.cgi?id=138189
+
+        Reviewed by Timothy Hatcher.
+
+        Test: inspector/css/selector-specificity.html
+
+        * css/CSSSelector.h:
+        Remove very stale comment. '*' is a starAtom now instead of a special -1 tag.
+        Made the specificity masks public class constants.
+
+        * inspector/InspectorStyleSheet.h:
+        * inspector/InspectorStyleSheet.cpp:
+        (WebCore::InspectorStyle::buildArrayForComputedStyle):
+        (WebCore::InspectorStyle::styleWithProperties):
+        (WebCore::InspectorStyleSheet::buildObjectForStyleSheetInfo):
+        Drive by use release() in some cases to reduce ref count churn.
+
+        (WebCore::buildObjectForSelectorHelper):
+        (WebCore::selectorsFromSource):
+        (WebCore::InspectorStyleSheet::buildObjectForSelector):
+        (WebCore::InspectorStyleSheet::buildObjectForSelectorList):
+        Build CSSSelector objects for SelectorLists.
+
 2014-11-03  Chris Dumez  <cdumez@apple.com>
 
         Move -webkit-shape-outside to the new StyleBuilder
index a7c8146..cc81134 100644 (file)
@@ -61,12 +61,6 @@ void CSSSelector::createRareData()
 
 unsigned CSSSelector::specificity() const
 {
-    // make sure the result doesn't overflow
-    static const unsigned maxValueMask = 0xffffff;
-    static const unsigned idMask = 0xff0000;
-    static const unsigned classMask = 0xff00;
-    static const unsigned elementMask = 0xff;
-
     if (isForPage())
         return specificityForPage() & maxValueMask;
 
index ac108cb..b2124e1 100644 (file)
@@ -47,7 +47,10 @@ namespace WebCore {
         // checks if the 2 selectors (including sub selectors) agree.
         bool operator==(const CSSSelector&) const;
 
-        // tag == -1 means apply to all elements (Selector = *)
+        static const unsigned maxValueMask = 0xffffff;
+        static const unsigned idMask = 0xff0000;
+        static const unsigned classMask = 0xff00;
+        static const unsigned elementMask = 0xff;
 
         unsigned specificity() const;
 
index f61cf23..84dc034 100644 (file)
@@ -151,12 +151,12 @@ static PassRefPtr<Inspector::Protocol::CSS::SourceRange> buildSourceRangeObject(
     TextPosition start = ContentSearchUtilities::textPositionFromOffset(range.start, *lineEndings);
     TextPosition end = ContentSearchUtilities::textPositionFromOffset(range.end, *lineEndings);
 
-    RefPtr<Inspector::Protocol::CSS::SourceRange> result = Inspector::Protocol::CSS::SourceRange::create()
+    return Inspector::Protocol::CSS::SourceRange::create()
         .setStartLine(start.m_line.zeroBasedInt())
         .setStartColumn(start.m_column.zeroBasedInt())
         .setEndLine(end.m_line.zeroBasedInt())
-        .setEndColumn(end.m_column.zeroBasedInt());
-    return result.release();
+        .setEndColumn(end.m_column.zeroBasedInt())
+        .release();
 }
 
 static PassRefPtr<Inspector::Protocol::CSS::CSSMedia> buildMediaObject(const MediaList* media, MediaListSource mediaListSource, const String& sourceURL)
@@ -327,7 +327,7 @@ PassRefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSComputedStyle
         RefPtr<Inspector::Protocol::CSS::CSSComputedStyleProperty> entry = Inspector::Protocol::CSS::CSSComputedStyleProperty::create()
             .setName(propertyEntry.name)
             .setValue(propertyEntry.value);
-        result->addItem(entry);
+        result->addItem(entry.release());
     }
 
     return result.release();
@@ -603,7 +603,7 @@ PassRefPtr<Inspector::Protocol::CSS::CSSStyle> InspectorStyle::styleWithProperti
                         RefPtr<Inspector::Protocol::CSS::ShorthandEntry> entry = Inspector::Protocol::CSS::ShorthandEntry::create()
                             .setName(shorthand)
                             .setValue(shorthandValue(shorthand));
-                        shorthandEntries->addItem(entry);
+                        shorthandEntries->addItem(entry.release());
                     }
                 }
             }
@@ -614,10 +614,10 @@ PassRefPtr<Inspector::Protocol::CSS::CSSStyle> InspectorStyle::styleWithProperti
             property->setStatus(status);
     }
 
-    RefPtr<Inspector::Protocol::CSS::CSSStyle> result = Inspector::Protocol::CSS::CSSStyle::create()
-        .setCssProperties(propertiesObject)
-        .setShorthandEntries(shorthandEntries);
-    return result.release();
+    return Inspector::Protocol::CSS::CSSStyle::create()
+        .setCssProperties(propertiesObject.release())
+        .setShorthandEntries(shorthandEntries.release())
+        .release();
 }
 
 PassRefPtr<CSSRuleSourceData> InspectorStyle::extractSourceData() const
@@ -981,53 +981,75 @@ PassRefPtr<Inspector::Protocol::CSS::CSSStyleSheetHeader> InspectorStyleSheet::b
 
     Document* document = styleSheet->ownerDocument();
     Frame* frame = document ? document->frame() : nullptr;
-    RefPtr<Inspector::Protocol::CSS::CSSStyleSheetHeader> result = Inspector::Protocol::CSS::CSSStyleSheetHeader::create()
+    return Inspector::Protocol::CSS::CSSStyleSheetHeader::create()
         .setStyleSheetId(id())
         .setOrigin(m_origin)
         .setDisabled(styleSheet->disabled())
         .setSourceURL(finalURL())
         .setTitle(styleSheet->title())
-        .setFrameId(m_pageAgent->frameId(frame));
+        .setFrameId(m_pageAgent->frameId(frame))
+        .release();
+}
 
-    return result.release();
+static PassRefPtr<Inspector::Protocol::CSS::CSSSelector> buildObjectForSelectorHelper(const String& selectorText, unsigned specificity)
+{
+    RefPtr<Inspector::Protocol::CSS::CSSSelector> selector = Inspector::Protocol::CSS::CSSSelector::create()
+        .setText(selectorText);
+
+    RefPtr<Inspector::Protocol::Array<int>> tuple = Inspector::Protocol::Array<int>::create();
+    tuple->addItem(static_cast<int>((specificity & CSSSelector::idMask) >> 16));
+    tuple->addItem(static_cast<int>((specificity & CSSSelector::classMask) >> 8));
+    tuple->addItem(static_cast<int>(specificity & CSSSelector::elementMask));
+    selector->setSpecificity(tuple.release());
+
+    return selector.release();
 }
 
-static PassRefPtr<Inspector::Protocol::Array<String>> selectorsFromSource(const CSSRuleSourceData* sourceData, const String& sheetText)
+static PassRefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSSelector>> selectorsFromSource(const CSSRuleSourceData* sourceData, const String& sheetText, const CSSSelectorList& selectorList)
 {
     DEPRECATED_DEFINE_STATIC_LOCAL(JSC::Yarr::RegularExpression, comment, ("/\\*[^]*?\\*/", TextCaseSensitive, JSC::Yarr::MultilineEnabled));
-    RefPtr<Inspector::Protocol::Array<String>> result = Inspector::Protocol::Array<String>::create();
+
+    RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSSelector>> result = Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSSelector>::create();
     const SelectorRangeList& ranges = sourceData->selectorRanges;
+    const CSSSelector* selector = selectorList.first();
     for (size_t i = 0, size = ranges.size(); i < size; ++i) {
         const SourceRange& range = ranges.at(i);
-        String selector = sheetText.substring(range.start, range.length());
+        String selectorText = sheetText.substring(range.start, range.length());
 
         // We don't want to see any comments in the selector components, only the meaningful parts.
-        replace(selector, comment, "");
-        result->addItem(selector.stripWhiteSpace());
+        replace(selectorText, comment, String());
+        result->addItem(buildObjectForSelectorHelper(selectorText.stripWhiteSpace(), selector->specificity()));
+
+        selector = CSSSelectorList::next(selector);
     }
     return result.release();
 }
 
+PassRefPtr<Inspector::Protocol::CSS::CSSSelector> InspectorStyleSheet::buildObjectForSelector(const CSSSelector* selector)
+{
+    return buildObjectForSelectorHelper(selector->selectorText(), selector->specificity());
+}
+
 PassRefPtr<Inspector::Protocol::CSS::SelectorList> InspectorStyleSheet::buildObjectForSelectorList(CSSStyleRule* rule)
 {
     RefPtr<CSSRuleSourceData> sourceData;
     if (ensureParsedDataReady())
         sourceData = ruleSourceDataFor(&rule->style());
-    RefPtr<Inspector::Protocol::Array<String>> selectors;
+    RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSSelector>> selectors;
 
     // This intentionally does not rely on the source data to avoid catching the trailing comments (before the declaration starting '{').
     String selectorText = rule->selectorText();
 
     if (sourceData)
-        selectors = selectorsFromSource(sourceData.get(), m_parsedStyleSheet->text());
+        selectors = selectorsFromSource(sourceData.get(), m_parsedStyleSheet->text(), rule->styleRule()->selectorList());
     else {
-        selectors = Inspector::Protocol::Array<String>::create();
+        selectors = Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSSelector>::create();
         const CSSSelectorList& selectorList = rule->styleRule()->selectorList();
         for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector))
-            selectors->addItem(selector->selectorText());
+            selectors->addItem(buildObjectForSelector(selector));
     }
     RefPtr<Inspector::Protocol::CSS::SelectorList> result = Inspector::Protocol::CSS::SelectorList::create()
-        .setSelectors(selectors)
+        .setSelectors(selectors.release())
         .setText(selectorText)
         .release();
     if (sourceData)
@@ -1074,10 +1096,10 @@ PassRefPtr<Inspector::Protocol::CSS::CSSStyle> InspectorStyleSheet::buildObjectF
 
     InspectorCSSId id = ruleOrStyleId(style);
     if (id.isEmpty()) {
-        RefPtr<Inspector::Protocol::CSS::CSSStyle> bogusStyle = Inspector::Protocol::CSS::CSSStyle::create()
+        return Inspector::Protocol::CSS::CSSStyle::create()
             .setCssProperties(Array<Inspector::Protocol::CSS::CSSProperty>::create())
-            .setShorthandEntries(Array<Inspector::Protocol::CSS::ShorthandEntry>::create());
-        return bogusStyle.release();
+            .setShorthandEntries(Array<Inspector::Protocol::CSS::ShorthandEntry>::create())
+            .release();
     }
     RefPtr<InspectorStyle> inspectorStyle = inspectorStyleForId(id);
     RefPtr<Inspector::Protocol::CSS::CSSStyle> result = inspectorStyle->buildObjectForStyle();
@@ -1175,10 +1197,8 @@ PassRefPtr<InspectorStyle> InspectorStyleSheet::inspectorStyleForId(const Inspec
         return nullptr;
 
     InspectorStyleMap::iterator it = m_inspectorStyles.find(style);
-    if (it == m_inspectorStyles.end()) {
-        RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(id, style, this);
-        return inspectorStyle.release();
-    }
+    if (it == m_inspectorStyles.end())
+        return InspectorStyle::create(id, style, this);
     return it->value;
 }
 
index feeae38..fdbf78d 100644 (file)
@@ -43,6 +43,7 @@ class ParsedStyleSheet;
 namespace WebCore {
 
 class CSSRuleList;
+class CSSSelector;
 class CSSStyleDeclaration;
 class CSSStyleRule;
 class CSSStyleSheet;
@@ -243,6 +244,7 @@ private:
     bool resourceStyleSheetText(String* result) const;
     bool inlineStyleSheetText(String* result) const;
     PassRefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSRule>> buildArrayForRuleList(CSSRuleList*);
+    PassRefPtr<Inspector::Protocol::CSS::CSSSelector> buildObjectForSelector(const CSSSelector*);
     PassRefPtr<Inspector::Protocol::CSS::SelectorList> buildObjectForSelectorList(CSSStyleRule*);
 
     InspectorPageAgent* m_pageAgent;
index 97659fc..9dbeaf8 100644 (file)
@@ -1,5 +1,45 @@
 2014-11-03  Joseph Pecoraro  <pecoraro@apple.com>
 
+        Web Inspector: Show Selector's Specificity
+        https://bugs.webkit.org/show_bug.cgi?id=138189
+
+        Reviewed by Timothy Hatcher.
+
+        * Localizations/en.lproj/localizedStrings.js:
+        * UserInterface/Main.html:
+        * UserInterface/Test.html:
+        Add new files and strings.
+
+        * UserInterface/Models/CSSMedia.js:
+        Constructor functions are not needed, remove unnecessary code.
+
+        * UserInterface/Models/CSSRule.js:
+        (WebInspector.CSSRule.prototype.set selectors): Deleted.
+        This was unused and is no longer correct.
+
+        (WebInspector.CSSRule.prototype.get matchedSelectorText):
+        Update now that selectors are a list of objects, not just strings.
+
+        * UserInterface/Models/CSSSelector.js:
+        (WebInspector.CSSSelector):
+        (WebInspector.CSSSelector.prototype.get specificity):
+        New model object for protocol type CSS.CSSSelector.
+
+        * UserInterface/Models/DOMNodeStyles.js:
+        (WebInspector.DOMNodeStyles.prototype._parseSelectorListPayload.return):
+        (WebInspector.DOMNodeStyles.prototype._parseSelectorListPayload):
+        (WebInspector.DOMNodeStyles.prototype._parseRulePayload):
+        Handle parsing old and new SelectorLists.
+
+        * UserInterface/Views/CSSStyleDeclarationSection.js:
+        (WebInspector.CSSStyleDeclarationSection.prototype.refresh.appendSelector):
+        (WebInspector.CSSStyleDeclarationSection.prototype.refresh.appendSelectorText):
+        (WebInspector.CSSStyleDeclarationSection.prototype.refresh):
+        Update the code now that the list of selectors are model objects instead
+        of just selector text strings.
+
+2014-11-03  Joseph Pecoraro  <pecoraro@apple.com>
+
         Web Inspector: ALTERNATE_DISPATCHERS Let the frontend know about extra agents
         https://bugs.webkit.org/show_bug.cgi?id=138236
 
index 806034b..546114f 100644 (file)
Binary files a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js and b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js differ
index 262d54b..3077968 100644 (file)
     <script src="Models/CSSMedia.js"></script>
     <script src="Models/CSSProperty.js"></script>
     <script src="Models/CSSRule.js"></script>
+    <script src="Models/CSSSelector.js"></script>
     <script src="Models/CSSStyleDeclaration.js"></script>
     <script src="Models/CSSStyleSheet.js"></script>
     <script src="Models/CallFrame.js"></script>
index 6e4a4eb..a8c4287 100644 (file)
@@ -32,8 +32,6 @@ WebInspector.CSSMedia = function(type, text, sourceCodeLocation)
     this._sourceCodeLocation = sourceCodeLocation || null;
 };
 
-WebInspector.Object.addConstructorFunctions(WebInspector.CSSMedia);
-
 WebInspector.CSSMedia.Type = {
     MediaRule: "css-media-type-media-rule",
     ImportRule: "css-media-type-import-rule",
index 8866cb0..07d0710 100644 (file)
@@ -139,11 +139,6 @@ WebInspector.CSSRule.prototype = {
         return this._selectors;
     },
 
-    set selectors(selectors)
-    {
-        this.selectorText = (selectors || []).join(", ");
-    },
-
     get matchedSelectorIndices()
     {
         return this._matchedSelectorIndices;
@@ -178,7 +173,7 @@ WebInspector.CSSRule.prototype = {
         if ("_matchedSelectorText" in this)
             return this._matchedSelectorText;
 
-        this._matchedSelectorText = this.matchedSelectors.join(", ");
+        this._matchedSelectorText = this.matchedSelectors.map(function(x) { return x.text; }).join(", ");
 
         return this._matchedSelectorText;
     },
diff --git a/Source/WebInspectorUI/UserInterface/Models/CSSSelector.js b/Source/WebInspectorUI/UserInterface/Models/CSSSelector.js
new file mode 100644 (file)
index 0000000..ad2c59f
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 Apple Inc. 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.CSSSelector = function(text, specificity)
+{
+    WebInspector.Object.call(this);
+
+    console.assert(text);
+
+    this._text = text;
+    this._specificity = specificity || null;
+};
+
+WebInspector.CSSSelector.prototype = {
+    constructor: WebInspector.CSSSelector,
+    __proto__: WebInspector.Object.prototype,
+
+    // Public
+
+    get text()
+    {
+        return this._text;
+    },
+
+    get specificity()
+    {
+        return this._specificity;
+    }
+};
index fd433c6..802e2b7 100644 (file)
@@ -745,6 +745,29 @@ WebInspector.DOMNodeStyles.prototype = {
         return styleDeclaration;
     },
 
+    _parseSelectorListPayload: function(selectorList)
+    {
+        // COMPATIBILITY (iOS 6): The payload did not have 'selectorList'.
+        if (!selectorList)
+            return [];
+
+        var selectors = selectorList.selectors;
+        if (!selectors.length)
+            return [];
+
+        // COMPATIBILITY (iOS 8): The selectorList payload was an array of selector text strings.
+        // Now they are CSSSelector objects with multiple properties.
+        if (typeof selectors[0] === "string") {
+            return selectors.map(function(selectorText) {
+                return new WebInspector.CSSSelector(selectorText);
+            });
+        }
+
+        return selectors.map(function(selectorPayload) {
+            return new WebInspector.CSSSelector(selectorPayload.text, selectorPayload.specificity);
+        });
+    },
+
     _parseRulePayload: function(payload, matchedSelectorIndices, node, inherited, ruleOccurrences)
     {
         if (!payload)
@@ -791,7 +814,7 @@ WebInspector.DOMNodeStyles.prototype = {
         // COMPATIBILITY (iOS 6): The payload had 'selectorText' as a property,
         // now it has 'selectorList' with a 'text' property. Support both here.
         var selectorText = payload.selectorList ? payload.selectorList.text : payload.selectorText;
-        var selectors = payload.selectorList ? payload.selectorList.selectors : [];
+        var selectors = this._parseSelectorListPayload(payload.selectorList);
 
         // COMPATIBILITY (iOS 6): The payload did not have 'selectorList'.
         // Fallback to using 'sourceLine' without column information.
index 4dc1e87..7d4bb55 100644 (file)
@@ -74,6 +74,7 @@
     <script src="Models/CSSKeywordCompletions.js"></script>
     <script src="Models/CSSProperty.js"></script>
     <script src="Models/CSSRule.js"></script>
+    <script src="Models/CSSSelector.js"></script>
     <script src="Models/CSSStyleDeclaration.js"></script>
     <script src="Models/CSSStyleSheet.js"></script>
     <script src="Models/DOMNode.js"></script>
index af0d9c5..04fe847 100644 (file)
@@ -168,12 +168,30 @@ WebInspector.CSSStyleDeclarationSection.prototype = {
 
         this._originElement.appendChild(document.createTextNode(" \u2014 "));
 
-        function appendSelector(selectorText, matched)
+        function appendSelector(selector, matched)
         {
+            console.assert(selector instanceof WebInspector.CSSSelector);
+
             var selectorElement = document.createElement("span");
+            selectorElement.textContent = selector.text;
+
             if (matched)
                 selectorElement.className = WebInspector.CSSStyleDeclarationSection.MatchedSelectorElementStyleClassName;
+
+            var specificity = selector.specificity;
+            if (specificity) {
+                var approximatedSpecificity = (specificity[0] * 100) + (specificity[1] * 10) + specificity[2];
+                selectorElement.title = WebInspector.UIString("Specificity: (%d, %d, %d) ≈ %d").format(specificity[0], specificity[1], specificity[2], approximatedSpecificity);
+            }
+
+            this._selectorElement.appendChild(selectorElement);
+        }
+
+        function appendSelectorTextKnownToMatch(selectorText)
+        {
+            var selectorElement = document.createElement("span");
             selectorElement.textContent = selectorText;
+            selectorElement.className = WebInspector.CSSStyleDeclarationSection.MatchedSelectorElementStyleClassName;
             this._selectorElement.appendChild(selectorElement);
         }
 
@@ -190,7 +208,7 @@ WebInspector.CSSStyleDeclarationSection.prototype = {
                         this._selectorElement.appendChild(document.createTextNode(", "));
                 }
             } else
-                appendSelector.call(this, this._style.ownerRule.selectorText, true);
+                appendSelectorTextKnownToMatch.call(this, this._style.ownerRule.selectorText);
 
             if (this._style.ownerRule.sourceCodeLocation) {
                 var sourceCodeLink = WebInspector.createSourceCodeLocationLink(this._style.ownerRule.sourceCodeLocation, true);
@@ -223,12 +241,12 @@ WebInspector.CSSStyleDeclarationSection.prototype = {
             break;
 
         case WebInspector.CSSStyleDeclaration.Type.Inline:
-            appendSelector.call(this, WebInspector.displayNameForNode(this._style.node), true);
+            appendSelectorTextKnownToMatch.call(this, WebInspector.displayNameForNode(this._style.node));
             this._originElement.appendChild(document.createTextNode(WebInspector.UIString("Style Attribute")));
             break;
 
         case WebInspector.CSSStyleDeclaration.Type.Attribute:
-            appendSelector.call(this, WebInspector.displayNameForNode(this._style.node), true);
+            appendSelectorTextKnownToMatch.call(this, WebInspector.displayNameForNode(this._style.node));
             this._originElement.appendChild(document.createTextNode(WebInspector.UIString("HTML Attributes")));
             break;
         }