• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
27importScript("Placard.js");
28importScript("BreakpointsSidebarPane.js");
29importScript("CallStackSidebarPane.js");
30importScript("SimpleHistoryManager.js");
31importScript("EditingLocationHistoryManager.js");
32importScript("FilePathScoreFunction.js");
33importScript("FilteredItemSelectionDialog.js");
34importScript("UISourceCodeFrame.js");
35importScript("JavaScriptSourceFrame.js");
36importScript("CSSSourceFrame.js");
37importScript("NavigatorView.js");
38importScript("RevisionHistoryView.js");
39importScript("ScopeChainSidebarPane.js");
40importScript("SourcesNavigator.js");
41importScript("StyleSheetOutlineDialog.js");
42importScript("TabbedEditorContainer.js");
43importScript("WatchExpressionsSidebarPane.js");
44importScript("WorkersSidebarPane.js");
45importScript("TargetsToolbar.js");
46importScript("ScriptFormatterEditorAction.js");
47importScript("InplaceFormatterEditorAction.js");
48importScript("ScriptFormatter.js");
49importScript("SourcesView.js");
50
51/**
52 * @constructor
53 * @implements {WebInspector.ContextMenu.Provider}
54 * @implements {WebInspector.TargetManager.Observer}
55 * @extends {WebInspector.Panel}
56 * @param {!WebInspector.Workspace=} workspaceForTest
57 */
58WebInspector.SourcesPanel = function(workspaceForTest)
59{
60    WebInspector.Panel.call(this, "sources");
61    this.registerRequiredCSS("sourcesPanel.css");
62    this.registerRequiredCSS("suggestBox.css");
63    new WebInspector.UpgradeFileSystemDropTarget(this.element);
64
65    WebInspector.settings.showEditorInDrawer = WebInspector.settings.createSetting("showEditorInDrawer", true);
66
67    this._workspace = workspaceForTest || WebInspector.workspace;
68
69    var helpSection = WebInspector.shortcutsScreen.section(WebInspector.UIString("Sources Panel"));
70    this.debugToolbar = this._createDebugToolbar();
71    this._debugToolbarDrawer = this._createDebugToolbarDrawer();
72    this._targetsToolbar = new WebInspector.TargetsToolbar();
73
74    const initialDebugSidebarWidth = 225;
75    this._splitView = new WebInspector.SplitView(true, true, "sourcesPanelSplitViewState", initialDebugSidebarWidth);
76    this._splitView.enableShowModeSaving();
77    this._splitView.show(this.element);
78
79    // Create scripts navigator
80    const initialNavigatorWidth = 225;
81    this.editorView = new WebInspector.SplitView(true, false, "sourcesPanelNavigatorSplitViewState", initialNavigatorWidth);
82    this.editorView.enableShowModeSaving();
83    this.editorView.element.id = "scripts-editor-split-view";
84    this.editorView.element.tabIndex = 0;
85    this.editorView.show(this._splitView.mainElement());
86
87    this._navigator = new WebInspector.SourcesNavigator(this._workspace);
88    this._navigator.view.setMinimumSize(100, 25);
89    this._navigator.view.show(this.editorView.sidebarElement());
90    this._navigator.addEventListener(WebInspector.SourcesNavigator.Events.SourceSelected, this._sourceSelected, this);
91    this._navigator.addEventListener(WebInspector.SourcesNavigator.Events.SourceRenamed, this._sourceRenamed, this);
92
93    this._sourcesView = new WebInspector.SourcesView(this._workspace, this);
94    this._sourcesView.addEventListener(WebInspector.SourcesView.Events.EditorSelected, this._editorSelected.bind(this));
95    this._sourcesView.addEventListener(WebInspector.SourcesView.Events.EditorClosed, this._editorClosed.bind(this));
96    this._sourcesView.registerShortcuts(this.registerShortcuts.bind(this));
97
98    if (WebInspector.experimentsSettings.editorInDrawer.isEnabled()) {
99        this._drawerEditorView = new WebInspector.SourcesPanel.DrawerEditorView();
100        this._sourcesView.show(this._drawerEditorView.element);
101    } else {
102        this._sourcesView.show(this.editorView.mainElement());
103    }
104
105    this._debugSidebarResizeWidgetElement = document.createElementWithClass("div", "resizer-widget");
106    this._debugSidebarResizeWidgetElement.id = "scripts-debug-sidebar-resizer-widget";
107    this._splitView.addEventListener(WebInspector.SplitView.Events.ShowModeChanged, this._updateDebugSidebarResizeWidget, this);
108    this._updateDebugSidebarResizeWidget();
109    this._splitView.installResizer(this._debugSidebarResizeWidgetElement);
110
111    this.sidebarPanes = {};
112    this.sidebarPanes.watchExpressions = new WebInspector.WatchExpressionsSidebarPane();
113    this.sidebarPanes.callstack = new WebInspector.CallStackSidebarPane();
114    this.sidebarPanes.callstack.addEventListener(WebInspector.CallStackSidebarPane.Events.CallFrameSelected, this._callFrameSelectedInSidebar.bind(this));
115    this.sidebarPanes.callstack.addEventListener(WebInspector.CallStackSidebarPane.Events.CallFrameRestarted, this._callFrameRestartedInSidebar.bind(this));
116    this.sidebarPanes.callstack.registerShortcuts(this.registerShortcuts.bind(this));
117
118    this.sidebarPanes.scopechain = new WebInspector.ScopeChainSidebarPane();
119    this.sidebarPanes.jsBreakpoints = new WebInspector.JavaScriptBreakpointsSidebarPane(WebInspector.debuggerModel, WebInspector.breakpointManager, this.showUISourceCode.bind(this));
120    this.sidebarPanes.domBreakpoints = WebInspector.domBreakpointsSidebarPane.createProxy(this);
121    this.sidebarPanes.xhrBreakpoints = new WebInspector.XHRBreakpointsSidebarPane();
122    this.sidebarPanes.eventListenerBreakpoints = new WebInspector.EventListenerBreakpointsSidebarPane();
123
124    if (Capabilities.isMainFrontend)
125        this.sidebarPanes.workerList = new WebInspector.WorkersSidebarPane();
126
127    this._extensionSidebarPanes = [];
128    this._installDebuggerSidebarController();
129
130    WebInspector.dockController.addEventListener(WebInspector.DockController.Events.DockSideChanged, this._dockSideChanged.bind(this));
131    WebInspector.settings.splitVerticallyWhenDockedToRight.addChangeListener(this._dockSideChanged.bind(this));
132    this._dockSideChanged();
133
134    this._updateDebuggerButtons();
135    this._pauseOnExceptionEnabledChanged();
136    WebInspector.settings.pauseOnExceptionEnabled.addChangeListener(this._pauseOnExceptionEnabledChanged, this);
137    WebInspector.targetManager.observeTargets(this);
138    this._setTarget(WebInspector.context.flavor(WebInspector.Target));
139    WebInspector.context.addFlavorChangeListener(WebInspector.Target, this._onCurrentTargetChanged, this);
140}
141
142WebInspector.SourcesPanel.minToolbarWidth = 215;
143
144WebInspector.SourcesPanel.prototype = {
145    /**
146     * @param {!WebInspector.Target} target
147     */
148    targetAdded: function(target)
149    {
150        target.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerWasEnabled, this._debuggerWasEnabled, this);
151        target.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerWasDisabled, this._debuggerReset, this);
152        target.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
153        target.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerResumed, this._debuggerResumed, this);
154        target.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.CallFrameSelected, this._callFrameSelected, this);
155        target.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.ConsoleCommandEvaluatedInSelectedCallFrame, this._consoleCommandEvaluatedInSelectedCallFrame, this);
156        target.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointsActiveStateChanged, this._breakpointsActiveStateChanged, this);
157        target.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, this._debuggerReset, this);
158    },
159
160    /**
161     * @param {!WebInspector.Target} target
162     */
163    targetRemoved: function(target)
164    {
165        target.debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.DebuggerWasEnabled, this._debuggerWasEnabled, this);
166        target.debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.DebuggerWasDisabled, this._debuggerReset, this);
167        target.debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
168        target.debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.DebuggerResumed, this._debuggerResumed, this);
169        target.debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.CallFrameSelected, this._callFrameSelected, this);
170        target.debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.ConsoleCommandEvaluatedInSelectedCallFrame, this._consoleCommandEvaluatedInSelectedCallFrame, this);
171        target.debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.BreakpointsActiveStateChanged, this._breakpointsActiveStateChanged, this);
172        target.debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, this._debuggerReset, this);
173    },
174
175    /**
176     * @param {?WebInspector.Target} target
177     */
178    _setTarget: function(target)
179    {
180        if (!target)
181            return;
182
183        if (target.debuggerModel.isPaused()) {
184            this._showDebuggerPausedDetails(/** @type {!WebInspector.DebuggerPausedDetails} */ (target.debuggerModel.debuggerPausedDetails()));
185            var callFrame = target.debuggerModel.selectedCallFrame();
186            if (callFrame)
187                this._selectCallFrame(callFrame);
188        } else {
189            this._paused = false;
190            this._clearInterface();
191            this._toggleDebuggerSidebarButton.setEnabled(true);
192        }
193    },
194
195    /**
196     * @param {!WebInspector.Event} event
197     */
198    _onCurrentTargetChanged: function(event)
199    {
200        var target = /** @type {?WebInspector.Target} */ (event.data);
201        this._setTarget(target);
202    },
203
204    /**
205     * @return {!Element}
206     */
207    defaultFocusedElement: function()
208    {
209        return this._sourcesView.defaultFocusedElement() || this._navigator.view.defaultFocusedElement();
210    },
211
212    /**
213     * @return {boolean}
214     */
215    paused: function()
216    {
217        return this._paused;
218    },
219
220    /**
221     * @return {!WebInspector.SourcesPanel.DrawerEditor}
222     */
223    _drawerEditor: function()
224    {
225        var drawerEditorInstance = WebInspector.moduleManager.instance(WebInspector.DrawerEditor);
226        console.assert(drawerEditorInstance instanceof WebInspector.SourcesPanel.DrawerEditor, "WebInspector.DrawerEditor module instance does not use WebInspector.SourcesPanel.DrawerEditor as an implementation. ");
227        return /** @type {!WebInspector.SourcesPanel.DrawerEditor} */ (drawerEditorInstance);
228    },
229
230    wasShown: function()
231    {
232        WebInspector.context.setFlavor(WebInspector.SourcesPanel, this);
233        if (WebInspector.experimentsSettings.editorInDrawer.isEnabled()) {
234            this._drawerEditor()._panelWasShown();
235            this._sourcesView.show(this.editorView.mainElement());
236        }
237        WebInspector.Panel.prototype.wasShown.call(this);
238    },
239
240    willHide: function()
241    {
242        WebInspector.Panel.prototype.willHide.call(this);
243        if (WebInspector.experimentsSettings.editorInDrawer.isEnabled()) {
244            this._drawerEditor()._panelWillHide();
245            this._sourcesView.show(this._drawerEditorView.element);
246        }
247        WebInspector.context.setFlavor(WebInspector.SourcesPanel, null);
248    },
249
250    /**
251     * @return {!WebInspector.SearchableView}
252     */
253    searchableView: function()
254    {
255        return this._sourcesView.searchableView();
256    },
257
258    _consoleCommandEvaluatedInSelectedCallFrame: function(event)
259    {
260        this.sidebarPanes.scopechain.update(WebInspector.debuggerModel.selectedCallFrame());
261    },
262
263    /**
264     * @param {!WebInspector.Event} event
265     */
266    _debuggerPaused: function(event)
267    {
268        var details = /** @type {!WebInspector.DebuggerPausedDetails} */ (event.data);
269        if (!this._paused)
270            WebInspector.inspectorView.setCurrentPanel(this);
271
272        if (WebInspector.context.flavor(WebInspector.Target) === details.target())
273            this._showDebuggerPausedDetails(details);
274        else if (!this._paused)
275            WebInspector.context.setFlavor(WebInspector.Target, details.target());
276    },
277
278    /**
279     * @param {!WebInspector.DebuggerPausedDetails} details
280     */
281    _showDebuggerPausedDetails: function(details)
282    {
283        this._paused = true;
284        this._updateDebuggerButtons();
285
286        this.sidebarPanes.callstack.update(details);
287
288        /**
289         * @param {!Element} element
290         * @this {WebInspector.SourcesPanel}
291         */
292        function didCreateBreakpointHitStatusMessage(element)
293        {
294            this.sidebarPanes.callstack.setStatus(element);
295        }
296
297        /**
298         * @param {!WebInspector.UILocation} uiLocation
299         * @this {WebInspector.SourcesPanel}
300         */
301        function didGetUILocation(uiLocation)
302        {
303            var breakpoint = WebInspector.breakpointManager.findBreakpointOnLine(uiLocation.uiSourceCode, uiLocation.lineNumber);
304            if (!breakpoint)
305                return;
306            this.sidebarPanes.jsBreakpoints.highlightBreakpoint(breakpoint);
307            this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a JavaScript breakpoint."));
308        }
309
310        if (details.reason === WebInspector.DebuggerModel.BreakReason.DOM) {
311            WebInspector.domBreakpointsSidebarPane.highlightBreakpoint(details.auxData);
312            WebInspector.domBreakpointsSidebarPane.createBreakpointHitStatusMessage(details, didCreateBreakpointHitStatusMessage.bind(this));
313        } else if (details.reason === WebInspector.DebuggerModel.BreakReason.EventListener) {
314            var eventName = details.auxData["eventName"];
315            var targetName = details.auxData["targetName"];
316            this.sidebarPanes.eventListenerBreakpoints.highlightBreakpoint(eventName, targetName);
317            var eventNameForUI = WebInspector.EventListenerBreakpointsSidebarPane.eventNameForUI(eventName, details.auxData);
318            this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a \"%s\" Event Listener.", eventNameForUI));
319        } else if (details.reason === WebInspector.DebuggerModel.BreakReason.XHR) {
320            this.sidebarPanes.xhrBreakpoints.highlightBreakpoint(details.auxData["breakpointURL"]);
321            this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a XMLHttpRequest."));
322        } else if (details.reason === WebInspector.DebuggerModel.BreakReason.Exception)
323            this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on exception: '%s'.", details.auxData["description"]));
324        else if (details.reason === WebInspector.DebuggerModel.BreakReason.Assert)
325            this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on assertion."));
326        else if (details.reason === WebInspector.DebuggerModel.BreakReason.CSPViolation)
327            this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a script blocked due to Content Security Policy directive: \"%s\".", details.auxData["directiveText"]));
328        else if (details.reason === WebInspector.DebuggerModel.BreakReason.DebugCommand)
329            this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a debugged function"));
330        else {
331            if (details.callFrames.length)
332                details.callFrames[0].createLiveLocation(didGetUILocation.bind(this));
333            else
334                console.warn("ScriptsPanel paused, but callFrames.length is zero."); // TODO remove this once we understand this case better
335        }
336
337        this._splitView.showBoth(true);
338        this._toggleDebuggerSidebarButton.setEnabled(false);
339        window.focus();
340        InspectorFrontendHost.bringToFront();
341    },
342
343    /**
344     * @param {!WebInspector.Event} event
345     */
346    _debuggerResumed: function(event)
347    {
348        var target = /** @type {!WebInspector.Target} */  (event.target.target());
349        if (WebInspector.context.flavor(WebInspector.Target) !== target)
350            return;
351        this._paused = false;
352        this._clearInterface();
353        this._toggleDebuggerSidebarButton.setEnabled(true);
354    },
355
356    /**
357     * @param {!WebInspector.Event} event
358     */
359    _debuggerWasEnabled: function(event)
360    {
361        var target = /** @type {!WebInspector.Target} */  (event.target.target());
362        if (WebInspector.context.flavor(WebInspector.Target) !== target)
363            return;
364
365        this._updateDebuggerButtons();
366    },
367
368    /**
369     * @param {!WebInspector.Event} event
370     */
371    _debuggerReset: function(event)
372    {
373        this._debuggerResumed(event);
374        delete this._skipExecutionLineRevealing;
375    },
376
377    /**
378     * @return {!WebInspector.View}
379     */
380    get visibleView()
381    {
382        return this._sourcesView.visibleView();
383    },
384
385    /**
386     * @param {!WebInspector.UISourceCode} uiSourceCode
387     * @param {number=} lineNumber
388     * @param {number=} columnNumber
389     * @param {boolean=} forceShowInPanel
390     */
391    showUISourceCode: function(uiSourceCode, lineNumber, columnNumber, forceShowInPanel)
392    {
393        this._showEditor(forceShowInPanel);
394        this._sourcesView.showSourceLocation(uiSourceCode, lineNumber, columnNumber);
395    },
396
397    _showEditor: function(forceShowInPanel)
398    {
399        if (this._sourcesView.isShowing())
400            return;
401
402        if (this._shouldShowEditorInDrawer() && !forceShowInPanel)
403            this._drawerEditor()._show();
404        else
405            WebInspector.inspectorView.showPanel("sources");
406    },
407
408    /**
409     * @param {!WebInspector.UILocation} uiLocation
410     * @param {boolean=} forceShowInPanel
411     */
412    showUILocation: function(uiLocation, forceShowInPanel)
413    {
414        this.showUISourceCode(uiLocation.uiSourceCode, uiLocation.lineNumber, uiLocation.columnNumber, forceShowInPanel);
415    },
416
417    /**
418     * @return {boolean}
419     */
420    _shouldShowEditorInDrawer: function()
421    {
422        return WebInspector.experimentsSettings.editorInDrawer.isEnabled() && WebInspector.settings.showEditorInDrawer.get() && WebInspector.inspectorView.isDrawerEditorShown();
423    },
424
425    /**
426     * @param {!WebInspector.UISourceCode} uiSourceCode
427     */
428    _revealInNavigator: function(uiSourceCode)
429    {
430        this._navigator.revealUISourceCode(uiSourceCode);
431    },
432
433    _executionLineChanged: function(uiLocation)
434    {
435        this._sourcesView.clearCurrentExecutionLine();
436        this._sourcesView.setExecutionLine(uiLocation);
437        if (this._skipExecutionLineRevealing)
438            return;
439        this._skipExecutionLineRevealing = true;
440        this._sourcesView.showSourceLocation(uiLocation.uiSourceCode, uiLocation.lineNumber, 0, undefined, true);
441    },
442
443    /**
444     * @param {!WebInspector.Event} event
445     */
446    _callFrameSelected: function(event)
447    {
448        var callFrame = /** @type {?WebInspector.DebuggerModel.CallFrame} */ (event.data);
449
450        if (!callFrame || callFrame.target() !== WebInspector.context.flavor(WebInspector.Target))
451            return;
452
453        this._selectCallFrame(callFrame);
454    },
455
456    /**
457     * @param {!WebInspector.DebuggerModel.CallFrame}  callFrame
458     */
459    _selectCallFrame: function(callFrame)
460    {
461        this.sidebarPanes.scopechain.update(callFrame);
462        this.sidebarPanes.watchExpressions.refreshExpressions();
463        this.sidebarPanes.callstack.setSelectedCallFrame(callFrame);
464        callFrame.createLiveLocation(this._executionLineChanged.bind(this));
465    },
466
467    /**
468     * @param {!WebInspector.Event} event
469     */
470    _sourceSelected: function(event)
471    {
472        var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data.uiSourceCode);
473        this._sourcesView.showSourceLocation(uiSourceCode, undefined, undefined, !event.data.focusSource)
474    },
475
476    /**
477     * @param {!WebInspector.Event} event
478     */
479    _sourceRenamed: function(event)
480    {
481        var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
482        this._sourcesView.sourceRenamed(uiSourceCode);
483    },
484
485    _pauseOnExceptionEnabledChanged: function()
486    {
487        var enabled = WebInspector.settings.pauseOnExceptionEnabled.get();
488        this._pauseOnExceptionButton.toggled = enabled;
489        this._pauseOnExceptionButton.title = WebInspector.UIString(enabled ? "Don't pause on exceptions." : "Pause on exceptions.");
490        this._debugToolbarDrawer.classList.toggle("expanded", enabled);
491    },
492
493    _updateDebuggerButtons: function()
494    {
495        var currentTarget = WebInspector.context.flavor(WebInspector.Target);
496        if (!currentTarget)
497            return;
498
499        if (this._paused) {
500            this._updateButtonTitle(this._pauseButton, WebInspector.UIString("Resume script execution (%s)."))
501            this._pauseButton.state = true;
502            this._pauseButton.setLongClickOptionsEnabled((function() { return [ this._longResumeButton ] }).bind(this));
503
504            this._pauseButton.setEnabled(true);
505            this._stepOverButton.setEnabled(true);
506            this._stepIntoButton.setEnabled(true);
507            this._stepOutButton.setEnabled(true);
508        } else {
509            this._updateButtonTitle(this._pauseButton, WebInspector.UIString("Pause script execution (%s)."))
510            this._pauseButton.state = false;
511            this._pauseButton.setLongClickOptionsEnabled(null);
512
513            this._pauseButton.setEnabled(!currentTarget.debuggerModel.isPausing());
514            this._stepOverButton.setEnabled(false);
515            this._stepIntoButton.setEnabled(false);
516            this._stepOutButton.setEnabled(false);
517        }
518    },
519
520    _clearInterface: function()
521    {
522        this.sidebarPanes.callstack.update(null);
523        this.sidebarPanes.scopechain.update(null);
524        this.sidebarPanes.jsBreakpoints.clearBreakpointHighlight();
525        WebInspector.domBreakpointsSidebarPane.clearBreakpointHighlight();
526        this.sidebarPanes.eventListenerBreakpoints.clearBreakpointHighlight();
527        this.sidebarPanes.xhrBreakpoints.clearBreakpointHighlight();
528
529        this._sourcesView.clearCurrentExecutionLine();
530        this._updateDebuggerButtons();
531    },
532
533    _togglePauseOnExceptions: function()
534    {
535        WebInspector.settings.pauseOnExceptionEnabled.set(!this._pauseOnExceptionButton.toggled);
536    },
537
538    /**
539     * @return {boolean}
540     */
541    _runSnippet: function()
542    {
543        var uiSourceCode = this._sourcesView.currentUISourceCode();
544        if (uiSourceCode.project().type() !== WebInspector.projectTypes.Snippets)
545            return false;
546
547        var currentExecutionContext = WebInspector.context.flavor(WebInspector.ExecutionContext);
548        if (!currentExecutionContext)
549            return false;
550
551        WebInspector.scriptSnippetModel.evaluateScriptSnippet(currentExecutionContext, uiSourceCode);
552        return true;
553    },
554
555    /**
556     * @param {!WebInspector.Event} event
557     */
558    _editorSelected: function(event)
559    {
560        var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
561        this._editorChanged(uiSourceCode);
562   },
563
564    /**
565     * @param {!WebInspector.Event} event
566     */
567    _editorClosed: function(event)
568    {
569        var wasSelected = /** @type {boolean} */ (event.data.wasSelected);
570        if (wasSelected)
571            this._editorChanged(null);
572    },
573
574    /**
575     * @param {?WebInspector.UISourceCode} uiSourceCode
576     */
577    _editorChanged: function(uiSourceCode)
578    {
579        var isSnippet = uiSourceCode && uiSourceCode.project().type() === WebInspector.projectTypes.Snippets;
580        this._runSnippetButton.element.classList.toggle("hidden", !isSnippet);
581    },
582
583    /**
584     * @return {boolean}
585     */
586    togglePause: function()
587    {
588        var target = WebInspector.context.flavor(WebInspector.Target);
589        if (!target)
590            return true;
591
592        if (this._paused) {
593            delete this._skipExecutionLineRevealing;
594            this._paused = false;
595            target.debuggerModel.resume();
596        } else {
597            // Make sure pauses didn't stick skipped.
598            target.debuggerModel.pause();
599        }
600
601        this._clearInterface();
602        return true;
603    },
604
605    /**
606     * @return {?WebInspector.DebuggerModel}
607     */
608    _prepareToResume: function()
609    {
610        if (!this._paused)
611            return null;
612
613        delete this._skipExecutionLineRevealing;
614        this._paused = false;
615
616        this._clearInterface();
617        var target = WebInspector.context.flavor(WebInspector.Target);
618        return target ? target.debuggerModel : null;
619    },
620
621    /**
622     * @return {boolean}
623     */
624    _longResume: function()
625    {
626        var debuggerModel = this._prepareToResume();
627        if (!debuggerModel)
628            return true;
629
630        debuggerModel.skipAllPausesUntilReloadOrTimeout(500);
631        debuggerModel.resume();
632        return true;
633    },
634
635    /**
636     * @return {boolean}
637     */
638    _stepOverClicked: function()
639    {
640        var debuggerModel = this._prepareToResume();
641        if (!debuggerModel)
642            return true;
643
644        debuggerModel.stepOver();
645        return true;
646    },
647
648    /**
649     * @return {boolean}
650     */
651    _stepIntoClicked: function()
652    {
653        var debuggerModel = this._prepareToResume();
654        if (!debuggerModel)
655            return true;
656
657        debuggerModel.stepInto();
658        return true;
659    },
660
661    /**
662     * @return {boolean}
663     */
664    _stepOutClicked: function()
665    {
666        var debuggerModel = this._prepareToResume();
667        if (!debuggerModel)
668            return true;
669
670        debuggerModel.stepOut();
671        return true;
672    },
673
674    /**
675     * @param {!WebInspector.Event} event
676     */
677    _callFrameSelectedInSidebar: function(event)
678    {
679        var callFrame = /** @type {!WebInspector.DebuggerModel.CallFrame} */ (event.data);
680        delete this._skipExecutionLineRevealing;
681        callFrame.target().debuggerModel.setSelectedCallFrame(callFrame);
682    },
683
684    _callFrameRestartedInSidebar: function()
685    {
686        delete this._skipExecutionLineRevealing;
687    },
688
689    /**
690     * @param {!WebInspector.DebuggerModel.Location} rawLocation
691     */
692    continueToLocation: function(rawLocation)
693    {
694        if (!this._prepareToResume())
695            return;
696
697        rawLocation.continueToLocation();
698    },
699
700    _toggleBreakpointsClicked: function(event)
701    {
702        WebInspector.debuggerModel.setBreakpointsActive(!WebInspector.debuggerModel.breakpointsActive());
703    },
704
705    _breakpointsActiveStateChanged: function(event)
706    {
707        var active = event.data;
708        this._toggleBreakpointsButton.toggled = !active;
709        this.sidebarPanes.jsBreakpoints.listElement.classList.toggle("breakpoints-list-deactivated", !active);
710        this._sourcesView.toggleBreakpointsActiveState(active);
711        if (active)
712            this._toggleBreakpointsButton.title = WebInspector.UIString("Deactivate breakpoints.");
713        else
714            this._toggleBreakpointsButton.title = WebInspector.UIString("Activate breakpoints.");
715    },
716
717    _createDebugToolbar: function()
718    {
719        var debugToolbar = document.createElement("div");
720        debugToolbar.className = "scripts-debug-toolbar";
721
722        var title, handler;
723        var platformSpecificModifier = WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta;
724
725        // Run snippet.
726        title = WebInspector.UIString("Run snippet (%s).");
727        handler = this._runSnippet.bind(this);
728        this._runSnippetButton = this._createButtonAndRegisterShortcuts("scripts-run-snippet", title, handler, WebInspector.ShortcutsScreen.SourcesPanelShortcuts.RunSnippet);
729        debugToolbar.appendChild(this._runSnippetButton.element);
730        this._runSnippetButton.element.classList.add("hidden");
731
732        // Continue.
733        handler = function() { return WebInspector.actionRegistry.execute("debugger.toggle-pause"); };
734        this._pauseButton = this._createButtonAndRegisterShortcuts("scripts-pause", "", handler, []);
735        debugToolbar.appendChild(this._pauseButton.element);
736
737        // Long resume.
738        title = WebInspector.UIString("Resume with all pauses blocked for 500 ms");
739        this._longResumeButton = new WebInspector.StatusBarButton(title, "scripts-long-resume");
740        this._longResumeButton.addEventListener("click", this._longResume.bind(this), this);
741
742        // Step over.
743        title = WebInspector.UIString("Step over next function call (%s).");
744        handler = this._stepOverClicked.bind(this);
745        this._stepOverButton = this._createButtonAndRegisterShortcuts("scripts-step-over", title, handler, WebInspector.ShortcutsScreen.SourcesPanelShortcuts.StepOver);
746        debugToolbar.appendChild(this._stepOverButton.element);
747
748        // Step into.
749        title = WebInspector.UIString("Step into next function call (%s).");
750        handler = this._stepIntoClicked.bind(this);
751        this._stepIntoButton = this._createButtonAndRegisterShortcuts("scripts-step-into", title, handler, WebInspector.ShortcutsScreen.SourcesPanelShortcuts.StepInto);
752        debugToolbar.appendChild(this._stepIntoButton.element);
753
754        // Step out.
755        title = WebInspector.UIString("Step out of current function (%s).");
756        handler = this._stepOutClicked.bind(this);
757        this._stepOutButton = this._createButtonAndRegisterShortcuts("scripts-step-out", title, handler, WebInspector.ShortcutsScreen.SourcesPanelShortcuts.StepOut);
758        debugToolbar.appendChild(this._stepOutButton.element);
759
760        // Toggle Breakpoints
761        this._toggleBreakpointsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Deactivate breakpoints."), "scripts-toggle-breakpoints");
762        this._toggleBreakpointsButton.toggled = false;
763        this._toggleBreakpointsButton.addEventListener("click", this._toggleBreakpointsClicked, this);
764        debugToolbar.appendChild(this._toggleBreakpointsButton.element);
765
766        // Pause on Exception
767        this._pauseOnExceptionButton = new WebInspector.StatusBarButton("", "scripts-pause-on-exceptions-status-bar-item");
768        this._pauseOnExceptionButton.addEventListener("click", this._togglePauseOnExceptions, this);
769        debugToolbar.appendChild(this._pauseOnExceptionButton.element);
770
771        return debugToolbar;
772    },
773
774    _createDebugToolbarDrawer: function()
775    {
776        var debugToolbarDrawer = document.createElement("div");
777        debugToolbarDrawer.className = "scripts-debug-toolbar-drawer";
778
779        var label = WebInspector.UIString("Pause On Caught Exceptions");
780        var setting = WebInspector.settings.pauseOnCaughtException;
781        debugToolbarDrawer.appendChild(WebInspector.SettingsUI.createSettingCheckbox(label, setting, true));
782
783        return debugToolbarDrawer;
784    },
785
786    /**
787     * @param {!WebInspector.StatusBarButton} button
788     * @param {string} buttonTitle
789     */
790    _updateButtonTitle: function(button, buttonTitle)
791    {
792        var hasShortcuts = button.shortcuts && button.shortcuts.length;
793        if (hasShortcuts)
794            button.title = String.vsprintf(buttonTitle, [button.shortcuts[0].name]);
795        else
796            button.title = buttonTitle;
797    },
798
799    /**
800     * @param {string} buttonId
801     * @param {string} buttonTitle
802     * @param {function(?Event=):boolean} handler
803     * @param {!Array.<!WebInspector.KeyboardShortcut.Descriptor>} shortcuts
804     * @return {!WebInspector.StatusBarButton}
805     */
806    _createButtonAndRegisterShortcuts: function(buttonId, buttonTitle, handler, shortcuts)
807    {
808        var button = new WebInspector.StatusBarButton(buttonTitle, buttonId);
809        button.element.addEventListener("click", handler, false);
810        button.shortcuts = shortcuts;
811        this._updateButtonTitle(button, buttonTitle);
812        this.registerShortcuts(shortcuts, handler);
813        return button;
814    },
815
816    addToWatch: function(expression)
817    {
818        this.sidebarPanes.watchExpressions.addExpression(expression);
819    },
820
821    _installDebuggerSidebarController: function()
822    {
823        this._toggleNavigatorSidebarButton = this.editorView.createShowHideSidebarButton("navigator", "scripts-navigator-show-hide-button");
824        this.editorView.mainElement().appendChild(this._toggleNavigatorSidebarButton.element);
825
826        this._toggleDebuggerSidebarButton = this._splitView.createShowHideSidebarButton("debugger", "scripts-debugger-show-hide-button");
827
828        this._splitView.mainElement().appendChild(this._toggleDebuggerSidebarButton.element);
829        this._splitView.mainElement().appendChild(this._debugSidebarResizeWidgetElement);
830    },
831
832    _updateDebugSidebarResizeWidget: function()
833    {
834        this._debugSidebarResizeWidgetElement.classList.toggle("hidden", this._splitView.showMode() !== WebInspector.SplitView.ShowMode.Both);
835    },
836
837    /**
838     * @param {!WebInspector.UISourceCode} uiSourceCode
839     */
840    _showLocalHistory: function(uiSourceCode)
841    {
842        WebInspector.RevisionHistoryView.showHistory(uiSourceCode);
843    },
844
845    /**
846     * @param {!Event} event
847     * @param {!WebInspector.ContextMenu} contextMenu
848     * @param {!Object} target
849     */
850    appendApplicableItems: function(event, contextMenu, target)
851    {
852        this._appendUISourceCodeItems(event, contextMenu, target);
853        this._appendRemoteObjectItems(contextMenu, target);
854    },
855
856    _suggestReload: function()
857    {
858        if (window.confirm(WebInspector.UIString("It is recommended to restart inspector after making these changes. Would you like to restart it?")))
859            WebInspector.reload();
860    },
861
862    /**
863     * @param {!WebInspector.UISourceCode} uiSourceCode
864     */
865    _mapFileSystemToNetwork: function(uiSourceCode)
866    {
867        WebInspector.SelectUISourceCodeForProjectTypesDialog.show(uiSourceCode.name(), [WebInspector.projectTypes.Network, WebInspector.projectTypes.ContentScripts], mapFileSystemToNetwork.bind(this), this.editorView.mainElement())
868
869        /**
870         * @param {!WebInspector.UISourceCode} networkUISourceCode
871         * @this {WebInspector.SourcesPanel}
872         */
873        function mapFileSystemToNetwork(networkUISourceCode)
874        {
875            this._workspace.addMapping(networkUISourceCode, uiSourceCode, WebInspector.fileSystemWorkspaceBinding);
876            this._suggestReload();
877        }
878    },
879
880    /**
881     * @param {!WebInspector.UISourceCode} uiSourceCode
882     */
883    _removeNetworkMapping: function(uiSourceCode)
884    {
885        if (confirm(WebInspector.UIString("Are you sure you want to remove network mapping?"))) {
886            this._workspace.removeMapping(uiSourceCode);
887            this._suggestReload();
888        }
889    },
890
891    /**
892     * @param {!WebInspector.UISourceCode} networkUISourceCode
893     */
894    _mapNetworkToFileSystem: function(networkUISourceCode)
895    {
896        WebInspector.SelectUISourceCodeForProjectTypesDialog.show(networkUISourceCode.name(), [WebInspector.projectTypes.FileSystem], mapNetworkToFileSystem.bind(this), this.editorView.mainElement())
897
898        /**
899         * @param {!WebInspector.UISourceCode} uiSourceCode
900         * @this {WebInspector.SourcesPanel}
901         */
902        function mapNetworkToFileSystem(uiSourceCode)
903        {
904            this._workspace.addMapping(networkUISourceCode, uiSourceCode, WebInspector.fileSystemWorkspaceBinding);
905            this._suggestReload();
906        }
907    },
908
909    /**
910     * @param {!WebInspector.ContextMenu} contextMenu
911     * @param {!WebInspector.UISourceCode} uiSourceCode
912     */
913    _appendUISourceCodeMappingItems: function(contextMenu, uiSourceCode)
914    {
915        if (uiSourceCode.project().type() === WebInspector.projectTypes.FileSystem) {
916            var hasMappings = !!uiSourceCode.url;
917            if (!hasMappings)
918                contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Map to network resource\u2026" : "Map to Network Resource\u2026"), this._mapFileSystemToNetwork.bind(this, uiSourceCode));
919            else
920                contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Remove network mapping" : "Remove Network Mapping"), this._removeNetworkMapping.bind(this, uiSourceCode));
921        }
922
923        /**
924         * @param {!WebInspector.Project} project
925         */
926        function filterProject(project)
927        {
928            return project.type() === WebInspector.projectTypes.FileSystem;
929        }
930
931        if (uiSourceCode.project().type() === WebInspector.projectTypes.Network || uiSourceCode.project().type() === WebInspector.projectTypes.ContentScripts) {
932            if (!this._workspace.projects().filter(filterProject).length)
933                return;
934            if (this._workspace.uiSourceCodeForURL(uiSourceCode.url) === uiSourceCode)
935                contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Map to file system resource\u2026" : "Map to File System Resource\u2026"), this._mapNetworkToFileSystem.bind(this, uiSourceCode));
936        }
937    },
938
939    /**
940     * @param {?Event} event
941     * @param {!WebInspector.ContextMenu} contextMenu
942     * @param {!Object} target
943     */
944    _appendUISourceCodeItems: function(event, contextMenu, target)
945    {
946        if (!(target instanceof WebInspector.UISourceCode))
947            return;
948
949        var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (target);
950        var project = uiSourceCode.project();
951        if (project.type() !== WebInspector.projectTypes.FileSystem)
952            contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Local modifications\u2026" : "Local Modifications\u2026"), this._showLocalHistory.bind(this, uiSourceCode));
953        this._appendUISourceCodeMappingItems(contextMenu, uiSourceCode);
954
955        if (!event.target.isSelfOrDescendant(this.editorView.sidebarElement())) {
956            contextMenu.appendSeparator();
957            contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Reveal in navigator" : "Reveal in Navigator"), this._handleContextMenuReveal.bind(this, uiSourceCode));
958        }
959    },
960
961    /**
962     * @param {!WebInspector.UISourceCode} uiSourceCode
963     */
964    _handleContextMenuReveal: function(uiSourceCode)
965    {
966        this.editorView.showBoth();
967        this._revealInNavigator(uiSourceCode);
968    },
969
970    /**
971     * @param {!WebInspector.ContextMenu} contextMenu
972     * @param {!Object} target
973     */
974    _appendRemoteObjectItems: function(contextMenu, target)
975    {
976        if (!(target instanceof WebInspector.RemoteObject))
977            return;
978        var remoteObject = /** @type {!WebInspector.RemoteObject} */ (target);
979        contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Store as global variable" : "Store as Global Variable"), this._saveToTempVariable.bind(this, remoteObject));
980        if (remoteObject.type === "function")
981            contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Show function definition" : "Show Function Definition"), this._showFunctionDefinition.bind(this, remoteObject));
982    },
983
984    /**
985     * @param {!WebInspector.RemoteObject} remoteObject
986     */
987    _saveToTempVariable: function(remoteObject)
988    {
989        var currentExecutionContext = WebInspector.context.flavor(WebInspector.ExecutionContext);
990        if (!currentExecutionContext)
991            return;
992
993        currentExecutionContext.evaluate("window", "", false, true, false, false, didGetGlobalObject.bind(null, currentExecutionContext.target()));
994        /**
995         * @param {!WebInspector.Target} target
996         * @param {?WebInspector.RemoteObject} global
997         * @param {boolean=} wasThrown
998         */
999        function didGetGlobalObject(target, global, wasThrown)
1000        {
1001            /**
1002             * @suppressReceiverCheck
1003             * @this {Window}
1004             */
1005            function remoteFunction(value)
1006            {
1007                var prefix = "temp";
1008                var index = 1;
1009                while ((prefix + index) in this)
1010                    ++index;
1011                var name = prefix + index;
1012                this[name] = value;
1013                return name;
1014            }
1015
1016            if (wasThrown || !global)
1017                failedToSave(target, global);
1018            else
1019                global.callFunction(remoteFunction, [WebInspector.RemoteObject.toCallArgument(remoteObject)], didSave.bind(null, global));
1020        }
1021
1022        /**
1023         * @param {!WebInspector.RemoteObject} global
1024         * @param {?WebInspector.RemoteObject} result
1025         * @param {boolean=} wasThrown
1026         */
1027        function didSave(global, result, wasThrown)
1028        {
1029            var currentExecutionContext = WebInspector.context.flavor(WebInspector.ExecutionContext);
1030            global.release();
1031            if (!currentExecutionContext || wasThrown || !result || result.type !== "string")
1032                failedToSave(global.target(), result);
1033            else
1034                WebInspector.ConsoleModel.evaluateCommandInConsole(currentExecutionContext, result.value);
1035        }
1036
1037        /**
1038         * @param {!WebInspector.Target} target
1039         * @param {?WebInspector.RemoteObject} result
1040         */
1041        function failedToSave(target, result)
1042        {
1043            var message = WebInspector.UIString("Failed to save to temp variable.");
1044            if (result) {
1045                message += " " + result.description;
1046                result.release();
1047            }
1048            target.consoleModel.showErrorMessage(message);
1049        }
1050    },
1051
1052    /**
1053     * @param {!WebInspector.RemoteObject} remoteObject
1054     */
1055    _showFunctionDefinition: function(remoteObject)
1056    {
1057        var target = remoteObject.target();
1058
1059        /**
1060         * @param {?Protocol.Error} error
1061         * @param {!DebuggerAgent.FunctionDetails} response
1062         * @this {WebInspector.SourcesPanel}
1063         */
1064        function didGetFunctionDetails(error, response)
1065        {
1066            if (error) {
1067                console.error(error);
1068                return;
1069            }
1070
1071            var uiLocation = target.debuggerModel.rawLocationToUILocation(response.location);
1072            if (!uiLocation)
1073                return;
1074
1075            this.showUILocation(uiLocation, true);
1076        }
1077        target.debuggerAgent().getFunctionDetails(remoteObject.objectId, didGetFunctionDetails.bind(this));
1078    },
1079
1080    showGoToSourceDialog: function()
1081    {
1082        this._sourcesView.showOpenResourceDialog();
1083    },
1084
1085    _dockSideChanged: function()
1086    {
1087        var vertically = WebInspector.dockController.isVertical() && WebInspector.settings.splitVerticallyWhenDockedToRight.get();
1088        this._splitVertically(vertically);
1089    },
1090
1091    /**
1092     * @param {boolean} vertically
1093     */
1094    _splitVertically: function(vertically)
1095    {
1096        if (this.sidebarPaneView && vertically === !this._splitView.isVertical())
1097            return;
1098
1099        if (this.sidebarPaneView)
1100            this.sidebarPaneView.detach();
1101
1102        this._splitView.setVertical(!vertically);
1103
1104        if (!vertically)
1105            this._splitView.uninstallResizer(this._sourcesView.statusBarContainerElement());
1106        else
1107            this._splitView.installResizer(this._sourcesView.statusBarContainerElement());
1108
1109        // Create vertical box with stack.
1110        var vbox = new WebInspector.VBox();
1111        vbox.element.appendChild(this._debugToolbarDrawer);
1112        vbox.element.appendChild(this.debugToolbar);
1113        vbox.element.appendChild(this._targetsToolbar.element);
1114        vbox.setMinimumAndPreferredSizes(25, 25, WebInspector.SourcesPanel.minToolbarWidth, 100);
1115        var sidebarPaneStack = new WebInspector.SidebarPaneStack();
1116        sidebarPaneStack.element.classList.add("flex-auto");
1117        sidebarPaneStack.show(vbox.element);
1118
1119        if (!vertically) {
1120            // Populate the only stack.
1121            for (var pane in this.sidebarPanes)
1122                sidebarPaneStack.addPane(this.sidebarPanes[pane]);
1123            this._extensionSidebarPanesContainer = sidebarPaneStack;
1124
1125            this.sidebarPaneView = vbox;
1126        } else {
1127            var splitView = new WebInspector.SplitView(true, true, "sourcesPanelDebuggerSidebarSplitViewState", 0.5);
1128            vbox.show(splitView.mainElement());
1129
1130            // Populate the left stack.
1131            sidebarPaneStack.addPane(this.sidebarPanes.callstack);
1132            sidebarPaneStack.addPane(this.sidebarPanes.jsBreakpoints);
1133            sidebarPaneStack.addPane(this.sidebarPanes.domBreakpoints);
1134            sidebarPaneStack.addPane(this.sidebarPanes.xhrBreakpoints);
1135            sidebarPaneStack.addPane(this.sidebarPanes.eventListenerBreakpoints);
1136            if (this.sidebarPanes.workerList)
1137                sidebarPaneStack.addPane(this.sidebarPanes.workerList);
1138
1139            var tabbedPane = new WebInspector.SidebarTabbedPane();
1140            tabbedPane.show(splitView.sidebarElement());
1141            tabbedPane.addPane(this.sidebarPanes.scopechain);
1142            tabbedPane.addPane(this.sidebarPanes.watchExpressions);
1143            this._extensionSidebarPanesContainer = tabbedPane;
1144
1145            this.sidebarPaneView = splitView;
1146        }
1147        for (var i = 0; i < this._extensionSidebarPanes.length; ++i)
1148            this._extensionSidebarPanesContainer.addPane(this._extensionSidebarPanes[i]);
1149
1150        this.sidebarPaneView.show(this._splitView.sidebarElement());
1151
1152        this.sidebarPanes.scopechain.expand();
1153        this.sidebarPanes.jsBreakpoints.expand();
1154        this.sidebarPanes.callstack.expand();
1155
1156        if (WebInspector.settings.watchExpressions.get().length > 0)
1157            this.sidebarPanes.watchExpressions.expand();
1158    },
1159
1160    /**
1161     * @param {string} id
1162     * @param {!WebInspector.SidebarPane} pane
1163     */
1164    addExtensionSidebarPane: function(id, pane)
1165    {
1166        this._extensionSidebarPanes.push(pane);
1167        this._extensionSidebarPanesContainer.addPane(pane);
1168        this.setHideOnDetach();
1169    },
1170
1171    /**
1172     * @return {!WebInspector.SourcesView}
1173     */
1174    sourcesView: function()
1175    {
1176        return this._sourcesView;
1177    },
1178
1179    __proto__: WebInspector.Panel.prototype
1180}
1181
1182/**
1183 * @constructor
1184 * @param {!Element} element
1185 */
1186WebInspector.UpgradeFileSystemDropTarget = function(element)
1187{
1188    element.addEventListener("dragenter", this._onDragEnter.bind(this), true);
1189    element.addEventListener("dragover", this._onDragOver.bind(this), true);
1190    this._element = element;
1191}
1192
1193WebInspector.UpgradeFileSystemDropTarget.dragAndDropFilesType = "Files";
1194
1195WebInspector.UpgradeFileSystemDropTarget.prototype = {
1196    _onDragEnter: function (event)
1197    {
1198        if (event.dataTransfer.types.indexOf(WebInspector.UpgradeFileSystemDropTarget.dragAndDropFilesType) === -1)
1199            return;
1200        event.consume(true);
1201    },
1202
1203    _onDragOver: function (event)
1204    {
1205        if (event.dataTransfer.types.indexOf(WebInspector.UpgradeFileSystemDropTarget.dragAndDropFilesType) === -1)
1206            return;
1207        event.dataTransfer.dropEffect = "copy";
1208        event.consume(true);
1209        if (this._dragMaskElement)
1210            return;
1211        this._dragMaskElement = this._element.createChild("div", "fill drag-mask");
1212        this._dragMaskElement.createChild("div", "fill drag-mask-inner").textContent = WebInspector.UIString("Drop workspace folder here");
1213        this._dragMaskElement.addEventListener("drop", this._onDrop.bind(this), true);
1214        this._dragMaskElement.addEventListener("dragleave", this._onDragLeave.bind(this), true);
1215    },
1216
1217    _onDrop: function (event)
1218    {
1219        event.consume(true);
1220        this._removeMask();
1221        var items = /** @type {!Array.<!DataTransferItem>} */ (event.dataTransfer.items);
1222        if (!items.length)
1223            return;
1224        var entry = items[0].webkitGetAsEntry();
1225        if (!entry.isDirectory)
1226            return;
1227        InspectorFrontendHost.upgradeDraggedFileSystemPermissions(entry.filesystem);
1228    },
1229
1230    _onDragLeave: function (event)
1231    {
1232        event.consume(true);
1233        this._removeMask();
1234    },
1235
1236    _removeMask: function ()
1237    {
1238        this._dragMaskElement.remove();
1239        delete this._dragMaskElement;
1240    }
1241}
1242
1243/**
1244 * @constructor
1245 * @implements {WebInspector.DrawerEditor}
1246 */
1247WebInspector.SourcesPanel.DrawerEditor = function()
1248{
1249    this._panel = WebInspector.inspectorView.panel("sources");
1250}
1251
1252WebInspector.SourcesPanel.DrawerEditor.prototype = {
1253    /**
1254     * @return {!WebInspector.View}
1255     */
1256    view: function()
1257    {
1258        return this._panel._drawerEditorView;
1259    },
1260
1261    installedIntoDrawer: function()
1262    {
1263        if (this._panel.isShowing())
1264            this._panelWasShown();
1265        else
1266            this._panelWillHide();
1267    },
1268
1269    _panelWasShown: function()
1270    {
1271        WebInspector.inspectorView.setDrawerEditorAvailable(false);
1272        WebInspector.inspectorView.hideDrawerEditor();
1273    },
1274
1275    _panelWillHide: function()
1276    {
1277        WebInspector.inspectorView.setDrawerEditorAvailable(true);
1278        if (WebInspector.inspectorView.isDrawerEditorShown())
1279            WebInspector.inspectorView.showDrawerEditor();
1280    },
1281
1282    _show: function()
1283    {
1284        WebInspector.inspectorView.showDrawerEditor();
1285    },
1286}
1287
1288/**
1289 * @constructor
1290 * @extends {WebInspector.VBox}
1291 */
1292WebInspector.SourcesPanel.DrawerEditorView = function()
1293{
1294    WebInspector.VBox.call(this);
1295    this.element.id = "drawer-editor-view";
1296}
1297
1298WebInspector.SourcesPanel.DrawerEditorView.prototype = {
1299    __proto__: WebInspector.VBox.prototype
1300}
1301
1302
1303/**
1304 * @constructor
1305 * @implements {WebInspector.ContextMenu.Provider}
1306 */
1307WebInspector.SourcesPanel.ContextMenuProvider = function()
1308{
1309}
1310
1311WebInspector.SourcesPanel.ContextMenuProvider.prototype = {
1312    /**
1313     * @param {!Event} event
1314     * @param {!WebInspector.ContextMenu} contextMenu
1315     * @param {!Object} target
1316     */
1317    appendApplicableItems: function(event, contextMenu, target)
1318    {
1319        WebInspector.inspectorView.panel("sources").appendApplicableItems(event, contextMenu, target);
1320    }
1321}
1322
1323/**
1324 * @constructor
1325 * @implements {WebInspector.Revealer}
1326 */
1327WebInspector.SourcesPanel.UILocationRevealer = function()
1328{
1329}
1330
1331WebInspector.SourcesPanel.UILocationRevealer.prototype = {
1332    /**
1333     * @param {!Object} uiLocation
1334     */
1335    reveal: function(uiLocation)
1336    {
1337        if (uiLocation instanceof WebInspector.UILocation)
1338            /** @type {!WebInspector.SourcesPanel} */ (WebInspector.inspectorView.panel("sources")).showUILocation(uiLocation);
1339    }
1340}
1341
1342/**
1343 * @constructor
1344 * @implements {WebInspector.Revealer}
1345 */
1346WebInspector.SourcesPanel.UISourceCodeRevealer = function()
1347{
1348}
1349
1350WebInspector.SourcesPanel.UISourceCodeRevealer.prototype = {
1351    /**
1352     * @param {!Object} uiSourceCode
1353     */
1354    reveal: function(uiSourceCode)
1355    {
1356        if (uiSourceCode instanceof WebInspector.UISourceCode)
1357            /** @type {!WebInspector.SourcesPanel} */ (WebInspector.inspectorView.panel("sources")).showUISourceCode(uiSourceCode);
1358    }
1359}
1360
1361/**
1362 * @constructor
1363 * @implements {WebInspector.ActionDelegate}
1364 */
1365WebInspector.SourcesPanel.ShowGoToSourceDialogActionDelegate = function() {}
1366
1367WebInspector.SourcesPanel.ShowGoToSourceDialogActionDelegate.prototype = {
1368    /**
1369     * @return {boolean}
1370     */
1371    handleAction: function()
1372    {
1373        /** @type {!WebInspector.SourcesPanel} */ (WebInspector.inspectorView.showPanel("sources")).showGoToSourceDialog();
1374        return true;
1375    }
1376}
1377
1378/**
1379 * @constructor
1380 * @extends {WebInspector.UISettingDelegate}
1381 */
1382WebInspector.SourcesPanel.SkipStackFramePatternSettingDelegate = function()
1383{
1384    WebInspector.UISettingDelegate.call(this);
1385}
1386
1387WebInspector.SourcesPanel.SkipStackFramePatternSettingDelegate.prototype = {
1388    /**
1389     * @override
1390     * @return {!Element}
1391     */
1392    settingElement: function()
1393    {
1394        return WebInspector.SettingsUI.createSettingInputField(WebInspector.UIString("Pattern"), WebInspector.settings.skipStackFramesPattern, false, 1000, "100px", WebInspector.SettingsUI.regexValidator);
1395    },
1396
1397    __proto__: WebInspector.UISettingDelegate.prototype
1398}
1399
1400/**
1401 * @constructor
1402 * @extends {WebInspector.UISettingDelegate}
1403 */
1404WebInspector.SourcesPanel.DisableJavaScriptSettingDelegate = function()
1405{
1406    WebInspector.UISettingDelegate.call(this);
1407}
1408
1409WebInspector.SourcesPanel.DisableJavaScriptSettingDelegate.prototype = {
1410    /**
1411     * @override
1412     * @return {!Element}
1413     */
1414    settingElement: function()
1415    {
1416        var disableJSElement = WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Disable JavaScript"), WebInspector.settings.javaScriptDisabled);
1417        this._disableJSCheckbox = disableJSElement.getElementsByTagName("input")[0];
1418        WebInspector.settings.javaScriptDisabled.addChangeListener(this._settingChanged, this);
1419        var disableJSInfoParent = this._disableJSCheckbox.parentElement.createChild("span", "monospace");
1420        this._disableJSInfo = disableJSInfoParent.createChild("span", "object-info-state-note hidden");
1421        this._disableJSInfo.title = WebInspector.UIString("JavaScript is blocked on the inspected page (may be disabled in browser settings).");
1422
1423        WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._updateScriptDisabledCheckbox, this);
1424        this._updateScriptDisabledCheckbox();
1425        return disableJSElement;
1426    },
1427
1428    /**
1429     * @param {!WebInspector.Event} event
1430     */
1431    _settingChanged: function(event)
1432    {
1433        PageAgent.setScriptExecutionDisabled(event.data, this._updateScriptDisabledCheckbox.bind(this));
1434    },
1435
1436    _updateScriptDisabledCheckbox: function()
1437    {
1438        PageAgent.getScriptExecutionStatus(executionStatusCallback.bind(this));
1439
1440        /**
1441         * @param {?Protocol.Error} error
1442         * @param {string} status
1443         * @this {WebInspector.SourcesPanel.DisableJavaScriptSettingDelegate}
1444         */
1445        function executionStatusCallback(error, status)
1446        {
1447            if (error || !status)
1448                return;
1449
1450            var forbidden = (status === "forbidden");
1451            var disabled = forbidden || (status === "disabled");
1452
1453            this._disableJSInfo.classList.toggle("hidden", !forbidden);
1454            this._disableJSCheckbox.checked = disabled;
1455            this._disableJSCheckbox.disabled = forbidden;
1456        }
1457    },
1458
1459    __proto__: WebInspector.UISettingDelegate.prototype
1460}
1461
1462/**
1463 * @constructor
1464 * @implements {WebInspector.ActionDelegate}
1465 */
1466WebInspector.SourcesPanel.TogglePauseActionDelegate = function()
1467{
1468}
1469
1470WebInspector.SourcesPanel.TogglePauseActionDelegate.prototype = {
1471    /**
1472     * @return {boolean}
1473     */
1474    handleAction: function()
1475    {
1476        /** @type {!WebInspector.SourcesPanel} */ (WebInspector.inspectorView.showPanel("sources")).togglePause();
1477        return true;
1478    }
1479}
1480