• 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    createStatusBarButton: function()
70    {
71        var button = document.createElement("button");
72        var glyph = document.createElement("div");
73        glyph.className = "glyph";
74        button.appendChild(glyph);
75        var glyphShadow = document.createElement("div");
76        glyphShadow.className = "glyph shadow";
77        button.appendChild(glyphShadow);
78        return button;
79    },
80
81    show: function()
82    {
83        WebInspector.View.prototype.show.call(this);
84
85        var statusBarItems = this.statusBarItems;
86        if (statusBarItems) {
87            this._statusBarItemContainer = document.createElement("div");
88            for (var i = 0; i < statusBarItems.length; ++i)
89                this._statusBarItemContainer.appendChild(statusBarItems[i]);
90            document.getElementById("main-status-bar").appendChild(this._statusBarItemContainer);
91        }
92
93        if ("_toolbarItem" in this)
94            this._toolbarItem.addStyleClass("toggled-on");
95
96        WebInspector.currentFocusElement = document.getElementById("main-panels");
97    },
98
99    hide: function()
100    {
101        WebInspector.View.prototype.hide.call(this);
102
103        if (this._statusBarItemContainer && this._statusBarItemContainer.parentNode)
104            this._statusBarItemContainer.parentNode.removeChild(this._statusBarItemContainer);
105        delete this._statusBarItemContainer;
106        if ("_toolbarItem" in this)
107            this._toolbarItem.removeStyleClass("toggled-on");
108    },
109
110    attach: function()
111    {
112        if (!this.element.parentNode)
113            document.getElementById("main-panels").appendChild(this.element);
114    },
115
116    searchCanceled: function(startingNewSearch)
117    {
118        if (this._searchResults) {
119            for (var i = 0; i < this._searchResults.length; ++i) {
120                var view = this._searchResults[i];
121                if (view.searchCanceled)
122                    view.searchCanceled();
123                delete view.currentQuery;
124            }
125        }
126
127        WebInspector.updateSearchMatchesCount(0, this);
128
129        if (this._currentSearchChunkIntervalIdentifier) {
130            clearInterval(this._currentSearchChunkIntervalIdentifier);
131            delete this._currentSearchChunkIntervalIdentifier;
132        }
133
134        this._totalSearchMatches = 0;
135        this._currentSearchResultIndex = 0;
136        this._searchResults = [];
137    },
138
139    performSearch: function(query)
140    {
141        // Call searchCanceled since it will reset everything we need before doing a new search.
142        this.searchCanceled(true);
143
144        var searchableViews = this.searchableViews;
145        if (!searchableViews || !searchableViews.length)
146            return;
147
148        var parentElement = this.viewsContainerElement;
149        var visibleView = this.visibleView;
150        var sortFuction = this.searchResultsSortFunction;
151
152        var matchesCountUpdateTimeout = null;
153
154        function updateMatchesCount()
155        {
156            WebInspector.updateSearchMatchesCount(this._totalSearchMatches, this);
157            matchesCountUpdateTimeout = null;
158        }
159
160        function updateMatchesCountSoon()
161        {
162            if (matchesCountUpdateTimeout)
163                return;
164            // Update the matches count every half-second so it doesn't feel twitchy.
165            matchesCountUpdateTimeout = setTimeout(updateMatchesCount.bind(this), 500);
166        }
167
168        function finishedCallback(view, searchMatches)
169        {
170            if (!searchMatches)
171                return;
172
173            this._totalSearchMatches += searchMatches;
174            this._searchResults.push(view);
175
176            if (sortFuction)
177                this._searchResults.sort(sortFuction);
178
179            if (this.searchMatchFound)
180                this.searchMatchFound(view, searchMatches);
181
182            updateMatchesCountSoon.call(this);
183
184            if (view === visibleView)
185                view.jumpToFirstSearchResult();
186        }
187
188        var i = 0;
189        var panel = this;
190        var boundFinishedCallback = finishedCallback.bind(this);
191        var chunkIntervalIdentifier = null;
192
193        // Split up the work into chunks so we don't block the
194        // UI thread while processing.
195
196        function processChunk()
197        {
198            var view = searchableViews[i];
199
200            if (++i >= searchableViews.length) {
201                if (panel._currentSearchChunkIntervalIdentifier === chunkIntervalIdentifier)
202                    delete panel._currentSearchChunkIntervalIdentifier;
203                clearInterval(chunkIntervalIdentifier);
204            }
205
206            if (!view)
207                return;
208
209            if (view.element.parentNode !== parentElement && view.element.parentNode && parentElement)
210                view.detach();
211
212            view.currentQuery = query;
213            view.performSearch(query, boundFinishedCallback);
214        }
215
216        processChunk();
217
218        chunkIntervalIdentifier = setInterval(processChunk, 25);
219        this._currentSearchChunkIntervalIdentifier = chunkIntervalIdentifier;
220    },
221
222    jumpToNextSearchResult: function()
223    {
224        if (!this.showView || !this._searchResults || !this._searchResults.length)
225            return;
226
227        var showFirstResult = false;
228
229        this._currentSearchResultIndex = this._searchResults.indexOf(this.visibleView);
230        if (this._currentSearchResultIndex === -1) {
231            this._currentSearchResultIndex = 0;
232            showFirstResult = true;
233        }
234
235        var currentView = this._searchResults[this._currentSearchResultIndex];
236
237        if (currentView.showingLastSearchResult()) {
238            if (++this._currentSearchResultIndex >= this._searchResults.length)
239                this._currentSearchResultIndex = 0;
240            currentView = this._searchResults[this._currentSearchResultIndex];
241            showFirstResult = true;
242        }
243
244        if (currentView !== this.visibleView)
245            this.showView(currentView);
246
247        if (showFirstResult)
248            currentView.jumpToFirstSearchResult();
249        else
250            currentView.jumpToNextSearchResult();
251    },
252
253    jumpToPreviousSearchResult: function()
254    {
255        if (!this.showView || !this._searchResults || !this._searchResults.length)
256            return;
257
258        var showLastResult = false;
259
260        this._currentSearchResultIndex = this._searchResults.indexOf(this.visibleView);
261        if (this._currentSearchResultIndex === -1) {
262            this._currentSearchResultIndex = 0;
263            showLastResult = true;
264        }
265
266        var currentView = this._searchResults[this._currentSearchResultIndex];
267
268        if (currentView.showingFirstSearchResult()) {
269            if (--this._currentSearchResultIndex < 0)
270                this._currentSearchResultIndex = (this._searchResults.length - 1);
271            currentView = this._searchResults[this._currentSearchResultIndex];
272            showLastResult = true;
273        }
274
275        if (currentView !== this.visibleView)
276            this.showView(currentView);
277
278        if (showLastResult)
279            currentView.jumpToLastSearchResult();
280        else
281            currentView.jumpToPreviousSearchResult();
282    }
283}
284
285WebInspector.Panel.prototype.__proto__ = WebInspector.View.prototype;
286