Web Inspector: clicking Computed Styles sidebar "Show All" checkbox doesn't trigger...
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / ComputedStyleDetailsPanel.js
1 /*
2  * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 WebInspector.ComputedStyleDetailsPanel = class ComputedStyleDetailsPanel extends WebInspector.StyleDetailsPanel
27 {
28     constructor(delegate)
29     {
30         super(delegate, WebInspector.ComputedStyleDetailsPanel.StyleClassName, "computed", WebInspector.UIString("Styles \u2014 Computed"));
31
32         this._computedStyleShowAllSetting = new WebInspector.Setting("computed-style-show-all", false);
33
34         this.cssStyleDeclarationTextEditorShouldAddPropertyGoToArrows = true;
35     }
36
37     // Public
38
39     get regionFlow() { return this._regionFlow; }
40     set regionFlow(regionFlow)
41     {
42         this._regionFlow = regionFlow;
43         this._regionFlowNameLabelValue.textContent = regionFlow ? regionFlow.name : "";
44         this._regionFlowNameRow.value = regionFlow ? this._regionFlowFragment : null;
45         this._updateFlowNamesSectionVisibility();
46     }
47
48     get contentFlow() { return this._contentFlow; }
49     set contentFlow(contentFlow)
50     {
51         this._contentFlow = contentFlow;
52         this._contentFlowNameLabelValue.textContent = contentFlow ? contentFlow.name : "";
53         this._contentFlowNameRow.value = contentFlow ? this._contentFlowFragment : null;
54         this._updateFlowNamesSectionVisibility();
55     }
56
57     get containerRegions() { return this._containerRegions; }
58     set containerRegions(regions)
59     {
60         this._containerRegions = regions;
61
62         if (!regions || !regions.length) {
63             this._containerRegionsFlowSection.element.classList.add("hidden");
64             return;
65         }
66
67         this._containerRegionsDataGrid.removeChildren();
68         for (var regionNode of regions)
69             this._containerRegionsDataGrid.appendChild(new WebInspector.DOMTreeDataGridNode(regionNode));
70
71         this._containerRegionsFlowSection.element.classList.remove("hidden");
72
73         this._containerRegionsDataGrid.updateLayoutIfNeeded();
74     }
75
76     cssStyleDeclarationTextEditorShowProperty(property, showSource)
77     {
78         function delegateShowProperty() {
79             if (typeof this._delegate.computedStyleDetailsPanelShowProperty === "function")
80                 this._delegate.computedStyleDetailsPanelShowProperty(property);
81         }
82
83         if (!showSource) {
84             delegateShowProperty.call(this);
85             return;
86         }
87
88         let effectiveProperty = this._nodeStyles.effectivePropertyForName(property.name);
89         if (!effectiveProperty || !effectiveProperty.styleSheetTextRange) {
90             if (!effectiveProperty.relatedShorthandProperty) {
91                 delegateShowProperty.call(this);
92                 return;
93             }
94             effectiveProperty = effectiveProperty.relatedShorthandProperty;
95         }
96
97         let ownerRule = effectiveProperty.ownerStyle.ownerRule;
98         if (!ownerRule) {
99             delegateShowProperty.call(this);
100             return;
101         }
102
103         let sourceCode = ownerRule.sourceCodeLocation.sourceCode;
104         let {startLine, startColumn} = effectiveProperty.styleSheetTextRange;
105         let sourceCodeLocation = sourceCode.createSourceCodeLocation(startLine, startColumn);
106         WebInspector.showSourceCodeLocation(sourceCodeLocation);
107     }
108
109     refresh(significantChange)
110     {
111         // We only need to do a rebuild on significant changes. Other changes are handled
112         // by the sections and text editors themselves.
113         if (!significantChange) {
114             super.refresh();
115             return;
116         }
117
118         this._propertiesTextEditor.style = this.nodeStyles.computedStyle;
119         this._variablesTextEditor.style = this.nodeStyles.computedStyle;
120         this._refreshFlowDetails(this.nodeStyles.node);
121         this._boxModelDiagramRow.nodeStyles = this.nodeStyles;
122
123         super.refresh();
124
125         this._variablesSection.element.classList.toggle("hidden", !this._variablesTextEditor.shownProperties.length);
126     }
127
128     filterDidChange(filterBar)
129     {
130         let filterText = filterBar.filters.text;
131         this._propertiesTextEditor.removeNonMatchingProperties(filterText);
132         this._variablesTextEditor.removeNonMatchingProperties(filterText);
133     }
134
135     // Protected
136
137     initialLayout()
138     {
139         let computedStyleShowAllLabel = document.createElement("label");
140         computedStyleShowAllLabel.textContent = WebInspector.UIString("Show All");
141
142         this._computedStyleShowAllCheckbox = document.createElement("input");
143         this._computedStyleShowAllCheckbox.type = "checkbox";
144         this._computedStyleShowAllCheckbox.checked = this._computedStyleShowAllSetting.value;
145         this._computedStyleShowAllCheckbox.addEventListener("change", this._computedStyleShowAllCheckboxValueChanged.bind(this));
146         computedStyleShowAllLabel.appendChild(this._computedStyleShowAllCheckbox);
147
148         this._propertiesTextEditor = new WebInspector.CSSStyleDeclarationTextEditor(this);
149         this._propertiesTextEditor.propertyVisibilityMode = WebInspector.CSSStyleDeclarationTextEditor.PropertyVisibilityMode.HideVariables;
150         this._propertiesTextEditor.showsImplicitProperties = this._computedStyleShowAllSetting.value;
151         this._propertiesTextEditor.alwaysShowPropertyNames = ["display", "width", "height"];
152         this._propertiesTextEditor.sortProperties = true;
153
154         let propertiesRow = new WebInspector.DetailsSectionRow;
155         let propertiesGroup = new WebInspector.DetailsSectionGroup([propertiesRow]);
156         let propertiesSection = new WebInspector.DetailsSection("computed-style-properties", WebInspector.UIString("Properties"), [propertiesGroup], computedStyleShowAllLabel);
157         propertiesSection.addEventListener(WebInspector.DetailsSection.Event.CollapsedStateChanged, this._handlePropertiesSectionCollapsedStateChanged, this);
158
159         this.addSubview(this._propertiesTextEditor);
160
161         propertiesRow.element.appendChild(this._propertiesTextEditor.element);
162
163         this._variablesTextEditor = new WebInspector.CSSStyleDeclarationTextEditor(this);
164         this._variablesTextEditor.propertyVisibilityMode = WebInspector.CSSStyleDeclarationTextEditor.PropertyVisibilityMode.HideNonVariables;
165         this._variablesTextEditor.sortProperties = true;
166
167         let variablesRow = new WebInspector.DetailsSectionRow;
168         let variablesGroup = new WebInspector.DetailsSectionGroup([variablesRow]);
169         this._variablesSection = new WebInspector.DetailsSection("computed-style-properties", WebInspector.UIString("Variables"), [variablesGroup]);
170         this._variablesSection.addEventListener(WebInspector.DetailsSection.Event.CollapsedStateChanged, this._handleVariablesSectionCollapsedStateChanged, this);
171
172         this.addSubview(this._variablesTextEditor);
173
174         variablesRow.element.appendChild(this._variablesTextEditor.element);
175
176         // Region flow name is used to display the "flow-from" property of the Region Containers.
177         this._regionFlowFragment = document.createElement("span");
178         this._regionFlowFragment.appendChild(document.createElement("img")).className = "icon";
179         this._regionFlowNameLabelValue = this._regionFlowFragment.appendChild(document.createElement("span"));
180
181         let goToRegionFlowButton = this._regionFlowFragment.appendChild(WebInspector.createGoToArrowButton());
182         goToRegionFlowButton.addEventListener("click", this._goToRegionFlowArrowWasClicked.bind(this));
183
184         this._regionFlowNameRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Region Flow"));
185         this._regionFlowNameRow.element.classList.add("content-flow-link");
186
187         // Content flow name is used to display the "flow-into" property of the Content nodes.
188         this._contentFlowFragment = document.createElement("span");
189         this._contentFlowFragment.appendChild(document.createElement("img")).className = "icon";
190         this._contentFlowNameLabelValue = this._contentFlowFragment.appendChild(document.createElement("span"));
191
192         let goToContentFlowButton = this._contentFlowFragment.appendChild(WebInspector.createGoToArrowButton());
193         goToContentFlowButton.addEventListener("click", this._goToContentFlowArrowWasClicked.bind(this));
194
195         this._contentFlowNameRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Content Flow"));
196         this._contentFlowNameRow.element.classList.add("content-flow-link");
197
198         let flowNamesGroup = new WebInspector.DetailsSectionGroup([this._regionFlowNameRow, this._contentFlowNameRow]);
199         this._flowNamesSection = new WebInspector.DetailsSection("content-flow", WebInspector.UIString("Flows"), [flowNamesGroup]);
200
201         this._containerRegionsDataGrid = new WebInspector.DOMTreeDataGrid;
202         this._containerRegionsDataGrid.element.classList.add("no-header");
203
204         let containerRegionsRow = new WebInspector.DetailsSectionDataGridRow(this._containerRegionsDataGrid);
205         let containerRegionsGroup = new WebInspector.DetailsSectionGroup([containerRegionsRow]);
206         this._containerRegionsFlowSection = new WebInspector.DetailsSection("container-regions", WebInspector.UIString("Container Regions"), [containerRegionsGroup]);
207
208         this.element.appendChild(propertiesSection.element);
209         this.element.appendChild(this._variablesSection.element);
210         this.element.appendChild(this._flowNamesSection.element);
211         this.element.appendChild(this._containerRegionsFlowSection.element);
212
213         this._resetFlowDetails();
214
215         this._boxModelDiagramRow = new WebInspector.BoxModelDetailsSectionRow;
216
217         let boxModelGroup = new WebInspector.DetailsSectionGroup([this._boxModelDiagramRow]);
218         let boxModelSection = new WebInspector.DetailsSection("style-box-model", WebInspector.UIString("Box Model"), [boxModelGroup]);
219
220         this.element.appendChild(boxModelSection.element);
221     }
222
223     // Private
224
225     _computedStyleShowAllCheckboxValueChanged(event)
226     {
227         let checked = this._computedStyleShowAllCheckbox.checked;
228         this._computedStyleShowAllSetting.value = checked;
229         this._propertiesTextEditor.showsImplicitProperties = checked;
230         this._propertiesTextEditor.updateLayout();
231     }
232
233     _handlePropertiesSectionCollapsedStateChanged(event)
234     {
235         if (event && event.data && !event.data.collapsed)
236             this._propertiesTextEditor.refresh();
237     }
238
239     _handleVariablesSectionCollapsedStateChanged(event)
240     {
241         if (event && event.data && !event.data.collapsed)
242             this._variablesTextEditor.refresh();
243     }
244
245     _updateFlowNamesSectionVisibility()
246     {
247         this._flowNamesSection.element.classList.toggle("hidden", !this._contentFlow && !this._regionFlow);
248     }
249
250     _resetFlowDetails ()
251     {
252         this.regionFlow = null;
253         this.contentFlow = null;
254         this.containerRegions = null;
255     }
256
257     _refreshFlowDetails(domNode)
258     {
259         this._resetFlowDetails();
260         if (!domNode)
261             return;
262
263         function contentFlowInfoReady(error, flowData)
264         {
265             // Element is not part of any flow.
266             if (error || !flowData) {
267                 this._resetFlowDetails();
268                 return;
269             }
270
271             this.regionFlow = flowData.regionFlow;
272             this.contentFlow = flowData.contentFlow;
273             this.containerRegions = flowData.regions;
274         }
275
276         WebInspector.domTreeManager.getNodeContentFlowInfo(domNode, contentFlowInfoReady.bind(this));
277     }
278
279     _goToRegionFlowArrowWasClicked()
280     {
281         WebInspector.showContentFlowDOMTree(this._regionFlow);
282     }
283
284     _goToContentFlowArrowWasClicked()
285     {
286         WebInspector.showContentFlowDOMTree(this._contentFlow, this.nodeStyles.node);
287     }
288 };
289
290 WebInspector.ComputedStyleDetailsPanel.StyleClassName = "computed";