Script.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  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. * @constructor
  27. * @extends {WebInspector.Object}
  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. /** @type {!Set.<!WebInspector.Script.Location>} */
  51. this._locations = new Set();
  52. /** @type {!Array.<!WebInspector.SourceMapping>} */
  53. this._sourceMappings = [];
  54. }
  55. WebInspector.Script.Events = {
  56. ScriptEdited: "ScriptEdited",
  57. }
  58. WebInspector.Script.snippetSourceURLPrefix = "snippets:///";
  59. WebInspector.Script.prototype = {
  60. /**
  61. * @return {string}
  62. */
  63. contentURL: function()
  64. {
  65. return this.sourceURL;
  66. },
  67. /**
  68. * @return {WebInspector.ResourceType}
  69. */
  70. contentType: function()
  71. {
  72. return WebInspector.resourceTypes.Script;
  73. },
  74. /**
  75. * @param {function(?string,boolean,string)} callback
  76. */
  77. requestContent: function(callback)
  78. {
  79. if (this._source) {
  80. callback(this._source, false, "text/javascript");
  81. return;
  82. }
  83. /**
  84. * @this {WebInspector.Script}
  85. * @param {?Protocol.Error} error
  86. * @param {string} source
  87. */
  88. function didGetScriptSource(error, source)
  89. {
  90. this._source = error ? "" : source;
  91. callback(this._source, false, "text/javascript");
  92. }
  93. if (this.scriptId) {
  94. // Script failed to parse.
  95. DebuggerAgent.getScriptSource(this.scriptId, didGetScriptSource.bind(this));
  96. } else
  97. callback("", false, "text/javascript");
  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. if (this.scriptId) {
  124. // Script failed to parse.
  125. DebuggerAgent.searchInContent(this.scriptId, query, caseSensitive, isRegex, innerCallback.bind(this));
  126. } else
  127. callback([]);
  128. },
  129. /**
  130. * @param {string} newSource
  131. * @param {function(?Protocol.Error, DebuggerAgent.SetScriptSourceError=, Array.<DebuggerAgent.CallFrame>=, boolean=)} callback
  132. */
  133. editSource: function(newSource, callback)
  134. {
  135. /**
  136. * @this {WebInspector.Script}
  137. * @param {?Protocol.Error} error
  138. * @param {DebuggerAgent.SetScriptSourceError=} errorData
  139. * @param {Array.<DebuggerAgent.CallFrame>=} callFrames
  140. * @param {Object=} debugData
  141. */
  142. function didEditScriptSource(error, errorData, callFrames, debugData)
  143. {
  144. // FIXME: support debugData.stack_update_needs_step_in flag by calling WebInspector.debugger_model.callStackModified
  145. if (!error)
  146. this._source = newSource;
  147. var needsStepIn = !!debugData && debugData["stack_update_needs_step_in"] === true;
  148. callback(error, errorData, callFrames, needsStepIn);
  149. if (!error)
  150. this.dispatchEventToListeners(WebInspector.Script.Events.ScriptEdited, newSource);
  151. }
  152. if (this.scriptId) {
  153. // Script failed to parse.
  154. DebuggerAgent.setScriptSource(this.scriptId, newSource, undefined, didEditScriptSource.bind(this));
  155. } else
  156. callback("Script failed to parse");
  157. },
  158. /**
  159. * @return {boolean}
  160. */
  161. isInlineScript: function()
  162. {
  163. var startsAtZero = !this.lineOffset && !this.columnOffset;
  164. return !!this.sourceURL && !startsAtZero;
  165. },
  166. /**
  167. * @return {boolean}
  168. */
  169. isAnonymousScript: function()
  170. {
  171. return !this.sourceURL;
  172. },
  173. /**
  174. * @return {boolean}
  175. */
  176. isSnippet: function()
  177. {
  178. return !!this.sourceURL && this.sourceURL.startsWith(WebInspector.Script.snippetSourceURLPrefix);
  179. },
  180. /**
  181. * @param {number} lineNumber
  182. * @param {number=} columnNumber
  183. * @return {WebInspector.UILocation}
  184. */
  185. rawLocationToUILocation: function(lineNumber, columnNumber)
  186. {
  187. var uiLocation;
  188. var rawLocation = new WebInspector.DebuggerModel.Location(this.scriptId, lineNumber, columnNumber || 0);
  189. for (var i = this._sourceMappings.length - 1; !uiLocation && i >= 0; --i)
  190. uiLocation = this._sourceMappings[i].rawLocationToUILocation(rawLocation);
  191. console.assert(uiLocation, "Script raw location can not be mapped to any ui location.");
  192. return uiLocation.uiSourceCode.overrideLocation(uiLocation);
  193. },
  194. /**
  195. * @param {!WebInspector.SourceMapping} sourceMapping
  196. */
  197. pushSourceMapping: function(sourceMapping)
  198. {
  199. this._sourceMappings.push(sourceMapping);
  200. this.updateLocations();
  201. },
  202. updateLocations: function()
  203. {
  204. var items = this._locations.items();
  205. for (var i = 0; i < items.length; ++i)
  206. items[i].update();
  207. },
  208. /**
  209. * @param {WebInspector.DebuggerModel.Location} rawLocation
  210. * @param {function(WebInspector.UILocation):(boolean|undefined)} updateDelegate
  211. * @return {WebInspector.Script.Location}
  212. */
  213. createLiveLocation: function(rawLocation, updateDelegate)
  214. {
  215. console.assert(rawLocation.scriptId === this.scriptId);
  216. var location = new WebInspector.Script.Location(this, rawLocation, updateDelegate);
  217. this._locations.add(location);
  218. location.update();
  219. return location;
  220. },
  221. __proto__: WebInspector.Object.prototype
  222. }
  223. /**
  224. * @constructor
  225. * @extends {WebInspector.LiveLocation}
  226. * @param {WebInspector.Script} script
  227. * @param {WebInspector.DebuggerModel.Location} rawLocation
  228. * @param {function(WebInspector.UILocation):(boolean|undefined)} updateDelegate
  229. */
  230. WebInspector.Script.Location = function(script, rawLocation, updateDelegate)
  231. {
  232. WebInspector.LiveLocation.call(this, rawLocation, updateDelegate);
  233. this._script = script;
  234. }
  235. WebInspector.Script.Location.prototype = {
  236. /**
  237. * @return {WebInspector.UILocation}
  238. */
  239. uiLocation: function()
  240. {
  241. var debuggerModelLocation = /** @type {WebInspector.DebuggerModel.Location} */ (this.rawLocation());
  242. return this._script.rawLocationToUILocation(debuggerModelLocation.lineNumber, debuggerModelLocation.columnNumber);
  243. },
  244. dispose: function()
  245. {
  246. WebInspector.LiveLocation.prototype.dispose.call(this);
  247. this._script._locations.remove(this);
  248. },
  249. __proto__: WebInspector.LiveLocation.prototype
  250. }