| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| /** |
| * @implements {Sources.TabbedEditorContainerDelegate} |
| * @implements {UI.Searchable} |
| * @implements {UI.Replaceable} |
| * @unrestricted |
| */ |
| Sources.SourcesView = class extends UI.VBox { |
| /** |
| * @suppressGlobalPropertiesCheck |
| */ |
| constructor() { |
| super(); |
| this.registerRequiredCSS('sources/sourcesView.css'); |
| this.element.id = 'sources-panel-sources-view'; |
| this.setMinimumAndPreferredSizes(50, 52, 150, 100); |
| |
| var workspace = Workspace.workspace; |
| |
| this._searchableView = new UI.SearchableView(this, 'sourcesViewSearchConfig'); |
| this._searchableView.setMinimalSearchQuerySize(0); |
| this._searchableView.show(this.element); |
| |
| /** @type {!Map.<!Workspace.UISourceCode, !UI.Widget>} */ |
| this._sourceViewByUISourceCode = new Map(); |
| |
| var tabbedEditorPlaceholderText = |
| Host.isMac() ? Common.UIString('Hit \u2318+P to open a file') : Common.UIString('Hit Ctrl+P to open a file'); |
| this._editorContainer = new Sources.TabbedEditorContainer( |
| this, Common.settings.createLocalSetting('previouslyViewedFiles', []), tabbedEditorPlaceholderText); |
| this._editorContainer.show(this._searchableView.element); |
| this._editorContainer.addEventListener( |
| Sources.TabbedEditorContainer.Events.EditorSelected, this._editorSelected, this); |
| this._editorContainer.addEventListener(Sources.TabbedEditorContainer.Events.EditorClosed, this._editorClosed, this); |
| |
| this._historyManager = new Sources.EditingLocationHistoryManager(this, this.currentSourceFrame.bind(this)); |
| |
| this._toolbarContainerElement = this.element.createChild('div', 'sources-toolbar'); |
| this._toolbarEditorActions = new UI.Toolbar('', this._toolbarContainerElement); |
| |
| self.runtime.allInstances(Sources.SourcesView.EditorAction).then(appendButtonsForExtensions.bind(this)); |
| /** |
| * @param {!Array.<!Sources.SourcesView.EditorAction>} actions |
| * @this {Sources.SourcesView} |
| */ |
| function appendButtonsForExtensions(actions) { |
| for (var i = 0; i < actions.length; ++i) |
| this._toolbarEditorActions.appendToolbarItem(actions[i].button(this)); |
| } |
| this._scriptViewToolbar = new UI.Toolbar('', this._toolbarContainerElement); |
| this._scriptViewToolbar.element.style.flex = 'auto'; |
| this._bottomToolbar = new UI.Toolbar('', this._toolbarContainerElement); |
| |
| UI.startBatchUpdate(); |
| workspace.uiSourceCodes().forEach(this._addUISourceCode.bind(this)); |
| UI.endBatchUpdate(); |
| |
| workspace.addEventListener(Workspace.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this); |
| workspace.addEventListener(Workspace.Workspace.Events.UISourceCodeRemoved, this._uiSourceCodeRemoved, this); |
| workspace.addEventListener(Workspace.Workspace.Events.ProjectRemoved, this._projectRemoved.bind(this), this); |
| |
| /** |
| * @param {!Event} event |
| */ |
| function handleBeforeUnload(event) { |
| if (event.returnValue) |
| return; |
| |
| var unsavedSourceCodes = []; |
| var projects = Workspace.workspace.projectsForType(Workspace.projectTypes.FileSystem); |
| for (var i = 0; i < projects.length; ++i) |
| unsavedSourceCodes = unsavedSourceCodes.concat(projects[i].uiSourceCodes().filter(isUnsaved)); |
| |
| if (!unsavedSourceCodes.length) |
| return; |
| |
| event.returnValue = Common.UIString('DevTools have unsaved changes that will be permanently lost.'); |
| UI.viewManager.showView('sources'); |
| for (var i = 0; i < unsavedSourceCodes.length; ++i) |
| Common.Revealer.reveal(unsavedSourceCodes[i]); |
| |
| /** |
| * @param {!Workspace.UISourceCode} sourceCode |
| * @return {boolean} |
| */ |
| function isUnsaved(sourceCode) { |
| var binding = Persistence.persistence.binding(sourceCode); |
| if (binding) |
| return binding.network.isDirty(); |
| return sourceCode.isDirty(); |
| } |
| } |
| |
| if (!window.opener) |
| window.addEventListener('beforeunload', handleBeforeUnload, true); |
| |
| this._shortcuts = {}; |
| this.element.addEventListener('keydown', this._handleKeyDown.bind(this), false); |
| } |
| |
| /** |
| * @param {function(!Array.<!UI.KeyboardShortcut.Descriptor>, function(!Event=):boolean)} registerShortcutDelegate |
| */ |
| registerShortcuts(registerShortcutDelegate) { |
| /** |
| * @this {Sources.SourcesView} |
| * @param {!Array.<!UI.KeyboardShortcut.Descriptor>} shortcuts |
| * @param {function(!Event=):boolean} handler |
| */ |
| function registerShortcut(shortcuts, handler) { |
| registerShortcutDelegate(shortcuts, handler); |
| this._registerShortcuts(shortcuts, handler); |
| } |
| |
| registerShortcut.call( |
| this, Components.ShortcutsScreen.SourcesPanelShortcuts.JumpToPreviousLocation, |
| this._onJumpToPreviousLocation.bind(this)); |
| registerShortcut.call( |
| this, Components.ShortcutsScreen.SourcesPanelShortcuts.JumpToNextLocation, |
| this._onJumpToNextLocation.bind(this)); |
| registerShortcut.call( |
| this, Components.ShortcutsScreen.SourcesPanelShortcuts.CloseEditorTab, this._onCloseEditorTab.bind(this)); |
| registerShortcut.call( |
| this, Components.ShortcutsScreen.SourcesPanelShortcuts.GoToLine, this._showGoToLineDialog.bind(this)); |
| registerShortcut.call( |
| this, Components.ShortcutsScreen.SourcesPanelShortcuts.GoToMember, this._showOutlineDialog.bind(this)); |
| registerShortcut.call( |
| this, Components.ShortcutsScreen.SourcesPanelShortcuts.ToggleBreakpoint, this._toggleBreakpoint.bind(this)); |
| registerShortcut.call(this, Components.ShortcutsScreen.SourcesPanelShortcuts.Save, this._save.bind(this)); |
| registerShortcut.call(this, Components.ShortcutsScreen.SourcesPanelShortcuts.SaveAll, this._saveAll.bind(this)); |
| } |
| |
| /** |
| * @return {!UI.Toolbar} |
| */ |
| leftToolbar() { |
| return this._editorContainer.leftToolbar(); |
| } |
| |
| /** |
| * @return {!UI.Toolbar} |
| */ |
| rightToolbar() { |
| return this._editorContainer.rightToolbar(); |
| } |
| |
| /** |
| * @return {!UI.Toolbar} |
| */ |
| bottomToolbar() { |
| return this._bottomToolbar; |
| } |
| |
| /** |
| * @param {!Array.<!UI.KeyboardShortcut.Descriptor>} keys |
| * @param {function(!Event=):boolean} handler |
| */ |
| _registerShortcuts(keys, handler) { |
| for (var i = 0; i < keys.length; ++i) |
| this._shortcuts[keys[i].key] = handler; |
| } |
| |
| _handleKeyDown(event) { |
| var shortcutKey = UI.KeyboardShortcut.makeKeyFromEvent(event); |
| var handler = this._shortcuts[shortcutKey]; |
| if (handler && handler()) |
| event.consume(true); |
| } |
| |
| /** |
| * @override |
| */ |
| wasShown() { |
| super.wasShown(); |
| UI.context.setFlavor(Sources.SourcesView, this); |
| } |
| |
| /** |
| * @override |
| */ |
| willHide() { |
| UI.context.setFlavor(Sources.SourcesView, null); |
| super.willHide(); |
| } |
| |
| /** |
| * @return {!Element} |
| */ |
| toolbarContainerElement() { |
| return this._toolbarContainerElement; |
| } |
| |
| /** |
| * @return {!UI.SearchableView} |
| */ |
| searchableView() { |
| return this._searchableView; |
| } |
| |
| /** |
| * @return {?UI.Widget} |
| */ |
| visibleView() { |
| return this._editorContainer.visibleView; |
| } |
| |
| /** |
| * @return {?Sources.UISourceCodeFrame} |
| */ |
| currentSourceFrame() { |
| var view = this.visibleView(); |
| if (!(view instanceof Sources.UISourceCodeFrame)) |
| return null; |
| return /** @type {!Sources.UISourceCodeFrame} */ (view); |
| } |
| |
| /** |
| * @return {?Workspace.UISourceCode} |
| */ |
| currentUISourceCode() { |
| return this._editorContainer.currentFile(); |
| } |
| |
| /** |
| * @param {!Event=} event |
| */ |
| _onCloseEditorTab(event) { |
| var uiSourceCode = this._editorContainer.currentFile(); |
| if (!uiSourceCode) |
| return false; |
| this._editorContainer.closeFile(uiSourceCode); |
| return true; |
| } |
| |
| /** |
| * @param {!Event=} event |
| */ |
| _onJumpToPreviousLocation(event) { |
| this._historyManager.rollback(); |
| return true; |
| } |
| |
| /** |
| * @param {!Event=} event |
| */ |
| _onJumpToNextLocation(event) { |
| this._historyManager.rollover(); |
| return true; |
| } |
| |
| /** |
| * @param {!Common.Event} event |
| */ |
| _uiSourceCodeAdded(event) { |
| var uiSourceCode = /** @type {!Workspace.UISourceCode} */ (event.data); |
| this._addUISourceCode(uiSourceCode); |
| } |
| |
| /** |
| * @param {!Workspace.UISourceCode} uiSourceCode |
| */ |
| _addUISourceCode(uiSourceCode) { |
| if (uiSourceCode.isFromServiceProject()) |
| return; |
| this._editorContainer.addUISourceCode(uiSourceCode); |
| } |
| |
| _uiSourceCodeRemoved(event) { |
| var uiSourceCode = /** @type {!Workspace.UISourceCode} */ (event.data); |
| this._removeUISourceCodes([uiSourceCode]); |
| } |
| |
| /** |
| * @param {!Array.<!Workspace.UISourceCode>} uiSourceCodes |
| */ |
| _removeUISourceCodes(uiSourceCodes) { |
| this._editorContainer.removeUISourceCodes(uiSourceCodes); |
| for (var i = 0; i < uiSourceCodes.length; ++i) { |
| this._removeSourceFrame(uiSourceCodes[i]); |
| this._historyManager.removeHistoryForSourceCode(uiSourceCodes[i]); |
| } |
| } |
| |
| _projectRemoved(event) { |
| var project = event.data; |
| var uiSourceCodes = project.uiSourceCodes(); |
| this._removeUISourceCodes(uiSourceCodes); |
| } |
| |
| _updateScriptViewToolbarItems() { |
| this._scriptViewToolbar.removeToolbarItems(); |
| var view = this.visibleView(); |
| if (view instanceof UI.SimpleView) { |
| for (var item of (/** @type {?UI.SimpleView} */ (view)).syncToolbarItems()) |
| this._scriptViewToolbar.appendToolbarItem(item); |
| } |
| } |
| |
| /** |
| * @param {!Workspace.UISourceCode} uiSourceCode |
| * @param {number=} lineNumber 0-based |
| * @param {number=} columnNumber |
| * @param {boolean=} omitFocus |
| * @param {boolean=} omitHighlight |
| */ |
| showSourceLocation(uiSourceCode, lineNumber, columnNumber, omitFocus, omitHighlight) { |
| this._historyManager.updateCurrentState(); |
| this._editorContainer.showFile(uiSourceCode); |
| var currentSourceFrame = this.currentSourceFrame(); |
| if (currentSourceFrame && typeof lineNumber === 'number') |
| currentSourceFrame.revealPosition(lineNumber, columnNumber, !omitHighlight); |
| this._historyManager.pushNewState(); |
| if (!omitFocus) |
| this.visibleView().focus(); |
| } |
| |
| /** |
| * @param {!Workspace.UISourceCode} uiSourceCode |
| * @return {!UI.Widget} |
| */ |
| _createSourceView(uiSourceCode) { |
| var sourceFrame; |
| var sourceView; |
| var contentType = uiSourceCode.contentType(); |
| |
| if (contentType.hasScripts()) |
| sourceFrame = new Sources.JavaScriptSourceFrame(uiSourceCode); |
| else if (contentType.isStyleSheet()) |
| sourceFrame = new Sources.CSSSourceFrame(uiSourceCode); |
| else if (contentType === Common.resourceTypes.Image) |
| sourceView = new SourceFrame.ImageView(Bindings.NetworkProject.uiSourceCodeMimeType(uiSourceCode), uiSourceCode); |
| else if (contentType === Common.resourceTypes.Font) |
| sourceView = new SourceFrame.FontView(Bindings.NetworkProject.uiSourceCodeMimeType(uiSourceCode), uiSourceCode); |
| else |
| sourceFrame = new Sources.UISourceCodeFrame(uiSourceCode); |
| |
| if (sourceFrame) { |
| sourceFrame.setHighlighterType(Bindings.NetworkProject.uiSourceCodeMimeType(uiSourceCode)); |
| this._historyManager.trackSourceFrameCursorJumps(sourceFrame); |
| } |
| var widget = /** @type {!UI.Widget} */ (sourceFrame || sourceView); |
| this._sourceViewByUISourceCode.set(uiSourceCode, widget); |
| uiSourceCode.addEventListener(Workspace.UISourceCode.Events.TitleChanged, this._uiSourceCodeTitleChanged, this); |
| return widget; |
| } |
| |
| /** |
| * @param {!Workspace.UISourceCode} uiSourceCode |
| * @return {!UI.Widget} |
| */ |
| _getOrCreateSourceView(uiSourceCode) { |
| return this._sourceViewByUISourceCode.get(uiSourceCode) || this._createSourceView(uiSourceCode); |
| } |
| |
| /** |
| * @param {!Sources.UISourceCodeFrame} sourceFrame |
| * @param {!Workspace.UISourceCode} uiSourceCode |
| * @return {boolean} |
| */ |
| _sourceFrameMatchesUISourceCode(sourceFrame, uiSourceCode) { |
| if (uiSourceCode.contentType().hasScripts()) |
| return sourceFrame instanceof Sources.JavaScriptSourceFrame; |
| if (uiSourceCode.contentType().isStyleSheet()) |
| return sourceFrame instanceof Sources.CSSSourceFrame; |
| return !(sourceFrame instanceof Sources.JavaScriptSourceFrame); |
| } |
| |
| /** |
| * @param {!Workspace.UISourceCode} uiSourceCode |
| */ |
| _recreateSourceFrameIfNeeded(uiSourceCode) { |
| var oldSourceView = this._sourceViewByUISourceCode.get(uiSourceCode); |
| if (!oldSourceView || !(oldSourceView instanceof Sources.UISourceCodeFrame)) |
| return; |
| var oldSourceFrame = /** @type {!Sources.UISourceCodeFrame} */ (oldSourceView); |
| if (this._sourceFrameMatchesUISourceCode(oldSourceFrame, uiSourceCode)) { |
| oldSourceFrame.setHighlighterType(Bindings.NetworkProject.uiSourceCodeMimeType(uiSourceCode)); |
| } else { |
| this._editorContainer.removeUISourceCode(uiSourceCode); |
| this._removeSourceFrame(uiSourceCode); |
| } |
| } |
| |
| /** |
| * @override |
| * @param {!Workspace.UISourceCode} uiSourceCode |
| * @return {!UI.Widget} |
| */ |
| viewForFile(uiSourceCode) { |
| return this._getOrCreateSourceView(uiSourceCode); |
| } |
| |
| /** |
| * @param {!Workspace.UISourceCode} uiSourceCode |
| */ |
| _removeSourceFrame(uiSourceCode) { |
| var sourceView = this._sourceViewByUISourceCode.get(uiSourceCode); |
| this._sourceViewByUISourceCode.remove(uiSourceCode); |
| uiSourceCode.removeEventListener(Workspace.UISourceCode.Events.TitleChanged, this._uiSourceCodeTitleChanged, this); |
| if (sourceView && sourceView instanceof Sources.UISourceCodeFrame) |
| /** @type {!Sources.UISourceCodeFrame} */ (sourceView).dispose(); |
| } |
| |
| clearCurrentExecutionLine() { |
| if (this._executionSourceFrame) |
| this._executionSourceFrame.clearExecutionLine(); |
| delete this._executionSourceFrame; |
| } |
| |
| /** |
| * @param {!Workspace.UILocation} uiLocation |
| */ |
| setExecutionLocation(uiLocation) { |
| var sourceView = this._getOrCreateSourceView(uiLocation.uiSourceCode); |
| if (sourceView instanceof Sources.UISourceCodeFrame) { |
| var sourceFrame = /** @type {!Sources.UISourceCodeFrame} */ (sourceView); |
| sourceFrame.setExecutionLocation(uiLocation); |
| this._executionSourceFrame = sourceFrame; |
| } |
| } |
| |
| /** |
| * @param {!Common.Event} event |
| */ |
| _editorClosed(event) { |
| var uiSourceCode = /** @type {!Workspace.UISourceCode} */ (event.data); |
| this._historyManager.removeHistoryForSourceCode(uiSourceCode); |
| |
| var wasSelected = false; |
| if (!this._editorContainer.currentFile()) |
| wasSelected = true; |
| |
| // SourcesNavigator does not need to update on EditorClosed. |
| this._updateScriptViewToolbarItems(); |
| this._searchableView.resetSearch(); |
| |
| var data = {}; |
| data.uiSourceCode = uiSourceCode; |
| data.wasSelected = wasSelected; |
| this.dispatchEventToListeners(Sources.SourcesView.Events.EditorClosed, data); |
| } |
| |
| /** |
| * @param {!Common.Event} event |
| */ |
| _editorSelected(event) { |
| var previousSourceFrame = |
| event.data.previousView instanceof Sources.UISourceCodeFrame ? event.data.previousView : null; |
| if (previousSourceFrame) |
| previousSourceFrame.setSearchableView(null); |
| var currentSourceFrame = |
| event.data.currentView instanceof Sources.UISourceCodeFrame ? event.data.currentView : null; |
| if (currentSourceFrame) |
| currentSourceFrame.setSearchableView(this._searchableView); |
| |
| this._searchableView.setReplaceable(!!currentSourceFrame && currentSourceFrame.canEditSource()); |
| this._searchableView.refreshSearch(); |
| this._updateScriptViewToolbarItems(); |
| |
| this.dispatchEventToListeners(Sources.SourcesView.Events.EditorSelected, this._editorContainer.currentFile()); |
| } |
| |
| /** |
| * @param {!Common.Event} event |
| */ |
| _uiSourceCodeTitleChanged(event) { |
| this._recreateSourceFrameIfNeeded(/** @type {!Workspace.UISourceCode} */ (event.target)); |
| } |
| |
| /** |
| * @override |
| */ |
| searchCanceled() { |
| if (this._searchView) |
| this._searchView.searchCanceled(); |
| |
| delete this._searchView; |
| delete this._searchConfig; |
| } |
| |
| /** |
| * @override |
| * @param {!UI.SearchableView.SearchConfig} searchConfig |
| * @param {boolean} shouldJump |
| * @param {boolean=} jumpBackwards |
| */ |
| performSearch(searchConfig, shouldJump, jumpBackwards) { |
| var sourceFrame = this.currentSourceFrame(); |
| if (!sourceFrame) |
| return; |
| |
| this._searchView = sourceFrame; |
| this._searchConfig = searchConfig; |
| |
| this._searchView.performSearch(this._searchConfig, shouldJump, jumpBackwards); |
| } |
| |
| /** |
| * @override |
| */ |
| jumpToNextSearchResult() { |
| if (!this._searchView) |
| return; |
| |
| if (this._searchView !== this.currentSourceFrame()) { |
| this.performSearch(this._searchConfig, true); |
| return; |
| } |
| |
| this._searchView.jumpToNextSearchResult(); |
| } |
| |
| /** |
| * @override |
| */ |
| jumpToPreviousSearchResult() { |
| if (!this._searchView) |
| return; |
| |
| if (this._searchView !== this.currentSourceFrame()) { |
| this.performSearch(this._searchConfig, true); |
| if (this._searchView) |
| this._searchView.jumpToLastSearchResult(); |
| return; |
| } |
| |
| this._searchView.jumpToPreviousSearchResult(); |
| } |
| |
| /** |
| * @override |
| * @return {boolean} |
| */ |
| supportsCaseSensitiveSearch() { |
| return true; |
| } |
| |
| /** |
| * @override |
| * @return {boolean} |
| */ |
| supportsRegexSearch() { |
| return true; |
| } |
| |
| /** |
| * @override |
| * @param {!UI.SearchableView.SearchConfig} searchConfig |
| * @param {string} replacement |
| */ |
| replaceSelectionWith(searchConfig, replacement) { |
| var sourceFrame = this.currentSourceFrame(); |
| if (!sourceFrame) { |
| console.assert(sourceFrame); |
| return; |
| } |
| sourceFrame.replaceSelectionWith(searchConfig, replacement); |
| } |
| |
| /** |
| * @override |
| * @param {!UI.SearchableView.SearchConfig} searchConfig |
| * @param {string} replacement |
| */ |
| replaceAllWith(searchConfig, replacement) { |
| var sourceFrame = this.currentSourceFrame(); |
| if (!sourceFrame) { |
| console.assert(sourceFrame); |
| return; |
| } |
| sourceFrame.replaceAllWith(searchConfig, replacement); |
| } |
| |
| /** |
| * @param {!Event=} event |
| * @return {boolean} |
| */ |
| _showOutlineDialog(event) { |
| var uiSourceCode = this._editorContainer.currentFile(); |
| if (!uiSourceCode) |
| return false; |
| |
| if (uiSourceCode.contentType().hasScripts()) { |
| Sources.JavaScriptOutlineDialog.show(uiSourceCode, this.showSourceLocation.bind(this, uiSourceCode)); |
| return true; |
| } |
| |
| if (uiSourceCode.contentType().isStyleSheet()) { |
| Sources.StyleSheetOutlineDialog.show(uiSourceCode, this.showSourceLocation.bind(this, uiSourceCode)); |
| return true; |
| } |
| |
| // We don't want default browser shortcut to be executed, so pretend to handle this event. |
| return true; |
| } |
| |
| /** |
| * @param {string=} query |
| */ |
| showOpenResourceDialog(query) { |
| var uiSourceCodes = this._editorContainer.historyUISourceCodes(); |
| /** @type {!Map.<!Workspace.UISourceCode, number>} */ |
| var defaultScores = new Map(); |
| for (var i = 1; i < uiSourceCodes.length; ++i) // Skip current element |
| defaultScores.set(uiSourceCodes[i], uiSourceCodes.length - i); |
| if (!this._openResourceDialogHistory) |
| this._openResourceDialogHistory = []; |
| Sources.OpenResourceDialog.show(this, query || '', defaultScores, this._openResourceDialogHistory); |
| } |
| |
| /** |
| * @param {!Event=} event |
| * @return {boolean} |
| */ |
| _showGoToLineDialog(event) { |
| if (this._editorContainer.currentFile()) |
| this.showOpenResourceDialog(':'); |
| return true; |
| } |
| |
| /** |
| * @return {boolean} |
| */ |
| _save() { |
| this._saveSourceFrame(this.currentSourceFrame()); |
| return true; |
| } |
| |
| /** |
| * @return {boolean} |
| */ |
| _saveAll() { |
| var sourceFrames = this._editorContainer.fileViews(); |
| sourceFrames.forEach(this._saveSourceFrame.bind(this)); |
| return true; |
| } |
| |
| /** |
| * @param {?UI.Widget} sourceFrame |
| */ |
| _saveSourceFrame(sourceFrame) { |
| if (!(sourceFrame instanceof Sources.UISourceCodeFrame)) |
| return; |
| var uiSourceCodeFrame = /** @type {!Sources.UISourceCodeFrame} */ (sourceFrame); |
| uiSourceCodeFrame.commitEditing(); |
| } |
| |
| /** |
| * @return {boolean} |
| */ |
| _toggleBreakpoint() { |
| var sourceFrame = this.currentSourceFrame(); |
| if (!sourceFrame) |
| return false; |
| |
| if (sourceFrame instanceof Sources.JavaScriptSourceFrame) { |
| var javaScriptSourceFrame = /** @type {!Sources.JavaScriptSourceFrame} */ (sourceFrame); |
| javaScriptSourceFrame.toggleBreakpointOnCurrentLine(); |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * @param {boolean} active |
| */ |
| toggleBreakpointsActiveState(active) { |
| this._editorContainer.view.element.classList.toggle('breakpoints-deactivated', !active); |
| } |
| }; |
| |
| /** @enum {symbol} */ |
| Sources.SourcesView.Events = { |
| EditorClosed: Symbol('EditorClosed'), |
| EditorSelected: Symbol('EditorSelected'), |
| }; |
| |
| /** |
| * @interface |
| */ |
| Sources.SourcesView.EditorAction = function() {}; |
| |
| Sources.SourcesView.EditorAction.prototype = { |
| /** |
| * @param {!Sources.SourcesView} sourcesView |
| * @return {!UI.ToolbarButton} |
| */ |
| button: function(sourcesView) {} |
| }; |
| |
| /** |
| * @implements {UI.ActionDelegate} |
| * @unrestricted |
| */ |
| Sources.SourcesView.SwitchFileActionDelegate = class { |
| /** |
| * @param {!Workspace.UISourceCode} currentUISourceCode |
| * @return {?Workspace.UISourceCode} |
| */ |
| static _nextFile(currentUISourceCode) { |
| /** |
| * @param {string} name |
| * @return {string} |
| */ |
| function fileNamePrefix(name) { |
| var lastDotIndex = name.lastIndexOf('.'); |
| var namePrefix = name.substr(0, lastDotIndex !== -1 ? lastDotIndex : name.length); |
| return namePrefix.toLowerCase(); |
| } |
| |
| var uiSourceCodes = currentUISourceCode.project().uiSourceCodes(); |
| var candidates = []; |
| var url = currentUISourceCode.parentURL(); |
| var name = currentUISourceCode.name(); |
| var namePrefix = fileNamePrefix(name); |
| for (var i = 0; i < uiSourceCodes.length; ++i) { |
| var uiSourceCode = uiSourceCodes[i]; |
| if (url !== uiSourceCode.parentURL()) |
| continue; |
| if (fileNamePrefix(uiSourceCode.name()) === namePrefix) |
| candidates.push(uiSourceCode.name()); |
| } |
| candidates.sort(String.naturalOrderComparator); |
| var index = mod(candidates.indexOf(name) + 1, candidates.length); |
| var fullURL = (url ? url + '/' : '') + candidates[index]; |
| var nextUISourceCode = currentUISourceCode.project().uiSourceCodeForURL(fullURL); |
| return nextUISourceCode !== currentUISourceCode ? nextUISourceCode : null; |
| } |
| |
| /** |
| * @override |
| * @param {!UI.Context} context |
| * @param {string} actionId |
| * @return {boolean} |
| */ |
| handleAction(context, actionId) { |
| var sourcesView = UI.context.flavor(Sources.SourcesView); |
| var currentUISourceCode = sourcesView.currentUISourceCode(); |
| if (!currentUISourceCode) |
| return false; |
| var nextUISourceCode = Sources.SourcesView.SwitchFileActionDelegate._nextFile(currentUISourceCode); |
| if (!nextUISourceCode) |
| return false; |
| sourcesView.showSourceLocation(nextUISourceCode); |
| return true; |
| } |
| }; |
| |
| |
| /** |
| * @implements {UI.ActionDelegate} |
| * @unrestricted |
| */ |
| Sources.SourcesView.CloseAllActionDelegate = class { |
| /** |
| * @override |
| * @param {!UI.Context} context |
| * @param {string} actionId |
| * @return {boolean} |
| */ |
| handleAction(context, actionId) { |
| var sourcesView = UI.context.flavor(Sources.SourcesView); |
| if (!sourcesView) |
| return false; |
| sourcesView._editorContainer.closeAllFiles(); |
| return true; |
| } |
| }; |