Implements the rest of the Scripts panel to get the debugger
authortimothy@apple.com <timothy@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 May 2008 22:30:45 +0000 (22:30 +0000)
committertimothy@apple.com <timothy@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 May 2008 22:30:45 +0000 (22:30 +0000)
mostly working. "Basic debugging seems to work."

Reviewed by Geoff Garen.

* English.lproj/localizedStrings.js: Adds new strings.
* page/inspector/Resource.js:
(WebInspector.Resource.prototype.get scripts): Returns _scripts and
creates it lazily.
(WebInspector.Resource.prototype.addScript): Add the script object to the
front of the _scripts array.
(WebInspector.Resource.prototype.removeAllScripts): Removed all the scripts
and removes the resource back-reference.
(WebInspector.Resource.prototype.removeScript): Removes the script and
breaks the resource back-reference.
* page/inspector/ResourceView.js:
(WebInspector.ResourceView): Adds a reminder comment.
(WebInspector.ResourceView.prototype.get headersVisible): Returns _headersVisible.
(WebInspector.ResourceView.prototype.set headersVisible): Stubs out
a setter that currently just sets _headersVisible. Has a comment that
points out this needs implemented when network headers are added.
* page/inspector/ResourcesPanel.js:
(WebInspector.ResourcesPanel.prototype.show): Sets the headersVisible property of
the visible view to true and shows it again, in case it was being shown in Scripts.
(WebInspector.ResourcesPanel.prototype.recreateViewForResourceIfNeeded):
Copies the headersVisible property from the old view to the new view.
(WebInspector.ResourcesPanel.prototype.showResource): Sets the headersVisible
property to true before showing.
* page/inspector/ScriptView.js:
(WebInspector.ScriptView): Passes in _addBreakpoint for the add breakpoint delegate.
(WebInspector.ScriptView.prototype._addBreakpoint): Calls ScriptsPanel's addBreakpoint
for the current Script.sourceID and line.
* page/inspector/ScriptsPanel.js:
(WebInspector.ScriptsPanel):
(WebInspector.ScriptsPanel.prototype.show): Sets the headersVisible property of
the visible view to false and shows it again, in case it was being shown in Resources.
(WebInspector.ScriptsPanel.prototype.addScript): Makes a new Script object and
adds it to a Resource if one is found. Registers any breakpoint that match
the new Script's source URL, and sets the sourceID of the breakpoints.
(WebInspector.ScriptsPanel.prototype.addBreakpoint): Adds the breakpoint to the
BreakpointsSidebarPane. Also adds it to _breakpointsURLMap so it can be found
later in addScript by URL. Finally adds the breakpoint to the SourceFrame that
represents the resources or script.
(WebInspector.ScriptsPanel.prototype.removeBreakpoint): Removes the breakpoint from
the BreakpointsSidebarPane, _breakpointsURLMap and SourceFrame.
(WebInspector.ScriptsPanel.prototype.debuggerPaused): Update the debugger
state variables, the buttons and the CallStackSidebarPane.
(WebInspector.ScriptsPanel.prototype.reset): Clears and resets debugger
and interface state.
(WebInspector.ScriptsPanel.prototype.get visibleView): Returns _visibleView.
(WebInspector.ScriptsPanel.prototype.set visibleView): Sets _visibleView and
calls hide on the old view and show on the new view.
(WebInspector.ScriptsPanel.prototype.showScript): Calls _showScriptOrResource.
(WebInspector.ScriptsPanel.prototype.showResource): Ditto.
(WebInspector.ScriptsPanel.prototype.scriptViewForScript): Lazily creates a
ScriptView for the Script and returns it.
(WebInspector.ScriptsPanel.prototype.sourceFrameForScript): Returns the SourceFrame
for the Script.
(WebInspector.ScriptsPanel.prototype._sourceFrameForScriptOrResource): Returns the
SourceFrame based on the type of object passed in.
(WebInspector.ScriptsPanel.prototype._showScriptOrResource): Shows the view based on
the type of object passed in. If the object is a resource and there are breakpoints
defined for that Resource URL, then populate the SourceFrame with the breakpoints.
(WebInspector.ScriptsPanel.prototype._addScriptToFilesMenu): Adds a script to the
files menu. If the Script is part of a resource, that resource is added.
(WebInspector.ScriptsPanel.prototype._removeScriptFromFilesMenu): Remove a script from
the files menu. If that script is part of a resource and it is the last script of that
resource, then remove the whole resource.
(WebInspector.ScriptsPanel.prototype._clearCurrentExecutionLine): Clears the execution
line from the SourceFrame that is showing it.
(WebInspector.ScriptsPanel.prototype._callFrameSelected): Event listener for when the
call frame changes in the CallStackSidebarPane. Triggers updates to the ScopeChainSidebarPane
and the visible view.
(WebInspector.ScriptsPanel.prototype._changeVisibleFile): Event listener for the change state
of the files select element.
(WebInspector.ScriptsPanel.prototype._updateDebuggerButtons): Update more of the
buttons to reflect the current debugger state. Updates the status text too.
(WebInspector.ScriptsPanel.prototype._toggleDebugging): Reset the UI and state when
the debugger is attached/detached.
(WebInspector.ScriptsPanel.prototype._togglePause): Call InspectorController.resumeDebugger or
InspectorController.pauseInDebugger depending on the paused state.
(WebInspector.ScriptsPanel.prototype._stepOverClicked): Call InspectorController.stepOverStatementInDebugger.
(WebInspector.ScriptsPanel.prototype._stepIntoClicked): Call InspectorController.stepIntoStatementInDebugger.
(WebInspector.ScriptsPanel.prototype._stepOutClicked): InspectorController.stepOutOfFunctionInDebugger.
* page/inspector/SourceView.js:
(WebInspector.SourceView): Passes in _addBreakpoint for the add breakpoint delegate.
(WebInspector.SourceView.prototype._addBreakpoint): Calls ScriptsPanel's addBreakpoint
for the nearest Script's sourceID and passed in line.
* page/inspector/inspector.css: New style rules for the UI changes.
* page/inspector/inspector.js:
(WebInspector.loaded): Add the ScriptsPanel to the panels list.
(WebInspector.parsedScriptSource): Call ScriptsPanel.addScript.
(WebInspector.failedToParseScriptSource): Ditto.
(WebInspector.pausedScript): Call ScriptsPanel.debuggerPaused.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@33411 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog
WebCore/English.lproj/localizedStrings.js
WebCore/page/inspector/Resource.js
WebCore/page/inspector/ResourceView.js
WebCore/page/inspector/ResourcesPanel.js
WebCore/page/inspector/ScriptView.js
WebCore/page/inspector/ScriptsPanel.js
WebCore/page/inspector/SourceView.js
WebCore/page/inspector/inspector.css
WebCore/page/inspector/inspector.js

