WebInspector.DebuggerModel = function()
{
this._debuggerPausedDetails = null;
this._scripts = {};
this._scriptsBySourceURL = {};
this._canSetScriptSource = false;
this._breakpointsActive = true;
InspectorBackend.registerDebuggerDispatcher(new WebInspector.DebuggerDispatcher(this));
}
WebInspector.DebuggerModel.Location = function(script, lineNumber, columnNumber)
{
this.scriptId = script.scriptId;
this.lineNumber = lineNumber;
this.columnNumber = columnNumber;
}
WebInspector.DebuggerModel.Events = {
DebuggerWasEnabled: "DebuggerWasEnabled",
DebuggerWasDisabled: "DebuggerWasDisabled",
DebuggerPaused: "DebuggerPaused",
DebuggerResumed: "DebuggerResumed",
ParsedScriptSource: "ParsedScriptSource",
FailedToParseScriptSource: "FailedToParseScriptSource",
BreakpointResolved: "BreakpointResolved",
GlobalObjectCleared: "GlobalObjectCleared",
CallFrameSelected: "CallFrameSelected",
ExecutionLineChanged: "ExecutionLineChanged",
ConsoleCommandEvaluatedInSelectedCallFrame: "ConsoleCommandEvaluatedInSelectedCallFrame",
BreakpointsActiveStateChanged: "BreakpointsActiveStateChanged"
}
WebInspector.DebuggerModel.BreakReason = {
DOM: "DOM",
EventListener: "EventListener",
XHR: "XHR",
Exception: "exception"
}
WebInspector.DebuggerModel.prototype = {
enableDebugger: function()
{
function callback(error, result)
{
this._canSetScriptSource = result;
}
DebuggerAgent.canSetScriptSource(callback.bind(this));
DebuggerAgent.enable(this._debuggerWasEnabled.bind(this));
},
disableDebugger: function()
{
DebuggerAgent.disable(this._debuggerWasDisabled.bind(this));
},
canSetScriptSource: function()
{
return this._canSetScriptSource;
},
_debuggerWasEnabled: function()
{
this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerWasEnabled);
},
_debuggerWasDisabled: function()
{
this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerWasDisabled);
},
continueToLocation: function(location)
{
DebuggerAgent.continueToLocation(location);
},
setBreakpointByScriptLocation: function(location, condition, callback)
{
var script = this.scriptForId(location.scriptId);
if (script.sourceURL)
this.setBreakpoint(script.sourceURL, location.lineNumber, location.columnNumber, condition, callback);
else
this.setBreakpointBySourceId(location, condition, callback);
},
setBreakpoint: function(url, lineNumber, columnNumber, condition, callback)
{
var minColumnNumber = 0;
var scripts = this._scriptsBySourceURL[url] || [];
for (var i = 0, l = scripts.length; i < l; ++i) {
var script = scripts[i];
if (lineNumber === script.lineOffset)
minColumnNumber = minColumnNumber ? Math.min(minColumnNumber, script.columnOffset) : script.columnOffset;
}
columnNumber = Math.max(columnNumber, minColumnNumber);
function didSetBreakpoint(error, breakpointId, locations)
{
if (callback)
callback(error ? null : breakpointId, locations);
}
DebuggerAgent.setBreakpointByUrl(lineNumber, url, undefined, columnNumber, condition, didSetBreakpoint.bind(this));
WebInspector.userMetrics.ScriptsBreakpointSet.record();
},
setBreakpointBySourceId: function(location, condition, callback)
{
function didSetBreakpoint(error, breakpointId, actualLocation)
{
if (callback)
callback(error ? null : breakpointId, [actualLocation]);
}
DebuggerAgent.setBreakpoint(location, condition, didSetBreakpoint.bind(this));
WebInspector.userMetrics.ScriptsBreakpointSet.record();
},
removeBreakpoint: function(breakpointId, callback)
{
DebuggerAgent.removeBreakpoint(breakpointId, callback);
},
_breakpointResolved: function(breakpointId, location)
{
this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointResolved, {breakpointId: breakpointId, location: location});
},
_globalObjectCleared: function()
{
this._setDebuggerPausedDetails(null);
this._reset();
this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.GlobalObjectCleared);
},
_reset: function()
{
this._scripts = {};
this._scriptsBySourceURL = {};
},
get scripts()
{
return this._scripts;
},
scriptForId: function(scriptId)
{
return this._scripts[scriptId] || null;
},
setScriptSource: function(scriptId, newSource, callback)
{
this._scripts[scriptId].editSource(newSource, this._didEditScriptSource.bind(this, scriptId, newSource, callback));
},
_didEditScriptSource: function(scriptId, newSource, callback, error, callFrames)
{
callback(error);
if (!error && callFrames && callFrames.length)
this._pausedScript(callFrames, this._debuggerPausedDetails.reason, this._debuggerPausedDetails.auxData);
},
get callFrames()
{
return this._debuggerPausedDetails ? this._debuggerPausedDetails.callFrames : null;
},
debuggerPausedDetails: function()
{
return this._debuggerPausedDetails;
},
_setDebuggerPausedDetails: function(debuggerPausedDetails)
{
if (this._debuggerPausedDetails)
this._debuggerPausedDetails.dispose();
this._debuggerPausedDetails = debuggerPausedDetails;
if (this._debuggerPausedDetails)
this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPausedDetails);
if (debuggerPausedDetails)
this.setSelectedCallFrame(debuggerPausedDetails.callFrames[0]);
else
this.setSelectedCallFrame(null);
},
_pausedScript: function(callFrames, reason, auxData)
{
this._setDebuggerPausedDetails(new WebInspector.DebuggerPausedDetails(this, callFrames, reason, auxData));
},
_resumedScript: function()
{
this._setDebuggerPausedDetails(null);
if (this._executionLineLiveLocation)
this._executionLineLiveLocation.dispose();
this._executionLineLiveLocation = null;
this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerResumed);
},
_parsedScriptSource: function(scriptId, sourceURL, startLine, startColumn, endLine, endColumn, isContentScript, sourceMapURL)
{
var script = new WebInspector.Script(scriptId, sourceURL, startLine, startColumn, endLine, endColumn, isContentScript, sourceMapURL);
this._registerScript(script);
this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.ParsedScriptSource, script);
},
_registerScript: function(script)
{
this._scripts[script.scriptId] = script;
if (script.sourceURL) {
var scripts = this._scriptsBySourceURL[script.sourceURL];
if (!scripts) {
scripts = [];
this._scriptsBySourceURL[script.sourceURL] = scripts;
}
scripts.push(script);
}
},
_failedToParseScriptSource: function(sourceURL, source, startingLine, errorLine, errorMessage)
{
var script = new WebInspector.Script("", sourceURL, startingLine, 0, 0, 0, false);
this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.FailedToParseScriptSource, script);
},
createRawLocation: function(script, lineNumber, columnNumber)
{
if (script.sourceURL)
return this.createRawLocationByURL(script.sourceURL, lineNumber, columnNumber)
return new WebInspector.DebuggerModel.Location(script, lineNumber, columnNumber);
},
createRawLocationByURL: function(sourceURL, lineNumber, columnNumber)
{
var closestScript = null;
var scripts = this._scriptsBySourceURL[sourceURL] || [];
for (var i = 0, l = scripts.length; i < l; ++i) {
var script = scripts[i];
if (!closestScript)
closestScript = script;
if (script.lineOffset > lineNumber || (script.lineOffset === lineNumber && script.columnOffset > columnNumber))
continue;
if (script.endLine < lineNumber || (script.endLine === lineNumber && script.endColumn <= columnNumber))
continue;
closestScript = script;
break;
}
return closestScript ? new WebInspector.DebuggerModel.Location(closestScript, lineNumber, columnNumber) : null;
},
isPaused: function()
{
return !!this.debuggerPausedDetails();
},
setSelectedCallFrame: function(callFrame)
{
if (this._executionLineLiveLocation)
this._executionLineLiveLocation.dispose();
delete this._executionLineLiveLocation;
this._selectedCallFrame = callFrame;
if (!this._selectedCallFrame)
return;
this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.CallFrameSelected, callFrame);
function updateExecutionLine(uiLocation)
{
this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.ExecutionLineChanged, uiLocation);
}
this._executionLineLiveLocation = callFrame.script.createLiveLocation(callFrame._payload.location, updateExecutionLine.bind(this));
},
selectedCallFrame: function()
{
return this._selectedCallFrame;
},
evaluateOnSelectedCallFrame: function(code, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, callback)
{
function didEvaluate(result, wasThrown)
{
if (returnByValue)
callback(null, !!wasThrown, wasThrown ? null : result);
else
callback(WebInspector.RemoteObject.fromPayload(result), !!wasThrown);
if (objectGroup === "console")
this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.ConsoleCommandEvaluatedInSelectedCallFrame);
}
this.selectedCallFrame().evaluate(code, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, didEvaluate.bind(this));
},
getSelectedCallFrameVariables: function(callback)
{
var result = { this: true };
var selectedCallFrame = this._selectedCallFrame;
if (!selectedCallFrame)
callback(result);
var pendingRequests = 0;
function propertiesCollected(properties)
{
for (var i = 0; properties && i < properties.length; ++i)
result[properties[i].name] = true;
if (--pendingRequests == 0)
callback(result);
}
for (var i = 0; i < selectedCallFrame.scopeChain.length; ++i) {
var scope = selectedCallFrame.scopeChain[i];
var object = WebInspector.RemoteObject.fromPayload(scope.object);
pendingRequests++;
object.getAllProperties(propertiesCollected);
}
},
setBreakpointsActive: function(active)
{
if (this._breakpointsActive === active)
return;
this._breakpointsActive = active;
DebuggerAgent.setBreakpointsActive(active);
this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointsActiveStateChanged, active);
},
breakpointsActive: function()
{
return this._breakpointsActive;
},
createLiveLocation: function(location, updateDelegate)
{
var script = this._scripts[location.scriptId];
return script.createLiveLocation(location, updateDelegate);
},
rawLocationToUILocation: function(rawLocation)
{
var script = this._scripts[rawLocation.scriptId];
if (!script)
return null;
return script.rawLocationToUILocation(rawLocation);
}
}
WebInspector.DebuggerModel.prototype.__proto__ = WebInspector.Object.prototype;
WebInspector.DebuggerEventTypes = {
JavaScriptPause: 0,
JavaScriptBreakpoint: 1,
NativeBreakpoint: 2
};
WebInspector.DebuggerDispatcher = function(debuggerModel)
{
this._debuggerModel = debuggerModel;
}
WebInspector.DebuggerDispatcher.prototype = {
paused: function(callFrames, reason, auxData)
{
this._debuggerModel._pausedScript(callFrames, reason, auxData);
},
resumed: function()
{
this._debuggerModel._resumedScript();
},
globalObjectCleared: function()
{
this._debuggerModel._globalObjectCleared();
},
scriptParsed: function(scriptId, sourceURL, startLine, startColumn, endLine, endColumn, isContentScript, sourceMapURL)
{
this._debuggerModel._parsedScriptSource(scriptId, sourceURL, startLine, startColumn, endLine, endColumn, !!isContentScript, sourceMapURL);
},
scriptFailedToParse: function(sourceURL, source, startingLine, errorLine, errorMessage)
{
this._debuggerModel._failedToParseScriptSource(sourceURL, source, startingLine, errorLine, errorMessage);
},
breakpointResolved: function(breakpointId, location)
{
this._debuggerModel._breakpointResolved(breakpointId, location);
}
}
WebInspector.DebuggerModel.CallFrame = function(script, payload)
{
this._script = script;
this._payload = payload;
this._locations = [];
}
WebInspector.DebuggerModel.CallFrame.prototype = {
get script()
{
return this._script;
},
get type()
{
return this._payload.type;
},
get scopeChain()
{
return this._payload.scopeChain;
},
get this()
{
return this._payload.this;
},
get functionName()
{
return this._payload.functionName;
},
get location()
{
return this._payload.location;
},
evaluate: function(code, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, callback)
{
function didEvaluateOnCallFrame(error, result, wasThrown)
{
if (error) {
console.error(error);
callback(null, false);
return;
}
callback(result, wasThrown);
}
DebuggerAgent.evaluateOnCallFrame(this._payload.callFrameId, code, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, didEvaluateOnCallFrame.bind(this));
},
createLiveLocation: function(updateDelegate)
{
var location = this._script.createLiveLocation(this._payload.location, updateDelegate);
this._locations.push(location);
return location;
},
dispose: function(updateDelegate)
{
for (var i = 0; i < this._locations.length; ++i)
this._locations[i].dispose();
this._locations = [];
}
}
WebInspector.DebuggerPausedDetails = function(model, callFrames, reason, auxData)
{
this.callFrames = [];
for (var i = 0; i < callFrames.length; ++i) {
var callFrame = callFrames[i];
var script = model.scriptForId(callFrame.location.scriptId);
if (script)
this.callFrames.push(new WebInspector.DebuggerModel.CallFrame(script, callFrame));
}
this.reason = reason;
this.auxData = auxData;
}
WebInspector.DebuggerPausedDetails.prototype = {
dispose: function()
{
for (var i = 0; i < this.callFrames.length; ++i) {
var callFrame = this.callFrames[i];
callFrame.dispose();
}
}
}
WebInspector.debuggerModel = null;