Diff
Modified: trunk/Source/WebInspectorUI/ChangeLog (188225 => 188226)
--- trunk/Source/WebInspectorUI/ChangeLog 2015-08-10 20:38:50 UTC (rev 188225)
+++ trunk/Source/WebInspectorUI/ChangeLog 2015-08-10 20:49:47 UTC (rev 188226)
@@ -1,3 +1,98 @@
+2015-08-10 Devin Rousso <drou...@apple.com>
+
+ Web Inspector: Add VisualStyleSelectorSection
+ https://bugs.webkit.org/show_bug.cgi?id=147572
+
+ Reviewed by Brian Burg.
+
+ Adds a section to the new Visual style sidebar panel that contains the list of
+ styles for the currently selected node.
+
+ * UserInterface/Models/CSSRule.js:
+ (WebInspector.CSSRule.prototype.get mediaText):
+ Returns a string containing the list of media queries.
+
+ * UserInterface/Models/CSSStyleDeclaration.js:
+ (WebInspector.CSSStyleDeclaration):
+ (WebInspector.CSSStyleDeclaration.prototype.set text):
+ (WebInspector.CSSStyleDeclaration.prototype.get modified):
+ (WebInspector.CSSStyleDeclaration.prototype.resetText):
+ (WebInspector.CSSStyleDeclaration.prototype.generateCSSRuleString):
+ Generates a formatted string of the style text.
+
+ * UserInterface/Views/CSSStyleDeclarationSection.js:
+ (WebInspector.CSSStyleDeclarationSection.prototype._handleContextMenuEvent):
+ (WebInspector.CSSStyleDeclarationSection.prototype._generateCSSRuleString): Deleted.
+
+ * UserInterface/Views/VisualStyleSelectorSection.css: Added.
+ (.details-section.visual-style-selector-section > .header):
+ (.details-section.visual-style-selector-section:not(.collapsed) > .header):
+ (@media (-webkit-min-device-pixel-ratio: 2)):
+ (.details-section.visual-style-selector-section > .header > .current-selector):
+ (.visual-style-selector-section.details-section:not(.collapsed) > .header > .current-selector):
+ (.details-section.visual-style-selector-section > .header > .current-selector > .icon):
+ (.details-section.visual-style-selector-section > .header > .current-selector > span):
+ (.details-section.visual-style-selector-section > .header > .controls):
+ (.details-section.visual-style-selector-section.collapsed > .header > .controls):
+ (.details-section.visual-style-selector-section > .header > .controls > .visual-style-selector-section-add-rule):
+ (.details-section.visual-style-selector-section > .content > .selectors):
+ (.details-section.visual-style-selector-section > .content > .selectors > .selector-list):
+ (.details-section.visual-style-selector-section > .content > .selectors > .selector-list > .visual-style-selector-item:nth-child(odd)):
+ (.details-section.visual-style-selector-section > .content > .selectors > .selector-list > .section-divider):
+ (.details-section.visual-style-selector-section > .content > .selectors > .selector-list > .section-divider > .icon):
+ (.details-section.visual-style-selector-section > .content > .selectors > .selector-list > .section-divider > :matches(.disclosure-button, .icon)):
+ (.details-section.visual-style-selector-section > .content > .selectors > .selector-list > .section-divider > .titles > .title):
+ (.details-section.visual-style-selector-section > .content > .selectors > .selector-list > .section-divider ~ .visual-style-selector-item:nth-child(even)):
+ (.details-section.visual-style-selector-section > .content > .selectors > .selector-list > .section-divider ~ .visual-style-selector-item:nth-child(odd)):
+
+ * UserInterface/Views/VisualStyleSelectorSection.js: Added.
+ (WebInspector.VisualStyleSelectorSection):
+ (WebInspector.VisualStyleSelectorSection.prototype.update.createSelectorItem):
+ (WebInspector.VisualStyleSelectorSection.prototype.update.uniqueOrderedRules):
+ (WebInspector.VisualStyleSelectorSection.prototype.update.insertAllMatchingPseudoRules):
+ (WebInspector.VisualStyleSelectorSection.prototype.update):
+ (WebInspector.VisualStyleSelectorSection.prototype.currentStyle):
+ (WebInspector.VisualStyleSelectorSection.prototype._selectorChanged):
+ (WebInspector.VisualStyleSelectorSection.prototype._styleTextReset):
+ (WebInspector.VisualStyleSelectorSection.prototype._addNewRule):
+ (WebInspector.VisualStyleSelectorSection.prototype._treeElementCheckboxToggled):
+ (WebInspector.VisualStyleSelectorSection.prototype._handleMouseOver):
+ (WebInspector.VisualStyleSelectorSection.prototype._handleMouseOut):
+
+ * UserInterface/Views/VisualStyleSelectorTreeItem.css:
+ (.item.visual-style-selector-item):
+ (.item.visual-style-selector-item.selected):
+ (.item.visual-style-selector-item > .disclosure-button):
+ (.item.visual-style-selector-item > input[type="checkbox"]):
+ (.item.visual-style-selector-item > .icon):
+ (.item.visual-style-selector-item.modified > .icon):
+ (.item.visual-style-selector-item.selector-invalid > .icon):
+ (.item.visual-style-selector-item.selector-invalid > .titles > .title):
+ (.item.visual-style-selector-item.selector-invalid > .titles > .title::before):
+ (.item.visual-style-selector-item > .titles):
+ (.item.visual-style-selector-item:not(.dom-element-icon) > .titles > .title):
+ (.item.visual-style-selector-item:not(.dom-element-icon).editable > .titles > .title):
+ (.item.visual-style-selector-item:not(.dom-element-icon).editable > .titles > .title:focus):
+ (.item.visual-style-selector-item > .titles > .subtitle::before):
+ (.item.visual-style-selector-item > .titles > .subtitle):
+
+ * UserInterface/Views/VisualStyleSelectorTreeItem.js:
+ (WebInspector.VisualStyleSelectorTreeItem):
+ (WebInspector.VisualStyleSelectorTreeItem.prototype.get iconClassName):
+ (WebInspector.VisualStyleSelectorTreeItem.prototype.get selectorText):
+ (WebInspector.VisualStyleSelectorTreeItem.prototype.onattach):
+ (WebInspector.VisualStyleSelectorTreeItem.prototype.ondeselect):
+ (WebInspector.VisualStyleSelectorTreeItem.prototype._highlightNodesWithSelector):
+ (WebInspector.VisualStyleSelectorTreeItem.prototype._hideDOMNodeHighlight):
+ (WebInspector.VisualStyleSelectorTreeItem.prototype._handleContextMenuEvent):
+ (WebInspector.VisualStyleSelectorTreeItem.prototype._handleCheckboxChanged):
+ (WebInspector.VisualStyleSelectorTreeItem.prototype._updateCheckboxTitle):
+ (WebInspector.VisualStyleSelectorTreeItem.prototype._handleMainTitleMouseDown):
+ (WebInspector.VisualStyleSelectorTreeItem.prototype._handleMainTitleKeyDown):
+ (WebInspector.VisualStyleSelectorTreeItem.prototype._commitSelector):
+ (WebInspector.VisualStyleSelectorTreeItem.prototype._styleTextModified):
+ (WebInspector.VisualStyleSelectorTreeItem.prototype._selectorChanged):
+
2015-08-10 Joseph Pecoraro <pecor...@apple.com>
Web Inspector: TDZ in ProbeSetDataGrid construction
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/CSSRule.js (188225 => 188226)
--- trunk/Source/WebInspectorUI/UserInterface/Models/CSSRule.js 2015-08-10 20:38:50 UTC (rev 188225)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/CSSRule.js 2015-08-10 20:49:47 UTC (rev 188226)
@@ -177,6 +177,18 @@
return this._mediaList;
}
+ get mediaText()
+ {
+ if (!this._mediaList.length)
+ return;
+
+ let mediaText = "";
+ for (let media of this._mediaList)
+ mediaText += media.text;
+
+ return mediaText;
+ }
+
isEqualTo(rule)
{
if (!rule)
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js (188225 => 188226)
--- trunk/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js 2015-08-10 20:38:50 UTC (rev 188225)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js 2015-08-10 20:49:47 UTC (rev 188226)
@@ -43,6 +43,9 @@
this._pendingProperties = [];
this._propertyNameMap = {};
+ this._initialText = text;
+ this._hasModifiedInitialText = false;
+
this.update(text, properties, styleSheetTextRange, true);
}
@@ -183,9 +186,25 @@
if (this._text === text)
return;
+ var modified = text !== this._initialText;
+ if (modified !== this._hasModifiedInitialText) {
+ this._hasModifiedInitialText = modified;
+ this.dispatchEventToListeners(WebInspector.CSSStyleDeclaration.Event.InitialTextModified);
+ }
+
this._nodeStyles.changeStyleText(this, text);
}
+ resetText()
+ {
+ this.text = this._initialText;
+ }
+
+ get modified()
+ {
+ return this._hasModifiedInitialText;
+ }
+
get properties()
{
return this._properties;
@@ -260,6 +279,43 @@
return newProperty;
}
+ generateCSSRuleString()
+ {
+ if (!this._ownerRule)
+ return;
+
+ let styleText = "";
+ let mediaQueriesCount = 0;
+ let mediaList = this._ownerRule.mediaList;
+ if (mediaList.length) {
+ mediaQueriesCount = mediaList.length;
+
+ for (let i = mediaQueriesCount - 1; i >= 0; --i)
+ styleText += " ".repeat(mediaQueriesCount - i - 1) + "@media " + mediaList[i].text + " {\n";
+ }
+
+ styleText += " ".repeat(mediaQueriesCount) + this._ownerRule.selectorText + " {\n";
+
+ for (let property of this._properties) {
+ if (property.anonymous)
+ continue;
+
+ styleText += " ".repeat(mediaQueriesCount + 1) + property.text.trim();
+
+ if (!styleText.endsWith(";"))
+ styleText += ";";
+
+ styleText += "\n";
+ }
+
+ for (let i = mediaQueriesCount; i > 0; --i)
+ styleText += " ".repeat(i) + "}\n";
+
+ styleText += "}";
+
+ return styleText;
+ }
+
// Protected
get nodeStyles()
@@ -269,7 +325,8 @@
};
WebInspector.CSSStyleDeclaration.Event = {
- PropertiesChanged: "css-style-declaration-properties-changed"
+ PropertiesChanged: "css-style-declaration-properties-changed",
+ InitialTextModified: "css-style-declaration-initial-text-modified"
};
WebInspector.CSSStyleDeclaration.Type = {
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/CSSStyleDeclarationSection.js (188225 => 188226)
--- trunk/Source/WebInspectorUI/UserInterface/Views/CSSStyleDeclarationSection.js 2015-08-10 20:38:50 UTC (rev 188225)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/CSSStyleDeclarationSection.js 2015-08-10 20:49:47 UTC (rev 188226)
@@ -449,49 +449,12 @@
}
contextMenu.appendItem(WebInspector.UIString("Copy Rule"), function() {
- InspectorFrontendHost.copyText(this._generateCSSRuleString());
+ InspectorFrontendHost.copyText(this._style.generateCSSRuleString());
}.bind(this));
contextMenu.show();
}
- _generateCSSRuleString()
- {
- var numMediaQueries = 0;
- var styleText = "";
-
- if (this._style.ownerRule) {
- var mediaList = this._style.ownerRule.mediaList;
- if (mediaList.length) {
- numMediaQueries = mediaList.length;
-
- for (var i = numMediaQueries - 1; i >= 0; --i)
- styleText += " ".repeat(numMediaQueries - i - 1) + "@media " + mediaList[i].text + " {\n";
- }
-
- styleText += " ".repeat(numMediaQueries) + this._style.ownerRule.selectorText;
- } else
- styleText += this._selectorElement.textContent;
-
- styleText += " {\n";
-
- for (var property of this._style.visibleProperties) {
- styleText += " ".repeat(numMediaQueries + 1) + property.text.trim();
-
- if (!styleText.endsWith(";"))
- styleText += ";";
-
- styleText += "\n";
- }
-
- for (var i = numMediaQueries; i > 0; --i)
- styleText += " ".repeat(i) + "}\n";
-
- styleText += "}";
-
- return styleText;
- }
-
_toggleRuleOnOff()
{
if (this._hasInvalidSelector)
Added: trunk/Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorSection.css (0 => 188226)
--- trunk/Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorSection.css (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorSection.css 2015-08-10 20:49:47 UTC (rev 188226)
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+.details-section.visual-style-selector-section > .header {
+ display: flex;
+ height: 22px;
+}
+
+.details-section.visual-style-selector-section:not(.collapsed) > .header {
+ border-bottom: 1px solid hsl(0, 0%, 70%);
+}
+
+@media (-webkit-min-device-pixel-ratio: 2) {
+ .details-section.visual-style-selector-section:not(.collapsed) > .header {
+ border-width: 0.5px !important;
+ }
+}
+
+.details-section.visual-style-selector-section > .header > .current-selector {
+ width: calc(100% - 85px);
+ margin-left: 10px;
+ font-weight: normal;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.visual-style-selector-section.details-section:not(.collapsed) > .header > .current-selector {
+ display: none;
+}
+
+.details-section.visual-style-selector-section > .header > .current-selector > .icon {
+ width: 16px;
+ height: 16px;
+ position: absolute;
+ top: 3px;
+}
+
+.details-section.visual-style-selector-section > .header > .current-selector > span {
+ margin-left: 21px;
+}
+
+.details-section.visual-style-selector-section > .header > .controls {
+ position: absolute;
+ right: 0;
+ top: 0;
+ border-left: 1px solid hsl(0, 0%, 83%);
+}
+
+.details-section.visual-style-selector-section.collapsed > .header > .controls {
+ display: none;
+}
+
+.details-section.visual-style-selector-section > .header > .controls > .visual-style-selector-section-add-rule {
+ width: 23px;
+ height: 21px;
+ padding: 4px 5px;
+ -webkit-filter: opacity(0.7);
+}
+
+.details-section.visual-style-selector-section > .content > .selectors {
+ max-height: 110px;
+ overflow: auto;
+}
+
+.details-section.visual-style-selector-section > .content > .selectors > .selector-list {
+ margin: 0;
+ padding-left: 0;
+ outline: none;
+}
+
+.details-section.visual-style-selector-section > .content > .selectors > .selector-list > .visual-style-selector-item:nth-child(odd) {
+ background-color: hsl(0, 100%, 100%);
+}
+
+.details-section.visual-style-selector-section > .content > .selectors > .selector-list > .section-divider {
+ position: -webkit-sticky;
+ top: -1px;
+ height: 17px;
+ padding: 2px;
+ background-color: hsl(0, 0%, 95%);
+ border-color: hsl(0, 0%, 70%);
+ border-style: solid;
+ border-width: 1px 0;
+ z-index: 100;
+}
+
+.details-section.visual-style-selector-section > .content > .selectors > .selector-list > .section-divider > :matches(.disclosure-button, .icon) {
+ display: none;
+}
+
+.details-section.visual-style-selector-section > .content > .selectors > .selector-list > .section-divider > .titles > .title {
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
+
+.details-section.visual-style-selector-section > .content > .selectors > .selector-list > .section-divider ~ .visual-style-selector-item:nth-child(even) {
+ background-color: hsl(0, 100%, 100%);
+}
+
+.details-section.visual-style-selector-section > .content > .selectors > .selector-list > .section-divider ~ .visual-style-selector-item:nth-child(odd) {
+ background-color: transparent;
+}
Added: trunk/Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorSection.js (0 => 188226)
--- trunk/Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorSection.js (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorSection.js 2015-08-10 20:49:47 UTC (rev 188226)
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2015 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.VisualStyleSelectorSection = class VisualStyleSelectorSection extends WebInspector.DetailsSection
+{
+ constructor(delegate)
+ {
+ let selectorSection = {element: document.createElement("div")};
+ selectorSection.element.classList.add("selectors");
+
+ let controlElement = document.createElement("div");
+ controlElement.classList.add("controls");
+
+ super("visual-style-selector-section", WebInspector.UIString("Style Rules"), [selectorSection], controlElement);
+
+ this._delegate = delegate || null;
+ this._nodeStyles = null;
+
+ this._currentSelectorElement = document.createElement("div");
+ this._currentSelectorElement.classList.add("current-selector");
+
+ let currentSelectorIconElement = document.createElement("img");
+ currentSelectorIconElement.classList.add("icon");
+ this._currentSelectorElement.appendChild(currentSelectorIconElement);
+
+ this._currentSelectorText = document.createElement("span");
+ this._currentSelectorElement.appendChild(this._currentSelectorText);
+
+ this._headerElement.appendChild(this._currentSelectorElement);
+
+ let selectorListElement = document.createElement("ol");
+ selectorListElement.classList.add("selector-list");
+ selectorSection.element.appendChild(selectorListElement);
+
+ this._selectors = new WebInspector.TreeOutline(selectorListElement);
+ this._selectors._onselect_ = this._selectorChanged.bind(this);
+ this._focusNextNewInspectorRule = false;
+
+ wrappedSVGDocument("Images/Plus.svg", "visual-style-selector-section-add-rule", WebInspector.UIString("Click to add a new rule."), function(wrapper) {
+ wrapper.addEventListener("click", this._addNewRule.bind(this));
+ controlElement.appendChild(wrapper);
+ }.bind(this));
+
+ this._headerElement.addEventListener("mouseover", this._handleMouseOver.bind(this));
+ this._headerElement.addEventListener("mouseout", this._handleMouseOut.bind(this));
+ }
+
+ // Public
+
+ update(nodeStyles)
+ {
+ let style = this.currentStyle();
+ if (style)
+ this._nodeStyles[WebInspector.VisualStyleSelectorSection.LastSelectedRuleSymbol] = style;
+
+ if (nodeStyles)
+ this._nodeStyles = nodeStyles;
+
+ if (!this._nodeStyles)
+ return;
+
+ this._selectors.removeChildren();
+ let previousRule = null;
+
+ // Pseudo Styles
+ let pseudoRules = [];
+ let pseudoElements = this._nodeStyles.pseudoElements;
+ for (let pseudoIdentifier in pseudoElements)
+ pseudoRules = pseudoRules.concat(pseudoElements[pseudoIdentifier].matchedRules);
+
+ let orderedPseudoRules = uniqueOrderedRules(pseudoRules);
+ // Reverse the array to ensure that splicing the array will not mess with the order.
+ if (orderedPseudoRules.length)
+ orderedPseudoRules.reverse();
+
+ function createSelectorItem(style, title, subtitle) {
+ let selector = new WebInspector.VisualStyleSelectorTreeItem(style, title, subtitle);
+ selector.addEventListener(WebInspector.VisualStyleSelectorTreeItem.Event.StyleTextReset, this._styleTextReset, this);
+ selector.addEventListener(WebInspector.VisualStyleSelectorTreeItem.Event.CheckboxChanged, this._treeElementCheckboxToggled, this);
+ this._selectors.appendChild(selector);
+
+ if (this._focusNextNewInspectorRule && style.ownerRule && style.ownerRule.type === WebInspector.CSSRule.Type.Inspector) {
+ selector.select(true);
+ selector.element.scrollIntoView();
+ this._nodeStyles[WebInspector.VisualStyleSelectorSection.LastSelectedRuleSymbol] = style;
+ this._focusNextNewInspectorRule = false;
+ return;
+ }
+
+ if (this._nodeStyles[WebInspector.VisualStyleSelectorSection.LastSelectedRuleSymbol] === style) {
+ selector.select(true);
+ selector.element.scrollIntoView();
+ }
+ }
+
+ function uniqueOrderedRules(orderedRules)
+ {
+ if (!orderedRules || !orderedRules.length)
+ return new Array;
+
+ let uniqueRules = new Map;
+ for (let rule of orderedRules) {
+ if (!uniqueRules.has(rule.id))
+ uniqueRules.set(rule.id, rule);
+ }
+ return Array.from(uniqueRules.values());
+ }
+
+ function insertAllMatchingPseudoRules(force)
+ {
+ if (!orderedPseudoRules.length)
+ return;
+
+ if (force) {
+ for (let i = orderedPseudoRules.length - 1; i >= 0; --i) {
+ let pseudoRule = orderedPseudoRules[i];
+ createSelectorItem.call(this, pseudoRule.style, pseudoRule.selectorText, pseudoRule.mediaText);
+ }
+ orderedPseudoRules = [];
+ }
+
+ if (!previousRule)
+ return;
+
+ for (let i = orderedPseudoRules.length - 1; i >= 0; --i) {
+ let pseudoRule = orderedPseudoRules[i];
+ if (!pseudoRule.selectorIsGreater(previousRule.mostSpecificSelector))
+ continue;
+
+ createSelectorItem.call(this, pseudoRule.style, pseudoRule.selectorText, pseudoRule.mediaText);
+ previousRule = pseudoRule;
+ orderedPseudoRules.splice(i, 1);
+ }
+ }
+
+ if (!this._nodeStyles[WebInspector.VisualStyleSelectorSection.LastSelectedRuleSymbol])
+ this._nodeStyles[WebInspector.VisualStyleSelectorSection.LastSelectedRuleSymbol] = this._nodeStyles.inlineStyle;
+
+ // Inline Style
+ createSelectorItem.call(this, this._nodeStyles.inlineStyle, WebInspector.UIString("This Element"));
+
+ // Matched Rules
+ for (let rule of uniqueOrderedRules(this._nodeStyles.matchedRules)) {
+ if (rule.type === WebInspector.CSSRule.Type.UserAgent) {
+ insertAllMatchingPseudoRules.call(this, true);
+ continue;
+ }
+
+ insertAllMatchingPseudoRules.call(this);
+ createSelectorItem.call(this, rule.style, rule.selectorText, rule.mediaText);
+ previousRule = rule;
+ }
+
+ // Just in case there are any remaining pseudo-styles.
+ insertAllMatchingPseudoRules.call(this, true);
+
+ // Inherited Rules
+ for (let inherited of this._nodeStyles.inheritedRules) {
+ if (!inherited.matchedRules || !inherited.matchedRules.length)
+ continue;
+
+ let dividerText = WebInspector.UIString("Inherited from %s").format(WebInspector.displayNameForNode(inherited.node));
+ let divider = new WebInspector.GeneralTreeElement("section-divider", dividerText);
+ divider.selectable = false;
+ this._selectors.appendChild(divider);
+
+ for (let rule of uniqueOrderedRules(inherited.matchedRules)) {
+ if (rule.type === WebInspector.CSSRule.Type.UserAgent)
+ continue;
+
+ createSelectorItem.call(this, rule.style, rule.selectorText, rule.mediaText);
+ }
+ }
+
+ this._focusNextNewInspectorRule = false;
+ }
+
+ currentStyle()
+ {
+ if (!this._nodeStyles || !this._selectors.selectedTreeElement)
+ return;
+
+ return this._selectors.selectedTreeElement.representedObject;
+ }
+
+ // Private
+
+ _selectorChanged(selectedTreeElement)
+ {
+ console.assert(selectedTreeElement);
+ if (!selectedTreeElement)
+ return;
+
+ // The class needs to be completely reset as the previously selected treeElement most likely had
+ // a different icon className and it is simpler to regenerate the class than to find out which
+ // class was previously applied.
+ this._currentSelectorElement.className = "current-selector " + selectedTreeElement.iconClassName;
+
+ let selectorText = selectedTreeElement.mainTitle;
+ let mediaText = selectedTreeElement.subtitle;
+ if (mediaText && mediaText.length)
+ selectorText += " \u2014 " + mediaText; // em-dash
+
+ this._currentSelectorText.textContent = selectorText;
+
+ this.dispatchEventToListeners(WebInspector.VisualStyleSelectorSection.Event.SelectorChanged);
+ }
+
+ _styleTextReset()
+ {
+ this.dispatchEventToListeners(WebInspector.VisualStyleSelectorSection.Event.StyleTextChanged);
+ }
+
+ _addNewRule(event)
+ {
+ if (!this._nodeStyles)
+ return;
+
+ this._nodeStyles.addEmptyRule();
+ this._focusNextNewInspectorRule = true;
+ }
+
+ _treeElementCheckboxToggled(event)
+ {
+ let style = this.currentStyle();
+ if (!style)
+ return;
+
+ let styleText = style.text;
+ if (!styleText || !styleText.length)
+ return;
+
+ // Comment or uncomment the style text.
+ let newStyleText = "";
+ let styleEnabled = event && event.data && event.data.enabled;
+ if (styleEnabled)
+ newStyleText = styleText.replace(/\s*(\/\*|\*\/)\s*/g, "");
+ else
+ newStyleText = "/* " + styleText.replace(/(\s*;(?!$)\s*)/g, "$1 *//* ") + " */";
+
+ style.text = newStyleText;
+ style[WebInspector.VisualStyleDetailsPanel.StyleDisabledSymbol] = !styleEnabled;
+ this.dispatchEventToListeners(WebInspector.VisualStyleSelectorSection.Event.SelectorChanged);
+
+ }
+
+ _handleMouseOver()
+ {
+ if (!this.collapsed)
+ return;
+
+ let style = this.currentStyle();
+ if (!style.ownerRule) {
+ WebInspector.domTreeManager.highlightDOMNode(style.node.id);
+ return;
+ }
+
+ WebInspector.domTreeManager.highlightSelector(style.ownerRule.selectorText, style.node.ownerDocument.frameIdentifier);
+ }
+
+ _handleMouseOut()
+ {
+ if (!this.collapsed)
+ return;
+
+ WebInspector.domTreeManager.hideDOMNodeHighlight();
+ }
+};
+
+WebInspector.VisualStyleSelectorSection.LastSelectedRuleSymbol = Symbol("visual-style-selector-section-last-selected-rule");
+
+WebInspector.VisualStyleSelectorSection.Event = {
+ SelectorChanged: "visual-style-selector-section-selector-changed",
+ StyleTextChanged: "visual-style-selector-section-style-text-changed"
+}
Added: trunk/Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorTreeItem.css (0 => 188226)
--- trunk/Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorTreeItem.css (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorTreeItem.css 2015-08-10 20:49:47 UTC (rev 188226)
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+.item.visual-style-selector-item {
+ display: flex;
+ width: 100%;
+ height: 25px;
+ padding: 2px 0;
+ line-height: 20px;
+ font-size: 11px;
+}
+
+.item.visual-style-selector-item.selected {
+ background-color: hsl(213, 92%, 55%) !important;
+ color: hsl(0, 100%, 100%);
+}
+
+.item.visual-style-selector-item > .disclosure-button {
+ display: none;
+}
+
+.item.visual-style-selector-item > input[type="checkbox"] {
+ margin: 4.5px 0 4px 5px;
+}
+
+.item.visual-style-selector-item > .icon {
+ width: 16px;
+ height: 16px;
+ margin: 2.5px 0 2.5px 4px;
+}
+
+.item.visual-style-selector-item.modified > .icon {
+ -webkit-filter: brightness(0.75);
+}
+
+.item.visual-style-selector-item.selector-invalid > .icon {
+ width: 14px;
+ height: 14px;
+ margin: 3.5px 0 3.5px 5px;
+ content: url(../Images/Error.svg);
+}
+
+.item.visual-style-selector-item.selector-invalid > .titles > .title {
+ position: relative;
+}
+
+.item.visual-style-selector-item.selector-invalid > .titles > .title::before {
+ position: absolute;
+ top: calc(50% - 0.5px);
+ left: 0;
+ width: 100%;
+ border-bottom: 1px solid hsla(0, 100%, 50%, 0.6);
+ content: "";
+}
+
+.item.visual-style-selector-item > .titles {
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ padding: 0 2px 0 3px;
+}
+
+.item.visual-style-selector-item:not(.dom-element-icon) > .titles > .title {
+ padding: 0 1px 2px;
+ line-height: 12px;
+ outline: none;
+}
+
+.item.visual-style-selector-item:not(.dom-element-icon).editable > .titles > .title {
+ cursor: text;
+ -webkit-user-select: text;
+ -webkit-user-modify: read-write-plaintext-only;
+}
+
+.item.visual-style-selector-item:not(.dom-element-icon).editable > .titles > .title:focus {
+ color: black;
+ background-color: hsl(0, 100%, 100%);
+ border-radius: 2px;
+ box-shadow: hsla(0, 0%, 0%, 0.15) 0 1px 0, 0 0 0 3px hsla(0, 100%, 100%, 0.3);
+}
+
+.item.visual-style-selector-item > .titles > .subtitle::before {
+ margin-right: 5px;
+ font-size: 11px;
+ /* The extra space at the beginning is necessary to prevent the -webkit-user-modify
+ cursor bar from displaying at the beginning of the em-dash. */
+ content: " \2014"; /* em-dash */
+}
+
+.item.visual-style-selector-item > .titles > .subtitle {
+ font-size: 9px;
+}
Added: trunk/Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorTreeItem.js (0 => 188226)
--- trunk/Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorTreeItem.js (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/VisualStyleSelectorTreeItem.js 2015-08-10 20:49:47 UTC (rev 188226)
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2015 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.VisualStyleSelectorTreeItem = class VisualStyleSelectorTreeItem extends WebInspector.GeneralTreeElement
+{
+ constructor(style, title, subtitle)
+ {
+ let iconClassName;
+ switch (style.type) {
+ case WebInspector.CSSStyleDeclaration.Type.Rule:
+ console.assert(style.ownerRule instanceof WebInspector.CSSRule, style.ownerRule);
+
+ if (style.inherited)
+ iconClassName = WebInspector.CSSStyleDeclarationSection.InheritedStyleRuleIconStyleClassName;
+ else if (style.ownerRule.type === WebInspector.CSSRule.Type.Author)
+ iconClassName = WebInspector.CSSStyleDeclarationSection.AuthorStyleRuleIconStyleClassName;
+ else if (style.ownerRule.type === WebInspector.CSSRule.Type.User)
+ iconClassName = WebInspector.CSSStyleDeclarationSection.UserStyleRuleIconStyleClassName;
+ else if (style.ownerRule.type === WebInspector.CSSRule.Type.UserAgent)
+ iconClassName = WebInspector.CSSStyleDeclarationSection.UserAgentStyleRuleIconStyleClassName;
+ else if (style.ownerRule.type === WebInspector.CSSRule.Type.Inspector)
+ iconClassName = WebInspector.CSSStyleDeclarationSection.InspectorStyleRuleIconStyleClassName;
+ break;
+
+ case WebInspector.CSSStyleDeclaration.Type.Inline:
+ case WebInspector.CSSStyleDeclaration.Type.Attribute:
+ if (style.inherited)
+ iconClassName = WebInspector.CSSStyleDeclarationSection.InheritedElementStyleRuleIconStyleClassName;
+ else
+ iconClassName = WebInspector.DOMTreeElementPathComponent.DOMElementIconStyleClassName;
+ break;
+ }
+
+ title = title.trim();
+
+ super(["visual-style-selector-item", iconClassName], title, subtitle, style);
+
+ this._iconClassName = iconClassName;
+ this._lastValue = title;
+ this._enableEditing = true;
+ }
+
+ // Public
+
+ get iconClassName()
+ {
+ return this._iconClassName;
+ }
+
+ get selectorText()
+ {
+ let titleText = this._mainTitleElement.textContent;
+ if (!titleText || !titleText.length)
+ titleText = this._mainTitle;
+
+ return titleText.trim();
+ }
+
+ // Protected
+
+ onattach()
+ {
+ super.onattach();
+
+ this._listItemNode.addEventListener("mouseover", this._highlightNodesWithSelector.bind(this));
+ this._listItemNode.addEventListener("mouseout", this._hideDOMNodeHighlight.bind(this));
+ this._listItemNode.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this));
+
+ this._checkboxElement = document.createElement("input");
+ this._checkboxElement.type = "checkbox";
+ this._checkboxElement.checked = !this.representedObject[WebInspector.VisualStyleDetailsPanel.StyleDisabledSymbol];
+ this._updateCheckboxTitle();
+ this._checkboxElement.addEventListener("change", this._handleCheckboxChanged.bind(this));
+ this._listItemNode.insertBefore(this._checkboxElement, this._iconElement);
+
+ this._mainTitleElement.spellcheck = false;
+ this._mainTitleElement.addEventListener("mousedown", this._handleMainTitleMouseDown.bind(this));
+ this._mainTitleElement.addEventListener("keydown", this._handleMainTitleKeyDown.bind(this));
+ this._mainTitleElement.addEventListener("keyup", this._highlightNodesWithSelector.bind(this));
+ this._mainTitleElement.addEventListener("blur", this._commitSelector.bind(this));
+
+ this.representedObject.addEventListener(WebInspector.CSSStyleDeclaration.Event.InitialTextModified, this._styleTextModified, this);
+ if (this.representedObject.ownerRule)
+ this.representedObject.ownerRule.addEventListener(WebInspector.CSSRule.Event.SelectorChanged, this._selectorChanged, this);
+
+ this._styleTextModified();
+ }
+
+ ondeselect()
+ {
+ this._listItemNode.classList.remove("editable");
+ }
+
+ // Private
+
+ _highlightNodesWithSelector()
+ {
+ if (!this.representedObject.ownerRule) {
+ WebInspector.domTreeManager.highlightDOMNode(this.representedObject.node.id);
+ return;
+ }
+
+ WebInspector.domTreeManager.highlightSelector(this.selectorText, this.representedObject.node.ownerDocument.frameIdentifier);
+ }
+
+ _hideDOMNodeHighlight()
+ {
+ WebInspector.domTreeManager.hideDOMNodeHighlight();
+ }
+
+ _handleContextMenuEvent(event)
+ {
+ let contextMenu = new WebInspector.ContextMenu(event);
+
+ contextMenu.appendItem(WebInspector.UIString("Copy Rule"), function() {
+ InspectorFrontendHost.copyText(this.representedObject.generateCSSRuleString());
+ }.bind(this));
+
+ contextMenu.appendItem(WebInspector.UIString("Reset"), function() {
+ this.representedObject.resetText();
+ this.dispatchEventToListeners(WebInspector.VisualStyleSelectorTreeItem.Event.StyleTextReset);
+ }.bind(this));
+
+ contextMenu.show();
+ }
+
+ _handleCheckboxChanged(event)
+ {
+ this._updateCheckboxTitle();
+ this.dispatchEventToListeners(WebInspector.VisualStyleSelectorTreeItem.Event.CheckboxChanged, {enabled: this._checkboxElement.checked});
+ }
+
+ _updateCheckboxTitle()
+ {
+ if (this._checkboxElement.checked)
+ this._checkboxElement.title = WebInspector.UIString("Click to disable the selected rule");
+ else
+ this._checkboxElement.title = WebInspector.UIString("Click to enable the selected rule");
+ }
+
+ _handleMainTitleMouseDown(event)
+ {
+ this._listItemNode.classList.toggle("editable", this.selected);
+ }
+
+ _handleMainTitleKeyDown(event)
+ {
+ this._highlightNodesWithSelector();
+
+ let enterKeyCode = WebInspector.KeyboardShortcut.Key.Enter.keyCode;
+ if (event.keyCode === enterKeyCode)
+ this._mainTitleElement.blur();
+ }
+
+ _commitSelector()
+ {
+ this._hideDOMNodeHighlight();
+ this._listItemNode.classList.remove("editable");
+
+ let value = this.selectorText;
+ if (value === this._lastValue && this._valid)
+ return;
+
+ this.representedObject.ownerRule.selectorText = value;
+ }
+
+ _styleTextModified()
+ {
+ this._listItemNode.classList.toggle("modified", this.representedObject.modified);
+ }
+
+ _selectorChanged(event)
+ {
+ this._valid = event && event.data && event.data.valid;
+ this._listItemNode.classList.toggle("selector-invalid", !this._valid);
+ let invalidTitle = WebInspector.UIString("The selector '%s' is invalid.").format(this.selectorText);
+ this._iconElement.title = !this._valid ? invalidTitle : null;
+ }
+};
+
+WebInspector.VisualStyleSelectorTreeItem.Event = {
+ StyleTextReset: "visual-style-selector-item-style-text-reset",
+ CheckboxChanged: "visual-style-selector-item-checkbox-changed"
+};