Web Inspector: Styles Redesign: hook up real data to spreadsheet style editor
authornvasilyev@apple.com <nvasilyev@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 4 Sep 2017 20:24:10 +0000 (20:24 +0000)
committernvasilyev@apple.com <nvasilyev@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 4 Sep 2017 20:24:10 +0000 (20:24 +0000)
https://bugs.webkit.org/show_bug.cgi?id=175343
<rdar://problem/33784793>

Reviewed by Devin Rousso.

Replace static HTML added in <https://webkit.org/b/174838> with actual data.

Addressed in this patch:
- CSS rules can be copied.
- Source links work as expected.
- Nonmatching selectors are grayed out.

Known limitations:
- Neither CSS selectors nor CSS properties are editable.
- "Inherited from" and media query section headers are missing.
- No syntax highlighting of complex CSS values, e.g. hsl(0, 0%, 70%).

* UserInterface/Main.html:
* UserInterface/Models/CSSStyleDeclaration.js:
* UserInterface/Views/CSSStyleDeclarationTextEditor.js:
(WI.CSSStyleDeclarationTextEditor):
* UserInterface/Views/CSSStyleDetailsSidebarPanel.js:
(WI.CSSStyleDetailsSidebarPanel):
* UserInterface/Views/RulesStyleSpreadsheetDetailsPanel.js: Removed.
Rename RulesStyleSpreadsheetDetailsPanel to SpreadsheetRulesStyleDetailsPanel. All files related to the spreadsheet editor start with "Spreadsheet" now.

* UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.css: Added.
(.spreadsheet-style-declaration-editor):
(.spreadsheet-style-declaration-editor .name):
(.spreadsheet-style-declaration-editor .value):
(.spreadsheet-style-declaration-editor.no-properties):
* UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.js: Added.
(WI.SpreadsheetCSSStyleDeclarationEditor):
(WI.SpreadsheetCSSStyleDeclarationEditor.prototype.layout):
(WI.SpreadsheetCSSStyleDeclarationEditor.prototype.get delegate):
(WI.SpreadsheetCSSStyleDeclarationEditor.prototype.set delegate):
(WI.SpreadsheetCSSStyleDeclarationEditor.prototype.get style):
(WI.SpreadsheetCSSStyleDeclarationEditor.prototype.set style):
(WI.SpreadsheetCSSStyleDeclarationEditor.prototype.get _propertiesToRender):
Similar condition is commonly used in CSSStyleDeclarationTextEditor. Abstact it out to its own method.

(WI.SpreadsheetCSSStyleDeclarationEditor.prototype._renderProperty):
* UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.css: Copied from Source/WebInspectorUI/UserInterface/Views/RulesStyleSpreadsheetDetailsPanel.css.
(.spreadsheet-css-declaration):
(.spreadsheet-css-declaration .origin):
(.spreadsheet-css-declaration.locked .origin::after):
(.spreadsheet-css-declaration .origin .go-to-link):
(.spreadsheet-css-declaration .origin .go-to-link:hover):
(.spreadsheet-css-declaration .styles-source):
(.spreadsheet-css-declaration .selector.style-attribute):
(.spreadsheet-css-declaration .selector > span):
(.spreadsheet-css-declaration .selector > .matched):
(.spreadsheet-css-declaration .properties):
(.spreadsheet-css-declaration.locked):
(.spreadsheet-css-declaration .locked-icon):
* UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.js: Added.
(WI.SpreadsheetCSSStyleDeclarationSection):
(WI.SpreadsheetCSSStyleDeclarationSection.prototype.get element):
(WI.SpreadsheetCSSStyleDeclarationSection.prototype.get style):
(WI.SpreadsheetCSSStyleDeclarationSection.prototype.initialLayout):
(WI.SpreadsheetCSSStyleDeclarationSection.prototype.layout):
(WI.SpreadsheetCSSStyleDeclarationSection.prototype.cssStyleDeclarationTextEditorFocused):
(WI.SpreadsheetCSSStyleDeclarationSection.prototype.get locked):
(WI.SpreadsheetCSSStyleDeclarationSection.prototype.get selectorEditable):
* UserInterface/Views/SpreadsheetRulesStyleDetailsPanel.css: Renamed from Source/WebInspectorUI/UserInterface/Views/RulesStyleSpreadsheetDetailsPanel.css.
* UserInterface/Views/SpreadsheetRulesStyleDetailsPanel.js: Added.
(WI.SpreadsheetRulesStyleDetailsPanel):
(WI.SpreadsheetRulesStyleDetailsPanel.prototype.refresh):
* UserInterface/Views/StyleDetailsPanel.js:
(WI.StyleDetailsPanel.prototype.filterDidChange):