index 0545500..23f9afd 100644 (file)
@@ -1,5 +1,102 @@
 2008-05-13  Timothy Hatcher  <timothy@apple.com>
 
+        Implements the rest of the Scripts panel to get the debugger
+        mostly working. "Basic debugging seems to work."
+
+        Reviewed by Geoff Garen.
+
+        * English.lproj/localizedStrings.js: Adds new strings.
+        * page/inspector/Resource.js:
+        (WebInspector.Resource.prototype.get scripts): Returns _scripts and 
+        creates it lazily.
+        (WebInspector.Resource.prototype.addScript): Add the script object to the
+        front of the _scripts array.
+        (WebInspector.Resource.prototype.removeAllScripts): Removed all the scripts
+        and removes the resource back-reference.
+        (WebInspector.Resource.prototype.removeScript): Removes the script and
+        breaks the resource back-reference.
+        * page/inspector/ResourceView.js:
+        (WebInspector.ResourceView): Adds a reminder comment.
+        (WebInspector.ResourceView.prototype.get headersVisible): Returns _headersVisible. 
+        (WebInspector.ResourceView.prototype.set headersVisible): Stubs out
+        a setter that currently just sets _headersVisible. Has a comment that
+        points out this needs implemented when network headers are added.
+        * page/inspector/ResourcesPanel.js:
+        (WebInspector.ResourcesPanel.prototype.show): Sets the headersVisible property of
+        the visible view to true and shows it again, in case it was being shown in Scripts.
+        (WebInspector.ResourcesPanel.prototype.recreateViewForResourceIfNeeded):
+        Copies the headersVisible property from the old view to the new view.
+        (WebInspector.ResourcesPanel.prototype.showResource): Sets the headersVisible
+        property to true before showing.
+        * page/inspector/ScriptView.js:
+        (WebInspector.ScriptView): Passes in _addBreakpoint for the add breakpoint delegate.
+        (WebInspector.ScriptView.prototype._addBreakpoint): Calls ScriptsPanel's addBreakpoint
+        for the current Script.sourceID and line.
+        * page/inspector/ScriptsPanel.js:
+        (WebInspector.ScriptsPanel): 
+        (WebInspector.ScriptsPanel.prototype.show): Sets the headersVisible property of
+        the visible view to false and shows it again, in case it was being shown in Resources.
+        (WebInspector.ScriptsPanel.prototype.addScript): Makes a new Script object and
+        adds it to a Resource if one is found. Registers any breakpoint that match
+        the new Script's source URL, and sets the sourceID of the breakpoints.
+        (WebInspector.ScriptsPanel.prototype.addBreakpoint): Adds the breakpoint to the
+        BreakpointsSidebarPane. Also adds it to _breakpointsURLMap so it can be found
+        later in addScript by URL. Finally adds the breakpoint to the SourceFrame that
+        represents the resources or script.
+        (WebInspector.ScriptsPanel.prototype.removeBreakpoint): Removes the breakpoint from
+        the BreakpointsSidebarPane, _breakpointsURLMap and SourceFrame.
+        (WebInspector.ScriptsPanel.prototype.debuggerPaused): Update the debugger
+        state variables, the buttons and the CallStackSidebarPane.
+        (WebInspector.ScriptsPanel.prototype.reset): Clears and resets debugger
+        and interface state.
+        (WebInspector.ScriptsPanel.prototype.get visibleView): Returns _visibleView.
+        (WebInspector.ScriptsPanel.prototype.set visibleView): Sets _visibleView and
+        calls hide on the old view and show on the new view.
+        (WebInspector.ScriptsPanel.prototype.showScript): Calls _showScriptOrResource.
+        (WebInspector.ScriptsPanel.prototype.showResource): Ditto.
+        (WebInspector.ScriptsPanel.prototype.scriptViewForScript): Lazily creates a
+        ScriptView for the Script and returns it. 
+        (WebInspector.ScriptsPanel.prototype.sourceFrameForScript): Returns the SourceFrame
+        for the Script.
+        (WebInspector.ScriptsPanel.prototype._sourceFrameForScriptOrResource): Returns the
+        SourceFrame based on the type of object passed in.
+        (WebInspector.ScriptsPanel.prototype._showScriptOrResource): Shows the view based on
+        the type of object passed in. If the object is a resource and there are breakpoints
+        defined for that Resource URL, then populate the SourceFrame with the breakpoints.
+        (WebInspector.ScriptsPanel.prototype._addScriptToFilesMenu): Adds a script to the 
+        files menu. If the Script is part of a resource, that resource is added.
+        (WebInspector.ScriptsPanel.prototype._removeScriptFromFilesMenu): Remove a script from
+        the files menu. If that script is part of a resource and it is the last script of that
+        resource, then remove the whole resource.
+        (WebInspector.ScriptsPanel.prototype._clearCurrentExecutionLine): Clears the execution
+        line from the SourceFrame that is showing it.
+        (WebInspector.ScriptsPanel.prototype._callFrameSelected): Event listener for when the
+        call frame changes in the CallStackSidebarPane. Triggers updates to the ScopeChainSidebarPane
+        and the visible view.
+        (WebInspector.ScriptsPanel.prototype._changeVisibleFile): Event listener for the change state
+        of the files select element.
+        (WebInspector.ScriptsPanel.prototype._updateDebuggerButtons): Update more of the 
+        buttons to reflect the current debugger state. Updates the status text too.
+        (WebInspector.ScriptsPanel.prototype._toggleDebugging): Reset the UI and state when
+        the debugger is attached/detached.
+        (WebInspector.ScriptsPanel.prototype._togglePause): Call InspectorController.resumeDebugger or
+        InspectorController.pauseInDebugger depending on the paused state.
+        (WebInspector.ScriptsPanel.prototype._stepOverClicked): Call InspectorController.stepOverStatementInDebugger.
+        (WebInspector.ScriptsPanel.prototype._stepIntoClicked): Call InspectorController.stepIntoStatementInDebugger.
+        (WebInspector.ScriptsPanel.prototype._stepOutClicked): InspectorController.stepOutOfFunctionInDebugger.
+        * page/inspector/SourceView.js:
+        (WebInspector.SourceView): Passes in _addBreakpoint for the add breakpoint delegate.
+        (WebInspector.SourceView.prototype._addBreakpoint): Calls ScriptsPanel's addBreakpoint
+        for the nearest Script's sourceID and passed in line.
+        * page/inspector/inspector.css: New style rules for the UI changes.
+        * page/inspector/inspector.js:
+        (WebInspector.loaded): Add the ScriptsPanel to the panels list.
+        (WebInspector.parsedScriptSource): Call ScriptsPanel.addScript.
+        (WebInspector.failedToParseScriptSource): Ditto.
+        (WebInspector.pausedScript): Call ScriptsPanel.debuggerPaused.
+
+2008-05-13  Timothy Hatcher  <timothy@apple.com>
+
         Adds implementations of the Scope Chain and Call Stack sidebar panes.
         These panes use the JSJavaScriptCallFrame object that will be passed
         to the update functions.
