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