<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[172094] trunk/Source/WebInspectorUI</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/172094">172094</a></dd>
<dt>Author</dt> <dd>burg@cs.washington.edu</dd>
<dt>Date</dt> <dd>2014-08-05 15:32:58 -0700 (Tue, 05 Aug 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Web Inspector: support storing multiple timeline recordings in the manager
https://bugs.webkit.org/show_bug.cgi?id=132875

Reviewed by Timothy Hatcher.

This patch adds support for capturing multiple timeline recordings and switching
between them in the user interface using hierarchical path components.

* Localizations/en.lproj/localizedStrings.js:
* UserInterface/Base/Main.js:
(WebInspector.contentLoaded): Remove hard-coded priming of the timeline sidebar panel.
Instead, load the first recording in the timeline manager after the initial load.

(WebInspector._revealAndSelectRepresentedObjectInNavigationSidebar): Don't suppress
onselect events when selecting the tree element for a newly shown content view. This
allows the sidebar to sync the current content view and timeline tree element selection
with what is displayed in the content browser.

* UserInterface/Controllers/TimelineManager.js: Add two new events, RecordingCreated and
RecordingLoaded. A recording is considered active when any new records recieved will be
appended to that recording. The user interface is not necessarily viewing the active
recording.

(WebInspector.TimelineManager.delayedWork):
(WebInspector.TimelineManager): Keep a list of recordings, and load the first recording
asynchronously so that everyone can add an event listener for it.

(WebInspector.TimelineManager.prototype.get activeRecording):
(WebInspector.TimelineManager.prototype.get recordings):
(WebInspector.TimelineManager.prototype.startCapturing):
(WebInspector.TimelineManager.prototype.stopCapturing): Use promises to make the iOS 7
fallback path better match the async semantics of the non-fallback path.

(WebInspector.TimelineManager.prototype.unloadRecording):
(WebInspector.TimelineManager.prototype._loadNewRecording): Stop capturing and unload
any existing recording before creating and loading a new recording.

(WebInspector.TimelineManager.prototype._startAutoCapturing): Create a new recording
rather than resetting the current recording.

* UserInterface/Models/NetworkTimeline.js:
(WebInspector.NetworkTimeline):
* UserInterface/Models/Timeline.js:
(WebInspector.Timeline):
(WebInspector.Timeline.prototype.get type): Each timeline stores its TimelineRecord.Type
so that other code can create type-specific views using the Timeline as a representedObject.

* UserInterface/Models/TimelineRecording.js: For each recording, add new state for a unique identifier,
display string, and an isWritable flag. Once a recording is unloaded, it becomes read-only.
(WebInspector.TimelineRecording.prototype.get displayName):
(WebInspector.TimelineRecording.prototype.get identifier):
(WebInspector.TimelineRecording.prototype.isWritable):
(WebInspector.TimelineRecording.prototype.unloaded):
(WebInspector.TimelineRecording.prototype.reset): A recording can only be reset if it is writable.

* UserInterface/Protocol/InspectorFrontendAPI.js:
(InspectorFrontendAPI.setTimelineProfilingEnabled): Don't make redundant start/stop capturing calls.

* UserInterface/Views/LayoutTimelineOverviewGraph.js: Use a timeline as the representedObject for all
timeline-specific graphs and views. Otherwise, use the recording.
(WebInspector.LayoutTimelineOverviewGraph):
* UserInterface/Views/LayoutTimelineView.js:
(WebInspector.LayoutTimelineView):
(WebInspector.LayoutTimelineView.prototype._treeElementSelected):
* UserInterface/Views/NetworkTimelineOverviewGraph.js:
(WebInspector.NetworkTimelineOverviewGraph):
* UserInterface/Views/NetworkTimelineView.js:
(WebInspector.NetworkTimelineView):
* UserInterface/Views/OverviewTimelineView.js:
(WebInspector.OverviewTimelineView.prototype._networkTimelineRecordAdded):
* UserInterface/Views/ScriptTimelineOverviewGraph.js:
(WebInspector.ScriptTimelineOverviewGraph):
* UserInterface/Views/ScriptTimelineView.js:
(WebInspector.ScriptTimelineView):
(WebInspector.ScriptTimelineView.prototype._treeElementSelected):

* UserInterface/Views/TimelineContentView.js: Iterate over timeline objects when setting up maps. Use timelines
as keys rather than their type identifiers.
(WebInspector.TimelineContentView.prototype.showTimelineViewForTimeline): Renamed from showTimelineView. This
function takes a Timeline instance rather than an identifier, since the conten view is specific to one recording.
(WebInspector.TimelineContentView.prototype.get selectionPathComponents): Match types against the currently
visible timeline's representedObject.
(WebInspector.TimelineContentView.prototype.get currentTimelineView): Used by the sidebar panel to sync timeline
tree element selections to TimelineView shown by the TimelineContentView.
(WebInspector.TimelineContentView.prototype.shown): Sync enablement of the &quot;Clear Timelines&quot; button to recording
read-only state.

(WebInspector.TimelineContentView.prototype.saveToCookie):
(WebInspector.TimelineContentView.prototype.restoreFromCookie): Added. Only handle saving/restoring the subview.

(WebInspector.TimelineContentView.prototype._pathComponentSelected):
(WebInspector.TimelineContentView.prototype._showTimelineView): Relax the early return so that timeline views
and content tree outlines are reattached when re-navigating to the same timeline view via back-forward entries.
(WebInspector.TimelineContentView.prototype.showTimelineView): Deleted.

* UserInterface/Views/TimelineOverviewGraph.js:
(WebInspector.TimelineOverviewGraph):

* UserInterface/Views/TimelineSidebarPanel.js:
(WebInspector.TimelineSidebarPanel): Keep a tree outline and tree element map for storing available recordings.
(WebInspector.TimelineSidebarPanel.createTimelineTreeElement):
(WebInspector.TimelineSidebarPanel.prototype.shown): Added.
(WebInspector.TimelineSidebarPanel.prototype.showDefaultContentView): Add a guard.
(WebInspector.TimelineSidebarPanel.prototype.get hasSelectedElement): Added. Selected recording tree elements
should be considered when deciding whether a represented object has been selected in the sidebar panel.

(WebInspector.TimelineSidebarPanel.prototype.treeElementForRepresentedObject.looselyCompareRepresentedObjects):
(WebInspector.TimelineSidebarPanel.prototype.treeElementForRepresentedObject.get if):
(WebInspector.TimelineSidebarPanel.prototype.treeElementForRepresentedObject):
(WebInspector.TimelineSidebarPanel.prototype.showTimelineOverview):
(WebInspector.TimelineSidebarPanel.prototype.showTimelineViewForType): Renamed to explicit take a type identifier.
Delegate the actual showing of the timeline view to the onselect handler for the timelines tree outline.

(WebInspector.TimelineSidebarPanel.prototype.matchTreeElementAgainstCustomFilters):
(WebInspector.TimelineSidebarPanel.prototype.saveStateToCookie): Fix a typo.
(WebInspector.TimelineSidebarPanel.prototype.restoreStateFromCookie): Fix a typo.
(WebInspector.TimelineSidebarPanel.prototype._recordingsTreeElementSelected): Sync the currently displayed
recording object and content view, and sync the selected tree element to the displayed timeline subview.

(WebInspector.TimelineSidebarPanel.prototype._timelinesTreeElementSelected): If this is a user action, show the timeline.
(WebInspector.TimelineSidebarPanel.prototype._contentBrowserCurrentContentViewDidChange): Use classList.toggle().
(WebInspector.TimelineSidebarPanel.prototype._recordingCreated): Dynamically add new recordings to the interface.
(WebInspector.TimelineSidebarPanel.prototype._recordingLoaded): Automatically show recordings when they are loaded.
(WebInspector.TimelineSidebarPanel.prototype._recordGlyphClicked): Shift+click will force-create a new recording.
(WebInspector.TimelineSidebarPanel.prototype.initialize): Deleted.
* UserInterface/Views/TimelineView.js:
(WebInspector.TimelineView):
(WebInspector.TimelineView.prototype.get representedObject):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUILocalizationsenlprojlocalizedStringsjs">trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceBaseMainjs">trunk/Source/WebInspectorUI/UserInterface/Base/Main.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceControllersTimelineManagerjs">trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceModelsNetworkTimelinejs">trunk/Source/WebInspectorUI/UserInterface/Models/NetworkTimeline.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceModelsTimelinejs">trunk/Source/WebInspectorUI/UserInterface/Models/Timeline.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceModelsTimelineRecordingjs">trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceProtocolInspectorFrontendAPIjs">trunk/Source/WebInspectorUI/UserInterface/Protocol/InspectorFrontendAPI.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsLayoutTimelineOverviewGraphjs">trunk/Source/WebInspectorUI/UserInterface/Views/LayoutTimelineOverviewGraph.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsLayoutTimelineViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/LayoutTimelineView.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsNetworkTimelineOverviewGraphjs">trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTimelineOverviewGraph.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsNetworkTimelineViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTimelineView.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsOverviewTimelineViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/OverviewTimelineView.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsScriptTimelineOverviewGraphjs">trunk/Source/WebInspectorUI/UserInterface/Views/ScriptTimelineOverviewGraph.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsScriptTimelineViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/ScriptTimelineView.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsTimelineContentViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/TimelineContentView.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsTimelineOverviewGraphjs">trunk/Source/WebInspectorUI/UserInterface/Views/TimelineOverviewGraph.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsTimelineSidebarPaneljs">trunk/Source/WebInspectorUI/UserInterface/Views/TimelineSidebarPanel.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsTimelineViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/TimelineView.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (172093 => 172094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/ChangeLog        2014-08-05 22:28:19 UTC (rev 172093)
+++ trunk/Source/WebInspectorUI/ChangeLog        2014-08-05 22:32:58 UTC (rev 172094)
</span><span class="lines">@@ -1,5 +1,136 @@
</span><span class="cx"> 2014-08-05  Brian J. Burg  &lt;burg@cs.washington.edu&gt;
</span><span class="cx"> 
</span><ins>+        Web Inspector: support storing multiple timeline recordings in the manager
+        https://bugs.webkit.org/show_bug.cgi?id=132875
+
+        Reviewed by Timothy Hatcher.
+
+        This patch adds support for capturing multiple timeline recordings and switching
+        between them in the user interface using hierarchical path components.
+
+        * Localizations/en.lproj/localizedStrings.js:
+        * UserInterface/Base/Main.js:
+        (WebInspector.contentLoaded): Remove hard-coded priming of the timeline sidebar panel.
+        Instead, load the first recording in the timeline manager after the initial load.
+
+        (WebInspector._revealAndSelectRepresentedObjectInNavigationSidebar): Don't suppress
+        onselect events when selecting the tree element for a newly shown content view. This
+        allows the sidebar to sync the current content view and timeline tree element selection
+        with what is displayed in the content browser.
+
+        * UserInterface/Controllers/TimelineManager.js: Add two new events, RecordingCreated and
+        RecordingLoaded. A recording is considered active when any new records recieved will be
+        appended to that recording. The user interface is not necessarily viewing the active
+        recording.
+
+        (WebInspector.TimelineManager.delayedWork):
+        (WebInspector.TimelineManager): Keep a list of recordings, and load the first recording
+        asynchronously so that everyone can add an event listener for it.
+
+        (WebInspector.TimelineManager.prototype.get activeRecording):
+        (WebInspector.TimelineManager.prototype.get recordings):
+        (WebInspector.TimelineManager.prototype.startCapturing):
+        (WebInspector.TimelineManager.prototype.stopCapturing): Use promises to make the iOS 7
+        fallback path better match the async semantics of the non-fallback path.
+
+        (WebInspector.TimelineManager.prototype.unloadRecording):
+        (WebInspector.TimelineManager.prototype._loadNewRecording): Stop capturing and unload
+        any existing recording before creating and loading a new recording.
+
+        (WebInspector.TimelineManager.prototype._startAutoCapturing): Create a new recording
+        rather than resetting the current recording.
+
+        * UserInterface/Models/NetworkTimeline.js:
+        (WebInspector.NetworkTimeline):
+        * UserInterface/Models/Timeline.js:
+        (WebInspector.Timeline):
+        (WebInspector.Timeline.prototype.get type): Each timeline stores its TimelineRecord.Type
+        so that other code can create type-specific views using the Timeline as a representedObject.
+
+        * UserInterface/Models/TimelineRecording.js: For each recording, add new state for a unique identifier,
+        display string, and an isWritable flag. Once a recording is unloaded, it becomes read-only.
+        (WebInspector.TimelineRecording.prototype.get displayName):
+        (WebInspector.TimelineRecording.prototype.get identifier):
+        (WebInspector.TimelineRecording.prototype.isWritable):
+        (WebInspector.TimelineRecording.prototype.unloaded):
+        (WebInspector.TimelineRecording.prototype.reset): A recording can only be reset if it is writable.
+
+        * UserInterface/Protocol/InspectorFrontendAPI.js:
+        (InspectorFrontendAPI.setTimelineProfilingEnabled): Don't make redundant start/stop capturing calls.
+
+        * UserInterface/Views/LayoutTimelineOverviewGraph.js: Use a timeline as the representedObject for all
+        timeline-specific graphs and views. Otherwise, use the recording.
+        (WebInspector.LayoutTimelineOverviewGraph):
+        * UserInterface/Views/LayoutTimelineView.js:
+        (WebInspector.LayoutTimelineView):
+        (WebInspector.LayoutTimelineView.prototype._treeElementSelected):
+        * UserInterface/Views/NetworkTimelineOverviewGraph.js:
+        (WebInspector.NetworkTimelineOverviewGraph):
+        * UserInterface/Views/NetworkTimelineView.js:
+        (WebInspector.NetworkTimelineView):
+        * UserInterface/Views/OverviewTimelineView.js:
+        (WebInspector.OverviewTimelineView.prototype._networkTimelineRecordAdded):
+        * UserInterface/Views/ScriptTimelineOverviewGraph.js:
+        (WebInspector.ScriptTimelineOverviewGraph):
+        * UserInterface/Views/ScriptTimelineView.js:
+        (WebInspector.ScriptTimelineView):
+        (WebInspector.ScriptTimelineView.prototype._treeElementSelected):
+
+        * UserInterface/Views/TimelineContentView.js: Iterate over timeline objects when setting up maps. Use timelines
+        as keys rather than their type identifiers.
+        (WebInspector.TimelineContentView.prototype.showTimelineViewForTimeline): Renamed from showTimelineView. This
+        function takes a Timeline instance rather than an identifier, since the conten view is specific to one recording.
+        (WebInspector.TimelineContentView.prototype.get selectionPathComponents): Match types against the currently
+        visible timeline's representedObject.
+        (WebInspector.TimelineContentView.prototype.get currentTimelineView): Used by the sidebar panel to sync timeline
+        tree element selections to TimelineView shown by the TimelineContentView.
+        (WebInspector.TimelineContentView.prototype.shown): Sync enablement of the &quot;Clear Timelines&quot; button to recording
+        read-only state.
+
+        (WebInspector.TimelineContentView.prototype.saveToCookie):
+        (WebInspector.TimelineContentView.prototype.restoreFromCookie): Added. Only handle saving/restoring the subview.
+
+        (WebInspector.TimelineContentView.prototype._pathComponentSelected):
+        (WebInspector.TimelineContentView.prototype._showTimelineView): Relax the early return so that timeline views
+        and content tree outlines are reattached when re-navigating to the same timeline view via back-forward entries.
+        (WebInspector.TimelineContentView.prototype.showTimelineView): Deleted.
+
+        * UserInterface/Views/TimelineOverviewGraph.js:
+        (WebInspector.TimelineOverviewGraph):
+
+        * UserInterface/Views/TimelineSidebarPanel.js:
+        (WebInspector.TimelineSidebarPanel): Keep a tree outline and tree element map for storing available recordings.
+        (WebInspector.TimelineSidebarPanel.createTimelineTreeElement):
+        (WebInspector.TimelineSidebarPanel.prototype.shown): Added.
+        (WebInspector.TimelineSidebarPanel.prototype.showDefaultContentView): Add a guard.
+        (WebInspector.TimelineSidebarPanel.prototype.get hasSelectedElement): Added. Selected recording tree elements
+        should be considered when deciding whether a represented object has been selected in the sidebar panel.
+
+        (WebInspector.TimelineSidebarPanel.prototype.treeElementForRepresentedObject.looselyCompareRepresentedObjects):
+        (WebInspector.TimelineSidebarPanel.prototype.treeElementForRepresentedObject.get if):
+        (WebInspector.TimelineSidebarPanel.prototype.treeElementForRepresentedObject):
+        (WebInspector.TimelineSidebarPanel.prototype.showTimelineOverview):
+        (WebInspector.TimelineSidebarPanel.prototype.showTimelineViewForType): Renamed to explicit take a type identifier.
+        Delegate the actual showing of the timeline view to the onselect handler for the timelines tree outline.
+
+        (WebInspector.TimelineSidebarPanel.prototype.matchTreeElementAgainstCustomFilters):
+        (WebInspector.TimelineSidebarPanel.prototype.saveStateToCookie): Fix a typo.
+        (WebInspector.TimelineSidebarPanel.prototype.restoreStateFromCookie): Fix a typo.
+        (WebInspector.TimelineSidebarPanel.prototype._recordingsTreeElementSelected): Sync the currently displayed
+        recording object and content view, and sync the selected tree element to the displayed timeline subview.
+
+        (WebInspector.TimelineSidebarPanel.prototype._timelinesTreeElementSelected): If this is a user action, show the timeline.
+        (WebInspector.TimelineSidebarPanel.prototype._contentBrowserCurrentContentViewDidChange): Use classList.toggle().
+        (WebInspector.TimelineSidebarPanel.prototype._recordingCreated): Dynamically add new recordings to the interface.
+        (WebInspector.TimelineSidebarPanel.prototype._recordingLoaded): Automatically show recordings when they are loaded.
+        (WebInspector.TimelineSidebarPanel.prototype._recordGlyphClicked): Shift+click will force-create a new recording.
+        (WebInspector.TimelineSidebarPanel.prototype.initialize): Deleted.
+        * UserInterface/Views/TimelineView.js:
+        (WebInspector.TimelineView):
+        (WebInspector.TimelineView.prototype.get representedObject):
+
+2014-08-05  Brian J. Burg  &lt;burg@cs.washington.edu&gt;
+
</ins><span class="cx">         Web Inspector: ReplayManager shouldn't assume replay status when the inspector is opened
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=135212
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebInspectorUILocalizationsenlprojlocalizedStringsjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (172093 => 172094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js        2014-08-05 22:28:19 UTC (rev 172093)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js        2014-08-05 22:32:58 UTC (rev 172094)
</span><span class="lines">@@ -431,6 +431,7 @@
</span><span class="cx"> localizedStrings[&quot;The  %s \ntable is empty.&quot;] = &quot;The  %s \ntable is empty.&quot;;
</span><span class="cx"> localizedStrings[&quot;Time until the load event fired, click to show the Network Requests timeline&quot;] = &quot;Time until the load event fired, click to show the Network Requests timeline&quot;;
</span><span class="cx"> localizedStrings[&quot;Timeline Events&quot;] = &quot;Timeline Events&quot;;
</span><ins>+localizedStrings[&quot;Timeline Recording %d&quot;] = &quot;Timeline Recording %d&quot;;
</ins><span class="cx"> localizedStrings[&quot;Timelines&quot;] = &quot;Timelines&quot;;
</span><span class="cx"> localizedStrings[&quot;Timer %s Fired&quot;] = &quot;Timer %s Fired&quot;;
</span><span class="cx"> localizedStrings[&quot;Timer %s Installed&quot;] = &quot;Timer %s Installed&quot;;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceBaseMainjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Base/Main.js (172093 => 172094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Base/Main.js        2014-08-05 22:28:19 UTC (rev 172093)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/Main.js        2014-08-05 22:32:58 UTC (rev 172094)
</span><span class="lines">@@ -257,8 +257,6 @@
</span><span class="cx">     this.timelineSidebarPanel = new WebInspector.TimelineSidebarPanel;
</span><span class="cx">     this.debuggerSidebarPanel = new WebInspector.DebuggerSidebarPanel;
</span><span class="cx"> 
</span><del>-    this.timelineSidebarPanel.initialize();
-
</del><span class="cx">     this.navigationSidebar.addSidebarPanel(this.resourceSidebarPanel);
</span><span class="cx">     // FIXME: Enable timelines panel for JavaScript inspection.
</span><span class="cx">     if (this.debuggableType !== WebInspector.DebuggableType.JavaScript)
</span><span class="lines">@@ -911,7 +909,7 @@
</span><span class="cx">     var treeElement = selectedSidebarPanel.treeElementForRepresentedObject(representedObject);
</span><span class="cx"> 
</span><span class="cx">     if (treeElement)
</span><del>-        treeElement.revealAndSelect(true, false, true, true);
</del><ins>+        treeElement.revealAndSelect(true, false, false, true);
</ins><span class="cx">     else if (selectedSidebarPanel.contentTreeOutline.selectedTreeElement)
</span><span class="cx">         selectedSidebarPanel.contentTreeOutline.selectedTreeElement.deselect(true);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceControllersTimelineManagerjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js (172093 => 172094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js        2014-08-05 22:28:19 UTC (rev 172093)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js        2014-08-05 22:32:58 UTC (rev 172094)
</span><span class="lines">@@ -31,11 +31,24 @@
</span><span class="cx">     WebInspector.Frame.addEventListener(WebInspector.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
</span><span class="cx">     WebInspector.Frame.addEventListener(WebInspector.Frame.Event.ResourceWasAdded, this._resourceWasAdded, this);
</span><span class="cx"> 
</span><del>-    this._activeRecording = new WebInspector.TimelineRecording;
</del><ins>+    this._recordings = [];
+    this._activeRecording = null;
</ins><span class="cx">     this._isCapturing = false;
</span><ins>+
+    this._nextRecordingIdentifier = 1;
+
+    function delayedWork()
+    {
+        this._loadNewRecording();
+    }
+
+    // Allow other code to set up listeners before firing the initial RecordingLoaded event.
+    setTimeout(delayedWork.bind(this), 0);
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> WebInspector.TimelineManager.Event = {
</span><ins>+    RecordingCreated: &quot;timeline-manager-recording-created&quot;,
+    RecordingLoaded: &quot;timeline-manager-recording-loaded&quot;,
</ins><span class="cx">     CapturingStarted: &quot;timeline-manager-capturing-started&quot;,
</span><span class="cx">     CapturingStopped: &quot;timeline-manager-capturing-stopped&quot;
</span><span class="cx"> };
</span><span class="lines">@@ -49,27 +62,44 @@
</span><span class="cx"> 
</span><span class="cx">     // Public
</span><span class="cx"> 
</span><ins>+    // The current recording that new timeline records will be appended to, if any.
</ins><span class="cx">     get activeRecording()
</span><span class="cx">     {
</span><ins>+        console.assert(this._activeRecording || !this._isCapturing);
</ins><span class="cx">         return this._activeRecording;
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    get recordings()
+    {
+        return this._recordings.slice();
+    },
+
</ins><span class="cx">     isCapturing: function()
</span><span class="cx">     {
</span><span class="cx">         return this._isCapturing;
</span><span class="cx">     },
</span><span class="cx"> 
</span><del>-    startCapturing: function()
</del><ins>+    startCapturing: function(shouldCreateRecording)
</ins><span class="cx">     {
</span><del>-        TimelineAgent.start();
</del><ins>+        console.assert(!this._isCapturing, &quot;TimelineManager is already capturing.&quot;);
</ins><span class="cx"> 
</span><ins>+        if (!this._activeRecording || shouldCreateRecording)
+            this._loadNewRecording();
+
+        var result = TimelineAgent.start.promise();
+
</ins><span class="cx">         // COMPATIBILITY (iOS 7): recordingStarted event did not exist yet. Start explicitly.
</span><del>-        if (!TimelineAgent.hasEvent(&quot;recordingStarted&quot;))
-            this.capturingStarted();
</del><ins>+        if (!TimelineAgent.hasEvent(&quot;recordingStarted&quot;)) {
+            result.then(function() {
+                WebInspector.timelineManager.capturingStarted();
+            });
+        }
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     stopCapturing: function()
</span><span class="cx">     {
</span><ins>+        console.assert(this._isCapturing, &quot;TimelineManager is not capturing.&quot;);
+
</ins><span class="cx">         TimelineAgent.stop();
</span><span class="cx"> 
</span><span class="cx">         // NOTE: Always stop immediately instead of waiting for a Timeline.recordingStopped event.
</span><span class="lines">@@ -77,6 +107,20 @@
</span><span class="cx">         this.capturingStopped();
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    unloadRecording: function()
+    {
+        if (!this._activeRecording)
+            return;
+
+        if (this._isCapturing)
+            this.stopCapturing();
+
+        this._activeRecording.unloaded();
+        this._activeRecording = null;
+    },
+
+    // Protected
+
</ins><span class="cx">     capturingStarted: function()
</span><span class="cx">     {
</span><span class="cx">         if (this._isCapturing)
</span><span class="lines">@@ -352,6 +396,26 @@
</span><span class="cx"> 
</span><span class="cx">     // Private
</span><span class="cx"> 
</span><ins>+    _loadNewRecording: function()
+    {
+        var identifier = this._nextRecordingIdentifier++;
+        var newRecording = new WebInspector.TimelineRecording(identifier, WebInspector.UIString(&quot;Timeline Recording %d&quot;).format(identifier));
+        this._recordings.push(newRecording);
+        this.dispatchEventToListeners(WebInspector.TimelineManager.Event.RecordingCreated, {recording: newRecording});
+
+        console.assert(newRecording.isWritable());
+
+        if (this._isCapturing)
+            this.stopCapturing();
+
+        var oldRecording = this._activeRecording;
+        if (oldRecording)
+            oldRecording.unloaded();
+
+        this._activeRecording = newRecording;
+        this.dispatchEventToListeners(WebInspector.TimelineManager.Event.RecordingLoaded, {oldRecording: oldRecording});
+    },
+
</ins><span class="cx">     _callFramesFromPayload: function(payload)
</span><span class="cx">     {
</span><span class="cx">         if (!payload)
</span><span class="lines">@@ -401,11 +465,12 @@
</span><span class="cx">         if (mainResource === this._autoCapturingMainResource)
</span><span class="cx">             return false;
</span><span class="cx"> 
</span><del>-        this.stopCapturing();
</del><ins>+        if (this._isCapturing)
+            this.stopCapturing();
</ins><span class="cx"> 
</span><span class="cx">         this._autoCapturingMainResource = mainResource;
</span><span class="cx"> 
</span><del>-        this._activeRecording.reset();
</del><ins>+        this._loadNewRecording();
</ins><span class="cx"> 
</span><span class="cx">         this.startCapturing();
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceModelsNetworkTimelinejs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Models/NetworkTimeline.js (172093 => 172094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Models/NetworkTimeline.js        2014-08-05 22:28:19 UTC (rev 172093)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/NetworkTimeline.js        2014-08-05 22:32:58 UTC (rev 172094)
</span><span class="lines">@@ -23,9 +23,9 @@
</span><span class="cx">  * THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-WebInspector.NetworkTimeline = function()
</del><ins>+WebInspector.NetworkTimeline = function(type)
</ins><span class="cx"> {
</span><del>-    WebInspector.Timeline.call(this);
</del><ins>+    WebInspector.Timeline.call(this, type);
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> WebInspector.NetworkTimeline.prototype = {
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceModelsTimelinejs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Models/Timeline.js (172093 => 172094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Models/Timeline.js        2014-08-05 22:28:19 UTC (rev 172093)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/Timeline.js        2014-08-05 22:32:58 UTC (rev 172094)
</span><span class="lines">@@ -23,10 +23,18 @@
</span><span class="cx">  * THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-WebInspector.Timeline = function()
</del><ins>+WebInspector.Timeline = function(type)
</ins><span class="cx"> {
</span><ins>+    if (this.constructor === WebInspector.Timeline) {
+        // When instantiated directly, potentially return an instance of a concrete subclass.
+        if (type === WebInspector.TimelineRecord.Type.Network)
+            return new WebInspector.NetworkTimeline(type);
+    }
+
</ins><span class="cx">     WebInspector.Object.call(this);
</span><span class="cx"> 
</span><ins>+    this._type = type;
+
</ins><span class="cx">     this.reset(true);
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="lines">@@ -57,6 +65,11 @@
</span><span class="cx">         return this._records;
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    get type()
+    {
+        return this._type;
+    },
+
</ins><span class="cx">     reset: function(suppressEvents)
</span><span class="cx">     {
</span><span class="cx">         this._records = [];
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceModelsTimelineRecordingjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js (172093 => 172094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js        2014-08-05 22:28:19 UTC (rev 172093)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js        2014-08-05 22:32:58 UTC (rev 172094)
</span><span class="lines">@@ -23,17 +23,21 @@
</span><span class="cx">  * THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-WebInspector.TimelineRecording = function()
</del><ins>+WebInspector.TimelineRecording = function(identifier, displayName)
</ins><span class="cx"> {
</span><span class="cx">     WebInspector.Object.call(this);
</span><span class="cx"> 
</span><ins>+    this._identifier = identifier;
</ins><span class="cx">     this._timelines = new Map;
</span><del>-    this._timelines.set(WebInspector.TimelineRecord.Type.Network, new WebInspector.NetworkTimeline);
-    this._timelines.set(WebInspector.TimelineRecord.Type.Script, new WebInspector.Timeline);
-    this._timelines.set(WebInspector.TimelineRecord.Type.Layout, new WebInspector.Timeline);
</del><ins>+    this._displayName = displayName;
+    this._isWritable = true;
</ins><span class="cx"> 
</span><del>-    for (var timeline of this._timelines.values())
</del><ins>+    for (var key of Object.keys(WebInspector.TimelineRecord.Type)) {
+        var type = WebInspector.TimelineRecord.Type[key];
+        var timeline = new WebInspector.Timeline(type);
+        this._timelines.set(type, timeline);
</ins><span class="cx">         timeline.addEventListener(WebInspector.Timeline.Event.TimesUpdated, this._timelineTimesUpdated, this);
</span><ins>+    }
</ins><span class="cx"> 
</span><span class="cx">     this.reset(true);
</span><span class="cx"> };
</span><span class="lines">@@ -50,6 +54,16 @@
</span><span class="cx"> 
</span><span class="cx">     // Public
</span><span class="cx"> 
</span><ins>+    get displayName()
+    {
+        return this._displayName;
+    },
+
+    get identifier()
+    {
+        return this._identifier;
+    },
+
</ins><span class="cx">     get timelines()
</span><span class="cx">     {
</span><span class="cx">         return this._timelines;
</span><span class="lines">@@ -65,8 +79,20 @@
</span><span class="cx">         return this._endTime;
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    isWritable: function()
+    {
+        return this._isWritable;
+    },
+
+    unloaded: function()
+    {
+        this._isWritable = false;
+    },
+
</ins><span class="cx">     reset: function(suppressEvents)
</span><span class="cx">     {
</span><ins>+        console.assert(this._isWritable, &quot;Can't reset a read-only recording.&quot;);
+
</ins><span class="cx">         this._sourceCodeTimelinesMap = new Map;
</span><span class="cx">         this._eventMarkers = [];
</span><span class="cx">         this._startTime = NaN;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceProtocolInspectorFrontendAPIjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Protocol/InspectorFrontendAPI.js (172093 => 172094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Protocol/InspectorFrontendAPI.js        2014-08-05 22:28:19 UTC (rev 172093)
+++ trunk/Source/WebInspectorUI/UserInterface/Protocol/InspectorFrontendAPI.js        2014-08-05 22:32:58 UTC (rev 172094)
</span><span class="lines">@@ -56,6 +56,9 @@
</span><span class="cx"> 
</span><span class="cx">     setTimelineProfilingEnabled: function(enabled)
</span><span class="cx">     {
</span><ins>+        if (WebInspector.timelineManager.isCapturing() !== enabled)
+            return;
+
</ins><span class="cx">         if (enabled) {
</span><span class="cx">             WebInspector.navigationSidebar.selectedSidebarPanel = WebInspector.timelineSidebarPanel;
</span><span class="cx">             WebInspector.timelineSidebarPanel.showTimelineOverview();
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsLayoutTimelineOverviewGraphjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/LayoutTimelineOverviewGraph.js (172093 => 172094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/LayoutTimelineOverviewGraph.js        2014-08-05 22:28:19 UTC (rev 172093)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/LayoutTimelineOverviewGraph.js        2014-08-05 22:32:58 UTC (rev 172094)
</span><span class="lines">@@ -23,13 +23,13 @@
</span><span class="cx">  * THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-WebInspector.LayoutTimelineOverviewGraph = function(recording)
</del><ins>+WebInspector.LayoutTimelineOverviewGraph = function(timeline)
</ins><span class="cx"> {
</span><del>-    WebInspector.TimelineOverviewGraph.call(this, recording);
</del><ins>+    WebInspector.TimelineOverviewGraph.call(this, timeline);
</ins><span class="cx"> 
</span><span class="cx">     this.element.classList.add(WebInspector.LayoutTimelineOverviewGraph.StyleClassName);
</span><span class="cx"> 
</span><del>-    this._layoutTimeline = recording.timelines.get(WebInspector.TimelineRecord.Type.Layout);
</del><ins>+    this._layoutTimeline = timeline;
</ins><span class="cx">     this._layoutTimeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._layoutTimelineRecordAdded, this);
</span><span class="cx"> 
</span><span class="cx">     this._timelineRecordBars = [];
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsLayoutTimelineViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/LayoutTimelineView.js (172093 => 172094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/LayoutTimelineView.js        2014-08-05 22:28:19 UTC (rev 172093)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/LayoutTimelineView.js        2014-08-05 22:32:58 UTC (rev 172094)
</span><span class="lines">@@ -23,10 +23,12 @@
</span><span class="cx">  * THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-WebInspector.LayoutTimelineView = function(recording)
</del><ins>+WebInspector.LayoutTimelineView = function(timeline)
</ins><span class="cx"> {
</span><del>-    WebInspector.TimelineView.call(this);
</del><ins>+    WebInspector.TimelineView.call(this, timeline);
</ins><span class="cx"> 
</span><ins>+    console.assert(timeline.type === WebInspector.TimelineRecord.Type.Layout);
+
</ins><span class="cx">     this.navigationSidebarTreeOutline.onselect = this._treeElementSelected.bind(this);
</span><span class="cx">     this.navigationSidebarTreeOutline.element.classList.add(WebInspector.NavigationSidebarPanel.HideDisclosureButtonsStyleClassName);
</span><span class="cx">     this.navigationSidebarTreeOutline.element.classList.add(WebInspector.LayoutTimelineView.TreeOutlineStyleClassName);
</span><span class="lines">@@ -68,8 +70,7 @@
</span><span class="cx">     this.element.classList.add(WebInspector.LayoutTimelineView.StyleClassName);
</span><span class="cx">     this.element.appendChild(this._dataGrid.element);
</span><span class="cx"> 
</span><del>-    var layoutTimeline = recording.timelines.get(WebInspector.TimelineRecord.Type.Layout);
-    layoutTimeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._layoutTimelineRecordAdded, this);
</del><ins>+    timeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._layoutTimelineRecordAdded, this);
</ins><span class="cx"> 
</span><span class="cx">     this._pendingRecords = [];
</span><span class="cx"> };
</span><span class="lines">@@ -187,7 +188,7 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (!treeElement.record.sourceCodeLocation) {
</span><del>-            WebInspector.timelineSidebarPanel.showTimelineView(WebInspector.TimelineRecord.Type.Layout);
</del><ins>+            WebInspector.timelineSidebarPanel.showTimelineViewForType(WebInspector.TimelineRecord.Type.Layout);
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsNetworkTimelineOverviewGraphjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTimelineOverviewGraph.js (172093 => 172094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTimelineOverviewGraph.js        2014-08-05 22:28:19 UTC (rev 172093)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTimelineOverviewGraph.js        2014-08-05 22:32:58 UTC (rev 172094)
</span><span class="lines">@@ -24,15 +24,14 @@
</span><span class="cx">  * THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-WebInspector.NetworkTimelineOverviewGraph = function(recording)
</del><ins>+WebInspector.NetworkTimelineOverviewGraph = function(timeline)
</ins><span class="cx"> {
</span><del>-    WebInspector.TimelineOverviewGraph.call(this, recording);
</del><ins>+    WebInspector.TimelineOverviewGraph.call(this, timeline);
</ins><span class="cx"> 
</span><span class="cx">     this.element.classList.add(WebInspector.NetworkTimelineOverviewGraph.StyleClassName);
</span><span class="cx"> 
</span><del>-    var networkTimeline = recording.timelines.get(WebInspector.TimelineRecord.Type.Network);
-    networkTimeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._networkTimelineRecordAdded, this);
-    networkTimeline.addEventListener(WebInspector.Timeline.Event.TimesUpdated, this.needsLayout, this);
</del><ins>+    timeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._networkTimelineRecordAdded, this);
+    timeline.addEventListener(WebInspector.Timeline.Event.TimesUpdated, this.needsLayout, this);
</ins><span class="cx"> 
</span><span class="cx">     this.reset();
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsNetworkTimelineViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTimelineView.js (172093 => 172094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTimelineView.js        2014-08-05 22:28:19 UTC (rev 172093)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTimelineView.js        2014-08-05 22:32:58 UTC (rev 172094)
</span><span class="lines">@@ -23,10 +23,12 @@
</span><span class="cx">  * THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-WebInspector.NetworkTimelineView = function(recording)
</del><ins>+WebInspector.NetworkTimelineView = function(timeline)
</ins><span class="cx"> {
</span><del>-    WebInspector.TimelineView.call(this);
</del><ins>+    WebInspector.TimelineView.call(this, timeline);
</ins><span class="cx"> 
</span><ins>+    console.assert(timeline.type === WebInspector.TimelineRecord.Type.Network);
+
</ins><span class="cx">     this.navigationSidebarTreeOutline.onselect = this._treeElementSelected.bind(this);
</span><span class="cx">     this.navigationSidebarTreeOutline.element.classList.add(WebInspector.NavigationSidebarPanel.HideDisclosureButtonsStyleClassName);
</span><span class="cx">     this.navigationSidebarTreeOutline.element.classList.add(WebInspector.NetworkTimelineView.TreeOutlineStyleClassName);
</span><span class="lines">@@ -84,8 +86,7 @@
</span><span class="cx">     this.element.classList.add(WebInspector.NetworkTimelineView.StyleClassName);
</span><span class="cx">     this.element.appendChild(this._dataGrid.element);
</span><span class="cx"> 
</span><del>-    var networkTimeline = recording.timelines.get(WebInspector.TimelineRecord.Type.Network);
-    networkTimeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._networkTimelineRecordAdded, this);
</del><ins>+    timeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._networkTimelineRecordAdded, this);
</ins><span class="cx"> 
</span><span class="cx">     this._pendingRecords = [];
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsOverviewTimelineViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/OverviewTimelineView.js (172093 => 172094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/OverviewTimelineView.js        2014-08-05 22:28:19 UTC (rev 172093)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/OverviewTimelineView.js        2014-08-05 22:32:58 UTC (rev 172094)
</span><span class="lines">@@ -25,12 +25,12 @@
</span><span class="cx"> 
</span><span class="cx"> WebInspector.OverviewTimelineView = function(recording)
</span><span class="cx"> {
</span><del>-    WebInspector.TimelineView.call(this);
</del><ins>+    WebInspector.TimelineView.call(this, recording);
</ins><span class="cx"> 
</span><ins>+    this.navigationSidebarTreeOutline.onselect = this._treeElementSelected.bind(this);
+
</ins><span class="cx">     this._recording = recording;
</span><span class="cx"> 
</span><del>-    this.navigationSidebarTreeOutline.onselect = this._treeElementSelected.bind(this);
-
</del><span class="cx">     var columns = {&quot;graph&quot;: {width: &quot;100%&quot;}};
</span><span class="cx"> 
</span><span class="cx">     this._dataGrid = new WebInspector.DataGrid(columns);
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsScriptTimelineOverviewGraphjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ScriptTimelineOverviewGraph.js (172093 => 172094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/ScriptTimelineOverviewGraph.js        2014-08-05 22:28:19 UTC (rev 172093)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ScriptTimelineOverviewGraph.js        2014-08-05 22:32:58 UTC (rev 172094)
</span><span class="lines">@@ -23,13 +23,13 @@
</span><span class="cx">  * THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-WebInspector.ScriptTimelineOverviewGraph = function(recording)
</del><ins>+WebInspector.ScriptTimelineOverviewGraph = function(timeline)
</ins><span class="cx"> {
</span><del>-    WebInspector.TimelineOverviewGraph.call(this, recording);
</del><ins>+    WebInspector.TimelineOverviewGraph.call(this, timeline);
</ins><span class="cx"> 
</span><span class="cx">     this.element.classList.add(WebInspector.ScriptTimelineOverviewGraph.StyleClassName);
</span><span class="cx"> 
</span><del>-    this._scriptTimeline = recording.timelines.get(WebInspector.TimelineRecord.Type.Script);
</del><ins>+    this._scriptTimeline = timeline;
</ins><span class="cx">     this._scriptTimeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._scriptTimelineRecordAdded, this);
</span><span class="cx"> 
</span><span class="cx">     this._timelineRecordBars = [];
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsScriptTimelineViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ScriptTimelineView.js (172093 => 172094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/ScriptTimelineView.js        2014-08-05 22:28:19 UTC (rev 172093)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ScriptTimelineView.js        2014-08-05 22:32:58 UTC (rev 172094)
</span><span class="lines">@@ -23,10 +23,12 @@
</span><span class="cx">  * THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-WebInspector.ScriptTimelineView = function(recording)
</del><ins>+WebInspector.ScriptTimelineView = function(timeline)
</ins><span class="cx"> {
</span><del>-    WebInspector.TimelineView.call(this);
</del><ins>+    WebInspector.TimelineView.call(this, timeline);
</ins><span class="cx"> 
</span><ins>+    console.assert(timeline.type === WebInspector.TimelineRecord.Type.Script);
+
</ins><span class="cx">     this.navigationSidebarTreeOutline.onselect = this._treeElementSelected.bind(this);
</span><span class="cx">     this.navigationSidebarTreeOutline.element.classList.add(WebInspector.ScriptTimelineView.TreeOutlineStyleClassName);
</span><span class="cx"> 
</span><span class="lines">@@ -67,8 +69,7 @@
</span><span class="cx">     this.element.classList.add(WebInspector.ScriptTimelineView.StyleClassName);
</span><span class="cx">     this.element.appendChild(this._dataGrid.element);
</span><span class="cx"> 
</span><del>-    var scriptTimeline = recording.timelines.get(WebInspector.TimelineRecord.Type.Script);
-    scriptTimeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._scriptTimelineRecordAdded, this);
</del><ins>+    timeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._scriptTimelineRecordAdded, this);
</ins><span class="cx"> 
</span><span class="cx">     this._pendingRecords = [];
</span><span class="cx"> };
</span><span class="lines">@@ -271,7 +272,7 @@
</span><span class="cx">             console.error(&quot;Unknown tree element selected.&quot;);
</span><span class="cx"> 
</span><span class="cx">         if (!sourceCodeLocation) {
</span><del>-            WebInspector.timelineSidebarPanel.showTimelineView(WebInspector.TimelineRecord.Type.Script);
</del><ins>+            WebInspector.timelineSidebarPanel.showTimelineViewForType(WebInspector.TimelineRecord.Type.Script);
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsTimelineContentViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineContentView.js (172093 => 172094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/TimelineContentView.js        2014-08-05 22:28:19 UTC (rev 172093)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TimelineContentView.js        2014-08-05 22:32:58 UTC (rev 172094)
</span><span class="lines">@@ -32,9 +32,8 @@
</span><span class="cx">     this.element.classList.add(WebInspector.TimelineContentView.StyleClassName);
</span><span class="cx"> 
</span><span class="cx">     this._discreteTimelineOverviewGraphMap = new Map;
</span><del>-    this._discreteTimelineOverviewGraphMap.set(WebInspector.TimelineRecord.Type.Network, new WebInspector.NetworkTimelineOverviewGraph(recording));
-    this._discreteTimelineOverviewGraphMap.set(WebInspector.TimelineRecord.Type.Layout, new WebInspector.LayoutTimelineOverviewGraph(recording));
-    this._discreteTimelineOverviewGraphMap.set(WebInspector.TimelineRecord.Type.Script, new WebInspector.ScriptTimelineOverviewGraph(recording));
</del><ins>+    for (var [identifier, timeline] of recording.timelines)
+        this._discreteTimelineOverviewGraphMap.set(timeline, new WebInspector.TimelineOverviewGraph(timeline));
</ins><span class="cx"> 
</span><span class="cx">     this._timelineOverview = new WebInspector.TimelineOverview(this._discreteTimelineOverviewGraphMap);
</span><span class="cx">     this._timelineOverview.addEventListener(WebInspector.TimelineOverview.Event.TimeRangeSelectionChanged, this._timeRangeSelectionChanged, this);
</span><span class="lines">@@ -50,9 +49,8 @@
</span><span class="cx">     this._overviewTimelineView = new WebInspector.OverviewTimelineView(recording);
</span><span class="cx"> 
</span><span class="cx">     this._discreteTimelineViewMap = new Map;
</span><del>-    this._discreteTimelineViewMap.set(WebInspector.TimelineRecord.Type.Network, new WebInspector.NetworkTimelineView(recording));
-    this._discreteTimelineViewMap.set(WebInspector.TimelineRecord.Type.Layout, new WebInspector.LayoutTimelineView(recording));
-    this._discreteTimelineViewMap.set(WebInspector.TimelineRecord.Type.Script, new WebInspector.ScriptTimelineView(recording));
</del><ins>+    for (var [identifier, timeline] of recording.timelines)
+        this._discreteTimelineViewMap.set(timeline, new WebInspector.TimelineView(timeline));
</ins><span class="cx"> 
</span><span class="cx">     function createPathComponent(displayName, className, representedObject)
</span><span class="cx">     {
</span><span class="lines">@@ -61,10 +59,14 @@
</span><span class="cx">         return pathComponent;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    var networkTimeline = recording.timelines.get(WebInspector.TimelineRecord.Type.Network);
+    var layoutTimeline = recording.timelines.get(WebInspector.TimelineRecord.Type.Layout);
+    var scriptTimeline = recording.timelines.get(WebInspector.TimelineRecord.Type.Script);
+
</ins><span class="cx">     this._pathComponentMap = new Map;
</span><del>-    this._pathComponentMap.set(WebInspector.TimelineRecord.Type.Network, createPathComponent.call(this, WebInspector.UIString(&quot;Network Requests&quot;), WebInspector.TimelineSidebarPanel.NetworkIconStyleClass, WebInspector.TimelineRecord.Type.Network));
-    this._pathComponentMap.set(WebInspector.TimelineRecord.Type.Layout, createPathComponent.call(this, WebInspector.UIString(&quot;Layout &amp; Rendering&quot;), WebInspector.TimelineSidebarPanel.ColorsIconStyleClass, WebInspector.TimelineRecord.Type.Layout));
-    this._pathComponentMap.set(WebInspector.TimelineRecord.Type.Script, createPathComponent.call(this, WebInspector.UIString(&quot;JavaScript &amp; Events&quot;), WebInspector.TimelineSidebarPanel.ScriptIconStyleClass, WebInspector.TimelineRecord.Type.Script));
</del><ins>+    this._pathComponentMap.set(networkTimeline, createPathComponent.call(this, WebInspector.UIString(&quot;Network Requests&quot;), WebInspector.TimelineSidebarPanel.NetworkIconStyleClass, networkTimeline));
+    this._pathComponentMap.set(layoutTimeline, createPathComponent.call(this, WebInspector.UIString(&quot;Layout &amp; Rendering&quot;), WebInspector.TimelineSidebarPanel.ColorsIconStyleClass, layoutTimeline));
+    this._pathComponentMap.set(scriptTimeline, createPathComponent.call(this, WebInspector.UIString(&quot;JavaScript &amp; Events&quot;), WebInspector.TimelineSidebarPanel.ScriptIconStyleClass, scriptTimeline));
</ins><span class="cx"> 
</span><span class="cx">     var previousPathComponent = null;
</span><span class="cx">     for (var pathComponent of this._pathComponentMap.values()) {
</span><span class="lines">@@ -95,6 +97,9 @@
</span><span class="cx"> WebInspector.TimelineContentView.StyleClassName = &quot;timeline&quot;;
</span><span class="cx"> WebInspector.TimelineContentView.ViewContainerStyleClassName = &quot;view-container&quot;;
</span><span class="cx"> 
</span><ins>+WebInspector.TimelineContentView.SelectedTimelineTypeCookieKey = &quot;timeline-content-view-selected-timeline-type&quot;;
+WebInspector.TimelineContentView.OverviewTimelineViewCookieValue = &quot;timeline-content-view-overview-timeline-view&quot;;
+
</ins><span class="cx"> WebInspector.TimelineContentView.prototype = {
</span><span class="cx">     constructor: WebInspector.TimelineContentView,
</span><span class="cx">     __proto__: WebInspector.ContentView.prototype,
</span><span class="lines">@@ -106,13 +111,14 @@
</span><span class="cx">         this._showTimelineView(this._overviewTimelineView);
</span><span class="cx">     },
</span><span class="cx"> 
</span><del>-    showTimelineView: function(identifier)
</del><ins>+    showTimelineViewForTimeline: function(timeline)
</ins><span class="cx">     {
</span><del>-        console.assert(this._discreteTimelineViewMap.has(identifier));
-        if (!this._discreteTimelineViewMap.has(identifier))
</del><ins>+        console.assert(timeline instanceof WebInspector.Timeline, timeline);
+        console.assert(this._discreteTimelineViewMap.has(timeline), timeline);
+        if (!this._discreteTimelineViewMap.has(timeline))
</ins><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        this._showTimelineView(this._discreteTimelineViewMap.get(identifier), identifier);
</del><ins>+        this._showTimelineView(this._discreteTimelineViewMap.get(timeline));
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     get allowedNavigationSidebarPanels()
</span><span class="lines">@@ -128,7 +134,9 @@
</span><span class="cx"> 
</span><span class="cx">     get selectionPathComponents()
</span><span class="cx">     {
</span><del>-        var pathComponents = this._currentTimelineViewIdentifier ? [this._pathComponentMap.get(this._currentTimelineViewIdentifier)] : [];
</del><ins>+        var pathComponents = [];
+        if (this._currentTimelineView.representedObject instanceof WebInspector.Timeline)
+            pathComponents.push(this._pathComponentMap.get(this._currentTimelineView.representedObject));
</ins><span class="cx">         pathComponents = pathComponents.concat(this._currentTimelineView.selectionPathComponents || []);
</span><span class="cx">         return pathComponents;
</span><span class="cx">     },
</span><span class="lines">@@ -138,12 +146,18 @@
</span><span class="cx">         return [this._clearTimelineNavigationItem];
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    get currentTimelineView()
+    {
+        return this._currentTimelineView;
+    },
+
</ins><span class="cx">     shown: function()
</span><span class="cx">     {
</span><span class="cx">         if (!this._currentTimelineView)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><span class="cx">         this._currentTimelineView.shown();
</span><ins>+        this._clearTimelineNavigationItem.enabled = this._recording.isWritable();
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     hidden: function()
</span><span class="lines">@@ -164,6 +178,26 @@
</span><span class="cx">         this._currentTimelineView.updateLayout();
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    saveToCookie: function(cookie)
+    {
+        cookie.type = WebInspector.ContentViewCookieType.Timelines;
+
+        if (!this._currentTimelineView || this._currentTimelineView === this._overviewTimelineView)
+            cookie[WebInspector.TimelineContentView.SelectedTimelineTypeCookieKey] = WebInspector.TimelineContentView.OverviewTimelineViewCookieValue;
+        else
+            cookie[WebInspector.TimelineContentView.SelectedTimelineTypeCookieKey] = this._currentTimelineView.representedObject.type;
+    },
+
+    restoreFromCookie: function(cookie)
+    {
+        var timelineType = cookie[WebInspector.TimelineContentView.SelectedTimelineTypeCookieKey];
+
+        if (timelineType === WebInspector.TimelineContentView.OverviewTimelineViewCookieValue)
+            this.showOverviewTimelineView();
+        else
+            this.showTimelineViewForTimeline(this.representedObject.timelines.get(timelineType));
+    },
+
</ins><span class="cx">     matchTreeElementAgainstCustomFilters: function(treeElement)
</span><span class="cx">     {
</span><span class="cx">         if (this._currentTimelineView &amp;&amp; !this._currentTimelineView.matchTreeElementAgainstCustomFilters(treeElement))
</span><span class="lines">@@ -224,7 +258,7 @@
</span><span class="cx"> 
</span><span class="cx">     _pathComponentSelected: function(event)
</span><span class="cx">     {
</span><del>-        WebInspector.timelineSidebarPanel.showTimelineView(event.data.pathComponent.representedObject);
</del><ins>+        WebInspector.timelineSidebarPanel.showTimelineViewForType(event.data.pathComponent.representedObject.type);
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     _timelineViewSelectionPathComponentsDidChange: function()
</span><span class="lines">@@ -232,11 +266,12 @@
</span><span class="cx">         this.dispatchEventToListeners(WebInspector.ContentView.Event.SelectionPathComponentsDidChange);
</span><span class="cx">     },
</span><span class="cx"> 
</span><del>-    _showTimelineView: function(timelineView, identifier)
</del><ins>+    _showTimelineView: function(timelineView)
</ins><span class="cx">     {
</span><span class="cx">         console.assert(timelineView instanceof WebInspector.TimelineView);
</span><span class="cx"> 
</span><del>-        if (this._currentTimelineView === timelineView)
</del><ins>+        // If the content view is shown and then hidden, we must reattach the content tree outline and timeline view.
+        if (timelineView.visible &amp;&amp; timelineView === this._currentTimelineView)
</ins><span class="cx">             return;
</span><span class="cx"> 
</span><span class="cx">         if (this._currentTimelineView) {
</span><span class="lines">@@ -247,7 +282,6 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         this._currentTimelineView = timelineView;
</span><del>-        this._currentTimelineViewIdentifier = identifier || null;
</del><span class="cx"> 
</span><span class="cx">         WebInspector.timelineSidebarPanel.contentTreeOutline = timelineView &amp;&amp; timelineView.navigationSidebarTreeOutline;
</span><span class="cx">         WebInspector.timelineSidebarPanel.contentTreeOutlineLabel = timelineView &amp;&amp; timelineView.navigationSidebarTreeOutlineLabel;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsTimelineOverviewGraphjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineOverviewGraph.js (172093 => 172094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/TimelineOverviewGraph.js        2014-08-05 22:28:19 UTC (rev 172093)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TimelineOverviewGraph.js        2014-08-05 22:32:58 UTC (rev 172094)
</span><span class="lines">@@ -23,8 +23,29 @@
</span><span class="cx">  * THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-WebInspector.TimelineOverviewGraph = function(recording)
</del><ins>+WebInspector.TimelineOverviewGraph = function(timeline)
</ins><span class="cx"> {
</span><ins>+    if (this.constructor === WebInspector.TimelineOverviewGraph) {
+        // When instantiated directly return an instance of a type-based concrete subclass.
+
+        console.assert(timeline &amp;&amp; timeline instanceof WebInspector.Timeline);
+
+        var timelineType = timeline.type;
+        if (timelineType === WebInspector.TimelineRecord.Type.Network)
+            return new WebInspector.NetworkTimelineOverviewGraph(timeline);
+
+        if (timelineType === WebInspector.TimelineRecord.Type.Layout)
+            return new WebInspector.LayoutTimelineOverviewGraph(timeline);
+
+        if (timelineType === WebInspector.TimelineRecord.Type.Script)
+            return new WebInspector.ScriptTimelineOverviewGraph(timeline);
+
+        throw Error(&quot;Can't make a graph for an unknown timeline.&quot;);
+    }
+
+    // Concrete object instantiation.
+    console.assert(this.constructor !== WebInspector.TimelineOverviewGraph &amp;&amp; this instanceof WebInspector.TimelineOverviewGraph);
+
</ins><span class="cx">     WebInspector.Object.call(this);
</span><span class="cx"> 
</span><span class="cx">     this.element = document.createElement(&quot;div&quot;);
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsTimelineSidebarPaneljs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineSidebarPanel.js (172093 => 172094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/TimelineSidebarPanel.js        2014-08-05 22:28:19 UTC (rev 172093)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TimelineSidebarPanel.js        2014-08-05 22:32:58 UTC (rev 172094)
</span><span class="lines">@@ -38,11 +38,40 @@
</span><span class="cx">     this._timelinesContentContainer.classList.add(WebInspector.TimelineSidebarPanel.TimelinesContentContainerStyleClass);
</span><span class="cx">     this.element.insertBefore(this._timelinesContentContainer, this.element.firstChild);
</span><span class="cx"> 
</span><ins>+    // Maintain an invisible tree outline containing tree elements for all recordings.
+    // The visible recording's tree element is selected when the content view changes.
+    this._recordingTreeElementMap = new Map;
+    this._recordingsTreeOutline = this.createContentTreeOutline(true, true);
+    this._recordingsTreeOutline.element.classList.add(WebInspector.NavigationSidebarPanel.HideDisclosureButtonsStyleClassName);
+    this._recordingsTreeOutline.element.classList.add(WebInspector.NavigationSidebarPanel.ContentTreeOutlineElementHiddenStyleClassName);
+    this._recordingsTreeOutline.onselect = this._recordingsTreeElementSelected.bind(this);
+    this._timelinesContentContainer.appendChild(this._recordingsTreeOutline.element);
+
</ins><span class="cx">     this._timelinesTreeOutline = this.createContentTreeOutline(true, true);
</span><span class="cx">     this._timelinesTreeOutline.element.classList.add(WebInspector.NavigationSidebarPanel.HideDisclosureButtonsStyleClassName);
</span><span class="cx">     this._timelinesTreeOutline.onselect = this._timelinesTreeElementSelected.bind(this);
</span><span class="cx">     this._timelinesContentContainer.appendChild(this._timelinesTreeOutline.element);
</span><span class="cx"> 
</span><ins>+    function createTimelineTreeElement(label, iconClass, identifier)
+    {
+        var treeElement = new WebInspector.GeneralTreeElement([iconClass, WebInspector.TimelineSidebarPanel.LargeIconStyleClass], label, null, identifier);
+        var closeButton = document.createElement(&quot;img&quot;);
+        closeButton.classList.add(WebInspector.TimelineSidebarPanel.CloseButtonStyleClass);
+        closeButton.addEventListener(&quot;click&quot;, this.showTimelineOverview.bind(this));
+        treeElement.status = closeButton;
+        return treeElement;
+    }
+
+    // Timeline elements are reused; clicking them displays a TimelineView
+    // for the relevant timeline of the active recording.
+    this._timelineTreeElementMap = new Map;
+    this._timelineTreeElementMap.set(WebInspector.TimelineRecord.Type.Network, createTimelineTreeElement.call(this, WebInspector.UIString(&quot;Network Requests&quot;), WebInspector.TimelineSidebarPanel.NetworkIconStyleClass, WebInspector.TimelineRecord.Type.Network));
+    this._timelineTreeElementMap.set(WebInspector.TimelineRecord.Type.Layout, createTimelineTreeElement.call(this, WebInspector.UIString(&quot;Layout &amp; Rendering&quot;), WebInspector.TimelineSidebarPanel.ColorsIconStyleClass, WebInspector.TimelineRecord.Type.Layout));
+    this._timelineTreeElementMap.set(WebInspector.TimelineRecord.Type.Script, createTimelineTreeElement.call(this, WebInspector.UIString(&quot;JavaScript &amp; Events&quot;), WebInspector.TimelineSidebarPanel.ScriptIconStyleClass, WebInspector.TimelineRecord.Type.Script));
+
+    for (var timelineTreeElement of this._timelineTreeElementMap.values())
+        this._timelinesTreeOutline.appendChild(timelineTreeElement);
+
</ins><span class="cx">     var timelinesTitleBarElement = document.createElement(&quot;div&quot;);
</span><span class="cx">     timelinesTitleBarElement.textContent = WebInspector.UIString(&quot;Timelines&quot;);
</span><span class="cx">     timelinesTitleBarElement.classList.add(WebInspector.TimelineSidebarPanel.TitleBarStyleClass);
</span><span class="lines">@@ -91,27 +120,9 @@
</span><span class="cx">     this._navigationBar.element.oncontextmenu = this._contextMenuNavigationBarOrStatusBar.bind(this);
</span><span class="cx">     this._updateReplayInterfaceVisibility();
</span><span class="cx"> 
</span><del>-    function createTimelineTreeElement(label, iconClass, identifier)
-    {
-        var treeElement = new WebInspector.GeneralTreeElement([iconClass, WebInspector.TimelineSidebarPanel.LargeIconStyleClass], label, null, identifier);
-        var closeButton = document.createElement(&quot;img&quot;);
-        closeButton.classList.add(WebInspector.TimelineSidebarPanel.CloseButtonStyleClass);
-        closeButton.addEventListener(&quot;click&quot;, this.showTimelineOverview.bind(this));
-        treeElement.status = closeButton;
-        return treeElement;
-    }
</del><ins>+    WebInspector.timelineManager.addEventListener(WebInspector.TimelineManager.Event.RecordingCreated, this._recordingCreated, this);
+    WebInspector.timelineManager.addEventListener(WebInspector.TimelineManager.Event.RecordingLoaded, this._recordingLoaded, this);
</ins><span class="cx"> 
</span><del>-    this._timelineTreeElementMap = new Map;
-    this._timelineTreeElementMap.set(WebInspector.TimelineRecord.Type.Network, createTimelineTreeElement.call(this, WebInspector.UIString(&quot;Network Requests&quot;), WebInspector.TimelineSidebarPanel.NetworkIconStyleClass, WebInspector.TimelineRecord.Type.Network));
-    this._timelineTreeElementMap.set(WebInspector.TimelineRecord.Type.Layout, createTimelineTreeElement.call(this, WebInspector.UIString(&quot;Layout &amp; Rendering&quot;), WebInspector.TimelineSidebarPanel.ColorsIconStyleClass, WebInspector.TimelineRecord.Type.Layout));
-    this._timelineTreeElementMap.set(WebInspector.TimelineRecord.Type.Script, createTimelineTreeElement.call(this, WebInspector.UIString(&quot;JavaScript &amp; Events&quot;), WebInspector.TimelineSidebarPanel.ScriptIconStyleClass, WebInspector.TimelineRecord.Type.Script));
-
-    for (var timelineTreeElement of this._timelineTreeElementMap.values())
-        this._timelinesTreeOutline.appendChild(timelineTreeElement);
-
-    this._timelineOverviewTreeElement = new WebInspector.GeneralTreeElement(WebInspector.TimelineSidebarPanel.StopwatchIconStyleClass, WebInspector.UIString(&quot;Timelines&quot;), null, WebInspector.timelineManager.activeRecording);
-    this._timelineOverviewTreeElement.addEventListener(WebInspector.HierarchicalPathComponent.Event.SiblingWasSelected, this.showTimelineOverview, this);
-
</del><span class="cx">     this._stripeBackgroundElement = document.createElement(&quot;div&quot;);
</span><span class="cx">     this._stripeBackgroundElement.className = WebInspector.TimelineSidebarPanel.StripeBackgroundStyleClass;
</span><span class="cx">     this.contentElement.insertBefore(this._stripeBackgroundElement, this.contentElement.firstChild);
</span><span class="lines">@@ -139,6 +150,7 @@
</span><span class="cx"> WebInspector.TimelineSidebarPanel.ColorsIconStyleClass = &quot;colors-icon&quot;;
</span><span class="cx"> WebInspector.TimelineSidebarPanel.ScriptIconStyleClass = &quot;script-icon&quot;;
</span><span class="cx"> WebInspector.TimelineSidebarPanel.TimelineContentViewShowingStyleClass = &quot;timeline-content-view-showing&quot;;
</span><ins>+
</ins><span class="cx"> WebInspector.TimelineSidebarPanel.ShowingTimelineContentViewCookieKey = &quot;timeline-sidebar-panel-showing-timeline-content-view&quot;;
</span><span class="cx"> WebInspector.TimelineSidebarPanel.SelectedTimelineViewIdentifierCookieKey = &quot;timeline-sidebar-panel-selected-timeline-view-identifier&quot;;
</span><span class="cx"> WebInspector.TimelineSidebarPanel.OverviewTimelineIdentifierCookieValue = &quot;overview&quot;;
</span><span class="lines">@@ -149,21 +161,29 @@
</span><span class="cx"> 
</span><span class="cx">     // Public
</span><span class="cx"> 
</span><del>-    initialize: function()
</del><ins>+    shown: function()
</ins><span class="cx">     {
</span><del>-        // Prime the creation of the singleton TimelineContentView since it needs to listen for events.
-        this._timelineContentView = WebInspector.contentBrowser.contentViewForRepresentedObject(WebInspector.timelineManager.activeRecording);
</del><ins>+        WebInspector.NavigationSidebarPanel.prototype.shown.call(this);
+
+        if (this._activeContentView)
+            WebInspector.contentBrowser.showContentView(this._activeContentView);
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     showDefaultContentView: function()
</span><span class="cx">     {
</span><del>-        WebInspector.contentBrowser.showContentView(this._timelineContentView);
</del><ins>+        if (this._activeContentView)
+            this.showTimelineOverview();
</ins><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    get hasSelectedElement()
+    {
+        return !!this._contentTreeOutline.selectedTreeElement || !!this._recordingsTreeOutline.selectedTreeElement;
+    },
+
</ins><span class="cx">     treeElementForRepresentedObject: function(representedObject)
</span><span class="cx">     {
</span><span class="cx">         if (representedObject instanceof WebInspector.TimelineRecording)
</span><del>-            return this._timelineOverviewTreeElement;
</del><ins>+            return this._recordingTreeElementMap.get(representedObject);
</ins><span class="cx"> 
</span><span class="cx">         // The main resource is used as the representedObject instead of Frame in our tree.
</span><span class="cx">         if (representedObject instanceof WebInspector.Frame)
</span><span class="lines">@@ -200,7 +220,7 @@
</span><span class="cx">             if (candidateRepresentedObject instanceof WebInspector.ProfileNode)
</span><span class="cx">                 return false;
</span><span class="cx"> 
</span><del>-            console.error(&quot;Unknown TreeElement&quot;);
</del><ins>+            console.error(&quot;Unknown TreeElement&quot;, candidateTreeElement);
</ins><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -237,20 +257,20 @@
</span><span class="cx">         if (this._timelinesTreeOutline.selectedTreeElement)
</span><span class="cx">             this._timelinesTreeOutline.selectedTreeElement.deselect();
</span><span class="cx"> 
</span><del>-        this._timelineContentView.showOverviewTimelineView();
-        WebInspector.contentBrowser.showContentView(this._timelineContentView);
</del><ins>+        this._activeContentView.showOverviewTimelineView();
+        WebInspector.contentBrowser.showContentView(this._activeContentView);
</ins><span class="cx">     },
</span><span class="cx"> 
</span><del>-    showTimelineView: function(identifier)
</del><ins>+    showTimelineViewForType: function(timelineType)
</ins><span class="cx">     {
</span><del>-        console.assert(this._timelineTreeElementMap.has(identifier));
-        if (!this._timelineTreeElementMap.has(identifier))
</del><ins>+        console.assert(this._timelineTreeElementMap.has(timelineType), timelineType);
+        if (!this._timelineTreeElementMap.has(timelineType))
</ins><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        this._timelineTreeElementMap.get(identifier).select(true, false, true, true);
-
-        this._timelineContentView.showTimelineView(identifier);
-        WebInspector.contentBrowser.showContentView(this._timelineContentView);
</del><ins>+        // Defer showing the relevant timeline to the onselect handler of the timelines tree element.
+        const wasSelectedByUser = true;
+        const shouldSuppressOnSelect = false;
+        this._timelineTreeElementMap.get(timelineType).select(true, wasSelectedByUser, shouldSuppressOnSelect, true);
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     // Protected
</span><span class="lines">@@ -273,10 +293,10 @@
</span><span class="cx"> 
</span><span class="cx">     matchTreeElementAgainstCustomFilters: function(treeElement)
</span><span class="cx">     {
</span><del>-        if (!this._timelineContentView)
</del><ins>+        if (!this._activeContentView)
</ins><span class="cx">             return true;
</span><span class="cx"> 
</span><del>-        return this._timelineContentView.matchTreeElementAgainstCustomFilters(treeElement);
</del><ins>+        return this._activeContentView.matchTreeElementAgainstCustomFilters(treeElement);
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     canShowDifferentContentView: function()
</span><span class="lines">@@ -288,11 +308,11 @@
</span><span class="cx">     {
</span><span class="cx">         console.assert(cookie);
</span><span class="cx"> 
</span><del>-        cookie[WebInspector.timelineSidebarPanel.ShowingTimelineContentViewCookieKey] = WebInspector.contentBrowser.currentContentView instanceof WebInspector.TimelineContentView;
</del><ins>+        cookie[WebInspector.TimelineSidebarPanel.ShowingTimelineContentViewCookieKey] = WebInspector.contentBrowser.currentContentView instanceof WebInspector.TimelineContentView;
</ins><span class="cx"> 
</span><span class="cx">         var selectedTreeElement = this._timelinesTreeOutline.selectedTreeElement;
</span><span class="cx">         if (selectedTreeElement)
</span><del>-            cookie[WebInspector.TimelineSidebarPanel.SelectedTimelineViewIdentifierCookieKey] = selectedTreeElement.representedObject;
</del><ins>+            cookie[WebInspector.TimelineSidebarPanel.SelectedTimelineViewIdentifierCookieKey] = selectedTreeElement.representedObject.type;
</ins><span class="cx">         else
</span><span class="cx">             cookie[WebInspector.TimelineSidebarPanel.SelectedTimelineViewIdentifierCookieKey] = WebInspector.TimelineSidebarPanel.OverviewTimelineIdentifierCookieValue;
</span><span class="cx"> 
</span><span class="lines">@@ -303,38 +323,63 @@
</span><span class="cx">     {
</span><span class="cx">         console.assert(cookie);
</span><span class="cx"> 
</span><del>-        // The _timelineContentView is not ready on initial load, so delay the restore.
</del><ins>+        // The _activeContentView is not ready on initial load, so delay the restore.
</ins><span class="cx">         // This matches the delayed work in the WebInspector.TimelineSidebarPanel constructor.
</span><del>-        if (!this._timelineContentView) {
</del><ins>+        if (!this._activeContentView) {
</ins><span class="cx">             setTimeout(this.restoreStateFromCookie.bind(this, cookie, relaxedMatchDelay), 0);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        this._restoredShowingTimelineContentView = cookie[WebInspector.timelineSidebarPanel.ShowingTimelineContentViewCookieKey];
</del><ins>+        this._restoredShowingTimelineContentView = cookie[WebInspector.TimelineSidebarPanel.ShowingTimelineContentViewCookieKey];
</ins><span class="cx"> 
</span><span class="cx">         var selectedTimelineViewIdentifier = cookie[WebInspector.TimelineSidebarPanel.SelectedTimelineViewIdentifierCookieKey];
</span><span class="cx">         if (selectedTimelineViewIdentifier === WebInspector.TimelineSidebarPanel.OverviewTimelineIdentifierCookieValue)
</span><span class="cx">             this.showTimelineOverview();
</span><span class="cx">         else
</span><del>-            this.showTimelineView(selectedTimelineViewIdentifier);
</del><ins>+            this.showTimelineViewForType(selectedTimelineViewIdentifier);
</ins><span class="cx"> 
</span><span class="cx">         WebInspector.NavigationSidebarPanel.prototype.restoreStateFromCookie.call(this, cookie, relaxedMatchDelay);
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     // Private
</span><span class="cx"> 
</span><ins>+    _recordingsTreeElementSelected: function(treeElement, selectedByUser)
+    {
+        console.assert(treeElement.representedObject instanceof WebInspector.TimelineRecording);
+        console.assert(!selectedByUser, &quot;Recording tree elements should be hidden and only programmatically selectable.&quot;)
+
+        this._activeContentView = WebInspector.contentBrowser.contentViewForRepresentedObject(treeElement.representedObject);
+
+        // Deselect or re-select the timeline tree element for the timeline view being displayed.
+        var currentTimelineView = this._activeContentView.currentTimelineView;
+        if (currentTimelineView &amp;&amp; currentTimelineView.representedObject instanceof WebInspector.Timeline) {
+            const wasSelectedByUser = false; // This is a simulated selection.
+            const shouldSuppressOnSelect = false;
+            this._timelineTreeElementMap.get(currentTimelineView.representedObject.type).select(true, wasSelectedByUser, shouldSuppressOnSelect, true);
+        } else if (this._timelinesTreeOutline.selectedTreeElement)
+            this._timelinesTreeOutline.selectedTreeElement.deselect();
+    },
+
</ins><span class="cx">     _timelinesTreeElementSelected: function(treeElement, selectedByUser)
</span><span class="cx">     {
</span><del>-        console.assert(this._timelineTreeElementMap.get(treeElement.representedObject) === treeElement);
-        this.showTimelineView(treeElement.representedObject);
</del><ins>+        console.assert(this._timelineTreeElementMap.get(treeElement.representedObject) === treeElement, treeElement);
+
+        // If not selected by user, then this selection merely synced the tree element with the content view's contents.
+        if (!selectedByUser) {
+            console.assert(this._activeContentView.currentTimelineView.representedObject.type === treeElement.representedObject);
+            return;
+        }
+
+        var timelineType = treeElement.representedObject;
+        var timeline = this._activeContentView.representedObject.timelines.get(timelineType);
+        this._activeContentView.showTimelineViewForTimeline(timeline);
+        WebInspector.contentBrowser.showContentView(this._activeContentView);
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     _contentBrowserCurrentContentViewDidChange: function(event)
</span><span class="cx">     {
</span><del>-        if (WebInspector.contentBrowser.currentContentView instanceof WebInspector.TimelineContentView)
-            this.element.classList.add(WebInspector.TimelineSidebarPanel.TimelineContentViewShowingStyleClass);
-        else
-            this.element.classList.remove(WebInspector.TimelineSidebarPanel.TimelineContentViewShowingStyleClass);
</del><ins>+        var didShowTimelineContentView = WebInspector.contentBrowser.currentContentView instanceof WebInspector.TimelineContentView;
+        this.element.classList.toggle(WebInspector.TimelineSidebarPanel.TimelineContentViewShowingStyleClass, didShowTimelineContentView);
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     _capturingStarted: function(event)
</span><span class="lines">@@ -349,6 +394,32 @@
</span><span class="cx">         this._recordGlyphElement.classList.remove(WebInspector.TimelineSidebarPanel.RecordGlyphRecordingStyleClass);
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    _recordingCreated: function(event)
+    {
+        var recording = event.data.recording;
+        console.assert(recording instanceof WebInspector.TimelineRecording, recording);
+
+        var recordingTreeElement = new WebInspector.GeneralTreeElement(WebInspector.TimelineSidebarPanel.StopwatchIconStyleClass, recording.displayName, null, recording);
+        this._recordingTreeElementMap.set(recording, recordingTreeElement);
+        this._recordingsTreeOutline.appendChild(recordingTreeElement);
+
+        var previousTreeElement = null;
+        for (var treeElement of this._recordingTreeElementMap.values()) {
+            if (previousTreeElement) {
+                previousTreeElement.nextSibling = treeElement;
+                treeElement.previousSibling = previousTreeElement;
+            }
+
+            previousTreeElement = treeElement;
+        }
+    },
+
+    _recordingLoaded: function()
+    {
+        this._activeContentView = WebInspector.contentBrowser.contentViewForRepresentedObject(WebInspector.timelineManager.activeRecording);
+        WebInspector.contentBrowser.showContentView(this._activeContentView);
+    },
+
</ins><span class="cx">     _recordGlyphMousedOver: function(event)
</span><span class="cx">     {
</span><span class="cx">         this._recordGlyphElement.classList.remove(WebInspector.TimelineSidebarPanel.RecordGlyphRecordingForcedStyleClass);
</span><span class="lines">@@ -374,10 +445,15 @@
</span><span class="cx">         // Add forced class to prevent the glyph from showing a confusing status after click.
</span><span class="cx">         this._recordGlyphElement.classList.add(WebInspector.TimelineSidebarPanel.RecordGlyphRecordingForcedStyleClass);
</span><span class="cx"> 
</span><ins>+        var shouldCreateRecording = event.shiftKey;
+
</ins><span class="cx">         if (WebInspector.timelineManager.isCapturing())
</span><span class="cx">             WebInspector.timelineManager.stopCapturing();
</span><del>-        else
-            WebInspector.timelineManager.startCapturing();
</del><ins>+        else {
+            WebInspector.timelineManager.startCapturing(shouldCreateRecording);
+            // Show the timeline to which events will be appended.
+            this._recordingLoaded();
+        }
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     // These methods are only used when ReplayAgent is available.
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsTimelineViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineView.js (172093 => 172094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/TimelineView.js        2014-08-05 22:28:19 UTC (rev 172093)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TimelineView.js        2014-08-05 22:32:58 UTC (rev 172094)
</span><span class="lines">@@ -23,10 +23,34 @@
</span><span class="cx">  * THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-WebInspector.TimelineView = function()
</del><ins>+WebInspector.TimelineView = function(representedObject)
</ins><span class="cx"> {
</span><ins>+    if (this.constructor === WebInspector.TimelineView) {
+        // When instantiated directly return an instance of a type-based concrete subclass.
+
+        console.assert(representedObject &amp;&amp; representedObject instanceof WebInspector.Timeline);
+
+        var timelineType = representedObject.type;
+        if (timelineType === WebInspector.TimelineRecord.Type.Network)
+            return new WebInspector.NetworkTimelineView(representedObject);
+
+        if (timelineType === WebInspector.TimelineRecord.Type.Layout)
+            return new WebInspector.LayoutTimelineView(representedObject);
+
+        if (timelineType === WebInspector.TimelineRecord.Type.Script)
+            return new WebInspector.ScriptTimelineView(representedObject);
+
+        throw Error(&quot;Can't make a Timeline for an unknown representedObject.&quot;);
+    }
+
+    // Concrete object instantiation.
+    console.assert(this.constructor !== WebInspector.TimelineView &amp;&amp; this instanceof WebInspector.TimelineView);
+
</ins><span class="cx">     WebInspector.Object.call(this);
</span><span class="cx"> 
</span><ins>+    console.assert(representedObject instanceof WebInspector.Timeline || representedObject instanceof WebInspector.TimelineRecording);
+    this._representedObject = representedObject;
+
</ins><span class="cx">     this._contentTreeOutline = WebInspector.timelineSidebarPanel.createContentTreeOutline();
</span><span class="cx"> 
</span><span class="cx">     this.element = document.createElement(&quot;div&quot;);
</span><span class="lines">@@ -50,6 +74,11 @@
</span><span class="cx"> 
</span><span class="cx">     // Public
</span><span class="cx"> 
</span><ins>+    get representedObject()
+    {
+        return this._representedObject;
+    },
+
</ins><span class="cx">     get navigationSidebarTreeOutline()
</span><span class="cx">     {
</span><span class="cx">         return this._contentTreeOutline;
</span></span></pre>
</div>
</div>

</body>
</html>