123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676 |
- /*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC.
- * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- /**
- * @interface
- */
- WebInspector.TabbedEditorContainerDelegate = function() { }
- WebInspector.TabbedEditorContainerDelegate.prototype = {
- /**
- * @param {WebInspector.UISourceCode} uiSourceCode
- * @return {WebInspector.SourceFrame}
- */
- viewForFile: function(uiSourceCode) { }
- }
- /**
- * @constructor
- * @extends {WebInspector.Object}
- * @param {WebInspector.TabbedEditorContainerDelegate} delegate
- * @param {string} settingName
- */
- WebInspector.TabbedEditorContainer = function(delegate, settingName)
- {
- WebInspector.Object.call(this);
- this._delegate = delegate;
- this._tabbedPane = new WebInspector.TabbedPane();
- this._tabbedPane.setTabDelegate(new WebInspector.EditorContainerTabDelegate(this));
- this._tabbedPane.closeableTabs = true;
- this._tabbedPane.element.id = "scripts-editor-container-tabbed-pane";
- this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabClosed, this._tabClosed, this);
- this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, this._tabSelected, this);
- this._tabIds = new Map();
- this._files = {};
- this._loadedURIs = {};
- this._previouslyViewedFilesSetting = WebInspector.settings.createSetting(settingName, []);
- this._history = WebInspector.TabbedEditorContainer.History.fromObject(this._previouslyViewedFilesSetting.get());
- }
- WebInspector.TabbedEditorContainer.Events = {
- EditorSelected: "EditorSelected",
- EditorClosed: "EditorClosed"
- }
- WebInspector.TabbedEditorContainer._tabId = 0;
- WebInspector.TabbedEditorContainer.maximalPreviouslyViewedFilesCount = 30;
- WebInspector.TabbedEditorContainer.prototype = {
- /**
- * @return {WebInspector.View}
- */
- get view()
- {
- return this._tabbedPane;
- },
- /**
- * @type {WebInspector.SourceFrame}
- */
- get visibleView()
- {
- return this._tabbedPane.visibleView;
- },
- /**
- * @param {Element} parentElement
- */
- show: function(parentElement)
- {
- this._tabbedPane.show(parentElement);
- },
- /**
- * @param {WebInspector.UISourceCode} uiSourceCode
- */
- showFile: function(uiSourceCode)
- {
- this._innerShowFile(uiSourceCode, true);
- },
- _addScrollAndSelectionListeners: function()
- {
- if (!this._currentView)
- return;
- this._currentView.addEventListener(WebInspector.SourceFrame.Events.ScrollChanged, this._scrollChanged, this);
- this._currentView.addEventListener(WebInspector.SourceFrame.Events.SelectionChanged, this._selectionChanged, this);
- },
- _removeScrollAndSelectionListeners: function()
- {
- if (!this._currentView)
- return;
- this._currentView.removeEventListener(WebInspector.SourceFrame.Events.ScrollChanged, this._scrollChanged, this);
- this._currentView.removeEventListener(WebInspector.SourceFrame.Events.SelectionChanged, this._selectionChanged, this);
- },
- _scrollChanged: function(event)
- {
- var lineNumber = /** @type {number} */ (event.data);
- this._history.updateScrollLineNumber(this._currentFile.uri(), lineNumber);
- this._history.save(this._previouslyViewedFilesSetting);
- },
- _selectionChanged: function(event)
- {
- var range = /** @type {WebInspector.TextRange} */ (event.data);
- this._history.updateSelectionRange(this._currentFile.uri(), range);
- this._history.save(this._previouslyViewedFilesSetting);
- },
- /**
- * @param {WebInspector.UISourceCode} uiSourceCode
- * @param {boolean=} userGesture
- */
- _innerShowFile: function(uiSourceCode, userGesture)
- {
- if (this._currentFile === uiSourceCode)
- return;
- this._removeScrollAndSelectionListeners();
- this._currentFile = uiSourceCode;
- var tabId = this._tabIds.get(uiSourceCode) || this._appendFileTab(uiSourceCode, userGesture);
-
- this._tabbedPane.selectTab(tabId, userGesture);
- if (userGesture)
- this._editorSelectedByUserAction();
-
- this._currentView = this.visibleView;
- this._addScrollAndSelectionListeners();
-
- this.dispatchEventToListeners(WebInspector.TabbedEditorContainer.Events.EditorSelected, this._currentFile);
- },
- /**
- * @param {WebInspector.UISourceCode} uiSourceCode
- * @return {string}
- */
- _titleForFile: function(uiSourceCode)
- {
- const maxDisplayNameLength = 30;
- const minDisplayQueryParamLength = 5;
- var title = uiSourceCode.name();
- title = title ? title.centerEllipsizedToLength(maxDisplayNameLength) : WebInspector.UIString("(program)");
- if (uiSourceCode.isDirty())
- title += "*";
- return title;
- },
- /**
- * @param {string} id
- * @param {string} nextTabId
- */
- _maybeCloseTab: function(id, nextTabId)
- {
- var uiSourceCode = this._files[id];
- var shouldPrompt = uiSourceCode.isDirty() && uiSourceCode.project().canSetFileContent();
- // FIXME: this should be replaced with common Save/Discard/Cancel dialog.
- if (!shouldPrompt || confirm(WebInspector.UIString("Are you sure you want to close unsaved file: %s?", uiSourceCode.name()))) {
- uiSourceCode.resetWorkingCopy();
- if (nextTabId)
- this._tabbedPane.selectTab(nextTabId, true);
- this._tabbedPane.closeTab(id, true);
- return true;
- }
- return false;
- },
- /**
- * @param {Array.<string>} ids
- */
- _closeTabs: function(ids)
- {
- var dirtyTabs = [];
- var cleanTabs = [];
- for (var i = 0; i < ids.length; ++i) {
- var id = ids[i];
- var uiSourceCode = this._files[id];
- if (uiSourceCode.isDirty())
- dirtyTabs.push(id);
- else
- cleanTabs.push(id);
- }
- if (dirtyTabs.length)
- this._tabbedPane.selectTab(dirtyTabs[0], true);
- this._tabbedPane.closeTabs(cleanTabs, true);
- for (var i = 0; i < dirtyTabs.length; ++i) {
- var nextTabId = i + 1 < dirtyTabs.length ? dirtyTabs[i + 1] : null;
- if (!this._maybeCloseTab(dirtyTabs[i], nextTabId))
- break;
- }
- },
- /**
- * @param {WebInspector.UISourceCode} uiSourceCode
- */
- addUISourceCode: function(uiSourceCode)
- {
- if (this._userSelectedFiles || this._loadedURIs[uiSourceCode.uri()])
- return;
- this._loadedURIs[uiSourceCode.uri()] = true;
- var index = this._history.index(uiSourceCode.uri())
- if (index === -1)
- return;
- var tabId = this._tabIds.get(uiSourceCode) || this._appendFileTab(uiSourceCode, false);
- if (!this._currentFile)
- return;
- // Select tab if this file was the last to be shown.
- if (!index) {
- this._innerShowFile(uiSourceCode, false);
- return;
- }
- var currentProjectType = this._currentFile.project().type();
- var addedProjectType = uiSourceCode.project().type();
- var snippetsProjectType = WebInspector.projectTypes.Snippets;
- if (this._history.index(this._currentFile.uri()) && currentProjectType === snippetsProjectType && addedProjectType !== snippetsProjectType)
- this._innerShowFile(uiSourceCode, false);
- },
- /**
- * @param {WebInspector.UISourceCode} uiSourceCode
- */
- removeUISourceCode: function(uiSourceCode)
- {
- this.removeUISourceCodes([uiSourceCode]);
- },
- /**
- * @param {Array.<WebInspector.UISourceCode>} uiSourceCodes
- */
- removeUISourceCodes: function(uiSourceCodes)
- {
- var tabIds = [];
- for (var i = 0; i < uiSourceCodes.length; ++i) {
- var uiSourceCode = uiSourceCodes[i];
- delete this._loadedURIs[uiSourceCode.uri()];
- var tabId = this._tabIds.get(uiSourceCode);
- if (tabId)
- tabIds.push(tabId);
- }
- this._tabbedPane.closeTabs(tabIds);
- },
- /**
- * @param {WebInspector.UISourceCode} uiSourceCode
- */
- _editorClosedByUserAction: function(uiSourceCode)
- {
- this._userSelectedFiles = true;
- this._history.remove(uiSourceCode.uri());
- this._updateHistory();
- },
- _editorSelectedByUserAction: function()
- {
- this._userSelectedFiles = true;
- this._updateHistory();
- },
- _updateHistory: function()
- {
- var tabIds = this._tabbedPane.lastOpenedTabIds(WebInspector.TabbedEditorContainer.maximalPreviouslyViewedFilesCount);
-
- function tabIdToURI(tabId)
- {
- return this._files[tabId].uri();
- }
-
- this._history.update(tabIds.map(tabIdToURI.bind(this)));
- this._history.save(this._previouslyViewedFilesSetting);
- },
- /**
- * @param {WebInspector.UISourceCode} uiSourceCode
- * @return {string}
- */
- _tooltipForFile: function(uiSourceCode)
- {
- return uiSourceCode.originURL();
- },
- /**
- * @param {WebInspector.UISourceCode} uiSourceCode
- * @param {boolean=} userGesture
- */
- _appendFileTab: function(uiSourceCode, userGesture)
- {
- var view = this._delegate.viewForFile(uiSourceCode);
- var title = this._titleForFile(uiSourceCode);
- var tooltip = this._tooltipForFile(uiSourceCode);
- var tabId = this._generateTabId();
- this._tabIds.put(uiSourceCode, tabId);
- this._files[tabId] = uiSourceCode;
- var savedScrollLineNumber = this._history.scrollLineNumber(uiSourceCode.uri());
- if (savedScrollLineNumber)
- view.scrollToLine(savedScrollLineNumber);
- var savedSelectionRange = this._history.selectionRange(uiSourceCode.uri());
- if (savedSelectionRange)
- view.setSelection(savedSelectionRange);
- this._tabbedPane.appendTab(tabId, title, view, tooltip, userGesture);
- this._addUISourceCodeListeners(uiSourceCode);
- return tabId;
- },
- /**
- * @param {WebInspector.Event} event
- */
- _tabClosed: function(event)
- {
- var tabId = /** @type {string} */ (event.data.tabId);
- var userGesture = /** @type {boolean} */ (event.data.isUserGesture);
- var uiSourceCode = this._files[tabId];
- if (this._currentFile === uiSourceCode) {
- this._removeScrollAndSelectionListeners();
- delete this._currentView;
- delete this._currentFile;
- }
- this._tabIds.remove(uiSourceCode);
- delete this._files[tabId];
- this._removeUISourceCodeListeners(uiSourceCode);
- this.dispatchEventToListeners(WebInspector.TabbedEditorContainer.Events.EditorClosed, uiSourceCode);
- if (userGesture)
- this._editorClosedByUserAction(uiSourceCode);
- },
- /**
- * @param {WebInspector.Event} event
- */
- _tabSelected: function(event)
- {
- var tabId = /** @type {string} */ (event.data.tabId);
- var userGesture = /** @type {boolean} */ (event.data.isUserGesture);
- var uiSourceCode = this._files[tabId];
- this._innerShowFile(uiSourceCode, userGesture);
- },
- /**
- * @param {WebInspector.UISourceCode} uiSourceCode
- */
- _addUISourceCodeListeners: function(uiSourceCode)
- {
- uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.TitleChanged, this._uiSourceCodeTitleChanged, this);
- uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._uiSourceCodeWorkingCopyChanged, this);
- uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._uiSourceCodeWorkingCopyCommitted, this);
- uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.FormattedChanged, this._uiSourceCodeFormattedChanged, this);
- },
- /**
- * @param {WebInspector.UISourceCode} uiSourceCode
- */
- _removeUISourceCodeListeners: function(uiSourceCode)
- {
- uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.TitleChanged, this._uiSourceCodeTitleChanged, this);
- uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._uiSourceCodeWorkingCopyChanged, this);
- uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._uiSourceCodeWorkingCopyCommitted, this);
- uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.FormattedChanged, this._uiSourceCodeFormattedChanged, this);
- },
- /**
- * @param {WebInspector.UISourceCode} uiSourceCode
- */
- _updateFileTitle: function(uiSourceCode)
- {
- var tabId = this._tabIds.get(uiSourceCode);
- if (tabId) {
- var title = this._titleForFile(uiSourceCode);
- this._tabbedPane.changeTabTitle(tabId, title);
- }
- },
- _uiSourceCodeTitleChanged: function(event)
- {
- var uiSourceCode = /** @type {WebInspector.UISourceCode} */ (event.target);
- this._updateFileTitle(uiSourceCode);
- },
- _uiSourceCodeWorkingCopyChanged: function(event)
- {
- var uiSourceCode = /** @type {WebInspector.UISourceCode} */ (event.target);
- this._updateFileTitle(uiSourceCode);
- },
- _uiSourceCodeWorkingCopyCommitted: function(event)
- {
- var uiSourceCode = /** @type {WebInspector.UISourceCode} */ (event.target);
- this._updateFileTitle(uiSourceCode);
- },
- _uiSourceCodeFormattedChanged: function(event)
- {
- var uiSourceCode = /** @type {WebInspector.UISourceCode} */ (event.target);
- this._updateFileTitle(uiSourceCode);
- },
- reset: function()
- {
- delete this._userSelectedFiles;
- },
- /**
- * @return {string}
- */
- _generateTabId: function()
- {
- return "tab_" + (WebInspector.TabbedEditorContainer._tabId++);
- },
- /**
- * @return {WebInspector.UISourceCode} uiSourceCode
- */
- currentFile: function()
- {
- return this._currentFile;
- },
- __proto__: WebInspector.Object.prototype
- }
- /**
- * @constructor
- * @param {string} url
- * @param {WebInspector.TextRange=} selectionRange
- * @param {number=} scrollLineNumber
- */
- WebInspector.TabbedEditorContainer.HistoryItem = function(url, selectionRange, scrollLineNumber)
- {
- /** @const */ this.url = url;
- /** @const */ this._isSerializable = url.length < WebInspector.TabbedEditorContainer.HistoryItem.serializableUrlLengthLimit;
- this.selectionRange = selectionRange;
- this.scrollLineNumber = scrollLineNumber;
- }
- WebInspector.TabbedEditorContainer.HistoryItem.serializableUrlLengthLimit = 4096;
- /**
- * @param {Object} serializedHistoryItem
- * @return {WebInspector.TabbedEditorContainer.HistoryItem}
- */
- WebInspector.TabbedEditorContainer.HistoryItem.fromObject = function (serializedHistoryItem)
- {
- var selectionRange = serializedHistoryItem.selectionRange ? WebInspector.TextRange.fromObject(serializedHistoryItem.selectionRange) : null;
- return new WebInspector.TabbedEditorContainer.HistoryItem(serializedHistoryItem.url, selectionRange, serializedHistoryItem.scrollLineNumber);
- }
- WebInspector.TabbedEditorContainer.HistoryItem.prototype = {
- /**
- * @return {?Object}
- */
- serializeToObject: function()
- {
- if (!this._isSerializable)
- return null;
- var serializedHistoryItem = {};
- serializedHistoryItem.url = this.url;
- serializedHistoryItem.selectionRange = this.selectionRange;
- serializedHistoryItem.scrollLineNumber = this.scrollLineNumber;
- return serializedHistoryItem;
- },
- __proto__: WebInspector.Object.prototype
- }
- /**
- * @constructor
- * @param {Array.<WebInspector.TabbedEditorContainer.HistoryItem>} items
- */
- WebInspector.TabbedEditorContainer.History = function(items)
- {
- this._items = items;
- this._rebuildItemIndex();
- }
- /**
- * @param {!Array.<!Object>} serializedHistory
- * @return {WebInspector.TabbedEditorContainer.History}
- */
- WebInspector.TabbedEditorContainer.History.fromObject = function(serializedHistory)
- {
- var items = [];
- for (var i = 0; i < serializedHistory.length; ++i)
- items.push(WebInspector.TabbedEditorContainer.HistoryItem.fromObject(serializedHistory[i]));
- return new WebInspector.TabbedEditorContainer.History(items);
- }
- WebInspector.TabbedEditorContainer.History.prototype = {
- /**
- * @param {string} url
- * @return {number}
- */
- index: function(url)
- {
- var index = this._itemsIndex[url];
- if (typeof index === "number")
- return index;
- return -1;
- },
- _rebuildItemIndex: function()
- {
- this._itemsIndex = {};
- for (var i = 0; i < this._items.length; ++i) {
- console.assert(!this._itemsIndex.hasOwnProperty(this._items[i].url));
- this._itemsIndex[this._items[i].url] = i;
- }
- },
- /**
- * @param {string} url
- * @return {WebInspector.TextRange|undefined}
- */
- selectionRange: function(url)
- {
- var index = this.index(url);
- return index !== -1 ? this._items[index].selectionRange : undefined;
- },
- /**
- * @param {string} url
- * @param {WebInspector.TextRange} selectionRange
- */
- updateSelectionRange: function(url, selectionRange)
- {
- if (!selectionRange)
- return;
- var index = this.index(url);
- if (index === -1)
- return;
- this._items[index].selectionRange = selectionRange;
- },
- /**
- * @param {string} url
- * @return {number|undefined}
- */
- scrollLineNumber: function(url)
- {
- var index = this.index(url);
- return index !== -1 ? this._items[index].scrollLineNumber : undefined;
- },
- /**
- * @param {string} url
- * @param {number} scrollLineNumber
- */
- updateScrollLineNumber: function(url, scrollLineNumber)
- {
- var index = this.index(url);
- if (index === -1)
- return;
- this._items[index].scrollLineNumber = scrollLineNumber;
- },
- /**
- * @param {Array.<string>} urls
- */
- update: function(urls)
- {
- for (var i = urls.length - 1; i >= 0; --i) {
- var index = this.index(urls[i]);
- var item;
- if (index !== -1) {
- item = this._items[index];
- this._items.splice(index, 1);
- } else
- item = new WebInspector.TabbedEditorContainer.HistoryItem(urls[i]);
- this._items.unshift(item);
- this._rebuildItemIndex();
- }
- },
- /**
- * @param {string} url
- */
- remove: function(url)
- {
- var index = this.index(url);
- if (index !== -1) {
- this._items.splice(index, 1);
- this._rebuildItemIndex();
- }
- },
-
- /**
- * @param {WebInspector.Setting} setting
- */
- save: function(setting)
- {
- setting.set(this._serializeToObject());
- },
-
- /**
- * @return {!Array.<!Object>}
- */
- _serializeToObject: function()
- {
- var serializedHistory = [];
- for (var i = 0; i < this._items.length; ++i) {
- var serializedItem = this._items[i].serializeToObject();
- if (serializedItem)
- serializedHistory.push(serializedItem);
- if (serializedHistory.length === WebInspector.TabbedEditorContainer.maximalPreviouslyViewedFilesCount)
- break;
- }
- return serializedHistory;
- },
- __proto__: WebInspector.Object.prototype
- }
- /**
- * @constructor
- * @implements {WebInspector.TabbedPaneTabDelegate}
- * @param {WebInspector.TabbedEditorContainer} editorContainer
- */
- WebInspector.EditorContainerTabDelegate = function(editorContainer)
- {
- this._editorContainer = editorContainer;
- }
- WebInspector.EditorContainerTabDelegate.prototype = {
- /**
- * @param {WebInspector.TabbedPane} tabbedPane
- * @param {Array.<string>} ids
- */
- closeTabs: function(tabbedPane, ids)
- {
- this._editorContainer._closeTabs(ids);
- }
- }
|