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