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.SourceView = function(resource) | |
30 { | |
31 // Set the sourceFrame first since WebInspector.ResourceView will set header
sVisible | |
32 // and our override of headersVisible needs the sourceFrame. | |
33 this.sourceFrame = new WebInspector.SourceFrame(null, this._addBreakpoint.bi
nd(this)); | |
34 | |
35 WebInspector.ResourceView.call(this, resource); | |
36 | |
37 resource.addEventListener("finished", this._resourceLoadingFinished, this); | |
38 | |
39 this.element.addStyleClass("source"); | |
40 | |
41 this._frameNeedsSetup = true; | |
42 | |
43 this.contentElement.appendChild(this.sourceFrame.element); | |
44 | |
45 var gutterElement = document.createElement("div"); | |
46 gutterElement.className = "webkit-line-gutter-backdrop"; | |
47 this.element.appendChild(gutterElement); | |
48 } | |
49 | |
50 WebInspector.SourceView.prototype = { | |
51 set headersVisible(x) | |
52 { | |
53 if (x === this._headersVisible) | |
54 return; | |
55 | |
56 var superSetter = WebInspector.ResourceView.prototype.__lookupSetter__("
headersVisible"); | |
57 if (superSetter) | |
58 superSetter.call(this, x); | |
59 | |
60 this.sourceFrame.autoSizesToFitContentHeight = x; | |
61 }, | |
62 | |
63 show: function(parentElement) | |
64 { | |
65 WebInspector.ResourceView.prototype.show.call(this, parentElement); | |
66 this.setupSourceFrameIfNeeded(); | |
67 }, | |
68 | |
69 hide: function() | |
70 { | |
71 WebInspector.View.prototype.hide.call(this); | |
72 this._currentSearchResultIndex = -1; | |
73 }, | |
74 | |
75 resize: function() | |
76 { | |
77 if (this.sourceFrame.autoSizesToFitContentHeight) | |
78 this.sourceFrame.sizeToFitContentHeight(); | |
79 }, | |
80 | |
81 detach: function() | |
82 { | |
83 WebInspector.ResourceView.prototype.detach.call(this); | |
84 | |
85 // FIXME: We need to mark the frame for setup on detach because the fram
e DOM is cleared | |
86 // when it is removed from the document. Is this a bug? | |
87 this._frameNeedsSetup = true; | |
88 this._sourceFrameSetup = false; | |
89 }, | |
90 | |
91 setupSourceFrameIfNeeded: function() | |
92 { | |
93 if (!this._frameNeedsSetup) | |
94 return; | |
95 | |
96 this.attach(); | |
97 | |
98 delete this._frameNeedsSetup; | |
99 this.sourceFrame.addEventListener("content loaded", this._contentLoaded,
this); | |
100 InspectorController.addResourceSourceToFrame(this.resource.identifier, t
his.sourceFrame.element); | |
101 }, | |
102 | |
103 _contentLoaded: function() | |
104 { | |
105 delete this._frameNeedsSetup; | |
106 this.sourceFrame.removeEventListener("content loaded", this._contentLoad
ed, this); | |
107 | |
108 if (this.resource.type === WebInspector.Resource.Type.Script | |
109 || this.resource.mimeType === "application/json" | |
110 || this.resource.mimeType === "application/javascript" | |
111 || /\.js(on)?$/.test(this.resource.lastPathComponent) ) { | |
112 this.sourceFrame.addEventListener("syntax highlighting complete", th
is._syntaxHighlightingComplete, this); | |
113 this.sourceFrame.syntaxHighlightJavascript(); | |
114 } else if (this.resource.type === WebInspector.Resource.Type.Stylesheet | |
115 || this.resource.mimeType === "text/css" | |
116 || /\.css$/.test(this.resource.lastPathComponent) ) { | |
117 this.sourceFrame.addEventListener("syntax highlighting complete", th
is._syntaxHighlightingComplete, this); | |
118 this.sourceFrame.syntaxHighlightCSS(); | |
119 } else | |
120 this._sourceFrameSetupFinished(); | |
121 }, | |
122 | |
123 _resourceLoadingFinished: function(event) | |
124 { | |
125 this._frameNeedsSetup = true; | |
126 this._sourceFrameSetup = false; | |
127 if (this.visible) | |
128 this.setupSourceFrameIfNeeded(); | |
129 this.resource.removeEventListener("finished", this._resourceLoadingFinis
hed, this); | |
130 }, | |
131 | |
132 _addBreakpoint: function(line) | |
133 { | |
134 var sourceID = null; | |
135 var closestStartingLine = 0; | |
136 var scripts = this.resource.scripts; | |
137 for (var i = 0; i < scripts.length; ++i) { | |
138 var script = scripts[i]; | |
139 if (script.startingLine <= line && script.startingLine >= closestSta
rtingLine) { | |
140 closestStartingLine = script.startingLine; | |
141 sourceID = script.sourceID; | |
142 } | |
143 } | |
144 | |
145 if (WebInspector.panels.scripts) { | |
146 var breakpoint = new WebInspector.Breakpoint(this.resource.url, line
, sourceID); | |
147 WebInspector.panels.scripts.addBreakpoint(breakpoint); | |
148 } | |
149 }, | |
150 | |
151 // The rest of the methods in this prototype need to be generic enough to wo
rk with a ScriptView. | |
152 // The ScriptView prototype pulls these methods into it's prototype to avoid
duplicate code. | |
153 | |
154 searchCanceled: function() | |
155 { | |
156 this._currentSearchResultIndex = -1; | |
157 this._searchResults = []; | |
158 delete this._delayedFindSearchMatches; | |
159 }, | |
160 | |
161 performSearch: function(query, finishedCallback) | |
162 { | |
163 // Call searchCanceled since it will reset everything we need before doi
ng a new search. | |
164 this.searchCanceled(); | |
165 | |
166 var lineQueryRegex = /(^|\s)(?:#|line:\s*)(\d+)(\s|$)/i; | |
167 var lineQueryMatch = query.match(lineQueryRegex); | |
168 if (lineQueryMatch) { | |
169 var lineToSearch = parseInt(lineQueryMatch[2]); | |
170 | |
171 // If there was a space before and after the line query part, replac
e with a space. | |
172 // Otherwise replace with an empty string to eat the prefix or postf
ix space. | |
173 var lineQueryReplacement = (lineQueryMatch[1] && lineQueryMatch[3] ?
" " : ""); | |
174 var filterlessQuery = query.replace(lineQueryRegex, lineQueryReplace
ment); | |
175 } | |
176 | |
177 this._searchFinishedCallback = finishedCallback; | |
178 | |
179 function findSearchMatches(query, finishedCallback) | |
180 { | |
181 if (isNaN(lineToSearch)) { | |
182 // Search the whole document since there was no line to search. | |
183 this._searchResults = (InspectorController.search(this.sourceFra
me.element.contentDocument, query) || []); | |
184 } else { | |
185 var sourceRow = this.sourceFrame.sourceRow(lineToSearch); | |
186 if (sourceRow) { | |
187 if (filterlessQuery) { | |
188 // There is still a query string, so search for that str
ing in the line. | |
189 this._searchResults = (InspectorController.search(source
Row, filterlessQuery) || []); | |
190 } else { | |
191 // Match the whole line, since there was no remaining qu
ery string to match. | |
192 var rowRange = this.sourceFrame.element.contentDocument.
createRange(); | |
193 rowRange.selectNodeContents(sourceRow); | |
194 this._searchResults = [rowRange]; | |
195 } | |
196 } | |
197 | |
198 // Attempt to search for the whole query, just incase it matches
a color like "#333". | |
199 var wholeQueryMatches = InspectorController.search(this.sourceFr
ame.element.contentDocument, query); | |
200 if (wholeQueryMatches) | |
201 this._searchResults = this._searchResults.concat(wholeQueryM
atches); | |
202 } | |
203 | |
204 if (this._searchResults) | |
205 finishedCallback(this, this._searchResults.length); | |
206 } | |
207 | |
208 if (!this._sourceFrameSetup) { | |
209 // The search is performed in _sourceFrameSetupFinished by calling _
delayedFindSearchMatches. | |
210 this._delayedFindSearchMatches = findSearchMatches.bind(this, query,
finishedCallback); | |
211 this.setupSourceFrameIfNeeded(); | |
212 return; | |
213 } | |
214 | |
215 findSearchMatches.call(this, query, finishedCallback); | |
216 }, | |
217 | |
218 jumpToFirstSearchResult: function() | |
219 { | |
220 if (!this._searchResults || !this._searchResults.length) | |
221 return; | |
222 this._currentSearchResultIndex = 0; | |
223 this._jumpToSearchResult(this._currentSearchResultIndex); | |
224 }, | |
225 | |
226 jumpToLastSearchResult: function() | |
227 { | |
228 if (!this._searchResults || !this._searchResults.length) | |
229 return; | |
230 this._currentSearchResultIndex = (this._searchResults.length - 1); | |
231 this._jumpToSearchResult(this._currentSearchResultIndex); | |
232 }, | |
233 | |
234 jumpToNextSearchResult: function() | |
235 { | |
236 if (!this._searchResults || !this._searchResults.length) | |
237 return; | |
238 if (++this._currentSearchResultIndex >= this._searchResults.length) | |
239 this._currentSearchResultIndex = 0; | |
240 this._jumpToSearchResult(this._currentSearchResultIndex); | |
241 }, | |
242 | |
243 jumpToPreviousSearchResult: function() | |
244 { | |
245 if (!this._searchResults || !this._searchResults.length) | |
246 return; | |
247 if (--this._currentSearchResultIndex < 0) | |
248 this._currentSearchResultIndex = (this._searchResults.length - 1); | |
249 this._jumpToSearchResult(this._currentSearchResultIndex); | |
250 }, | |
251 | |
252 showingFirstSearchResult: function() | |
253 { | |
254 return (this._currentSearchResultIndex === 0); | |
255 }, | |
256 | |
257 showingLastSearchResult: function() | |
258 { | |
259 return (this._searchResults && this._currentSearchResultIndex === (this.
_searchResults.length - 1)); | |
260 }, | |
261 | |
262 revealLine: function(lineNumber) | |
263 { | |
264 this.setupSourceFrameIfNeeded(); | |
265 this.sourceFrame.revealLine(lineNumber); | |
266 }, | |
267 | |
268 highlightLine: function(lineNumber) | |
269 { | |
270 this.setupSourceFrameIfNeeded(); | |
271 this.sourceFrame.highlightLine(lineNumber); | |
272 }, | |
273 | |
274 addMessage: function(msg) | |
275 { | |
276 this.sourceFrame.addMessage(msg); | |
277 }, | |
278 | |
279 clearMessages: function() | |
280 { | |
281 this.sourceFrame.clearMessages(); | |
282 }, | |
283 | |
284 _jumpToSearchResult: function(index) | |
285 { | |
286 var foundRange = this._searchResults[index]; | |
287 if (!foundRange) | |
288 return; | |
289 | |
290 var selection = this.sourceFrame.element.contentWindow.getSelection(); | |
291 selection.removeAllRanges(); | |
292 selection.addRange(foundRange); | |
293 | |
294 if (foundRange.startContainer.scrollIntoViewIfNeeded) | |
295 foundRange.startContainer.scrollIntoViewIfNeeded(true); | |
296 else if (foundRange.startContainer.parentNode) | |
297 foundRange.startContainer.parentNode.scrollIntoViewIfNeeded(true); | |
298 }, | |
299 | |
300 _sourceFrameSetupFinished: function() | |
301 { | |
302 this._sourceFrameSetup = true; | |
303 if (this._delayedFindSearchMatches) { | |
304 this._delayedFindSearchMatches(); | |
305 delete this._delayedFindSearchMatches; | |
306 } | |
307 }, | |
308 | |
309 _syntaxHighlightingComplete: function(event) | |
310 { | |
311 this._sourceFrameSetupFinished(); | |
312 this.sourceFrame.removeEventListener("syntax highlighting complete", nul
l, this); | |
313 } | |
314 } | |
315 | |
316 WebInspector.SourceView.prototype.__proto__ = WebInspector.ResourceView.prototyp
e; | |
OLD | NEW |