From 1612a95e9674c679bb4fd5b1c17fe403afc480b4 Mon Sep 17 00:00:00 2001 From: "vsevik@chromium.org" Date: Tue, 3 Jul 2012 09:28:41 +0000 Subject: [PATCH] Web Inspector: Save scroll selection and cursor position of SourceFrames in sources panel. https://bugs.webkit.org/show_bug.cgi?id=90294 Reviewed by Yury Semikhatsky. Source/WebCore: Scroll and selection change handling is now delegated from TextViewer to SourceFrame. SourceFrame now dispatches ScrollChanged and SelectionChanged events. TabbedEditorContainer now saves scroll and selection information together with the url history and restores scroll and selection on resource opening. * inspector/front-end/JavaScriptSourceFrame.js: (WebInspector.JavaScriptSourceFrame.prototype.setExecutionLine): * inspector/front-end/SourceFrame.js: (WebInspector.SourceFrame.prototype.wasShown): (WebInspector.SourceFrame.prototype.highlightLine): (WebInspector.SourceFrame.prototype._innerHighlightLineIfNeeded): (WebInspector.SourceFrame.prototype._clearLineHighlight): (WebInspector.SourceFrame.prototype.revealLine): (WebInspector.SourceFrame.prototype._innerRevealLineIfNeeded): (WebInspector.SourceFrame.prototype._clearLineToReveal): (WebInspector.SourceFrame.prototype.scrollToLine): (WebInspector.SourceFrame.prototype._innerScrollToLineIfNeeded): (WebInspector.SourceFrame.prototype._clearLineToScrollTo): (WebInspector.SourceFrame.prototype.setSelection): (WebInspector.SourceFrame.prototype._innerSetSelectionIfNeeded): (WebInspector.SourceFrame.prototype._wasShownOrLoaded): (WebInspector.SourceFrame.prototype.setContent): (WebInspector.SourceFrame.prototype.commitEditing): (WebInspector.SourceFrame.prototype.selectionChanged): (WebInspector.SourceFrame.prototype.scrollChanged): (WebInspector.TextViewerDelegateForSourceFrame.prototype.selectionChanged): (WebInspector.TextViewerDelegateForSourceFrame.prototype.scrollChanged): * inspector/front-end/TabbedEditorContainer.js: (WebInspector.TabbedEditorContainer): (WebInspector.TabbedEditorContainer.prototype._addScrollAndSelectionListeners): (WebInspector.TabbedEditorContainer.prototype._removeScrollAndSelectionListeners): (WebInspector.TabbedEditorContainer.prototype._scrollChanged): (WebInspector.TabbedEditorContainer.prototype._selectionChanged): (WebInspector.TabbedEditorContainer.prototype._appendFileTab): (WebInspector.TabbedEditorContainer.prototype._tabClosed): (WebInspector.TabbedEditorContainer.HistoryItem): (WebInspector.TabbedEditorContainer.HistoryItem.fromObject): (WebInspector.TabbedEditorContainer.HistoryItem.prototype.serializeToObject): (WebInspector.TabbedEditorContainer.History): (WebInspector.TabbedEditorContainer.History.fromObject): (WebInspector.TabbedEditorContainer.History.prototype.index): (WebInspector.TabbedEditorContainer.History.prototype.selectionRange): (WebInspector.TabbedEditorContainer.History.prototype.updateSelectionRange): (WebInspector.TabbedEditorContainer.History.prototype.scrollLineNumber): (WebInspector.TabbedEditorContainer.History.prototype.updateScrollLineNumber): (WebInspector.TabbedEditorContainer.History.prototype.update): (WebInspector.TabbedEditorContainer.History.prototype.remove): (WebInspector.TabbedEditorContainer.History.prototype.save): (WebInspector.TabbedEditorContainer.History.prototype.set _serializeToObject): * inspector/front-end/TextEditorModel.js: (WebInspector.TextRange.fromObject): (WebInspector.TextRange.prototype.clone): (WebInspector.TextRange.prototype.serializeToObject): * inspector/front-end/TextViewer.js: (WebInspector.TextViewer.prototype._handleScrollChanged): (WebInspector.TextViewer.prototype.scrollToLine): (WebInspector.TextViewer.prototype._handleSelectionChange): (WebInspector.TextViewer.prototype.setSelection): (WebInspector.TextViewer.prototype.wasShown): (WebInspector.TextViewer.prototype._handleFocused): (WebInspector.TextViewer.prototype.willHide): (WebInspector.TextViewerDelegate.prototype.selectionChanged): (WebInspector.TextViewerDelegate.prototype.scrollChanged): (WebInspector.TextEditorChunkedPanel.prototype.scrollToLine): LayoutTests: * inspector/tabbed-editors-history-expected.txt: * inspector/tabbed-editors-history.html: git-svn-id: http://svn.webkit.org/repository/webkit/trunk@121750 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- LayoutTests/ChangeLog | 10 ++ .../inspector/tabbed-editors-history-expected.txt | 43 ++--- LayoutTests/inspector/tabbed-editors-history.html | 10 +- Source/WebCore/ChangeLog | 72 ++++++++ .../inspector/front-end/JavaScriptSourceFrame.js | 4 +- Source/WebCore/inspector/front-end/SourceFrame.js | 154 +++++++++++++---- .../inspector/front-end/TabbedEditorContainer.js | 182 +++++++++++++++++++-- Source/WebCore/inspector/front-end/TextEditor.js | 66 ++++++++ .../WebCore/inspector/front-end/TextEditorModel.js | 22 +++ 9 files changed, 496 insertions(+), 67 deletions(-) diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog index 0ac4257..b3eee91 100644 --- a/LayoutTests/ChangeLog +++ b/LayoutTests/ChangeLog @@ -1,3 +1,13 @@ +2012-07-03 Vsevolod Vlasov + + Web Inspector: Save scroll selection and cursor position of SourceFrames in sources panel. + https://bugs.webkit.org/show_bug.cgi?id=90294 + + Reviewed by Yury Semikhatsky. + + * inspector/tabbed-editors-history-expected.txt: + * inspector/tabbed-editors-history.html: + 2012-07-03 Taiju Tsuiki Web Inspector: Make DirectoryContentView sortable diff --git a/LayoutTests/inspector/tabbed-editors-history-expected.txt b/LayoutTests/inspector/tabbed-editors-history-expected.txt index 7f8beee..36291ce 100644 --- a/LayoutTests/inspector/tabbed-editors-history-expected.txt +++ b/LayoutTests/inspector/tabbed-editors-history-expected.txt @@ -2,26 +2,27 @@ Tests history saving logic in TabbedEditorContainer. Bug 76912 history = [] - history = [url_1] - history = [url_2,url_1] - history = [url_3,url_2,url_1] - history = [url_2,url_3,url_1] - history = [url_1,url_2,url_3] - history = [url_11,url_1,url_2,url_3] - history = [url_12,url_11,url_1,url_2,url_3] - history = [url_13,url_12,url_11,url_1,url_2,url_3] - history = [url_12,url_13,url_11,url_1,url_2,url_3] - history = [url_11,url_12,url_13,url_1,url_2,url_3] - history = [url_12,url_13,url_1,url_2,url_3] - history = [url_12,url_1,url_2,url_3] - history = [url_14,url_12,url_1,url_2,url_3] - history = [url_15,url_14,url_12,url_1,url_2,url_3] - history = [url_16,url_15,url_14,url_12,url_1,url_2,url_3] - history = [url_15,url_14,url_12,url_1,url_2,url_3] - history = [url_14,url_12,url_1,url_2,url_3] - history = [url_12,url_1,url_2,url_3] - history = [url_1,url_2,url_3] - history = [url_2,url_3] - history = [url_3] + history = [{"url":"url_1"}] + history = [{"url":"url_2"},{"url":"url_1"}] + history = [{"url":"url_3"},{"url":"url_2"},{"url":"url_1"}] + history = [{"url":"url_2"},{"url":"url_3"},{"url":"url_1"}] + history = [{"url":"url_1"},{"url":"url_2"},{"url":"url_3"}] + history = [{"url":"url_11"},{"url":"url_1"},{"url":"url_2"},{"url":"url_3"}] + history = [{"url":"url_12"},{"url":"url_11"},{"url":"url_1"},{"url":"url_2"},{"url":"url_3"}] + history = [{"url":"url_13"},{"url":"url_12"},{"url":"url_11"},{"url":"url_1"},{"url":"url_2"},{"url":"url_3"}] + history = [{"url":"url_12"},{"url":"url_13"},{"url":"url_11"},{"url":"url_1"},{"url":"url_2"},{"url":"url_3"}] + history = [{"url":"url_11"},{"url":"url_12"},{"url":"url_13"},{"url":"url_1"},{"url":"url_2"},{"url":"url_3"}] + history = [{"url":"url_11","selectionRange":{"startLine":15,"startColumn":5,"endLine":15,"endColumn":10},"scrollLineNumber":10},{"url":"url_12"},{"url":"url_13"},{"url":"url_1"},{"url":"url_2"},{"url":"url_3"}] + history = [{"url":"url_12"},{"url":"url_13"},{"url":"url_1"},{"url":"url_2"},{"url":"url_3"}] + history = [{"url":"url_12"},{"url":"url_1"},{"url":"url_2"},{"url":"url_3"}] + history = [{"url":"url_14"},{"url":"url_12"},{"url":"url_1"},{"url":"url_2"},{"url":"url_3"}] + history = [{"url":"url_15"},{"url":"url_14"},{"url":"url_12"},{"url":"url_1"},{"url":"url_2"},{"url":"url_3"}] + history = [{"url":"url_16"},{"url":"url_15"},{"url":"url_14"},{"url":"url_12"},{"url":"url_1"},{"url":"url_2"},{"url":"url_3"}] + history = [{"url":"url_15"},{"url":"url_14"},{"url":"url_12"},{"url":"url_1"},{"url":"url_2"},{"url":"url_3"}] + history = [{"url":"url_14"},{"url":"url_12"},{"url":"url_1"},{"url":"url_2"},{"url":"url_3"}] + history = [{"url":"url_12"},{"url":"url_1"},{"url":"url_2"},{"url":"url_3"}] + history = [{"url":"url_1"},{"url":"url_2"},{"url":"url_3"}] + history = [{"url":"url_2"},{"url":"url_3"}] + history = [{"url":"url_3"}] history = [] diff --git a/LayoutTests/inspector/tabbed-editors-history.html b/LayoutTests/inspector/tabbed-editors-history.html index 12c421e..3c4ee17 100644 --- a/LayoutTests/inspector/tabbed-editors-history.html +++ b/LayoutTests/inspector/tabbed-editors-history.html @@ -6,7 +6,14 @@ var test = function() { function dumpHistory(history) { - InspectorTest.addResult(" history = [" + String(history._urls) + "]"); + InspectorTest.addResult(" history = " + JSON.stringify(history._serializeToObject()) + ""); + } + + function updateScrollAndSelectionAndDump(history, url, scrollLineNumber, selection) + { + history.updateScrollLineNumber(url, scrollLineNumber); + history.updateSelectionRange(url, selection); + dumpHistory(history); } function updateAndDump(history, urls) @@ -43,6 +50,7 @@ var test = function() // ... and switching between them. updateAndDump(history, [url(12), url(13), url(11)]); updateAndDump(history, [url(11), url(12), url(13)]); + updateScrollAndSelectionAndDump(history, url(11), 10, new WebInspector.TextRange(15, 5, 15, 10)); // Now close some tabs. removeAndDump(history, url(11)); removeAndDump(history, url(13)); diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog index 73e6222..7fbe713 100644 --- a/Source/WebCore/ChangeLog +++ b/Source/WebCore/ChangeLog @@ -1,3 +1,75 @@ +2012-07-03 Vsevolod Vlasov + + Web Inspector: Save scroll selection and cursor position of SourceFrames in sources panel. + https://bugs.webkit.org/show_bug.cgi?id=90294 + + Reviewed by Yury Semikhatsky. + + Scroll and selection change handling is now delegated from TextViewer to SourceFrame. + SourceFrame now dispatches ScrollChanged and SelectionChanged events. + TabbedEditorContainer now saves scroll and selection information together + with the url history and restores scroll and selection on resource opening. + + * inspector/front-end/JavaScriptSourceFrame.js: + (WebInspector.JavaScriptSourceFrame.prototype.setExecutionLine): + * inspector/front-end/SourceFrame.js: + (WebInspector.SourceFrame.prototype.wasShown): + (WebInspector.SourceFrame.prototype.highlightLine): + (WebInspector.SourceFrame.prototype._innerHighlightLineIfNeeded): + (WebInspector.SourceFrame.prototype._clearLineHighlight): + (WebInspector.SourceFrame.prototype.revealLine): + (WebInspector.SourceFrame.prototype._innerRevealLineIfNeeded): + (WebInspector.SourceFrame.prototype._clearLineToReveal): + (WebInspector.SourceFrame.prototype.scrollToLine): + (WebInspector.SourceFrame.prototype._innerScrollToLineIfNeeded): + (WebInspector.SourceFrame.prototype._clearLineToScrollTo): + (WebInspector.SourceFrame.prototype.setSelection): + (WebInspector.SourceFrame.prototype._innerSetSelectionIfNeeded): + (WebInspector.SourceFrame.prototype._wasShownOrLoaded): + (WebInspector.SourceFrame.prototype.setContent): + (WebInspector.SourceFrame.prototype.commitEditing): + (WebInspector.SourceFrame.prototype.selectionChanged): + (WebInspector.SourceFrame.prototype.scrollChanged): + (WebInspector.TextViewerDelegateForSourceFrame.prototype.selectionChanged): + (WebInspector.TextViewerDelegateForSourceFrame.prototype.scrollChanged): + * inspector/front-end/TabbedEditorContainer.js: + (WebInspector.TabbedEditorContainer): + (WebInspector.TabbedEditorContainer.prototype._addScrollAndSelectionListeners): + (WebInspector.TabbedEditorContainer.prototype._removeScrollAndSelectionListeners): + (WebInspector.TabbedEditorContainer.prototype._scrollChanged): + (WebInspector.TabbedEditorContainer.prototype._selectionChanged): + (WebInspector.TabbedEditorContainer.prototype._appendFileTab): + (WebInspector.TabbedEditorContainer.prototype._tabClosed): + (WebInspector.TabbedEditorContainer.HistoryItem): + (WebInspector.TabbedEditorContainer.HistoryItem.fromObject): + (WebInspector.TabbedEditorContainer.HistoryItem.prototype.serializeToObject): + (WebInspector.TabbedEditorContainer.History): + (WebInspector.TabbedEditorContainer.History.fromObject): + (WebInspector.TabbedEditorContainer.History.prototype.index): + (WebInspector.TabbedEditorContainer.History.prototype.selectionRange): + (WebInspector.TabbedEditorContainer.History.prototype.updateSelectionRange): + (WebInspector.TabbedEditorContainer.History.prototype.scrollLineNumber): + (WebInspector.TabbedEditorContainer.History.prototype.updateScrollLineNumber): + (WebInspector.TabbedEditorContainer.History.prototype.update): + (WebInspector.TabbedEditorContainer.History.prototype.remove): + (WebInspector.TabbedEditorContainer.History.prototype.save): + (WebInspector.TabbedEditorContainer.History.prototype.set _serializeToObject): + * inspector/front-end/TextEditorModel.js: + (WebInspector.TextRange.fromObject): + (WebInspector.TextRange.prototype.clone): + (WebInspector.TextRange.prototype.serializeToObject): + * inspector/front-end/TextViewer.js: + (WebInspector.TextViewer.prototype._handleScrollChanged): + (WebInspector.TextViewer.prototype.scrollToLine): + (WebInspector.TextViewer.prototype._handleSelectionChange): + (WebInspector.TextViewer.prototype.setSelection): + (WebInspector.TextViewer.prototype.wasShown): + (WebInspector.TextViewer.prototype._handleFocused): + (WebInspector.TextViewer.prototype.willHide): + (WebInspector.TextViewerDelegate.prototype.selectionChanged): + (WebInspector.TextViewerDelegate.prototype.scrollChanged): + (WebInspector.TextEditorChunkedPanel.prototype.scrollToLine): + 2012-07-03 Taiju Tsuiki Web Inspector: Make DirectoryContentView sortable diff --git a/Source/WebCore/inspector/front-end/JavaScriptSourceFrame.js b/Source/WebCore/inspector/front-end/JavaScriptSourceFrame.js index e8f02c3..435ae21 100644 --- a/Source/WebCore/inspector/front-end/JavaScriptSourceFrame.js +++ b/Source/WebCore/inspector/front-end/JavaScriptSourceFrame.js @@ -440,9 +440,9 @@ WebInspector.JavaScriptSourceFrame.prototype = { if (this.loaded) { this.textEditor.addDecoration(lineNumber, "webkit-execution-line"); this.revealLine(this._executionLineNumber); + if (this.canEditSource()) + this.setSelection(WebInspector.TextRange.createFromLocation(lineNumber, 0)); } - if (this.canEditSource()) - this.setSelection(WebInspector.TextRange.createFromLocation(lineNumber, 0)); }, clearExecutionLine: function() diff --git a/Source/WebCore/inspector/front-end/SourceFrame.js b/Source/WebCore/inspector/front-end/SourceFrame.js index 37ac1ef..d939e20 100644 --- a/Source/WebCore/inspector/front-end/SourceFrame.js +++ b/Source/WebCore/inspector/front-end/SourceFrame.js @@ -75,11 +75,17 @@ WebInspector.SourceFrame.createSearchRegex = function(query) return regex; } +WebInspector.SourceFrame.Events = { + ScrollChanged: "ScrollChanged", + SelectionChanged: "SelectionChanged" +} + WebInspector.SourceFrame.prototype = { wasShown: function() { this._ensureContentLoaded(); this._textEditor.show(this.element); + this._wasShownOrLoaded(); }, willHide: function() @@ -146,35 +152,91 @@ WebInspector.SourceFrame.prototype = { return this._textModel; }, + /** + * @param {number} line + */ canHighlightLine: function(line) { return true; }, + /** + * @param {number} line + */ highlightLine: function(line) { this._clearLineToReveal(); - if (this.loaded) - this._textEditor.highlightLine(line); - else - this._lineToHighlight = line; + this._clearLineToScrollTo(); + this._lineToHighlight = line; + this._innerHighlightLineIfNeeded(); + }, + + _innerHighlightLineIfNeeded: function() + { + if (typeof this._lineToHighlight === "number") { + if (this.loaded && this._textEditor.isShowing()) { + this._textEditor.highlightLine(this._lineToHighlight); + delete this._lineToHighlight + } + } }, _clearLineHighlight: function() { - if (this.loaded) - this._textEditor.clearLineHighlight(); - else - delete this._lineToHighlight; + this._textEditor.clearLineHighlight(); + delete this._lineToHighlight; }, + /** + * @param {number} line + */ revealLine: function(line) { this._clearLineHighlight(); - if (this.loaded) - this._textEditor.revealLine(line); - else - this._lineToReveal = line; + this._clearLineToScrollTo(); + this._lineToReveal = line; + this._innerRevealLineIfNeeded(); + }, + + _innerRevealLineIfNeeded: function() + { + if (typeof this._lineToReveal === "number") { + if (this.loaded && this._textEditor.isShowing()) { + this._textEditor.revealLine(this._lineToReveal); + delete this._lineToReveal + } + } + }, + + _clearLineToReveal: function() + { + delete this._lineToReveal; + }, + + /** + * @param {number} line + */ + scrollToLine: function(line) + { + this._clearLineHighlight(); + this._clearLineToReveal(); + this._lineToScrollTo = line; + this._innerScrollToLineIfNeeded(); + }, + + _innerScrollToLineIfNeeded: function() + { + if (typeof this._lineToScrollTo === "number") { + if (this.loaded && this._textEditor.isShowing()) { + this._textEditor.scrollToLine(this._lineToScrollTo); + delete this._lineToScrollTo + } + } + }, + + _clearLineToScrollTo: function() + { + delete this._lineToScrollTo; }, /** @@ -182,15 +244,24 @@ WebInspector.SourceFrame.prototype = { */ setSelection: function(textRange) { - if (this.loaded) - this._textEditor.setSelection(textRange); - else - this._selectionToSet = textRange; + this._selectionToSet = textRange; + this._innerSetSelectionIfNeeded(); }, - _clearLineToReveal: function() + _innerSetSelectionIfNeeded: function() { - delete this._lineToReveal; + if (this._selectionToSet && this.loaded && this._textEditor.isShowing()) { + this._textEditor.setSelection(this._selectionToSet); + delete this._selectionToSet; + } + }, + + _wasShownOrLoaded: function() + { + this._innerHighlightLineIfNeeded(); + this._innerRevealLineIfNeeded(); + this._innerScrollToLineIfNeeded(); + this._innerSetSelectionIfNeeded(); }, beforeTextChanged: function() @@ -219,20 +290,7 @@ WebInspector.SourceFrame.prototype = { this._setTextEditorDecorations(); - if (typeof this._lineToHighlight === "number") { - this.highlightLine(this._lineToHighlight); - delete this._lineToHighlight; - } - - if (typeof this._lineToReveal === "number") { - this.revealLine(this._lineToReveal); - delete this._lineToReveal; - } - - if (typeof this._selectionToSet === "object") { - this.setSelection(this._selectionToSet); - delete this._selectionToSet; - } + this._wasShownOrLoaded(); if (this._delayedFindSearchMatches) { this._delayedFindSearchMatches(); @@ -496,6 +554,22 @@ WebInspector.SourceFrame.prototype = { */ commitEditing: function(text) { + }, + + /** + * @param {WebInspector.TextRange} textRange + */ + selectionChanged: function(textRange) + { + this.dispatchEventToListeners(WebInspector.SourceFrame.Events.SelectionChanged, textRange); + }, + + /** + * @param {number} lineNumber + */ + scrollChanged: function(lineNumber) + { + this.dispatchEventToListeners(WebInspector.SourceFrame.Events.ScrollChanged, lineNumber); } } @@ -527,6 +601,22 @@ WebInspector.TextEditorDelegateForSourceFrame.prototype = { this._sourceFrame.commitEditing(this._sourceFrame._textModel.text); }, + /** + * @param {WebInspector.TextRange} textRange + */ + selectionChanged: function(textRange) + { + this._sourceFrame.selectionChanged(textRange); + }, + + /** + * @param {number} lineNumber + */ + scrollChanged: function(lineNumber) + { + this._sourceFrame.scrollChanged(lineNumber); + }, + populateLineGutterContextMenu: function(contextMenu, lineNumber) { this._sourceFrame.populateLineGutterContextMenu(contextMenu, lineNumber); diff --git a/Source/WebCore/inspector/front-end/TabbedEditorContainer.js b/Source/WebCore/inspector/front-end/TabbedEditorContainer.js index c18e005..31f1a4f 100644 --- a/Source/WebCore/inspector/front-end/TabbedEditorContainer.js +++ b/Source/WebCore/inspector/front-end/TabbedEditorContainer.js @@ -62,7 +62,7 @@ WebInspector.TabbedEditorContainer = function(delegate, settingName) this._loadedURLs = {}; this._previouslyViewedFilesSetting = WebInspector.settings.createSetting(settingName, []); - this._history = new WebInspector.TabbedEditorContainer.History(this._previouslyViewedFilesSetting.get()); + this._history = WebInspector.TabbedEditorContainer.History.fromObject(this._previouslyViewedFilesSetting.get()); } @@ -108,6 +108,37 @@ WebInspector.TabbedEditorContainer.prototype = { this._innerShowFile(uiSourceCode, true); }, + _addScrollAndSelectionListeners: function() + { + console.assert(this._currentFile); + var sourceFrame = this._delegate.viewForFile(this._currentFile); + sourceFrame.addEventListener(WebInspector.SourceFrame.Events.ScrollChanged, this._scrollChanged, this); + sourceFrame.addEventListener(WebInspector.SourceFrame.Events.SelectionChanged, this._selectionChanged, this); + }, + + _removeScrollAndSelectionListeners: function() + { + if (!this._currentFile) + return; + var sourceFrame = this._delegate.viewForFile(this._currentFile); + sourceFrame.removeEventListener(WebInspector.SourceFrame.Events.ScrollChanged, this._scrollChanged, this); + sourceFrame.removeEventListener(WebInspector.SourceFrame.Events.SelectionChanged, this._selectionChanged, this); + }, + + _scrollChanged: function(event) + { + var lineNumber = /** @type {number} */ event.data; + this._history.updateScrollLineNumber(this._currentFile.url, lineNumber); + this._history.save(this._previouslyViewedFilesSetting); + }, + + _selectionChanged: function(event) + { + var range = /** @type {WebInspector.TextRange} */ event.data; + this._history.updateSelectionRange(this._currentFile.url, range); + this._history.save(this._previouslyViewedFilesSetting); + }, + /** * @param {WebInspector.UISourceCode} uiSourceCode * @param {boolean=} userGesture @@ -116,6 +147,7 @@ WebInspector.TabbedEditorContainer.prototype = { { if (this._currentFile === uiSourceCode) return; + this._removeScrollAndSelectionListeners(); this._currentFile = uiSourceCode; var tabId = this._tabIds.get(uiSourceCode) || this._appendFileTab(uiSourceCode, userGesture); @@ -124,6 +156,8 @@ WebInspector.TabbedEditorContainer.prototype = { if (userGesture) this._editorSelectedByUserAction(); + this._addScrollAndSelectionListeners(); + this.dispatchEventToListeners(WebInspector.TabbedEditorContainer.Events.EditorSelected, this._currentFile); }, @@ -225,6 +259,13 @@ WebInspector.TabbedEditorContainer.prototype = { this._tabIds.put(uiSourceCode, tabId); this._files[tabId] = uiSourceCode; + var savedScrollLineNumber = this._history.scrollLineNumber(uiSourceCode.url); + if (savedScrollLineNumber) + view.scrollToLine(savedScrollLineNumber); + var savedSelectionRange = this._history.selectionRange(uiSourceCode.url); + if (savedSelectionRange) + view.setSelection(savedSelectionRange); + this._tabbedPane.appendTab(tabId, title, view, tooltip, userGesture); uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.TitleChanged, this._uiSourceCodeTitleChanged, this); @@ -252,6 +293,7 @@ WebInspector.TabbedEditorContainer.prototype = { var tabId = /** @type {string} */ event.data.tabId; var userGesture = /** @type {boolean} */ event.data.isUserGesture; + this._removeScrollAndSelectionListeners(); var uiSourceCode = this._files[tabId]; this._tabIds.remove(uiSourceCode); delete this._files[tabId]; @@ -361,19 +403,122 @@ WebInspector.TabbedEditorContainer.prototype.__proto__ = WebInspector.Object.pro /** * @constructor + * @param {string} url + * @param {WebInspector.TextRange=} selectionRange + * @param {number=} scrollLineNumber + */ +WebInspector.TabbedEditorContainer.HistoryItem = function(url, selectionRange, scrollLineNumber) +{ + this.url = url; + this.selectionRange = selectionRange; + this.scrollLineNumber = scrollLineNumber; +} + +/** + * @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() + { + var serializedHistoryItem = {}; + serializedHistoryItem.url = this.url; + serializedHistoryItem.selectionRange = this.selectionRange; + serializedHistoryItem.scrollLineNumber = this.scrollLineNumber; + return serializedHistoryItem; + } +} + +WebInspector.TabbedEditorContainer.HistoryItem.prototype.__proto__ = WebInspector.Object.prototype; + +/** + * @constructor + * @param {Array.} items */ -WebInspector.TabbedEditorContainer.History = function(urls) +WebInspector.TabbedEditorContainer.History = function(items) { - this._urls = urls; + this._items = items; +} + +/** + * @param {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) { - return this._urls.indexOf(url); + for (var i = 0; i < this._items.length; ++i) { + if (this._items[i].url === url) + return i; + } + return -1; + }, + + /** + * @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; }, /** @@ -382,10 +527,14 @@ WebInspector.TabbedEditorContainer.History.prototype = { update: function(urls) { for (var i = urls.length - 1; i >= 0; --i) { - var index = this._urls.indexOf(urls[i]); - if (index !== -1) - this._urls.splice(index, 1); - this._urls.unshift(urls[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); } }, @@ -394,9 +543,9 @@ WebInspector.TabbedEditorContainer.History.prototype = { */ remove: function(url) { - var index = this._urls.indexOf(url); + var index = this.index(url); if (index !== -1) - this._urls.splice(index, 1); + this._items.splice(index, 1); }, /** @@ -404,7 +553,18 @@ WebInspector.TabbedEditorContainer.History.prototype = { */ save: function(setting) { - setting.set(this._urls); + setting.set(this._serializeToObject()); + }, + + /** + * @return {Object} + */ + _serializeToObject: function() + { + var serializedHistory = []; + for (var i = 0; i < this._items.length; ++i) + serializedHistory.push(this._items[i].serializeToObject()); + return serializedHistory; } } diff --git a/Source/WebCore/inspector/front-end/TextEditor.js b/Source/WebCore/inspector/front-end/TextEditor.js index 88314e6..00e2380 100644 --- a/Source/WebCore/inspector/front-end/TextEditor.js +++ b/Source/WebCore/inspector/front-end/TextEditor.js @@ -55,6 +55,10 @@ WebInspector.TextEditor = function(textModel, url, delegate) var syncLineHeightListener = this._syncLineHeight.bind(this); this._mainPanel = new WebInspector.TextEditorMainPanel(this._textModel, url, syncScrollListener, syncDecorationsForLineListener, enterTextChangeMode, exitTextChangeMode); this._gutterPanel = new WebInspector.TextEditorGutterPanel(this._textModel, syncDecorationsForLineListener, syncLineHeightListener); + + this._mainPanel.element.addEventListener("scroll", this._handleScrollChanged.bind(this), false); + this._mainPanel._container.addEventListener("focus", this._handleFocused.bind(this), false); + this.element.appendChild(this._mainPanel.element); this.element.appendChild(this._gutterPanel.element); @@ -355,6 +359,29 @@ WebInspector.TextEditor.prototype = { return true; }, + _handleScrollChanged: function(event) + { + var visibleFrom = this._mainPanel.element.scrollTop; + var firstVisibleLineNumber = this._mainPanel._findFirstVisibleLineNumber(visibleFrom); + this._delegate.scrollChanged(firstVisibleLineNumber); + }, + + /** + * @param {number} lineNumber + */ + scrollToLine: function(lineNumber) + { + this._mainPanel.scrollToLine(lineNumber); + }, + + _handleSelectionChange: function(event) + { + var textRange = this._mainPanel._getSelection(); + if (textRange) + this._lastSelection = textRange; + this._delegate.selectionChanged(textRange); + }, + /** * @return {WebInspector.TextRange} */ @@ -368,6 +395,7 @@ WebInspector.TextEditor.prototype = { */ setSelection: function(textRange) { + this._lastSelection = textRange; this._mainPanel._restoreSelection(textRange); }, @@ -375,10 +403,26 @@ WebInspector.TextEditor.prototype = { { if (!this.readOnly()) WebInspector.markBeingEdited(this.element, true); + + this._boundSelectionChangeListener = this._handleSelectionChange.bind(this); + document.addEventListener("selectionchange", this._boundSelectionChangeListener, false); + }, + + _handleFocused: function() + { + if (this._lastSelection) { + // We do not restore selection after focus lost to avoid selection blinking. We restore only cursor position instead. + // FIXME: consider adding selection decoration to blurred editor. + var newSelection = WebInspector.TextRange.createFromLocation(this._lastSelection.endLine, this._lastSelection.endColumn); + this.setSelection(newSelection); + } }, willHide: function() { + document.removeEventListener("selectionchange", this._boundSelectionChangeListener, false); + delete this._boundSelectionChangeListener; + if (!this.readOnly()) WebInspector.markBeingEdited(this.element, false); } @@ -405,6 +449,16 @@ WebInspector.TextEditorDelegate.prototype = { commitEditing: function() { }, /** + * @param {WebInspector.TextRange} textRange + */ + selectionChanged: function(textRange) { }, + + /** + * @param {number} lineNumber + */ + scrollChanged: function(lineNumber) { }, + + /** * @param {WebInspector.ContextMenu} contextMenu * @param {number} lineNumber */ @@ -442,6 +496,18 @@ WebInspector.TextEditorChunkedPanel.prototype = { /** * @param {number} lineNumber */ + scrollToLine: function(lineNumber) + { + if (lineNumber >= this._textModel.linesCount) + return; + + var chunk = this.makeLineAChunk(lineNumber); + this.element.scrollTop = chunk.offsetTop; + }, + + /** + * @param {number} lineNumber + */ revealLine: function(lineNumber) { if (lineNumber >= this._textModel.linesCount) diff --git a/Source/WebCore/inspector/front-end/TextEditorModel.js b/Source/WebCore/inspector/front-end/TextEditorModel.js index c86adb5..c237a66 100644 --- a/Source/WebCore/inspector/front-end/TextEditorModel.js +++ b/Source/WebCore/inspector/front-end/TextEditorModel.js @@ -48,6 +48,15 @@ WebInspector.TextRange.createFromLocation = function(line, column) return new WebInspector.TextRange(line, column, line, column); } +/** + * @param {Object} serializedTextRange + * @return {WebInspector.TextRange} + */ +WebInspector.TextRange.fromObject = function (serializedTextRange) +{ + return new WebInspector.TextRange(serializedTextRange.startLine, serializedTextRange.startColumn, serializedTextRange.endLine, serializedTextRange.endColumn); +} + WebInspector.TextRange.prototype = { /** * @return {boolean} @@ -87,6 +96,19 @@ WebInspector.TextRange.prototype = { clone: function() { return new WebInspector.TextRange(this.startLine, this.startColumn, this.endLine, this.endColumn); + }, + + /** + * @return {Object} + */ + serializeToObject: function() + { + var serializedTextRange = {}; + serializedTextRange.startLine = this.startLine; + serializedTextRange.startColumn = this.startColumn; + serializedTextRange.endLine = this.endLine; + serializedTextRange.endColumn = this.endColumn; + return serializedTextRange; } } -- 2.7.4