Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / SourcesView.js
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.setMinimumSize(50, 25);
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.SourceFrame>} */
29     this._sourceFramesByUISourceCode = new Map();
30
31     var tabbedEditorPlaceholderText = WebInspector.isMac() ? WebInspector.UIString("Hit Cmd+O to open a file") : WebInspector.UIString("Hit Ctrl+O 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.ProjectWillReset, this._projectWillReset.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.panels.sources.showUISourceCode(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.ShortcutsScreen.SourcesPanelShortcuts.ToggleBreakpoint, this._toggleBreakpoint.bind(this));
116         registerShortcut.call(this, WebInspector.ShortcutsScreen.SourcesPanelShortcuts.Save, this._save.bind(this));
117     },
118
119     /**
120      * @param {!Array.<!WebInspector.KeyboardShortcut.Descriptor>} keys
121      * @param {function(?Event=):boolean} handler
122      */
123     _registerShortcuts: function(keys, handler)
124     {
125         for (var i = 0; i < keys.length; ++i)
126             this._shortcuts[keys[i].key] = handler;
127     },
128
129     _handleKeyDown: function(event)
130     {
131         var shortcutKey = WebInspector.KeyboardShortcut.makeKeyFromEvent(event);
132         var handler = this._shortcuts[shortcutKey];
133         if (handler && handler())
134             event.consume(true);
135     },
136
137     /**
138      * @return {!Element}
139      */
140     statusBarContainerElement: function()
141     {
142         return this._statusBarContainerElement;
143     },
144
145     /**
146      * @return {!Element}
147      */
148     defaultFocusedElement: function()
149     {
150         return this._editorContainer.view.defaultFocusedElement();
151     },
152
153     /**
154      * @return {!WebInspector.SearchableView}
155      */
156     searchableView: function()
157     {
158         return this._searchableView;
159     },
160
161     /**
162      * @return {!WebInspector.View}
163      */
164     visibleView: function()
165     {
166         return this._editorContainer.visibleView;
167     },
168
169     /**
170      * @return {?WebInspector.SourceFrame}
171      */
172     currentSourceFrame: function()
173     {
174         var view = this.visibleView();
175         if (!(view instanceof WebInspector.SourceFrame))
176             return null;
177         return /** @type {!WebInspector.SourceFrame} */ (view);
178     },
179
180     /**
181      * @return {?WebInspector.UISourceCode}
182      */
183     currentUISourceCode: function()
184     {
185         return this._currentUISourceCode;
186     },
187
188     /**
189      * @param {?Event=} event
190      */
191     _onCloseEditorTab: function(event)
192     {
193         var uiSourceCode = this.currentUISourceCode();
194         if (!uiSourceCode)
195             return false;
196         this._editorContainer.closeFile(uiSourceCode);
197         return true;
198     },
199
200     /**
201      * @param {?Event=} event
202      */
203     _onJumpToPreviousLocation: function(event)
204     {
205         this._historyManager.rollback();
206         return true;
207     },
208
209     /**
210      * @param {?Event=} event
211      */
212     _onJumpToNextLocation: function(event)
213     {
214         this._historyManager.rollover();
215         return true;
216     },
217
218     /**
219      * @param {!WebInspector.Event} event
220      */
221     _uiSourceCodeAdded: function(event)
222     {
223         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
224         this._addUISourceCode(uiSourceCode);
225     },
226
227     /**
228      * @param {!WebInspector.UISourceCode} uiSourceCode
229      */
230     _addUISourceCode: function(uiSourceCode)
231     {
232         if (uiSourceCode.project().isServiceProject())
233             return;
234         this._editorContainer.addUISourceCode(uiSourceCode);
235         // Replace debugger script-based uiSourceCode with a network-based one.
236         var currentUISourceCode = this._currentUISourceCode;
237         if (currentUISourceCode && currentUISourceCode.project().isServiceProject() && currentUISourceCode !== uiSourceCode && currentUISourceCode.url === uiSourceCode.url) {
238             this._showFile(uiSourceCode);
239             this._editorContainer.removeUISourceCode(currentUISourceCode);
240         }
241     },
242
243     _uiSourceCodeRemoved: function(event)
244     {
245         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
246         this._removeUISourceCodes([uiSourceCode]);
247     },
248
249     /**
250      * @param {!Array.<!WebInspector.UISourceCode>} uiSourceCodes
251      */
252     _removeUISourceCodes: function(uiSourceCodes)
253     {
254         for (var i = 0; i < uiSourceCodes.length; ++i) {
255             this._removeSourceFrame(uiSourceCodes[i]);
256             this._historyManager.removeHistoryForSourceCode(uiSourceCodes[i]);
257         }
258         this._editorContainer.removeUISourceCodes(uiSourceCodes);
259     },
260
261     _projectWillReset: function(event)
262     {
263         var project = event.data;
264         var uiSourceCodes = project.uiSourceCodes();
265         this._removeUISourceCodes(uiSourceCodes);
266         if (project.type() === WebInspector.projectTypes.Network)
267             this._editorContainer.reset();
268     },
269
270     _updateScriptViewStatusBarItems: function()
271     {
272         this._scriptViewStatusBarItemsContainer.removeChildren();
273         this._scriptViewStatusBarTextContainer.removeChildren();
274         var sourceFrame = this.currentSourceFrame();
275         if (!sourceFrame)
276             return;
277
278         var statusBarItems = sourceFrame.statusBarItems() || [];
279         for (var i = 0; i < statusBarItems.length; ++i)
280             this._scriptViewStatusBarItemsContainer.appendChild(statusBarItems[i]);
281         var statusBarText = sourceFrame.statusBarText();
282         if (statusBarText)
283             this._scriptViewStatusBarTextContainer.appendChild(statusBarText);
284     },
285
286     /**
287      * @param {!WebInspector.UISourceCode} uiSourceCode
288      * @param {number=} lineNumber
289      * @param {number=} columnNumber
290      * @param {boolean=} omitFocus
291      * @param {boolean=} omitHighlight
292      */
293     showSourceLocation: function(uiSourceCode, lineNumber, columnNumber, omitFocus, omitHighlight)
294     {
295         this._historyManager.updateCurrentState();
296         var sourceFrame = this._showFile(uiSourceCode);
297         if (typeof lineNumber === "number")
298             sourceFrame.revealPosition(lineNumber, columnNumber, !omitHighlight);
299         this._historyManager.pushNewState();
300         if (!omitFocus)
301             sourceFrame.focus();
302         WebInspector.notifications.dispatchEventToListeners(WebInspector.UserMetrics.UserAction, {
303             action: WebInspector.UserMetrics.UserActionNames.OpenSourceLink,
304             url: uiSourceCode.originURL(),
305             lineNumber: lineNumber
306         });
307     },
308
309     /**
310      * @param {!WebInspector.UISourceCode} uiSourceCode
311      * @return {!WebInspector.SourceFrame}
312      */
313     _showFile: function(uiSourceCode)
314     {
315         var sourceFrame = this._getOrCreateSourceFrame(uiSourceCode);
316         if (this._currentUISourceCode === uiSourceCode)
317             return sourceFrame;
318
319         this._currentUISourceCode = uiSourceCode;
320         this._editorContainer.showFile(uiSourceCode);
321         this._updateScriptViewStatusBarItems();
322         return sourceFrame;
323     },
324
325     /**
326      * @param {!WebInspector.UISourceCode} uiSourceCode
327      * @return {!WebInspector.SourceFrame}
328      */
329     _createSourceFrame: function(uiSourceCode)
330     {
331         var sourceFrame;
332         switch (uiSourceCode.contentType()) {
333         case WebInspector.resourceTypes.Script:
334             sourceFrame = new WebInspector.JavaScriptSourceFrame(this._sourcesPanel, uiSourceCode);
335             break;
336         case WebInspector.resourceTypes.Document:
337             sourceFrame = new WebInspector.JavaScriptSourceFrame(this._sourcesPanel, uiSourceCode);
338             break;
339         case WebInspector.resourceTypes.Stylesheet:
340             sourceFrame = new WebInspector.CSSSourceFrame(uiSourceCode);
341             break;
342         default:
343             sourceFrame = new WebInspector.UISourceCodeFrame(uiSourceCode);
344         break;
345         }
346         sourceFrame.setHighlighterType(uiSourceCode.highlighterType());
347         this._sourceFramesByUISourceCode.put(uiSourceCode, sourceFrame);
348         this._historyManager.trackSourceFrameCursorJumps(sourceFrame);
349         return sourceFrame;
350     },
351
352     /**
353      * @param {!WebInspector.UISourceCode} uiSourceCode
354      * @return {!WebInspector.SourceFrame}
355      */
356     _getOrCreateSourceFrame: function(uiSourceCode)
357     {
358         return this._sourceFramesByUISourceCode.get(uiSourceCode) || this._createSourceFrame(uiSourceCode);
359     },
360
361     /**
362      * @param {!WebInspector.SourceFrame} sourceFrame
363      * @param {!WebInspector.UISourceCode} uiSourceCode
364      * @return {boolean}
365      */
366     _sourceFrameMatchesUISourceCode: function(sourceFrame, uiSourceCode)
367     {
368         switch (uiSourceCode.contentType()) {
369         case WebInspector.resourceTypes.Script:
370         case WebInspector.resourceTypes.Document:
371             return sourceFrame instanceof WebInspector.JavaScriptSourceFrame;
372         case WebInspector.resourceTypes.Stylesheet:
373             return sourceFrame instanceof WebInspector.CSSSourceFrame;
374         default:
375             return !(sourceFrame instanceof WebInspector.JavaScriptSourceFrame);
376         }
377     },
378
379     /**
380      * @param {!WebInspector.UISourceCode} uiSourceCode
381      */
382     _recreateSourceFrameIfNeeded: function(uiSourceCode)
383     {
384         var oldSourceFrame = this._sourceFramesByUISourceCode.get(uiSourceCode);
385         if (!oldSourceFrame)
386             return;
387         if (this._sourceFrameMatchesUISourceCode(oldSourceFrame, uiSourceCode)) {
388             oldSourceFrame.setHighlighterType(uiSourceCode.highlighterType());
389         } else {
390             this._editorContainer.removeUISourceCode(uiSourceCode);
391             this._removeSourceFrame(uiSourceCode);
392         }
393     },
394
395     /**
396      * @param {!WebInspector.UISourceCode} uiSourceCode
397      * @return {!WebInspector.SourceFrame}
398      */
399     viewForFile: function(uiSourceCode)
400     {
401         return this._getOrCreateSourceFrame(uiSourceCode);
402     },
403
404     /**
405      * @param {!WebInspector.UISourceCode} uiSourceCode
406      */
407     _removeSourceFrame: function(uiSourceCode)
408     {
409         var sourceFrame = this._sourceFramesByUISourceCode.get(uiSourceCode);
410         if (!sourceFrame)
411             return;
412         this._sourceFramesByUISourceCode.remove(uiSourceCode);
413         sourceFrame.dispose();
414     },
415
416     clearCurrentExecutionLine: function()
417     {
418         if (this._executionSourceFrame)
419             this._executionSourceFrame.clearExecutionLine();
420         delete this._executionSourceFrame;
421     },
422
423     setExecutionLine: function(uiLocation)
424     {
425         var sourceFrame = this._getOrCreateSourceFrame(uiLocation.uiSourceCode);
426         sourceFrame.setExecutionLine(uiLocation.lineNumber);
427         this._executionSourceFrame = sourceFrame;
428     },
429
430     _editorClosed: function(event)
431     {
432         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
433         this._historyManager.removeHistoryForSourceCode(uiSourceCode);
434
435         var wasSelected = false;
436         if (this._currentUISourceCode === uiSourceCode) {
437             delete this._currentUISourceCode;
438             wasSelected = true;
439         }
440
441         // SourcesNavigator does not need to update on EditorClosed.
442         this._updateScriptViewStatusBarItems();
443         this._searchableView.resetSearch();
444
445         var data = {};
446         data.uiSourceCode = uiSourceCode;
447         data.wasSelected = wasSelected;
448         this.dispatchEventToListeners(WebInspector.SourcesView.Events.EditorClosed, data);
449     },
450
451     _editorSelected: function(event)
452     {
453         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data.currentFile);
454         var shouldUseHistoryManager = uiSourceCode !== this._currentUISourceCode && event.data.userGesture;
455         if (shouldUseHistoryManager)
456             this._historyManager.updateCurrentState();
457         var sourceFrame = this._showFile(uiSourceCode);
458         if (shouldUseHistoryManager)
459             this._historyManager.pushNewState();
460
461         this._searchableView.setReplaceable(!!sourceFrame && sourceFrame.canEditSource());
462         this._searchableView.resetSearch();
463
464         this.dispatchEventToListeners(WebInspector.SourcesView.Events.EditorSelected, uiSourceCode);
465     },
466
467     /**
468      * @param {!WebInspector.UISourceCode} uiSourceCode
469      */
470     sourceRenamed: function(uiSourceCode)
471     {
472         this._recreateSourceFrameIfNeeded(uiSourceCode);
473     },
474
475     searchCanceled: function()
476     {
477         if (this._searchView)
478             this._searchView.searchCanceled();
479
480         delete this._searchView;
481         delete this._searchQuery;
482     },
483
484     /**
485      * @param {string} query
486      * @param {boolean} shouldJump
487      */
488     performSearch: function(query, shouldJump)
489     {
490         this._searchableView.updateSearchMatchesCount(0);
491
492         var sourceFrame = this.currentSourceFrame();
493         if (!sourceFrame)
494             return;
495
496         this._searchView = sourceFrame;
497         this._searchQuery = query;
498
499         /**
500          * @param {!WebInspector.View} view
501          * @param {number} searchMatches
502          * @this {WebInspector.SourcesView}
503          */
504         function finishedCallback(view, searchMatches)
505         {
506             if (!searchMatches)
507                 return;
508
509             this._searchableView.updateSearchMatchesCount(searchMatches);
510         }
511
512         /**
513          * @param {number} currentMatchIndex
514          * @this {WebInspector.SourcesView}
515          */
516         function currentMatchChanged(currentMatchIndex)
517         {
518             this._searchableView.updateCurrentMatchIndex(currentMatchIndex);
519         }
520
521         /**
522          * @this {WebInspector.SourcesView}
523          */
524         function searchResultsChanged()
525         {
526             this._searchableView.cancelSearch();
527         }
528
529         this._searchView.performSearch(query, shouldJump, finishedCallback.bind(this), currentMatchChanged.bind(this), searchResultsChanged.bind(this));
530     },
531
532     jumpToNextSearchResult: function()
533     {
534         if (!this._searchView)
535             return;
536
537         if (this._searchView !== this.currentSourceFrame()) {
538             this.performSearch(this._searchQuery, true);
539             return;
540         }
541
542         this._searchView.jumpToNextSearchResult();
543     },
544
545     jumpToPreviousSearchResult: function()
546     {
547         if (!this._searchView)
548             return;
549
550         if (this._searchView !== this.currentSourceFrame()) {
551             this.performSearch(this._searchQuery, true);
552             if (this._searchView)
553                 this._searchView.jumpToLastSearchResult();
554             return;
555         }
556
557         this._searchView.jumpToPreviousSearchResult();
558     },
559
560     /**
561      * @param {string} text
562      */
563     replaceSelectionWith: function(text)
564     {
565         var sourceFrame = this.currentSourceFrame();
566         if (!sourceFrame) {
567             console.assert(sourceFrame);
568             return;
569         }
570         sourceFrame.replaceSelectionWith(text);
571     },
572
573     /**
574      * @param {string} query
575      * @param {string} text
576      */
577     replaceAllWith: function(query, text)
578     {
579         var sourceFrame = this.currentSourceFrame();
580         if (!sourceFrame) {
581             console.assert(sourceFrame);
582             return;
583         }
584         sourceFrame.replaceAllWith(query, text);
585     },
586
587     /**
588      * @param {?Event=} event
589      * @return {boolean}
590      */
591     _showOutlineDialog: function(event)
592     {
593         var uiSourceCode = this._editorContainer.currentFile();
594         if (!uiSourceCode)
595             return false;
596
597         switch (uiSourceCode.contentType()) {
598         case WebInspector.resourceTypes.Document:
599         case WebInspector.resourceTypes.Script:
600             WebInspector.JavaScriptOutlineDialog.show(this, uiSourceCode, this.showSourceLocation.bind(this, uiSourceCode));
601             return true;
602         case WebInspector.resourceTypes.Stylesheet:
603             WebInspector.StyleSheetOutlineDialog.show(this, uiSourceCode, this.showSourceLocation.bind(this, uiSourceCode));
604             return true;
605         }
606         return false;
607     },
608
609     /**
610      * @param {string=} query
611      */
612     showOpenResourceDialog: function(query)
613     {
614         var uiSourceCodes = this._editorContainer.historyUISourceCodes();
615         /** @type {!Map.<!WebInspector.UISourceCode, number>} */
616         var defaultScores = new Map();
617         for (var i = 1; i < uiSourceCodes.length; ++i) // Skip current element
618             defaultScores.put(uiSourceCodes[i], uiSourceCodes.length - i);
619         WebInspector.OpenResourceDialog.show(this, this.element, query, defaultScores);
620     },
621
622     /**
623      * @param {?Event=} event
624      * @return {boolean}
625      */
626     _showGoToLineDialog: function(event)
627     {
628         if (this._currentUISourceCode)
629             this.showOpenResourceDialog(":");
630         return true;
631     },
632
633     /**
634      * @return {boolean}
635      */
636     _save: function()
637     {
638         var sourceFrame = this.currentSourceFrame();
639         if (!sourceFrame)
640             return true;
641         if (!(sourceFrame instanceof WebInspector.UISourceCodeFrame))
642             return true;
643         var uiSourceCodeFrame = /** @type {!WebInspector.UISourceCodeFrame} */ (sourceFrame);
644         uiSourceCodeFrame.commitEditing();
645         return true;
646     },
647
648     /**
649      * @return {boolean}
650      */
651     _toggleBreakpoint: function()
652     {
653         var sourceFrame = this.currentSourceFrame();
654         if (!sourceFrame)
655             return false;
656
657         if (sourceFrame instanceof WebInspector.JavaScriptSourceFrame) {
658             var javaScriptSourceFrame = /** @type {!WebInspector.JavaScriptSourceFrame} */ (sourceFrame);
659             javaScriptSourceFrame.toggleBreakpointOnCurrentLine();
660             return true;
661         }
662         return false;
663     },
664
665     /**
666      * @param {boolean} active
667      */
668     toggleBreakpointsActiveState: function(active)
669     {
670         this._editorContainer.view.element.classList.toggle("breakpoints-deactivated", !active);
671     },
672
673     __proto__: WebInspector.VBox.prototype
674 }
675
676 /**
677  * @interface
678  */
679 WebInspector.SourcesView.EditorAction = function()
680 {
681 }
682
683 WebInspector.SourcesView.EditorAction.prototype = {
684     /**
685      * @param {!WebInspector.SourcesView} sourcesView
686      * @return {!Element}
687      */
688     button: function(sourcesView) { }
689 }