• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
14WebInspector.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
88WebInspector.SourcesView.Events = {
89    EditorClosed: "EditorClosed",
90    EditorSelected: "EditorSelected",
91}
92
93WebInspector.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 */
698WebInspector.SourcesView.EditorAction = function()
699{
700}
701
702WebInspector.SourcesView.EditorAction.prototype = {
703    /**
704     * @param {!WebInspector.SourcesView} sourcesView
705     * @return {!Element}
706     */
707    button: function(sourcesView) { }
708}
709