Web Inspector: small memory leak in scripts panel.
[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  * @extends {WebInspector.Panel}
30  */
31 WebInspector.ScriptsPanel = function(presentationModel)
32 {
33     WebInspector.Panel.call(this, "scripts");
34
35     WebInspector.settings.pauseOnExceptionStateString = WebInspector.settings.createSetting("pauseOnExceptionStateString", WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions);
36
37     this._presentationModel = presentationModel;
38
39     function viewGetter()
40     {
41         return this.visibleView;
42     }
43     WebInspector.GoToLineDialog.install(this, viewGetter.bind(this));
44
45     this.topStatusBar = document.createElement("div");
46     this.topStatusBar.className = "status-bar";
47     this.topStatusBar.id = "scripts-status-bar";
48     this.element.appendChild(this.topStatusBar);
49
50     this.backButton = document.createElement("button");
51     this.backButton.className = "status-bar-item";
52     this.backButton.id = "scripts-back";
53     this.backButton.title = WebInspector.UIString("Show the previous script resource.");
54     this.backButton.disabled = true;
55     this.backButton.appendChild(document.createElement("img"));
56     this.backButton.addEventListener("click", this._goBack.bind(this), false);
57     this.topStatusBar.appendChild(this.backButton);
58
59     this.forwardButton = document.createElement("button");
60     this.forwardButton.className = "status-bar-item";
61     this.forwardButton.id = "scripts-forward";
62     this.forwardButton.title = WebInspector.UIString("Show the next script resource.");
63     this.forwardButton.disabled = true;
64     this.forwardButton.appendChild(document.createElement("img"));
65     this.forwardButton.addEventListener("click", this._goForward.bind(this), false);
66     this.topStatusBar.appendChild(this.forwardButton);
67
68     this._filesSelectElement = document.createElement("select");
69     this._filesSelectElement.className = "status-bar-item";
70     this._filesSelectElement.id = "scripts-files";
71     this._filesSelectElement.addEventListener("change", this._filesSelectChanged.bind(this), false);
72     this._filesSelectElement.addEventListener("keyup", this._filesSelectChanged.bind(this), false);
73     this.topStatusBar.appendChild(this._filesSelectElement);
74
75     this.functionsSelectElement = document.createElement("select");
76     this.functionsSelectElement.className = "status-bar-item";
77     this.functionsSelectElement.id = "scripts-functions";
78
79     // FIXME: append the functions select element to the top status bar when it is implemented.
80     // this.topStatusBar.appendChild(this.functionsSelectElement);
81
82     this._createSidebarButtons();
83
84     this.toggleBreakpointsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Deactivate all breakpoints."), "toggle-breakpoints");
85     this.toggleBreakpointsButton.toggled = true;
86     this.toggleBreakpointsButton.addEventListener("click", this._toggleBreakpointsClicked.bind(this), false);
87     this.sidebarButtonsElement.appendChild(this.toggleBreakpointsButton.element);
88
89     this.debuggerStatusElement = document.createElement("div");
90     this.debuggerStatusElement.id = "scripts-debugger-status";
91     this.sidebarButtonsElement.appendChild(this.debuggerStatusElement);
92
93     this.viewsContainerElement = document.createElement("div");
94     this.viewsContainerElement.id = "script-resource-views";
95
96     this.sidebarElement = document.createElement("div");
97     this.sidebarElement.id = "scripts-sidebar";
98
99     this.sidebarResizeElement = document.createElement("div");
100     this.sidebarResizeElement.className = "sidebar-resizer-vertical";
101     this.sidebarResizeElement.addEventListener("mousedown", this._startSidebarResizeDrag.bind(this), false);
102
103     this.sidebarResizeWidgetElement = document.createElement("div");
104     this.sidebarResizeWidgetElement.id = "scripts-sidebar-resizer-widget";
105     this.sidebarResizeWidgetElement.addEventListener("mousedown", this._startSidebarResizeDrag.bind(this), false);
106     this.topStatusBar.appendChild(this.sidebarResizeWidgetElement);
107
108     this.sidebarPanes = {};
109     this.sidebarPanes.watchExpressions = new WebInspector.WatchExpressionsSidebarPane();
110     this.sidebarPanes.callstack = new WebInspector.CallStackSidebarPane(this._presentationModel);
111     this.sidebarPanes.scopechain = new WebInspector.ScopeChainSidebarPane();
112     this.sidebarPanes.jsBreakpoints = new WebInspector.JavaScriptBreakpointsSidebarPane(this._presentationModel, this._showSourceLine.bind(this));
113     if (Preferences.nativeInstrumentationEnabled) {
114         this.sidebarPanes.domBreakpoints = WebInspector.domBreakpointsSidebarPane;
115         this.sidebarPanes.xhrBreakpoints = new WebInspector.XHRBreakpointsSidebarPane();
116         this.sidebarPanes.eventListenerBreakpoints = new WebInspector.EventListenerBreakpointsSidebarPane();
117     }
118
119     if (Preferences.canInspectWorkers && WebInspector.workerManager)
120         this.sidebarElement.addEventListener("contextmenu", this._contextMenu.bind(this), false);
121     if (Preferences.canInspectWorkers && WebInspector.workerManager && WebInspector.settings.workerInspectionEnabled.get()) {
122         WorkerAgent.setWorkerInspectionEnabled(true);
123         this.sidebarPanes.workerList = new WebInspector.WorkerListSidebarPane(WebInspector.workerManager);
124     } else
125         this.sidebarPanes.workers = new WebInspector.WorkersSidebarPane();
126
127     for (var pane in this.sidebarPanes)
128         this.sidebarElement.appendChild(this.sidebarPanes[pane].element);
129
130     this.sidebarPanes.callstack.expanded = true;
131
132     this.sidebarPanes.scopechain.expanded = true;
133     this.sidebarPanes.jsBreakpoints.expanded = true;
134
135     var helpSection = WebInspector.shortcutsScreen.section(WebInspector.UIString("Scripts Panel"));
136     this.sidebarPanes.callstack.registerShortcuts(helpSection, this.registerShortcut.bind(this));
137
138     var panelEnablerHeading = WebInspector.UIString("You need to enable debugging before you can use the Scripts panel.");
139     var panelEnablerDisclaimer = WebInspector.UIString("Enabling debugging will make scripts run slower.");
140     var panelEnablerButton = WebInspector.UIString("Enable Debugging");
141
142     this.panelEnablerView = new WebInspector.PanelEnablerView("scripts", panelEnablerHeading, panelEnablerDisclaimer, panelEnablerButton);
143     this.panelEnablerView.addEventListener("enable clicked", this._enableDebugging, this);
144
145     this.element.appendChild(this.panelEnablerView.element);
146     this.element.appendChild(this.viewsContainerElement);
147     this.element.appendChild(this.sidebarElement);
148     this.element.appendChild(this.sidebarResizeElement);
149
150     this.enableToggleButton = new WebInspector.StatusBarButton("", "enable-toggle-status-bar-item");
151     this.enableToggleButton.addEventListener("click", this._toggleDebugging.bind(this), false);
152     if (Preferences.debuggerAlwaysEnabled)
153         this.enableToggleButton.element.addStyleClass("hidden");
154
155     this._pauseOnExceptionButton = new WebInspector.StatusBarButton("", "scripts-pause-on-exceptions-status-bar-item", 3);
156     this._pauseOnExceptionButton.addEventListener("click", this._togglePauseOnExceptions.bind(this), false);
157
158     this._toggleFormatSourceButton = new WebInspector.StatusBarButton(WebInspector.UIString("Pretty print"), "scripts-toggle-pretty-print-status-bar-item");
159     this._toggleFormatSourceButton.toggled = false;
160     this._toggleFormatSourceButton.addEventListener("click", this._toggleFormatSource.bind(this), false);
161
162     this._scriptViewStatusBarItemsContainer = document.createElement("div");
163     this._scriptViewStatusBarItemsContainer.style.display = "inline-block";
164
165     this._debuggerEnabled = Preferences.debuggerAlwaysEnabled;
166
167     this.reset();
168
169     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerWasEnabled, this._debuggerWasEnabled, this);
170     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerWasDisabled, this._debuggerWasDisabled, this);
171
172     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this)
173     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.UISourceCodeReplaced, this._uiSourceCodeReplaced, this);
174     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.UISourceCodeRemoved, this._uiSourceCodeRemoved, this);
175     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.ConsoleMessageAdded, this._consoleMessageAdded, this);
176     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.ConsoleMessagesCleared, this._consoleMessagesCleared, this);
177     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.BreakpointAdded, this._breakpointAdded, this);
178     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.BreakpointRemoved, this._breakpointRemoved, this);
179     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.DebuggerPaused, this._debuggerPaused, this);
180     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.DebuggerResumed, this._debuggerResumed, this);
181     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.CallFrameSelected, this._callFrameSelected, this);
182     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.ExecutionLineChanged, this._executionLineChanged, this);
183
184     var enableDebugger = Preferences.debuggerAlwaysEnabled || WebInspector.settings.debuggerEnabled.get();
185     if (enableDebugger)
186         WebInspector.debuggerModel.enableDebugger();
187
188     WebInspector.settings.showScriptFolders.addChangeListener(this._showScriptFoldersSettingChanged.bind(this));
189 }
190
191 // Keep these in sync with WebCore::ScriptDebugServer
192 WebInspector.ScriptsPanel.PauseOnExceptionsState = {
193     DontPauseOnExceptions : "none",
194     PauseOnAllExceptions : "all",
195     PauseOnUncaughtExceptions: "uncaught"
196 };
197
198 WebInspector.ScriptsPanel.prototype = {
199     get toolbarItemLabel()
200     {
201         return WebInspector.UIString("Scripts");
202     },
203
204     get statusBarItems()
205     {
206         return [this.enableToggleButton.element, this._pauseOnExceptionButton.element, this._toggleFormatSourceButton.element, this._scriptViewStatusBarItemsContainer];
207     },
208
209     get defaultFocusedElement()
210     {
211         return this._filesSelectElement;
212     },
213
214     get paused()
215     {
216         return this._paused;
217     },
218
219     show: function()
220     {
221         WebInspector.Panel.prototype.show.call(this);
222         this.sidebarResizeElement.style.right = (this.sidebarElement.offsetWidth - 3) + "px";
223         if (Preferences.nativeInstrumentationEnabled)
224             this.sidebarElement.insertBefore(this.sidebarPanes.domBreakpoints.element, this.sidebarPanes.xhrBreakpoints.element);
225         this.sidebarPanes.watchExpressions.show();
226     },
227
228     get breakpointsActivated()
229     {
230         return this.toggleBreakpointsButton.toggled;
231     },
232
233     _uiSourceCodeAdded: function(event)
234     {
235         var uiSourceCode = event.data;
236
237         if (!uiSourceCode.url) {
238             // Anonymous sources are shown only when stepping.
239             return;
240         }
241
242         this._addOptionToFilesSelect(uiSourceCode);
243
244         var lastViewedURL = WebInspector.settings.lastViewedScriptFile.get();
245         if (!this._filesSelectElement.initialSelectionProcessed) {
246             this._filesSelectElement.initialSelectionProcessed = true;
247             // Option we just added is the only option in files select.
248             // We have to show corresponding source frame immediately.
249             this._showSourceFrameAndAddToHistory(uiSourceCode);
250             // Restore original value of lastViewedScriptFile because
251             // source frame was shown as a result of initial load.
252             WebInspector.settings.lastViewedScriptFile.set(lastViewedURL);
253         } else if (uiSourceCode.url === lastViewedURL)
254             this._showSourceFrameAndAddToHistory(uiSourceCode);
255     },
256
257     _uiSourceCodeRemoved: function(event)
258     {
259         var uiSourceCode = event.data;
260         if (uiSourceCode._sourceFrame)
261             this.removeChildView(uiSourceCode._sourceFrame);
262     },
263
264     _showScriptFoldersSettingChanged: function()
265     {
266         var selectedOption = this._filesSelectElement[this._filesSelectElement.selectedIndex];
267         var uiSourceCode = selectedOption ? selectedOption._uiSourceCode : null;
268
269         var options = Array.prototype.slice.call(this._filesSelectElement);
270         this._resetFilesSelect();
271         for (var i = 0; i < options.length; ++i) {
272             if (options[i]._uiSourceCode)
273                 this._addOptionToFilesSelect(options[i]._uiSourceCode);
274         }
275
276         if (uiSourceCode) {
277             var index = uiSourceCode._option.index;
278             if (typeof index === "number")
279                 this._filesSelectElement.selectedIndex = index;
280         }
281     },
282
283     _addOptionToFilesSelect: function(uiSourceCode)
284     {
285         var showScriptFolders = WebInspector.settings.showScriptFolders.get();
286
287         var select = this._filesSelectElement;
288         if (!select.domainOptions)
289             select.domainOptions = {};
290         if (!select.folderOptions)
291             select.folderOptions = {};
292
293         var option = document.createElement("option");
294         option._uiSourceCode = uiSourceCode;
295         var parsedURL = uiSourceCode.url.asParsedURL();
296
297         const indent = WebInspector.isMac() ? "" : "\u00a0\u00a0\u00a0\u00a0";
298
299         var names = this._folderAndDisplayNameForScriptURL(uiSourceCode.url);
300         option.displayName = names.displayName;
301
302         var contentScriptPrefix = uiSourceCode.isContentScript ? "2:" : "0:";
303
304         if (uiSourceCode.isContentScript && names.domain) {
305             // Render extension domain as a path in structured view
306             names.folderName = names.domain + (names.folderName ? names.folderName : "");
307             delete names.domain;
308         }
309
310         var folderNameForSorting = contentScriptPrefix + (names.domain ? names.domain + "\t\t" : "") + names.folderName;
311
312         if (showScriptFolders) {
313             option.text = indent + (names.displayName ? names.displayName : WebInspector.UIString("(program)"));
314             option.nameForSorting = folderNameForSorting + "\t/\t" + names.displayName; // Use '\t' to make files stick to their folder.
315         } else {
316             option.text = names.displayName ? names.displayName : WebInspector.UIString("(program)");
317             // Content script should contain its domain name as a prefix
318             if (uiSourceCode.isContentScript && names.folderName)
319                 option.text = names.folderName + "/" + option.text;
320             option.nameForSorting = contentScriptPrefix + option.text;
321         }
322         option.title = uiSourceCode.url;
323
324         if (uiSourceCode.isContentScript)
325             option.addStyleClass("extension-script");
326
327         function insertOrdered(option)
328         {
329             function optionCompare(a, b)
330             {
331                 return a.nameForSorting.localeCompare(b.nameForSorting);
332             }
333             var insertionIndex = insertionIndexForObjectInListSortedByFunction(option, select.childNodes, optionCompare);
334             select.insertBefore(option, insertionIndex < 0 ? null : select.childNodes.item(insertionIndex));
335         }
336
337         insertOrdered(option);
338
339         if (uiSourceCode.isContentScript && !select.contentScriptSection) {
340             var contentScriptSection = document.createElement("option");
341             contentScriptSection.text = "\u2014 " + WebInspector.UIString("Content scripts") + " \u2014";
342             contentScriptSection.disabled = true;
343             contentScriptSection.nameForSorting = "1/ContentScriptSeparator";
344             select.contentScriptSection = contentScriptSection;
345             insertOrdered(contentScriptSection);
346         }
347
348         if (showScriptFolders && !uiSourceCode.isContentScript && names.domain && !select.domainOptions[names.domain]) {
349             var domainOption = document.createElement("option");
350             domainOption.text = "\u2014 " + names.domain + " \u2014";
351             domainOption.nameForSorting = "0:" + names.domain;
352             domainOption.disabled = true;
353             select.domainOptions[names.domain] = domainOption;
354             insertOrdered(domainOption);
355         }
356
357         if (showScriptFolders && names.folderName && !select.folderOptions[folderNameForSorting]) {
358             var folderOption = document.createElement("option");
359             folderOption.text = names.folderName;
360             folderOption.nameForSorting = folderNameForSorting;
361             folderOption.disabled = true;
362             select.folderOptions[folderNameForSorting] = folderOption;
363             insertOrdered(folderOption);
364         }
365
366         option._uiSourceCode = uiSourceCode;
367         uiSourceCode._option = option;
368     },
369
370     _folderAndDisplayNameForScriptURL: function(url)
371     {
372         var parsedURL = url.asParsedURL();
373         if (parsedURL)
374             url = parsedURL.path;
375
376         var folderName = "";
377         var displayName = url;
378
379         var pathLength = displayName.indexOf("?");
380         if (pathLength === -1)
381             pathLength = displayName.length;
382
383         var fromIndex = displayName.lastIndexOf("/", pathLength - 2);
384         if (fromIndex !== -1) {
385             folderName = displayName.substring(0, fromIndex);
386             displayName = displayName.substring(fromIndex + 1);
387         }
388
389         if (displayName.length > 80)
390             displayName = "\u2026" + displayName.substring(displayName.length - 80);
391
392         if (folderName.length > 80)
393             folderName = "\u2026" + folderName.substring(folderName.length - 80);
394
395         return { domain: (parsedURL ? parsedURL.host : ""), folderName: folderName, displayName: displayName };
396     },
397
398     _setScriptSourceIsBeingEdited: function(uiSourceCode, inEditMode)
399     {
400         var option = uiSourceCode._option;
401         if (!option)
402             return;
403         if (inEditMode)
404             option.text = option.text.replace(/[^*]$/, "$&*");
405         else
406             option.text = option.text.replace(/[*]$/, "");
407     },
408
409     _consoleMessagesCleared: function()
410     {
411         for (var i = 0; i < this._filesSelectElement.length; ++i) {
412             var option = this._filesSelectElement[i];
413             if (option._uiSourceCode && option._uiSourceCode._sourceFrame)
414                 option._uiSourceCode._sourceFrame.clearMessages();
415         }
416     },
417
418     _consoleMessageAdded: function(event)
419     {
420         var message = event.data;
421
422         var sourceFrame = message.uiSourceCode._sourceFrame;
423         if (sourceFrame && sourceFrame.loaded)
424             sourceFrame.addMessageToSource(message.lineNumber, message.originalMessage);
425     },
426
427     _breakpointAdded: function(event)
428     {
429         var breakpoint = event.data;
430
431         var sourceFrame = breakpoint.uiSourceCode._sourceFrame;
432         if (sourceFrame && sourceFrame.loaded)
433             sourceFrame.addBreakpoint(breakpoint.lineNumber, breakpoint.resolved, breakpoint.condition, breakpoint.enabled);
434
435         this.sidebarPanes.jsBreakpoints.addBreakpoint(breakpoint);
436     },
437
438     _breakpointRemoved: function(event)
439     {
440         var breakpoint = event.data;
441
442         var sourceFrame = breakpoint.uiSourceCode._sourceFrame;
443         if (sourceFrame && sourceFrame.loaded)
444             sourceFrame.removeBreakpoint(breakpoint.lineNumber);
445
446         this.sidebarPanes.jsBreakpoints.removeBreakpoint(breakpoint.uiSourceCode, breakpoint.lineNumber);
447     },
448
449     evaluateInSelectedCallFrame: function(code, objectGroup, includeCommandLineAPI, returnByValue, callback)
450     {
451         function didEvaluate()
452         {
453             if (objectGroup === "console")
454                 this.sidebarPanes.scopechain.update(this._presentationModel.selectedCallFrame);
455             callback.apply(null, arguments);
456         }
457         var selectedCallFrame = this._presentationModel.selectedCallFrame;
458         selectedCallFrame.evaluate(code, objectGroup, includeCommandLineAPI, returnByValue, didEvaluate.bind(this));
459     },
460
461     getSelectedCallFrameVariables: function(callback)
462     {
463         var result = { this: true };
464
465         var selectedCallFrame = this._presentationModel.selectedCallFrame;
466         if (!selectedCallFrame)
467             callback(result);
468
469         var pendingRequests = 0;
470
471         function propertiesCollected(properties)
472         {
473             for (var i = 0; properties && i < properties.length; ++i)
474                 result[properties[i].name] = true;
475             if (--pendingRequests == 0)
476                 callback(result);
477         }
478
479         for (var i = 0; i < selectedCallFrame.scopeChain.length; ++i) {
480             var scope = selectedCallFrame.scopeChain[i];
481             var object = WebInspector.RemoteObject.fromPayload(scope.object);
482             pendingRequests++;
483             object.getAllProperties(propertiesCollected);
484         }
485     },
486
487     _debuggerPaused: function(event)
488     {
489         var callFrames = event.data.callFrames;
490         var details = event.data.details;
491
492         this._paused = true;
493         this._waitingToPause = false;
494         this._stepping = false;
495
496         this._updateDebuggerButtons();
497
498         WebInspector.setCurrentPanel(this);
499
500         this.sidebarPanes.callstack.update(callFrames);
501         this.sidebarPanes.callstack.selectedCallFrame = this._presentationModel.selectedCallFrame;
502
503         if (details.reason === WebInspector.DebuggerModel.BreakReason.DOM) {
504             this.sidebarPanes.domBreakpoints.highlightBreakpoint(details.auxData);
505             function didCreateBreakpointHitStatusMessage(element)
506             {
507                 this.sidebarPanes.callstack.setStatus(element);
508             }
509             this.sidebarPanes.domBreakpoints.createBreakpointHitStatusMessage(details.auxData, didCreateBreakpointHitStatusMessage.bind(this));
510         } else if (details.reason === WebInspector.DebuggerModel.BreakReason.EventListener) {
511             var eventName = details.auxData.eventName;
512             this.sidebarPanes.eventListenerBreakpoints.highlightBreakpoint(details.auxData.eventName);
513             var eventNameForUI = WebInspector.EventListenerBreakpointsSidebarPane.eventNameForUI(eventName);
514             this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a \"%s\" Event Listener.", eventNameForUI));
515         } else if (details.reason === WebInspector.DebuggerModel.BreakReason.XHR) {
516             this.sidebarPanes.xhrBreakpoints.highlightBreakpoint(details.auxData["breakpointURL"]);
517             this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a XMLHttpRequest."));
518         } else if (details.reason === WebInspector.DebuggerModel.BreakReason.Exception) {
519             this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on exception: '%s'.", details.auxData.description));
520         } else {
521             function didGetUILocation(uiLocation)
522             {
523                 if (!this._presentationModel.findBreakpoint(uiLocation.uiSourceCode, uiLocation.lineNumber))
524                     return;
525                 this.sidebarPanes.jsBreakpoints.highlightBreakpoint(uiLocation.uiSourceCode, uiLocation.lineNumber);
526                 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a JavaScript breakpoint."));
527             }
528             callFrames[0].uiLocation(didGetUILocation.bind(this));
529         }
530
531         window.focus();
532         InspectorFrontendHost.bringToFront();
533     },
534
535     _debuggerResumed: function()
536     {
537         this._paused = false;
538         this._waitingToPause = false;
539         this._stepping = false;
540
541         this._clearInterface();
542     },
543
544     _debuggerWasEnabled: function()
545     {
546         this._setPauseOnExceptions(WebInspector.settings.pauseOnExceptionStateString.get());
547
548         if (this._debuggerEnabled)
549             return;
550
551         this._debuggerEnabled = true;
552         this.reset(true);
553     },
554
555     _debuggerWasDisabled: function()
556     {
557         if (!this._debuggerEnabled)
558             return;
559
560         this._debuggerEnabled = false;
561         this.reset(true);
562     },
563
564     reset: function(preserveItems)
565     {
566         this.visibleView = null;
567
568         delete this.currentQuery;
569         this.searchCanceled();
570
571         this._debuggerResumed();
572
573         this._backForwardList = [];
574         this._currentBackForwardIndex = -1;
575         this._updateBackAndForwardButtons();
576
577         this._resetFilesSelect();
578         delete this._filesSelectElement.initialSelectionProcessed;
579
580         this.functionsSelectElement.removeChildren();
581         this.viewsContainerElement.removeChildren();
582
583         this.sidebarPanes.jsBreakpoints.reset();
584         this.sidebarPanes.watchExpressions.reset();
585         if (!preserveItems && this.sidebarPanes.workers)
586             this.sidebarPanes.workers.reset();
587     },
588
589     _resetFilesSelect: function()
590     {
591         this._filesSelectElement.removeChildren();
592         this._filesSelectElement.domainOptions = {};
593         this._filesSelectElement.folderOptions = {};
594         delete this._filesSelectElement.contentScriptSection;
595     },
596
597     get visibleView()
598     {
599         return this._visibleView;
600     },
601
602     set visibleView(x)
603     {
604         if (this._visibleView === x)
605             return;
606
607         if (this._visibleView)
608             this._visibleView.hide();
609
610         this._visibleView = x;
611
612         if (x) {
613             x.show(this.viewsContainerElement);
614             this._scriptViewStatusBarItemsContainer.removeChildren();
615             var statusBarItems = x.statusBarItems || [];
616             for (var i = 0; i < statusBarItems.length; ++i)
617                 this._scriptViewStatusBarItemsContainer.appendChild(statusBarItems[i]);
618         }
619     },
620
621     canShowAnchorLocation: function(anchor)
622     {
623         return this._debuggerEnabled && WebInspector.debuggerModel.scriptsForURL(anchor.href).length;
624     },
625
626     showAnchorLocation: function(anchor)
627     {
628         this._showSourceLine(anchor.uiSourceCode, anchor.lineNumber);
629     },
630
631     _showSourceLine: function(uiSourceCode, lineNumber)
632     {
633         var sourceFrame = this._showSourceFrameAndAddToHistory(uiSourceCode);
634         sourceFrame.highlightLine(lineNumber);
635     },
636
637     _showSourceFrameAndAddToHistory: function(uiSourceCode)
638     {
639         if (!uiSourceCode._option)
640             return;
641
642         var sourceFrame = this._showSourceFrame(uiSourceCode);
643
644         var oldIndex = this._currentBackForwardIndex;
645         if (oldIndex >= 0)
646             this._backForwardList.splice(oldIndex + 1, this._backForwardList.length - oldIndex);
647
648         // Check for a previous entry of the same object in _backForwardList.
649         // If one is found, remove it.
650         var previousEntryIndex = this._backForwardList.indexOf(uiSourceCode);
651         if (previousEntryIndex !== -1)
652             this._backForwardList.splice(previousEntryIndex, 1);
653
654         this._backForwardList.push(uiSourceCode);
655         this._currentBackForwardIndex = this._backForwardList.length - 1;
656
657         this._updateBackAndForwardButtons();
658
659         return sourceFrame;
660     },
661
662     _showSourceFrame: function(uiSourceCode)
663     {
664         this._filesSelectElement.selectedIndex = uiSourceCode._option.index;
665
666         var sourceFrame = uiSourceCode._sourceFrame || this._createSourceFrame(uiSourceCode);
667         this.visibleView = sourceFrame;
668
669         if (uiSourceCode.url)
670             WebInspector.settings.lastViewedScriptFile.set(uiSourceCode.url);
671
672         return sourceFrame;
673     },
674
675     _createSourceFrame: function(uiSourceCode)
676     {
677         var delegate = new WebInspector.SourceFrameDelegateForScriptsPanel(this, uiSourceCode);
678         var sourceFrame = new WebInspector.JavaScriptSourceFrame(delegate, uiSourceCode);
679
680         this.addChildView(sourceFrame);
681         sourceFrame._uiSourceCode = uiSourceCode;
682         sourceFrame.addEventListener(WebInspector.SourceFrame.Events.Loaded, this._sourceFrameLoaded, this);
683         uiSourceCode._sourceFrame = sourceFrame;
684         return sourceFrame;
685     },
686
687     _removeSourceFrame: function(uiSourceCode)
688     {
689         var sourceFrame = uiSourceCode._sourceFrame;
690         if (!sourceFrame)
691             return;
692         delete uiSourceCode._sourceFrame;
693         this.removeChildView(sourceFrame);
694         sourceFrame.removeEventListener(WebInspector.SourceFrame.Events.Loaded, this._sourceFrameLoaded, this);
695     },
696
697     _uiSourceCodeReplaced: function(event)
698     {
699         var oldUISourceCode = event.data.oldUISourceCode;
700         var uiSourceCode = event.data.uiSourceCode;
701
702         // Re-bind file select option from old source file to new one.
703         var option = oldUISourceCode._option;
704         if (!option)
705             return;
706         delete oldUISourceCode._option;
707         option._uiSourceCode = uiSourceCode;
708         uiSourceCode._option = option;
709
710         // Remove old source frame and create new one if needed.
711         this._removeSourceFrame(oldUISourceCode);
712         if (option === this._filesSelectElement[this._filesSelectElement.selectedIndex])
713             this._showSourceFrame(uiSourceCode);
714     },
715
716     _sourceFrameLoaded: function(event)
717     {
718         var sourceFrame = event.target;
719         var uiSourceCode = sourceFrame._uiSourceCode;
720
721         var messages = this._presentationModel.messagesForUISourceCode(uiSourceCode);
722         for (var i = 0; i < messages.length; ++i) {
723             var message = messages[i];
724             sourceFrame.addMessageToSource(message.lineNumber, message.originalMessage);
725         }
726
727         var breakpoints = this._presentationModel.breakpointsForUISourceCode(uiSourceCode);
728         for (var i = 0; i < breakpoints.length; ++i) {
729             var breakpoint = breakpoints[i];
730             sourceFrame.addBreakpoint(breakpoint.lineNumber, breakpoint.resolved, breakpoint.condition, breakpoint.enabled);
731         }
732     },
733
734     _clearCurrentExecutionLine: function()
735     {
736         if (this._executionSourceFrame)
737             this._executionSourceFrame.clearExecutionLine();
738         delete this._executionSourceFrame;
739     },
740
741     _executionLineChanged: function(event)
742     {
743         var uiLocation = event.data;
744
745         this._clearCurrentExecutionLine();
746         if (!uiLocation)
747             return;
748
749         if (!uiLocation.uiSourceCode._option) {
750             // Anonymous scripts are not added to files select by default.
751             this._addOptionToFilesSelect(uiLocation.uiSourceCode);
752         }
753         var sourceFrame = this._showSourceFrameAndAddToHistory(uiLocation.uiSourceCode);
754         sourceFrame.setExecutionLine(uiLocation.lineNumber);
755         this._executionSourceFrame = sourceFrame;
756     },
757
758     _callFrameSelected: function(event)
759     {
760         var callFrame = event.data;
761
762         if (!callFrame)
763             return;
764
765         this.sidebarPanes.scopechain.update(callFrame);
766         this.sidebarPanes.watchExpressions.refreshExpressions();
767         this.sidebarPanes.callstack.selectedCallFrame = this._presentationModel.selectedCallFrame;
768     },
769
770     _filesSelectChanged: function()
771     {
772         if (this._filesSelectElement.selectedIndex === -1)
773             return;
774
775         var uiSourceCode = this._filesSelectElement[this._filesSelectElement.selectedIndex]._uiSourceCode;
776         this._showSourceFrameAndAddToHistory(uiSourceCode);
777     },
778
779     _startSidebarResizeDrag: function(event)
780     {
781         WebInspector.elementDragStart(this.sidebarElement, this._sidebarResizeDrag.bind(this), this._endSidebarResizeDrag.bind(this), event, "ew-resize");
782
783         if (event.target === this.sidebarResizeWidgetElement)
784             this._dragOffset = (event.target.offsetWidth - (event.pageX - event.target.totalOffsetLeft()));
785         else
786             this._dragOffset = 0;
787     },
788
789     _endSidebarResizeDrag: function(event)
790     {
791         WebInspector.elementDragEnd(event);
792         delete this._dragOffset;
793         this.saveSidebarWidth();
794     },
795
796     _sidebarResizeDrag: function(event)
797     {
798         var x = event.pageX + this._dragOffset;
799         var newWidth = Number.constrain(window.innerWidth - x, Preferences.minScriptsSidebarWidth, window.innerWidth * 0.66);
800         this.setSidebarWidth(newWidth);
801         event.preventDefault();
802     },
803
804     setSidebarWidth: function(newWidth)
805     {
806         this.sidebarElement.style.width = newWidth + "px";
807         this.sidebarButtonsElement.style.width = newWidth + "px";
808         this.viewsContainerElement.style.right = newWidth + "px";
809         this.sidebarResizeWidgetElement.style.right = newWidth + "px";
810         this.sidebarResizeElement.style.right = (newWidth - 3) + "px";
811
812         this.doResize();
813     },
814
815     _setPauseOnExceptions: function(pauseOnExceptionsState)
816     {
817         pauseOnExceptionsState = pauseOnExceptionsState || WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions;
818         function callback(error)
819         {
820             if (error)
821                 return;
822             if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions)
823                 this._pauseOnExceptionButton.title = WebInspector.UIString("Don't pause on exceptions.\nClick to Pause on all exceptions.");
824             else if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.PauseOnAllExceptions)
825                 this._pauseOnExceptionButton.title = WebInspector.UIString("Pause on all exceptions.\nClick to Pause on uncaught exceptions.");
826             else if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.PauseOnUncaughtExceptions)
827                 this._pauseOnExceptionButton.title = WebInspector.UIString("Pause on uncaught exceptions.\nClick to Not pause on exceptions.");
828
829             this._pauseOnExceptionButton.state = pauseOnExceptionsState;
830             WebInspector.settings.pauseOnExceptionStateString.set(pauseOnExceptionsState);
831         }
832         DebuggerAgent.setPauseOnExceptions(pauseOnExceptionsState, callback.bind(this));
833     },
834
835     _updateDebuggerButtons: function()
836     {
837         if (this._debuggerEnabled) {
838             this.enableToggleButton.title = WebInspector.UIString("Debugging enabled. Click to disable.");
839             this.enableToggleButton.toggled = true;
840             this._pauseOnExceptionButton.visible = true;
841             this.panelEnablerView.visible = false;
842         } else {
843             this.enableToggleButton.title = WebInspector.UIString("Debugging disabled. Click to enable.");
844             this.enableToggleButton.toggled = false;
845             this._pauseOnExceptionButton.visible = false;
846             this.panelEnablerView.visible = true;
847         }
848
849         if (this._paused) {
850             this.pauseButton.addStyleClass("paused");
851
852             this.pauseButton.disabled = false;
853             this.stepOverButton.disabled = false;
854             this.stepIntoButton.disabled = false;
855             this.stepOutButton.disabled = false;
856
857             this.debuggerStatusElement.textContent = WebInspector.UIString("Paused");
858         } else {
859             this.pauseButton.removeStyleClass("paused");
860
861             this.pauseButton.disabled = this._waitingToPause;
862             this.stepOverButton.disabled = true;
863             this.stepIntoButton.disabled = true;
864             this.stepOutButton.disabled = true;
865
866             if (this._waitingToPause)
867                 this.debuggerStatusElement.textContent = WebInspector.UIString("Pausing");
868             else if (this._stepping)
869                 this.debuggerStatusElement.textContent = WebInspector.UIString("Stepping");
870             else
871                 this.debuggerStatusElement.textContent = "";
872         }
873     },
874
875     _updateBackAndForwardButtons: function()
876     {
877         this.backButton.disabled = this._currentBackForwardIndex <= 0;
878         this.forwardButton.disabled = this._currentBackForwardIndex >= (this._backForwardList.length - 1);
879     },
880
881     _clearInterface: function()
882     {
883         this.sidebarPanes.callstack.update(null);
884         this.sidebarPanes.scopechain.update(null);
885         this.sidebarPanes.jsBreakpoints.clearBreakpointHighlight();
886         if (Preferences.nativeInstrumentationEnabled) {
887             this.sidebarPanes.domBreakpoints.clearBreakpointHighlight();
888             this.sidebarPanes.eventListenerBreakpoints.clearBreakpointHighlight();
889             this.sidebarPanes.xhrBreakpoints.clearBreakpointHighlight();
890         }
891
892         this._clearCurrentExecutionLine();
893         this._updateDebuggerButtons();
894     },
895
896     _goBack: function()
897     {
898         if (this._currentBackForwardIndex <= 0) {
899             console.error("Can't go back from index " + this._currentBackForwardIndex);
900             return;
901         }
902
903         this._showSourceFrame(this._backForwardList[--this._currentBackForwardIndex]);
904         this._updateBackAndForwardButtons();
905     },
906
907     _goForward: function()
908     {
909         if (this._currentBackForwardIndex >= this._backForwardList.length - 1) {
910             console.error("Can't go forward from index " + this._currentBackForwardIndex);
911             return;
912         }
913
914         this._showSourceFrame(this._backForwardList[++this._currentBackForwardIndex]);
915         this._updateBackAndForwardButtons();
916     },
917
918     _enableDebugging: function()
919     {
920         if (this._debuggerEnabled)
921             return;
922         this._toggleDebugging(this.panelEnablerView.alwaysEnabled);
923     },
924
925     _toggleDebugging: function(optionalAlways)
926     {
927         this._paused = false;
928         this._waitingToPause = false;
929         this._stepping = false;
930
931         if (this._debuggerEnabled) {
932             WebInspector.settings.debuggerEnabled.set(false);
933             WebInspector.debuggerModel.disableDebugger();
934         } else {
935             WebInspector.settings.debuggerEnabled.set(!!optionalAlways);
936             WebInspector.debuggerModel.enableDebugger();
937         }
938     },
939
940     _togglePauseOnExceptions: function()
941     {
942         var nextStateMap = {};
943         var stateEnum = WebInspector.ScriptsPanel.PauseOnExceptionsState;
944         nextStateMap[stateEnum.DontPauseOnExceptions] = stateEnum.PauseOnAllExceptions;
945         nextStateMap[stateEnum.PauseOnAllExceptions] = stateEnum.PauseOnUncaughtExceptions;
946         nextStateMap[stateEnum.PauseOnUncaughtExceptions] = stateEnum.DontPauseOnExceptions;
947         this._setPauseOnExceptions(nextStateMap[this._pauseOnExceptionButton.state]);
948     },
949
950     _togglePause: function()
951     {
952         if (this._paused) {
953             this._paused = false;
954             this._waitingToPause = false;
955             DebuggerAgent.resume();
956         } else {
957             this._stepping = false;
958             this._waitingToPause = true;
959             DebuggerAgent.pause();
960         }
961
962         this._clearInterface();
963     },
964
965     _stepOverClicked: function()
966     {
967         if (!this._paused)
968             return;
969
970         this._paused = false;
971         this._stepping = true;
972
973         this._clearInterface();
974
975         DebuggerAgent.stepOver();
976     },
977
978     _stepIntoClicked: function()
979     {
980         if (!this._paused)
981             return;
982
983         this._paused = false;
984         this._stepping = true;
985
986         this._clearInterface();
987
988         DebuggerAgent.stepInto();
989     },
990
991     _stepOutClicked: function()
992     {
993         if (!this._paused)
994             return;
995
996         this._paused = false;
997         this._stepping = true;
998
999         this._clearInterface();
1000
1001         DebuggerAgent.stepOut();
1002     },
1003
1004     _toggleBreakpointsClicked: function()
1005     {
1006         this.toggleBreakpointsButton.toggled = !this.toggleBreakpointsButton.toggled;
1007         if (this.toggleBreakpointsButton.toggled) {
1008             DebuggerAgent.setBreakpointsActive(true);
1009             this.toggleBreakpointsButton.title = WebInspector.UIString("Deactivate all breakpoints.");
1010             document.getElementById("main-panels").removeStyleClass("breakpoints-deactivated");
1011         } else {
1012             DebuggerAgent.setBreakpointsActive(false);
1013             this.toggleBreakpointsButton.title = WebInspector.UIString("Activate all breakpoints.");
1014             document.getElementById("main-panels").addStyleClass("breakpoints-deactivated");
1015         }
1016     },
1017
1018     elementsToRestoreScrollPositionsFor: function()
1019     {
1020         return [ this.sidebarElement ];
1021     },
1022
1023     _createSidebarButtons: function()
1024     {
1025         this.sidebarButtonsElement = document.createElement("div");
1026         this.sidebarButtonsElement.id = "scripts-sidebar-buttons";
1027         this.topStatusBar.appendChild(this.sidebarButtonsElement);
1028
1029         var title, handler, shortcuts;
1030         var platformSpecificModifier = WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta;
1031
1032         // Continue.
1033         title = WebInspector.UIString("Pause script execution (%s).");
1034         handler = this._togglePause.bind(this);
1035         shortcuts = [];
1036         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F8));
1037         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Slash, platformSpecificModifier));
1038         this.pauseButton = this._createSidebarButtonAndRegisterShortcuts("scripts-pause", title, handler, shortcuts, WebInspector.UIString("Pause/Continue"));
1039
1040         // Step over.
1041         title = WebInspector.UIString("Step over next function call (%s).");
1042         handler = this._stepOverClicked.bind(this);
1043         shortcuts = [];
1044         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F10));
1045         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.SingleQuote, platformSpecificModifier));
1046         this.stepOverButton = this._createSidebarButtonAndRegisterShortcuts("scripts-step-over", title, handler, shortcuts, WebInspector.UIString("Step over"));
1047
1048         // Step into.
1049         title = WebInspector.UIString("Step into next function call (%s).");
1050         handler = this._stepIntoClicked.bind(this);
1051         shortcuts = [];
1052         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F11));
1053         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Semicolon, platformSpecificModifier));
1054         this.stepIntoButton = this._createSidebarButtonAndRegisterShortcuts("scripts-step-into", title, handler, shortcuts, WebInspector.UIString("Step into"));
1055
1056         // Step out.
1057         title = WebInspector.UIString("Step out of current function (%s).");
1058         handler = this._stepOutClicked.bind(this);
1059         shortcuts = [];
1060         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F11, WebInspector.KeyboardShortcut.Modifiers.Shift));
1061         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Semicolon, WebInspector.KeyboardShortcut.Modifiers.Shift | platformSpecificModifier));
1062         this.stepOutButton = this._createSidebarButtonAndRegisterShortcuts("scripts-step-out", title, handler, shortcuts, WebInspector.UIString("Step out"));
1063     },
1064
1065     _createSidebarButtonAndRegisterShortcuts: function(buttonId, buttonTitle, handler, shortcuts, shortcutDescription)
1066     {
1067         var button = document.createElement("button");
1068         button.className = "status-bar-item";
1069         button.id = buttonId;
1070         button.title = String.vsprintf(buttonTitle, [shortcuts[0].name]);
1071         button.disabled = true;
1072         button.appendChild(document.createElement("img"));
1073         button.addEventListener("click", handler, false);
1074         this.sidebarButtonsElement.appendChild(button);
1075
1076         var shortcutNames = [];
1077         for (var i = 0; i < shortcuts.length; ++i) {
1078             this.registerShortcut(shortcuts[i].key, handler);
1079             shortcutNames.push(shortcuts[i].name);
1080         }
1081         var section = WebInspector.shortcutsScreen.section(WebInspector.UIString("Scripts Panel"));
1082         section.addAlternateKeys(shortcutNames, shortcutDescription);
1083
1084         return button;
1085     },
1086
1087     searchCanceled: function()
1088     {
1089         if (this._searchView)
1090             this._searchView.searchCanceled();
1091
1092         delete this._searchView;
1093         delete this._searchQuery;
1094     },
1095
1096     performSearch: function(query)
1097     {
1098         WebInspector.searchController.updateSearchMatchesCount(0, this);
1099
1100         if (!this.visibleView)
1101             return;
1102
1103         // Call searchCanceled since it will reset everything we need before doing a new search.
1104         this.searchCanceled();
1105
1106         this._searchView = this.visibleView;
1107         this._searchQuery = query;
1108
1109         function finishedCallback(view, searchMatches)
1110         {
1111             if (!searchMatches)
1112                 return;
1113
1114             WebInspector.searchController.updateSearchMatchesCount(searchMatches, this);
1115             view.jumpToFirstSearchResult();
1116             WebInspector.searchController.updateCurrentMatchIndex(view.currentSearchResultIndex + 1, this);
1117         }
1118
1119         this._searchView.performSearch(query, finishedCallback.bind(this));
1120     },
1121
1122     jumpToNextSearchResult: function()
1123     {
1124         if (!this._searchView)
1125             return;
1126
1127         if (this._searchView !== this.visibleView) {
1128             this.performSearch(this._searchQuery);
1129             return;
1130         }
1131
1132         if (this._searchView.showingLastSearchResult())
1133             this._searchView.jumpToFirstSearchResult();
1134         else
1135             this._searchView.jumpToNextSearchResult();
1136         WebInspector.searchController.updateCurrentMatchIndex(this._searchView.currentSearchResultIndex + 1, this);
1137     },
1138
1139     jumpToPreviousSearchResult: function()
1140     {
1141         if (!this._searchView)
1142             return;
1143
1144         if (this._searchView !== this.visibleView) {
1145             this.performSearch(this._searchQuery);
1146             if (this._searchView)
1147                 this._searchView.jumpToLastSearchResult();
1148             return;
1149         }
1150
1151         if (this._searchView.showingFirstSearchResult())
1152             this._searchView.jumpToLastSearchResult();
1153         else
1154             this._searchView.jumpToPreviousSearchResult();
1155         WebInspector.searchController.updateCurrentMatchIndex(this._searchView.currentSearchResultIndex + 1, this);
1156     },
1157
1158     _toggleFormatSource: function()
1159     {
1160         this._toggleFormatSourceButton.toggled = !this._toggleFormatSourceButton.toggled;
1161         this._presentationModel.setFormatSource(this._toggleFormatSourceButton.toggled);
1162     },
1163
1164     _contextMenu: function(event)
1165     {
1166         var contextMenu = new WebInspector.ContextMenu();
1167
1168         function enableWorkerInspection()
1169         {
1170             var newValue = !WebInspector.settings.workerInspectionEnabled.get();
1171             WebInspector.settings.workerInspectionEnabled.set(newValue);
1172             WorkerAgent.setWorkerInspectionEnabled(newValue);
1173             if (newValue) {
1174                 var element = this.sidebarPanes.workers.element;
1175                 delete this.sidebarPanes.workers;
1176                 this.sidebarPanes.workerList = new WebInspector.WorkerListSidebarPane(WebInspector.workerManager);
1177                 element.parentNode.replaceChild(this.sidebarPanes.workerList.element, element);
1178             } else {
1179                 var element = this.sidebarPanes.workerList.element;
1180                 delete this.sidebarPanes.workerList;
1181                 this.sidebarPanes.workers = new WebInspector.WorkersSidebarPane();
1182                 element.parentNode.replaceChild(this.sidebarPanes.workers.element, element);
1183             }
1184         }
1185         contextMenu.appendCheckboxItem(WebInspector.UIString("Enable worker inspection"), enableWorkerInspection.bind(this), WebInspector.settings.workerInspectionEnabled.get());
1186
1187         contextMenu.show(event);
1188     }
1189 }
1190
1191 WebInspector.ScriptsPanel.prototype.__proto__ = WebInspector.Panel.prototype;
1192
1193 /**
1194  * @constructor
1195  * @implements {WebInspector.SourceFrameDelegate}
1196  * @param {WebInspector.ScriptsPanel} scriptsPanel
1197  * @param {WebInspector.UISourceCode} uiSourceCode
1198  */
1199 WebInspector.SourceFrameDelegateForScriptsPanel = function(scriptsPanel, uiSourceCode)
1200 {
1201     WebInspector.SourceFrameDelegate.call(this);
1202
1203     this._scriptsPanel = scriptsPanel;
1204     this._model = this._scriptsPanel._presentationModel;
1205     this._uiSourceCode = uiSourceCode;
1206     this._popoverObjectGroup = "popover";
1207 }
1208
1209 WebInspector.SourceFrameDelegateForScriptsPanel.prototype = {
1210     requestContent: function(callback)
1211     {
1212         this._uiSourceCode.requestContent(callback);
1213     },
1214
1215     debuggingSupported: function()
1216     {
1217         return true;
1218     },
1219
1220     setBreakpoint: function(lineNumber, condition, enabled)
1221     {
1222         this._model.setBreakpoint(this._uiSourceCode, lineNumber, condition, enabled);
1223
1224         if (!this._scriptsPanel.breakpointsActivated)
1225             this._scriptsPanel._toggleBreakpointsClicked();
1226     },
1227
1228     updateBreakpoint: function(lineNumber, condition, enabled)
1229     {
1230         this._model.updateBreakpoint(this._uiSourceCode, lineNumber, condition, enabled);
1231     },
1232
1233     removeBreakpoint: function(lineNumber)
1234     {
1235         this._model.removeBreakpoint(this._uiSourceCode, lineNumber);
1236     },
1237
1238     findBreakpoint: function(lineNumber)
1239     {
1240         return this._model.findBreakpoint(this._uiSourceCode, lineNumber);
1241     },
1242
1243     continueToLine: function(lineNumber)
1244     {
1245         this._model.continueToLine(this._uiSourceCode, lineNumber);
1246     },
1247
1248     canEditScriptSource: function()
1249     {
1250         return this._model.canEditScriptSource(this._uiSourceCode);
1251     },
1252
1253     setScriptSource: function(text, callback)
1254     {
1255         this._model.setScriptSource(this._uiSourceCode, text, callback);
1256     },
1257
1258     setScriptSourceIsBeingEdited: function(inEditMode)
1259     {
1260         this._scriptsPanel._setScriptSourceIsBeingEdited(this._uiSourceCode, inEditMode);
1261     },
1262
1263     debuggerPaused: function()
1264     {
1265         return WebInspector.panels.scripts.paused;
1266     },
1267
1268     evaluateInSelectedCallFrame: function(string, callback)
1269     {
1270         this._scriptsPanel.evaluateInSelectedCallFrame(string, this._popoverObjectGroup, false, false, callback);
1271     },
1272
1273     releaseEvaluationResult: function()
1274     {
1275         RuntimeAgent.releaseObjectGroup(this._popoverObjectGroup);
1276     },
1277
1278     suggestedFileName: function()
1279     {
1280         var names = this._scriptsPanel._folderAndDisplayNameForScriptURL(this._uiSourceCode.url);
1281         return names.displayName || "untitled.js";
1282     }
1283 }
1284
1285 WebInspector.SourceFrameDelegateForScriptsPanel.prototype.__proto__ = WebInspector.SourceFrameDelegate.prototype;