OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2007 Apple Inc. All rights reserved. | 2 * Copyright (C) 2007 Apple Inc. All rights reserved. |
3 * Copyright (C) 2009 Joseph Pecoraro | 3 * Copyright (C) 2009 Joseph Pecoraro |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
7 * are met: | 7 * are met: |
8 * | 8 * |
9 * 1. Redistributions of source code must retain the above copyright | 9 * 1. Redistributions of source code must retain the above copyright |
10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
11 * 2. Redistributions in binary form must reproduce the above copyright | 11 * 2. Redistributions in binary form must reproduce the above copyright |
12 * notice, this list of conditions and the following disclaimer in the | 12 * notice, this list of conditions and the following disclaimer in the |
13 * documentation and/or other materials provided with the distribution. | 13 * documentation and/or other materials provided with the distribution. |
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of | 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 | 15 * its contributors may be used to endorse or promote products derived |
16 * from this software without specific prior written permission. | 16 * from this software without specific prior written permission. |
17 * | 17 * |
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | 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 | 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 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 | 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 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 | 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 | 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 | 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. | 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 */ | 28 */ |
| 29 /** |
| 30 * @unrestricted |
| 31 */ |
| 32 WebInspector.ComputedStyleWidget = class extends WebInspector.ThrottledWidget { |
| 33 constructor() { |
| 34 super(); |
| 35 this.element.classList.add('computed-style-sidebar-pane'); |
29 | 36 |
30 /** | 37 this.registerRequiredCSS('elements/computedStyleSidebarPane.css'); |
31 * @constructor | 38 this._alwaysShowComputedProperties = {'display': true, 'height': true, 'widt
h': true}; |
32 * @extends {WebInspector.ThrottledWidget} | |
33 */ | |
34 WebInspector.ComputedStyleWidget = function() | |
35 { | |
36 WebInspector.ThrottledWidget.call(this); | |
37 this.element.classList.add("computed-style-sidebar-pane"); | |
38 | |
39 this.registerRequiredCSS("elements/computedStyleSidebarPane.css"); | |
40 this._alwaysShowComputedProperties = { "display": true, "height": true, "wid
th": true }; | |
41 | 39 |
42 this._computedStyleModel = new WebInspector.ComputedStyleModel(); | 40 this._computedStyleModel = new WebInspector.ComputedStyleModel(); |
43 this._computedStyleModel.addEventListener(WebInspector.ComputedStyleModel.Ev
ents.ComputedStyleChanged, this.update, this); | 41 this._computedStyleModel.addEventListener( |
| 42 WebInspector.ComputedStyleModel.Events.ComputedStyleChanged, this.update
, this); |
44 | 43 |
45 this._showInheritedComputedStylePropertiesSetting = WebInspector.settings.cr
eateSetting("showInheritedComputedStyleProperties", false); | 44 this._showInheritedComputedStylePropertiesSetting = |
46 this._showInheritedComputedStylePropertiesSetting.addChangeListener(this._sh
owInheritedComputedStyleChanged.bind(this)); | 45 WebInspector.settings.createSetting('showInheritedComputedStylePropertie
s', false); |
| 46 this._showInheritedComputedStylePropertiesSetting.addChangeListener( |
| 47 this._showInheritedComputedStyleChanged.bind(this)); |
47 | 48 |
48 var hbox = this.element.createChild("div", "hbox styles-sidebar-pane-toolbar
"); | 49 var hbox = this.element.createChild('div', 'hbox styles-sidebar-pane-toolbar
'); |
49 var filterContainerElement = hbox.createChild("div", "styles-sidebar-pane-fi
lter-box"); | 50 var filterContainerElement = hbox.createChild('div', 'styles-sidebar-pane-fi
lter-box'); |
50 var filterInput = WebInspector.StylesSidebarPane.createPropertyFilterElement
(WebInspector.UIString("Filter"), hbox, filterCallback.bind(this)); | 51 var filterInput = WebInspector.StylesSidebarPane.createPropertyFilterElement
( |
| 52 WebInspector.UIString('Filter'), hbox, filterCallback.bind(this)); |
51 filterContainerElement.appendChild(filterInput); | 53 filterContainerElement.appendChild(filterInput); |
52 | 54 |
53 var toolbar = new WebInspector.Toolbar("styles-pane-toolbar", hbox); | 55 var toolbar = new WebInspector.Toolbar('styles-pane-toolbar', hbox); |
54 toolbar.appendToolbarItem(new WebInspector.ToolbarCheckbox(WebInspector.UISt
ring("Show all"), undefined, this._showInheritedComputedStylePropertiesSetting))
; | 56 toolbar.appendToolbarItem(new WebInspector.ToolbarCheckbox( |
| 57 WebInspector.UIString('Show all'), undefined, this._showInheritedCompute
dStylePropertiesSetting)); |
55 | 58 |
56 this._propertiesOutline = new TreeOutlineInShadow(); | 59 this._propertiesOutline = new TreeOutlineInShadow(); |
57 this._propertiesOutline.hideOverflow(); | 60 this._propertiesOutline.hideOverflow(); |
58 this._propertiesOutline.registerRequiredCSS("elements/computedStyleSidebarPa
ne.css"); | 61 this._propertiesOutline.registerRequiredCSS('elements/computedStyleSidebarPa
ne.css'); |
59 this._propertiesOutline.element.classList.add("monospace", "computed-propert
ies"); | 62 this._propertiesOutline.element.classList.add('monospace', 'computed-propert
ies'); |
60 this.element.appendChild(this._propertiesOutline.element); | 63 this.element.appendChild(this._propertiesOutline.element); |
61 | 64 |
62 this._linkifier = new WebInspector.Linkifier(new WebInspector.Linkifier.Defa
ultCSSFormatter()); | 65 this._linkifier = new WebInspector.Linkifier(new WebInspector.Linkifier.Defa
ultCSSFormatter()); |
63 | 66 |
64 /** | 67 /** |
65 * @param {?RegExp} regex | 68 * @param {?RegExp} regex |
66 * @this {WebInspector.ComputedStyleWidget} | 69 * @this {WebInspector.ComputedStyleWidget} |
67 */ | 70 */ |
68 function filterCallback(regex) | 71 function filterCallback(regex) { |
69 { | 72 this._filterRegex = regex; |
70 this._filterRegex = regex; | 73 this._updateFilter(regex); |
71 this._updateFilter(regex); | |
72 } | 74 } |
73 | 75 |
74 var fontsWidget = new WebInspector.PlatformFontsWidget(this._computedStyleMo
del); | 76 var fontsWidget = new WebInspector.PlatformFontsWidget(this._computedStyleMo
del); |
75 fontsWidget.show(this.element); | 77 fontsWidget.show(this.element); |
| 78 } |
| 79 |
| 80 _showInheritedComputedStyleChanged() { |
| 81 this.update(); |
| 82 } |
| 83 |
| 84 /** |
| 85 * @override |
| 86 * @return {!Promise.<?>} |
| 87 */ |
| 88 doUpdate() { |
| 89 var promises = [this._computedStyleModel.fetchComputedStyle(), this._fetchMa
tchedCascade()]; |
| 90 return Promise.all(promises).spread(this._innerRebuildUpdate.bind(this)); |
| 91 } |
| 92 |
| 93 /** |
| 94 * @return {!Promise.<?WebInspector.CSSMatchedStyles>} |
| 95 */ |
| 96 _fetchMatchedCascade() { |
| 97 var node = this._computedStyleModel.node(); |
| 98 if (!node || !this._computedStyleModel.cssModel()) |
| 99 return Promise.resolve(/** @type {?WebInspector.CSSMatchedStyles} */ (null
)); |
| 100 |
| 101 return this._computedStyleModel.cssModel().cachedMatchedCascadeForNode(node)
.then(validateStyles.bind(this)); |
| 102 |
| 103 /** |
| 104 * @param {?WebInspector.CSSMatchedStyles} matchedStyles |
| 105 * @return {?WebInspector.CSSMatchedStyles} |
| 106 * @this {WebInspector.ComputedStyleWidget} |
| 107 */ |
| 108 function validateStyles(matchedStyles) { |
| 109 return matchedStyles && matchedStyles.node() === this._computedStyleModel.
node() ? matchedStyles : null; |
| 110 } |
| 111 } |
| 112 |
| 113 /** |
| 114 * @param {string} text |
| 115 * @return {!Node} |
| 116 */ |
| 117 _processColor(text) { |
| 118 var color = WebInspector.Color.parse(text); |
| 119 if (!color) |
| 120 return createTextNode(text); |
| 121 var swatch = WebInspector.ColorSwatch.create(); |
| 122 swatch.setColor(color); |
| 123 swatch.setFormat(WebInspector.Color.detectColorFormat(color)); |
| 124 return swatch; |
| 125 } |
| 126 |
| 127 /** |
| 128 * @param {?WebInspector.ComputedStyleModel.ComputedStyle} nodeStyle |
| 129 * @param {?WebInspector.CSSMatchedStyles} matchedStyles |
| 130 */ |
| 131 _innerRebuildUpdate(nodeStyle, matchedStyles) { |
| 132 /** @type {!Set<string>} */ |
| 133 var expandedProperties = new Set(); |
| 134 for (var treeElement of this._propertiesOutline.rootElement().children()) { |
| 135 if (!treeElement.expanded) |
| 136 continue; |
| 137 var propertyName = treeElement[WebInspector.ComputedStyleWidget._propertyS
ymbol].name; |
| 138 expandedProperties.add(propertyName); |
| 139 } |
| 140 this._propertiesOutline.removeChildren(); |
| 141 this._linkifier.reset(); |
| 142 var cssModel = this._computedStyleModel.cssModel(); |
| 143 if (!nodeStyle || !matchedStyles || !cssModel) |
| 144 return; |
| 145 |
| 146 var uniqueProperties = nodeStyle.computedStyle.keysArray(); |
| 147 uniqueProperties.sort(propertySorter); |
| 148 |
| 149 var propertyTraces = this._computePropertyTraces(matchedStyles); |
| 150 var inhertiedProperties = this._computeInheritedProperties(matchedStyles); |
| 151 var showInherited = this._showInheritedComputedStylePropertiesSetting.get(); |
| 152 for (var i = 0; i < uniqueProperties.length; ++i) { |
| 153 var propertyName = uniqueProperties[i]; |
| 154 var propertyValue = nodeStyle.computedStyle.get(propertyName); |
| 155 var canonicalName = WebInspector.cssMetadata().canonicalPropertyName(prope
rtyName); |
| 156 var inherited = !inhertiedProperties.has(canonicalName); |
| 157 if (!showInherited && inherited && !(propertyName in this._alwaysShowCompu
tedProperties)) |
| 158 continue; |
| 159 if (propertyName !== canonicalName && propertyValue === nodeStyle.computed
Style.get(canonicalName)) |
| 160 continue; |
| 161 |
| 162 var propertyElement = createElement('div'); |
| 163 propertyElement.classList.add('computed-style-property'); |
| 164 propertyElement.classList.toggle('computed-style-property-inherited', inhe
rited); |
| 165 var renderer = new WebInspector.StylesSidebarPropertyRenderer( |
| 166 null, nodeStyle.node, propertyName, /** @type {string} */ (propertyVal
ue)); |
| 167 renderer.setColorHandler(this._processColor.bind(this)); |
| 168 var propertyNameElement = renderer.renderName(); |
| 169 propertyNameElement.classList.add('property-name'); |
| 170 propertyElement.appendChild(propertyNameElement); |
| 171 |
| 172 var colon = createElementWithClass('span', 'delimeter'); |
| 173 colon.textContent = ':'; |
| 174 propertyNameElement.appendChild(colon); |
| 175 |
| 176 var propertyValueElement = propertyElement.createChild('span', 'property-v
alue'); |
| 177 |
| 178 var propertyValueText = renderer.renderValue(); |
| 179 propertyValueText.classList.add('property-value-text'); |
| 180 propertyValueElement.appendChild(propertyValueText); |
| 181 |
| 182 var semicolon = createElementWithClass('span', 'delimeter'); |
| 183 semicolon.textContent = ';'; |
| 184 propertyValueElement.appendChild(semicolon); |
| 185 |
| 186 var treeElement = new TreeElement(); |
| 187 treeElement.selectable = false; |
| 188 treeElement.title = propertyElement; |
| 189 treeElement[WebInspector.ComputedStyleWidget._propertySymbol] = {name: pro
pertyName, value: propertyValue}; |
| 190 var isOdd = this._propertiesOutline.rootElement().children().length % 2 ==
= 0; |
| 191 treeElement.listItemElement.classList.toggle('odd-row', isOdd); |
| 192 this._propertiesOutline.appendChild(treeElement); |
| 193 |
| 194 var trace = propertyTraces.get(propertyName); |
| 195 if (trace) { |
| 196 var activeProperty = this._renderPropertyTrace(cssModel, matchedStyles,
nodeStyle.node, treeElement, trace); |
| 197 treeElement.listItemElement.addEventListener('mousedown', (e) => e.consu
me(), false); |
| 198 treeElement.listItemElement.addEventListener('dblclick', (e) => e.consum
e(), false); |
| 199 treeElement.listItemElement.addEventListener('click', handleClick.bind(n
ull, treeElement), false); |
| 200 var gotoSourceElement = propertyValueElement.createChild('div', 'goto-so
urce-icon'); |
| 201 gotoSourceElement.addEventListener('click', this._navigateToSource.bind(
this, activeProperty)); |
| 202 if (expandedProperties.has(propertyName)) |
| 203 treeElement.expand(); |
| 204 } |
| 205 } |
| 206 |
| 207 this._updateFilter(this._filterRegex); |
| 208 |
| 209 /** |
| 210 * @param {string} a |
| 211 * @param {string} b |
| 212 * @return {number} |
| 213 */ |
| 214 function propertySorter(a, b) { |
| 215 if (a.startsWith('-webkit') ^ b.startsWith('-webkit')) |
| 216 return a.startsWith('-webkit') ? 1 : -1; |
| 217 var canonical1 = WebInspector.cssMetadata().canonicalPropertyName(a); |
| 218 var canonical2 = WebInspector.cssMetadata().canonicalPropertyName(b); |
| 219 return canonical1.compareTo(canonical2); |
| 220 } |
| 221 |
| 222 /** |
| 223 * @param {!TreeElement} treeElement |
| 224 * @param {!Event} event |
| 225 */ |
| 226 function handleClick(treeElement, event) { |
| 227 if (!treeElement.expanded) |
| 228 treeElement.expand(); |
| 229 else |
| 230 treeElement.collapse(); |
| 231 event.consume(); |
| 232 } |
| 233 } |
| 234 |
| 235 /** |
| 236 * @param {!WebInspector.CSSProperty} cssProperty |
| 237 * @param {!Event} event |
| 238 */ |
| 239 _navigateToSource(cssProperty, event) { |
| 240 WebInspector.Revealer.reveal(cssProperty); |
| 241 event.consume(true); |
| 242 } |
| 243 |
| 244 /** |
| 245 * @param {!WebInspector.CSSModel} cssModel |
| 246 * @param {!WebInspector.CSSMatchedStyles} matchedStyles |
| 247 * @param {!WebInspector.DOMNode} node |
| 248 * @param {!TreeElement} rootTreeElement |
| 249 * @param {!Array<!WebInspector.CSSProperty>} tracedProperties |
| 250 * @return {!WebInspector.CSSProperty} |
| 251 */ |
| 252 _renderPropertyTrace(cssModel, matchedStyles, node, rootTreeElement, tracedPro
perties) { |
| 253 var activeProperty = null; |
| 254 for (var property of tracedProperties) { |
| 255 var trace = createElement('div'); |
| 256 trace.classList.add('property-trace'); |
| 257 if (matchedStyles.propertyState(property) === WebInspector.CSSMatchedStyle
s.PropertyState.Overloaded) |
| 258 trace.classList.add('property-trace-inactive'); |
| 259 else |
| 260 activeProperty = property; |
| 261 |
| 262 var renderer = new WebInspector.StylesSidebarPropertyRenderer( |
| 263 null, node, property.name, /** @type {string} */ (property.value)); |
| 264 renderer.setColorHandler(this._processColor.bind(this)); |
| 265 var valueElement = renderer.renderValue(); |
| 266 valueElement.classList.add('property-trace-value'); |
| 267 valueElement.addEventListener('click', this._navigateToSource.bind(this, p
roperty), false); |
| 268 var gotoSourceElement = createElement('div'); |
| 269 gotoSourceElement.classList.add('goto-source-icon'); |
| 270 gotoSourceElement.addEventListener('click', this._navigateToSource.bind(th
is, property)); |
| 271 valueElement.insertBefore(gotoSourceElement, valueElement.firstChild); |
| 272 |
| 273 trace.appendChild(valueElement); |
| 274 |
| 275 var rule = property.ownerStyle.parentRule; |
| 276 if (rule) { |
| 277 var linkSpan = trace.createChild('span', 'trace-link'); |
| 278 linkSpan.appendChild( |
| 279 WebInspector.StylePropertiesSection.createRuleOriginNode(matchedStyl
es, this._linkifier, rule)); |
| 280 } |
| 281 |
| 282 var selectorElement = trace.createChild('span', 'property-trace-selector')
; |
| 283 selectorElement.textContent = rule ? rule.selectorText() : 'element.style'
; |
| 284 selectorElement.title = selectorElement.textContent; |
| 285 |
| 286 var traceTreeElement = new TreeElement(); |
| 287 traceTreeElement.title = trace; |
| 288 traceTreeElement.selectable = false; |
| 289 rootTreeElement.appendChild(traceTreeElement); |
| 290 } |
| 291 return /** @type {!WebInspector.CSSProperty} */ (activeProperty); |
| 292 } |
| 293 |
| 294 /** |
| 295 * @param {!WebInspector.CSSMatchedStyles} matchedStyles |
| 296 * @return {!Map<string, !Array<!WebInspector.CSSProperty>>} |
| 297 */ |
| 298 _computePropertyTraces(matchedStyles) { |
| 299 var result = new Map(); |
| 300 for (var style of matchedStyles.nodeStyles()) { |
| 301 var allProperties = style.allProperties; |
| 302 for (var property of allProperties) { |
| 303 if (!property.activeInStyle() || !matchedStyles.propertyState(property)) |
| 304 continue; |
| 305 if (!result.has(property.name)) |
| 306 result.set(property.name, []); |
| 307 result.get(property.name).push(property); |
| 308 } |
| 309 } |
| 310 return result; |
| 311 } |
| 312 |
| 313 /** |
| 314 * @param {!WebInspector.CSSMatchedStyles} matchedStyles |
| 315 * @return {!Set<string>} |
| 316 */ |
| 317 _computeInheritedProperties(matchedStyles) { |
| 318 var result = new Set(); |
| 319 for (var style of matchedStyles.nodeStyles()) { |
| 320 for (var property of style.allProperties) { |
| 321 if (!matchedStyles.propertyState(property)) |
| 322 continue; |
| 323 result.add(WebInspector.cssMetadata().canonicalPropertyName(property.nam
e)); |
| 324 } |
| 325 } |
| 326 return result; |
| 327 } |
| 328 |
| 329 /** |
| 330 * @param {?RegExp} regex |
| 331 */ |
| 332 _updateFilter(regex) { |
| 333 var children = this._propertiesOutline.rootElement().children(); |
| 334 for (var child of children) { |
| 335 var property = child[WebInspector.ComputedStyleWidget._propertySymbol]; |
| 336 var matched = !regex || regex.test(property.name) || regex.test(property.v
alue); |
| 337 child.hidden = !matched; |
| 338 } |
| 339 } |
76 }; | 340 }; |
77 | 341 |
78 WebInspector.ComputedStyleWidget._propertySymbol = Symbol("property"); | 342 WebInspector.ComputedStyleWidget._propertySymbol = Symbol('property'); |
79 | |
80 WebInspector.ComputedStyleWidget.prototype = { | |
81 _showInheritedComputedStyleChanged: function() | |
82 { | |
83 this.update(); | |
84 }, | |
85 | |
86 /** | |
87 * @override | |
88 * @return {!Promise.<?>} | |
89 */ | |
90 doUpdate: function() | |
91 { | |
92 var promises = [ | |
93 this._computedStyleModel.fetchComputedStyle(), | |
94 this._fetchMatchedCascade() | |
95 ]; | |
96 return Promise.all(promises) | |
97 .spread(this._innerRebuildUpdate.bind(this)); | |
98 }, | |
99 | |
100 /** | |
101 * @return {!Promise.<?WebInspector.CSSMatchedStyles>} | |
102 */ | |
103 _fetchMatchedCascade: function() | |
104 { | |
105 var node = this._computedStyleModel.node(); | |
106 if (!node || !this._computedStyleModel.cssModel()) | |
107 return Promise.resolve(/** @type {?WebInspector.CSSMatchedStyles} */
(null)); | |
108 | |
109 return this._computedStyleModel.cssModel().cachedMatchedCascadeForNode(n
ode).then(validateStyles.bind(this)); | |
110 | |
111 /** | |
112 * @param {?WebInspector.CSSMatchedStyles} matchedStyles | |
113 * @return {?WebInspector.CSSMatchedStyles} | |
114 * @this {WebInspector.ComputedStyleWidget} | |
115 */ | |
116 function validateStyles(matchedStyles) | |
117 { | |
118 return matchedStyles && matchedStyles.node() === this._computedStyle
Model.node() ? matchedStyles : null; | |
119 } | |
120 }, | |
121 | |
122 /** | |
123 * @param {string} text | |
124 * @return {!Node} | |
125 */ | |
126 _processColor: function(text) | |
127 { | |
128 var color = WebInspector.Color.parse(text); | |
129 if (!color) | |
130 return createTextNode(text); | |
131 var swatch = WebInspector.ColorSwatch.create(); | |
132 swatch.setColor(color); | |
133 swatch.setFormat(WebInspector.Color.detectColorFormat(color)); | |
134 return swatch; | |
135 }, | |
136 | |
137 /** | |
138 * @param {?WebInspector.ComputedStyleModel.ComputedStyle} nodeStyle | |
139 * @param {?WebInspector.CSSMatchedStyles} matchedStyles | |
140 */ | |
141 _innerRebuildUpdate: function(nodeStyle, matchedStyles) | |
142 { | |
143 /** @type {!Set<string>} */ | |
144 var expandedProperties = new Set(); | |
145 for (var treeElement of this._propertiesOutline.rootElement().children()
) { | |
146 if (!treeElement.expanded) | |
147 continue; | |
148 var propertyName = treeElement[WebInspector.ComputedStyleWidget._pro
pertySymbol].name; | |
149 expandedProperties.add(propertyName); | |
150 } | |
151 this._propertiesOutline.removeChildren(); | |
152 this._linkifier.reset(); | |
153 var cssModel = this._computedStyleModel.cssModel(); | |
154 if (!nodeStyle || !matchedStyles || !cssModel) | |
155 return; | |
156 | |
157 var uniqueProperties = nodeStyle.computedStyle.keysArray(); | |
158 uniqueProperties.sort(propertySorter); | |
159 | |
160 var propertyTraces = this._computePropertyTraces(matchedStyles); | |
161 var inhertiedProperties = this._computeInheritedProperties(matchedStyles
); | |
162 var showInherited = this._showInheritedComputedStylePropertiesSetting.ge
t(); | |
163 for (var i = 0; i < uniqueProperties.length; ++i) { | |
164 var propertyName = uniqueProperties[i]; | |
165 var propertyValue = nodeStyle.computedStyle.get(propertyName); | |
166 var canonicalName = WebInspector.cssMetadata().canonicalPropertyName
(propertyName); | |
167 var inherited = !inhertiedProperties.has(canonicalName); | |
168 if (!showInherited && inherited && !(propertyName in this._alwaysSho
wComputedProperties)) | |
169 continue; | |
170 if (propertyName !== canonicalName && propertyValue === nodeStyle.co
mputedStyle.get(canonicalName)) | |
171 continue; | |
172 | |
173 var propertyElement = createElement("div"); | |
174 propertyElement.classList.add("computed-style-property"); | |
175 propertyElement.classList.toggle("computed-style-property-inherited"
, inherited); | |
176 var renderer = new WebInspector.StylesSidebarPropertyRenderer(null,
nodeStyle.node, propertyName, /** @type {string} */(propertyValue)); | |
177 renderer.setColorHandler(this._processColor.bind(this)); | |
178 var propertyNameElement = renderer.renderName(); | |
179 propertyNameElement.classList.add("property-name"); | |
180 propertyElement.appendChild(propertyNameElement); | |
181 | |
182 var colon = createElementWithClass("span", "delimeter"); | |
183 colon.textContent = ":"; | |
184 propertyNameElement.appendChild(colon); | |
185 | |
186 var propertyValueElement = propertyElement.createChild("span", "prop
erty-value"); | |
187 | |
188 var propertyValueText = renderer.renderValue(); | |
189 propertyValueText.classList.add("property-value-text"); | |
190 propertyValueElement.appendChild(propertyValueText); | |
191 | |
192 var semicolon = createElementWithClass("span", "delimeter"); | |
193 semicolon.textContent = ";"; | |
194 propertyValueElement.appendChild(semicolon); | |
195 | |
196 var treeElement = new TreeElement(); | |
197 treeElement.selectable = false; | |
198 treeElement.title = propertyElement; | |
199 treeElement[WebInspector.ComputedStyleWidget._propertySymbol] = { | |
200 name: propertyName, | |
201 value: propertyValue | |
202 }; | |
203 var isOdd = this._propertiesOutline.rootElement().children().length
% 2 === 0; | |
204 treeElement.listItemElement.classList.toggle("odd-row", isOdd); | |
205 this._propertiesOutline.appendChild(treeElement); | |
206 | |
207 var trace = propertyTraces.get(propertyName); | |
208 if (trace) { | |
209 var activeProperty = this._renderPropertyTrace(cssModel, matched
Styles, nodeStyle.node, treeElement, trace); | |
210 treeElement.listItemElement.addEventListener("mousedown", (e) =>
e.consume(), false); | |
211 treeElement.listItemElement.addEventListener("dblclick", (e) =>
e.consume(), false); | |
212 treeElement.listItemElement.addEventListener("click", handleClic
k.bind(null, treeElement), false); | |
213 var gotoSourceElement = propertyValueElement.createChild("div",
"goto-source-icon"); | |
214 gotoSourceElement.addEventListener("click", this._navigateToSour
ce.bind(this, activeProperty)); | |
215 if (expandedProperties.has(propertyName)) | |
216 treeElement.expand(); | |
217 } | |
218 } | |
219 | |
220 this._updateFilter(this._filterRegex); | |
221 | |
222 /** | |
223 * @param {string} a | |
224 * @param {string} b | |
225 * @return {number} | |
226 */ | |
227 function propertySorter(a, b) | |
228 { | |
229 if (a.startsWith("-webkit") ^ b.startsWith("-webkit")) | |
230 return a.startsWith("-webkit") ? 1 : -1; | |
231 var canonical1 = WebInspector.cssMetadata().canonicalPropertyName(a)
; | |
232 var canonical2 = WebInspector.cssMetadata().canonicalPropertyName(b)
; | |
233 return canonical1.compareTo(canonical2); | |
234 } | |
235 | |
236 /** | |
237 * @param {!TreeElement} treeElement | |
238 * @param {!Event} event | |
239 */ | |
240 function handleClick(treeElement, event) | |
241 { | |
242 if (!treeElement.expanded) | |
243 treeElement.expand(); | |
244 else | |
245 treeElement.collapse(); | |
246 event.consume(); | |
247 } | |
248 }, | |
249 | |
250 /** | |
251 * @param {!WebInspector.CSSProperty} cssProperty | |
252 * @param {!Event} event | |
253 */ | |
254 _navigateToSource: function(cssProperty, event) | |
255 { | |
256 WebInspector.Revealer.reveal(cssProperty); | |
257 event.consume(true); | |
258 }, | |
259 | |
260 /** | |
261 * @param {!WebInspector.CSSModel} cssModel | |
262 * @param {!WebInspector.CSSMatchedStyles} matchedStyles | |
263 * @param {!WebInspector.DOMNode} node | |
264 * @param {!TreeElement} rootTreeElement | |
265 * @param {!Array<!WebInspector.CSSProperty>} tracedProperties | |
266 * @return {!WebInspector.CSSProperty} | |
267 */ | |
268 _renderPropertyTrace: function(cssModel, matchedStyles, node, rootTreeElemen
t, tracedProperties) | |
269 { | |
270 var activeProperty = null; | |
271 for (var property of tracedProperties) { | |
272 var trace = createElement("div"); | |
273 trace.classList.add("property-trace"); | |
274 if (matchedStyles.propertyState(property) === WebInspector.CSSMatche
dStyles.PropertyState.Overloaded) | |
275 trace.classList.add("property-trace-inactive"); | |
276 else | |
277 activeProperty = property; | |
278 | |
279 var renderer = new WebInspector.StylesSidebarPropertyRenderer(null,
node, property.name, /** @type {string} */(property.value)); | |
280 renderer.setColorHandler(this._processColor.bind(this)); | |
281 var valueElement = renderer.renderValue(); | |
282 valueElement.classList.add("property-trace-value"); | |
283 valueElement.addEventListener("click", this._navigateToSource.bind(t
his, property), false); | |
284 var gotoSourceElement = createElement("div"); | |
285 gotoSourceElement.classList.add("goto-source-icon"); | |
286 gotoSourceElement.addEventListener("click", this._navigateToSource.b
ind(this, property)); | |
287 valueElement.insertBefore(gotoSourceElement, valueElement.firstChild
); | |
288 | |
289 trace.appendChild(valueElement); | |
290 | |
291 var rule = property.ownerStyle.parentRule; | |
292 if (rule) { | |
293 var linkSpan = trace.createChild("span", "trace-link"); | |
294 linkSpan.appendChild(WebInspector.StylePropertiesSection.createR
uleOriginNode(matchedStyles, this._linkifier, rule)); | |
295 } | |
296 | |
297 var selectorElement = trace.createChild("span", "property-trace-sele
ctor"); | |
298 selectorElement.textContent = rule ? rule.selectorText() : "element.
style"; | |
299 selectorElement.title = selectorElement.textContent; | |
300 | |
301 var traceTreeElement = new TreeElement(); | |
302 traceTreeElement.title = trace; | |
303 traceTreeElement.selectable = false; | |
304 rootTreeElement.appendChild(traceTreeElement); | |
305 } | |
306 return /** @type {!WebInspector.CSSProperty} */(activeProperty); | |
307 }, | |
308 | |
309 /** | |
310 * @param {!WebInspector.CSSMatchedStyles} matchedStyles | |
311 * @return {!Map<string, !Array<!WebInspector.CSSProperty>>} | |
312 */ | |
313 _computePropertyTraces: function(matchedStyles) | |
314 { | |
315 var result = new Map(); | |
316 for (var style of matchedStyles.nodeStyles()) { | |
317 var allProperties = style.allProperties; | |
318 for (var property of allProperties) { | |
319 if (!property.activeInStyle() || !matchedStyles.propertyState(pr
operty)) | |
320 continue; | |
321 if (!result.has(property.name)) | |
322 result.set(property.name, []); | |
323 result.get(property.name).push(property); | |
324 } | |
325 } | |
326 return result; | |
327 }, | |
328 | |
329 /** | |
330 * @param {!WebInspector.CSSMatchedStyles} matchedStyles | |
331 * @return {!Set<string>} | |
332 */ | |
333 _computeInheritedProperties: function(matchedStyles) | |
334 { | |
335 var result = new Set(); | |
336 for (var style of matchedStyles.nodeStyles()) { | |
337 for (var property of style.allProperties) { | |
338 if (!matchedStyles.propertyState(property)) | |
339 continue; | |
340 result.add(WebInspector.cssMetadata().canonicalPropertyName(prop
erty.name)); | |
341 } | |
342 } | |
343 return result; | |
344 }, | |
345 | |
346 /** | |
347 * @param {?RegExp} regex | |
348 */ | |
349 _updateFilter: function(regex) | |
350 { | |
351 var children = this._propertiesOutline.rootElement().children(); | |
352 for (var child of children) { | |
353 var property = child[WebInspector.ComputedStyleWidget._propertySymbo
l]; | |
354 var matched = !regex || regex.test(property.name) || regex.test(prop
erty.value); | |
355 child.hidden = !matched; | |
356 } | |
357 }, | |
358 | |
359 __proto__: WebInspector.ThrottledWidget.prototype | |
360 }; | |
OLD | NEW |