65cd965ef29b8fb264e3f8e95a43adf1b9b62de9
[WebKit-https.git] / Source / WebCore / inspector / front-end / ScriptsPanel.js
1 /*
2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3  * Copyright (C) 2011 Google Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 /**
28  * @constructor
29  * @implements {WebInspector.TabbedEditorContainerDelegate}
30  * @implements {WebInspector.ContextMenu.Provider}
31  * @extends {WebInspector.Panel}
32  * @param {WebInspector.UISourceCodeProvider=} uiSourceCodeProviderForTest
33  */
34 WebInspector.ScriptsPanel = function(uiSourceCodeProviderForTest)
35 {
36     WebInspector.Panel.call(this, "scripts");
37     this.registerRequiredCSS("scriptsPanel.css");
38
39     WebInspector.settings.pauseOnExceptionStateString = WebInspector.settings.createSetting("pauseOnExceptionStateString", WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions);
40     WebInspector.settings.navigatorWasOnceHidden = WebInspector.settings.createSetting("navigatorWasOnceHidden", false);
41     WebInspector.settings.debuggerSidebarHidden = WebInspector.settings.createSetting("debuggerSidebarHidden", false);
42
43     this._uiSourceCodeProvider = uiSourceCodeProviderForTest || WebInspector.workspace;
44
45     function viewGetter()
46     {
47         return this.visibleView;
48     }
49     WebInspector.GoToLineDialog.install(this, viewGetter.bind(this));
50
51     var helpSection = WebInspector.shortcutsScreen.section(WebInspector.UIString("Sources Panel"));
52     this.debugToolbar = this._createDebugToolbar(helpSection);
53
54     const initialDebugSidebarWidth = 225;
55     const maximalDebugSidebarWidthPercent = 50;
56     this.createSplitView(this.element, WebInspector.SplitView.SidebarPosition.Right, initialDebugSidebarWidth);
57     this.splitView.element.id = "scripts-split-view";
58     this.splitView.minimalSidebarWidth = Preferences.minScriptsSidebarWidth;
59     this.splitView.minimalMainWidthPercent = 100 - maximalDebugSidebarWidthPercent;
60
61     this.sidebarElement.appendChild(this.debugToolbar);
62
63     this.debugSidebarResizeWidgetElement = document.createElement("div");
64     this.debugSidebarResizeWidgetElement.id = "scripts-debug-sidebar-resizer-widget";
65     this.splitView.installResizer(this.debugSidebarResizeWidgetElement);
66
67     // Create scripts navigator
68     const initialNavigatorWidth = 225;
69     const minimalViewsContainerWidthPercent = 50;
70     this.editorView = new WebInspector.SplitView(WebInspector.SplitView.SidebarPosition.Left, "scriptsPanelNavigatorSidebarWidth", initialNavigatorWidth);
71     this.editorView.element.tabIndex = 0;
72
73     this.editorView.minimalSidebarWidth = Preferences.minScriptsSidebarWidth;
74     this.editorView.minimalMainWidthPercent = minimalViewsContainerWidthPercent;
75     this.editorView.show(this.splitView.mainElement);
76
77     this._navigator = new WebInspector.ScriptsNavigator();
78     this._navigator.view.show(this.editorView.sidebarElement);
79
80     this._editorContainer = new WebInspector.TabbedEditorContainer(this, "previouslyViewedFiles");
81     this._editorContainer.show(this.editorView.mainElement);
82
83     this._navigatorController = new WebInspector.NavigatorOverlayController(this, this.editorView, this._navigator.view, this._editorContainer.view);
84
85     this._navigator.addEventListener(WebInspector.ScriptsNavigator.Events.ScriptSelected, this._scriptSelected, this);
86     this._navigator.addEventListener(WebInspector.ScriptsNavigator.Events.SnippetCreationRequested, this._snippetCreationRequested, this);
87     this._navigator.addEventListener(WebInspector.ScriptsNavigator.Events.FileRenamed, this._fileRenamed, this);
88
89     this._editorContainer.addEventListener(WebInspector.TabbedEditorContainer.Events.EditorSelected, this._editorSelected, this);
90     this._editorContainer.addEventListener(WebInspector.TabbedEditorContainer.Events.EditorClosed, this._editorClosed, this);
91
92     this.splitView.mainElement.appendChild(this.debugSidebarResizeWidgetElement);
93
94     this.sidebarPanes = {};
95     this.sidebarPanes.watchExpressions = new WebInspector.WatchExpressionsSidebarPane();
96     this.sidebarPanes.callstack = new WebInspector.CallStackSidebarPane();
97     this.sidebarPanes.scopechain = new WebInspector.ScopeChainSidebarPane();
98     this.sidebarPanes.jsBreakpoints = new WebInspector.JavaScriptBreakpointsSidebarPane(WebInspector.breakpointManager, this._showSourceLine.bind(this));
99     this.sidebarPanes.domBreakpoints = WebInspector.domBreakpointsSidebarPane;
100     this.sidebarPanes.xhrBreakpoints = new WebInspector.XHRBreakpointsSidebarPane();
101     this.sidebarPanes.eventListenerBreakpoints = new WebInspector.EventListenerBreakpointsSidebarPane();
102
103     if (Preferences.exposeWorkersInspection && !WebInspector.WorkerManager.isWorkerFrontend()) {
104         WorkerAgent.setWorkerInspectionEnabled(true);
105         this.sidebarPanes.workerList = new WebInspector.WorkerListSidebarPane(WebInspector.workerManager);
106     } else
107         this.sidebarPanes.workers = new WebInspector.WorkersSidebarPane();
108
109     this._debugSidebarContentsElement = document.createElement("div");
110     this._debugSidebarContentsElement.id = "scripts-debug-sidebar-contents";
111     this.sidebarElement.appendChild(this._debugSidebarContentsElement);
112
113     for (var pane in this.sidebarPanes)
114         this._debugSidebarContentsElement.appendChild(this.sidebarPanes[pane].element);
115
116     this.sidebarPanes.callstack.expanded = true;
117
118     this.sidebarPanes.scopechain.expanded = true;
119     this.sidebarPanes.jsBreakpoints.expanded = true;
120
121     this.sidebarPanes.callstack.registerShortcuts(helpSection, this.registerShortcut.bind(this));
122     var evaluateInConsoleShortcut = WebInspector.KeyboardShortcut.makeDescriptor("e", WebInspector.KeyboardShortcut.Modifiers.Shift | WebInspector.KeyboardShortcut.Modifiers.Ctrl);
123     helpSection.addKey(evaluateInConsoleShortcut.name, WebInspector.UIString("Evaluate selection in console"));
124     this.registerShortcut(evaluateInConsoleShortcut.key, this._evaluateSelectionInConsole.bind(this));
125
126     var outlineShortcut = WebInspector.KeyboardShortcut.makeDescriptor("o", WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta | WebInspector.KeyboardShortcut.Modifiers.Shift);
127     helpSection.addKey(outlineShortcut.name, WebInspector.UIString("Go to member"));
128     this.registerShortcut(outlineShortcut.key, this._showOutlineDialog.bind(this));
129
130     var createBreakpointShortcut = WebInspector.KeyboardShortcut.makeDescriptor("b", WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta);
131     helpSection.addKey(createBreakpointShortcut.name, WebInspector.UIString("Toggle breakpoint"));
132     this.registerShortcut(createBreakpointShortcut.key, this._toggleBreakpoint.bind(this));
133
134     var panelEnablerHeading = WebInspector.UIString("You need to enable debugging before you can use the Scripts panel.");
135     var panelEnablerDisclaimer = WebInspector.UIString("Enabling debugging will make scripts run slower.");
136     var panelEnablerButton = WebInspector.UIString("Enable Debugging");
137
138     this.panelEnablerView = new WebInspector.PanelEnablerView("scripts", panelEnablerHeading, panelEnablerDisclaimer, panelEnablerButton);
139     this.panelEnablerView.addEventListener("enable clicked", this.enableDebugging, this);
140
141     this.enableToggleButton = new WebInspector.StatusBarButton("", "enable-toggle-status-bar-item");
142     this.enableToggleButton.addEventListener("click", this.toggleDebugging, this);
143     if (!Capabilities.debuggerCausesRecompilation)
144         this.enableToggleButton.element.addStyleClass("hidden");
145
146     this._pauseOnExceptionButton = new WebInspector.StatusBarButton("", "scripts-pause-on-exceptions-status-bar-item", 3);
147     this._pauseOnExceptionButton.addEventListener("click", this._togglePauseOnExceptions, this);
148
149     this._toggleFormatSourceButton = new WebInspector.StatusBarButton(WebInspector.UIString("Pretty print"), "scripts-toggle-pretty-print-status-bar-item");
150     this._toggleFormatSourceButton.toggled = false;
151     this._toggleFormatSourceButton.addEventListener("click", this._toggleFormatSource, this);
152
153     this._scriptViewStatusBarItemsContainer = document.createElement("div");
154     this._scriptViewStatusBarItemsContainer.style.display = "inline-block";
155
156     this._debuggerEnabled = !Capabilities.debuggerCausesRecompilation;
157     this._installDebuggerSidebarController();
158
159     this._sourceFramesByUISourceCode = new Map();
160     this._reset(false);
161
162     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerWasEnabled, this._debuggerWasEnabled, this);
163     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerWasDisabled, this._debuggerWasDisabled, this);
164     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
165     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerResumed, this._debuggerResumed, this);
166     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.CallFrameSelected, this._callFrameSelected, this);
167     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.ConsoleCommandEvaluatedInSelectedCallFrame, this._consoleCommandEvaluatedInSelectedCallFrame, this);
168     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.ExecutionLineChanged, this._executionLineChanged, this);
169     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, this._reset.bind(this, false));
170     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointsActiveStateChanged, this._breakpointsActiveStateChanged, this);
171
172     this._uiSourceCodeProvider.addEventListener(WebInspector.UISourceCodeProvider.Events.UISourceCodeAdded, this._handleUISourceCodeAdded, this);
173     this._uiSourceCodeProvider.addEventListener(WebInspector.UISourceCodeProvider.Events.UISourceCodeReplaced, this._uiSourceCodeReplaced, this);
174     this._uiSourceCodeProvider.addEventListener(WebInspector.UISourceCodeProvider.Events.UISourceCodeRemoved, this._uiSourceCodeRemoved, this);
175
176     var enableDebugger = !Capabilities.debuggerCausesRecompilation || WebInspector.settings.debuggerEnabled.get();
177     if (enableDebugger)
178         WebInspector.debuggerModel.enableDebugger();
179
180     WebInspector.advancedSearchController.registerSearchScope(new WebInspector.ScriptsSearchScope(this._uiSourceCodeProvider));
181     WebInspector.ContextMenu.registerProvider(this);
182 }
183
184 // Keep these in sync with WebCore::ScriptDebugServer
185 WebInspector.ScriptsPanel.PauseOnExceptionsState = {
186     DontPauseOnExceptions : "none",
187     PauseOnAllExceptions : "all",
188     PauseOnUncaughtExceptions: "uncaught"
189 };
190
191 WebInspector.ScriptsPanel.prototype = {
192     get toolbarItemLabel()
193     {
194         return WebInspector.UIString("Sources");
195     },
196
197     get statusBarItems()
198     {
199         return [this.enableToggleButton.element, this._pauseOnExceptionButton.element, this._toggleFormatSourceButton.element, this._scriptViewStatusBarItemsContainer];
200     },
201
202     defaultFocusedElement: function()
203     {
204         return this._navigator.view.defaultFocusedElement();
205     },
206
207     get paused()
208     {
209         return this._paused;
210     },
211
212     wasShown: function()
213     {
214         WebInspector.Panel.prototype.wasShown.call(this);
215         this._debugSidebarContentsElement.insertBefore(this.sidebarPanes.domBreakpoints.element, this.sidebarPanes.xhrBreakpoints.element);
216         this.sidebarPanes.watchExpressions.show();
217
218         this._navigatorController.wasShown();
219     },
220
221     willHide: function()
222     {
223         WebInspector.Panel.prototype.willHide.call(this);
224         WebInspector.closeViewInDrawer();
225     },
226
227     /**
228      * @param {WebInspector.Event} event
229      */
230     _handleUISourceCodeAdded: function(event)
231     {
232         var uiSourceCode = /** @type {WebInspector.UISourceCode} */ event.data;
233         if (this._toggleFormatSourceButton.toggled)
234             uiSourceCode.setFormatted(true);
235         this._uiSourceCodeAdded(uiSourceCode);
236     },
237
238     _loadUISourceCodes: function()
239     {
240         var uiSourceCodes = this._uiSourceCodeProvider.uiSourceCodes();
241         for (var i = 0; i < uiSourceCodes.length; ++i)
242             this._uiSourceCodeAdded(uiSourceCodes[i]);
243     },
244
245     /**
246      * @param {WebInspector.UISourceCode} uiSourceCode
247      */
248     _uiSourceCodeAdded: function(uiSourceCode)
249     {
250         this._addUISourceCode(uiSourceCode);
251     },
252
253     /**
254      * @param {WebInspector.UISourceCode} uiSourceCode
255      */
256     _addUISourceCode: function(uiSourceCode)
257     {
258         this._navigator.addUISourceCode(uiSourceCode);
259         this._editorContainer.uiSourceCodeAdded(uiSourceCode);
260     },
261
262     _uiSourceCodeRemoved: function(event)
263     {
264         var uiSourceCode = /** @type {WebInspector.UISourceCode} */ event.data;
265         this._removeSourceFrame(uiSourceCode);
266     },
267
268     _consoleCommandEvaluatedInSelectedCallFrame: function(event)
269     {
270         this.sidebarPanes.scopechain.update(WebInspector.debuggerModel.selectedCallFrame());
271     },
272
273     _debuggerPaused: function(event)
274     {
275         var details = /** @type {WebInspector.DebuggerPausedDetails} */ event.data;
276
277         this._paused = true;
278         this._waitingToPause = false;
279         this._stepping = false;
280
281         this._updateDebuggerButtons();
282
283         WebInspector.inspectorView.setCurrentPanel(this);
284         this.sidebarPanes.callstack.update(details.callFrames);
285
286         if (details.reason === WebInspector.DebuggerModel.BreakReason.DOM) {
287             this.sidebarPanes.domBreakpoints.highlightBreakpoint(details.auxData);
288             function didCreateBreakpointHitStatusMessage(element)
289             {
290                 this.sidebarPanes.callstack.setStatus(element);
291             }
292             this.sidebarPanes.domBreakpoints.createBreakpointHitStatusMessage(details.auxData, didCreateBreakpointHitStatusMessage.bind(this));
293         } else if (details.reason === WebInspector.DebuggerModel.BreakReason.EventListener) {
294             var eventName = details.auxData.eventName;
295             this.sidebarPanes.eventListenerBreakpoints.highlightBreakpoint(details.auxData.eventName);
296             var eventNameForUI = WebInspector.EventListenerBreakpointsSidebarPane.eventNameForUI(eventName);
297             this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a \"%s\" Event Listener.", eventNameForUI));
298         } else if (details.reason === WebInspector.DebuggerModel.BreakReason.XHR) {
299             this.sidebarPanes.xhrBreakpoints.highlightBreakpoint(details.auxData["breakpointURL"]);
300             this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a XMLHttpRequest."));
301         } else if (details.reason === WebInspector.DebuggerModel.BreakReason.Exception) {
302             this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on exception: '%s'.", details.auxData.description));
303         } else {
304             function didGetUILocation(uiLocation)
305             {
306                 var breakpoint = WebInspector.breakpointManager.findBreakpoint(uiLocation.uiSourceCode, uiLocation.lineNumber);
307                 if (!breakpoint)
308                     return;
309                 this.sidebarPanes.jsBreakpoints.highlightBreakpoint(breakpoint);
310                 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a JavaScript breakpoint."));
311             }
312             details.callFrames[0].createLiveLocation(didGetUILocation.bind(this));
313         }
314
315         this._showDebuggerSidebar();
316         this._toggleDebuggerSidebarButton.disabled = true;
317         window.focus();
318         InspectorFrontendHost.bringToFront();
319     },
320
321     _debuggerResumed: function()
322     {
323         this._paused = false;
324         this._waitingToPause = false;
325         this._stepping = false;
326
327         this._clearInterface();
328         this._toggleDebuggerSidebarButton.disabled = false;
329     },
330
331     _debuggerWasEnabled: function()
332     {
333         this._setPauseOnExceptions(WebInspector.settings.pauseOnExceptionStateString.get());
334
335         if (this._debuggerEnabled)
336             return;
337
338         this._debuggerEnabled = true;
339         this._reset(true);
340     },
341
342     _debuggerWasDisabled: function()
343     {
344         if (!this._debuggerEnabled)
345             return;
346
347         this._debuggerEnabled = false;
348         this._reset(true);
349     },
350
351     _reset: function(preserveItems)
352     {
353         delete this.currentQuery;
354         this.searchCanceled();
355
356         this._debuggerResumed();
357
358         delete this._currentUISourceCode;
359         this._navigator.reset();
360         this._editorContainer.reset();
361         this._updateScriptViewStatusBarItems();
362         this.sidebarPanes.jsBreakpoints.reset();
363         this.sidebarPanes.watchExpressions.reset();
364         if (!preserveItems && this.sidebarPanes.workers)
365             this.sidebarPanes.workers.reset();
366         WebInspector.RevisionHistoryView.reset();
367
368         this._loadUISourceCodes();
369     },
370
371     get visibleView()
372     {
373         return this._editorContainer.visibleView;
374     },
375
376     _updateScriptViewStatusBarItems: function()
377     {
378         this._scriptViewStatusBarItemsContainer.removeChildren();
379
380         var sourceFrame = this.visibleView;
381         if (sourceFrame) {
382             var statusBarItems = sourceFrame.statusBarItems || [];
383             for (var i = 0; i < statusBarItems.length; ++i)
384                 this._scriptViewStatusBarItemsContainer.appendChild(statusBarItems[i]);
385         }
386     },
387
388     canShowAnchorLocation: function(anchor)
389     {
390         if (this._debuggerEnabled && anchor.uiSourceCode)
391             return true;
392         var uiSourceCodes = this._uiSourceCodeProvider.uiSourceCodes();
393         for (var i = 0; i < uiSourceCodes.length; ++i) {
394             if (uiSourceCodes[i].url === anchor.href) {
395                 anchor.uiSourceCode = uiSourceCodes[i];
396                 return true;
397             }
398         }
399         return false;
400     },
401
402     showAnchorLocation: function(anchor)
403     {
404         this._showSourceLine(anchor.uiSourceCode, anchor.lineNumber);
405     },
406
407     showFunctionDefinition: function(functionLocation)
408     {
409         WebInspector.showPanelForAnchorNavigation(this);
410         var uiLocation = WebInspector.debuggerModel.rawLocationToUILocation(functionLocation);
411         this._showSourceLine(uiLocation.uiSourceCode, uiLocation.lineNumber);
412     },
413
414     /**
415      * @param {WebInspector.UISourceCode} uiSourceCode
416      * @param {number} lineNumber
417      */
418     showUISourceCode: function(uiSourceCode, lineNumber)
419     {
420         this._showSourceLine(uiSourceCode, lineNumber);
421     },
422
423     /**
424      * @param {WebInspector.UISourceCode} uiSourceCode
425      * @param {number=} lineNumber
426      */
427     _showSourceLine: function(uiSourceCode, lineNumber)
428     {
429         var sourceFrame = this._showFile(uiSourceCode);
430         if (typeof lineNumber === "number")
431             sourceFrame.highlightLine(lineNumber);
432         sourceFrame.focus();
433     },
434
435     /**
436      * @param {WebInspector.UISourceCode} uiSourceCode
437      * @return {WebInspector.SourceFrame}
438      */
439     _showFile: function(uiSourceCode)
440     {
441         var sourceFrame = this._getOrCreateSourceFrame(uiSourceCode);
442         if (this._currentUISourceCode === uiSourceCode)
443             return sourceFrame;
444         this._currentUISourceCode = uiSourceCode;
445
446         if (this._navigator.isScriptSourceAdded(uiSourceCode))
447             this._navigator.revealUISourceCode(uiSourceCode);
448         this._editorContainer.showFile(uiSourceCode);
449         this._updateScriptViewStatusBarItems();
450
451         return sourceFrame;
452     },
453
454     /**
455      * @param {WebInspector.UISourceCode} uiSourceCode
456      * @return {WebInspector.SourceFrame}
457      */
458     _createSourceFrame: function(uiSourceCode)
459     {
460         var sourceFrame;
461         if (uiSourceCode instanceof WebInspector.JavaScriptSource) {
462             var javaScriptSource = /** @type {WebInspector.JavaScriptSource} */ uiSourceCode;
463             sourceFrame = new WebInspector.JavaScriptSourceFrame(this, javaScriptSource);
464         } else if (uiSourceCode instanceof WebInspector.StyleSource) {
465             var styleSource = /** @type {WebInspector.StyleSource} */ uiSourceCode;
466             sourceFrame = new WebInspector.StyleSourceFrame(styleSource);
467         } else {
468             console.assert(false, "Unknown UISourceCode type");
469             sourceFrame = new WebInspector.SourceFrame(uiSourceCode);
470         }
471          
472         this._sourceFramesByUISourceCode.put(uiSourceCode, sourceFrame);
473         return sourceFrame;
474     },
475
476     /**
477      * @param {WebInspector.UISourceCode} uiSourceCode
478      * @return {WebInspector.SourceFrame}
479      */
480     _getOrCreateSourceFrame: function(uiSourceCode)
481     {
482         return this._sourceFramesByUISourceCode.get(uiSourceCode) || this._createSourceFrame(uiSourceCode);
483     },
484
485     /**
486      * @param {WebInspector.UISourceCode} uiSourceCode
487      * @return {WebInspector.SourceFrame}
488      */
489     viewForFile: function(uiSourceCode)
490     {
491         return this._getOrCreateSourceFrame(uiSourceCode);
492     },
493
494     /**
495      * @param {WebInspector.UISourceCode} uiSourceCode
496      */
497     _removeSourceFrame: function(uiSourceCode)
498     {
499         var sourceFrame = this._sourceFramesByUISourceCode.get(uiSourceCode);
500         if (!sourceFrame)
501             return;
502         this._sourceFramesByUISourceCode.remove(uiSourceCode);
503         sourceFrame.detach();
504     },
505
506     /**
507      * @param {WebInspector.Event} event
508      */
509     _uiSourceCodeReplaced: function(event)
510     {
511         var oldUISourceCode = /** @type {WebInspector.UISourceCode} */ event.data.oldUISourceCode;
512         var uiSourceCode = /** @type {WebInspector.UISourceCode} */ event.data.uiSourceCode;
513
514         this._navigator.replaceUISourceCode(oldUISourceCode, uiSourceCode);
515         this._editorContainer.replaceFile(oldUISourceCode, uiSourceCode);
516         this._removeSourceFrame(oldUISourceCode);
517     },
518
519     _clearCurrentExecutionLine: function()
520     {
521         if (this._executionSourceFrame)
522             this._executionSourceFrame.clearExecutionLine();
523         delete this._executionSourceFrame;
524     },
525
526     _executionLineChanged: function(event)
527     {
528         var uiLocation = event.data;
529
530         this._clearCurrentExecutionLine();
531         if (!uiLocation)
532             return;
533         var sourceFrame = this._getOrCreateSourceFrame(uiLocation.uiSourceCode);
534         sourceFrame.setExecutionLine(uiLocation.lineNumber);
535         this._executionSourceFrame = sourceFrame;
536     },
537
538     _revealExecutionLine: function(uiLocation)
539     {
540         // Some scripts (anonymous and snippets evaluations) are not added to files select by default.
541         this._editorContainer.uiSourceCodeAdded(uiLocation.uiSourceCode);
542         var sourceFrame = this._showFile(uiLocation.uiSourceCode);
543         sourceFrame.revealLine(uiLocation.lineNumber);
544         sourceFrame.focus();
545     },
546
547     _callFrameSelected: function(event)
548     {
549         var callFrame = event.data;
550
551         if (!callFrame)
552             return;
553
554         this.sidebarPanes.scopechain.update(callFrame);
555         this.sidebarPanes.watchExpressions.refreshExpressions();
556         this.sidebarPanes.callstack.setSelectedCallFrame(callFrame);
557         callFrame.createLiveLocation(this._revealExecutionLine.bind(this));
558     },
559
560     _editorClosed: function(event)
561     {
562         this._navigatorController.hideNavigatorOverlay();
563         var uiSourceCode = /** @type {WebInspector.UISourceCode} */ event.data;
564
565         if (this._currentUISourceCode === uiSourceCode)
566             delete this._currentUISourceCode;
567
568         // ScriptsNavigator does not need to update on EditorClosed.
569         this._updateScriptViewStatusBarItems();
570     },
571
572     _editorSelected: function(event)
573     {
574         var uiSourceCode = /** @type {WebInspector.UISourceCode} */ event.data;
575         var sourceFrame = this._showFile(uiSourceCode);
576         this._navigatorController.hideNavigatorOverlay();
577         sourceFrame.focus();
578     },
579
580     _scriptSelected: function(event)
581     {
582         var uiSourceCode = /** @type {WebInspector.UISourceCode} */ event.data.uiSourceCode;
583         var sourceFrame = this._showFile(uiSourceCode);
584         this._navigatorController.hideNavigatorOverlay();
585         if (sourceFrame && event.data.focusSource)
586             sourceFrame.focus();
587     },
588
589     _setPauseOnExceptions: function(pauseOnExceptionsState)
590     {
591         pauseOnExceptionsState = pauseOnExceptionsState || WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions;
592         function callback(error)
593         {
594             if (error)
595                 return;
596             if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions)
597                 this._pauseOnExceptionButton.title = WebInspector.UIString("Don't pause on exceptions.\nClick to Pause on all exceptions.");
598             else if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.PauseOnAllExceptions)
599                 this._pauseOnExceptionButton.title = WebInspector.UIString("Pause on all exceptions.\nClick to Pause on uncaught exceptions.");
600             else if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.PauseOnUncaughtExceptions)
601                 this._pauseOnExceptionButton.title = WebInspector.UIString("Pause on uncaught exceptions.\nClick to Not pause on exceptions.");
602
603             this._pauseOnExceptionButton.state = pauseOnExceptionsState;
604             WebInspector.settings.pauseOnExceptionStateString.set(pauseOnExceptionsState);
605         }
606         DebuggerAgent.setPauseOnExceptions(pauseOnExceptionsState, callback.bind(this));
607     },
608
609     _updateDebuggerButtons: function()
610     {
611         if (this._debuggerEnabled) {
612             this.enableToggleButton.title = WebInspector.UIString("Debugging enabled. Click to disable.");
613             this.enableToggleButton.toggled = true;
614             this._pauseOnExceptionButton.visible = true;
615             this.panelEnablerView.detach();
616         } else {
617             this.enableToggleButton.title = WebInspector.UIString("Debugging disabled. Click to enable.");
618             this.enableToggleButton.toggled = false;
619             this._pauseOnExceptionButton.visible = false;
620             this.panelEnablerView.show(this.element);
621         }
622
623         if (this._paused) {
624             this.pauseButton.addStyleClass("paused");
625
626             this.pauseButton.disabled = false;
627             this.stepOverButton.disabled = false;
628             this.stepIntoButton.disabled = false;
629             this.stepOutButton.disabled = false;
630
631             this.debuggerStatusElement.textContent = WebInspector.UIString("Paused");
632         } else {
633             this.pauseButton.removeStyleClass("paused");
634
635             this.pauseButton.disabled = this._waitingToPause;
636             this.stepOverButton.disabled = true;
637             this.stepIntoButton.disabled = true;
638             this.stepOutButton.disabled = true;
639
640             if (this._waitingToPause)
641                 this.debuggerStatusElement.textContent = WebInspector.UIString("Pausing");
642             else if (this._stepping)
643                 this.debuggerStatusElement.textContent = WebInspector.UIString("Stepping");
644             else
645                 this.debuggerStatusElement.textContent = "";
646         }
647     },
648
649     _clearInterface: function()
650     {
651         this.sidebarPanes.callstack.update(null);
652         this.sidebarPanes.scopechain.update(null);
653         this.sidebarPanes.jsBreakpoints.clearBreakpointHighlight();
654         this.sidebarPanes.domBreakpoints.clearBreakpointHighlight();
655         this.sidebarPanes.eventListenerBreakpoints.clearBreakpointHighlight();
656         this.sidebarPanes.xhrBreakpoints.clearBreakpointHighlight();
657
658         this._clearCurrentExecutionLine();
659         this._updateDebuggerButtons();
660     },
661
662     get debuggingEnabled()
663     {
664         return this._debuggerEnabled;
665     },
666
667     enableDebugging: function()
668     {
669         if (this._debuggerEnabled)
670             return;
671         this.toggleDebugging(this.panelEnablerView.alwaysEnabled);
672     },
673
674     disableDebugging: function()
675     {
676         if (!this._debuggerEnabled)
677             return;
678         this.toggleDebugging(this.panelEnablerView.alwaysEnabled);
679     },
680
681     toggleDebugging: function(optionalAlways)
682     {
683         this._paused = false;
684         this._waitingToPause = false;
685         this._stepping = false;
686
687         if (this._debuggerEnabled) {
688             WebInspector.settings.debuggerEnabled.set(false);
689             WebInspector.debuggerModel.disableDebugger();
690         } else {
691             WebInspector.settings.debuggerEnabled.set(!!optionalAlways);
692             WebInspector.debuggerModel.enableDebugger();
693         }
694     },
695
696     _togglePauseOnExceptions: function()
697     {
698         var nextStateMap = {};
699         var stateEnum = WebInspector.ScriptsPanel.PauseOnExceptionsState;
700         nextStateMap[stateEnum.DontPauseOnExceptions] = stateEnum.PauseOnAllExceptions;
701         nextStateMap[stateEnum.PauseOnAllExceptions] = stateEnum.PauseOnUncaughtExceptions;
702         nextStateMap[stateEnum.PauseOnUncaughtExceptions] = stateEnum.DontPauseOnExceptions;
703         this._setPauseOnExceptions(nextStateMap[this._pauseOnExceptionButton.state]);
704     },
705
706     _togglePause: function()
707     {
708         if (this._paused) {
709             this._paused = false;
710             this._waitingToPause = false;
711             DebuggerAgent.resume();
712         } else {
713             this._stepping = false;
714             this._waitingToPause = true;
715             DebuggerAgent.pause();
716         }
717
718         this._clearInterface();
719     },
720
721     _stepOverClicked: function()
722     {
723         if (!this._paused)
724             return;
725
726         this._paused = false;
727         this._stepping = true;
728
729         this._clearInterface();
730
731         DebuggerAgent.stepOver();
732     },
733
734     _stepIntoClicked: function()
735     {
736         if (!this._paused)
737             return;
738
739         this._paused = false;
740         this._stepping = true;
741
742         this._clearInterface();
743
744         DebuggerAgent.stepInto();
745     },
746
747     _stepOutClicked: function()
748     {
749         if (!this._paused)
750             return;
751
752         this._paused = false;
753         this._stepping = true;
754
755         this._clearInterface();
756
757         DebuggerAgent.stepOut();
758     },
759
760     _toggleBreakpointsClicked: function(event)
761     {
762         WebInspector.debuggerModel.setBreakpointsActive(!WebInspector.debuggerModel.breakpointsActive());
763     },
764
765     _breakpointsActiveStateChanged: function(event)
766     {
767         var active = event.data;
768         this._toggleBreakpointsButton.toggled = active;
769         if (active) {
770             this._toggleBreakpointsButton.title = WebInspector.UIString("Deactivate all breakpoints.");
771             WebInspector.inspectorView.element.removeStyleClass("breakpoints-deactivated");
772             this.sidebarPanes.jsBreakpoints.listElement.removeStyleClass("breakpoints-list-deactivated");
773         } else {
774             this._toggleBreakpointsButton.title = WebInspector.UIString("Activate all breakpoints.");
775             WebInspector.inspectorView.element.addStyleClass("breakpoints-deactivated");
776             this.sidebarPanes.jsBreakpoints.listElement.addStyleClass("breakpoints-list-deactivated");
777         }
778     },
779
780     _evaluateSelectionInConsole: function()
781     {
782         var selection = window.getSelection();
783         if (selection.type === "Range" && !selection.isCollapsed)
784             WebInspector.evaluateInConsole(selection.toString());
785     },
786
787     _createDebugToolbar: function(section)
788     {
789         var debugToolbar = document.createElement("div");
790         debugToolbar.className = "status-bar";
791         debugToolbar.id = "scripts-debug-toolbar";
792
793         var title, handler, shortcuts;
794         var platformSpecificModifier = WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta;
795
796         // Continue.
797         title = WebInspector.UIString("Pause script execution (%s).");
798         handler = this._togglePause.bind(this);
799         shortcuts = [];
800         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F8));
801         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Slash, platformSpecificModifier));
802         this.pauseButton = this._createButtonAndRegisterShortcuts(section, "scripts-pause", title, handler, shortcuts, WebInspector.UIString("Pause/Continue"));
803         debugToolbar.appendChild(this.pauseButton);
804
805         // Step over.
806         title = WebInspector.UIString("Step over next function call (%s).");
807         handler = this._stepOverClicked.bind(this);
808         shortcuts = [];
809         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F10));
810         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.SingleQuote, platformSpecificModifier));
811         this.stepOverButton = this._createButtonAndRegisterShortcuts(section, "scripts-step-over", title, handler, shortcuts, WebInspector.UIString("Step over"));
812         debugToolbar.appendChild(this.stepOverButton);
813
814         // Step into.
815         title = WebInspector.UIString("Step into next function call (%s).");
816         handler = this._stepIntoClicked.bind(this);
817         shortcuts = [];
818         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F11));
819         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Semicolon, platformSpecificModifier));
820         this.stepIntoButton = this._createButtonAndRegisterShortcuts(section, "scripts-step-into", title, handler, shortcuts, WebInspector.UIString("Step into"));
821         debugToolbar.appendChild(this.stepIntoButton);
822
823         // Step out.
824         title = WebInspector.UIString("Step out of current function (%s).");
825         handler = this._stepOutClicked.bind(this);
826         shortcuts = [];
827         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F11, WebInspector.KeyboardShortcut.Modifiers.Shift));
828         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Semicolon, WebInspector.KeyboardShortcut.Modifiers.Shift | platformSpecificModifier));
829         this.stepOutButton = this._createButtonAndRegisterShortcuts(section, "scripts-step-out", title, handler, shortcuts, WebInspector.UIString("Step out"));
830         debugToolbar.appendChild(this.stepOutButton);
831
832         this._toggleBreakpointsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Deactivate all breakpoints."), "toggle-breakpoints");
833         this._toggleBreakpointsButton.toggled = true;
834         this._toggleBreakpointsButton.addEventListener("click", this._toggleBreakpointsClicked, this);
835         debugToolbar.appendChild(this._toggleBreakpointsButton.element);
836
837         this.debuggerStatusElement = document.createElement("div");
838         this.debuggerStatusElement.id = "scripts-debugger-status";
839         debugToolbar.appendChild(this.debuggerStatusElement);
840
841         return debugToolbar;
842     },
843
844     _createButtonAndRegisterShortcuts: function(section, buttonId, buttonTitle, handler, shortcuts, shortcutDescription)
845     {
846         var button = document.createElement("button");
847         button.className = "status-bar-item";
848         button.id = buttonId;
849         button.title = String.vsprintf(buttonTitle, [shortcuts[0].name]);
850         button.disabled = true;
851         button.appendChild(document.createElement("img"));
852         button.addEventListener("click", handler, false);
853
854         var shortcutNames = [];
855         for (var i = 0; i < shortcuts.length; ++i) {
856             this.registerShortcut(shortcuts[i].key, handler);
857             shortcutNames.push(shortcuts[i].name);
858         }
859         section.addAlternateKeys(shortcutNames, shortcutDescription);
860
861         return button;
862     },
863
864     searchCanceled: function()
865     {
866         if (this._searchView)
867             this._searchView.searchCanceled();
868
869         delete this._searchView;
870         delete this._searchQuery;
871     },
872
873     performSearch: function(query)
874     {
875         WebInspector.searchController.updateSearchMatchesCount(0, this);
876
877         if (!this.visibleView)
878             return;
879
880         // Call searchCanceled since it will reset everything we need before doing a new search.
881         this.searchCanceled();
882
883         this._searchView = this.visibleView;
884         this._searchQuery = query;
885
886         function finishedCallback(view, searchMatches)
887         {
888             if (!searchMatches)
889                 return;
890
891             WebInspector.searchController.updateSearchMatchesCount(searchMatches, this);
892             view.jumpToFirstSearchResult();
893             WebInspector.searchController.updateCurrentMatchIndex(view.currentSearchResultIndex, this);
894         }
895
896         this._searchView.performSearch(query, finishedCallback.bind(this));
897     },
898
899     jumpToNextSearchResult: function()
900     {
901         if (!this._searchView)
902             return;
903
904         if (this._searchView !== this.visibleView) {
905             this.performSearch(this._searchQuery);
906             return;
907         }
908
909         if (this._searchView.showingLastSearchResult())
910             this._searchView.jumpToFirstSearchResult();
911         else
912             this._searchView.jumpToNextSearchResult();
913         WebInspector.searchController.updateCurrentMatchIndex(this._searchView.currentSearchResultIndex, this);
914     },
915
916     jumpToPreviousSearchResult: function()
917     {
918         if (!this._searchView)
919             return;
920
921         if (this._searchView !== this.visibleView) {
922             this.performSearch(this._searchQuery);
923             if (this._searchView)
924                 this._searchView.jumpToLastSearchResult();
925             return;
926         }
927
928         if (this._searchView.showingFirstSearchResult())
929             this._searchView.jumpToLastSearchResult();
930         else
931             this._searchView.jumpToPreviousSearchResult();
932         WebInspector.searchController.updateCurrentMatchIndex(this._searchView.currentSearchResultIndex, this);
933     },
934
935     _toggleFormatSource: function()
936     {
937         this._toggleFormatSourceButton.toggled = !this._toggleFormatSourceButton.toggled;
938         var uiSourceCodes = this._uiSourceCodeProvider.uiSourceCodes();
939         for (var i = 0; i < uiSourceCodes.length; ++i)
940             uiSourceCodes[i].setFormatted(this._toggleFormatSourceButton.toggled);
941     },
942
943     addToWatch: function(expression)
944     {
945         this.sidebarPanes.watchExpressions.addExpression(expression);
946     },
947
948     _toggleBreakpoint: function()
949     {
950         var sourceFrame = this.visibleView;
951         if (!sourceFrame)
952             return;
953
954         if (sourceFrame instanceof WebInspector.JavaScriptSourceFrame) {
955             var javaScriptSourceFrame = /** @type {WebInspector.JavaScriptSourceFrame} */ sourceFrame;
956             javaScriptSourceFrame.toggleBreakpointOnCurrentLine();
957         }            
958     },
959
960     _showOutlineDialog: function()
961     {
962         var uiSourceCode = this._editorContainer.currentFile();
963         if (!uiSourceCode)
964             return;
965
966         if (uiSourceCode instanceof WebInspector.JavaScriptSource)
967             WebInspector.JavaScriptOutlineDialog.show(this.visibleView, uiSourceCode);
968         else if (uiSourceCode instanceof WebInspector.StyleSource)
969             WebInspector.StyleSheetOutlineDialog.show(this.visibleView, /** @type {WebInspector.StyleSource} */ uiSourceCode);
970     },
971
972     _installDebuggerSidebarController: function()
973     {
974         this._toggleDebuggerSidebarButton = new WebInspector.StatusBarButton(WebInspector.UIString("Hide debugger"), "scripts-debugger-show-hide-button", 3);
975         this._toggleDebuggerSidebarButton.state = "shown";
976         this._toggleDebuggerSidebarButton.addEventListener("click", clickHandler, this);
977
978         function clickHandler()
979         {
980             if (this._toggleDebuggerSidebarButton.state === "shown")
981                 this._hideDebuggerSidebar();
982             else
983                 this._showDebuggerSidebar();
984         }
985         this.editorView.element.appendChild(this._toggleDebuggerSidebarButton.element);
986
987         if (WebInspector.settings.debuggerSidebarHidden.get())
988             this._hideDebuggerSidebar();
989
990     },
991
992     _showDebuggerSidebar: function()
993     {
994         if (this._toggleDebuggerSidebarButton.state === "shown")
995             return;
996         this._toggleDebuggerSidebarButton.state = "shown";
997         this._toggleDebuggerSidebarButton.title = WebInspector.UIString("Hide debugger");
998         this.splitView.showSidebarElement();
999         WebInspector.settings.debuggerSidebarHidden.set(false);
1000     },
1001
1002     _hideDebuggerSidebar: function()
1003     {
1004         if (this._toggleDebuggerSidebarButton.state === "hidden")
1005             return;
1006         this._toggleDebuggerSidebarButton.state = "hidden";
1007         this._toggleDebuggerSidebarButton.title = WebInspector.UIString("Show debugger");
1008         this.splitView.hideSidebarElement();
1009         WebInspector.settings.debuggerSidebarHidden.set(true);
1010     },
1011
1012     _fileRenamed: function(event)
1013     {
1014         var uiSourceCode = /** @type {WebInspector.UISourceCode} */ event.data.uiSourceCode;
1015         var name = /** @type {string} */ event.data.name;
1016         if (!uiSourceCode.isSnippet)
1017             return;
1018         var snippetJavaScriptSource = /** @type {WebInspector.SnippetJavaScriptSource} */ uiSourceCode;
1019         WebInspector.scriptSnippetModel.renameScriptSnippet(snippetJavaScriptSource, name);
1020     },
1021         
1022     _snippetCreationRequested: function()
1023     {
1024         var snippetJavaScriptSource = WebInspector.scriptSnippetModel.createScriptSnippet();
1025         this._showSourceLine(snippetJavaScriptSource);
1026         
1027         var shouldHideNavigator = !this._navigatorController.isNavigatorPinned();
1028         if (this._navigatorController.isNavigatorHidden())
1029             this._navigatorController.showNavigatorOverlay();
1030         this._navigator.rename(snippetJavaScriptSource, callback.bind(this));
1031     
1032         /**
1033          * @param {boolean} committed
1034          */
1035         function callback(committed)
1036         {
1037             if (shouldHideNavigator)
1038                 this._navigatorController.hideNavigatorOverlay();
1039
1040             if (!committed) {
1041                 WebInspector.scriptSnippetModel.deleteScriptSnippet(snippetJavaScriptSource);
1042                 return;
1043             }
1044
1045             this._showSourceLine(snippetJavaScriptSource);
1046         }
1047     },
1048
1049     /**
1050      * @param {WebInspector.UISourceCode} uiSourceCode
1051      */
1052     _showLocalHistory: function(uiSourceCode)
1053     {
1054         WebInspector.RevisionHistoryView.showHistory(uiSourceCode);
1055     },
1056
1057     /** 
1058      * @param {WebInspector.ContextMenu} contextMenu
1059      * @param {Object} target
1060      */
1061     appendApplicableItems: function(contextMenu, target)
1062     {
1063         if (!(target instanceof WebInspector.UISourceCode))
1064             return;
1065
1066         var uiSourceCode = /** @type {WebInspector.UISourceCode} */ target;
1067         contextMenu.appendItem(WebInspector.UIString("Local modifications..."), this._showLocalHistory.bind(this, uiSourceCode));
1068         if (uiSourceCode.resource() && uiSourceCode.resource().request)
1069             contextMenu.appendApplicableItems(uiSourceCode.resource().request);
1070     },
1071
1072     showGoToSourceDialog: function()
1073     {
1074         WebInspector.inspectorView.setCurrentPanel(this);
1075         WebInspector.OpenResourceDialog.show(this, this._uiSourceCodeProvider, this.editorView.mainElement);
1076     }
1077 }
1078
1079 WebInspector.ScriptsPanel.prototype.__proto__ = WebInspector.Panel.prototype;