2 * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 WebInspector.Sidebar = class Sidebar extends WebInspector.Object
28 constructor(element, side, sidebarPanels, role, label, hasNavigationBar)
32 console.assert(!side || side === WebInspector.Sidebar.Sides.Left || side === WebInspector.Sidebar.Sides.Right);
33 this._side = side || WebInspector.Sidebar.Sides.Left;
35 this._element = element || document.createElement("div");
36 this._element.classList.add("sidebar", this._side, WebInspector.Sidebar.CollapsedStyleClassName);
38 this._element.setAttribute("role", role || "group");
40 this._element.setAttribute("aria-label", label);
42 if (hasNavigationBar) {
43 this._element.classList.add("has-navigation-bar");
45 this._navigationBar = new WebInspector.NavigationBar(null, null, "tablist");
46 this._navigationBar.addEventListener(WebInspector.NavigationBar.Event.NavigationItemSelected, this._navigationItemSelected, this);
47 this._element.appendChild(this._navigationBar.element);
50 this._resizer = new WebInspector.Resizer(WebInspector.Resizer.RuleOrientation.Vertical, this);
51 this._element.insertBefore(this._resizer.element, this._element.firstChild);
53 this._sidebarPanels = [];
56 for (var i = 0; i < sidebarPanels.length; ++i)
57 this.addSidebarPanel(sidebarPanels[i]);
63 addSidebarPanel(sidebarPanel)
65 console.assert(sidebarPanel instanceof WebInspector.SidebarPanel);
66 if (!(sidebarPanel instanceof WebInspector.SidebarPanel))
69 console.assert(!sidebarPanel.parentSidebar);
70 if (sidebarPanel.parentSidebar)
73 sidebarPanel._parentSidebar = this;
75 this._sidebarPanels.push(sidebarPanel);
76 this._element.appendChild(sidebarPanel.element);
78 if (this._navigationBar) {
79 console.assert(sidebarPanel.navigationItem);
80 this._navigationBar.addNavigationItem(sidebarPanel.navigationItem);
88 removeSidebarPanel(sidebarPanelOrIdentifierOrIndex)
90 var sidebarPanel = this.findSidebarPanel(sidebarPanelOrIdentifierOrIndex);
94 sidebarPanel.willRemove();
96 sidebarPanel._parentSidebar = null;
98 if (this._selectedSidebarPanel === sidebarPanel) {
99 var index = this._sidebarPanels.indexOf(sidebarPanel);
100 this.selectedSidebarPanel = this._sidebarPanels[index - 1] || this._sidebarPanels[index + 1] || null;
103 this._sidebarPanels.remove(sidebarPanel);
104 this._element.removeChild(sidebarPanel.element);
106 if (this._navigationBar) {
107 console.assert(sidebarPanel.navigationItem);
108 this._navigationBar.removeNavigationItem(sidebarPanel.navigationItem);
111 sidebarPanel.removed();
116 get selectedSidebarPanel()
118 return this._selectedSidebarPanel || null;
121 set selectedSidebarPanel(sidebarPanelOrIdentifierOrIndex)
123 var sidebarPanel = this.findSidebarPanel(sidebarPanelOrIdentifierOrIndex);
124 if (this._selectedSidebarPanel === sidebarPanel)
127 if (this._selectedSidebarPanel) {
128 var wasVisible = this._selectedSidebarPanel.visible;
130 this._selectedSidebarPanel.selected = false;
133 this._selectedSidebarPanel.hidden();
134 this._selectedSidebarPanel.visibilityDidChange();
138 this._selectedSidebarPanel = sidebarPanel || null;
140 if (this._navigationBar)
141 this._navigationBar.selectedNavigationItem = sidebarPanel ? sidebarPanel.navigationItem : null;
143 if (this._selectedSidebarPanel) {
144 this._selectedSidebarPanel.selected = true;
146 if (this._selectedSidebarPanel.visible) {
147 this._selectedSidebarPanel.shown();
148 this._selectedSidebarPanel.visibilityDidChange();
152 this.dispatchEventToListeners(WebInspector.Sidebar.Event.SidebarPanelSelected);
157 if (this._navigationBar)
158 return Math.max(WebInspector.Sidebar.AbsoluteMinimumWidth, this._navigationBar.minimumWidth);
159 return WebInspector.Sidebar.AbsoluteMinimumWidth;
164 // FIXME: This is kind of arbitrary and ideally would be a more complex calculation based on the
165 // available space for the sibling elements.
166 return Math.round(window.innerWidth / 3);
171 return this._element.offsetWidth;
176 if (newWidth === this.width)
179 newWidth = Math.max(this.minimumWidth, Math.min(newWidth, this.maximumWidth));
181 this._element.style.width = newWidth + "px";
183 if (!this.collapsed && this._navigationBar)
184 this._navigationBar.updateLayout();
186 if (!this.collapsed && this._selectedSidebarPanel)
187 this._selectedSidebarPanel.widthDidChange();
189 this.dispatchEventToListeners(WebInspector.Sidebar.Event.WidthDidChange);
194 return this._element.classList.contains(WebInspector.Sidebar.CollapsedStyleClassName);
199 if (flag === this.collapsed)
203 this._element.classList.add(WebInspector.Sidebar.CollapsedStyleClassName);
205 this._element.classList.remove(WebInspector.Sidebar.CollapsedStyleClassName);
207 if (this._navigationBar)
208 this._navigationBar.updateLayout();
211 if (this._selectedSidebarPanel) {
212 if (this._selectedSidebarPanel.visible)
213 this._selectedSidebarPanel.shown();
215 this._selectedSidebarPanel.hidden();
217 this._selectedSidebarPanel.visibilityDidChange();
219 this._selectedSidebarPanel.widthDidChange();
222 this.dispatchEventToListeners(WebInspector.Sidebar.Event.CollapsedStateDidChange);
223 this.dispatchEventToListeners(WebInspector.Sidebar.Event.WidthDidChange);
228 return this._sidebarPanels;
233 return this._element;
241 findSidebarPanel(sidebarPanelOrIdentifierOrIndex)
243 var sidebarPanel = null;
245 if (sidebarPanelOrIdentifierOrIndex instanceof WebInspector.SidebarPanel) {
246 if (this._sidebarPanels.includes(sidebarPanelOrIdentifierOrIndex))
247 sidebarPanel = sidebarPanelOrIdentifierOrIndex;
248 } else if (typeof sidebarPanelOrIdentifierOrIndex === "number") {
249 sidebarPanel = this._sidebarPanels[sidebarPanelOrIdentifierOrIndex];
250 } else if (typeof sidebarPanelOrIdentifierOrIndex === "string") {
251 for (var i = 0; i < this._sidebarPanels.length; ++i) {
252 if (this._sidebarPanels[i].identifier === sidebarPanelOrIdentifierOrIndex) {
253 sidebarPanel = this._sidebarPanels[i];
264 resizerDragStarted(resizer)
266 this._widthBeforeResize = this.width;
269 resizerDragging(resizer, positionDelta)
271 if (this._side === WebInspector.Sidebar.Sides.Left)
274 var newWidth = positionDelta + this._widthBeforeResize;
275 this.width = newWidth;
276 this.collapsed = (newWidth < (this.minimumWidth / 2));
279 resizerDragEnded(resizer)
281 delete this._widthBeforeResize;
286 _navigationItemSelected(event)
288 this.selectedSidebarPanel = event.target.selectedNavigationItem ? event.target.selectedNavigationItem.identifier : null;
292 WebInspector.Sidebar.CollapsedStyleClassName = "collapsed";
293 WebInspector.Sidebar.AbsoluteMinimumWidth = 200;
295 WebInspector.Sidebar.Sides = {
300 WebInspector.Sidebar.Event = {
301 SidebarPanelSelected: "sidebar-panel-selected",
302 CollapsedStateDidChange: "sidebar-collapsed-state-did-change",
303 WidthDidChange: "sidebar-width-did-change",