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.SourceView = function(resource) 30{ 31 WebInspector.ResourceView.call(this, resource); 32 33 this.element.addStyleClass("source"); 34 35 this.sourceFrame = new WebInspector.SourceFrame(this.contentElement, this._addBreakpoint.bind(this), this._removeBreakpoint.bind(this)); 36 resource.addEventListener("finished", this._resourceLoadingFinished, this); 37 this._frameNeedsSetup = true; 38} 39 40WebInspector.SourceView.prototype = { 41 show: function(parentElement) 42 { 43 WebInspector.ResourceView.prototype.show.call(this, parentElement); 44 this.sourceFrame.visible = true; 45 this.resize(); 46 }, 47 48 hide: function() 49 { 50 WebInspector.View.prototype.hide.call(this); 51 this.sourceFrame.visible = false; 52 this._currentSearchResultIndex = -1; 53 }, 54 55 resize: function() 56 { 57 if (this.sourceFrame) 58 this.sourceFrame.resize(); 59 }, 60 61 setupSourceFrameIfNeeded: function() 62 { 63 if (!this._frameNeedsSetup) 64 return; 65 66 this.attach(); 67 68 delete this._frameNeedsSetup; 69 WebInspector.getResourceContent(this.resource.identifier, this._contentLoaded.bind(this)); 70 }, 71 72 contentTabSelected: function() 73 { 74 this.setupSourceFrameIfNeeded(); 75 }, 76 77 _contentLoaded: function(content) 78 { 79 this.sourceFrame.setContent(this.resource.mimeType, content, this.resource.url); 80 this._sourceFrameSetupFinished(); 81 }, 82 83 _resourceLoadingFinished: function(event) 84 { 85 this._frameNeedsSetup = true; 86 this._sourceFrameSetup = false; 87 if (this.visible) 88 this.setupSourceFrameIfNeeded(); 89 this.resource.removeEventListener("finished", this._resourceLoadingFinished, this); 90 }, 91 92 _addBreakpoint: function(line) 93 { 94 var sourceID = null; 95 var closestStartingLine = 0; 96 var scripts = this.resource.scripts; 97 for (var i = 0; i < scripts.length; ++i) { 98 var script = scripts[i]; 99 if (script.startingLine <= line && script.startingLine >= closestStartingLine) { 100 closestStartingLine = script.startingLine; 101 sourceID = script.sourceID; 102 } 103 } 104 105 if (WebInspector.panels.scripts) { 106 var breakpoint = new WebInspector.Breakpoint(this.resource.url, line, sourceID); 107 WebInspector.panels.scripts.addBreakpoint(breakpoint); 108 } 109 }, 110 111 _removeBreakpoint: function(breakpoint) 112 { 113 if (WebInspector.panels.scripts) 114 WebInspector.panels.scripts.removeBreakpoint(breakpoint); 115 }, 116 117 // The rest of the methods in this prototype need to be generic enough to work with a ScriptView. 118 // The ScriptView prototype pulls these methods into it's prototype to avoid duplicate code. 119 120 searchCanceled: function() 121 { 122 this._currentSearchResultIndex = -1; 123 this._searchResults = []; 124 this.sourceFrame.clearMarkedRange(); 125 delete this._delayedFindSearchMatches; 126 }, 127 128 performSearch: function(query, finishedCallback) 129 { 130 // Call searchCanceled since it will reset everything we need before doing a new search. 131 this.searchCanceled(); 132 133 this._searchFinishedCallback = finishedCallback; 134 135 function findSearchMatches(query, finishedCallback) 136 { 137 this._searchResults = this.sourceFrame.findSearchMatches(query); 138 if (this._searchResults) 139 finishedCallback(this, this._searchResults.length); 140 } 141 142 if (!this._sourceFrameSetup) { 143 // The search is performed in _sourceFrameSetupFinished by calling _delayedFindSearchMatches. 144 this._delayedFindSearchMatches = findSearchMatches.bind(this, query, finishedCallback); 145 this.setupSourceFrameIfNeeded(); 146 return; 147 } 148 149 findSearchMatches.call(this, query, finishedCallback); 150 }, 151 152 jumpToFirstSearchResult: function() 153 { 154 if (!this._searchResults || !this._searchResults.length) 155 return; 156 this._currentSearchResultIndex = 0; 157 this._jumpToSearchResult(this._currentSearchResultIndex); 158 }, 159 160 jumpToLastSearchResult: function() 161 { 162 if (!this._searchResults || !this._searchResults.length) 163 return; 164 this._currentSearchResultIndex = (this._searchResults.length - 1); 165 this._jumpToSearchResult(this._currentSearchResultIndex); 166 }, 167 168 jumpToNextSearchResult: function() 169 { 170 if (!this._searchResults || !this._searchResults.length) 171 return; 172 if (++this._currentSearchResultIndex >= this._searchResults.length) 173 this._currentSearchResultIndex = 0; 174 this._jumpToSearchResult(this._currentSearchResultIndex); 175 }, 176 177 jumpToPreviousSearchResult: function() 178 { 179 if (!this._searchResults || !this._searchResults.length) 180 return; 181 if (--this._currentSearchResultIndex < 0) 182 this._currentSearchResultIndex = (this._searchResults.length - 1); 183 this._jumpToSearchResult(this._currentSearchResultIndex); 184 }, 185 186 showingFirstSearchResult: function() 187 { 188 return (this._currentSearchResultIndex === 0); 189 }, 190 191 showingLastSearchResult: function() 192 { 193 return (this._searchResults && this._currentSearchResultIndex === (this._searchResults.length - 1)); 194 }, 195 196 revealLine: function(lineNumber) 197 { 198 this.setupSourceFrameIfNeeded(); 199 this.sourceFrame.revealLine(lineNumber); 200 }, 201 202 highlightLine: function(lineNumber) 203 { 204 this.setupSourceFrameIfNeeded(); 205 this.sourceFrame.highlightLine(lineNumber); 206 }, 207 208 addMessage: function(msg) 209 { 210 this.sourceFrame.addMessage(msg); 211 }, 212 213 clearMessages: function() 214 { 215 this.sourceFrame.clearMessages(); 216 }, 217 218 _jumpToSearchResult: function(index) 219 { 220 var foundRange = this._searchResults[index]; 221 if (!foundRange) 222 return; 223 224 this.sourceFrame.markAndRevealRange(foundRange); 225 }, 226 227 _sourceFrameSetupFinished: function() 228 { 229 this._sourceFrameSetup = true; 230 this.resize(); 231 if (this._delayedFindSearchMatches) { 232 this._delayedFindSearchMatches(); 233 delete this._delayedFindSearchMatches; 234 } 235 } 236} 237 238WebInspector.SourceView.prototype.__proto__ = WebInspector.ResourceView.prototype; 239