index 3a0e7a9..8eaac1a 100644 (file)
Binary files a/WebCore/English.lproj/localizedStrings.js and b/WebCore/English.lproj/localizedStrings.js differ
index b30c145..563e42c 100644 (file)
@@ -390,6 +390,48 @@ WebInspector.Resource.prototype = {
         return this._sortedResponseHeaders;
     },
 
+    get scripts()
+    {
+        if (!("_scripts" in this))
+            this._scripts = [];
+        return this._scripts;
+    },
+
+    addScript: function(script)
+    {
+        if (!script)
+            return;
+        this.scripts.unshift(script);
+        script.resource = this;
+    },
+
+    removeAllScripts: function()
+    {
+        if (!this._scripts)
+            return;
+
+        for (var i = 0; i < this._scripts.length; ++i) {
+            if (this._scripts[i].resource === this)
+                delete this._scripts[i].resource;
+        }
+
+        delete this._scripts;
+    },
+
+    removeScript: function(script)
+    {
+        if (!script)
+            return;
+
+        if (script.resource === this)
+            delete script.resource;
+
+        if (!this._scripts)
+            return;
+
+        this._scripts.remove(script);
+    },
+
     get errors()
     {
         if (!("_errors" in this))
index 73e6971..5372efc 100644 (file)
@@ -34,12 +34,33 @@ WebInspector.ResourceView = function(resource)
 
     this.resource = resource;
 
+    // FIXME: Implement the setter for headersVisible when the header element is added.
+
     this.contentElement = document.createElement("div");
     this.contentElement.className = "resource-view-content";
     this.element.appendChild(this.contentElement);
 }
 
 WebInspector.ResourceView.prototype = {
+    get headersVisible()
+    {
+        return this._headersVisible;
+    },
+
+    set headersVisible(x)
+    {
+        if (x === this._headersVisible)
+            return;
+
+        this._headersVisible = x;
+
+        if (x) {
+            // FIXME: Implement this when headers are added.
+        } else {
+            // FIXME: Implement this when headers are added.
+        }
+    },
+
     attach: function()
     {
         if (!this.element.parentNode)
index 81311fc..b3aa950 100644 (file)
@@ -151,6 +151,12 @@ WebInspector.ResourcesPanel.prototype = {
         this._updateDividersLabelBarPosition();
         this._updateSidebarWidth();
         this.refreshIfNeeded();
+
+        var visibleResourceView = this.visibleResourceView;
+        if (visibleResourceView) {
+            visibleResourceView.headersVisible = true;
+            visibleResourceView.show(this.resourceViews);
+        }
     },
 
     resize: function()
@@ -395,6 +401,8 @@ WebInspector.ResourcesPanel.prototype = {
 
         resource._resourcesView = newView;
 
+        newView.headersVisible = oldView.headersVisible;
+
         if (oldView.visible && oldView.element.parentNode)
             newView.show(oldView.element.parentNode);
     },
@@ -410,6 +418,7 @@ WebInspector.ResourcesPanel.prototype = {
             this.visibleResource._resourcesView.hide();
 
         var view = this.resourceViewForResource(resource);
+        view.headersVisible = true;
         view.show(this.resourceViews);
 
         if (line && view.revealLine)
index dbadf75..d4ce430 100644 (file)
@@ -33,7 +33,7 @@ WebInspector.ScriptView = function(script)
 
     this._frameNeedsSetup = true;
 
-    this.sourceFrame = new WebInspector.SourceFrame();
+    this.sourceFrame = new WebInspector.SourceFrame(null, this._addBreakpoint.bind(this));
 
     this.element.appendChild(this.sourceFrame.element);
 }
@@ -77,6 +77,12 @@ WebInspector.ScriptView.prototype = {
     {
         if (!this.element.parentNode)
             document.getElementById("script-resource-views").appendChild(this.element);
+    },
+
+    _addBreakpoint: function(line)
+    {
+        var breakpoint = new WebInspector.Breakpoint(this.script.sourceURL, line, this.script.sourceID);
+        WebInspector.panels.scripts.addBreakpoint(breakpoint);
     }
 }
 
index dbc0e4c..3f00071 100644 (file)
@@ -53,6 +53,7 @@ WebInspector.ScriptsPanel = function()
     this.filesSelectElement = document.createElement("select");
     this.filesSelectElement.className = "status-bar-item";
     this.filesSelectElement.id = "scripts-files";
+    this.filesSelectElement.addEventListener("change", this._changeVisibleFile.bind(this), false);
     this.topStatusBar.appendChild(this.filesSelectElement);
 
     this.functionsSelectElement = document.createElement("select");
@@ -70,6 +71,7 @@ WebInspector.ScriptsPanel = function()
     this.pauseButton.title = WebInspector.UIString("Pause script execution.");
     this.pauseButton.disabled = true;
     this.pauseButton.appendChild(document.createElement("img"));
+    this.pauseButton.addEventListener("click", this._togglePause.bind(this), false);
     this.sidebarButtonsElement.appendChild(this.pauseButton);
 
     this.stepOverButton = document.createElement("button");
@@ -77,6 +79,7 @@ WebInspector.ScriptsPanel = function()
     this.stepOverButton.id = "scripts-step-over";
     this.stepOverButton.title = WebInspector.UIString("Step over next function call.");
     this.stepOverButton.disabled = true;
+    this.stepOverButton.addEventListener("click", this._stepOverClicked.bind(this), false);
     this.stepOverButton.appendChild(document.createElement("img"));
     this.sidebarButtonsElement.appendChild(this.stepOverButton);
 
@@ -85,6 +88,7 @@ WebInspector.ScriptsPanel = function()
     this.stepIntoButton.id = "scripts-step-into";
     this.stepIntoButton.title = WebInspector.UIString("Step into next function call.");
     this.stepIntoButton.disabled = true;
+    this.stepIntoButton.addEventListener("click", this._stepIntoClicked.bind(this), false);
     this.stepIntoButton.appendChild(document.createElement("img"));
     this.sidebarButtonsElement.appendChild(this.stepIntoButton);
 
@@ -93,6 +97,7 @@ WebInspector.ScriptsPanel = function()
     this.stepOutButton.id = "scripts-step-out";
     this.stepOutButton.title = WebInspector.UIString("Step out of current function.");
     this.stepOutButton.disabled = true;
+    this.stepOutButton.addEventListener("click", this._stepOutClicked.bind(this), false);
     this.stepOutButton.appendChild(document.createElement("img"));
     this.sidebarButtonsElement.appendChild(this.stepOutButton);
 
@@ -117,11 +122,17 @@ WebInspector.ScriptsPanel = function()
 
     this.sidebarPanes = {};
     this.sidebarPanes.callstack = new WebInspector.CallStackSidebarPane();
+    this.sidebarPanes.scopechain = new WebInspector.ScopeChainSidebarPane();
     this.sidebarPanes.breakpoints = new WebInspector.BreakpointsSidebarPane();
 
     for (var pane in this.sidebarPanes)
         this.sidebarElement.appendChild(this.sidebarPanes[pane].element);
 
+    this.sidebarPanes.callstack.expanded = true;
+    this.sidebarPanes.callstack.addEventListener("call frame selected", this._callFrameSelected, this);
+
+    this.sidebarPanes.scopechain.expanded = true;
+
     this.element.appendChild(this.scriptResourceViews);
     this.element.appendChild(this.sidebarElement);
     this.element.appendChild(this.sidebarResizeElement);
@@ -131,6 +142,8 @@ WebInspector.ScriptsPanel = function()
     this.debuggingButton.className = "status-bar-item";
     this.debuggingButton.addEventListener("click", this._toggleDebugging.bind(this), false);
 
+    this._breakpointsURLMap = {};
+
     this.reset();
 }
 
@@ -151,11 +164,315 @@ WebInspector.ScriptsPanel.prototype = {
     {
         WebInspector.Panel.prototype.show.call(this);
         this.sidebarResizeElement.style.right = (this.sidebarElement.offsetWidth - 3) + "px";
+
+        if (this.visibleView) {
+            if (this.visibleView instanceof WebInspector.ResourceView)
+                this.visibleView.headersVisible = false;
+            this.visibleView.show(this.scriptResourceViews);
+        }
+    },
+
+    addScript: function(sourceID, sourceURL, source, startingLine, errorLine, errorMessage)
+    {
+        var script = new WebInspector.Script(sourceID, sourceURL, source, startingLine, errorLine, errorMessage);
+
+        if (sourceURL in WebInspector.resourceURLMap) {
+            var resource = WebInspector.resourceURLMap[sourceURL];
+            resource.addScript(script);
+        }
+
+        if (sourceURL in this._breakpointsURLMap && sourceID) {
+            var breakpoints = this._breakpointsURLMap[sourceURL];
+            var breakpointsLength = breakpoints.length;
+            for (var i = 0; i < breakpointsLength; ++i) {
+                var breakpoint = breakpoints[i];
+                if (startingLine <= breakpoint.line)
+                    breakpoint.sourceID = sourceID;
+            }
+
+            InspectorController.addBreakpoint(breakpoint.sourceID, breakpoint.line);
+        }
+
+        if (sourceID)
+            this._sourceIDMap[sourceID] = (resource || script);
+
+        this._addScriptToFilesMenu(script);
+    },
+
+    addBreakpoint: function(breakpoint)
+    {
+        this.sidebarPanes.breakpoints.addBreakpoint(breakpoint);
+
+        var sourceFrame;
+        if (breakpoint.url) {
+            if (!(breakpoint.url in this._breakpointsURLMap))
+                this._breakpointsURLMap[breakpoint.url] = [];
+            this._breakpointsURLMap[breakpoint.url].unshift(breakpoint);
+
+            if (breakpoint.url in WebInspector.resourceURLMap) {
+                var resource = WebInspector.resourceURLMap[breakpoint.url];
+                sourceFrame = this._sourceFrameForScriptOrResource(resource);
+            }
+        }
+
+        if (breakpoint.sourceID && !sourceFrame) {
+            var object = this._sourceIDMap[breakpoint.sourceID]
+            sourceFrame = this._sourceFrameForScriptOrResource(object);
+        }
+
+        if (sourceFrame)
+            sourceFrame.addBreakpoint(breakpoint);
+    },
+
+    removeBreakpoint: function(breakpoint)
+    {
+        this.sidebarPanes.breakpoints.removeBreakpoint(breakpoint);
+
+        var sourceFrame;
+        if (breakpoint.url && breakpoint.url in this._breakpointsURLMap) {
+            var breakpoints = this._breakpointsURLMap[breakpoint.url];
+            breakpoints.remove(breakpoint);
+            if (!breakpoints.length)
+                delete this._breakpointsURLMap[breakpoint.url];
+
+            if (breakpoint.url in WebInspector.resourceURLMap) {
+                var resource = WebInspector.resourceURLMap[breakpoint.url];
+                sourceFrame = this._sourceFrameForScriptOrResource(resource);
+            }
+        }
+
+        if (breakpoint.sourceID && !sourceFrame) {
+            var object = this._sourceIDMap[breakpoint.sourceID]
+            sourceFrame = this._sourceFrameForScriptOrResource(object);
+        }
+
+        if (sourceFrame)
+            sourceFrame.removeBreakpoint(breakpoint);
+    },
+
+    debuggerPaused: function()
+    {
+        this._paused = true;
+        this._waitingToPause = false;
+        this._stepping = false;
+
+        this._updateDebuggerButtons();
+
+        var callStackPane = this.sidebarPanes.callstack;
+        var currentFrame = InspectorController.currentCallFrame();
+        callStackPane.update(currentFrame);
+        callStackPane.selectedCallFrame = currentFrame;
     },
 
     reset: function()
     {
+        this.visibleView = null;
+
+        this._clearCurrentExecutionLine();
+
+        if (!InspectorController.debuggerAttached()) {
+            this._paused = false;
+            this._waitingToPause = false;
+            this._stepping = false;
+        }
+
+        this.sidebarPanes.callstack.update(null);
+        this.sidebarPanes.scopechain.update(null);
+
         this._updateDebuggerButtons();
+
+        this.filesSelectElement.removeChildren();
+        this.functionsSelectElement.removeChildren();
+        this.scriptResourceViews.removeChildren();
+
+        if (this._sourceIDMap) {
+            for (var sourceID in this._sourceIDMap) {
+                var object = this._sourceIDMap[sourceID];
+                if (object instanceof WebInspector.Resource)
+                    object.removeAllScripts();
+            }
+        }
+
+        this._sourceIDMap = {};
+    },
+
+    get visibleView()
+    {
+        return this._visibleView;
+    },
+
+    set visibleView(x)
+    {
+        if (this._visibleView === x)
+            return;
+
+        if (this._visibleView)
+            this._visibleView.hide();
+
+        this._visibleView = x;
+
+        if (x)
+            x.show(this.scriptResourceViews);
+    },
+
+    showScript: function(script, line)
+    {
+        this._showScriptOrResource(script, line);
+    },
+
+    showResource: function(resource, line)
+    {
+        this._showScriptOrResource(resource, line);
+    },
+
+    scriptViewForScript: function(script)
+    {
+        if (!script)
+            return null;
+        if (!script._scriptView)
+            script._scriptView = new WebInspector.ScriptView(script);
+        return script._scriptView;
+    },
+
+    sourceFrameForScript: function(script)
+    {
+        var view = this.scriptViewForScript(script);
+        if (!view)
+            return null;
+
+        // Setting up the source frame requires that we be attached.
+        if (!this.element.parentNode)
+            this.attach();
+
+        view.setupSourceFrameIfNeeded();
+        return view.sourceFrame;
+    },
+
+    _sourceFrameForScriptOrResource: function(scriptOrResource)
+    {
+        if (scriptOrResource instanceof WebInspector.Resource)
+            return WebInspector.panels.resources.sourceFrameForResource(scriptOrResource);
+        if (scriptOrResource instanceof WebInspector.Script)
+            return this.sourceFrameForScript(scriptOrResource);
+    },
+
+    _showScriptOrResource: function(scriptOrResource, line)
+    {
+        if (!scriptOrResource)
+            return;
+
+        var view;
+        if (scriptOrResource instanceof WebInspector.Resource) {
+            view = WebInspector.panels.resources.resourceViewForResource(scriptOrResource);
+            view.headersVisible = false;
+
+            if (scriptOrResource.url in this._breakpointsURLMap) {
+                var sourceFrame = this._sourceFrameForScriptOrResource(scriptOrResource);
+                if (sourceFrame && !sourceFrame.breakpoints.length) {
+                    var breakpoints = this._breakpointsURLMap[scriptOrResource.url];
+                    var breakpointsLength = breakpoints.length;
+                    for (var i = 0; i < breakpointsLength; ++i)
+                        sourceFrame.addBreakpoint(breakpoints[i]);
+                }
+            }
+        } else if (scriptOrResource instanceof WebInspector.Script)
+            view = this.scriptViewForScript(scriptOrResource);
+
+        if (!view)
+            return;
+
+        this.visibleView = view;
+
+        if (line && view.revealLine)
+            view.revealLine(line);
+
+        var select = this.filesSelectElement;
+        var options = select.options;
+        for (var i = 0; i < options.length; ++i) {
+            if (options[i].representedObject === scriptOrResource)
+                break;
+        }
+
+        select.selectedIndex = i;
+    },
+
+    _addScriptToFilesMenu: function(script)
+    {
+        var select = this.filesSelectElement;
+        var options = select.options;
+        for (var i = 0; i < options.length; ++i) {
+            var option = options[i];
+            if (option.representedObject === (script.resource || script))
+                return;
+        }
+
+        // FIXME: Append in some meaningful order.
+        var option = document.createElement("option");
+        option.representedObject = (script.resource || script);
+        option.text = (script.sourceURL ? script.sourceURL.trimURL(WebInspector.mainResource ? WebInspector.mainResource.domain : "") : "(eval script)");
+        select.appendChild(option);
+
+        // Call _showScriptOrResource if the option we just appended ended up being selected.
+        // This will happen for the first item added to the menu.
+        if (options[select.selectedIndex] === option)
+            this._showScriptOrResource(option.representedObject);
+    },
+
+    _removeScriptFromFilesMenu: function(script)
+    {
+        // This function assumes it is called before removeScript is called on the resource.
+        if (script.resource && script.resource.scripts.length > 1)
+            return; // The resource has more than one script, so keep the resource in the menu.
+
+        var select = this.filesSelectElement;
+        var options = select.options;
+        for (var i = 0; i < options.length; ++i) {
+            if (option.representedObject !== script.resource && option.representedObject !== script)
+                continue;
+
+            if (select.selectedIndex === i) {
+                // Pick the next selectedIndex. If we're at the end of the list, loop back to beginning.
+                var nextSelectedIndex = ((select.selectedIndex + 1) >= select.options.length ? 0 : select.selectedIndex);
+            }
+
+            // Remove the option from the select
+            select.options[select.selectedIndex] = null;
+
+            if (nextSelectedIndex)
+                select.selectedIndex = nextSelectedIndex;
+        }
+    },
+
+    _clearCurrentExecutionLine: function()
+    {
+        if (this._executionSourceFrame)
+            this._executionSourceFrame.executionLine = 0;
+        delete this._executionSourceFrame;
+    },
+
+    _callFrameSelected: function()
+    {
+        this._clearCurrentExecutionLine();
+
+        var callStackPane = this.sidebarPanes.callstack;
+        var currentFrame = callStackPane.selectedCallFrame;
+        if (!currentFrame)
+            return;
+
+        this.sidebarPanes.scopechain.update(currentFrame);
+
+        var scriptOrResource = this._sourceIDMap[currentFrame.sourceIdentifier];
+        this._showScriptOrResource(scriptOrResource, currentFrame.line);
+
+        this._executionSourceFrame = this._sourceFrameForScriptOrResource(scriptOrResource);
+        if (this._executionSourceFrame)
+            this._executionSourceFrame.executionLine = currentFrame.line;
+    },
+
+    _changeVisibleFile: function(event)
+    {
+        var select = this.filesSelectElement;
+        this._showScriptOrResource(select.options[select.selectedIndex].representedObject);
     },
 
     _startSidebarResizeDrag: function(event)
@@ -200,16 +517,93 @@ WebInspector.ScriptsPanel.prototype = {
             this.debuggingButton.removeStyleClass("toggled-on");
             this.pauseButton.disabled = true;
         }
+
+        if (this._paused) {
+            this.pauseButton.addStyleClass("paused");
+
+            this.pauseButton.disabled = false;
+            this.stepOverButton.disabled = false;
+            this.stepIntoButton.disabled = false;
+            this.stepOutButton.disabled = false;
+
+            this.debuggerStatusElement.textContent = WebInspector.UIString("Paused");
+        } else {
+            this.pauseButton.removeStyleClass("paused");
+
+            this.pauseButton.disabled = this._waitingToPause;
+            this.stepOverButton.disabled = true;
+            this.stepIntoButton.disabled = true;
+            this.stepOutButton.disabled = true;
+
+            if (this._waitingToPause)
+                this.debuggerStatusElement.textContent = WebInspector.UIString("Pausing");
+            else if (this._stepping)
+                this.debuggerStatusElement.textContent = WebInspector.UIString("Stepping");
+            else
+                this.debuggerStatusElement.textContent = "";
+        }
     },
 
     _toggleDebugging: function()
     {
+        this._paused = false;
+        this._waitingToPause = false;
+        this._stepping = false;
+
         if (InspectorController.debuggerAttached())
             InspectorController.stopDebugging();
         else
             InspectorController.startDebuggingAndReloadInspectedPage();
+
+        this.sidebarPanes.callstack.update(null);
+        this.sidebarPanes.scopechain.update(null);
+
+        this._clearCurrentExecutionLine();
         this._updateDebuggerButtons();
     },
+
+    _togglePause: function()
+    {
+        if (this._paused) {
+            this._paused = false;
+            this._waitingToPause = false;
+            InspectorController.resumeDebugger();
+        } else {
+            this._stepping = false;
+            this._waitingToPause = true;
+            InspectorController.pauseInDebugger();
+        }
+
+        this.sidebarPanes.callstack.update(null);
+        this.sidebarPanes.scopechain.update(null);
+
+        this._clearCurrentExecutionLine();
+        this._updateDebuggerButtons();
+    },
+
+    _stepOverClicked: function()
+    {
+        this._paused = false;
+        this._stepping = true;
+
+        InspectorController.stepOverStatementInDebugger();
+    },
+
+    _stepIntoClicked: function()
+    {
+        this._paused = false;
+        this._stepping = true;
+
+        InspectorController.stepIntoStatementInDebugger();
+    },
+
+    _stepOutClicked: function()
+    {
+        this._paused = false;
+        this._stepping = true;
+
+        InspectorController.stepOutOfFunctionInDebugger();
+    }
 }
 
 WebInspector.ScriptsPanel.prototype.__proto__ = WebInspector.Panel.prototype;
