Web Inspector: restore navigation panel state across reloads and reopens

https://bugs.webkit.org/show_bug.cgi?id=122125

Patch by Brian J. Burg <burg@cs.washington.edu> on 2013-12-03
Reviewed by Timothy Hatcher.

The previous strategy for restoring content views after inspector
re-open did not consider the active sidebar and its selection, and
tried to recreate the appropriate selection from the saved content
view. However, doesn't work for tree elements in the sidebar panel
that don't change views when selected, such as script breakpoints,
special breakpoints, call stack, timeline sections, etc.

This patch implements a new strategy that saves the navigation
sidebar panel's view state by serializing the identity of the
selected element's represented object. Relevant represented
object classes implement the saveIdentityToCookie() method. Each
represented object class also adds a TypeIdentifier property to
its constructor, to aid inexact matching based on represented
object type, rather than its complete identity.

When restoring, the navigation sidebar attempts to match added
tree elements against the pending cookie, and selects the element
if it matches. A represented object matches if its serialized
identity matches the previously saved serialized identity.

The inspector view state is now only saved on the page hide event
(for saving across reopen) and when the main frame commits its
provisional load (for saving across same-page reloads). It
consolidates similar view state settings into a single setting.

* UserInterface/ApplicationCacheFrame.js:
(WebInspector.ApplicationCacheFrame): Add cookie keys and type identifier.
(WebInspector.ApplicationCacheFrame.prototype.saveIdentityToCookie): Added.
* UserInterface/ApplicationCacheManager.js: remove objectForCookie().
* UserInterface/Breakpoint.js:
(WebInspector.Breakpoint): Add cookie keys and type identifier.
(WebInspector.Breakpoint.prototype.saveIdentityToCookie):
* UserInterface/CookieStorageObject.js:
(WebInspector.CookieStorageObject.prototype.saveIdentityToCookie): Added.
* UserInterface/DOMStorageObject.js:
(WebInspector.DOMStorageObject): Add cookie keys and type identifier.
(WebInspector.DOMStorageObject.prototype.saveIdentityToCookie): Added.
* UserInterface/DatabaseObject.js:
(WebInspector.DatabaseObject): Add cookie keys and type identifier.
(WebInspector.DatabaseObject.prototype.saveIdentityToCookie): Added.
* UserInterface/DatabaseTableObject.js:
(WebInspector.DatabaseTableObject): Add cookie keys and type identifier.
(WebInspector.DatabaseTableObject.prototype.saveIdentityToCookie): Added.
* UserInterface/DebuggerSidebarPanel.js:
(WebInspector.DebuggerSidebarPanel.prototype.saveStateToCookie): Added.
(WebInspector.DebuggerSidebarPanel.prototype.restoreStateFromCookie): Added.
* UserInterface/Frame.js:
(WebInspector.Frame): Add cookie keys and type identifier.
(WebInspector.Frame.prototype.saveIdentityToCookie): Added.
* UserInterface/FrameResourceManager.js: remove objectForCookie().
* UserInterface/InstrumentSidebarPanel.js:
(WebInspector.InstrumentSidebarPanel.prototype.showTimelineForRecordType):
Return the shown timeline, if any.

(WebInspector.InstrumentSidebarPanel.prototype.saveStateToCookie): Added.
(WebInspector.InstrumentSidebarPanel.prototype.restoreStateFromCookie): Added.
(WebInspector.InstrumentSidebarPanel.prototype.showProfile):
Return the shown profile, if any.

* UserInterface/Main.js:
(WebInspector): Added cookie keys for the selected sidebar and
typeidentifier of the sidebar's selected tree element.

(WebInspector.contentLoaded): Remove callbacks for
resolveAndShowPendingContentViewCookie(). Consolidate all saved
inspector view state into one Setting. Move special-cased
restoring of the console to the restoration method. Move saving
of last opened navigation panel to the saving method.

(WebInspector._mainResourceDidChange): Try to restore saved view
state when the main resource changes.

(WebInspector._provisionalLoadCommitted): Update the saved view
state when the navigation commits. This is the last chance to save
it before the main resource changes and the navigation panel view
state is discarded and rebuilt.

(WebInspector._pageHidden): Update the saved view state when the
inspector page is hidden, but before state is discarded.

