Home | History | Annotate | Download | only in sources
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 /**
      6  * @constructor
      7  * @implements {WebInspector.TabbedEditorContainerDelegate}
      8  * @implements {WebInspector.Searchable}
      9  * @implements {WebInspector.Replaceable}
     10  * @extends {WebInspector.VBox}
     11  * @param {!WebInspector.Workspace} workspace
     12  * @param {!WebInspector.SourcesPanel} sourcesPanel
     13  */
     14 WebInspector.SourcesView = function(workspace, sourcesPanel)
     15 {
     16     WebInspector.VBox.call(this);
     17     this.registerRequiredCSS("sourcesView.css");
     18     this.element.id = "sources-panel-sources-view";
     19     this.setMinimumAndPreferredSizes(50, 25, 150, 100);
     20 
     21     this._workspace = workspace;
     22     this._sourcesPanel = sourcesPanel;
     23 
     24     this._searchableView = new WebInspector.SearchableView(this);
     25     this._searchableView.setMinimalSearchQuerySize(0);
     26     this._searchableView.show(this.element);
     27 
     28     /** @type {!Map.<!WebInspector.UISourceCode, !WebInspector.UISourceCodeFrame>} */
     29     this._sourceFramesByUISourceCode = new Map();
     30 
     31     var tabbedEditorPlaceholderText = WebInspector.isMac() ? WebInspector.UIString("Hit Cmd+P to open a file") : WebInspector.UIString("Hit Ctrl+P to open a file");
     32     this._editorContainer = new WebInspector.TabbedEditorContainer(this, "previouslyViewedFiles", tabbedEditorPlaceholderText);
     33     this._editorContainer.show(this._searchableView.element);
     34     this._editorContainer.addEventListener(WebInspector.TabbedEditorContainer.Events.EditorSelected, this._editorSelected, this);
     35     this._editorContainer.addEventListener(WebInspector.TabbedEditorContainer.Events.EditorClosed, this._editorClosed, this);
     36 
     37     this._historyManager = new WebInspector.EditingLocationHistoryManager(this, this.currentSourceFrame.bind(this));
     38 
     39     this._scriptViewStatusBarItemsContainer = document.createElement("div");
     40     this._scriptViewStatusBarItemsContainer.className = "inline-block";
     41 
     42     this._scriptViewStatusBarTextContainer = document.createElement("div");
     43     this._scriptViewStatusBarTextContainer.className = "hbox";
     44 
     45     this._statusBarContainerElement = this.element.createChild("div", "sources-status-bar");
     46 
     47     /**
     48      * @this {WebInspector.SourcesView}
     49      * @param {!WebInspector.SourcesView.EditorAction} EditorAction
     50      */
     51     function appendButtonForExtension(EditorAction)
     52     {
     53         this._statusBarContainerElement.appendChild(EditorAction.button(this));
     54     }
     55     var editorActions = /** @type {!Array.<!WebInspector.SourcesView.EditorAction>} */ (WebInspector.moduleManager.instances(WebInspector.SourcesView.EditorAction));
     56     editorActions.forEach(appendButtonForExtension.bind(this));
     57 
     58     this._statusBarContainerElement.appendChild(this._scriptViewStatusBarItemsContainer);
     59     this._statusBarContainerElement.appendChild(this._scriptViewStatusBarTextContainer);
     60 
     61     WebInspector.startBatchUpdate();
     62     this._workspace.uiSourceCodes().forEach(this._addUISourceCode.bind(this));
     63     WebInspector.endBatchUpdate();
     64 
     65     this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this);
     66     this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeRemoved, this._uiSourceCodeRemoved, this);
     67     this._workspace.addEventListener(WebInspector.Workspace.Events.ProjectRemoved, this._projectRemoved.bind(this), this);
     68 
     69     function handleBeforeUnload(event)
     70     {
     71         if (event.returnValue)
     72             return;
     73         var unsavedSourceCodes = WebInspector.workspace.unsavedSourceCodes();
     74         if (!unsavedSourceCodes.length)
     75             return;
     76 
     77         event.returnValue = WebInspector.UIString("DevTools have unsaved changes that will be permanently lost.");
     78         WebInspector.inspectorView.showPanel("sources");
     79         for (var i = 0; i < unsavedSourceCodes.length; ++i)
     80             WebInspector.Revealer.reveal(unsavedSourceCodes[i]);
     81     }
     82     window.addEventListener("beforeunload", handleBeforeUnload, true);
     83 
     84     this._shortcuts = {};
     85     this.element.addEventListener("keydown", this._handleKeyDown.bind(this), false);
     86 }
     87 
     88 WebInspector.SourcesView.Events = {
     89     EditorClosed: "EditorClosed",
     90     EditorSelected: "EditorSelected",
     91 }
     92 
     93 WebInspector.SourcesView.prototype = {
     94     /**
     95      * @param {function(!Array.<!WebInspector.KeyboardShortcut.Descriptor>, function(?Event=):boolean)} registerShortcutDelegate
     96      */
     97     registerShortcuts: function(registerShortcutDelegate)
     98     {
     99         /**
    100          * @this {WebInspector.SourcesView}
    101          * @param {!Array.<!WebInspector.KeyboardShortcut.Descriptor>} shortcuts
    102          * @param {function(?Event=):boolean} handler
    103          */
    104         function registerShortcut(shortcuts, handler)
    105         {
    106             registerShortcutDelegate(shortcuts, handler);
    107             this._registerShortcuts(shortcuts, handler);
    108         }
    109 
    110         registerShortcut.call(this, WebInspector.ShortcutsScreen.SourcesPanelShortcuts.JumpToPreviousLocation, this._onJumpToPreviousLocation.bind(this));
    111         registerShortcut.call(this, WebInspector.ShortcutsScreen.SourcesPanelShortcuts.JumpToNextLocation, this._onJumpToNextLocation.bind(this));
    112         registerShortcut.call(this, WebInspector.ShortcutsScreen.SourcesPanelShortcuts.CloseEditorTab, this._onCloseEditorTab.bind(this));
    113         registerShortcut.call(this, WebInspector.ShortcutsScreen.SourcesPanelShortcuts.GoToLine, this._showGoToLineDialog.bind(this));
    114         registerShortcut.call(this, WebInspector.ShortcutsScreen.SourcesPanelShortcuts.GoToMember, this._showOutlineDialog.bind(this));
    115         registerShortcut.call(this, [WebInspector.KeyboardShortcut.makeDescriptor("o", WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta | WebInspector.KeyboardShortcut.Modifiers.Shift)], this._showOutlineDialog.bind(this));
    116         registerShortcut.call(this, WebInspector.ShortcutsScreen.SourcesPanelShortcuts.ToggleBreakpoint, this._toggleBreakpoint.bind(this));
    117         registerShortcut.call(this, WebInspector.ShortcutsScreen.SourcesPanelShortcuts.Save, this._save.bind(this));
    118         registerShortcut.call(this, WebInspector.ShortcutsScreen.SourcesPanelShortcuts.SaveAll, this._saveAll.bind(this));
    119     },
    120 
    121     /**
    122      * @param {!Array.<!WebInspector.KeyboardShortcut.Descriptor>} keys
    123      * @param {function(?Event=):boolean} handler
    124      */
    125     _registerShortcuts: function(keys, handler)
    126     {
    127         for (var i = 0; i < keys.length; ++i)
    128             this._shortcuts[keys[i].key] = handler;
    129     },
    130 
    131     _handleKeyDown: function(event)
    132     {
    133         var shortcutKey = WebInspector.KeyboardShortcut.makeKeyFromEvent(event);
    134         var handler = this._shortcuts[shortcutKey];
    135         if (handler && handler())
    136             event.consume(true);
    137     },
    138 
    139     /**
    140      * @return {!Element}
    141      */
    142     statusBarContainerElement: function()
    143     {
    144         return this._statusBarContainerElement;
    145     },
    146 
    147     /**
    148      * @return {!Element}
    149      */
    150     defaultFocusedElement: function()
    151     {
    152         return this._editorContainer.view.defaultFocusedElement();
    153     },
    154 
    155     /**
    156      * @return {!WebInspector.SearchableView}
    157      */
    158     searchableView: function()
    159     {
    160         return this._searchableView;
    161     },
    162 
    163     /**
    164      * @return {!WebInspector.View}
    165      */
    166     visibleView: function()
    167     {
    168         return this._editorContainer.visibleView;
    169     },
    170 
    171     /**
    172      * @return {?WebInspector.SourceFrame}
    173      */
    174     currentSourceFrame: function()
    175     {
    176         var view = this.visibleView();
    177         if (!(view instanceof WebInspector.SourceFrame))
    178             return null;
    179         return /** @type {!WebInspector.SourceFrame} */ (view);
    180     },
    181 
    182     /**
    183      * @return {?WebInspector.UISourceCode}
    184      */
    185     currentUISourceCode: function()
    186     {
    187         return this._currentUISourceCode;
    188     },
    189 
    190     /**
    191      * @param {?Event=} event
    192      */
    193     _onCloseEditorTab: function(event)
    194     {
    195         var uiSourceCode = this.currentUISourceCode();
    196         if (!uiSourceCode)
    197             return false;
    198         this._editorContainer.closeFile(uiSourceCode);
    199         return true;
    200     },
    201 
    202     /**
    203      * @param {?Event=} event
    204      */
    205     _onJumpToPreviousLocation: function(event)
    206     {
    207         this._historyManager.rollback();
    208         return true;
    209     },
    210 
    211     /**
    212      * @param {?Event=} event
    213      */
    214     _onJumpToNextLocation: function(event)
    215     {
    216         this._historyManager.rollover();
    217         return true;
    218     },
    219 
    220     /**
    221      * @param {!WebInspector.Event} event
    222      */
    223     _uiSourceCodeAdded: function(event)
    224     {
    225         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
    226         this._addUISourceCode(uiSourceCode);
    227     },
    228 
    229     /**
    230      * @param {!WebInspector.UISourceCode} uiSourceCode
    231      */
    232     _addUISourceCode: function(uiSourceCode)
    233     {
    234         if (uiSourceCode.project().isServiceProject())
    235             return;
    236         this._editorContainer.addUISourceCode(uiSourceCode);
    237         // Replace debugger script-based uiSourceCode with a network-based one.
    238         var currentUISourceCode = this._currentUISourceCode;
    239         if (currentUISourceCode && currentUISourceCode.project().isServiceProject() && currentUISourceCode !== uiSourceCode && currentUISourceCode.url === uiSourceCode.url) {
    240             this._showFile(uiSourceCode);
    241             this._editorContainer.removeUISourceCode(currentUISourceCode);
    242         }
    243     },
    244 
    245     _uiSourceCodeRemoved: function(event)
    246     {
    247         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
    248         this._removeUISourceCodes([uiSourceCode]);
    249     },
    250 
    251     /**
    252      * @param {!Array.<!WebInspector.UISourceCode>} uiSourceCodes
    253      */
    254     _removeUISourceCodes: function(uiSourceCodes)
    255     {
    256         this._editorContainer.removeUISourceCodes(uiSourceCodes);
    257         for (var i = 0; i < uiSourceCodes.length; ++i) {
    258             this._removeSourceFrame(uiSourceCodes[i]);
    259             this._historyManager.removeHistoryForSourceCode(uiSourceCodes[i]);
    260         }
    261     },
    262 
    263     _projectRemoved: function(event)
    264     {
    265         var project = event.data;
    266         var uiSourceCodes = project.uiSourceCodes();
    267         this._removeUISourceCodes(uiSourceCodes);
    268         if (project.type() === WebInspector.projectTypes.Network)
    269             this._editorContainer.reset();
    270     },
    271 
    272     _updateScriptViewStatusBarItems: function()
    273     {
    274         this._scriptViewStatusBarItemsContainer.removeChildren();
    275         this._scriptViewStatusBarTextContainer.removeChildren();
    276         var sourceFrame = this.currentSourceFrame();
    277         if (!sourceFrame)
    278             return;
    279 
    280         var statusBarItems = sourceFrame.statusBarItems() || [];
    281         for (var i = 0; i < statusBarItems.length; ++i)
    282             this._scriptViewStatusBarItemsContainer.appendChild(statusBarItems[i]);
    283         var statusBarText = sourceFrame.statusBarText();
    284         if (statusBarText)
    285             this._scriptViewStatusBarTextContainer.appendChild(statusBarText);
    286     },
    287 
    288     /**
    289      * @param {!WebInspector.UISourceCode} uiSourceCode
    290      * @param {number=} lineNumber
    291      * @param {number=} columnNumber
    292      * @param {boolean=} omitFocus
    293      * @param {boolean=} omitHighlight
    294      */
    295     showSourceLocation: function(uiSourceCode, lineNumber, columnNumber, omitFocus, omitHighlight)
    296     {
    297         this._historyManager.updateCurrentState();
    298         var sourceFrame = this._showFile(uiSourceCode);
    299         if (typeof lineNumber === "number")
    300             sourceFrame.revealPosition(lineNumber, columnNumber, !omitHighlight);
    301         this._historyManager.pushNewState();
    302         if (!omitFocus)
    303             sourceFrame.focus();
    304         WebInspector.notifications.dispatchEventToListeners(WebInspector.UserMetrics.UserAction, {
    305             action: WebInspector.UserMetrics.UserActionNames.OpenSourceLink,
    306             url: uiSourceCode.originURL(),
    307             lineNumber: lineNumber
    308         });
    309     },
    310 
    311     /**
    312      * @param {!WebInspector.UISourceCode} uiSourceCode
    313      * @return {!WebInspector.SourceFrame}
    314      */
    315     _showFile: function(uiSourceCode)
    316     {
    317         var sourceFrame = this._getOrCreateSourceFrame(uiSourceCode);
    318         if (this._currentUISourceCode === uiSourceCode)
    319             return sourceFrame;
    320 
    321         this._currentUISourceCode = uiSourceCode;
    322         this._editorContainer.showFile(uiSourceCode);
    323         this._updateScriptViewStatusBarItems();
    324         return sourceFrame;
    325     },
    326 
    327     /**
    328      * @param {!WebInspector.UISourceCode} uiSourceCode
    329      * @return {!WebInspector.UISourceCodeFrame}
    330      */
    331     _createSourceFrame: function(uiSourceCode)
    332     {
    333         var sourceFrame;
    334         switch (uiSourceCode.contentType()) {
    335         case WebInspector.resourceTypes.Script:
    336             sourceFrame = new WebInspector.JavaScriptSourceFrame(this._sourcesPanel, uiSourceCode);
    337             break;
    338         case WebInspector.resourceTypes.Document:
    339             sourceFrame = new WebInspector.JavaScriptSourceFrame(this._sourcesPanel, uiSourceCode);
    340             break;
    341         case WebInspector.resourceTypes.Stylesheet:
    342             sourceFrame = new WebInspector.CSSSourceFrame(uiSourceCode);
    343             break;
    344         default:
    345             sourceFrame = new WebInspector.UISourceCodeFrame(uiSourceCode);
    346         break;
    347         }
    348         sourceFrame.setHighlighterType(uiSourceCode.highlighterType());
    349         this._sourceFramesByUISourceCode.put(uiSourceCode, sourceFrame);
    350         this._historyManager.trackSourceFrameCursorJumps(sourceFrame);
    351         return sourceFrame;
    352     },
    353 
    354     /**
    355      * @param {!WebInspector.UISourceCode} uiSourceCode
    356      * @return {!WebInspector.UISourceCodeFrame}
    357      */
    358     _getOrCreateSourceFrame: function(uiSourceCode)
    359     {
    360         return this._sourceFramesByUISourceCode.get(uiSourceCode) || this._createSourceFrame(uiSourceCode);
    361     },
    362 
    363     /**
    364      * @param {!WebInspector.SourceFrame} sourceFrame
    365      * @param {!WebInspector.UISourceCode} uiSourceCode
    366      * @return {boolean}
    367      */
    368     _sourceFrameMatchesUISourceCode: function(sourceFrame, uiSourceCode)
    369     {
    370         switch (uiSourceCode.contentType()) {
    371         case WebInspector.resourceTypes.Script:
    372         case WebInspector.resourceTypes.Document:
    373             return sourceFrame instanceof WebInspector.JavaScriptSourceFrame;
    374         case WebInspector.resourceTypes.Stylesheet:
    375             return sourceFrame instanceof WebInspector.CSSSourceFrame;
    376         default:
    377             return !(sourceFrame instanceof WebInspector.JavaScriptSourceFrame);
    378         }
    379     },
    380 
    381     /**
    382      * @param {!WebInspector.UISourceCode} uiSourceCode
    383      */
    384     _recreateSourceFrameIfNeeded: function(uiSourceCode)
    385     {
    386         var oldSourceFrame = this._sourceFramesByUISourceCode.get(uiSourceCode);
    387         if (!oldSourceFrame)
    388             return;
    389         if (this._sourceFrameMatchesUISourceCode(oldSourceFrame, uiSourceCode)) {
    390             oldSourceFrame.setHighlighterType(uiSourceCode.highlighterType());
    391         } else {
    392             this._editorContainer.removeUISourceCode(uiSourceCode);
    393             this._removeSourceFrame(uiSourceCode);
    394         }
    395     },
    396 
    397     /**
    398      * @param {!WebInspector.UISourceCode} uiSourceCode
    399      * @return {!WebInspector.SourceFrame}
    400      */
    401     viewForFile: function(uiSourceCode)
    402     {
    403         return this._getOrCreateSourceFrame(uiSourceCode);
    404     },
    405 
    406     /**
    407      * @param {!WebInspector.UISourceCode} uiSourceCode
    408      */
    409     _removeSourceFrame: function(uiSourceCode)
    410     {
    411         var sourceFrame = this._sourceFramesByUISourceCode.get(uiSourceCode);
    412         if (!sourceFrame)
    413             return;
    414         this._sourceFramesByUISourceCode.remove(uiSourceCode);
    415         sourceFrame.dispose();
    416     },
    417 
    418     clearCurrentExecutionLine: function()
    419     {
    420         if (this._executionSourceFrame)
    421             this._executionSourceFrame.clearExecutionLine();
    422         delete this._executionSourceFrame;
    423     },
    424 
    425     setExecutionLine: function(uiLocation)
    426     {
    427         var sourceFrame = this._getOrCreateSourceFrame(uiLocation.uiSourceCode);
    428         sourceFrame.setExecutionLine(uiLocation.lineNumber);
    429         this._executionSourceFrame = sourceFrame;
    430     },
    431 
    432     _editorClosed: function(event)
    433     {
    434         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
    435         this._historyManager.removeHistoryForSourceCode(uiSourceCode);
    436 
    437         var wasSelected = false;
    438         if (this._currentUISourceCode === uiSourceCode) {
    439             delete this._currentUISourceCode;
    440             wasSelected = true;
    441         }
    442 
    443         // SourcesNavigator does not need to update on EditorClosed.
    444         this._updateScriptViewStatusBarItems();
    445         this._searchableView.resetSearch();
    446 
    447         var data = {};
    448         data.uiSourceCode = uiSourceCode;
    449         data.wasSelected = wasSelected;
    450         this.dispatchEventToListeners(WebInspector.SourcesView.Events.EditorClosed, data);
    451     },
    452 
    453     _editorSelected: function(event)
    454     {
    455         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data.currentFile);
    456         var shouldUseHistoryManager = uiSourceCode !== this._currentUISourceCode && event.data.userGesture;
    457         if (shouldUseHistoryManager)
    458             this._historyManager.updateCurrentState();
    459         var sourceFrame = this._showFile(uiSourceCode);
    460         if (shouldUseHistoryManager)
    461             this._historyManager.pushNewState();
    462 
    463         this._searchableView.setReplaceable(!!sourceFrame && sourceFrame.canEditSource());
    464         this._searchableView.resetSearch();
    465 
    466         this.dispatchEventToListeners(WebInspector.SourcesView.Events.EditorSelected, uiSourceCode);
    467     },
    468 
    469     /**
    470      * @param {!WebInspector.UISourceCode} uiSourceCode
    471      */
    472     sourceRenamed: function(uiSourceCode)
    473     {
    474         this._recreateSourceFrameIfNeeded(uiSourceCode);
    475     },
    476 
    477     searchCanceled: function()
    478     {
    479         if (this._searchView)
    480             this._searchView.searchCanceled();
    481 
    482         delete this._searchView;
    483         delete this._searchQuery;
    484     },
    485 
    486     /**
    487      * @param {string} query
    488      * @param {boolean} shouldJump
    489      * @param {boolean=} jumpBackwards
    490      */
    491     performSearch: function(query, shouldJump, jumpBackwards)
    492     {
    493         this._searchableView.updateSearchMatchesCount(0);
    494 
    495         var sourceFrame = this.currentSourceFrame();
    496         if (!sourceFrame)
    497             return;
    498 
    499         this._searchView = sourceFrame;
    500         this._searchQuery = query;
    501 
    502         /**
    503          * @param {!WebInspector.View} view
    504          * @param {number} searchMatches
    505          * @this {WebInspector.SourcesView}
    506          */
    507         function finishedCallback(view, searchMatches)
    508         {
    509             if (!searchMatches)
    510                 return;
    511 
    512             this._searchableView.updateSearchMatchesCount(searchMatches);
    513         }
    514 
    515         /**
    516          * @param {number} currentMatchIndex
    517          * @this {WebInspector.SourcesView}
    518          */
    519         function currentMatchChanged(currentMatchIndex)
    520         {
    521             this._searchableView.updateCurrentMatchIndex(currentMatchIndex);
    522         }
    523 
    524         /**
    525          * @this {WebInspector.SourcesView}
    526          */
    527         function searchResultsChanged()
    528         {
    529             this._searchableView.cancelSearch();
    530         }
    531 
    532         this._searchView.performSearch(query, shouldJump, !!jumpBackwards, finishedCallback.bind(this), currentMatchChanged.bind(this), searchResultsChanged.bind(this));
    533     },
    534 
    535     jumpToNextSearchResult: function()
    536     {
    537         if (!this._searchView)
    538             return;
    539 
    540         if (this._searchView !== this.currentSourceFrame()) {
    541             this.performSearch(this._searchQuery, true);
    542             return;
    543         }
    544 
    545         this._searchView.jumpToNextSearchResult();
    546     },
    547 
    548     jumpToPreviousSearchResult: function()
    549     {
    550         if (!this._searchView)
    551             return;
    552 
    553         if (this._searchView !== this.currentSourceFrame()) {
    554             this.performSearch(this._searchQuery, true);
    555             if (this._searchView)
    556                 this._searchView.jumpToLastSearchResult();
    557             return;
    558         }
    559 
    560         this._searchView.jumpToPreviousSearchResult();
    561     },
    562 
    563     /**
    564      * @param {string} text
    565      */
    566     replaceSelectionWith: function(text)
    567     {
    568         var sourceFrame = this.currentSourceFrame();
    569         if (!sourceFrame) {
    570             console.assert(sourceFrame);
    571             return;
    572         }
    573         sourceFrame.replaceSelectionWith(text);
    574     },
    575 
    576     /**
    577      * @param {string} query
    578      * @param {string} text
    579      */
    580     replaceAllWith: function(query, text)
    581     {
    582         var sourceFrame = this.currentSourceFrame();
    583         if (!sourceFrame) {
    584             console.assert(sourceFrame);
    585             return;
    586         }
    587         sourceFrame.replaceAllWith(query, text);
    588     },
    589 
    590     /**
    591      * @param {?Event=} event
    592      * @return {boolean}
    593      */
    594     _showOutlineDialog: function(event)
    595     {
    596         var uiSourceCode = this._editorContainer.currentFile();
    597         if (!uiSourceCode)
    598             return false;
    599 
    600         switch (uiSourceCode.contentType()) {
    601         case WebInspector.resourceTypes.Document:
    602         case WebInspector.resourceTypes.Script:
    603             WebInspector.JavaScriptOutlineDialog.show(this, uiSourceCode, this.showSourceLocation.bind(this, uiSourceCode));
    604             return true;
    605         case WebInspector.resourceTypes.Stylesheet:
    606             WebInspector.StyleSheetOutlineDialog.show(this, uiSourceCode, this.showSourceLocation.bind(this, uiSourceCode));
    607             return true;
    608         }
    609         return false;
    610     },
    611 
    612     /**
    613      * @param {string=} query
    614      */
    615     showOpenResourceDialog: function(query)
    616     {
    617         var uiSourceCodes = this._editorContainer.historyUISourceCodes();
    618         /** @type {!Map.<!WebInspector.UISourceCode, number>} */
    619         var defaultScores = new Map();
    620         for (var i = 1; i < uiSourceCodes.length; ++i) // Skip current element
    621             defaultScores.put(uiSourceCodes[i], uiSourceCodes.length - i);
    622         WebInspector.OpenResourceDialog.show(this, this.element, query, defaultScores);
    623     },
    624 
    625     /**
    626      * @param {?Event=} event
    627      * @return {boolean}
    628      */
    629     _showGoToLineDialog: function(event)
    630     {
    631         if (this._currentUISourceCode)
    632             this.showOpenResourceDialog(":");
    633         return true;
    634     },
    635 
    636     /**
    637      * @return {boolean}
    638      */
    639     _save: function()
    640     {
    641         this._saveSourceFrame(this.currentSourceFrame());
    642         return true;
    643     },
    644 
    645     /**
    646      * @return {boolean}
    647      */
    648     _saveAll: function()
    649     {
    650         var sourceFrames = this._editorContainer.fileViews();
    651         sourceFrames.forEach(this._saveSourceFrame.bind(this));
    652         return true;
    653     },
    654 
    655     /**
    656      * @param {?WebInspector.SourceFrame} sourceFrame
    657      */
    658     _saveSourceFrame: function(sourceFrame)
    659     {
    660         if (!sourceFrame)
    661             return;
    662         if (!(sourceFrame instanceof WebInspector.UISourceCodeFrame))
    663             return;
    664         var uiSourceCodeFrame = /** @type {!WebInspector.UISourceCodeFrame} */ (sourceFrame);
    665         uiSourceCodeFrame.commitEditing();
    666     },
    667     /**
    668      * @return {boolean}
    669      */
    670     _toggleBreakpoint: function()
    671     {
    672         var sourceFrame = this.currentSourceFrame();
    673         if (!sourceFrame)
    674             return false;
    675 
    676         if (sourceFrame instanceof WebInspector.JavaScriptSourceFrame) {
    677             var javaScriptSourceFrame = /** @type {!WebInspector.JavaScriptSourceFrame} */ (sourceFrame);
    678             javaScriptSourceFrame.toggleBreakpointOnCurrentLine();
    679             return true;
    680         }
    681         return false;
    682     },
    683 
    684     /**
    685      * @param {boolean} active
    686      */
    687     toggleBreakpointsActiveState: function(active)
    688     {
    689         this._editorContainer.view.element.classList.toggle("breakpoints-deactivated", !active);
    690     },
    691 
    692     __proto__: WebInspector.VBox.prototype
    693 }
    694 
    695 /**
    696  * @interface
    697  */
    698 WebInspector.SourcesView.EditorAction = function()
    699 {
    700 }
    701 
    702 WebInspector.SourcesView.EditorAction.prototype = {
    703     /**
    704      * @param {!WebInspector.SourcesView} sourcesView
    705      * @return {!Element}
    706      */
    707     button: function(sourcesView) { }
    708 }
    709