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