c9fcb2f515c5928e1aaeb46e124737aa7fd3576d
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / CSSStyleDetailsSidebarPanel.js
1 /*
2  * Copyright (C) 2013 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.CSSStyleDetailsSidebarPanel = function()
27 {
28     WebInspector.DOMDetailsSidebarPanel.call(this, "css-style", WebInspector.UIString("Styles"), WebInspector.UIString("Style"), "Images/NavigationItemBrushAndRuler.svg", "4");
29
30     this._selectedPanel = null;
31
32     this._navigationBar = new WebInspector.NavigationBar(null, null, "tablist");
33     this._navigationBar.addEventListener(WebInspector.NavigationBar.Event.NavigationItemSelected, this._navigationItemSelected, this);
34     this.element.appendChild(this._navigationBar.element);
35
36     this._contentElement = document.createElement("div");
37     this._contentElement.className = WebInspector.CSSStyleDetailsSidebarPanel.ContentStyleClassName;
38
39     this._forcedPseudoClassCheckboxes = {};
40
41     if (WebInspector.cssStyleManager.canForcePseudoClasses()) {
42         this._forcedPseudoClassContainer = document.createElement("div");
43         this._forcedPseudoClassContainer.className = WebInspector.CSSStyleDetailsSidebarPanel.PseudoClassesElementStyleClassName;
44
45         var groupElement = null;
46
47         WebInspector.CSSStyleManager.ForceablePseudoClasses.forEach(function(pseudoClass) {
48             // We don't localize the label since it is a CSS pseudo-class from the CSS standard.
49             var label = pseudoClass.capitalize();
50
51             var labelElement = document.createElement("label");
52
53             var checkboxElement = document.createElement("input");
54             checkboxElement.addEventListener("change", this._forcedPseudoClassCheckboxChanged.bind(this, pseudoClass));
55             checkboxElement.type = "checkbox";
56
57             this._forcedPseudoClassCheckboxes[pseudoClass] = checkboxElement;
58
59             labelElement.appendChild(checkboxElement);
60             labelElement.appendChild(document.createTextNode(label));
61
62             if (!groupElement || groupElement.children.length === 2) {
63                 groupElement = document.createElement("div");
64                 groupElement.className = WebInspector.CSSStyleDetailsSidebarPanel.PseudoClassesGroupElementStyleClassName;
65                 this._forcedPseudoClassContainer.appendChild(groupElement);
66             }
67
68             groupElement.appendChild(labelElement);
69         }, this);
70
71         this._contentElement.appendChild(this._forcedPseudoClassContainer);
72     }
73
74     this.element.appendChild(this._contentElement);
75
76     this._computedStyleDetailsPanel = new WebInspector.ComputedStyleDetailsPanel;
77     this._rulesStyleDetailsPanel = new WebInspector.RulesStyleDetailsPanel;
78     this._metricsStyleDetailsPanel = new WebInspector.MetricsStyleDetailsPanel;
79
80     this._panels = [this._computedStyleDetailsPanel, this._rulesStyleDetailsPanel, this._metricsStyleDetailsPanel];
81
82     this._navigationBar.addNavigationItem(this._computedStyleDetailsPanel.navigationItem);
83     this._navigationBar.addNavigationItem(this._rulesStyleDetailsPanel.navigationItem);
84     this._navigationBar.addNavigationItem(this._metricsStyleDetailsPanel.navigationItem);
85
86     this._lastSelectedSectionSetting = new WebInspector.Setting("last-selected-style-details-panel", this._rulesStyleDetailsPanel.navigationItem.identifier);
87
88     // This will cause the selected panel to be set in _navigationItemSelected.
89     this._navigationBar.selectedNavigationItem = this._lastSelectedSectionSetting.value;
90 };
91
92 WebInspector.CSSStyleDetailsSidebarPanel.ContentStyleClassName = "content";
93 WebInspector.CSSStyleDetailsSidebarPanel.PseudoClassesElementStyleClassName = "pseudo-classes";
94 WebInspector.CSSStyleDetailsSidebarPanel.PseudoClassesGroupElementStyleClassName = "group";
95 WebInspector.CSSStyleDetailsSidebarPanel.NoForcedPseudoClassesScrollOffset = 38; // Default height of the forced pseudo classes container. Updated in widthDidChange.
96
97 WebInspector.CSSStyleDetailsSidebarPanel.prototype = {
98     constructor: WebInspector.CSSStyleDetailsSidebarPanel,
99
100     // Public
101
102     supportsDOMNode: function(nodeToInspect)
103     {
104         return nodeToInspect.nodeType() === Node.ELEMENT_NODE;
105     },
106
107     refresh: function()
108     {
109         var domNode = this.domNode;
110         if (!domNode)
111             return;
112
113         this._contentElement.scrollTop = this._initialScrollOffset;
114
115         for (var i = 0; i < this._panels.length; ++i) {
116             delete this._panels[i].element._savedScrollTop;
117             this._panels[i].markAsNeedsRefresh(domNode);
118         }
119
120         this._updatePseudoClassCheckboxes();
121     },
122
123     visibilityDidChange: function()
124     {
125         WebInspector.SidebarPanel.prototype.visibilityDidChange.call(this);
126
127         if (!this._selectedPanel)
128             return;
129
130         if (!this.visible) {
131             this._selectedPanel.hidden();
132             return;
133         }
134
135         this._navigationBar.updateLayout();
136
137         this._updateNoForcedPseudoClassesScrollOffset();
138
139         this._selectedPanel.shown();
140         this._selectedPanel.markAsNeedsRefresh(this.domNode);
141     },
142
143     widthDidChange: function()
144     {
145         this._updateNoForcedPseudoClassesScrollOffset();
146
147         if (this._selectedPanel)
148             this._selectedPanel.widthDidChange();
149     },
150
151     // Protected
152
153     addEventListeners: function()
154     {
155         this.domNode.addEventListener(WebInspector.DOMNode.Event.EnabledPseudoClassesChanged, this._updatePseudoClassCheckboxes, this);
156     },
157
158     removeEventListeners: function()
159     {
160         this.domNode.removeEventListener(null, null, this);
161     },
162
163     // Private
164
165     get _initialScrollOffset()
166     {
167         if (!WebInspector.cssStyleManager.canForcePseudoClasses())
168             return 0;
169         return this.domNode && this.domNode.enabledPseudoClasses.length ? 0 : WebInspector.CSSStyleDetailsSidebarPanel.NoForcedPseudoClassesScrollOffset;
170     },
171
172     _updateNoForcedPseudoClassesScrollOffset: function()
173     {
174         if (this._forcedPseudoClassContainer)
175             WebInspector.CSSStyleDetailsSidebarPanel.NoForcedPseudoClassesScrollOffset = this._forcedPseudoClassContainer.offsetHeight;
176     },
177
178     _navigationItemSelected: function(event)
179     {
180         console.assert(event.target.selectedNavigationItem);
181         if (!event.target.selectedNavigationItem)
182             return;
183
184         var selectedNavigationItem = event.target.selectedNavigationItem;
185
186         var selectedPanel = null;
187         for (var i = 0; i < this._panels.length; ++i) {
188             if (this._panels[i].navigationItem !== selectedNavigationItem)
189                 continue;
190             selectedPanel = this._panels[i];
191             break;
192         }
193
194         console.assert(selectedPanel);
195
196         if (this._selectedPanel) {
197             this._selectedPanel.hidden();
198             this._selectedPanel.element._savedScrollTop = this._contentElement.scrollTop;
199             this._selectedPanel.element.remove();
200         }
201
202         this._selectedPanel = selectedPanel;
203
204         if (this._selectedPanel) {
205             this._contentElement.appendChild(this._selectedPanel.element);
206
207             if (typeof this._selectedPanel.element._savedScrollTop === "number")
208                 this._contentElement.scrollTop = this._selectedPanel.element._savedScrollTop;
209             else
210                 this._contentElement.scrollTop = this._initialScrollOffset;
211
212             this._selectedPanel.shown();
213         }
214
215         this._lastSelectedSectionSetting.value = selectedNavigationItem.identifier;
216     },
217
218     _forcedPseudoClassCheckboxChanged: function(pseudoClass, event)
219     {
220         if (!this.domNode)
221             return;
222
223         this.domNode.setPseudoClassEnabled(pseudoClass, event.target.checked);
224     },
225
226     _updatePseudoClassCheckboxes: function()
227     {
228         if (!this.domNode)
229             return;
230
231         var enabledPseudoClasses = this.domNode.enabledPseudoClasses;
232
233         for (var pseudoClass in this._forcedPseudoClassCheckboxes) {
234             var checkboxElement = this._forcedPseudoClassCheckboxes[pseudoClass];
235             checkboxElement.checked = enabledPseudoClasses.contains(pseudoClass);
236         }
237     }
238 };
239
240 WebInspector.CSSStyleDetailsSidebarPanel.prototype.__proto__ = WebInspector.DOMDetailsSidebarPanel.prototype;