e794477521fab46a8f456b288bd7d064a799d0b5
[WebKit-https.git] / Source / WebCore / inspector / front-end / Script.js
1 /*
2  * Copyright (C) 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 /**
27  * @constructor
28  * @implements {WebInspector.ContentProvider}
29  * @param {string} scriptId
30  * @param {string} sourceURL
31  * @param {number} startLine
32  * @param {number} startColumn
33  * @param {number} endLine
34  * @param {number} endColumn
35  * @param {boolean} isContentScript
36  * @param {string=} sourceMapURL
37  * @param {boolean=} hasSourceURL
38  */
39 WebInspector.Script = function(scriptId, sourceURL, startLine, startColumn, endLine, endColumn, isContentScript, sourceMapURL, hasSourceURL)
40 {
41     this.scriptId = scriptId;
42     this.sourceURL = sourceURL;
43     this.lineOffset = startLine;
44     this.columnOffset = startColumn;
45     this.endLine = endLine;
46     this.endColumn = endColumn;
47     this.isContentScript = isContentScript;
48     this.sourceMapURL = sourceMapURL;
49     this.hasSourceURL = hasSourceURL;
50     this._locations = [];
51 }
52
53 WebInspector.Script.snippetSourceURLPrefix = "snippets:///";
54
55 WebInspector.Script.prototype = {
56     /**
57      * @return {string}
58      */
59     contentURL: function()
60     {
61         return this.sourceURL;
62     },
63
64     /**
65      * @return {WebInspector.ResourceType}
66      */
67     contentType: function()
68     {
69         return WebInspector.resourceTypes.Script;
70     },
71
72     /**
73      * @param {function(?string,boolean,string)} callback
74      */
75     requestContent: function(callback)
76     {
77         if (this._source) {
78             callback(this._source, false, "text/javascript");
79             return;
80         }
81
82         /**
83          * @this {WebInspector.Script}
84          * @param {?Protocol.Error} error
85          * @param {string} source
86          */
87         function didGetScriptSource(error, source)
88         {
89             this._source = error ? "" : source;
90             callback(this._source, false, "text/javascript");
91         }
92         if (this.scriptId) {
93             // Script failed to parse.
94             DebuggerAgent.getScriptSource(this.scriptId, didGetScriptSource.bind(this));
95         } else
96             callback("", false, "text/javascript");
97     },
98
99     /**
100      * @param {string} query
101      * @param {boolean} caseSensitive
102      * @param {boolean} isRegex
103      * @param {function(Array.<PageAgent.SearchMatch>)} callback
104      */
105     searchInContent: function(query, caseSensitive, isRegex, callback)
106     {
107         /**
108          * @this {WebInspector.Script}
109          * @param {?Protocol.Error} error
110          * @param {Array.<PageAgent.SearchMatch>} searchMatches
111          */
112         function innerCallback(error, searchMatches)
113         {
114             if (error)
115                 console.error(error);
116             var result = [];
117             for (var i = 0; i < searchMatches.length; ++i) {
118                 var searchMatch = new WebInspector.ContentProvider.SearchMatch(searchMatches[i].lineNumber, searchMatches[i].lineContent);
119                 result.push(searchMatch);
120             }
121             callback(result || []);
122         }
123
124         if (this.scriptId) {
125             // Script failed to parse.
126             DebuggerAgent.searchInContent(this.scriptId, query, caseSensitive, isRegex, innerCallback.bind(this));
127         } else
128             callback([]);
129     },
130
131     /**
132      * @param {string} newSource
133      * @param {function(?Protocol.Error, Array.<DebuggerAgent.CallFrame>=)} callback
134      */
135     editSource: function(newSource, callback)
136     {
137         /**
138          * @this {WebInspector.Script}
139          * @param {?Protocol.Error} error
140          * @param {Array.<DebuggerAgent.CallFrame>|undefined} callFrames
141          * @param {Object=} debugData
142          */
143         function didEditScriptSource(error, callFrames, debugData)
144         {
145             // FIXME: support debugData.stack_update_needs_step_in flag by calling WebInspector.debugger_model.callStackModified
146             if (!error)
147                 this._source = newSource;
148             callback(error, callFrames);
149         }
150         if (this.scriptId) {
151             // Script failed to parse.
152             DebuggerAgent.setScriptSource(this.scriptId, newSource, undefined, didEditScriptSource.bind(this));
153         } else
154             callback("Script failed to parse");
155     },
156
157     /**
158      * @return {boolean}
159      */
160     isInlineScript: function()
161     {
162         var startsAtZero = !this.lineOffset && !this.columnOffset;
163         return !!this.sourceURL && !startsAtZero;
164     },
165
166     /**
167      * @return {boolean}
168      */
169     isAnonymousScript: function()
170     {
171         return !this.sourceURL;
172     },
173
174     /**
175      * @return {boolean}
176      */
177     isSnippet: function()
178     {
179         return this.sourceURL && this.sourceURL.startsWith(WebInspector.Script.snippetSourceURLPrefix);
180     },
181
182     /**
183      * @param {number} lineNumber
184      * @param {number=} columnNumber
185      * @return {WebInspector.UILocation}
186      */
187     rawLocationToUILocation: function(lineNumber, columnNumber)
188     {
189         var uiLocation = this._sourceMapping.rawLocationToUILocation(new WebInspector.DebuggerModel.Location(this.scriptId, lineNumber, columnNumber || 0));
190         return uiLocation.uiSourceCode.overrideLocation(uiLocation);
191     },
192
193     /**
194      * @param {WebInspector.SourceMapping} sourceMapping
195      */
196     setSourceMapping: function(sourceMapping)
197     {
198         this._sourceMapping = sourceMapping;
199         for (var i = 0; i < this._locations.length; ++i)
200             this._locations[i].update();
201     },
202
203     /**
204      * @param {WebInspector.DebuggerModel.Location} rawLocation
205      * @param {function(WebInspector.UILocation):(boolean|undefined)} updateDelegate
206      * @return {WebInspector.Script.Location}
207      */
208     createLiveLocation: function(rawLocation, updateDelegate)
209     {
210         console.assert(rawLocation.scriptId === this.scriptId);
211         var location = new WebInspector.Script.Location(this, rawLocation, updateDelegate);
212         this._locations.push(location);
213         location.update();
214         return location;
215     }
216 }
217
218 /**
219  * @constructor
220  * @extends {WebInspector.LiveLocation}
221  * @param {WebInspector.Script} script
222  * @param {WebInspector.DebuggerModel.Location} rawLocation
223  * @param {function(WebInspector.UILocation):(boolean|undefined)} updateDelegate
224  */
225 WebInspector.Script.Location = function(script, rawLocation, updateDelegate)
226 {
227     WebInspector.LiveLocation.call(this, rawLocation, updateDelegate);
228     this._script = script;
229 }
230
231 WebInspector.Script.Location.prototype = {
232     /**
233      * @return {WebInspector.UILocation}
234      */
235     uiLocation: function()
236     {
237         var debuggerModelLocation = /** @type {WebInspector.DebuggerModel.Location} */ (this.rawLocation());
238         return this._script.rawLocationToUILocation(debuggerModelLocation.lineNumber, debuggerModelLocation.columnNumber);
239     },
240
241     dispose: function()
242     {
243         WebInspector.LiveLocation.prototype.dispose.call(this);
244         this._script._locations.remove(this);
245     },
246
247     __proto__: WebInspector.LiveLocation.prototype
248 }