• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2007, 2008 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 *
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.
16 *
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.
27 */
28
29WebInspector.Panel = function()
30{
31    WebInspector.View.call(this);
32
33    this.element.addStyleClass("panel");
34}
35
36WebInspector.Panel.prototype = {
37    get toolbarItem()
38    {
39        if (this._toolbarItem)
40            return this._toolbarItem;
41
42        // Sample toolbar item as markup:
43        // <button class="toolbar-item resources toggleable">
44        // <div class="toolbar-icon"></div>
45        // <div class="toolbar-label">Resources</div>
46        // </button>
47
48        this._toolbarItem = document.createElement("button");
49        this._toolbarItem.className = "toolbar-item toggleable";
50        this._toolbarItem.panel = this;
51
52        if ("toolbarItemClass" in this)
53            this._toolbarItem.addStyleClass(this.toolbarItemClass);
54
55        var iconElement = document.createElement("div");
56        iconElement.className = "toolbar-icon";
57        this._toolbarItem.appendChild(iconElement);
58
59        if ("toolbarItemLabel" in this) {
60            var labelElement = document.createElement("div");
61            labelElement.className = "toolbar-label";
62            labelElement.textContent = this.toolbarItemLabel;
63            this._toolbarItem.appendChild(labelElement);
64        }
65
66        return this._toolbarItem;
67    },
68
69    show: function()
70    {
71        WebInspector.View.prototype.show.call(this);
72
73        var statusBarItems = this.statusBarItems;
74        if (statusBarItems) {
75            this._statusBarItemContainer = document.createElement("div");
76            for (var i = 0; i < statusBarItems.length; ++i)
77                this._statusBarItemContainer.appendChild(statusBarItems[i]);
78            document.getElementById("main-status-bar").appendChild(this._statusBarItemContainer);
79        }
80
81        if ("_toolbarItem" in this)
82            this._toolbarItem.addStyleClass("toggled-on");
83
84        WebInspector.currentFocusElement = document.getElementById("main-panels");
85    },
86
87    hide: function()
88    {
89        WebInspector.View.prototype.hide.call(this);
90
91        if (this._statusBarItemContainer && this._statusBarItemContainer.parentNode)
92            this._statusBarItemContainer.parentNode.removeChild(this._statusBarItemContainer);
93        delete this._statusBarItemContainer;
94        if ("_toolbarItem" in this)
95            this._toolbarItem.removeStyleClass("toggled-on");
96    },
97
98    attach: function()
99    {
100        if (!this.element.parentNode)
101            document.getElementById("main-panels").appendChild(this.element);
102    },
103
104    searchCanceled: function(startingNewSearch)
105    {
106        if (this._searchResults) {
107            for (var i = 0; i < this._searchResults.length; ++i) {
108                var view = this._searchResults[i];
109                if (view.searchCanceled)
110                    view.searchCanceled();
111                delete view.currentQuery;
112            }
113        }
114
115        WebInspector.updateSearchMatchesCount(0, this);
116
117        if (this._currentSearchChunkIntervalIdentifier) {
118            clearInterval(this._currentSearchChunkIntervalIdentifier);
119            delete this._currentSearchChunkIntervalIdentifier;
120        }
121
122        this._totalSearchMatches = 0;
123        this._currentSearchResultIndex = 0;
124        this._searchResults = [];
125    },
126
127    performSearch: function(query)
128    {
129        // Call searchCanceled since it will reset everything we need before doing a new search.
130        this.searchCanceled(true);
131
132        var searchableViews = this.searchableViews;
133        if (!searchableViews || !searchableViews.length)
134            return;
135
136        var parentElement = this.viewsContainerElement;
137        var visibleView = this.visibleView;
138        var sortFuction = this.searchResultsSortFunction;
139
140        var matchesCountUpdateTimeout = null;
141
142        function updateMatchesCount()
143        {
144            WebInspector.updateSearchMatchesCount(this._totalSearchMatches, this);
145            matchesCountUpdateTimeout = null;
146        }
147
148        function updateMatchesCountSoon()
149        {
150            if (matchesCountUpdateTimeout)
151                return;
152            // Update the matches count every half-second so it doesn't feel twitchy.
153            matchesCountUpdateTimeout = setTimeout(updateMatchesCount.bind(this), 500);
154        }
155
156        function finishedCallback(view, searchMatches)
157        {
158            if (!searchMatches)
159                return;
160
161            this._totalSearchMatches += searchMatches;
162            this._searchResults.push(view);
163
164            if (sortFuction)
165                this._searchResults.sort(sortFuction);
166
167            if (this.searchMatchFound)
168                this.searchMatchFound(view, searchMatches);
169
170            updateMatchesCountSoon.call(this);
171
172            if (view === visibleView)
173                view.jumpToFirstSearchResult();
174        }
175
176        var i = 0;
177        var panel = this;
178        var boundFinishedCallback = finishedCallback.bind(this);
179        var chunkIntervalIdentifier = null;
180
181        // Split up the work into chunks so we don't block the
182        // UI thread while processing.
183
184        function processChunk()
185        {
186            var view = searchableViews[i];
187
188            if (++i >= searchableViews.length) {
189                if (panel._currentSearchChunkIntervalIdentifier === chunkIntervalIdentifier)
190                    delete panel._currentSearchChunkIntervalIdentifier;
191                clearInterval(chunkIntervalIdentifier);
192            }
193
194            if (!view)
195                return;
196
197            if (view.element.parentNode !== parentElement && view.element.parentNode && parentElement)
198                view.detach();
199
200            view.currentQuery = query;
201            view.performSearch(query, boundFinishedCallback);
202        }
203
204        processChunk();
205
206        chunkIntervalIdentifier = setInterval(processChunk, 25);
207        this._currentSearchChunkIntervalIdentifier = chunkIntervalIdentifier;
208    },
209
210    jumpToNextSearchResult: function()
211    {
212        if (!this.showView || !this._searchResults || !this._searchResults.length)
213            return;
214
215        var showFirstResult = false;
216
217        this._currentSearchResultIndex = this._searchResults.indexOf(this.visibleView);
218        if (this._currentSearchResultIndex === -1) {
219            this._currentSearchResultIndex = 0;
220            showFirstResult = true;
221        }
222
223        var currentView = this._searchResults[this._currentSearchResultIndex];
224
225        if (currentView.showingLastSearchResult()) {
226            if (++this._currentSearchResultIndex >= this._searchResults.length)
227                this._currentSearchResultIndex = 0;
228            currentView = this._searchResults[this._currentSearchResultIndex];
229            showFirstResult = true;
230        }
231
232        if (currentView !== this.visibleView)
233            this.showView(currentView);
234
235        if (showFirstResult)
236            currentView.jumpToFirstSearchResult();
237        else
238            currentView.jumpToNextSearchResult();
239    },
240
241    jumpToPreviousSearchResult: function()
242    {
243        if (!this.showView || !this._searchResults || !this._searchResults.length)
244            return;
245
246        var showLastResult = false;
247
248        this._currentSearchResultIndex = this._searchResults.indexOf(this.visibleView);
249        if (this._currentSearchResultIndex === -1) {
250            this._currentSearchResultIndex = 0;
251            showLastResult = true;
252        }
253
254        var currentView = this._searchResults[this._currentSearchResultIndex];
255
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;
261        }
262
263        if (currentView !== this.visibleView)
264            this.showView(currentView);
265
266        if (showLastResult)
267            currentView.jumpToLastSearchResult();
268        else
269            currentView.jumpToPreviousSearchResult();
270    }
271}
272
273WebInspector.Panel.prototype.__proto__ = WebInspector.View.prototype;
274