(WebInspector._navigationSidebarPanelSelected): Don't save last
navigation sidebar panel.
(WebInspector._updateCookieForInspectorViewState): Renamed from
_updateCurrentContentViewCookie. It delegates view state
serialization to the currently open navigation sidebar, rather
than the current content view.

(WebInspector._contentBrowserRepresentedObjectsDidChange): Don't
spuriously serialize the current view state cookie on every
ContentView change.

(WebInspector._restoreInspectorViewStateFromCookie): Renamed from
_showContentViewForCookie. It now restores a specific navigation
panel and delegates remaining view state restoration to the panel
itself. Last-resort selection of any tree element with the same
type identifier was moved to the navigation panel's restore method.

* UserInterface/NavigationSidebarPanel.js:
(WebInspector.NavigationSidebarPanel):
(WebInspector.NavigationSidebarPanel.prototype.set contentTreeOutline):
(WebInspector.NavigationSidebarPanel.prototype.createContentTreeOutline):
Save references to all created TreeOutlines in a Set, so we can
restore any tree's selection.

(WebInspector.NavigationSidebarPanel.prototype.saveStateToCookie):
Added. Find the selected tree element from all tree outlines and
ask it to serialize its identity.

(WebInspector.NavigationSidebarPanel.prototype.restoreStateFromCookie):
Added. Eagerly search existing tree elements for a matching
representedObject. If none exists, save the pending cookie and
schedule last-resort matching using the provided timeout interval.

(WebInspector.NavigationSidebarPanel.prototype._treeElementAddedOrChanged):
Check if the added tree element matches a pending view state
cookie, if one exists.

(WebInspector.NavigationSidebarPanel.prototype.treeElementMatchesCookie):
Added. Check if the tree element's representedObject matches the
pending view state cookie.

(WebInspector.NavigationSidebarPanel.prototype._checkElementsForPendingViewStateCookie):
Added. For each provided tree element, check if the tree
element's represented object produces the same serialized identity
as the pending view state cookie that we are trying to resolve.
If a match is found (possibly by relaxing to matching anything
with the same type), select the tree element and clear both the
pending view state cookie and last-resort selection timer.

* UserInterface/Resource.js:
(WebInspector.Resource): Add cookie keys and type identifier.
(WebInspector.Resource.prototype.saveIdentityToCookie): Added.

* UserInterface/ResourceClusterContentView.js:
(WebInspector.ResourceClusterContentView.prototype.saveToCookie):
(WebInspector.ResourceClusterContentView.prototype.restoreFromCookie):
Since identity state is serialized by the representedObject, these
methods only need to save view-specific state, such as the visible
subview. Remove extraneous state.

* UserInterface/Script.js:
(WebInspector.Script): Add cookie keys and type identifier.
(WebInspector.Script.prototype.saveIdentityToCookie): Added.
* UserInterface/StorageManager.js: remove objectForCookie().
* UserInterface/TimelineManager.js: remove objectForCookie().
* UserInterface/TimelinesContentView.js:
(WebInspector.TimelinesContentView.prototype.saveToCookie):
(WebInspector.TimelinesContentView.prototype.restoreFromCookie):
Since identity state is serialized by the representedObject, these
methods only need to save view-specific state, such as the visible
subview. Remove extraneous state.

