| /* |
| * Copyright (C) 2011 Google Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following disclaimer |
| * in the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name of Google Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| WebInspector.DebuggerPresentationModel = function() |
| { |
| this._sourceFiles = {}; |
| this._messages = []; |
| this._breakpointsByDebuggerId = {}; |
| this._breakpointsWithoutSourceFile = {}; |
| |
| this._presentationCallFrames = []; |
| this._selectedCallFrameIndex = 0; |
| |
| WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerWasEnabled, this._debuggerWasEnabled, this); |
| WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.ParsedScriptSource, this._parsedScriptSource, this); |
| WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.FailedToParseScriptSource, this._failedToParseScriptSource, this); |
| WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointResolved, this._breakpointResolved, this); |
| WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this); |
| WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerResumed, this._debuggerResumed, this); |
| WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.Reset, this._debuggerReset, this); |
| |
| new WebInspector.DebuggerPresentationModelResourceBinding(this); |
| } |
| |
| WebInspector.DebuggerPresentationModel.Events = { |
| SourceFileAdded: "source-file-added", |
| SourceFileChanged: "source-file-changed", |
| ConsoleMessageAdded: "console-message-added", |
| BreakpointAdded: "breakpoint-added", |
| BreakpointRemoved: "breakpoint-removed", |
| DebuggerPaused: "debugger-paused", |
| DebuggerResumed: "debugger-resumed", |
| CallFrameSelected: "call-frame-selected" |
| } |
| |
| WebInspector.DebuggerPresentationModel.prototype = { |
| _debuggerWasEnabled: function() |
| { |
| if (this._breakpointsRestored) |
| return; |
| this._restoreBreakpointsFromSettings(); |
| this._breakpointsRestored = true; |
| }, |
| |
| sourceFile: function(sourceFileId) |
| { |
| return this._sourceFiles[sourceFileId]; |
| }, |
| |
| sourceFileForScriptURL: function(scriptURL) |
| { |
| return this._sourceFiles[scriptURL]; |
| }, |
| |
| requestSourceFileContent: function(sourceFileId, callback) |
| { |
| this._sourceFiles[sourceFileId].requestContent(callback); |
| }, |
| |
| _parsedScriptSource: function(event) |
| { |
| this._addScript(event.data); |
| }, |
| |
| _failedToParseScriptSource: function(event) |
| { |
| this._addScript(event.data); |
| }, |
| |
| _addScript: function(script) |
| { |
| var sourceFileId = this._createSourceFileId(script.sourceURL, script.sourceID); |
| var sourceFile = this._sourceFiles[sourceFileId]; |
| if (sourceFile) { |
| sourceFile.addScript(script); |
| return; |
| } |
| |
| function contentChanged(sourceFile) |
| { |
| this.dispatchEventToListeners(WebInspector.DebuggerPresentationModel.Events.SourceFileChanged, this._sourceFiles[sourceFileId]); |
| } |
| if (!this._formatSourceFiles) |
| sourceFile = new WebInspector.SourceFile(sourceFileId, script, contentChanged.bind(this)); |
| else |
| sourceFile = new WebInspector.FormattedSourceFile(sourceFileId, script, contentChanged.bind(this), this._formatter()); |
| this._sourceFiles[sourceFileId] = sourceFile; |
| |
| this._restoreBreakpoints(sourceFile); |
| |
| this.dispatchEventToListeners(WebInspector.DebuggerPresentationModel.Events.SourceFileAdded, sourceFile); |
| }, |
| |
| _restoreBreakpoints: function(sourceFile) |
| { |
| var pendingBreakpoints = this._breakpointsWithoutSourceFile[sourceFile.id]; |
| for (var i = 0; pendingBreakpoints && i < pendingBreakpoints.length; ++i) { |
| var breakpointData = pendingBreakpoints[i]; |
| if ("debuggerId" in breakpointData) { |
| var breakpoint = new WebInspector.PresentationBreakpoint(sourceFile, breakpointData.lineNumber, breakpointData.condition, breakpointData.enabled); |
| this._bindDebuggerId(breakpoint, breakpointData.debuggerId); |
| this._breakpointAdded(breakpoint); |
| } else |
| this.setBreakpoint(sourceFile.id, breakpointData.lineNumber, breakpointData.condition, breakpointData.enabled, true); |
| } |
| delete this._breakpointsWithoutSourceFile[sourceFile.id]; |
| }, |
| |
| canEditScriptSource: function(sourceFileId) |
| { |
| if (!Preferences.canEditScriptSource || this._formatSourceFiles) |
| return false; |
| var script = this._scriptForSourceFileId(sourceFileId); |
| return !script.lineOffset && !script.columnOffset; |
| }, |
| |
| editScriptSource: function(sourceFileId, newSource, callback) |
| { |
| var script = this._scriptForSourceFileId(sourceFileId); |
| var sourceFile = this._sourceFiles[sourceFileId]; |
| |
| function didEditScriptSource(oldSource, error) |
| { |
| if (!error) { |
| sourceFile.content = newSource; |
| |
| var resource = WebInspector.resourceForURL(sourceFile.url); |
| if (resource) |
| resource.addRevision(newSource); |
| } |
| |
| callback(error); |
| |
| if (!error && WebInspector.debuggerModel.callFrames) |
| this._debuggerPaused(); |
| } |
| |
| var oldSource = sourceFile.requestContent(didReceiveSource.bind(this)); |
| function didReceiveSource(oldSource) |
| { |
| WebInspector.debuggerModel.editScriptSource(script.sourceID, newSource, didEditScriptSource.bind(this, oldSource)); |
| } |
| }, |
| |
| _updateBreakpointsAfterLiveEdit: function(sourceFileId, oldSource, newSource) |
| { |
| var sourceFile = this._sourceFiles[sourceFileId]; |
| |
| // Clear and re-create breakpoints according to text diff. |
| var diff = Array.diff(oldSource.split("\n"), newSource.split("\n")); |
| for (var lineNumber in sourceFile.breakpoints) { |
| var breakpoint = sourceFile.breakpoints[lineNumber]; |
| |
| var lineNumber = breakpoint.lineNumber; |
| this.removeBreakpoint(sourceFileId, lineNumber); |
| |
| var newLineNumber = diff.left[lineNumber].row; |
| if (newLineNumber === undefined) { |
| for (var i = lineNumber - 1; i >= 0; --i) { |
| if (diff.left[i].row === undefined) |
| continue; |
| var shiftedLineNumber = diff.left[i].row + lineNumber - i; |
| if (shiftedLineNumber < diff.right.length) { |
| var originalLineNumber = diff.right[shiftedLineNumber].row; |
| if (originalLineNumber === lineNumber || originalLineNumber === undefined) |
| newLineNumber = shiftedLineNumber; |
| } |
| break; |
| } |
| } |
| if (newLineNumber !== undefined) |
| this.setBreakpoint(sourceFileId, newLineNumber, breakpoint.condition, breakpoint.enabled); |
| } |
| }, |
| |
| toggleFormatSourceFiles: function() |
| { |
| this._formatSourceFiles = !this._formatSourceFiles; |
| |
| for (var id in this._sourceFiles) { |
| var sourceFile = this._sourceFiles[id]; |
| for (var line in sourceFile.breakpoints) |
| this._removeBreakpointFromDebugger(sourceFile.breakpoints[line]); |
| } |
| |
| var messages = this._messages; |
| this._reset(); |
| |
| var scripts = WebInspector.debuggerModel.scripts; |
| for (var id in scripts) |
| this._addScript(scripts[id]); |
| |
| for (var i = 0; i < messages.length; ++i) |
| this.addConsoleMessage(messages[i]); |
| |
| if (WebInspector.debuggerModel.callFrames) |
| this._debuggerPaused(); |
| }, |
| |
| formatSourceFilesToggled: function() |
| { |
| return this._formatSourceFiles; |
| }, |
| |
| _formatter: function() |
| { |
| if (!this._scriptFormatter) |
| this._scriptFormatter = new WebInspector.ScriptFormatter(); |
| return this._scriptFormatter; |
| }, |
| |
| addConsoleMessage: function(message) |
| { |
| this._messages.push(message); |
| |
| var sourceFile = this._sourceFileForScript(message.url); |
| if (!sourceFile) |
| return; |
| |
| function didRequestSourceMapping(mapping) |
| { |
| var presentationMessage = {}; |
| presentationMessage.sourceFileId = sourceFile.id; |
| presentationMessage.lineNumber = mapping.scriptLocationToSourceLine({lineNumber:message.line - 1, columnNumber:0}); |
| presentationMessage.originalMessage = message; |
| sourceFile.messages.push(presentationMessage); |
| this.dispatchEventToListeners(WebInspector.DebuggerPresentationModel.Events.ConsoleMessageAdded, presentationMessage); |
| } |
| sourceFile.requestSourceMapping(didRequestSourceMapping.bind(this)); |
| }, |
| |
| clearConsoleMessages: function() |
| { |
| this._messages = []; |
| for (var id in this._sourceFiles) |
| this._sourceFiles[id].messages = []; |
| }, |
| |
| continueToLine: function(sourceFileId, lineNumber) |
| { |
| function didRequestSourceMapping(mapping) |
| { |
| var location = mapping.sourceLineToScriptLocation(lineNumber); |
| WebInspector.debuggerModel.continueToLocation(location); |
| } |
| this._sourceFiles[sourceFileId].requestSourceMapping(didRequestSourceMapping.bind(this)); |
| }, |
| |
| breakpointsForSourceFileId: function(sourceFileId) |
| { |
| var sourceFile = this.sourceFile(sourceFileId); |
| if (!sourceFile) |
| return []; |
| var breakpoints = []; |
| for (var lineNumber in sourceFile.breakpoints) |
| breakpoints.push(sourceFile.breakpoints[lineNumber]); |
| return breakpoints; |
| }, |
| |
| setBreakpoint: function(sourceFileId, lineNumber, condition, enabled, dontSaveBreakpoints) |
| { |
| var sourceFile = this._sourceFiles[sourceFileId]; |
| if (!sourceFile) |
| return; |
| |
| var breakpoint = new WebInspector.PresentationBreakpoint(sourceFile, lineNumber, condition, enabled); |
| if (!enabled) { |
| this._breakpointAdded(breakpoint); |
| if (!dontSaveBreakpoints) |
| this._saveBreakpoints(); |
| return; |
| } |
| |
| function callback() |
| { |
| this._breakpointAdded(breakpoint); |
| if (!dontSaveBreakpoints) |
| this._saveBreakpoints(); |
| } |
| this._setBreakpointInDebugger(breakpoint, callback.bind(this)); |
| }, |
| |
| _setBreakpointInDebugger: function(breakpoint, callback) |
| { |
| function didSetBreakpoint(breakpointId, locations) |
| { |
| if (!breakpointId) |
| return; |
| |
| this._bindDebuggerId(breakpoint, breakpointId); |
| breakpoint.location = locations[0]; |
| callback(); |
| } |
| |
| function didRequestSourceMapping(mapping) |
| { |
| var location = mapping.sourceLineToScriptLocation(breakpoint.lineNumber); |
| var script = WebInspector.debuggerModel.scriptForSourceID(location.sourceID); |
| if (script.sourceURL) |
| WebInspector.debuggerModel.setBreakpoint(script.sourceURL, location.lineNumber, location.columnNumber, breakpoint.condition, didSetBreakpoint.bind(this)); |
| else { |
| location.sourceID = script.sourceID; |
| WebInspector.debuggerModel.setBreakpointBySourceId(location, breakpoint.condition, didSetBreakpoint.bind(this)); |
| } |
| } |
| breakpoint.sourceFile.requestSourceMapping(didRequestSourceMapping.bind(this)); |
| }, |
| |
| _removeBreakpointFromDebugger: function(breakpoint, callback) |
| { |
| if (!("debuggerId" in breakpoint)) { |
| if (callback) |
| callback(); |
| return; |
| } |
| |
| function didRemoveBreakpoint() |
| { |
| this._unbindDebuggerId(breakpoint); |
| if (callback) |
| callback(); |
| } |
| WebInspector.debuggerModel.removeBreakpoint(breakpoint.debuggerId, didRemoveBreakpoint.bind(this)); |
| }, |
| |
| _bindDebuggerId: function(breakpoint, debuggerId) |
| { |
| breakpoint.debuggerId = debuggerId; |
| this._breakpointsByDebuggerId[debuggerId] = breakpoint; |
| }, |
| |
| _unbindDebuggerId: function(breakpoint) |
| { |
| delete this._breakpointsByDebuggerId[breakpoint.debuggerId]; |
| delete breakpoint.debuggerId; |
| }, |
| |
| setBreakpointEnabled: function(sourceFileId, lineNumber, enabled) |
| { |
| var breakpoint = this.findBreakpoint(sourceFileId, lineNumber); |
| if (!breakpoint) |
| return; |
| |
| this.dispatchEventToListeners(WebInspector.DebuggerPresentationModel.Events.BreakpointRemoved, breakpoint); |
| |
| breakpoint.enabled = enabled; |
| |
| function afterUpdate() |
| { |
| this.dispatchEventToListeners(WebInspector.DebuggerPresentationModel.Events.BreakpointAdded, breakpoint); |
| this._saveBreakpoints(); |
| } |
| |
| if (!enabled) |
| this._removeBreakpointFromDebugger(breakpoint, afterUpdate.call(this)); |
| else |
| this._setBreakpointInDebugger(breakpoint, afterUpdate.bind(this)); |
| }, |
| |
| updateBreakpoint: function(sourceFileId, lineNumber, condition, enabled) |
| { |
| this.removeBreakpoint(sourceFileId, lineNumber); |
| this.setBreakpoint(sourceFileId, lineNumber, condition, enabled); |
| }, |
| |
| removeBreakpoint: function(sourceFileId, lineNumber) |
| { |
| var breakpoint = this.findBreakpoint(sourceFileId, lineNumber); |
| if (!breakpoint) |
| return; |
| |
| function callback() |
| { |
| this._breakpointRemoved(breakpoint); |
| this._saveBreakpoints(); |
| } |
| this._removeBreakpointFromDebugger(breakpoint, callback.bind(this)); |
| }, |
| |
| findBreakpoint: function(sourceFileId, lineNumber) |
| { |
| var sourceFile = this.sourceFile(sourceFileId); |
| if (sourceFile) |
| return sourceFile.breakpoints[lineNumber]; |
| }, |
| |
| _breakpointAdded: function(breakpoint) |
| { |
| var sourceFile = breakpoint.sourceFile; |
| if (!sourceFile) |
| return; |
| |
| function didRequestSourceMapping(mapping) |
| { |
| // Refine line number based on resolved location. |
| if (breakpoint.location) |
| breakpoint.lineNumber = mapping.scriptLocationToSourceLine(breakpoint.location); |
| |
| var existingBreakpoint = this.findBreakpoint(sourceFile.id, breakpoint.lineNumber); |
| if (existingBreakpoint) { |
| // We can't show more than one breakpoint on a single source file line. |
| this._removeBreakpointFromDebugger(breakpoint); |
| return; |
| } |
| sourceFile.breakpoints[breakpoint.lineNumber] = breakpoint; |
| this.dispatchEventToListeners(WebInspector.DebuggerPresentationModel.Events.BreakpointAdded, breakpoint); |
| } |
| sourceFile.requestSourceMapping(didRequestSourceMapping.bind(this)); |
| }, |
| |
| _breakpointRemoved: function(breakpoint) |
| { |
| var sourceFile = breakpoint.sourceFile; |
| if (sourceFile.breakpoints[breakpoint.lineNumber] === breakpoint) { |
| // There can already be a newer breakpoint; |
| delete sourceFile.breakpoints[breakpoint.lineNumber]; |
| this.dispatchEventToListeners(WebInspector.DebuggerPresentationModel.Events.BreakpointRemoved, breakpoint); |
| } |
| }, |
| |
| _breakpointResolved: function(event) |
| { |
| var debuggerId = event.data.breakpointId; |
| if (!(debuggerId in this._breakpointsByDebuggerId)) |
| return; |
| var breakpoint = this._breakpointsByDebuggerId[debuggerId]; |
| |
| this._breakpointRemoved(breakpoint); |
| breakpoint.location = event.data.location; |
| this._breakpointAdded(breakpoint); |
| }, |
| |
| _restoreBreakpointsFromSettings: function() |
| { |
| var breakpoints = WebInspector.settings.breakpoints; |
| for (var i = 0; i < breakpoints.length; ++i) { |
| var breakpointData = breakpoints[i]; |
| var sourceFileId = breakpointData.sourceFileId; |
| if (!sourceFileId) |
| continue; |
| var sourceFile = this._sourceFiles[sourceFileId]; |
| if (sourceFile) { |
| this.setBreakpoint(sourceFileId, breakpointData.lineNumber, breakpointData.condition, breakpointData.enabled); |
| continue; |
| } |
| |
| // Add breakpoint once source file becomes available. |
| var pendingBreakpoints = this._breakpointsWithoutSourceFile[sourceFileId]; |
| if (!pendingBreakpoints) { |
| pendingBreakpoints = []; |
| this._breakpointsWithoutSourceFile[sourceFileId] = pendingBreakpoints; |
| } |
| pendingBreakpoints.push(breakpointData); |
| } |
| }, |
| |
| _saveBreakpoints: function() |
| { |
| var serializedBreakpoints = []; |
| |
| // Store added breakpoints. |
| for (var sourceFileId in this._sourceFiles) { |
| var sourceFile = this._sourceFiles[sourceFileId]; |
| if (!sourceFile.url) |
| continue; |
| |
| for (var lineNumber in sourceFile.breakpoints) |
| serializedBreakpoints.push(sourceFile.breakpoints[lineNumber].serialize()); |
| } |
| |
| // Store not added breakpoints. |
| for (var sourceFileId in this._breakpointsWithoutSourceFile) |
| serializedBreakpoints = serializedBreakpoints.concat(this._breakpointsWithoutSourceFile[sourceFileId]); |
| |
| // Sanitize debugger ids. |
| for (var i = 0; i < serializedBreakpoints.length; ++i) { |
| var breakpoint = serializedBreakpoints[i]; |
| var breakpointCopy = {}; |
| for (var property in breakpoint) { |
| if (property !== "debuggerId") |
| breakpointCopy[property] = breakpoint[property]; |
| } |
| serializedBreakpoints[i] = breakpointCopy; |
| } |
| |
| WebInspector.settings.breakpoints = serializedBreakpoints; |
| }, |
| |
| _debuggerPaused: function() |
| { |
| var callFrames = WebInspector.debuggerModel.callFrames; |
| this._presentationCallFrames = []; |
| for (var i = 0; i < callFrames.length; ++i) { |
| var callFrame = callFrames[i]; |
| var sourceFile; |
| var script = WebInspector.debuggerModel.scriptForSourceID(callFrame.location.sourceID); |
| if (script) |
| sourceFile = this._sourceFileForScript(script.sourceURL, script.sourceID); |
| this._presentationCallFrames.push(new WebInspector.PresenationCallFrame(callFrame, i, sourceFile)); |
| } |
| var details = WebInspector.debuggerModel.debuggerPausedDetails; |
| this.dispatchEventToListeners(WebInspector.DebuggerPresentationModel.Events.DebuggerPaused, { callFrames: this._presentationCallFrames, details: details }); |
| |
| this.selectedCallFrame = this._presentationCallFrames[this._selectedCallFrameIndex]; |
| }, |
| |
| _debuggerResumed: function() |
| { |
| this._presentationCallFrames = []; |
| this._selectedCallFrameIndex = 0; |
| this.dispatchEventToListeners(WebInspector.DebuggerPresentationModel.Events.DebuggerResumed); |
| }, |
| |
| set selectedCallFrame(callFrame) |
| { |
| this._selectedCallFrameIndex = callFrame.index; |
| callFrame.select(); |
| this.dispatchEventToListeners(WebInspector.DebuggerPresentationModel.Events.CallFrameSelected, callFrame); |
| }, |
| |
| get selectedCallFrame() |
| { |
| return this._presentationCallFrames[this._selectedCallFrameIndex]; |
| }, |
| |
| _sourceFileForScript: function(sourceURL, sourceID) |
| { |
| return this._sourceFiles[this._createSourceFileId(sourceURL, sourceID)]; |
| }, |
| |
| _scriptForSourceFileId: function(sourceFileId) |
| { |
| function filter(script) |
| { |
| return this._createSourceFileId(script.sourceURL, script.sourceID) === sourceFileId; |
| } |
| return WebInspector.debuggerModel.queryScripts(filter.bind(this))[0]; |
| }, |
| |
| _createSourceFileId: function(sourceURL, sourceID) |
| { |
| var prefix = this._formatSourceFiles ? "deobfuscated:" : ""; |
| return prefix + (sourceURL || sourceID); |
| }, |
| |
| _reset: function() |
| { |
| for (var id in this._sourceFiles) { |
| var sourceFile = this._sourceFiles[id]; |
| for (var line in sourceFile.breakpoints) { |
| var breakpoints = this._breakpointsWithoutSourceFile[sourceFile.id]; |
| if (!breakpoints) { |
| breakpoints = []; |
| this._breakpointsWithoutSourceFile[sourceFile.id] = breakpoints; |
| } |
| breakpoints.push(sourceFile.breakpoints[line].serialize()); |
| } |
| } |
| |
| this._sourceFiles = {}; |
| this._messages = []; |
| this._breakpointsByDebuggerId = {}; |
| }, |
| |
| _debuggerReset: function() |
| { |
| this._reset(); |
| this._presentationCallFrames = []; |
| this._selectedCallFrameIndex = 0; |
| } |
| } |
| |
| WebInspector.DebuggerPresentationModel.prototype.__proto__ = WebInspector.Object.prototype; |
| |
| WebInspector.PresentationBreakpoint = function(sourceFile, lineNumber, condition, enabled) |
| { |
| this.sourceFile = sourceFile; |
| this.sourceFileId = sourceFile.id; |
| this.lineNumber = lineNumber; |
| this.condition = condition; |
| this.enabled = enabled; |
| } |
| |
| WebInspector.PresentationBreakpoint.prototype = { |
| get url() |
| { |
| return this.sourceFile.url; |
| }, |
| |
| get resolved() |
| { |
| return !!this.location; |
| }, |
| |
| loadSnippet: function(callback) |
| { |
| function didRequestContent(mimeType, content) |
| { |
| var lineEndings = content.lineEndings(); |
| var snippet = ""; |
| if (this.lineNumber < lineEndings.length) |
| snippet = content.substring(lineEndings[this.lineNumber - 1], lineEndings[this.lineNumber]); |
| callback(snippet); |
| } |
| if (!this.sourceFile) { |
| callback(WebInspector.UIString("N/A")); |
| return; |
| } |
| this.sourceFile.requestContent(didRequestContent.bind(this)); |
| }, |
| |
| serialize: function() |
| { |
| var serializedBreakpoint = {}; |
| serializedBreakpoint.sourceFileId = this.sourceFile.id; |
| serializedBreakpoint.lineNumber = this.lineNumber; |
| serializedBreakpoint.condition = this.condition; |
| serializedBreakpoint.enabled = this.enabled; |
| serializedBreakpoint.debuggerId = this.debuggerId; |
| return serializedBreakpoint; |
| } |
| } |
| |
| WebInspector.PresenationCallFrame = function(callFrame, index, sourceFile) |
| { |
| this._callFrame = callFrame; |
| this._index = index; |
| this._sourceFile = sourceFile; |
| this._script = WebInspector.debuggerModel.scriptForSourceID(callFrame.location.sourceID); |
| } |
| |
| WebInspector.PresenationCallFrame.prototype = { |
| get functionName() |
| { |
| return this._callFrame.functionName; |
| }, |
| |
| get type() |
| { |
| return this._callFrame.type; |
| }, |
| |
| get isInternalScript() |
| { |
| return !this._script; |
| }, |
| |
| get url() |
| { |
| if (this._sourceFile) |
| return this._sourceFile.url; |
| }, |
| |
| get scopeChain() |
| { |
| return this._callFrame.scopeChain; |
| }, |
| |
| get index() |
| { |
| return this._index; |
| }, |
| |
| select: function() |
| { |
| if (this._sourceFile) |
| this._sourceFile.forceLoadContent(this._script); |
| }, |
| |
| evaluate: function(code, objectGroup, includeCommandLineAPI, callback) |
| { |
| function didEvaluateOnCallFrame(error, result) |
| { |
| callback(WebInspector.RemoteObject.fromPayload(result)); |
| } |
| DebuggerAgent.evaluateOnCallFrame(this._callFrame.id, code, objectGroup, includeCommandLineAPI, didEvaluateOnCallFrame.bind(this)); |
| }, |
| |
| sourceLine: function(callback) |
| { |
| if (!this._sourceFile) { |
| callback(undefined, this._callFrame.location.lineNumber); |
| return; |
| } |
| |
| function didRequestSourceMapping(mapping) |
| { |
| callback(this._sourceFile.id, mapping.scriptLocationToSourceLine(this._callFrame.location)); |
| } |
| this._sourceFile.requestSourceMapping(didRequestSourceMapping.bind(this)); |
| } |
| } |
| |
| WebInspector.DebuggerPresentationModelResourceBinding = function(model) |
| { |
| this._presentationModel = model; |
| WebInspector.Resource.registerDomainModelBinding(WebInspector.Resource.Type.Script, this); |
| } |
| |
| WebInspector.DebuggerPresentationModelResourceBinding.prototype = { |
| canSetContent: function(resource) |
| { |
| var sourceFile = this._presentationModel._sourceFileForScript(resource.url) |
| if (!sourceFile) |
| return false; |
| return this._presentationModel.canEditScriptSource(sourceFile.id); |
| }, |
| |
| setContent: function(resource, content, majorChange, userCallback) |
| { |
| if (!majorChange) |
| return; |
| |
| var sourceFile = this._presentationModel._sourceFileForScript(resource.url); |
| if (!sourceFile) { |
| userCallback("Resource is not editable"); |
| return; |
| } |
| |
| resource.requestContent(this._setContentWithInitialContent.bind(this, sourceFile, content, userCallback)); |
| }, |
| |
| _setContentWithInitialContent: function(sourceFile, content, userCallback, oldContent) |
| { |
| function callback(error) |
| { |
| if (userCallback) |
| userCallback(error); |
| if (!error) { |
| this._presentationModel._updateBreakpointsAfterLiveEdit(sourceFile.id, oldContent, content); |
| sourceFile.reload(); |
| } |
| } |
| this._presentationModel.editScriptSource(sourceFile.id, content, callback.bind(this)); |
| } |
| } |
| |
| WebInspector.DebuggerPresentationModelResourceBinding.prototype.__proto__ = WebInspector.ResourceDomainModelBinding.prototype; |