2 * Copyright (C) 2007, 2008 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
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 WebInspector.Panel = function(name)
31 WebInspector.View.call(this);
33 this.element.addStyleClass("panel");
34 this.element.addStyleClass(name);
35 this._panelName = name;
37 WebInspector.settings.installApplicationSetting(this._sidebarWidthSettingName(), undefined);
40 // Should by in sync with style declarations.
41 WebInspector.Panel.counterRightMargin = 25;
43 WebInspector.Panel.prototype = {
46 if (this._toolbarItem)
47 return this._toolbarItem;
49 this._toolbarItem = WebInspector.Toolbar.createPanelToolbarItem(this);
50 return this._toolbarItem;
55 return this._panelName;
60 WebInspector.View.prototype.show.call(this);
62 var statusBarItems = this.statusBarItems;
64 this._statusBarItemContainer = document.createElement("div");
65 for (var i = 0; i < statusBarItems.length; ++i)
66 this._statusBarItemContainer.appendChild(statusBarItems[i]);
67 document.getElementById("main-status-bar").appendChild(this._statusBarItemContainer);
70 if ("_toolbarItem" in this)
71 this._toolbarItem.addStyleClass("toggled-on");
73 WebInspector.currentFocusElement = this.defaultFocusedElement;
75 this.restoreSidebarWidth();
76 this._restoreScrollPositions();
81 this._storeScrollPositions();
82 WebInspector.View.prototype.hide.call(this);
84 if (this._statusBarItemContainer && this._statusBarItemContainer.parentNode)
85 this._statusBarItemContainer.parentNode.removeChild(this._statusBarItemContainer);
86 delete this._statusBarItemContainer;
87 if ("_toolbarItem" in this)
88 this._toolbarItem.removeStyleClass("toggled-on");
91 get defaultFocusedElement()
93 return this.sidebarTreeElement || this.element;
98 if (!this.element.parentNode)
99 document.getElementById("main-panels").appendChild(this.element);
102 searchCanceled: function()
104 if (this._searchResults) {
105 for (var i = 0; i < this._searchResults.length; ++i) {
106 var view = this._searchResults[i];
107 if (view.searchCanceled)
108 view.searchCanceled();
109 delete view.currentQuery;
113 WebInspector.searchController.updateSearchMatchesCount(0, this);
115 if (this._currentSearchChunkIntervalIdentifier) {
116 clearInterval(this._currentSearchChunkIntervalIdentifier);
117 delete this._currentSearchChunkIntervalIdentifier;
120 this._totalSearchMatches = 0;
121 this._currentSearchResultIndex = 0;
122 this._searchResults = [];
125 performSearch: function(query)
127 // Call searchCanceled since it will reset everything we need before doing a new search.
128 this.searchCanceled(true);
130 var searchableViews = this.searchableViews;
131 if (!searchableViews || !searchableViews.length)
134 var parentElement = this.viewsContainerElement;
135 var visibleView = this.visibleView;
136 var sortFuction = this.searchResultsSortFunction;
138 var matchesCountUpdateTimeout = null;
140 function updateMatchesCount()
142 WebInspector.searchController.updateSearchMatchesCount(this._totalSearchMatches, this);
143 matchesCountUpdateTimeout = null;
146 function updateMatchesCountSoon()
148 if (matchesCountUpdateTimeout)
150 // Update the matches count every half-second so it doesn't feel twitchy.
151 matchesCountUpdateTimeout = setTimeout(updateMatchesCount.bind(this), 500);
154 function finishedCallback(view, searchMatches)
159 this._totalSearchMatches += searchMatches;
160 this._searchResults.push(view);
163 this._searchResults.sort(sortFuction);
165 if (this.searchMatchFound)
166 this.searchMatchFound(view, searchMatches);
168 updateMatchesCountSoon.call(this);
170 if (view === visibleView)
171 view.jumpToFirstSearchResult();
176 var boundFinishedCallback = finishedCallback.bind(this);
177 var chunkIntervalIdentifier = null;
179 // Split up the work into chunks so we don't block the
180 // UI thread while processing.
182 function processChunk()
184 var view = searchableViews[i];
186 if (++i >= searchableViews.length) {
187 if (panel._currentSearchChunkIntervalIdentifier === chunkIntervalIdentifier)
188 delete panel._currentSearchChunkIntervalIdentifier;
189 clearInterval(chunkIntervalIdentifier);
195 if (view.element.parentNode !== parentElement && view.element.parentNode && parentElement)
198 view.currentQuery = query;
199 view.performSearch(query, boundFinishedCallback);
204 chunkIntervalIdentifier = setInterval(processChunk, 25);
205 this._currentSearchChunkIntervalIdentifier = chunkIntervalIdentifier;
208 jumpToNextSearchResult: function()
210 if (!this.showView || !this._searchResults || !this._searchResults.length)
213 var showFirstResult = false;
215 this._currentSearchResultIndex = this._searchResults.indexOf(this.visibleView);
216 if (this._currentSearchResultIndex === -1) {
217 this._currentSearchResultIndex = 0;
218 showFirstResult = true;
221 var currentView = this._searchResults[this._currentSearchResultIndex];
223 if (currentView.showingLastSearchResult()) {
224 if (++this._currentSearchResultIndex >= this._searchResults.length)
225 this._currentSearchResultIndex = 0;
226 currentView = this._searchResults[this._currentSearchResultIndex];
227 showFirstResult = true;
230 if (currentView !== this.visibleView) {
231 this.showView(currentView);
232 WebInspector.focusSearchField();
236 currentView.jumpToFirstSearchResult();
238 currentView.jumpToNextSearchResult();
241 jumpToPreviousSearchResult: function()
243 if (!this.showView || !this._searchResults || !this._searchResults.length)
246 var showLastResult = false;
248 this._currentSearchResultIndex = this._searchResults.indexOf(this.visibleView);
249 if (this._currentSearchResultIndex === -1) {
250 this._currentSearchResultIndex = 0;
251 showLastResult = true;
254 var currentView = this._searchResults[this._currentSearchResultIndex];
256 if (currentView.showingFirstSearchResult()) {
257 if (--this._currentSearchResultIndex < 0)
258 this._currentSearchResultIndex = (this._searchResults.length - 1);
259 currentView = this._searchResults[this._currentSearchResultIndex];
260 showLastResult = true;
263 if (currentView !== this.visibleView) {
264 this.showView(currentView);
265 WebInspector.focusSearchField();
269 currentView.jumpToLastSearchResult();
271 currentView.jumpToPreviousSearchResult();
274 createSidebar: function(parentElement, resizerParentElement)
276 if (this.sidebarElement)
280 parentElement = this.element;
282 if (!resizerParentElement)
283 resizerParentElement = parentElement;
285 this.sidebarElement = document.createElement("div");
286 this.sidebarElement.className = "sidebar";
287 parentElement.appendChild(this.sidebarElement);
289 this.sidebarResizeElement = document.createElement("div");
290 this.sidebarResizeElement.className = "sidebar-resizer-vertical";
291 this.sidebarResizeElement.addEventListener("mousedown", this._startSidebarDragging.bind(this), false);
292 resizerParentElement.appendChild(this.sidebarResizeElement);
294 this.sidebarTreeElement = document.createElement("ol");
295 this.sidebarTreeElement.className = "sidebar-tree";
296 this.sidebarElement.appendChild(this.sidebarTreeElement);
298 this.sidebarTree = new TreeOutline(this.sidebarTreeElement);
299 this.sidebarTree.panel = this;
302 _sidebarWidthSettingName: function()
304 return this._panelName + "SidebarWidth";
307 _startSidebarDragging: function(event)
309 WebInspector.elementDragStart(this.sidebarResizeElement, this._sidebarDragging.bind(this), this._endSidebarDragging.bind(this), event, "col-resize");
312 _sidebarDragging: function(event)
314 this.updateSidebarWidth(event.pageX);
316 event.preventDefault();
319 _endSidebarDragging: function(event)
321 WebInspector.elementDragEnd(event);
322 this.saveSidebarWidth();
325 updateSidebarWidth: function(width)
327 if (!this.sidebarElement)
330 if (this.sidebarElement.offsetWidth <= 0) {
331 // The stylesheet hasn't loaded yet or the window is closed,
332 // so we can't calculate what is need. Return early.
336 if (!("_currentSidebarWidth" in this))
337 this._currentSidebarWidth = this.sidebarElement.offsetWidth;
339 if (typeof width === "undefined")
340 width = this._currentSidebarWidth;
342 width = Number.constrain(width, Preferences.minSidebarWidth, window.innerWidth / 2);
344 this._currentSidebarWidth = width;
345 this.setSidebarWidth(width);
347 this.updateMainViewWidth(width);
350 setSidebarWidth: function(width)
352 this.sidebarElement.style.width = width + "px";
353 this.sidebarResizeElement.style.left = (width - 3) + "px";
356 restoreSidebarWidth: function()
358 var sidebarWidth = WebInspector.settings[this._sidebarWidthSettingName()];
359 this.updateSidebarWidth(sidebarWidth);
362 saveSidebarWidth: function()
364 if (!this.sidebarElement)
366 WebInspector.settings[this._sidebarWidthSettingName()] = this.sidebarElement.offsetWidth;
369 updateMainViewWidth: function(width)
371 // Should be implemented by ancestors.
376 var visibleView = this.visibleView;
377 if (visibleView && "resize" in visibleView)
378 visibleView.resize();
381 canShowSourceLine: function(url, line)
386 showSourceLine: function(url, line)
391 elementsToRestoreScrollPositionsFor: function()
396 _storeScrollPositions: function()
398 var elements = this.elementsToRestoreScrollPositionsFor();
399 for (var i = 0; i < elements.length; ++i) {
400 var container = elements[i];
401 container._scrollTop = container.scrollTop;
405 _restoreScrollPositions: function()
407 var elements = this.elementsToRestoreScrollPositionsFor();
408 for (var i = 0; i < elements.length; ++i) {
409 var container = elements[i];
410 if (container._scrollTop)
411 container.scrollTop = container._scrollTop;
416 WebInspector.Panel.prototype.__proto__ = WebInspector.View.prototype;