index 4c70b74..d052f51 100644 (file)
@@ -36,7 +36,7 @@ WebInspector.SourceView = function(resource)
 
     this._frameNeedsSetup = true;
 
-    this.sourceFrame = new WebInspector.SourceFrame();
+    this.sourceFrame = new WebInspector.SourceFrame(null, this._addBreakpoint.bind(this));
 
     this.contentElement.appendChild(this.sourceFrame.element);
 }
@@ -88,6 +88,23 @@ WebInspector.SourceView.prototype = {
         if (this.visible)
             this.setupSourceFrameIfNeeded();
         this.resource.removeEventListener("finished", this._resourceLoadingFinished, this);
+    },
+
+    _addBreakpoint: function(line)
+    {
+        var sourceID = null;
+        var closestStartingLine = 0;
+        var scripts = this.resource.scripts;
+        for (var i = 0; i < scripts.length; ++i) {
+            var script = scripts[i];
+            if (script.startingLine <= line && script.startingLine >= closestStartingLine) {
+                closestStartingLine = script.startingLine;
+                sourceID = script.sourceID;
+            }
+        }
+
+        var breakpoint = new WebInspector.Breakpoint(this.resource.url, line, sourceID);
+        WebInspector.panels.scripts.addBreakpoint(breakpoint);
     }
 }
 
