Web Inspector: clicking Timelines tree view nodes should not change the current conte...
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / ResourceTimelineDataGridNode.js
1 /*
2  * Copyright (C) 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 WebInspector.ResourceTimelineDataGridNode = function(resourceTimelineRecord, graphOnly, graphDataSource)
27 {
28     WebInspector.TimelineDataGridNode.call(this, graphOnly, graphDataSource);
29
30     this._resource = resourceTimelineRecord.resource;
31     this._record = resourceTimelineRecord;
32
33     this._record.addEventListener(WebInspector.TimelineRecord.Event.Updated, graphOnly ? this._timelineRecordUpdated : this._needsRefresh, this);
34
35     if (!graphOnly) {
36         this._resource.addEventListener(WebInspector.Resource.Event.URLDidChange, this._needsRefresh, this);
37         this._resource.addEventListener(WebInspector.Resource.Event.TypeDidChange, this._needsRefresh, this);
38         this._resource.addEventListener(WebInspector.Resource.Event.LoadingDidFinish, this._needsRefresh, this);
39         this._resource.addEventListener(WebInspector.Resource.Event.LoadingDidFail, this._needsRefresh, this);
40         this._resource.addEventListener(WebInspector.Resource.Event.SizeDidChange, this._needsRefresh, this);
41         this._resource.addEventListener(WebInspector.Resource.Event.TransferSizeDidChange, this._needsRefresh, this);
42     }
43 };
44
45 // FIXME: Move to a WebInspector.Object subclass and we can remove this.
46 WebInspector.Object.deprecatedAddConstructorFunctions(WebInspector.ResourceTimelineDataGridNode);
47
48 WebInspector.ResourceTimelineDataGridNode.IconStyleClassName = "icon";
49 WebInspector.ResourceTimelineDataGridNode.ErrorStyleClassName = "error";
50
51 WebInspector.ResourceTimelineDataGridNode.prototype = {
52     constructor: WebInspector.ResourceTimelineDataGridNode,
53     __proto__: WebInspector.TimelineDataGridNode.prototype,
54
55     // Public
56
57     get records()
58     {
59         return [this._record];
60     },
61
62     get resource()
63     {
64         return this._resource;
65     },
66
67     get data()
68     {
69         if (this._cachedData)
70             return this._cachedData;
71
72         var resource = this._resource;
73         var data = {};
74
75         if (!this._graphOnly) {
76             var zeroTime = this.graphDataSource ? this.graphDataSource.zeroTime : 0;
77
78             data.domain = WebInspector.displayNameForHost(resource.urlComponents.host);
79             data.scheme = resource.urlComponents.scheme ? resource.urlComponents.scheme.toUpperCase() : "";
80             data.method = resource.requestMethod;
81             data.type = resource.type;
82             data.statusCode = resource.statusCode;
83             data.cached = resource.cached;
84             data.size = resource.size;
85             data.transferSize = resource.transferSize;
86             data.requestSent = resource.requestSentTimestamp - zeroTime;
87             data.duration = resource.receiveDuration;
88             data.latency = resource.latency;
89         }
90
91         data.graph = this._record.startTime;
92
93         this._cachedData = data;
94         return data;
95     },
96
97     createCellContent: function(columnIdentifier, cell)
98     {
99         var resource = this._resource;
100
101         if (resource.failed || resource.canceled || resource.statusCode >= 400)
102             cell.classList.add(WebInspector.ResourceTimelineDataGridNode.ErrorStyleClassName);
103
104         const emptyValuePlaceholderString = "\u2014";
105         var value = this.data[columnIdentifier];
106
107         switch (columnIdentifier) {
108         case "type":
109             return WebInspector.Resource.displayNameForType(value);
110
111         case "statusCode":
112             cell.title = resource.statusText || "";
113             return value || emptyValuePlaceholderString;
114
115         case "cached":
116             return value ? WebInspector.UIString("Yes") : WebInspector.UIString("No");
117
118         case "domain":
119             var fragment = document.createDocumentFragment();
120
121             var goToButton = WebInspector.createGoToArrowButton();
122             goToButton.addEventListener("click", this._goToResource.bind(this));
123             fragment.appendChild(goToButton);
124
125             var text = document.createTextNode(value || emptyValuePlaceholderString);
126             fragment.appendChild(text);
127
128             return fragment;
129
130         case "size":
131         case "transferSize":
132             return isNaN(value) ? emptyValuePlaceholderString : Number.bytesToString(value, true);
133
134         case "requestSent":
135         case "latency":
136         case "duration":
137             return isNaN(value) ? emptyValuePlaceholderString : Number.secondsToString(value, true);
138         }
139
140         return WebInspector.TimelineDataGridNode.prototype.createCellContent.call(this, columnIdentifier, cell);
141     },
142
143     refresh: function()
144     {
145         if (this._scheduledRefreshIdentifier) {
146             cancelAnimationFrame(this._scheduledRefreshIdentifier);
147             delete this._scheduledRefreshIdentifier;
148         }
149
150         delete this._cachedData;
151
152         WebInspector.TimelineDataGridNode.prototype.refresh.call(this);
153     },
154
155     // Private
156
157     _needsRefresh: function()
158     {
159         if (this.dataGrid instanceof WebInspector.TimelineDataGrid) {
160             this.dataGrid.dataGridNodeNeedsRefresh(this);
161             return;
162         }
163
164         if (this._scheduledRefreshIdentifier)
165             return;
166
167         this._scheduledRefreshIdentifier = requestAnimationFrame(this.refresh.bind(this));
168     },
169
170     _goToResource: function(event)
171     {
172         WebInspector.resourceSidebarPanel.showSourceCode(this._resource);
173     },
174
175     _timelineRecordUpdated: function(event)
176     {
177         if (this.isRecordVisible(this._record))
178             this.needsGraphRefresh();
179     }
180 };