/* * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2007 Matt Lilek (pewtermoose@gmail.com). * Copyright (C) 2009 Joseph Pecoraro * Copyright (C) 2011 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @constructor */ WebInspector.Toolbar = function() { this.element = document.getElementById("toolbar"); WebInspector.installDragHandle(this.element, this._toolbarDragStart.bind(this), this._toolbarDrag.bind(this), this._toolbarDragEnd.bind(this), "default"); this._dropdownButton = document.getElementById("toolbar-dropdown-arrow"); this._dropdownButton.addEventListener("click", this._toggleDropdown.bind(this), false); this._panelsMenuButton = document.getElementById("toolbar-panels-menu"); if (this._isToolbarCustomizable()) { this._panelsMenuButton.addEventListener("mousedown", this._togglePanelsMenu.bind(this), false); this._panelsMenuButton.removeStyleClass("hidden"); } document.getElementById("close-button-left").addEventListener("click", this._onClose, true); document.getElementById("close-button-right").addEventListener("click", this._onClose, true); this._panelDescriptors = []; } WebInspector.Toolbar.prototype = { resize: function() { this._updateDropdownButtonAndHideDropdown(); }, /** * @param {!WebInspector.PanelDescriptor} panelDescriptor */ addPanel: function(panelDescriptor) { this._panelDescriptors.push(panelDescriptor); panelDescriptor._toolbarElement = this._createPanelToolbarItem(panelDescriptor); if (!this._isToolbarCustomizable() || this._isPanelVisible(panelDescriptor.name())) this.element.insertBefore(panelDescriptor._toolbarElement, this._panelInsertLocation(panelDescriptor)); this._updatePanelsMenuState(); this.resize(); }, /** * @param {!WebInspector.PanelDescriptor} panelDescriptor * @return {Element} */ _panelInsertLocation: function(panelDescriptor) { if (!this._isToolbarCustomizable()) return null; if (this._isDefaultPanel(panelDescriptor.name())) return this._firstNonDefaultPanel || null; if (!this._firstNonDefaultPanel) this._firstNonDefaultPanel = panelDescriptor._toolbarElement; return null; }, /** * @param {!string} name * @return {boolean} */ _isDefaultPanel: function(name) { var defaultPanels = { "elements": true, "resources": true, "scripts": true, "console": true, "network": true, "timeline": true, }; return !!defaultPanels[name]; }, /** * @param {!string} name * @return {boolean} */ _isPanelVisibleByDefault: function(name) { var visible = { "elements": true, "console": true, "network": true, "scripts": true, "timeline": true, "profiles": true, "cpu-profiler": true, "heap-profiler": true, "audits": true, "resources": true, }; return !!visible[name]; }, /** * @return {boolean} */ _isToolbarCustomizable: function() { return WebInspector.experimentsSettings.customizableToolbar.isEnabled(); }, /** * @param {!string} name * @return {boolean} */ _isPanelVisible: function(name) { if (!this._isToolbarCustomizable()) return true; var visiblePanels = WebInspector.settings.visiblePanels.get(); return visiblePanels.hasOwnProperty(name) ? visiblePanels[name] : this._isPanelVisibleByDefault(name); }, /** * @param {!string} name * @param {boolean} visible */ _setPanelVisible: function(name, visible) { var visiblePanels = WebInspector.settings.visiblePanels.get(); visiblePanels[name] = visible; WebInspector.settings.visiblePanels.set(visiblePanels); }, /** * @param {!WebInspector.PanelDescriptor} panelDescriptor */ _hidePanel: function(panelDescriptor) { if (!this._isPanelVisible(panelDescriptor.name())) return; var switchToSibling = panelDescriptor._toolbarElement.nextSibling; if (!switchToSibling || !switchToSibling.classList.contains("toggleable")) switchToSibling = panelDescriptor._toolbarElement.previousSibling; if (!switchToSibling || !switchToSibling.classList || !switchToSibling.classList.contains("toggleable")) return; this._setPanelVisible(panelDescriptor.name(), false); this.element.removeChild(panelDescriptor._toolbarElement); if (WebInspector.inspectorView.currentPanel().name === panelDescriptor.name()) { for (var i = 0; i < this._panelDescriptors.length; ++i) { var descr = this._panelDescriptors[i]; if (descr._toolbarElement === switchToSibling) { WebInspector.showPanel(descr.name()); break; } } } this._updatePanelsMenuState(); this.resize(); }, _updatePanelsMenuState: function() { if (this._panelDescriptors.every(function (descr) { return this._isPanelVisible(descr.name()); }, this) && this._allItemsFitOntoToolbar()) document.getElementById("toolbar-panels-menu").addStyleClass("disabled"); else document.getElementById("toolbar-panels-menu").removeStyleClass("disabled"); }, /** * @return {boolean} */ _allItemsFitOntoToolbar: function() { var toolbarItems = this.element.querySelectorAll(".toolbar-item.toggleable"); return toolbarItems.length === 0 || this.element.scrollHeight < toolbarItems[0].offsetHeight * 2; }, /** * @param {!WebInspector.PanelDescriptor} panelDescriptor */ _showPanel: function(panelDescriptor) { if (this._isPanelVisible(panelDescriptor.name())) return; this.element.appendChild(panelDescriptor._toolbarElement); panelDescriptor._toolbarElement.removeStyleClass("hidden"); this._setPanelVisible(panelDescriptor.name(), true); this._updatePanelsMenuState(); this.resize(); }, /** * @param {WebInspector.PanelDescriptor} panelDescriptor * @param {boolean=} noCloseButton * @return {Element} */ _createPanelToolbarItem: function(panelDescriptor, noCloseButton) { var toolbarItem = document.createElement("button"); toolbarItem.className = "toolbar-item toggleable"; toolbarItem.panelDescriptor = panelDescriptor; toolbarItem.addStyleClass(panelDescriptor.name()); /** * @param {Event} event */ function onContextMenuEvent(event) { var contextMenu = new WebInspector.ContextMenu(event); contextMenu.appendItem(WebInspector.UIString("Close"), this._hidePanel.bind(this, panelDescriptor)); contextMenu.show(); } if (!this._isDefaultPanel(panelDescriptor.name())) toolbarItem.addEventListener("contextmenu", onContextMenuEvent.bind(this), true); function onToolbarItemClicked() { this._showPanel(panelDescriptor); this._updateDropdownButtonAndHideDropdown(); WebInspector.inspectorView.setCurrentPanel(panelDescriptor.panel()); } toolbarItem.addEventListener("click", onToolbarItemClicked.bind(this), false); function onToolbarItemCloseButtonClicked(event) { event.stopPropagation(); this._hidePanel(panelDescriptor); } function panelSelected() { if (WebInspector.inspectorView.currentPanel() && panelDescriptor.name() === WebInspector.inspectorView.currentPanel().name) toolbarItem.addStyleClass("toggled-on"); else toolbarItem.removeStyleClass("toggled-on"); } WebInspector.inspectorView.addEventListener(WebInspector.InspectorView.Events.PanelSelected, panelSelected); toolbarItem.createChild("div", "toolbar-label").textContent = panelDescriptor.title(); if (this._isToolbarCustomizable() && !this._isDefaultPanel(panelDescriptor.name()) && !noCloseButton) { var closeButton = toolbarItem.createChild("div", "close-button"); closeButton.addEventListener("click", onToolbarItemCloseButtonClicked.bind(this), false); } panelSelected(); return toolbarItem; }, /** * @return {boolean} */ _isDockedToBottom: function() { return !!WebInspector.dockController && WebInspector.dockController.dockSide() == WebInspector.DockController.State.DockedToBottom; }, /** * @return {boolean} */ _isUndocked: function() { return !!WebInspector.dockController && WebInspector.dockController.dockSide() == WebInspector.DockController.State.Undocked; }, /** * @return {boolean} */ _toolbarDragStart: function(event) { if (this._isUndocked()) return false; var target = event.target; if (target.hasStyleClass("toolbar-item") && target.hasStyleClass("toggleable")) return false; if (target !== this.element && !target.hasStyleClass("toolbar-item")) return false; this._lastScreenX = event.screenX; this._lastScreenY = event.screenY; this._lastHeightDuringDrag = window.innerHeight; this._startDistanceToRight = window.innerWidth - event.clientX; this._startDinstanceToBottom = window.innerHeight - event.clientY; return true; }, _toolbarDragEnd: function(event) { // We may not get the drag event at the end. // Apply last changes manually. this._toolbarDrag(event); delete this._lastScreenX; delete this._lastScreenY; delete this._lastHeightDuringDrag; delete this._startDistanceToRight; delete this._startDinstanceToBottom; }, _toolbarDrag: function(event) { event.preventDefault(); if (this._isUndocked()) return this._toolbarDragMoveWindow(event); return this._toolbarDragChangeDocking(event); }, _toolbarDragMoveWindow: function(event) { var x = event.screenX - this._lastScreenX; var y = event.screenY - this._lastScreenY; this._lastScreenX = event.screenX; this._lastScreenY = event.screenY; InspectorFrontendHost.moveWindowBy(x, y); }, _toolbarDragChangeDocking: function(event) { if (this._isDockedToBottom()) { var distanceToRight = window.innerWidth - event.clientX; if (distanceToRight < this._startDistanceToRight * 2 / 3) { InspectorFrontendHost.requestSetDockSide(WebInspector.DockController.State.DockedToRight); return true; } } else { var distanceToBottom = window.innerHeight - event.clientY; if (distanceToBottom < this._startDinstanceToBottom * 2 / 3) { InspectorFrontendHost.requestSetDockSide(WebInspector.DockController.State.DockedToBottom); return true; } } }, _onClose: function() { WebInspector.close(); }, _setDropdownVisible: function(visible) { if (!this._dropdown) { if (!visible) return; this._dropdown = new WebInspector.ToolbarDropdown(this); } if (visible) this._dropdown.show(); else this._dropdown.hide(); }, _toggleDropdown: function() { this._setDropdownVisible(!this._dropdown || !this._dropdown.visible); }, _togglePanelsMenu: function(event) { function activatePanel(panelDescriptor) { this._showPanel(panelDescriptor); WebInspector.showPanel(panelDescriptor.name()); } var contextMenu = new WebInspector.ContextMenu(event); var currentPanelName = WebInspector.inspectorView.currentPanel().name; var toolbarItems = this.element.querySelectorAll(".toolbar-item.toggleable"); for (var i = 0; i < toolbarItems.length; ++i) { if (toolbarItems[i].offsetTop >= toolbarItems[0].offsetHeight) { var descr = toolbarItems[i].panelDescriptor; if (descr.name() === currentPanelName) contextMenu.appendCheckboxItem(descr.title(), activatePanel.bind(this, descr), true); else contextMenu.appendItem(descr.title(), activatePanel.bind(this, descr)); } } contextMenu.appendSeparator(); for (var i = 0; i < this._panelDescriptors.length; ++i) { var descr = this._panelDescriptors[i]; if (this._isPanelVisible(descr.name())) continue; contextMenu.appendItem(descr.title(), activatePanel.bind(this, descr)); } contextMenu.showSoftMenu(); }, _updateDropdownButtonAndHideDropdown: function() { WebInspector.invokeOnceAfterBatchUpdate(this, this._innerUpdateDropdownButtonAndHideDropdown); }, _innerUpdateDropdownButtonAndHideDropdown: function() { if (this._isToolbarCustomizable()) { this._updatePanelsMenuState(); return; } this._setDropdownVisible(false); if (this.element.scrollHeight > this.element.offsetHeight) this._dropdownButton.removeStyleClass("hidden"); else this._dropdownButton.addStyleClass("hidden"); } } /** * @constructor * @param {WebInspector.Toolbar} toolbar */ WebInspector.ToolbarDropdown = function(toolbar) { this._toolbar = toolbar; this._arrow = document.getElementById("toolbar-dropdown-arrow"); this.element = document.createElement("div"); this.element.id = "toolbar-dropdown"; this.element.className = "toolbar-small"; this._contentElement = this.element.createChild("div", "scrollable-content"); this._contentElement.tabIndex = 0; this._contentElement.addEventListener("keydown", this._onKeyDown.bind(this), true); } WebInspector.ToolbarDropdown.prototype = { show: function() { if (this.visible) return; var style = this.element.style; this._populate(); var top = this._arrow.totalOffsetTop() + this._arrow.clientHeight; this._arrow.addStyleClass("dropdown-visible"); this.element.style.top = top + "px"; this.element.style.right = window.innerWidth - this._arrow.totalOffsetLeft() - this._arrow.clientWidth + "px"; this._contentElement.style.maxHeight = window.innerHeight - top - 20 + "px"; this._toolbar.element.appendChild(this.element); }, hide: function() { if (!this.visible) return; this._arrow.removeStyleClass("dropdown-visible"); this.element.remove(); this._contentElement.removeChildren(); }, get visible() { return !!this.element.parentNode; }, _populate: function() { var toolbarItems = this._toolbar.element.querySelectorAll(".toolbar-item.toggleable"); var needsSeparator = false; for (var i = 0; i < toolbarItems.length; ++i) { if (toolbarItems[i].offsetTop >= toolbarItems[0].offsetHeight) { this._contentElement.appendChild(this._toolbar._createPanelToolbarItem(toolbarItems[i].panelDescriptor, true)); needsSeparator = true; } } var panelDescriptors = this._toolbar._panelDescriptors; for (var i = 0; i < panelDescriptors.length; ++i) { var descr = panelDescriptors[i]; if (this._toolbar._isPanelVisible(descr.name())) continue; if (needsSeparator) { this._contentElement.createChild("div", "toolbar-items-separator"); needsSeparator = false; } this._contentElement.appendChild(this._toolbar._createPanelToolbarItem(descr, true)); } }, _onKeyDown: function(event) { if (event.keyCode !== WebInspector.KeyboardShortcut.Keys.Esc.code) return; event.consume(); this.hide(); } } /** * @type {?WebInspector.Toolbar} */ WebInspector.toolbar = null;