index 9ce3143..de8f1ba 100644 (file)
@@ -598,7 +598,7 @@ body.console-visible #console {
     right: 0;
     bottom: 0;
     width: 225px;
-    background-color: rgb(232, 232, 232);
+    background-color: rgb(245, 245, 245);
     border-left: 1px solid rgb(64%, 64%, 64%);
     cursor: default;
     overflow: auto;
@@ -825,7 +825,7 @@ body:not(.inactive) .focused .outline-disclosure li.selected * {
 .placard {
     position: relative;
     margin-top: 1px;
-    padding: 3px 8px 4px 17px;
+    padding: 3px 8px 4px 18px;
     min-height: 18px;
     white-space: nowrap;
 }
@@ -886,17 +886,24 @@ body.inactive .placard.selected {
     margin-top: 1px;
 }
 
+.section:nth-last-of-type(1) {
+    margin-bottom: 1px;
+}
+
 .section .header {
-    padding: 3px 8px 4px 16px;
-    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(160, 172, 205)), to(rgb(132, 146, 190)));
+    padding: 2px 8px 4px 18px;
+    border-top: 1px solid rgb(145, 160, 192);
+    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(162, 177, 207)), to(rgb(120, 138, 177)));
     min-height: 18px;
     white-space: nowrap;
+    -webkit-background-origin: padding;
+    -webkit-background-clip: padding;
 }
 
 .section .header::before {
     position: absolute;
     top: 4px;
-    left: 6px;
+    left: 7px;
     width: 8px;
     height: 8px;
     content: url(Images/treeRightTriangleWhite.png);
@@ -947,7 +954,7 @@ body.inactive .placard.selected {
 .section .properties {
     display: none;
     margin: 0;
-    padding: 2px 6px 5px;
+    padding: 2px 6px 3px;
     list-style: none;
     background-color: white;
 }
@@ -957,7 +964,7 @@ body.inactive .placard.selected {
 }
 
 .section .properties li {
-    margin-left: 10px;
+    margin-left: 12px;
     white-space: nowrap;
     text-overflow: ellipsis;
     overflow: hidden;
@@ -967,7 +974,7 @@ body.inactive .placard.selected {
 }
 
 .section .properties li.parent {
-    margin-left: 0;
+    margin-left: 1px;
 }
 
 .section .properties ol {
@@ -988,7 +995,7 @@ body.inactive .placard.selected {
     width: 8px;
     height: 8px;
     margin-top: 0;
-    padding-right: 2px;
+    padding-right: 3px;
     -webkit-user-select: none;
     cursor: default;
 }
@@ -1071,45 +1078,48 @@ body.inactive .placard.selected {
     border: 1px solid rgb(180, 180, 180);
 }
 
-.pane {
-    margin-top: 1px;
+.pane:not(.expanded) + .pane, .pane:first-of-type {
+    margin-top: -1px;
 }
 
 .pane > .title {
-    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(221, 226, 239)), color-stop(0.5, rgb(220, 225, 238)), color-stop(0.5, rgb(194, 203, 219)), to(rgb(217, 222, 234)));
-    height: 16px;
-    padding: 0 6px;
-    border-top: 1px solid rgb(129, 129, 129);
-    border-bottom: 1px solid rgb(129, 129, 129);
+    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(243, 243, 243)), color-stop(0.05, rgb(243, 243, 243)), color-stop(0.05, rgb(230, 230, 230)), to(rgb(209, 209, 209)));
+    height: 20px;
+    padding: 0 5px;
+    border-top: 1px solid rgb(189, 189, 189);
+    border-bottom: 1px solid rgb(189, 189, 189);
     font-weight: bold;
-    font-size: 11px;
-    color: rgb(85, 85, 85);
+    font-size: 12px;
+    line-height: 18px;
+    color: rgb(110, 110, 110);
+    text-shadow: white 0 1px 0;
     -webkit-background-origin: padding;
     -webkit-background-clip: padding;
 }
 
 .pane > .title:active {
-    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(186, 191, 202)), color-stop(0.5, rgb(185, 190, 201)), color-stop(0.5, rgb(163, 171, 185)), to(rgb(183, 187, 197)));
+    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(231, 231, 231)), color-stop(0.05, rgb(231, 231, 231)), color-stop(0.05, rgb(207, 207, 207)), to(rgb(186, 186, 186)));
+    border-top: 1px solid rgb(178, 178, 178);
+    border-bottom: 1px solid rgb(178, 178, 178);
 }
 
 .pane > .title::before {
-    content: url(Images/treeRightTriangleBlack.png);
-    opacity: 0.75;
+    content: url(Images/disclosureTriangleSmallRightBlack.png);
     float: left;
-    width: 8px;
-    height: 8px;
-    margin-right: 3px;
-    margin-top: 0;
+    width: 11px;
+    height: 12px;
+    margin-right: 2px;
+    margin-top: 1px;
 }
 
 .pane.expanded > .title::before {
-    margin-top: 1px;
-    content: url(Images/treeDownTriangleBlack.png);
+    content: url(Images/disclosureTriangleSmallDownBlack.png);
 }
 
 .pane > .body {
     position: relative;
     display: none;
+    background-color: white;
     overflow-y: auto;
     overflow-x: hidden;
 }
