OLD | NEW |
| (Empty) |
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 | |
29 WebInspector.Panel = function(createSidebar) | |
30 { | |
31 WebInspector.View.call(this); | |
32 if (createSidebar) | |
33 this._createSidebar(); | |
34 | |
35 this.element.addStyleClass("panel"); | |
36 } | |
37 | |
38 WebInspector.Panel.prototype = { | |
39 get toolbarItem() | |
40 { | |
41 if (this._toolbarItem) | |
42 return this._toolbarItem; | |
43 | |
44 // Sample toolbar item as markup: | |
45 // <button class="toolbar-item resources toggleable"> | |
46 // <div class="toolbar-icon"></div> | |
47 // <div class="toolbar-label">Resources</div> | |
48 // </button> | |
49 | |
50 this._toolbarItem = document.createElement("button"); | |
51 this._toolbarItem.className = "toolbar-item toggleable"; | |
52 this._toolbarItem.panel = this; | |
53 | |
54 if ("toolbarItemClass" in this) | |
55 this._toolbarItem.addStyleClass(this.toolbarItemClass); | |
56 | |
57 var iconElement = document.createElement("div"); | |
58 iconElement.className = "toolbar-icon"; | |
59 this._toolbarItem.appendChild(iconElement); | |
60 | |
61 if ("toolbarItemLabel" in this) { | |
62 var labelElement = document.createElement("div"); | |
63 labelElement.className = "toolbar-label"; | |
64 labelElement.textContent = this.toolbarItemLabel; | |
65 this._toolbarItem.appendChild(labelElement); | |
66 } | |
67 | |
68 return this._toolbarItem; | |
69 }, | |
70 | |
71 show: function() | |
72 { | |
73 WebInspector.View.prototype.show.call(this); | |
74 | |
75 var statusBarItems = this.statusBarItems; | |
76 if (statusBarItems) { | |
77 this._statusBarItemContainer = document.createElement("div"); | |
78 for (var i = 0; i < statusBarItems.length; ++i) | |
79 this._statusBarItemContainer.appendChild(statusBarItems[i]); | |
80 document.getElementById("main-status-bar").appendChild(this._statusB
arItemContainer); | |
81 } | |
82 | |
83 if ("_toolbarItem" in this) | |
84 this._toolbarItem.addStyleClass("toggled-on"); | |
85 | |
86 WebInspector.currentFocusElement = document.getElementById("main-panels"
); | |
87 this._updateSidebarWidth(); | |
88 }, | |
89 | |
90 hide: function() | |
91 { | |
92 WebInspector.View.prototype.hide.call(this); | |
93 | |
94 if (this._statusBarItemContainer && this._statusBarItemContainer.parentN
ode) | |
95 this._statusBarItemContainer.parentNode.removeChild(this._statusBarI
temContainer); | |
96 delete this._statusBarItemContainer; | |
97 if ("_toolbarItem" in this) | |
98 this._toolbarItem.removeStyleClass("toggled-on"); | |
99 }, | |
100 | |
101 attach: function() | |
102 { | |
103 if (!this.element.parentNode) | |
104 document.getElementById("main-panels").appendChild(this.element); | |
105 }, | |
106 | |
107 searchCanceled: function(startingNewSearch) | |
108 { | |
109 if (this._searchResults) { | |
110 for (var i = 0; i < this._searchResults.length; ++i) { | |
111 var view = this._searchResults[i]; | |
112 if (view.searchCanceled) | |
113 view.searchCanceled(); | |
114 delete view.currentQuery; | |
115 } | |
116 } | |
117 | |
118 WebInspector.updateSearchMatchesCount(0, this); | |
119 | |
120 if (this._currentSearchChunkIntervalIdentifier) { | |
121 clearInterval(this._currentSearchChunkIntervalIdentifier); | |
122 delete this._currentSearchChunkIntervalIdentifier; | |
123 } | |
124 | |
125 this._totalSearchMatches = 0; | |
126 this._currentSearchResultIndex = 0; | |
127 this._searchResults = []; | |
128 }, | |
129 | |
130 performSearch: function(query) | |
131 { | |
132 // Call searchCanceled since it will reset everything we need before doi
ng a new search. | |
133 this.searchCanceled(true); | |
134 | |
135 var searchableViews = this.searchableViews; | |
136 if (!searchableViews || !searchableViews.length) | |
137 return; | |
138 | |
139 var parentElement = this.viewsContainerElement; | |
140 var visibleView = this.visibleView; | |
141 var sortFuction = this.searchResultsSortFunction; | |
142 | |
143 var matchesCountUpdateTimeout = null; | |
144 | |
145 function updateMatchesCount() | |
146 { | |
147 WebInspector.updateSearchMatchesCount(this._totalSearchMatches, this
); | |
148 matchesCountUpdateTimeout = null; | |
149 } | |
150 | |
151 function updateMatchesCountSoon() | |
152 { | |
153 if (matchesCountUpdateTimeout) | |
154 return; | |
155 // Update the matches count every half-second so it doesn't feel twi
tchy. | |
156 matchesCountUpdateTimeout = setTimeout(updateMatchesCount.bind(this)
, 500); | |
157 } | |
158 | |
159 function finishedCallback(view, searchMatches) | |
160 { | |
161 if (!searchMatches) | |
162 return; | |
163 | |
164 this._totalSearchMatches += searchMatches; | |
165 this._searchResults.push(view); | |
166 | |
167 if (sortFuction) | |
168 this._searchResults.sort(sortFuction); | |
169 | |
170 if (this.searchMatchFound) | |
171 this.searchMatchFound(view, searchMatches); | |
172 | |
173 updateMatchesCountSoon.call(this); | |
174 | |
175 if (view === visibleView) | |
176 view.jumpToFirstSearchResult(); | |
177 } | |
178 | |
179 var i = 0; | |
180 var panel = this; | |
181 var boundFinishedCallback = finishedCallback.bind(this); | |
182 var chunkIntervalIdentifier = null; | |
183 | |
184 // Split up the work into chunks so we don't block the | |
185 // UI thread while processing. | |
186 | |
187 function processChunk() | |
188 { | |
189 var view = searchableViews[i]; | |
190 | |
191 if (++i >= searchableViews.length) { | |
192 if (panel._currentSearchChunkIntervalIdentifier === chunkInterva
lIdentifier) | |
193 delete panel._currentSearchChunkIntervalIdentifier; | |
194 clearInterval(chunkIntervalIdentifier); | |
195 } | |
196 | |
197 if (!view) | |
198 return; | |
199 | |
200 if (view.element.parentNode !== parentElement && view.element.parent
Node && parentElement) | |
201 view.detach(); | |
202 | |
203 view.currentQuery = query; | |
204 view.performSearch(query, boundFinishedCallback); | |
205 } | |
206 | |
207 processChunk(); | |
208 | |
209 chunkIntervalIdentifier = setInterval(processChunk, 25); | |
210 this._currentSearchChunkIntervalIdentifier = chunkIntervalIdentifier; | |
211 }, | |
212 | |
213 jumpToNextSearchResult: function() | |
214 { | |
215 if (!this.showView || !this._searchResults || !this._searchResults.lengt
h) | |
216 return; | |
217 | |
218 var showFirstResult = false; | |
219 | |
220 this._currentSearchResultIndex = this._searchResults.indexOf(this.visibl
eView); | |
221 if (this._currentSearchResultIndex === -1) { | |
222 this._currentSearchResultIndex = 0; | |
223 showFirstResult = true; | |
224 } | |
225 | |
226 var currentView = this._searchResults[this._currentSearchResultIndex]; | |
227 | |
228 if (currentView.showingLastSearchResult()) { | |
229 if (++this._currentSearchResultIndex >= this._searchResults.length) | |
230 this._currentSearchResultIndex = 0; | |
231 currentView = this._searchResults[this._currentSearchResultIndex]; | |
232 showFirstResult = true; | |
233 } | |
234 | |
235 if (currentView !== this.visibleView) | |
236 this.showView(currentView); | |
237 | |
238 if (showFirstResult) | |
239 currentView.jumpToFirstSearchResult(); | |
240 else | |
241 currentView.jumpToNextSearchResult(); | |
242 }, | |
243 | |
244 jumpToPreviousSearchResult: function() | |
245 { | |
246 if (!this.showView || !this._searchResults || !this._searchResults.lengt
h) | |
247 return; | |
248 | |
249 var showLastResult = false; | |
250 | |
251 this._currentSearchResultIndex = this._searchResults.indexOf(this.visibl
eView); | |
252 if (this._currentSearchResultIndex === -1) { | |
253 this._currentSearchResultIndex = 0; | |
254 showLastResult = true; | |
255 } | |
256 | |
257 var currentView = this._searchResults[this._currentSearchResultIndex]; | |
258 | |
259 if (currentView.showingFirstSearchResult()) { | |
260 if (--this._currentSearchResultIndex < 0) | |
261 this._currentSearchResultIndex = (this._searchResults.length - 1
); | |
262 currentView = this._searchResults[this._currentSearchResultIndex]; | |
263 showLastResult = true; | |
264 } | |
265 | |
266 if (currentView !== this.visibleView) | |
267 this.showView(currentView); | |
268 | |
269 if (showLastResult) | |
270 currentView.jumpToLastSearchResult(); | |
271 else | |
272 currentView.jumpToPreviousSearchResult(); | |
273 }, | |
274 | |
275 handleKeyEvent: function(event) | |
276 { | |
277 this.sidebarTree.handleKeyEvent(event); | |
278 }, | |
279 | |
280 _createSidebar: function() | |
281 { | |
282 this.sidebarElement = document.createElement("div"); | |
283 this.sidebarElement.className = "sidebar"; | |
284 this.element.appendChild(this.sidebarElement); | |
285 | |
286 this.sidebarResizeElement = document.createElement("div"); | |
287 this.sidebarResizeElement.className = "sidebar-resizer-vertical"; | |
288 this.sidebarResizeElement.addEventListener("mousedown", this._startSideb
arDragging.bind(this), false); | |
289 this.element.appendChild(this.sidebarResizeElement); | |
290 | |
291 this.sidebarTreeElement = document.createElement("ol"); | |
292 this.sidebarTreeElement.className = "sidebar-tree"; | |
293 this.sidebarElement.appendChild(this.sidebarTreeElement); | |
294 this.sidebarTree = new TreeOutline(this.sidebarTreeElement); | |
295 }, | |
296 | |
297 _startSidebarDragging: function(event) | |
298 { | |
299 WebInspector.elementDragStart(this.sidebarResizeElement, this._sidebarDr
agging.bind(this), this._endSidebarDragging.bind(this), event, "col-resize"); | |
300 }, | |
301 | |
302 _sidebarDragging: function(event) | |
303 { | |
304 this._updateSidebarWidth(event.pageX); | |
305 | |
306 event.preventDefault(); | |
307 }, | |
308 | |
309 _endSidebarDragging: function(event) | |
310 { | |
311 WebInspector.elementDragEnd(event); | |
312 }, | |
313 | |
314 _updateSidebarWidth: function(width) | |
315 { | |
316 if (this.sidebarElement.offsetWidth <= 0) { | |
317 // The stylesheet hasn't loaded yet or the window is closed, | |
318 // so we can't calculate what is need. Return early. | |
319 return; | |
320 } | |
321 | |
322 if (!("_currentSidebarWidth" in this)) | |
323 this._currentSidebarWidth = this.sidebarElement.offsetWidth; | |
324 | |
325 if (typeof width === "undefined") | |
326 width = this._currentSidebarWidth; | |
327 | |
328 width = Number.constrain(width, Preferences.minSidebarWidth, window.inne
rWidth / 2); | |
329 | |
330 this._currentSidebarWidth = width; | |
331 | |
332 this.sidebarElement.style.width = width + "px"; | |
333 this.setMainViewWidth(width); | |
334 this.sidebarResizeElement.style.left = (width - 3) + "px"; | |
335 | |
336 var visibleView = this.visibleView; | |
337 if (visibleView && "resize" in visibleView) | |
338 visibleView.resize(); | |
339 }, | |
340 | |
341 setMainViewWidth: function(width) | |
342 { | |
343 // Should be implemented by ancestors. | |
344 } | |
345 } | |
346 | |
347 WebInspector.Panel.prototype.__proto__ = WebInspector.View.prototype; | |
OLD | NEW |