* UserInterface/Views/View.js:
(WI.View.prototype.removeAllSubviews):
Add a method to remove all subviews more efficiently.

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

12 files changed:
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Main.html
Source/WebInspectorUI/UserInterface/Views/CSSStyleDetailsSidebarPanel.js
Source/WebInspectorUI/UserInterface/Views/RulesStyleSpreadsheetDetailsPanel.js [deleted file]
Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.css [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.css [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Views/SpreadsheetRulesStyleDetailsPanel.css [moved from Source/WebInspectorUI/UserInterface/Views/RulesStyleSpreadsheetDetailsPanel.css with 100% similarity]
Source/WebInspectorUI/UserInterface/Views/SpreadsheetRulesStyleDetailsPanel.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Views/StyleDetailsPanel.js
Source/WebInspectorUI/UserInterface/Views/View.js

index 9a398cd..a978edf 100644 (file)
@@ -1,3 +1,81 @@
+2017-09-04  Nikita Vasilyev  <nvasilyev@apple.com>
+
+        Web Inspector: Styles Redesign: hook up real data to spreadsheet style editor
+        https://bugs.webkit.org/show_bug.cgi?id=175343
+        <rdar://problem/33784793>
+
+        Reviewed by Devin Rousso.
+
+        Replace static HTML added in <https://webkit.org/b/174838> with actual data.
+
+        Addressed in this patch:
+        - CSS rules can be copied.
+        - Source links work as expected.
+        - Nonmatching selectors are grayed out.
+
+        Known limitations:
+        - Neither CSS selectors nor CSS properties are editable.
+        - "Inherited from" and media query section headers are missing.
+        - No syntax highlighting of complex CSS values, e.g. hsl(0, 0%, 70%).
+
+        * UserInterface/Main.html:
+        * UserInterface/Models/CSSStyleDeclaration.js:
+        * UserInterface/Views/CSSStyleDeclarationTextEditor.js:
+        (WI.CSSStyleDeclarationTextEditor):
+        * UserInterface/Views/CSSStyleDetailsSidebarPanel.js:
+        (WI.CSSStyleDetailsSidebarPanel):
+        * UserInterface/Views/RulesStyleSpreadsheetDetailsPanel.js: Removed.
+        Rename RulesStyleSpreadsheetDetailsPanel to SpreadsheetRulesStyleDetailsPanel. All files related to the spreadsheet editor start with "Spreadsheet" now.
+
+        * UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.css: Added.
+        (.spreadsheet-style-declaration-editor):
+        (.spreadsheet-style-declaration-editor .name):
+        (.spreadsheet-style-declaration-editor .value):
+        (.spreadsheet-style-declaration-editor.no-properties):
+        * UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.js: Added.
+        (WI.SpreadsheetCSSStyleDeclarationEditor):
+        (WI.SpreadsheetCSSStyleDeclarationEditor.prototype.layout):
+        (WI.SpreadsheetCSSStyleDeclarationEditor.prototype.get delegate):
+        (WI.SpreadsheetCSSStyleDeclarationEditor.prototype.set delegate):
+        (WI.SpreadsheetCSSStyleDeclarationEditor.prototype.get style):
+        (WI.SpreadsheetCSSStyleDeclarationEditor.prototype.set style):
+        (WI.SpreadsheetCSSStyleDeclarationEditor.prototype.get _propertiesToRender):
+        Similar condition is commonly used in CSSStyleDeclarationTextEditor. Abstact it out to its own method.
+
+        (WI.SpreadsheetCSSStyleDeclarationEditor.prototype._renderProperty):
+        * UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.css: Copied from Source/WebInspectorUI/UserInterface/Views/RulesStyleSpreadsheetDetailsPanel.css.
+        (.spreadsheet-css-declaration):
+        (.spreadsheet-css-declaration .origin):
+        (.spreadsheet-css-declaration.locked .origin::after):
+        (.spreadsheet-css-declaration .origin .go-to-link):
+        (.spreadsheet-css-declaration .origin .go-to-link:hover):
+        (.spreadsheet-css-declaration .styles-source):
+        (.spreadsheet-css-declaration .selector.style-attribute):
+        (.spreadsheet-css-declaration .selector > span):
+        (.spreadsheet-css-declaration .selector > .matched):
+        (.spreadsheet-css-declaration .properties):
+        (.spreadsheet-css-declaration.locked):
+        (.spreadsheet-css-declaration .locked-icon):
+        * UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.js: Added.
+        (WI.SpreadsheetCSSStyleDeclarationSection):
+        (WI.SpreadsheetCSSStyleDeclarationSection.prototype.get element):
+        (WI.SpreadsheetCSSStyleDeclarationSection.prototype.get style):
+        (WI.SpreadsheetCSSStyleDeclarationSection.prototype.initialLayout):
+        (WI.SpreadsheetCSSStyleDeclarationSection.prototype.layout):
+        (WI.SpreadsheetCSSStyleDeclarationSection.prototype.cssStyleDeclarationTextEditorFocused):
+        (WI.SpreadsheetCSSStyleDeclarationSection.prototype.get locked):
+        (WI.SpreadsheetCSSStyleDeclarationSection.prototype.get selectorEditable):
+        * UserInterface/Views/SpreadsheetRulesStyleDetailsPanel.css: Renamed from Source/WebInspectorUI/UserInterface/Views/RulesStyleSpreadsheetDetailsPanel.css.
+        * UserInterface/Views/SpreadsheetRulesStyleDetailsPanel.js: Added.
+        (WI.SpreadsheetRulesStyleDetailsPanel):
+        (WI.SpreadsheetRulesStyleDetailsPanel.prototype.refresh):
+        * UserInterface/Views/StyleDetailsPanel.js:
+        (WI.StyleDetailsPanel.prototype.filterDidChange):
+
+        * UserInterface/Views/View.js:
+        (WI.View.prototype.removeAllSubviews):
+        Add a method to remove all subviews more efficiently.
+
 2017-08-29  Matt Baker  <mattbaker@apple.com>
 
         Web Inspector: Critical content browser toolbar buttons are hidden at narrow widths
index 5970e7a..4d3f796 100644 (file)
     <link rel="stylesheet" href="Views/ResourceTimelineDataGridNode.css">
     <link rel="stylesheet" href="Views/ResourceTreeElement.css">
     <link rel="stylesheet" href="Views/RulesStyleDetailsPanel.css">
-    <link rel="stylesheet" href="Views/RulesStyleSpreadsheetDetailsPanel.css">
     <link rel="stylesheet" href="Views/ScopeBar.css">
     <link rel="stylesheet" href="Views/ScopeChainDetailsSidebarPanel.css">
     <link rel="stylesheet" href="Views/ScopeRadioButtonNavigationItem.css">
     <link rel="stylesheet" href="Views/Slider.css">
     <link rel="stylesheet" href="Views/SoftContextMenu.css">
     <link rel="stylesheet" href="Views/SourceCodeTextEditor.css">
+    <link rel="stylesheet" href="Views/SpreadsheetCSSStyleDeclarationEditor.css">
+    <link rel="stylesheet" href="Views/SpreadsheetCSSStyleDeclarationSection.css">
+    <link rel="stylesheet" href="Views/SpreadsheetRulesStyleDetailsPanel.css">
     <link rel="stylesheet" href="Views/SpringEditor.css">
     <link rel="stylesheet" href="Views/StackTraceView.css">
     <link rel="stylesheet" href="Views/StorageSidebarPanel.css">
     <script src="Views/ResourceTimelineDataGridNode.js"></script>
     <script src="Views/ResourceTimingPopoverDataGridNode.js"></script>
     <script src="Views/RulesStyleDetailsPanel.js"></script>
-    <script src="Views/RulesStyleSpreadsheetDetailsPanel.js"></script>
     <script src="Views/ScopeBar.js"></script>
     <script src="Views/ScopeBarItem.js"></script>
     <script src="Views/ScopeChainDetailsSidebarPanel.js"></script>
     <script src="Views/SourceCodeTimelineTreeElement.js"></script>
     <script src="Views/SourceMapResourceTreeElement.js"></script>
     <script src="Views/SpanningDataGridNode.js"></script>
+
+    <script src="Views/SpreadsheetCSSStyleDeclarationEditor.js"></script>
+    <script src="Views/SpreadsheetCSSStyleDeclarationSection.js"></script>
+    <script src="Views/SpreadsheetRulesStyleDetailsPanel.js"></script>
+
     <script src="Views/SpringEditor.js"></script>
     <script src="Views/SVGImageResourceClusterContentView.js"></script>
     <script src="Views/StackTraceView.js"></script>
index 87dc44a..9bb8170 100644 (file)
@@ -36,7 +36,7 @@ WI.CSSStyleDetailsSidebarPanel = class CSSStyleDetailsSidebarPanel extends WI.DO
         this._visualStyleDetailsPanel = new WI.VisualStyleDetailsPanel(this);
 
         if (WI.settings.experimentalSpreadsheetStyleEditor.value)
-            this._activeRulesStyleDetailsPanel = new WI.RulesStyleSpreadsheetDetailsPanel(this);
+            this._activeRulesStyleDetailsPanel = new WI.SpreadsheetRulesStyleDetailsPanel(this);
         else
             this._activeRulesStyleDetailsPanel = this._rulesStyleDetailsPanel;
 
diff --git a/Source/WebInspectorUI/UserInterface/Views/RulesStyleSpreadsheetDetailsPanel.js b/Source/WebInspectorUI/UserInterface/Views/RulesStyleSpreadsheetDetailsPanel.js
deleted file mode 100644 (file)
index 4fb9ead..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-WI.RulesStyleSpreadsheetDetailsPanel = class RulesStyleSpreadsheetDetailsPanel extends WI.StyleDetailsPanel
-{
-    constructor(delegate)
-    {
-        super(delegate, "rules", "rules", WI.UIString("Styles \u2014 Rules"));
-
-        let styleSpreadsheetElement = document.createElement("div");
-        styleSpreadsheetElement.classList.add("style-spreadsheet");
-        styleSpreadsheetElement.innerHTML = `
-<section class="style-rule"><span class="selector selector-inline">Style Attribute</span> { }</section>
-
-<section class="style-rule">
-<span class="styles-source"><a href="#"><span class="resource-name">styleRule.css</span><span class="line-info">:24</span></a></span>
-<span class="selector-line"><span class="selector"><span class="matched">h1</span>, h2</span> {</span>
-<div class="declarations">
-    <div class="property"><input type="checkbox" checked><span class="name">font</span>: <span class="value">14px/32px sans-serif</span>;</div>
-    <div class="property"><input type="checkbox" checked><span class="name">margin</span>: <span class="value">0</span>;</div>
-    <div class="property"><input type="checkbox" checked><span class="name">padding</span>: <span class="value">8px 16px</span>;</div>
-}</div></section>
-
-<section class="style-rule">
-<span class="styles-source"><a href="#"><span class="resource-name">webkit.org</span><span class="line-info">:110</span></a></span>
-<span class="selector-line"><span class="selector"><span class="matched">.home .page-layer</span></span> {</span>
-<div class="declarations">
-    <div class="property"><input type="checkbox" checked><span class="name">background-color</span>: <span class="value">#f7f7f7</span>;</div>
-    <div class="property"><input type="checkbox" checked><span class="name">border-top</span>: <span class="value">1px solid #e7e7e7</span>;</div>
-    <div class="property"><input type="checkbox" checked><span class="name">position</span>: <span class="value">relative</span>;</div>
-    <div class="property"><input type="checkbox" checked><span class="name">z-index</span>: <span class="value">1</span>;</div>
-}</div></section>
-
-<section class="inherited"><strong>Inherited From: </strong><span role="link" title="body" class="node-link">body</span></section>
-
-<section class="style-rule">
-<span class="styles-source"><a href="#"><span class="resource-name">style.css</span><span class="line-info">:39</span></a></span>
-<span class="selector-line"><span class="selector"><span class="matched">body</span></span> {</span>
-<div class="declarations">
-    <div class="property"><input type="checkbox" checked><span class="name">background-color</span>: <span class="value">#f7f7f7</span>;</div>
-    <div class="property"><input type="checkbox" checked><span class="name">font-size</span>: <span class="value">1.6rem</span>;</div>
-    <div class="property property-disabled"><input type="checkbox">/* <span class="name">font-weight</span>: <span class="value">400</span>; */</div>
-    <div class="property"><input type="checkbox" checked><span class="name">line-height</span>: <span class="value">1.4</span>;</div>
-}</div></section>`;
-
-        this.element.append(styleSpreadsheetElement);
-    }
-
-    // Public
-
-    filterDidChange()
-    {
-        // Called by WI.CSSStyleDetailsSidebarPanel.prototype._filterDidChange.
-        // Unimplemented.
-    }
-
-    scrollToSectionAndHighlightProperty(property)
-    {
-        // Unimplemented.
-    }
-};
diff --git a/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.css b/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.css
new file mode 100644 (file)
index 0000000..647f10e
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+.spreadsheet-style-declaration-editor {
+    clear: both;
+}
+
+.spreadsheet-style-declaration-editor .name {
+    color: var(--syntax-highlight-boolean-color);
+}
+
+.spreadsheet-style-declaration-editor .value {
+    color: black;
+}
+
+.spreadsheet-style-declaration-editor.no-properties {
+    display: none;
+}
diff --git a/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.js b/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.js
new file mode 100644 (file)
index 0000000..95daf6f
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+WI.SpreadsheetCSSStyleDeclarationEditor = class SpreadsheetCSSStyleDeclarationEditor extends WI.View
+{
+    constructor(delegate, style)
+    {
+        super();
+
+        this.element.classList.add(WI.SpreadsheetCSSStyleDeclarationEditor.StyleClassName);
+
+        this._style = style;
+    }
+
+    // Public
+
+    layout()
+    {
+        super.layout();
+
+        this.element.removeChildren();
+
+        let properties = this._propertiesToRender;
+        this.element.classList.toggle("no-properties", !properties.length);
+
+        for (let property of properties)
+            this.element.append(this._renderProperty(property));
+    }
+
+    get style()
+    {
+        return this._style;
+    }
+
+    set style(style)
+    {
+        if (this._style === style)
+            return;
+
+        this._style = style || null;
+
+        this.needsLayout(WI.View.LayoutReason.Dirty);
+    }
+
+    // Private
+
+    get _propertiesToRender()
+    {
+        if (this._style._styleSheetTextRange)
+            return this._style.visibleProperties;
+
+        return this._style.properties;
+    }
+
+    _renderProperty(cssProperty)
+    {
+        let propertyElement = document.createElement("div");
+        propertyElement.classList.add("property");
+
+        let nameElement = propertyElement.appendChild(document.createElement("span"));
+        nameElement.classList.add("name");
+        nameElement.textContent = cssProperty.name;
+
+        propertyElement.append(": ");
+
+        let valueElement = propertyElement.appendChild(document.createElement("span"));
+        valueElement.classList.add("value");
+        valueElement.textContent = cssProperty.value;
+
+        propertyElement.append(";");
+
+        return propertyElement;
+    }
+};
+
+WI.SpreadsheetCSSStyleDeclarationEditor.StyleClassName = "spreadsheet-style-declaration-editor";
diff --git a/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.css b/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.css
new file mode 100644 (file)
index 0000000..49efcf7
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+.spreadsheet-css-declaration {
+    margin: 0;
+    padding: 4px 6px;
+    font-family: Menlo, monospace;
+    color: hsl(0, 0%, 70%);
+    background: white;
+    border-bottom: 0.5px solid hsla(0, 0%, 0%, 0.2);
+    -webkit-user-select: text;
+}
+
+.spreadsheet-css-declaration .origin {
+    float: right;
+    max-width: 100%;
+    font: 11px sans-serif;
+    color: hsl(0, 0%, 50%);
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+}
+
+.spreadsheet-css-declaration.locked .origin::after {
+    display: inline-block;
+    position: relative;
+    top: 1px;
+    width: 8px;
+    height: 10px;
+    margin-left: 4px;
+    content: url(../Images/Locked.svg);
+}
+
+.spreadsheet-css-declaration .origin .go-to-link {
+    color: hsl(0, 0%, 50%);
+}
+
+.spreadsheet-css-declaration .origin .go-to-link:hover {
+    color: hsl(0, 0%, 33%);
+}
+
+.spreadsheet-css-declaration .styles-source {
+    float: right;
+}
+
+.spreadsheet-css-declaration .selector.style-attribute {
+    font: 12px sans-serif;
+    color: hsl(0, 0%, 50%);
+    -webkit-user-modify: read-only;
+}
+
+.spreadsheet-css-declaration .selector > span {
+    color: hsl(0, 0%, 50%);
+}
+
+.spreadsheet-css-declaration .selector > .matched {
+    color: black;
+}
+
+.spreadsheet-css-declaration .properties {
+    margin-left: 1.4em;
+}
+
+.spreadsheet-css-declaration.locked {
+    background-color: hsl(0, 0%, 97%)
+}
+
+.spreadsheet-css-declaration .locked-icon {
+    width: 8px;
+    height: 10px;
+    content: url(../Images/Locked.svg);
+}
diff --git a/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.js b/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.js
new file mode 100644 (file)
index 0000000..40d03b6
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+WI.SpreadsheetCSSStyleDeclarationSection = class SpreadsheetCSSStyleDeclarationSection extends WI.View
+{
+    constructor(delegate, style)
+    {
+        console.assert(style instanceof WI.CSSStyleDeclaration, style);
+
+        let element = document.createElement("section");
+        element.classList.add("spreadsheet-css-declaration");
+        super(element);
+
+        this._delegate = delegate || null;
+        this._style = style;
+        this._selectorElements = [];
+    }
+
+    // Public
+
+    get style() { return this._style; }
+
+    initialLayout()
+    {
+        super.initialLayout();
+
+        this._headerElement = document.createElement("span");
+        this._headerElement.classList.add("header");
+
+        this._originElement = document.createElement("span");
+        this._originElement.classList.add("origin");
+        this._headerElement.append(this._originElement);
+
+        this._selectorElement = document.createElement("span");
+        this._selectorElement.classList.add("selector");
+        this._headerElement.append(this._selectorElement);
+
+        this._propertiesEditor = new WI.SpreadsheetCSSStyleDeclarationEditor(this, this._style);
+        this._propertiesEditor.element.classList.add("properties");
+
+        let openBrace = document.createElement("span");
+        openBrace.classList.add("open-brace");
+        openBrace.textContent = " {";
+
+        let closeBrace = document.createElement("span");
+        closeBrace.classList.add("close-brace");
+        closeBrace.textContent = "}";
+
+        this._element.append(this._headerElement, openBrace);
+        this.addSubview(this._propertiesEditor);
+        this._propertiesEditor.needsLayout(WI.View.LayoutReason.Dirty);
+        this._element.append(closeBrace);
+
+        if (!this._style.editable)
+            this._element.classList.add("locked");
+        else if (!this._style.ownerRule)
+            this._element.classList.add("selector-locked");
+    }
+
+    layout()
+    {
+        super.layout();
+
+        this._selectorElement.removeChildren();
+        this._originElement.removeChildren();
+
+        this._selectorElements = [];
+
+        let appendSelector = (selector, matched) => {
+            console.assert(selector instanceof WI.CSSSelector);
+
+            let selectorElement = this._selectorElement.appendChild(document.createElement("span"));
+            selectorElement.textContent = selector.text;
+
+            if (matched)
+                selectorElement.classList.add(WI.SpreadsheetCSSStyleDeclarationSection.MatchedSelectorElementStyleClassName);
+
+            let specificity = selector.specificity.map((number) => number.toLocaleString());
+            if (specificity) {
+                let tooltip = WI.UIString("Specificity: (%d, %d, %d)").format(...specificity);
+                if (selector.dynamic) {
+                    tooltip += "\n";
+                    if (this._style.inherited)
+                        tooltip += WI.UIString("Dynamically calculated for the parent element");
+                    else
+                        tooltip += WI.UIString("Dynamically calculated for the selected element");
+                }
+                selectorElement.title = tooltip;
+            } else if (selector.dynamic) {
+                let tooltip = WI.UIString("Specificity: No value for selected element");
+                tooltip += "\n";
+                tooltip += WI.UIString("Dynamically calculated for the selected element and did not match");
+                selectorElement.title = tooltip;
+            }
+
+            this._selectorElements.push(selectorElement);
+        };
+
+        let appendSelectorTextKnownToMatch = (selectorText) => {
+            let selectorElement = this._selectorElement.appendChild(document.createElement("span"));
+            selectorElement.textContent = selectorText;
+            selectorElement.classList.add(WI.SpreadsheetCSSStyleDeclarationSection.MatchedSelectorElementStyleClassName);
+        };
+
+        switch (this._style.type) {
+        case WI.CSSStyleDeclaration.Type.Rule:
+            console.assert(this._style.ownerRule);
+
+            let selectors = this._style.ownerRule.selectors;
+            let matchedSelectorIndices = this._style.ownerRule.matchedSelectorIndices;
+            let alwaysMatch = !matchedSelectorIndices.length;
+            if (selectors.length) {
+                let hasMatchingPseudoElementSelector = false;
+                for (let i = 0; i < selectors.length; ++i) {
+                    appendSelector(selectors[i], alwaysMatch || matchedSelectorIndices.includes(i));
+                    if (i < selectors.length - 1)
+                        this._selectorElement.append(", ");
+
+                    if (matchedSelectorIndices.includes(i) && selectors[i].isPseudoElementSelector())
+                        hasMatchingPseudoElementSelector = true;
+                }
+                this._element.classList.toggle("pseudo-element-selector", hasMatchingPseudoElementSelector);
+            } else
+                appendSelectorTextKnownToMatch(this._style.ownerRule.selectorText);
+
+            if (this._style.ownerRule.sourceCodeLocation) {
+                let options = {
+                    dontFloat: true,
+                    ignoreNetworkTab: true,
+                    ignoreSearchTab: true,
+                };
+
+                if (this._style.ownerStyleSheet.isInspectorStyleSheet()) {
+                    options.nameStyle = WI.SourceCodeLocation.NameStyle.None;
+                    options.prefix = WI.UIString("Inspector Style Sheet") + ":";
+                }
+
+                let sourceCodeLink = WI.createSourceCodeLocationLink(this._style.ownerRule.sourceCodeLocation, options);
+                this._originElement.appendChild(sourceCodeLink);
+            } else {
+                let originString = "";
+
+                switch (this._style.ownerRule.type) {
+                case WI.CSSStyleSheet.Type.Author:
+                    originString = WI.UIString("Author Stylesheet");
+                    break;
+
+                case WI.CSSStyleSheet.Type.User:
+                    originString = WI.UIString("User Stylesheet");
+                    break;
+
+                case WI.CSSStyleSheet.Type.UserAgent:
+                    originString = WI.UIString("User Agent Stylesheet");
+                    break;
+
+                case WI.CSSStyleSheet.Type.Inspector:
+                    originString = WI.UIString("Web Inspector");
+                    break;
+                }
+
+                console.assert(originString);
+                if (originString)
+                    this._originElement.append(originString);
+
+                if (!this._style.editable) {
+                    let styleTitle = "";
+                    if (this._style.ownerRule && this._style.ownerRule.type === WI.CSSStyleSheet.Type.UserAgent)
+                        styleTitle = WI.UIString("User Agent Stylesheet");
+                    else
+                        styleTitle = WI.UIString("Style rule");
+
+                    this._originElement.title = WI.UIString("%s cannot be modified").format(styleTitle);
+                }
+            }
+
+            break;
+
+        case WI.CSSStyleDeclaration.Type.Inline:
+            this._selectorElement.textContent = WI.UIString("Style Attribute");
+            this._selectorElement.classList.add("style-attribute");
+            break;
+
+        case WI.CSSStyleDeclaration.Type.Attribute:
+            appendSelectorTextKnownToMatch(this._style.node.displayName);
+            this._originElement.append(WI.UIString("HTML Attributes"));
+            break;
+        }
+    }
+
+    cssStyleDeclarationTextEditorFocused()
+    {
+        if (this._delegate && typeof this._delegate.cssStyleDeclarationSectionEditorFocused === "function")
+            this._delegate.cssStyleDeclarationSectionEditorFocused(this);
+    }
+
+    get locked()
+    {
+        return !this._style.editable;
+    }
+
+    get selectorEditable()
+    {
+        return this._style.editable && this._style.ownerRule;
+    }
+};
+
+WI.SpreadsheetCSSStyleDeclarationSection.MatchedSelectorElementStyleClassName = "matched";
diff --git a/Source/WebInspectorUI/UserInterface/Views/SpreadsheetRulesStyleDetailsPanel.js b/Source/WebInspectorUI/UserInterface/Views/SpreadsheetRulesStyleDetailsPanel.js
new file mode 100644 (file)
index 0000000..d3016da
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+WI.SpreadsheetRulesStyleDetailsPanel = class SpreadsheetRulesStyleDetailsPanel extends WI.StyleDetailsPanel
+{
+    constructor(delegate)
+    {
+        const className = "rules";
+        const identifier = "rules";
+        const label = WI.UIString("Styles \u2014 Rules");
+        super(delegate, className, identifier, label);
+
+        this._sections = [];
+        this._inspectorSection = null;
+        this._isInspectorSectionPendingFocus = false;
+        this._ruleMediaAndInherticanceList = [];
+        this._propertyToSelectAndHighlight = null;
+
+        this._emptyFilterResultsElement = document.createElement("div");
+        this._emptyFilterResultsElement.classList.add("no-filter-results");
+
+        this._emptyFilterResultsMessage = this._emptyFilterResultsElement.appendChild(document.createElement("div"));
+        this._emptyFilterResultsMessage.classList.add("no-filter-results-message");
+        this._emptyFilterResultsMessage.textContent = WI.UIString("No Results Found");
+    }
+
+    // Public
+
+    refresh(significantChange)
+    {
+        // We only need to do a rebuild on significant changes. Other changes are handled
+        // by the sections and text editors themselves.
+        if (!significantChange) {
+            super.refresh(significantChange);
+            return;
+        }
+
+        let uniqueOrderedStyles = (orderedStyles) => {
+            let uniqueStyles = [];
+
+            for (let style of orderedStyles) {
+                let rule = style.ownerRule;
+                if (!rule) {
+                    uniqueStyles.push(style);
+                    continue;
+                }
+
+                let found = false;
+                for (let existingStyle of uniqueStyles) {
+                    if (rule.isEqualTo(existingStyle.ownerRule)) {
+                        found = true;
+                        break;
+                    }
+                }
+                if (!found)
+                    uniqueStyles.push(style);
+            }
+
+            return uniqueStyles;
+        };
+
+        this.removeAllSubviews();
+
+        let orderedStyles = uniqueOrderedStyles(this.nodeStyles.orderedStyles);
+        for (let style of orderedStyles) {
+            // FIXME: <https://webkit.org/b/176033> Display "Inherited From" and media query section headers
+            // FIXME: <https://webkit.org/b/176187> Display matching pseudo-styles
+            let section = style[WI.SpreadsheetRulesStyleDetailsPanel.RuleSection];
+            if (!section) {
+                section = new WI.SpreadsheetCSSStyleDeclarationSection(this, style);
+                style[WI.SpreadsheetRulesStyleDetailsPanel.RuleSection] = section;
+            }
+
+            if (this._isInspectorSectionPendingFocus && style.isInspectorRule())
+                this._inspectorSection = section;
+
+            this.addSubview(section);
+            section.needsLayout(WI.View.LayoutReason.Dirty);
+        }
+
+        this.element.append(this._emptyFilterResultsElement);
+
+        super.refresh(significantChange);
+    }
+};
+
+WI.SpreadsheetRulesStyleDetailsPanel.RuleSection = Symbol("rule-section");
index 98fd60b..2a307c5 100644 (file)
@@ -114,6 +114,11 @@ WI.StyleDetailsPanel = class StyleDetailsPanel extends WI.View
             this._refreshPreservingScrollPosition(event.data.significantChange);
     }
 
+    filterDidChange(filterBar)
+    {
+        // Implemented by subclasses.
+    }
+
     // Private
 
     get _initialScrollOffset()
index 1c4f9ce..982fa2f 100644 (file)
@@ -132,6 +132,15 @@ WI.View = class View extends WI.Object
         view.didMoveToParent(null);
     }
 
+    removeAllSubviews()
+    {
+        for (let subview of this._subviews)
+            subview.didMoveToParent(null);
+
+        this._subviews = [];
+        this._element.removeChildren();
+    }
+
     replaceSubview(oldView, newView)
     {
         console.assert(oldView !== newView, "Cannot replace subview with itself.");