Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / devtools / front_end / elements / ComputedStyleWidget.js
blob17b703fdb60e4ea2a1158a734711d6239456fb03
1 /*
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
7 * are met:
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.
30 /**
31 * @constructor
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());
67 /**
68 * @param {?RegExp} regex
69 * @this {WebInspector.ComputedStyleWidget}
71 function filterCallback(regex)
73 this._filterRegex = regex;
74 this._updateFilter(regex);
78 /**
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()
94 this.update();
97 /**
98 * @override
99 * @return {!Promise.<?>}
101 doUpdate: function()
103 var promises = [
104 this._sharedModel.fetchComputedStyle(),
105 this._stylesSidebarPane.fetchMatchedCascade()
107 return Promise.all(promises)
108 .spread(this._innerRebuildUpdate.bind(this));
112 * @param {string} text
113 * @return {!Node}
115 _processColor: function(text)
117 var color = WebInspector.Color.parse(text);
118 if (!color)
119 return createTextNode(text);
120 var swatch = WebInspector.ColorSwatch.create();
121 swatch.setColorText(text);
122 return swatch;
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)
135 return;
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))
147 continue;
148 var canonicalName = WebInspector.CSSMetadata.canonicalPropertyName(propertyName);
149 if (propertyName !== canonicalName && propertyValue === nodeStyle.computedStyle.get(canonicalName))
150 continue;
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] = {
168 name: propertyName,
169 value: propertyValue
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);
176 if (trace) {
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);
187 * @param {string} a
188 * @param {string} b
189 * @return {number}
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();
207 else
208 treeElement.collapse();
209 consumeEvent(event);
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;
234 if (rule) {
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))
262 continue;
263 if (!result.has(property.name))
264 result.set(property.name, []);
265 result.get(property.name).push({
266 property: property,
267 overloaded: model.isPropertyOverloaded(property.name)
271 return result;
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