* UserInterface/TreeOutline.js: Add TreeOutline.prototype.constructor
so other code can assume the constructor property exists.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@160025 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 55fa369e
2013-12-03 Brian J. Burg <burg@cs.washington.edu>
Web Inspector: restore navigation panel state across reloads and reopens
https://bugs.webkit.org/show_bug.cgi?id=122125
Reviewed by Timothy Hatcher.
The previous strategy for restoring content views after inspector
re-open did not consider the active sidebar and its selection, and
tried to recreate the appropriate selection from the saved content
view. However, doesn't work for tree elements in the sidebar panel
that don't change views when selected, such as script breakpoints,
special breakpoints, call stack, timeline sections, etc.
This patch implements a new strategy that saves the navigation
sidebar panel's view state by serializing the identity of the
selected element's represented object. Relevant represented
object classes implement the saveIdentityToCookie() method. Each
represented object class also adds a TypeIdentifier property to
its constructor, to aid inexact matching based on represented
object type, rather than its complete identity.
When restoring, the navigation sidebar attempts to match added
tree elements against the pending cookie, and selects the element
if it matches. A represented object matches if its serialized
identity matches the previously saved serialized identity.
The inspector view state is now only saved on the page hide event
(for saving across reopen) and when the main frame commits its
provisional load (for saving across same-page reloads). It
consolidates similar view state settings into a single setting.
* UserInterface/ApplicationCacheFrame.js:
(WebInspector.ApplicationCacheFrame): Add cookie keys and type identifier.
(WebInspector.ApplicationCacheFrame.prototype.saveIdentityToCookie): Added.
* UserInterface/ApplicationCacheManager.js: remove objectForCookie().
* UserInterface/Breakpoint.js:
(WebInspector.Breakpoint): Add cookie keys and type identifier.
(WebInspector.Breakpoint.prototype.saveIdentityToCookie):
* UserInterface/CookieStorageObject.js:
(WebInspector.CookieStorageObject.prototype.saveIdentityToCookie): Added.
* UserInterface/DOMStorageObject.js:
(WebInspector.DOMStorageObject): Add cookie keys and type identifier.
(WebInspector.DOMStorageObject.prototype.saveIdentityToCookie): Added.
* UserInterface/DatabaseObject.js:
(WebInspector.DatabaseObject): Add cookie keys and type identifier.
(WebInspector.DatabaseObject.prototype.saveIdentityToCookie): Added.
* UserInterface/DatabaseTableObject.js:
(WebInspector.DatabaseTableObject): Add cookie keys and type identifier.
(WebInspector.DatabaseTableObject.prototype.saveIdentityToCookie): Added.
* UserInterface/DebuggerSidebarPanel.js:
(WebInspector.DebuggerSidebarPanel.prototype.saveStateToCookie): Added.
(WebInspector.DebuggerSidebarPanel.prototype.restoreStateFromCookie): Added.
* UserInterface/Frame.js:
(WebInspector.Frame): Add cookie keys and type identifier.
(WebInspector.Frame.prototype.saveIdentityToCookie): Added.
* UserInterface/FrameResourceManager.js: remove objectForCookie().
* UserInterface/InstrumentSidebarPanel.js:
(WebInspector.InstrumentSidebarPanel.prototype.showTimelineForRecordType):
Return the shown timeline, if any.
(WebInspector.InstrumentSidebarPanel.prototype.saveStateToCookie): Added.
(WebInspector.InstrumentSidebarPanel.prototype.restoreStateFromCookie): Added.
(WebInspector.InstrumentSidebarPanel.prototype.showProfile):
Return the shown profile, if any.
* UserInterface/Main.js:
(WebInspector): Added cookie keys for the selected sidebar and
typeidentifier of the sidebar's selected tree element.
(WebInspector.contentLoaded): Remove callbacks for
resolveAndShowPendingContentViewCookie(). Consolidate all saved
inspector view state into one Setting. Move special-cased
restoring of the console to the restoration method. Move saving
of last opened navigation panel to the saving method.
(WebInspector._mainResourceDidChange): Try to restore saved view
state when the main resource changes.
(WebInspector._provisionalLoadCommitted): Update the saved view
state when the navigation commits. This is the last chance to save
it before the main resource changes and the navigation panel view
state is discarded and rebuilt.
(WebInspector._pageHidden): Update the saved view state when the
inspector page is hidden, but before state is discarded.
(WebInspector._navigationSidebarPanelSelected): Don't save last
navigation sidebar panel.
(WebInspector._updateCookieForInspectorViewState): Renamed from
_updateCurrentContentViewCookie. It delegates view state
serialization to the currently open navigation sidebar, rather
than the current content view.
(WebInspector._contentBrowserRepresentedObjectsDidChange): Don't
spuriously serialize the current view state cookie on every
ContentView change.
(WebInspector._restoreInspectorViewStateFromCookie): Renamed from
_showContentViewForCookie. It now restores a specific navigation
panel and delegates remaining view state restoration to the panel
itself. Last-resort selection of any tree element with the same
type identifier was moved to the navigation panel's restore method.
* UserInterface/NavigationSidebarPanel.js:
(WebInspector.NavigationSidebarPanel):
(WebInspector.NavigationSidebarPanel.prototype.set contentTreeOutline):
(WebInspector.NavigationSidebarPanel.prototype.createContentTreeOutline):
Save references to all created TreeOutlines in a Set, so we can
restore any tree's selection.
(WebInspector.NavigationSidebarPanel.prototype.saveStateToCookie):
Added. Find the selected tree element from all tree outlines and
ask it to serialize its identity.
(WebInspector.NavigationSidebarPanel.prototype.restoreStateFromCookie):
Added. Eagerly search existing tree elements for a matching
representedObject. If none exists, save the pending cookie and
schedule last-resort matching using the provided timeout interval.
(WebInspector.NavigationSidebarPanel.prototype._treeElementAddedOrChanged):
Check if the added tree element matches a pending view state
cookie, if one exists.
(WebInspector.NavigationSidebarPanel.prototype.treeElementMatchesCookie):
Added. Check if the tree element's representedObject matches the
pending view state cookie.
(WebInspector.NavigationSidebarPanel.prototype._checkElementsForPendingViewStateCookie):
Added. For each provided tree element, check if the tree
element's represented object produces the same serialized identity
as the pending view state cookie that we are trying to resolve.
If a match is found (possibly by relaxing to matching anything
with the same type), select the tree element and clear both the
pending view state cookie and last-resort selection timer.
* UserInterface/Resource.js:
(WebInspector.Resource): Add cookie keys and type identifier.
(WebInspector.Resource.prototype.saveIdentityToCookie): Added.
* UserInterface/ResourceClusterContentView.js:
(WebInspector.ResourceClusterContentView.prototype.saveToCookie):
(WebInspector.ResourceClusterContentView.prototype.restoreFromCookie):
Since identity state is serialized by the representedObject, these
methods only need to save view-specific state, such as the visible
subview. Remove extraneous state.
* UserInterface/Script.js:
(WebInspector.Script): Add cookie keys and type identifier.
(WebInspector.Script.prototype.saveIdentityToCookie): Added.
* UserInterface/StorageManager.js: remove objectForCookie().
* UserInterface/TimelineManager.js: remove objectForCookie().
* UserInterface/TimelinesContentView.js:
(WebInspector.TimelinesContentView.prototype.saveToCookie):
(WebInspector.TimelinesContentView.prototype.restoreFromCookie):
Since identity state is serialized by the representedObject, these
methods only need to save view-specific state, such as the visible
subview. Remove extraneous state.
* UserInterface/TreeOutline.js: Add TreeOutline.prototype.constructor
so other code can assume the constructor property exists.
2013-12-02 Antoine Quint <graouts@apple.com>
Web Inspector: popover can overlap target frame
......
......@@ -35,9 +35,15 @@ WebInspector.ApplicationCacheFrame = function(frame, manifest, status)
this._status = status;
};
WebInspector.ApplicationCacheFrame.TypeIdentifier = "application-cache-frame";
WebInspector.ApplicationCacheFrame.FrameURLCookieKey = "application-cache-frame-url";
WebInspector.ApplicationCacheFrame.ManifestURLCookieKey = "application-cache-frame-manifest-url";
WebInspector.ApplicationCacheFrame.prototype = {
constructor: WebInspector.ApplicationCacheFrame,
// Public
get frame()
{
return this._frame;
......@@ -56,6 +62,12 @@ WebInspector.ApplicationCacheFrame.prototype = {
set status(status)
{
this._status = status;
},
saveIdentityToCookie: function(cookie)
{
cookie[WebInspector.ApplicationCacheFrame.FrameURLCookieKey] = this.frame.url;
cookie[WebInspector.ApplicationCacheFrame.ManifestURLCookieKey] = this.manifest.manifestURL;
}
};
......
......@@ -102,19 +102,6 @@ WebInspector.ApplicationCacheManager.prototype = {
ApplicationCacheAgent.getApplicationCacheForFrame(frame.id, callbackWrapper);
},
objectForCookie: function(cookie, matchOnTypeAlone)
{
console.assert(cookie.type && cookie.type === WebInspector.ContentViewCookieType.ApplicationCache);
for (var i = 0; i < this._applicationCacheObjects.length; ++i) {
var object = this._applicationCacheObjects[i];
if (object.frame.url === cookie.frame && object.manifest.manifestURL === cookie.manifest)
return object;
}
return matchOnTypeAlone && this._applicationCacheObjects.length ? this._applicationCacheObjects[0] : null;
},
// Private
_mainResourceDidChange: function(event)
......
......@@ -69,6 +69,11 @@ WebInspector.Breakpoint.PopoverOptionsAutoContinueInputId = "edit-breakpoint-pop
WebInspector.Breakpoint.DefaultBreakpointActionType = WebInspector.BreakpointAction.Type.Log;
WebInspector.Breakpoint.TypeIdentifier = "breakpoint";
WebInspector.Breakpoint.URLCookieKey = "breakpoint-url";
WebInspector.Breakpoint.LineNumberCookieKey = "breakpoint-line-number";
WebInspector.Breakpoint.ColumnNumberCookieKey = "breakpoint-column-number";
WebInspector.Breakpoint.Event = {
DisabledStateDidChange: "breakpoint-disabled-state-did-change",
ResolvedStateDidChange: "breakpoint-resolved-state-did-change",
......@@ -290,6 +295,13 @@ WebInspector.Breakpoint.prototype = {
this.dispatchEventToListeners(WebInspector.Breakpoint.Event.ActionsDidChange);
},
saveIdentityToCookie: function(cookie)
{
cookie[WebInspector.Breakpoint.URLCookieKey] = this.url;
cookie[WebInspector.Breakpoint.LineNumberCookieKey] = this.sourceCodeLocation.lineNumber;
cookie[WebInspector.Breakpoint.ColumnNumberCookieKey] = this.sourceCodeLocation.columnNumber;
},
// Protected (Called by BreakpointAction)
breakpointActionDidChange: function(action)
......
......@@ -28,6 +28,9 @@ WebInspector.CookieStorageObject = function(host)
this._host = host;
};
WebInspector.CookieStorageObject.TypeIdentifier = "cookie-storage";
WebInspector.CookieStorageObject.CookieHostCookieKey = "cookie-storage-host";
WebInspector.CookieStorageObject.prototype = {
constructor: WebInspector.CookieStorageObject,
......@@ -36,5 +39,9 @@ WebInspector.CookieStorageObject.prototype = {
return this._host;
},
saveIdentityToCookie: function(cookie)
{
cookie[WebInspector.CookieStorageObject.CookieHostCookieKey] = this.host;
}
// FIXME: This class will need to look up cookies that are set for this host.
};
......@@ -30,6 +30,10 @@ WebInspector.DOMStorageObject = function(id, host, isLocalStorage)
this._isLocalStorage = isLocalStorage;
};
WebInspector.DOMStorageObject.TypeIdentifier = "dom-storage";
WebInspector.DOMStorageObject.HostCookieKey = "dom-storage-object-host";
WebInspector.DOMStorageObject.LocalStorageCookieKey = "dom-storage-object-local-storage";
WebInspector.DOMStorageObject.prototype = {
constructor: WebInspector.DOMStorageObject,
......@@ -43,6 +47,12 @@ WebInspector.DOMStorageObject.prototype = {
return this._host;
},
saveIdentityToCookie: function(cookie)
{
cookie[WebInspector.DOMStorageObject.HostCookieKey] = this.host;
cookie[WebInspector.DOMStorageObject.LocalStorageCookieKey] = this.isLocalStorage();
},
isLocalStorage: function()
{
return this._isLocalStorage;
......
......@@ -31,9 +31,15 @@ WebInspector.DatabaseObject = function(id, host, name, version)
this._version = version;
};
WebInspector.DatabaseObject.TypeIdentifier = "database";
WebInspector.DatabaseObject.HostCookieKey = "database-object-host";
WebInspector.DatabaseObject.NameCookieKey = "database-object-name";
WebInspector.DatabaseObject.prototype = {
constructor: WebInspector.DatabaseObject,
// Public
get id()
{
return this._id;
......@@ -54,6 +60,12 @@ WebInspector.DatabaseObject.prototype = {
return this._version;
},
saveIdentityToCookie: function(cookie)
{
cookie[WebInspector.DatabaseObject.HostCookieKey] = this.host;
cookie[WebInspector.DatabaseObject.NameCookieKey] = this.name;
},
getTableNames: function(callback)
{
function sortingCallback(error, names)
......
......@@ -31,6 +31,9 @@ WebInspector.DatabaseTableObject = function(name, database)
this._database = database;
};
WebInspector.DatabaseTableObject.TypeIdentifier = "database-table";
WebInspector.DatabaseTableObject.NameCookieKey = "database-table-object-name";
WebInspector.DatabaseTableObject.prototype = {
constructor: WebInspector.DatabaseTableObject,
......@@ -42,7 +45,12 @@ WebInspector.DatabaseTableObject.prototype = {
get database()
{
return this._database;
}
},
saveIdentityToCookie: function(cookie)
{
cookie[WebInspector.DatabaseTableObject.NameCookieKey] = this.name;
},
};
WebInspector.DatabaseTableObject.prototype.__proto__ = WebInspector.Object.prototype;
......@@ -120,6 +120,9 @@ WebInspector.DebuggerSidebarPanel = function()
WebInspector.DebuggerSidebarPanel.OffsetSectionsStyleClassName = "offset-sections";
WebInspector.DebuggerSidebarPanel.ExceptionIconStyleClassName = "breakpoint-exception-icon";
WebInspector.DebuggerSidebarPanel.SelectedAllExceptionsCookieKey = "debugger-sidebar-panel-all-exceptions-breakpoint";
WebInspector.DebuggerSidebarPanel.SelectedAllUncaughtExceptionsCookieKey = "debugger-sidebar-panel-all-uncaught-exceptions-breakpoint";
WebInspector.DebuggerSidebarPanel.prototype = {
constructor: WebInspector.DebuggerSidebarPanel,
......@@ -134,6 +137,40 @@ WebInspector.DebuggerSidebarPanel.prototype = {
return this.contentTreeOutline.getCachedTreeElement(representedObject);
},
// Protected
saveStateToCookie: function(cookie)
{
console.assert(cookie);
var selectedTreeElement = this._breakpointsContentTreeOutline.selectedTreeElement;
if (!selectedTreeElement)
return;
var representedObject = selectedTreeElement.representedObject;
if (representedObject === WebInspector.debuggerManager.allExceptionsBreakpoint)
cookie[WebInspector.DebuggerSidebarPanel.SelectedAllExceptionsCookieKey] = true;
if (representedObject === WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint)
cookie[WebInspector.DebuggerSidebarPanel.SelectedAllUncaughtExceptionsCookieKey] = true;
WebInspector.NavigationSidebarPanel.prototype.saveStateToCookie.call(this, cookie);
},
restoreStateFromCookie: function(cookie)
{
console.assert(cookie);
// Eagerly resolve the special breakpoints; otherwise, use the default behavior.
if (cookie[WebInspector.DebuggerSidebarPanel.SelectedAllExceptionsCookieKey])
this._allExceptionsBreakpointTreeElement.revealAndSelect();
else if (cookie[WebInspector.DebuggerSidebarPanel.SelectedAllUncaughtExceptionsCookieKey])
this._allUncaughtExceptionsBreakpointTreeElement.revealAndSelect();
else
WebInspector.NavigationSidebarPanel.prototype.restoreStateFromCookie.call(this, cookie);
},
// Private
_debuggerPauseResumeButtonClicked: function(event)
......
......@@ -67,6 +67,9 @@ WebInspector.Frame.Event = {
ExecutionContextsCleared: "frame-execution-contexts-cleared"
};
WebInspector.Frame.TypeIdentifier = "Frame";
WebInspector.Frame.MainResourceURLCookieKey = "frame-main-resource-url";
WebInspector.Frame.prototype = {
constructor: WebInspector.Frame,
......@@ -432,6 +435,11 @@ WebInspector.Frame.prototype = {
this.dispatchEventToListeners(WebInspector.Frame.Event.AllResourcesRemoved);
},
saveIdentityToCookie: function(cookie)
{
cookie[WebInspector.Frame.MainResourceURLCookieKey] = this.mainResource.url;
},
// Private
_isProvisionalResource: function(resource)
......
......@@ -80,20 +80,6 @@ WebInspector.FrameResourceManager.prototype = {
return this._frameIdentifierMap[frameId] || null;
},
objectForCookie: function(cookie)
{
var representedObject = cookie.url ? this.resourceForURL(cookie.url) : this.mainFrame;
if (!representedObject)
representedObject = this.mainFrame;
if (representedObject instanceof WebInspector.Resource && representedObject.isMainResource())
representedObject = representedObject.parentFrame;
return representedObject;
},
frameDidNavigate: function(framePayload)
{
// Called from WebInspector.PageObserver.
......
......@@ -158,6 +158,10 @@ WebInspector.InstrumentSidebarPanel.StartJavaScriptProfileValue = "start-javascr
WebInspector.InstrumentSidebarPanel.StartCSSSelectorProfileValue = "start-css-selector-profile";
WebInspector.InstrumentSidebarPanel.StartCanvasProfileValue = "start-canvas-profile";
WebInspector.InstrumentSidebarPanel.SelectedTimelineCookieKey = "instrument-sidebar-panel-selected-timeline";
WebInspector.InstrumentSidebarPanel.SelectedProfileTypeCookieKey = "instrument-sidebar-panel-selected-profile-type";
WebInspector.InstrumentSidebarPanel.SelectedProfileTitleCookieKey = "instrument-sidebar-panel-selected-profile-title";
WebInspector.InstrumentSidebarPanel.prototype = {
constructor: WebInspector.InstrumentSidebarPanel,
......@@ -179,9 +183,48 @@ WebInspector.InstrumentSidebarPanel.prototype = {
{
var treeElementToSelect = this._timelineTreeElementMap[type];
if (!treeElementToSelect)
return;
return null;
treeElementToSelect.select(true, true);
return treeElementToSelect.representedObject;
},
saveStateToCookie: function(cookie)
{
console.assert(cookie);
// This sidebar has two separate tree outlines, but only one selected tree element between them.
var selectedTreeElement = this._timelinesTreeOutline.selectedTreeElement || this.contentTreeOutline.selectedTreeElement;
if (!selectedTreeElement)
return;
var representedObject = selectedTreeElement.representedObject;
if (representedObject === WebInspector.TimelineRecord.Type.Script || representedObject === WebInspector.TimelineRecord.Type.Layout || representedObject === WebInspector.TimelineRecord.Type.Network)
cookie[WebInspector.InstrumentSidebarPanel.SelectedTimelineCookieKey] = representedObject;
else if (representedObject instanceof WebInspector.ProfileObject) {
cookie[WebInspector.InstrumentSidebarPanel.SelectedProfileTypeCookieKey] = representedObject.type;
cookie[WebInspector.InstrumentSidebarPanel.SelectedProfileTitleCookieKey] = representedObject.title;
}
},
restoreStateFromCookie: function(cookie)
{
// Eagerly restore the sidebar's selection, since its elements are persistent or permanent.
console.assert(cookie);
var selectedTimelineType = cookie[WebInspector.InstrumentSidebarPanel.SelectedTimelineCookieKey];
if (selectedTimelineType) {
return this.showTimelineForRecordType(selectedTimelineType);
return WebInspector.timelineManager.timelines;
}
// Profiles are persisted across page reloads, but not across inspector open/close.
var selectedProfileType = cookie[WebInspector.InstrumentSidebarPanel.SelectedProfileTypeCookieKey];
var selectedProfileTitle = cookie[WebInspector.InstrumentSidebarPanel.SelectedProfileTitleCookieKey];
// Profile titles are optional, but profile types are mandatory.
if (!selectedProfileType)
return null;
return this.showProfile(selectedProfileType, selectedProfileTitle);
},
showProfile: function(type, title)
......@@ -192,7 +235,7 @@ WebInspector.InstrumentSidebarPanel.prototype = {
var profile = treeElement.representedObject;
if (profile.type === type && profile.title === title) {
treeElement.revealAndSelect();
return;
return profile;
}
}
},
......
This diff is collapsed.
......@@ -44,6 +44,8 @@ WebInspector.NavigationSidebarPanel = function(identifier, displayName, image, k
if (autoHideToolbarItemWhenEmpty)
this.toolbarItem.hidden = true;
this._visibleContentTreeOutlines = new Set;
this._contentElement = document.createElement("div");
this._contentElement.className = WebInspector.NavigationSidebarPanel.ContentElementStyleClassName;
this._contentElement.addEventListener("scroll", this._updateContentOverflowShadowVisibility.bind(this));
......@@ -135,6 +137,9 @@ WebInspector.NavigationSidebarPanel.prototype = {
this._contentTreeOutline = newTreeOutline;
this._contentTreeOutline.element.classList.remove(WebInspector.NavigationSidebarPanel.ContentTreeOutlineElementHiddenStyleClassName);
this._visibleContentTreeOutlines.delete(this._contentTreeOutline);
this._visibleContentTreeOutlines.add(newTreeOutline);
this._updateFilter();
},
......@@ -163,6 +168,9 @@ WebInspector.NavigationSidebarPanel.prototype = {
contentTreeOutline.oncollapse = this._treeElementExpandedOrCollapsed.bind(this);
contentTreeOutline.allowsRepeatSelection = true;
if (dontHideByDefault)
this._visibleContentTreeOutlines.add(contentTreeOutline);
return contentTreeOutline;
},
......@@ -179,6 +187,46 @@ WebInspector.NavigationSidebarPanel.prototype = {
selectedTreeElement.select();
},
saveStateToCookie: function(cookie)
{
console.assert(cookie);
// This does not save folder selections, which lack a represented object and content view.
var selectedTreeElement = null;
this._visibleContentTreeOutlines.forEach(function(outline) {
if (outline.selectedTreeElement)
selectedTreeElement = outline.selectedTreeElement;
});
if (!selectedTreeElement)
return;
var representedObject = selectedTreeElement.representedObject;
cookie[WebInspector.TypeIdentifierCookieKey] = representedObject.constructor.TypeIdentifier;
representedObject.saveIdentityToCookie(cookie);
},
// This can be supplemented by subclasses that admit a simpler strategy for static tree elements.
restoreStateFromCookie: function(cookie, relaxedMatchDelay)
{
this._pendingViewStateCookie = cookie;
// Check if any existing tree elements in any outline match the cookie.
this._checkOutlinesForPendingViewStateCookie();
if (this._finalAttemptToRestoreViewStateTimeout)
clearTimeout(this._finalAttemptToRestoreViewStateTimeout);
var finalAttemptToRestoreViewStateFromCookie = function() {
delete this._finalAttemptToRestoreViewStateTimeout;
this._checkOutlinesForPendingViewStateCookie(true);
};
// If the specific tree element wasn't found, we may need to wait for the resources
// to be registered. We try one last time (match type only) after an arbitrary amount of timeout.
this._finalAttemptToRestoreViewStateTimeout = setTimeout(finalAttemptToRestoreViewStateFromCookie.bind(this), relaxedMatchDelay);
},
showEmptyContentPlaceholder: function(message, hideToolbarItem)
{
console.assert(message);
......@@ -399,6 +447,7 @@ WebInspector.NavigationSidebarPanel.prototype = {
this._checkForEmptyFilterResults();
this._updateContentOverflowShadowVisibility();
this._checkElementsForPendingViewStateCookie(treeElement);
},
_treeElementExpandedOrCollapsed: function(treeElement)
......@@ -490,6 +539,70 @@ WebInspector.NavigationSidebarPanel.prototype = {
// Check on a delay to coalesce multiple calls to _checkForOldResources.
this._checkForOldResourcesTimeoutIdentifier = setTimeout(delayedWork.bind(this), 0);
},
_checkOutlinesForPendingViewStateCookie: function(matchTypeOnly)
{
if (!this._pendingViewStateCookie)
return;
var visibleTreeElements = [];
this._visibleContentTreeOutlines.forEach(function(outline) {
var currentTreeElement = outline.hasChildren ? outline.children[0] : null;
while (currentTreeElement) {
visibleTreeElements.push(currentTreeElement);
currentTreeElement = currentTreeElement.traverseNextTreeElement(false, null, false);
}
});
return this._checkElementsForPendingViewStateCookie(visibleTreeElements, matchTypeOnly);
},
_checkElementsForPendingViewStateCookie: function(treeElements, matchTypeOnly)
{
if (!this._pendingViewStateCookie)
return;
var cookie = this._pendingViewStateCookie;