Changeset 156809 in webkit


Ignore:
Timestamp:
Oct 2, 2013 4:33:14 PM (11 years ago)
Author:
commit-queue@webkit.org
Message:

Web Inspector: save and restore source positions in back/forward history
https://bugs.webkit.org/show_bug.cgi?id=122062

Patch by Brian J. Burg <Brian Burg> on 2013-10-02
Reviewed by Timothy Hatcher.

Previously, the back/forward entries comprised of only the content
views, but not their positions if navigated via hyperlink (i.e.,
handling script.js:42). When multiple instances of the same
content view appeared in the back/forward list, the most recent
navigation was displayed rather than the linked position.

We now store context necessary to re-navigate such hyperlinks by
storing view- specific data inside a cookie object, and invoke a
supplied callback to take any position initialization actions,
such as calling TextEditor.revealPosition. This state is
encapsulated into BackForwardEntry instances.

Functions that save and restore scroll positions inside content
views have been changed to store state in BackForwardEntry
instances, so multiple scroll positions can be saved for a content
view appearing in the navigation history more than once.

  • UserInterface/BackForwardEntry.js: Added.

(WebInspector.BackForwardEntry):
(WebInspector.BackForwardEntry.prototype.get contentView):
(WebInspector.BackForwardEntry.prototype.get cookie):
(WebInspector.BackForwardEntry.prototype.prepareToShow):
(WebInspector.BackForwardEntry.prototype.prepareToHide):
(WebInspector.BackForwardEntry.prototype._restoreFromCookie):
(WebInspector.BackForwardEntry.prototype._restoreScrollPositions):
(WebInspector.BackForwardEntry.prototype._saveScrollPositions):

  • UserInterface/ContentBrowser.js:

(WebInspector.ContentBrowser.prototype.showContentView):
(WebInspector.ContentBrowser.prototype._updateContentViewNavigationItems):
(WebInspector.ContentBrowser.prototype._updateFindBanner):

  • UserInterface/ContentViewContainer.js:

(WebInspector.ContentViewContainer.prototype.get currentContentView):
(WebInspector.ContentViewContainer.prototype.get currentBackForwardEntry):
(WebInspector.ContentViewContainer.prototype.showContentView):
(WebInspector.ContentViewContainer.prototype.showBackForwardEntryForIndex):
(WebInspector.ContentViewContainer.prototype.replaceContentView):
(WebInspector.ContentViewContainer.prototype.closeAllContentViewsOfPrototype):
(WebInspector.ContentViewContainer.prototype.closeAllContentViews):
(WebInspector.ContentViewContainer.prototype.goBack):
(WebInspector.ContentViewContainer.prototype.goForward):
(WebInspector.ContentViewContainer.prototype.shown):
(WebInspector.ContentViewContainer.prototype.hidden):
(WebInspector.ContentViewContainer.prototype._showEntry):
(WebInspector.ContentViewContainer.prototype._hideEntry):

  • UserInterface/Main.html:
  • UserInterface/Main.js:

(WebInspector.openURL):

  • UserInterface/ResourceSidebarPanel.js:

(WebInspector.ResourceSidebarPanel.prototype.restoreCallback):
(WebInspector.ResourceSidebarPanel.prototype.showSourceCode):

