2 * Copyright (C) 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2009 Joseph Pecoraro
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * @param {!WebInspector.StylesSidebarPane} stylesSidebarPane
33 * @param {!WebInspector.SharedSidebarModel} sharedModel
34 * @extends {WebInspector.ThrottledWidget}
36 WebInspector
.ComputedStyleWidget = function(stylesSidebarPane
, sharedModel
)
38 WebInspector
.ThrottledWidget
.call(this);
39 this.element
.classList
.add("computed-style-sidebar-pane");
41 this.registerRequiredCSS("elements/computedStyleSidebarPane.css");
42 this._alwaysShowComputedProperties
= { "display": true, "height": true, "width": true };
44 this._sharedModel
= sharedModel
;
45 this._sharedModel
.addEventListener(WebInspector
.SharedSidebarModel
.Events
.ComputedStyleChanged
, this.update
, this);
47 this._showInheritedComputedStylePropertiesSetting
= WebInspector
.settings
.createSetting("showInheritedComputedStyleProperties", false);
48 this._showInheritedComputedStylePropertiesSetting
.addChangeListener(this._showInheritedComputedStyleChanged
.bind(this));
50 var hbox
= this.element
.createChild("div", "hbox styles-sidebar-pane-toolbar");
51 var filterContainerElement
= hbox
.createChild("div", "styles-sidebar-pane-filter-box");
52 var filterInput
= WebInspector
.StylesSidebarPane
.createPropertyFilterElement(WebInspector
.UIString("Filter"), hbox
, filterCallback
.bind(this));
53 filterContainerElement
.appendChild(filterInput
);
55 var toolbar
= new WebInspector
.Toolbar(hbox
);
56 toolbar
.element
.classList
.add("styles-pane-toolbar");
57 toolbar
.appendToolbarItem(new WebInspector
.ToolbarCheckbox(WebInspector
.UIString("Show all"), undefined, this._showInheritedComputedStylePropertiesSetting
));
59 this._propertiesOutline
= new TreeOutlineInShadow();
60 this._propertiesOutline
.registerRequiredCSS("elements/computedStyleSidebarPane.css");
61 this._propertiesOutline
.element
.classList
.add("monospace", "computed-properties");
62 this.element
.appendChild(this._propertiesOutline
.element
);
64 this._stylesSidebarPane
= stylesSidebarPane
;
65 this._linkifier
= new WebInspector
.Linkifier(new WebInspector
.Linkifier
.DefaultCSSFormatter());
68 * @param {?RegExp} regex
69 * @this {WebInspector.ComputedStyleWidget}
71 function filterCallback(regex
)
73 this._filterRegex
= regex
;
74 this._updateFilter(regex
);
79 * @param {!WebInspector.StylesSidebarPane} stylesSidebarPane
80 * @param {!WebInspector.SharedSidebarModel} sharedModel
81 * @return {!WebInspector.ElementsSidebarViewWrapperPane}
83 WebInspector
.ComputedStyleWidget
.createSidebarWrapper = function(stylesSidebarPane
, sharedModel
)
85 var widget
= new WebInspector
.ComputedStyleWidget(stylesSidebarPane
, sharedModel
);
86 return new WebInspector
.ElementsSidebarViewWrapperPane(WebInspector
.UIString("Computed Style"), widget
)
89 WebInspector
.ComputedStyleWidget
._propertySymbol
= Symbol("property");
91 WebInspector
.ComputedStyleWidget
.prototype = {
92 _showInheritedComputedStyleChanged: function()
99 * @return {!Promise.<?>}
104 this._sharedModel
.fetchComputedStyle(),
105 this._stylesSidebarPane
.fetchMatchedCascade()
107 return Promise
.all(promises
)
108 .spread(this._innerRebuildUpdate
.bind(this));
112 * @param {string} text
115 _processColor: function(text
)
117 var color
= WebInspector
.Color
.parse(text
);
119 return createTextNode(text
);
120 var swatch
= WebInspector
.ColorSwatch
.create();
121 swatch
.setColorText(text
);
126 * @param {?WebInspector.SharedSidebarModel.ComputedStyle} nodeStyle
127 * @param {?{matched: !WebInspector.SectionCascade, pseudo: !Map.<number, !WebInspector.SectionCascade>}} cascades
129 _innerRebuildUpdate: function(nodeStyle
, cascades
)
131 this._propertiesOutline
.removeChildren();
132 this._linkifier
.reset();
133 var cssModel
= this._sharedModel
.cssModel();
134 if (!nodeStyle
|| !cascades
|| !cssModel
)
137 var uniqueProperties
= nodeStyle
.computedStyle
.keysArray();
138 uniqueProperties
.sort(propertySorter
);
140 var propertyTraces
= this._computePropertyTraces(cascades
.matched
);
141 var showInherited
= this._showInheritedComputedStylePropertiesSetting
.get();
142 for (var i
= 0; i
< uniqueProperties
.length
; ++i
) {
143 var propertyName
= uniqueProperties
[i
];
144 var propertyValue
= nodeStyle
.computedStyle
.get(propertyName
);
145 var inherited
= this._isPropertyInherited(cascades
.matched
, propertyName
);
146 if (!showInherited
&& inherited
&& !(propertyName
in this._alwaysShowComputedProperties
))
148 var canonicalName
= WebInspector
.CSSMetadata
.canonicalPropertyName(propertyName
);
149 if (propertyName
!== canonicalName
&& propertyValue
=== nodeStyle
.computedStyle
.get(canonicalName
))
152 var propertyElement
= createElement("div");
153 propertyElement
.classList
.add("computed-style-property");
154 propertyElement
.classList
.toggle("computed-style-property-inherited", inherited
);
155 var renderer
= new WebInspector
.StylesSidebarPropertyRenderer(null, nodeStyle
.node
, propertyName
, /** @type {string} */(propertyValue
));
156 renderer
.setColorHandler(this._processColor
.bind(this));
157 var propertyNameElement
= renderer
.renderName();
158 propertyNameElement
.classList
.add("property-name");
159 propertyElement
.appendChild(propertyNameElement
);
160 var propertyValueElement
= renderer
.renderValue();
161 propertyValueElement
.classList
.add("property-value");
162 propertyElement
.appendChild(propertyValueElement
);
164 var treeElement
= new TreeElement();
165 treeElement
.selectable
= false;
166 treeElement
.title
= propertyElement
;
167 treeElement
[WebInspector
.ComputedStyleWidget
._propertySymbol
] = {
171 var isOdd
= this._propertiesOutline
.rootElement().children().length
% 2 === 0;
172 treeElement
.listItemElement
.classList
.toggle("odd-row", isOdd
);
173 this._propertiesOutline
.appendChild(treeElement
);
175 var trace
= propertyTraces
.get(propertyName
);
177 this._renderPropertyTrace(cssModel
, nodeStyle
.node
, treeElement
, trace
);
178 treeElement
.listItemElement
.addEventListener("mousedown", consumeEvent
, false);
179 treeElement
.listItemElement
.addEventListener("dblclick", consumeEvent
, false);
180 treeElement
.listItemElement
.addEventListener("click", handleClick
.bind(null, treeElement
), false);
184 this._updateFilter(this._filterRegex
);
191 function propertySorter(a
, b
)
193 if (a
.startsWith("-webkit") ^ b
.startsWith("-webkit"))
194 return a
.startsWith("-webkit") ? 1 : -1;
195 var canonicalName
= WebInspector
.CSSMetadata
.canonicalPropertyName
;
196 return canonicalName(a
).compareTo(canonicalName(b
));
200 * @param {!TreeElement} treeElement
201 * @param {!Event} event
203 function handleClick(treeElement
, event
)
205 if (!treeElement
.expanded
)
206 treeElement
.expand();
208 treeElement
.collapse();
214 * @param {!WebInspector.CSSStyleModel} cssModel
215 * @param {!WebInspector.DOMNode} node
216 * @param {!TreeElement} rootTreeElement
217 * @param {!Array.<!{property: !WebInspector.CSSProperty, overloaded: boolean}>} tracedProperties
219 _renderPropertyTrace: function(cssModel
, node
, rootTreeElement
, tracedProperties
)
221 for (var propertyInfo
of tracedProperties
) {
222 var trace
= createElement("div");
223 trace
.classList
.add("property-trace");
224 if (propertyInfo
.overloaded
)
225 trace
.classList
.add("property-trace-inactive");
227 var renderer
= new WebInspector
.StylesSidebarPropertyRenderer(null, node
, propertyInfo
.property
.name
, /** @type {string} */(propertyInfo
.property
.value
));
228 renderer
.setColorHandler(this._processColor
.bind(this));
229 var valueElement
= renderer
.renderValue();
230 valueElement
.classList
.add("property-trace-value");
231 trace
.appendChild(valueElement
);
233 var rule
= propertyInfo
.property
.ownerStyle
.parentRule
;
235 var linkSpan
= trace
.createChild("span", "trace-link");
236 linkSpan
.appendChild(WebInspector
.StylePropertiesSection
.createRuleOriginNode(cssModel
, this._linkifier
, rule
));
239 var selectorElement
= trace
.createChild("span", "property-trace-selector");
240 selectorElement
.textContent
= rule
? rule
.selectorText() : "element.style";
241 selectorElement
.title
= selectorElement
.textContent
;
243 var traceTreeElement
= new TreeElement();
244 traceTreeElement
.title
= trace
;
245 traceTreeElement
.selectable
= false;
246 rootTreeElement
.appendChild(traceTreeElement
);
251 * @param {!WebInspector.SectionCascade} matchedCascade
252 * @return {!Map.<string, !Array.<!{property: !WebInspector.CSSProperty, overloaded: boolean}>>}
254 _computePropertyTraces: function(matchedCascade
)
256 var result
= new Map();
257 var models
= matchedCascade
.sectionModels();
258 for (var model
of models
) {
259 var allProperties
= model
.style().allProperties
;
260 for (var property
of allProperties
) {
261 if (!property
.activeInStyle() || !model
.isPropertyInCascade(property
.name
))
263 if (!result
.has(property
.name
))
264 result
.set(property
.name
, []);
265 result
.get(property
.name
).push({
267 overloaded
: model
.isPropertyOverloaded(property
.name
)
275 * @param {!WebInspector.SectionCascade} matchedCascade
276 * @param {string} propertyName
278 _isPropertyInherited: function(matchedCascade
, propertyName
)
280 var canonicalName
= WebInspector
.CSSMetadata
.canonicalPropertyName(propertyName
);
281 return !matchedCascade
.allUsedProperties().has(canonicalName
);
285 * @param {?RegExp} regex
287 _updateFilter: function(regex
)
289 var children
= this._propertiesOutline
.rootElement().children();
290 for (var child
of children
) {
291 var property
= child
[WebInspector
.ComputedStyleWidget
._propertySymbol
];
292 var matched
= !regex
|| regex
.test(property
.name
) || regex
.test(property
.value
);
293 child
.hidden
= !matched
;
297 __proto__
: WebInspector
.ThrottledWidget
.prototype