Web Inspector: introduce InspectorFrontendAPI for actions initiated from the applicat...
[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     this.registerRequiredCSS("scriptsPanel.css");
35
36     WebInspector.settings.pauseOnExceptionStateString = WebInspector.settings.createSetting("pauseOnExceptionStateString", WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions);
37
38     this._presentationModel = presentationModel;
39
40     function viewGetter()
41     {
42         return this.visibleView;
43     }
44     WebInspector.GoToLineDialog.install(this, viewGetter.bind(this));
45
46     this.topStatusBar = document.createElement("div");
47     this.topStatusBar.className = "status-bar";
48     this.topStatusBar.id = "scripts-status-bar";
49     this.element.appendChild(this.topStatusBar);
50
51     this.backButton = document.createElement("button");
52     this.backButton.className = "status-bar-item";
53     this.backButton.id = "scripts-back";
54     this.backButton.title = WebInspector.UIString("Show the previous script resource.");
55     this.backButton.disabled = true;
56     this.backButton.appendChild(document.createElement("img"));
57     this.backButton.addEventListener("click", this._goBack.bind(this), false);
58     this.topStatusBar.appendChild(this.backButton);
59
60     this.forwardButton = document.createElement("button");
61     this.forwardButton.className = "status-bar-item";
62     this.forwardButton.id = "scripts-forward";
63     this.forwardButton.title = WebInspector.UIString("Show the next script resource.");
64     this.forwardButton.disabled = true;
65     this.forwardButton.appendChild(document.createElement("img"));
66     this.forwardButton.addEventListener("click", this._goForward.bind(this), false);
67     this.topStatusBar.appendChild(this.forwardButton);
68
69     this._filesSelectElement = document.createElement("select");
70     this._filesSelectElement.className = "status-bar-item";
71     this._filesSelectElement.id = "scripts-files";
72     this._filesSelectElement.addEventListener("change", this._filesSelectChanged.bind(this), false);
73     this._filesSelectElement.addEventListener("keyup", this._filesSelectChanged.bind(this), false);
74     this.topStatusBar.appendChild(this._filesSelectElement);
75
76     this.functionsSelectElement = document.createElement("select");
77     this.functionsSelectElement.className = "status-bar-item";
78     this.functionsSelectElement.id = "scripts-functions";
79
80     // FIXME: append the functions select element to the top status bar when it is implemented.
81     // this.topStatusBar.appendChild(this.functionsSelectElement);
82
83     this._createSidebarButtons();
84
85     this.toggleBreakpointsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Deactivate all breakpoints."), "toggle-breakpoints");
86     this.toggleBreakpointsButton.toggled = true;
87     this.toggleBreakpointsButton.addEventListener("click", this._toggleBreakpointsClicked, this);
88     this.sidebarButtonsElement.appendChild(this.toggleBreakpointsButton.element);
89
90     this.debuggerStatusElement = document.createElement("div");
91     this.debuggerStatusElement.id = "scripts-debugger-status";
92     this.sidebarButtonsElement.appendChild(this.debuggerStatusElement);
93
94     this.viewsContainerElement = document.createElement("div");
95     this.viewsContainerElement.id = "script-resource-views";
96
97     this.sidebarElement = document.createElement("div");
98     this.sidebarElement.id = "scripts-sidebar";
99
100     this.sidebarResizeElement = document.createElement("div");
101     this.sidebarResizeElement.className = "sidebar-resizer-vertical";
102     this.sidebarResizeElement.addEventListener("mousedown", this._startSidebarResizeDrag.bind(this), false);
103
104     this.sidebarResizeWidgetElement = document.createElement("div");
105     this.sidebarResizeWidgetElement.id = "scripts-sidebar-resizer-widget";
106     this.sidebarResizeWidgetElement.addEventListener("mousedown", this._startSidebarResizeDrag.bind(this), false);
107     this.topStatusBar.appendChild(this.sidebarResizeWidgetElement);
108
109     this.sidebarPanes = {};
110     this.sidebarPanes.watchExpressions = new WebInspector.WatchExpressionsSidebarPane();
111     this.sidebarPanes.callstack = new WebInspector.CallStackSidebarPane(this._presentationModel);
112     this.sidebarPanes.scopechain = new WebInspector.ScopeChainSidebarPane();
113     this.sidebarPanes.jsBreakpoints = new WebInspector.JavaScriptBreakpointsSidebarPane(this._presentationModel, this._showSourceLine.bind(this));
114     if (Preferences.nativeInstrumentationEnabled) {
115         this.sidebarPanes.domBreakpoints = WebInspector.domBreakpointsSidebarPane;
116         this.sidebarPanes.xhrBreakpoints = new WebInspector.XHRBreakpointsSidebarPane();
117         this.sidebarPanes.eventListenerBreakpoints = new WebInspector.EventListenerBreakpointsSidebarPane();
118     }
119
120     if (Preferences.canInspectWorkers && !WebInspector.WorkerManager.isWorkerFrontend()) {
121         WorkerAgent.setWorkerInspectionEnabled(true);
122         this.sidebarPanes.workerList = new WebInspector.WorkerListSidebarPane(WebInspector.workerManager);
123     } else
124         this.sidebarPanes.workers = new WebInspector.WorkersSidebarPane();
125
126     for (var pane in this.sidebarPanes)
127         this.sidebarElement.appendChild(this.sidebarPanes[pane].element);
128
129     this.sidebarPanes.callstack.expanded = true;
130
131     this.sidebarPanes.scopechain.expanded = true;
132     this.sidebarPanes.jsBreakpoints.expanded = true;
133
134     var helpSection = WebInspector.shortcutsScreen.section(WebInspector.UIString("Scripts Panel"));
135     this.sidebarPanes.callstack.registerShortcuts(helpSection, this.registerShortcut.bind(this));
136     var evaluateInConsoleShortcut = WebInspector.KeyboardShortcut.makeDescriptor("e", WebInspector.KeyboardShortcut.Modifiers.Shift | WebInspector.KeyboardShortcut.Modifiers.Ctrl);
137     helpSection.addKey(evaluateInConsoleShortcut.name, WebInspector.UIString("Evaluate selection in console"));
138     this.registerShortcut(evaluateInConsoleShortcut.key, this._evaluateSelectionInConsole.bind(this));
139
140     var panelEnablerHeading = WebInspector.UIString("You need to enable debugging before you can use the Scripts panel.");
141     var panelEnablerDisclaimer = WebInspector.UIString("Enabling debugging will make scripts run slower.");
142     var panelEnablerButton = WebInspector.UIString("Enable Debugging");
143
144     this.panelEnablerView = new WebInspector.PanelEnablerView("scripts", panelEnablerHeading, panelEnablerDisclaimer, panelEnablerButton);
145     this.panelEnablerView.addEventListener("enable clicked", this.enableDebugging, this);
146
147     this.element.appendChild(this.viewsContainerElement);
148     this.element.appendChild(this.sidebarElement);
149     this.element.appendChild(this.sidebarResizeElement);
150
151     this.enableToggleButton = new WebInspector.StatusBarButton("", "enable-toggle-status-bar-item");
152     this.enableToggleButton.addEventListener("click", this._toggleDebugging, this);
153     if (Preferences.debuggerAlwaysEnabled)
154         this.enableToggleButton.element.addStyleClass("hidden");
155
156     this._pauseOnExceptionButton = new WebInspector.StatusBarButton("", "scripts-pause-on-exceptions-status-bar-item", 3);
157     this._pauseOnExceptionButton.addEventListener("click", this._togglePauseOnExceptions, this);
158
159     this._toggleFormatSourceButton = new WebInspector.StatusBarButton(WebInspector.UIString("Pretty print"), "scripts-toggle-pretty-print-status-bar-item");
160     this._toggleFormatSourceButton.toggled = false;
161     this._toggleFormatSourceButton.addEventListener("click", this._toggleFormatSource, this);
162
163     this._scriptViewStatusBarItemsContainer = document.createElement("div");
164     this._scriptViewStatusBarItemsContainer.style.display = "inline-block";
165
166     this._debuggerEnabled = Preferences.debuggerAlwaysEnabled;
167
168     this.reset();
169
170     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerWasEnabled, this._debuggerWasEnabled, this);
171     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerWasDisabled, this._debuggerWasDisabled, this);
172
173     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this)
174     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.UISourceCodeReplaced, this._uiSourceCodeReplaced, this);
175     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.UISourceCodeRemoved, this._uiSourceCodeRemoved, this);
176     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.ConsoleMessageAdded, this._consoleMessageAdded, this);
177     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.ConsoleMessagesCleared, this._consoleMessagesCleared, this);
178     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.BreakpointAdded, this._breakpointAdded, this);
179     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.BreakpointRemoved, this._breakpointRemoved, this);
180     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.DebuggerPaused, this._debuggerPaused, this);
181     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.DebuggerResumed, this._debuggerResumed, this);
182     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.CallFrameSelected, this._callFrameSelected, this);
183     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.ConsoleCommandEvaluatedInSelectedCallFrame, this._consoleCommandEvaluatedInSelectedCallFrame, this);
184     this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.ExecutionLineChanged, this._executionLineChanged, this);
185     
186     var enableDebugger = Preferences.debuggerAlwaysEnabled || WebInspector.settings.debuggerEnabled.get();
187     if (enableDebugger)
188         WebInspector.debuggerModel.enableDebugger();
189
190     WebInspector.settings.showScriptFolders.addChangeListener(this._showScriptFoldersSettingChanged.bind(this));
191
192     WebInspector.advancedSearchController.registerSearchScope(new WebInspector.ScriptsSearchScope());
193 }
194
195 // Keep these in sync with WebCore::ScriptDebugServer
196 WebInspector.ScriptsPanel.PauseOnExceptionsState = {
197     DontPauseOnExceptions : "none",
198     PauseOnAllExceptions : "all",
199     PauseOnUncaughtExceptions: "uncaught"
200 };
201
202 WebInspector.ScriptsPanel.prototype = {
203     get toolbarItemLabel()
204     {
205         return WebInspector.UIString("Scripts");
206     },
207
208     get statusBarItems()
209     {
210         return [this.enableToggleButton.element, this._pauseOnExceptionButton.element, this._toggleFormatSourceButton.element, this._scriptViewStatusBarItemsContainer];
211     },
212
213     get defaultFocusedElement()
214     {
215         return this._filesSelectElement;
216     },
217
218     get paused()
219     {
220         return this._paused;
221     },
222
223     wasShown: function()
224     {
225         WebInspector.Panel.prototype.wasShown.call(this);
226         this.sidebarResizeElement.style.right = (this.sidebarElement.offsetWidth - 3) + "px";
227         if (Preferences.nativeInstrumentationEnabled)
228             this.sidebarElement.insertBefore(this.sidebarPanes.domBreakpoints.element, this.sidebarPanes.xhrBreakpoints.element);
229         this.sidebarPanes.watchExpressions.show();
230     },
231
232     breakpointsActivated: function()
233     {
234         return this.toggleBreakpointsButton.toggled;
235     },
236
237     activateBreakpoints: function()
238     {
239         if (!this.breakpointsActivated)
240             this._toggleBreakpointsClicked();
241     },
242
243     _uiSourceCodeAdded: function(event)
244     {
245         var uiSourceCode = event.data;
246
247         if (!uiSourceCode.url) {
248             // Anonymous sources are shown only when stepping.
249             return;
250         }
251
252         this._addOptionToFilesSelect(uiSourceCode);
253
254         var lastViewedURL = WebInspector.settings.lastViewedScriptFile.get();
255         if (!this._filesSelectElement.initialSelectionProcessed) {
256             this._filesSelectElement.initialSelectionProcessed = true;
257             // Option we just added is the only option in files select.
258             // We have to show corresponding source frame immediately.
259             this._showSourceFrameAndAddToHistory(uiSourceCode);
260             // Restore original value of lastViewedScriptFile because
261             // source frame was shown as a result of initial load.
262             WebInspector.settings.lastViewedScriptFile.set(lastViewedURL);
263         } else if (uiSourceCode.url === lastViewedURL)
264             this._showSourceFrameAndAddToHistory(uiSourceCode);
265     },
266
267     _uiSourceCodeRemoved: function(event)
268     {
269         var uiSourceCode = event.data;
270         if (uiSourceCode._sourceFrame)
271             uiSourceCode._sourceFrame.detach();
272     },
273
274     _showScriptFoldersSettingChanged: function()
275     {
276         var selectedOption = this._filesSelectElement[this._filesSelectElement.selectedIndex];
277         var uiSourceCode = selectedOption ? selectedOption._uiSourceCode : null;
278
279         var options = Array.prototype.slice.call(this._filesSelectElement);
280         this._resetFilesSelect();
281         for (var i = 0; i < options.length; ++i) {
282             if (options[i]._uiSourceCode)
283                 this._addOptionToFilesSelect(options[i]._uiSourceCode);
284         }
285
286         if (uiSourceCode) {
287             var index = uiSourceCode._option.index;
288             if (typeof index === "number")
289                 this._filesSelectElement.selectedIndex = index;
290         }
291     },
292
293     _addOptionToFilesSelect: function(uiSourceCode)
294     {
295         var showScriptFolders = WebInspector.settings.showScriptFolders.get();
296
297         var select = this._filesSelectElement;
298         if (!select.domainOptions)
299             select.domainOptions = {};
300         if (!select.folderOptions)
301             select.folderOptions = {};
302
303         var option = document.createElement("option");
304         option._uiSourceCode = uiSourceCode;
305         var parsedURL = uiSourceCode.url.asParsedURL();
306
307         const indent = WebInspector.isMac() ? "" : "\u00a0\u00a0\u00a0\u00a0";
308
309         var names = this.folderAndDisplayNameForScriptURL(uiSourceCode.url);
310         option.displayName = names.displayName;
311
312         var contentScriptPrefix = uiSourceCode.isContentScript ? "2:" : "0:";
313
314         if (uiSourceCode.isContentScript && names.domain) {
315             // Render extension domain as a path in structured view
316             names.folderName = names.domain + (names.folderName ? names.folderName : "");
317             delete names.domain;
318         }
319
320         var folderNameForSorting = contentScriptPrefix + (names.domain ? names.domain + "\t\t" : "") + names.folderName;
321
322         if (showScriptFolders) {
323             option.text = indent + (names.displayName ? names.displayName : WebInspector.UIString("(program)"));
324             option.nameForSorting = folderNameForSorting + "\t/\t" + names.displayName; // Use '\t' to make files stick to their folder.
325         } else {
326             option.text = names.displayName ? names.displayName : WebInspector.UIString("(program)");
327             // Content script should contain its domain name as a prefix
328             if (uiSourceCode.isContentScript && names.folderName)
329                 option.text = names.folderName + "/" + option.text;
330             option.nameForSorting = contentScriptPrefix + option.text;
331         }
332         option.title = uiSourceCode.url;
333
334         if (uiSourceCode.isContentScript)
335             option.addStyleClass("extension-script");
336
337         function insertOrdered(option)
338         {
339             function optionCompare(a, b)
340             {
341                 return a.nameForSorting.localeCompare(b.nameForSorting);
342             }
343             var insertionIndex = insertionIndexForObjectInListSortedByFunction(option, select.childNodes, optionCompare);
344             select.insertBefore(option, insertionIndex < 0 ? null : select.childNodes.item(insertionIndex));
345         }
346
347         insertOrdered(option);
348
349         if (uiSourceCode.isContentScript && !select.contentScriptSection) {
350             var contentScriptSection = document.createElement("option");
351             contentScriptSection.text = "\u2014 " + WebInspector.UIString("Content scripts") + " \u2014";
352             contentScriptSection.disabled = true;
353             contentScriptSection.nameForSorting = "1/ContentScriptSeparator";
354             select.contentScriptSection = contentScriptSection;
355             insertOrdered(contentScriptSection);
356         }
357
358         if (showScriptFolders && !uiSourceCode.isContentScript && names.domain && !select.domainOptions[names.domain]) {
359             var domainOption = document.createElement("option");
360             domainOption.text = "\u2014 " + names.domain + " \u2014";
361             domainOption.nameForSorting = "0:" + names.domain;
362             domainOption.disabled = true;
363             select.domainOptions[names.domain] = domainOption;
364             insertOrdered(domainOption);
365         }
366
367         if (showScriptFolders && names.folderName && !select.folderOptions[folderNameForSorting]) {
368             var folderOption = document.createElement("option");
369             folderOption.text = names.folderName;
370             folderOption.nameForSorting = folderNameForSorting;
371             folderOption.disabled = true;
372             select.folderOptions[folderNameForSorting] = folderOption;
373             insertOrdered(folderOption);
374         }
375
376         option._uiSourceCode = uiSourceCode;
377         uiSourceCode._option = option;
378     },
379
380     folderAndDisplayNameForScriptURL: function(url)
381     {
382         var parsedURL = url.asParsedURL();
383         if (parsedURL)
384             url = parsedURL.path;
385
386         var folderName = "";
387         var displayName = url;
388
389         var pathLength = displayName.indexOf("?");
390         if (pathLength === -1)
391             pathLength = displayName.length;
392
393         var fromIndex = displayName.lastIndexOf("/", pathLength - 2);
394         if (fromIndex !== -1) {
395             folderName = displayName.substring(0, fromIndex);
396             displayName = displayName.substring(fromIndex + 1);
397         }
398
399         if (displayName.length > 80)
400             displayName = "\u2026" + displayName.substring(displayName.length - 80);
401
402         if (folderName.length > 80)
403             folderName = "\u2026" + folderName.substring(folderName.length - 80);
404
405         return { domain: (parsedURL ? parsedURL.host : ""), folderName: folderName, displayName: displayName };
406     },
407
408     setScriptSourceIsBeingEdited: function(uiSourceCode, inEditMode)
409     {
410         var option = uiSourceCode._option;
411         if (!option)
412             return;
413         if (inEditMode)
414             option.text = option.text.replace(/[^*]$/, "$&*");
415         else
416             option.text = option.text.replace(/[*]$/, "");
417     },
418
419     _consoleMessagesCleared: function()
420     {
421         for (var i = 0; i < this._filesSelectElement.length; ++i) {
422             var option = this._filesSelectElement[i];
423             if (option._uiSourceCode && option._uiSourceCode._sourceFrame)
424                 option._uiSourceCode._sourceFrame.clearMessages();
425         }
426     },
427
428     _consoleMessageAdded: function(event)
429     {
430         var message = event.data;
431
432         var sourceFrame = message.uiSourceCode._sourceFrame;
433         if (sourceFrame && sourceFrame.loaded)
434             sourceFrame.addMessageToSource(message.lineNumber, message.originalMessage);
435     },
436
437     _breakpointAdded: function(event)
438     {
439         var breakpoint = event.data;
440
441         var sourceFrame = breakpoint.uiSourceCode._sourceFrame;
442         if (sourceFrame && sourceFrame.loaded)
443             sourceFrame.addBreakpoint(breakpoint.lineNumber, breakpoint.resolved, breakpoint.condition, breakpoint.enabled);
444
445         this.sidebarPanes.jsBreakpoints.addBreakpoint(breakpoint);
446     },
447
448     _breakpointRemoved: function(event)
449     {
450         var breakpoint = event.data;
451
452         var sourceFrame = breakpoint.uiSourceCode._sourceFrame;
453         if (sourceFrame && sourceFrame.loaded)
454             sourceFrame.removeBreakpoint(breakpoint.lineNumber);
455
456         this.sidebarPanes.jsBreakpoints.removeBreakpoint(breakpoint.uiSourceCode, breakpoint.lineNumber);
457     },
458
459     _consoleCommandEvaluatedInSelectedCallFrame: function(event)
460     {
461         this.sidebarPanes.scopechain.update(this._presentationModel.selectedCallFrame);
462     },
463
464     _debuggerPaused: function(event)
465     {
466         var callFrames = event.data.callFrames;
467         var details = event.data.details;
468
469         this._paused = true;
470         this._waitingToPause = false;
471         this._stepping = false;
472
473         this._updateDebuggerButtons();
474
475         WebInspector.inspectorView.setCurrentPanel(this);
476
477         this.sidebarPanes.callstack.update(callFrames);
478         this._updateCallFrame(this._presentationModel.selectedCallFrame);
479
480         if (details.reason === WebInspector.DebuggerModel.BreakReason.DOM) {
481             this.sidebarPanes.domBreakpoints.highlightBreakpoint(details.auxData);
482             function didCreateBreakpointHitStatusMessage(element)
483             {
484                 this.sidebarPanes.callstack.setStatus(element);
485             }
486             this.sidebarPanes.domBreakpoints.createBreakpointHitStatusMessage(details.auxData, didCreateBreakpointHitStatusMessage.bind(this));
487         } else if (details.reason === WebInspector.DebuggerModel.BreakReason.EventListener) {
488             var eventName = details.auxData.eventName;
489             this.sidebarPanes.eventListenerBreakpoints.highlightBreakpoint(details.auxData.eventName);
490             var eventNameForUI = WebInspector.EventListenerBreakpointsSidebarPane.eventNameForUI(eventName);
491             this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a \"%s\" Event Listener.", eventNameForUI));
492         } else if (details.reason === WebInspector.DebuggerModel.BreakReason.XHR) {
493             this.sidebarPanes.xhrBreakpoints.highlightBreakpoint(details.auxData["breakpointURL"]);
494             this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a XMLHttpRequest."));
495         } else if (details.reason === WebInspector.DebuggerModel.BreakReason.Exception) {
496             this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on exception: '%s'.", details.auxData.description));
497         } else {
498             function didGetUILocation(uiLocation)
499             {
500                 if (!this._presentationModel.findBreakpoint(uiLocation.uiSourceCode, uiLocation.lineNumber))
501                     return;
502                 this.sidebarPanes.jsBreakpoints.highlightBreakpoint(uiLocation.uiSourceCode, uiLocation.lineNumber);
503                 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a JavaScript breakpoint."));
504             }
505             callFrames[0].uiLocation(didGetUILocation.bind(this));
506         }
507
508         window.focus();
509         InspectorFrontendHost.bringToFront();
510     },
511
512     _debuggerResumed: function()
513     {
514         this._paused = false;
515         this._waitingToPause = false;
516         this._stepping = false;
517
518         this._clearInterface();
519     },
520
521     _debuggerWasEnabled: function()
522     {
523         this._setPauseOnExceptions(WebInspector.settings.pauseOnExceptionStateString.get());
524
525         if (this._debuggerEnabled)
526             return;
527
528         this._debuggerEnabled = true;
529         this.reset(true);
530     },
531
532     _debuggerWasDisabled: function()
533     {
534         if (!this._debuggerEnabled)
535             return;
536
537         this._debuggerEnabled = false;
538         this.reset(true);
539     },
540
541     reset: function(preserveItems)
542     {
543         this.visibleView = null;
544
545         delete this.currentQuery;
546         this.searchCanceled();
547
548         this._debuggerResumed();
549
550         this._backForwardList = [];
551         this._currentBackForwardIndex = -1;
552         this._updateBackAndForwardButtons();
553
554         this._resetFilesSelect();
555         delete this._filesSelectElement.initialSelectionProcessed;
556
557         this.functionsSelectElement.removeChildren();
558         this.viewsContainerElement.removeChildren();
559
560         this.sidebarPanes.jsBreakpoints.reset();
561         this.sidebarPanes.watchExpressions.reset();
562         if (!preserveItems && this.sidebarPanes.workers)
563             this.sidebarPanes.workers.reset();
564     },
565
566     _resetFilesSelect: function()
567     {
568         this._filesSelectElement.removeChildren();
569         this._filesSelectElement.domainOptions = {};
570         this._filesSelectElement.folderOptions = {};
571         delete this._filesSelectElement.contentScriptSection;
572     },
573
574     get visibleView()
575     {
576         return this._visibleView;
577     },
578
579     set visibleView(x)
580     {
581         if (this._visibleView === x)
582             return;
583
584         if (this._visibleView)
585             this._visibleView.detach();
586
587         this._visibleView = x;
588
589         if (x) {
590             x.show(this.viewsContainerElement);
591             this._scriptViewStatusBarItemsContainer.removeChildren();
592             var statusBarItems = x.statusBarItems || [];
593             for (var i = 0; i < statusBarItems.length; ++i)
594                 this._scriptViewStatusBarItemsContainer.appendChild(statusBarItems[i]);
595         }
596     },
597
598     canShowAnchorLocation: function(anchor)
599     {
600         return this._debuggerEnabled && anchor.uiSourceCode;
601     },
602
603     showAnchorLocation: function(anchor)
604     {
605         this._showSourceLine(anchor.uiSourceCode, anchor.lineNumber);
606     },
607
608     showFunctionDefinition: function(functionLocation)
609     {
610         WebInspector.showPanelForAnchorNavigation(this);
611         var uiLocation = this._presentationModel.rawLocationToUILocation(functionLocation);
612         this._showSourceLine(uiLocation.uiSourceCode, uiLocation.lineNumber);
613     },
614
615     _showSourceLine: function(uiSourceCode, lineNumber)
616     {
617         var sourceFrame = this._showSourceFrameAndAddToHistory(uiSourceCode);
618         if (typeof lineNumber === "number")
619             sourceFrame.highlightLine(lineNumber);
620     },
621
622     _showSourceFrameAndAddToHistory: function(uiSourceCode)
623     {
624         if (!uiSourceCode._option)
625             return;
626
627         var sourceFrame = this._showSourceFrame(uiSourceCode);
628
629         var oldIndex = this._currentBackForwardIndex;
630         if (oldIndex >= 0)
631             this._backForwardList.splice(oldIndex + 1, this._backForwardList.length - oldIndex);
632
633         // Check for a previous entry of the same object in _backForwardList.
634         // If one is found, remove it.
635         var previousEntryIndex = this._backForwardList.indexOf(uiSourceCode);
636         if (previousEntryIndex !== -1)
637             this._backForwardList.splice(previousEntryIndex, 1);
638
639         this._backForwardList.push(uiSourceCode);
640         this._currentBackForwardIndex = this._backForwardList.length - 1;
641
642         this._updateBackAndForwardButtons();
643
644         return sourceFrame;
645     },
646
647     _showSourceFrame: function(uiSourceCode)
648     {
649         this._filesSelectElement.selectedIndex = uiSourceCode._option.index;
650
651         var sourceFrame = uiSourceCode._sourceFrame || this._createSourceFrame(uiSourceCode);
652         this.visibleView = sourceFrame;
653
654         if (uiSourceCode.url)
655             WebInspector.settings.lastViewedScriptFile.set(uiSourceCode.url);
656
657         return sourceFrame;
658     },
659
660     _createSourceFrame: function(uiSourceCode)
661     {
662         var sourceFrame = new WebInspector.JavaScriptSourceFrame(this, this._presentationModel, uiSourceCode);
663
664         sourceFrame._uiSourceCode = uiSourceCode;
665         sourceFrame.addEventListener(WebInspector.SourceFrame.Events.Loaded, this._sourceFrameLoaded, this);
666         uiSourceCode._sourceFrame = sourceFrame;
667         return sourceFrame;
668     },
669
670     _removeSourceFrame: function(uiSourceCode)
671     {
672         var option = uiSourceCode._option;
673         // FIXME: find out why we are getting here with option detached.
674         if (option && this._filesSelectElement === option.parentElement)
675             this._filesSelectElement.removeChild(option);
676
677         var sourceFrame = uiSourceCode._sourceFrame;
678         if (!sourceFrame)
679             return;
680         delete uiSourceCode._sourceFrame;
681         sourceFrame.detach();
682         sourceFrame.removeEventListener(WebInspector.SourceFrame.Events.Loaded, this._sourceFrameLoaded, this);
683     },
684
685     _uiSourceCodeReplaced: function(event)
686     {
687         var oldUISourceCodeList = event.data.oldUISourceCodeList;
688         var uiSourceCodeList = event.data.uiSourceCodeList;
689
690         var visible = false;
691         for (var i = 0; i < oldUISourceCodeList.length; ++i) {
692             var uiSourceCode = oldUISourceCodeList[i];
693             if (uiSourceCode._sourceFrame === this.visibleView)
694                 visible = true;
695             this._removeSourceFrame(uiSourceCode);
696         }
697
698         for (var i = 0; i < uiSourceCodeList.length; ++i)
699             this._uiSourceCodeAdded({ data: uiSourceCodeList[i] });
700
701         if (visible)
702             this._showSourceFrame(uiSourceCodeList[0]);
703     },
704
705     _sourceFrameLoaded: function(event)
706     {
707         var sourceFrame = event.target;
708         var uiSourceCode = sourceFrame._uiSourceCode;
709
710         var messages = this._presentationModel.messagesForUISourceCode(uiSourceCode);
711         for (var i = 0; i < messages.length; ++i) {
712             var message = messages[i];
713             sourceFrame.addMessageToSource(message.lineNumber, message.originalMessage);
714         }
715
716         var breakpoints = this._presentationModel.breakpointsForUISourceCode(uiSourceCode);
717         for (var i = 0; i < breakpoints.length; ++i) {
718             var breakpoint = breakpoints[i];
719             sourceFrame.addBreakpoint(breakpoint.lineNumber, breakpoint.resolved, breakpoint.condition, breakpoint.enabled);
720         }
721     },
722
723     _clearCurrentExecutionLine: function()
724     {
725         if (this._executionSourceFrame)
726             this._executionSourceFrame.clearExecutionLine();
727         delete this._executionSourceFrame;
728     },
729
730     _executionLineChanged: function(event)
731     {
732         var uiLocation = event.data;
733
734         this._updateExecutionLine(uiLocation);
735     },
736
737     _updateExecutionLine: function(uiLocation)
738     {
739         this._clearCurrentExecutionLine();
740         if (!uiLocation)
741             return;
742
743         if (!uiLocation.uiSourceCode._option) {
744             // Anonymous scripts are not added to files select by default.
745             this._addOptionToFilesSelect(uiLocation.uiSourceCode);
746         }
747         var sourceFrame = this._showSourceFrameAndAddToHistory(uiLocation.uiSourceCode);
748         sourceFrame.setExecutionLine(uiLocation.lineNumber);
749         this._executionSourceFrame = sourceFrame;
750     },
751
752     _callFrameSelected: function(event)
753     {
754         var callFrame = event.data;
755
756         if (!callFrame)
757             return;
758
759         this._updateCallFrame(callFrame);
760     },
761
762     _updateCallFrame: function(callFrame)
763     {
764         this.sidebarPanes.scopechain.update(callFrame);
765         this.sidebarPanes.watchExpressions.refreshExpressions();
766         this.sidebarPanes.callstack.selectedCallFrame = callFrame;
767         this._updateExecutionLine(this._presentationModel.executionLineLocation);
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.detach();
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.show(this.element);
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     get debuggingEnabled()
919     {
920         return this._debuggerEnabled;
921     },
922
923     enableDebugging: function()
924     {
925         if (this._debuggerEnabled)
926             return;
927         this.toggleDebugging(this.panelEnablerView.alwaysEnabled);
928     },
929
930     disableDebugging: function()
931     {
932         if (!this._debuggerEnabled)
933             return;
934         this.toggleDebugging(this.panelEnablerView.alwaysEnabled);
935     },
936
937     toggleDebugging: function(optionalAlways)
938     {
939         this._paused = false;
940         this._waitingToPause = false;
941         this._stepping = false;
942
943         if (this._debuggerEnabled) {
944             WebInspector.settings.debuggerEnabled.set(false);
945             WebInspector.debuggerModel.disableDebugger();
946         } else {
947             WebInspector.settings.debuggerEnabled.set(!!optionalAlways);
948             WebInspector.debuggerModel.enableDebugger();
949         }
950     },
951
952     _togglePauseOnExceptions: function()
953     {
954         var nextStateMap = {};
955         var stateEnum = WebInspector.ScriptsPanel.PauseOnExceptionsState;
956         nextStateMap[stateEnum.DontPauseOnExceptions] = stateEnum.PauseOnAllExceptions;
957         nextStateMap[stateEnum.PauseOnAllExceptions] = stateEnum.PauseOnUncaughtExceptions;
958         nextStateMap[stateEnum.PauseOnUncaughtExceptions] = stateEnum.DontPauseOnExceptions;
959         this._setPauseOnExceptions(nextStateMap[this._pauseOnExceptionButton.state]);
960     },
961
962     _togglePause: function()
963     {
964         if (this._paused) {
965             this._paused = false;
966             this._waitingToPause = false;
967             DebuggerAgent.resume();
968         } else {
969             this._stepping = false;
970             this._waitingToPause = true;
971             DebuggerAgent.pause();
972         }
973
974         this._clearInterface();
975     },
976
977     _stepOverClicked: function()
978     {
979         if (!this._paused)
980             return;
981
982         this._paused = false;
983         this._stepping = true;
984
985         this._clearInterface();
986
987         DebuggerAgent.stepOver();
988     },
989
990     _stepIntoClicked: function()
991     {
992         if (!this._paused)
993             return;
994
995         this._paused = false;
996         this._stepping = true;
997
998         this._clearInterface();
999
1000         DebuggerAgent.stepInto();
1001     },
1002
1003     _stepOutClicked: function()
1004     {
1005         if (!this._paused)
1006             return;
1007
1008         this._paused = false;
1009         this._stepping = true;
1010
1011         this._clearInterface();
1012
1013         DebuggerAgent.stepOut();
1014     },
1015
1016     _toggleBreakpointsClicked: function()
1017     {
1018         this.toggleBreakpointsButton.toggled = !this.toggleBreakpointsButton.toggled;
1019         if (this.toggleBreakpointsButton.toggled) {
1020             DebuggerAgent.setBreakpointsActive(true);
1021             this.toggleBreakpointsButton.title = WebInspector.UIString("Deactivate all breakpoints.");
1022             WebInspector.inspectorView.element.removeStyleClass("breakpoints-deactivated");
1023         } else {
1024             DebuggerAgent.setBreakpointsActive(false);
1025             this.toggleBreakpointsButton.title = WebInspector.UIString("Activate all breakpoints.");
1026             WebInspector.inspectorView.element.addStyleClass("breakpoints-deactivated");
1027         }
1028     },
1029
1030     _evaluateSelectionInConsole: function()
1031     {
1032         var selection = window.getSelection();
1033         if (selection.type === "Range" && !selection.isCollapsed)
1034             WebInspector.evaluateInConsole(selection.toString());
1035     },
1036
1037     elementsToRestoreScrollPositionsFor: function()
1038     {
1039         return [ this.sidebarElement ];
1040     },
1041
1042     _createSidebarButtons: function()
1043     {
1044         this.sidebarButtonsElement = document.createElement("div");
1045         this.sidebarButtonsElement.id = "scripts-sidebar-buttons";
1046         this.topStatusBar.appendChild(this.sidebarButtonsElement);
1047
1048         var title, handler, shortcuts;
1049         var platformSpecificModifier = WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta;
1050
1051         // Continue.
1052         title = WebInspector.UIString("Pause script execution (%s).");
1053         handler = this._togglePause.bind(this);
1054         shortcuts = [];
1055         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F8));
1056         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Slash, platformSpecificModifier));
1057         this.pauseButton = this._createSidebarButtonAndRegisterShortcuts("scripts-pause", title, handler, shortcuts, WebInspector.UIString("Pause/Continue"));
1058
1059         // Step over.
1060         title = WebInspector.UIString("Step over next function call (%s).");
1061         handler = this._stepOverClicked.bind(this);
1062         shortcuts = [];
1063         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F10));
1064         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.SingleQuote, platformSpecificModifier));
1065         this.stepOverButton = this._createSidebarButtonAndRegisterShortcuts("scripts-step-over", title, handler, shortcuts, WebInspector.UIString("Step over"));
1066
1067         // Step into.
1068         title = WebInspector.UIString("Step into next function call (%s).");
1069         handler = this._stepIntoClicked.bind(this);
1070         shortcuts = [];
1071         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F11));
1072         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Semicolon, platformSpecificModifier));
1073         this.stepIntoButton = this._createSidebarButtonAndRegisterShortcuts("scripts-step-into", title, handler, shortcuts, WebInspector.UIString("Step into"));
1074
1075         // Step out.
1076         title = WebInspector.UIString("Step out of current function (%s).");
1077         handler = this._stepOutClicked.bind(this);
1078         shortcuts = [];
1079         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F11, WebInspector.KeyboardShortcut.Modifiers.Shift));
1080         shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Semicolon, WebInspector.KeyboardShortcut.Modifiers.Shift | platformSpecificModifier));
1081         this.stepOutButton = this._createSidebarButtonAndRegisterShortcuts("scripts-step-out", title, handler, shortcuts, WebInspector.UIString("Step out"));
1082     },
1083
1084     _createSidebarButtonAndRegisterShortcuts: function(buttonId, buttonTitle, handler, shortcuts, shortcutDescription)
1085     {
1086         var button = document.createElement("button");
1087         button.className = "status-bar-item";
1088         button.id = buttonId;
1089         button.title = String.vsprintf(buttonTitle, [shortcuts[0].name]);
1090         button.disabled = true;
1091         button.appendChild(document.createElement("img"));
1092         button.addEventListener("click", handler, false);
1093         this.sidebarButtonsElement.appendChild(button);
1094
1095         var shortcutNames = [];
1096         for (var i = 0; i < shortcuts.length; ++i) {
1097             this.registerShortcut(shortcuts[i].key, handler);
1098             shortcutNames.push(shortcuts[i].name);
1099         }
1100         var section = WebInspector.shortcutsScreen.section(WebInspector.UIString("Scripts Panel"));
1101         section.addAlternateKeys(shortcutNames, shortcutDescription);
1102
1103         return button;
1104     },
1105
1106     searchCanceled: function()
1107     {
1108         if (this._searchView)
1109             this._searchView.searchCanceled();
1110
1111         delete this._searchView;
1112         delete this._searchQuery;
1113     },
1114
1115     performSearch: function(query)
1116     {
1117         WebInspector.searchController.updateSearchMatchesCount(0, this);
1118
1119         if (!this.visibleView)
1120             return;
1121
1122         // Call searchCanceled since it will reset everything we need before doing a new search.
1123         this.searchCanceled();
1124
1125         this._searchView = this.visibleView;
1126         this._searchQuery = query;
1127
1128         function finishedCallback(view, searchMatches)
1129         {
1130             if (!searchMatches)
1131                 return;
1132
1133             WebInspector.searchController.updateSearchMatchesCount(searchMatches, this);
1134             view.jumpToFirstSearchResult();
1135             WebInspector.searchController.updateCurrentMatchIndex(view.currentSearchResultIndex, this);
1136         }
1137
1138         this._searchView.performSearch(query, finishedCallback.bind(this));
1139     },
1140
1141     jumpToNextSearchResult: function()
1142     {
1143         if (!this._searchView)
1144             return;
1145
1146         if (this._searchView !== this.visibleView) {
1147             this.performSearch(this._searchQuery);
1148             return;
1149         }
1150
1151         if (this._searchView.showingLastSearchResult())
1152             this._searchView.jumpToFirstSearchResult();
1153         else
1154             this._searchView.jumpToNextSearchResult();
1155         WebInspector.searchController.updateCurrentMatchIndex(this._searchView.currentSearchResultIndex, this);
1156     },
1157
1158     jumpToPreviousSearchResult: function()
1159     {
1160         if (!this._searchView)
1161             return;
1162
1163         if (this._searchView !== this.visibleView) {
1164             this.performSearch(this._searchQuery);
1165             if (this._searchView)
1166                 this._searchView.jumpToLastSearchResult();
1167             return;
1168         }
1169
1170         if (this._searchView.showingFirstSearchResult())
1171             this._searchView.jumpToLastSearchResult();
1172         else
1173             this._searchView.jumpToPreviousSearchResult();
1174         WebInspector.searchController.updateCurrentMatchIndex(this._searchView.currentSearchResultIndex, this);
1175     },
1176
1177     _toggleFormatSource: function()
1178     {
1179         this._toggleFormatSourceButton.toggled = !this._toggleFormatSourceButton.toggled;
1180         this._presentationModel.setFormatSource(this._toggleFormatSourceButton.toggled);
1181     },
1182
1183     addToWatch: function(expression)
1184     {
1185         this.sidebarPanes.watchExpressions.addExpression(expression);
1186     }
1187 }
1188
1189 WebInspector.ScriptsPanel.prototype.__proto__ = WebInspector.Panel.prototype;