Location:
trunk/Source/WebInspectorUI
Files:
1 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebInspectorUI/ChangeLog

    r156765 r156809  
     12013-10-02  Brian J. Burg  <burg@cs.washington.edu>
     2
     3        Web Inspector: save and restore source positions in back/forward history
     4        https://bugs.webkit.org/show_bug.cgi?id=122062
     5
     6        Reviewed by Timothy Hatcher.
     7
     8        Previously, the back/forward entries comprised of only the content
     9        views, but not their positions if navigated via hyperlink (i.e.,
     10        handling script.js:42).  When multiple instances of the same
     11        content view appeared in the back/forward list, the most recent
     12        navigation was displayed rather than the linked position.
     13
     14        We now store context necessary to re-navigate such hyperlinks by
     15        storing view- specific data inside a cookie object, and invoke a
     16        supplied callback to take any position initialization actions,
     17        such as calling TextEditor.revealPosition.  This state is
     18        encapsulated into BackForwardEntry instances.
     19
     20        Functions that save and restore scroll positions inside content
     21        views have been changed to store state in BackForwardEntry
     22        instances, so multiple scroll positions can be saved for a content
     23        view appearing in the navigation history more than once.
     24
     25        * UserInterface/BackForwardEntry.js: Added.
     26        (WebInspector.BackForwardEntry):
     27        (WebInspector.BackForwardEntry.prototype.get contentView):
     28        (WebInspector.BackForwardEntry.prototype.get cookie):
     29        (WebInspector.BackForwardEntry.prototype.prepareToShow):
     30        (WebInspector.BackForwardEntry.prototype.prepareToHide):
     31        (WebInspector.BackForwardEntry.prototype._restoreFromCookie):
     32        (WebInspector.BackForwardEntry.prototype._restoreScrollPositions):
     33        (WebInspector.BackForwardEntry.prototype._saveScrollPositions):
     34        * UserInterface/ContentBrowser.js:
     35        (WebInspector.ContentBrowser.prototype.showContentView):
     36        (WebInspector.ContentBrowser.prototype._updateContentViewNavigationItems):
     37        (WebInspector.ContentBrowser.prototype._updateFindBanner):
     38        * UserInterface/ContentViewContainer.js:
     39        (WebInspector.ContentViewContainer.prototype.get currentContentView):
     40        (WebInspector.ContentViewContainer.prototype.get currentBackForwardEntry):
     41        (WebInspector.ContentViewContainer.prototype.showContentView):
     42        (WebInspector.ContentViewContainer.prototype.showBackForwardEntryForIndex):
     43        (WebInspector.ContentViewContainer.prototype.replaceContentView):
     44        (WebInspector.ContentViewContainer.prototype.closeAllContentViewsOfPrototype):
     45        (WebInspector.ContentViewContainer.prototype.closeAllContentViews):
     46        (WebInspector.ContentViewContainer.prototype.goBack):
     47        (WebInspector.ContentViewContainer.prototype.goForward):
     48        (WebInspector.ContentViewContainer.prototype.shown):
     49        (WebInspector.ContentViewContainer.prototype.hidden):
     50        (WebInspector.ContentViewContainer.prototype._showEntry):
     51        (WebInspector.ContentViewContainer.prototype._hideEntry):
     52        * UserInterface/Main.html:
     53        * UserInterface/Main.js:
     54        (WebInspector.openURL):
     55        * UserInterface/ResourceSidebarPanel.js:
     56        (WebInspector.ResourceSidebarPanel.prototype.restoreCallback):
     57        (WebInspector.ResourceSidebarPanel.prototype.showSourceCode):
     58
    1592013-10-02  Antoine Quint  <graouts@apple.com>
    260
  • trunk/Source/WebInspectorUI/UserInterface/ContentBrowser.js

    r156198 r156809  
    158158    },
    159159
    160     showContentView: function(contentView)
    161     {
    162         return this._contentViewContainer.showContentView(contentView);
     160    showContentView: function(contentView, cookie, restoreCallback)
     161    {
     162        return this._contentViewContainer.showContentView(contentView, cookie, restoreCallback);
    163163    },
    164164
     
    412412        // Go through each of the items of the new content view and add a divider before them.
    413413        currentContentView.navigationItems.forEach(function(navigationItem, index) {
    414             // Add dividers before items unless it's the first item and not a button. 
     414            // Add dividers before items unless it's the first item and not a button.
    415415            if (index !== 0 || navigationItem instanceof WebInspector.ButtonNavigationItem) {
    416416                var divider = new WebInspector.DividerNavigationItem;
     
    434434            return;
    435435        }
    436        
     436
    437437        this._findBanner.targetElement = currentContentView.element;
    438438        this._findBanner.numberOfResults = currentContentView.hasPerformedSearch ? currentContentView.numberOfSearchResults : null;
  • trunk/Source/WebInspectorUI/UserInterface/ContentViewContainer.js

    r156727 r156809  
    6565        if (this._currentIndex < 0 || this._currentIndex > this._backForwardList.length - 1)
    6666            return null;
     67        return this._backForwardList[this._currentIndex].contentView;
     68    },
     69
     70    get currentBackForwardEntry()
     71    {
     72        if (this._currentIndex < 0 || this._currentIndex > this._backForwardList.length - 1)
     73            return null;
    6774        return this._backForwardList[this._currentIndex];
    6875    },
     
    127134    },
    128135
    129     showContentView: function(contentView)
     136    showContentView: function(contentView, cookie, restoreCallback)
    130137    {
    131138        console.assert(contentView instanceof WebInspector.ContentView);
     
    139146            return null;
    140147
    141         // Don't do anything if the content view is already the current content view.
    142         var currentContentView = this.currentContentView;
    143         if (currentContentView === contentView)
    144             return contentView;
     148        var currentEntry = this.currentBackForwardEntry;
     149        var provisionalEntry = new WebInspector.BackForwardEntry(contentView, cookie, restoreCallback);
     150        // Don't do anything if we would have added an identical back/forward list entry.
     151        if (currentEntry && currentEntry.contentView === contentView && Object.shallowEqual(provisionalEntry.cookie, currentEntry.cookie))
     152            return currentEntry.contentView;
    145153
    146154        // Showing a content view will truncate the back/forward list after the current index and insert the content view
     
    151159
    152160        // Insert the content view at the new index. This will remove any content views greater than or equal to the index.
    153         var removedItems = this._backForwardList.splice(newIndex, this._backForwardList.length - newIndex, contentView);
     161        var removedEntries = this._backForwardList.splice(newIndex, this._backForwardList.length - newIndex, provisionalEntry);
    154162
    155163        console.assert(newIndex === this._backForwardList.length - 1);
    156         console.assert(this._backForwardList[newIndex] === contentView);
     164        console.assert(this._backForwardList[newIndex] === provisionalEntry);
    157165
    158166        // Disassociate with the removed content views.
    159         for (var i = 0; i < removedItems.length; ++i) {
     167        for (var i = 0; i < removedEntries.length; ++i) {
    160168            // Skip disassociation if this content view is still in the back/forward list.
    161             if (this._backForwardList.contains(removedItems[i]))
    162                 continue;
    163 
    164             this._disassociateFromContentView(removedItems[i]);
     169            var shouldDissociateContentView = this._backForwardList.some(function(existingEntry) {
     170                return existingEntry.contentView === removedEntries[i].contentView;
     171            });
     172            if (shouldDissociateContentView)
     173                this._disassociateFromContentView(removedEntries[i]);
    165174        }
    166175
     
    168177        contentView._parentContainer = this;
    169178
    170         this.showBackForwardEntry(newIndex);
     179        this.showBackForwardEntryForIndex(newIndex);
    171180
    172181        return contentView;
    173182    },
    174183
    175     showBackForwardEntry: function(index)
     184    showBackForwardEntryForIndex: function(index)
    176185    {
    177186        console.assert(index >= 0 && index <= this._backForwardList.length - 1);
     
    183192
    184193        // Hide the currently visible content view.
    185         var currentContentView = this.currentContentView;
    186         if (currentContentView)
    187             this._hideContentView(currentContentView);
     194        var previousEntry = this.currentBackForwardEntry;
     195        if (previousEntry)
     196            this._hideEntry(previousEntry);
    188197
    189198        this._currentIndex = index;
    190 
    191         this._showContentView(this.currentContentView);
     199        var currentEntry = this.currentBackForwardEntry;
     200        console.assert(currentEntry);
     201
     202        this._showEntry(currentEntry);
    192203
    193204        this.dispatchEventToListeners(WebInspector.ContentViewContainer.Event.CurrentContentViewDidChange);
     
    214225        var currentlyShowing = (this.currentContentView === oldContentView);
    215226        if (currentlyShowing)
    216             this._hideContentView(oldContentView);
     227            this._hideEntry(this.currentBackForwardEntry);
    217228
    218229        // Disassociate with the old content view.
     
    224235        // Replace all occurrences of oldContentView with newContentView in the back/forward list.
    225236        for (var i = 0; i < this._backForwardList.length; ++i) {
    226             if (this._backForwardList[i] === oldContentView)
    227                 this._backForwardList[i] = newContentView;
    228         }
    229 
     237            if (this._backForwardList[i].contentView === oldContentView)
     238                this._backForwardList[i].contentView = newContentView;
     239        }
     240
     241        // Re-show the current entry, because its content view instance was replaced.
    230242        if (currentlyShowing) {
    231             this._showContentView(newContentView);
     243            this._showEntry(this.currentBackForwardEntry);
    232244            this.dispatchEventToListeners(WebInspector.ContentViewContainer.Event.CurrentContentViewDidChange);
    233245        }
     
    245257        var allSamePrototype = true;
    246258        for (var i = this._backForwardList.length - 1; i >= 0; --i) {
    247             if (!(this._backForwardList[i] instanceof constructor)) {
     259            if (!(this._backForwardList[i].contentView instanceof constructor)) {
    248260                allSamePrototype = false;
    249261                break;
     
    261273        // Hide and disassociate with all the content views that are instances of the constructor.
    262274        for (var i = this._backForwardList.length - 1; i >= 0; --i) {
    263             var contentView = this._backForwardList[i];
    264             if (!(contentView instanceof constructor))
     275            var entry = this._backForwardList[i];
     276            if (!(entry.contentView instanceof constructor))
    265277                continue;
    266278
    267             if (contentView === oldCurrentContentView)
    268                 this._hideContentView(contentView);
     279            if (entry.contentView === oldCurrentContentView)
     280                this._hideEntry(entry);
    269281
    270282            if (this._currentIndex >= i) {
     
    274286            }
    275287
    276             this._disassociateFromContentView(contentView);
     288            this._disassociateFromContentView(entry.contentView);
    277289
    278290            // Remove the item from the back/forward list.
     
    281293        }
    282294
    283         var currentContentView = this.currentContentView;
    284         console.assert(currentContentView || (!currentContentView && this._currentIndex === -1));
    285 
    286         if (currentContentView && (currentContentView !== oldCurrentContentView || backForwardListDidChange)) {
    287             this._showContentView(currentContentView);
     295        var currentEntry = this.currentBackForwardEntry;
     296        console.assert(currentEntry || (!currentEntry && this._currentIndex === -1));
     297
     298        if (currentEntry && currentEntry.contentView !== oldCurrentContentView || backForwardListDidChange) {
     299            this._showEntry(currentEntry);
    288300            this.dispatchEventToListeners(WebInspector.ContentViewContainer.Event.CurrentContentViewDidChange);
    289301        }
     
    299311        // Hide and disassociate with all the content views.
    300312        for (var i = 0; i < this._backForwardList.length; ++i) {
    301             var contentView = this._backForwardList[i];
     313            var entry = this._backForwardList[i];
    302314            if (i === this._currentIndex)
    303                 this._hideContentView(contentView);
    304             this._disassociateFromContentView(contentView);
     315                this._hideEntry(entry);
     316            this._disassociateFromContentView(entry.contentView);
    305317        }
    306318
     
    325337        if (!this.canGoBack())
    326338            return;
    327         this.showBackForwardEntry(this._currentIndex - 1);
     339        this.showBackForwardEntryForIndex(this._currentIndex - 1);
    328340    },
    329341
     
    332344        if (!this.canGoForward())
    333345            return;
    334         this.showBackForwardEntry(this._currentIndex + 1);
     346        this.showBackForwardEntryForIndex(this._currentIndex + 1);
    335347    },
    336348
    337349    shown: function()
    338350    {
    339         var currentContentView = this.currentContentView;
    340         if (!currentContentView)
    341             return;
    342 
    343         this._showContentView(currentContentView);
     351        var currentEntry = this.currentBackForwardEntry;
     352        if (!currentEntry)
     353            return;
     354
     355        this._showEntry(currentEntry);
    344356    },
    345357
    346358    hidden: function()
    347359    {
    348         var currentContentView = this.currentContentView;
    349         if (!currentContentView)
    350             return;
    351 
    352         this._hideContentView(currentContentView);
     360        var currentEntry = this.currentBackForwardEntry;
     361        if (!currentEntry)
     362            return;
     363
     364        this._hideEntry(currentEntry);
    353365    },
    354366
     
    382394    },
    383395
    384     _saveScrollPositionsForContentView: function(contentView)
    385     {
    386         var scrollableElements = contentView.scrollableElements || [];
    387         for (var i = 0; i < scrollableElements.length; ++i) {
    388             var element = scrollableElements[i];
    389             if (!element)
    390                 continue;
    391             if (contentView.shouldKeepElementsScrolledToBottom)
    392                 element._savedIsScrolledToBottom = element.isScrolledToBottom();
    393             element._savedScrollTop = element.scrollTop;
    394             element._savedScrollLeft = element.scrollLeft;
    395         }
    396     },
    397 
    398     _restoreScrollPositionsForContentView: function(contentView)
    399     {
    400         var scrollableElements = contentView.scrollableElements || [];
    401         for (var i = 0; i < scrollableElements.length; ++i) {
    402             var element = scrollableElements[i];
    403             if (!element)
    404                 continue;
    405 
    406             // Restore the top scroll position by either scrolling to the bottom or to the saved position.
    407             element.scrollTop = element._savedIsScrolledToBottom ? element.scrollHeight : element._savedScrollTop;
    408 
    409             // Don't restore the left scroll position when scrolled to the bottom. This way the when content changes
    410             // the user won't be left in a weird horizontal position.
    411             element.scrollLeft = element._savedIsScrolledToBottom ? 0 : element._savedScrollLeft;
    412         }
    413     },
    414 
    415     _showContentView: function(contentView)
    416     {
    417         if (contentView.visible)
    418             return;
    419 
    420         this._addContentViewElement(contentView);
    421 
    422         this._prepareContentViewToShow(contentView);
    423     },
    424 
    425     _prepareContentViewToShow: function(contentView)
    426     {
    427         this._restoreScrollPositionsForContentView(contentView);
    428 
    429         contentView.visible = true;
    430         contentView.shown();
    431         contentView.updateLayout();
    432     },
    433 
    434     _hideContentView: function(contentView)
    435     {
    436         if (!contentView.visible)
    437             return;
    438 
    439         this._prepareContentViewToHide(contentView);
    440 
    441         this._removeContentViewElement(contentView);
    442     },
    443 
    444     _prepareContentViewToHide: function(contentView)
    445     {
    446         contentView.visible = false;
    447         contentView.hidden();
    448 
    449         this._saveScrollPositionsForContentView(contentView);
     396    _showEntry: function(entry)
     397    {
     398        console.assert(entry instanceof WebInspector.BackForwardEntry);
     399
     400        this._addContentViewElement(entry.contentView);
     401        entry.prepareToShow();
     402    },
     403
     404    _hideEntry: function(entry)
     405    {
     406        console.assert(entry instanceof WebInspector.BackForwardEntry);
     407
     408        entry.prepareToHide();
     409        this._removeContentViewElement(entry.contentView);
    450410    }
    451411};
  • trunk/Source/WebInspectorUI/UserInterface/Main.html

    r155134 r156809  
    240240    <script src="EventHandler.js"></script>
    241241    <script src="SourceCodeTextEditor.js"></script>
     242    <script src="BackForwardEntry.js"></script>
    242243    <script src="ContentViewContainer.js"></script>
    243244    <script src="ContentView.js"></script>
  • trunk/Source/WebInspectorUI/UserInterface/Main.js

    r156198 r156809  
    512512    var resource = frame.url === url ? frame.mainResource : frame.resourceForURL(url, searchChildFrames);
    513513    if (resource) {
    514         this.resourceSidebarPanel.showSourceCode(resource, lineNumber);
     514        var position = new WebInspector.SourceCodePosition(lineNumber, 0);
     515        this.resourceSidebarPanel.showSourceCode(resource, position);
    515516        return;
    516517    }
  • trunk/Source/WebInspectorUI/UserInterface/ResourceSidebarPanel.js

    r156198 r156809  
    249249    showSourceCode: function(sourceCode, positionToReveal, textRangeToSelect, forceUnformatted)
    250250    {
     251        console.assert(!positionToReveal || positionToReveal instanceof WebInspector.SourceCodePosition, positionToReveal);
    251252        var representedObject = sourceCode;
    252253
     
    260261            representedObject = representedObject.parentFrame;
    261262
    262         var contentView = WebInspector.contentBrowser.contentViewForRepresentedObject(representedObject);
    263 
    264         if (contentView instanceof WebInspector.FrameContentView)
    265             contentView.showSourceCode(positionToReveal, textRangeToSelect, forceUnformatted);
    266         else if (contentView instanceof WebInspector.ResourceClusterContentView)
    267             contentView.showResponse(positionToReveal, textRangeToSelect, forceUnformatted);
    268         else if (contentView instanceof WebInspector.ScriptContentView)
    269             contentView.revealPosition(positionToReveal, textRangeToSelect, forceUnformatted);
    270 
    271         WebInspector.contentBrowser.showContentView(contentView);
     263        var newContentView = WebInspector.contentBrowser.contentViewForRepresentedObject(representedObject);
     264        var cookie = {lineNumber: positionToReveal.lineNumber, columnNumber: positionToReveal.columnNumber};
     265
     266        var restoreCallback = function(contentView, savedCookie) {
     267            var lineNumber = savedCookie.lineNumber;
     268            var columnNumber = savedCookie.columnNumber;
     269            var position = new WebInspector.SourceCodePosition(lineNumber, columnNumber);
     270
     271            if (contentView instanceof WebInspector.FrameContentView)
     272                contentView.showSourceCode(position)
     273            else if (contentView instanceof WebInspector.ResourceClusterContentView)
     274                contentView.showResponse(position)
     275            else if (contentView instanceof WebInspector.ScriptContentView)
     276                contentView.revealPosition(position)
     277        };
     278
     279        WebInspector.contentBrowser.showContentView(newContentView, cookie, restoreCallback);
    272280    },
    273281
Note: See TracChangeset for help on using the changeset viewer.