@@ -1118,6 +1128,10 @@ body.inactive .placard.selected {
     display: block;
 }
 
+.pane.expanded:nth-last-of-type(1) {
+    border-bottom: 1px solid rgb(189, 189, 189);
+}
+
 .pane > .growbar {
     display: none;
     background-image: url(Images/paneGrowHandleLine.png), url(Images/paneBottomGrow.png);
@@ -1138,7 +1152,7 @@ body.inactive .placard.selected {
     margin-top: -10px;
     font-size: 9px;
     color: grey;
-    background-color: rgb(232, 232, 232);
+    background-color: white;
     margin-left: 3px;
     padding-left: 2px;
     padding-right: 2px;
@@ -1408,7 +1422,7 @@ body.inactive .data-grid th.sort-ascending, body.inactive .data-grid th.sort-des
 
 .database-user-query {
     position: relative;
-    border-bottom: 1px solid rgb(240, 240, 240);
+    border-bottom: 1px solid rgb(245, 245, 245);
     padding: 1px 22px 1px 24px;
     min-height: 16px; 
 }
@@ -1463,6 +1477,14 @@ body.inactive .data-grid th.sort-ascending, body.inactive .data-grid th.sort-des
     height: 24px;
 }
 
+#scripts-files {
+    max-width: 150px;
+}
+
+#scripts-functions {
+    max-width: 150px;
+}
+
 #scripts-status-bar .status-bar-item img {
     margin-top: 2px;
 }
@@ -1483,6 +1505,10 @@ body.inactive .data-grid th.sort-ascending, body.inactive .data-grid th.sort-des
     content: url(Images/debuggerPause.png);
 }
 
+#scripts-pause.paused img {
+    content: url(Images/debuggerContinue.png);
+}
+
 #scripts-step-over img {
     content: url(Images/debuggerStepOver.png);
 }
@@ -1502,10 +1528,6 @@ body.inactive .data-grid th.sort-ascending, body.inactive .data-grid th.sort-des
     right: 8px;
 }
 
-#scripts-debugger-status:empty {
-    display: none;
-}
-
 #scripts-sidebar-resizer-widget {
     position: absolute;
     top: 0;
@@ -1539,13 +1561,27 @@ body.inactive .data-grid th.sort-ascending, body.inactive .data-grid th.sort-des
     bottom: 0;
 }
 
+.script-view {
+    display: none;
+    overflow: hidden;
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+}
+
+.script-view.visible {
+    display: block;
+}
+
 #scripts-sidebar {
     position: absolute;
     top: 23px;
     right: 0;
     bottom: 0;
     width: 225px;
-    background-color: rgb(232, 232, 232);
+    background-color: rgb(245, 245, 245);
     border-left: 1px solid rgb(64%, 64%, 64%);
     cursor: default;
     overflow: auto;
index 5b81ab4..2f90b15 100644 (file)
@@ -193,6 +193,7 @@ WebInspector.loaded = function()
     this.panels = {
         elements: new WebInspector.ElementsPanel(),
         resources: new WebInspector.ResourcesPanel(),
+        scripts: new WebInspector.ScriptsPanel(),
         databases: new WebInspector.DatabasesPanel()
     };
 
@@ -628,6 +629,21 @@ WebInspector.addDatabase = function(database)
     this.panels.databases.addDatabase(database);
 }
 
+WebInspector.parsedScriptSource = function(sourceID, sourceURL, source, startingLine)
+{
+    this.panels.scripts.addScript(sourceID, sourceURL, source, startingLine);
+}
+
+WebInspector.failedToParseScriptSource = function(sourceURL, source, startingLine, errorLine, errorMessage)
+{
+    this.panels.scripts.addScript(null, sourceURL, source, startingLine, errorLine, errorMessage);
+}
+
+WebInspector.pausedScript = function()
+{
+    this.panels.scripts.debuggerPaused();
+}
+
 WebInspector.reset = function()
 {
     for (var panelName in this.panels) {