c62faa9250105e7d580b4cb501fcf0d8a0fd657a
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / NetworkTimelineView.js
1 /*
2  * Copyright (C) 2014, 2015 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.NetworkTimelineView = class NetworkTimelineView extends WebInspector.TimelineView
27 {
28     constructor(timeline, extraArguments)
29     {
30         super(timeline, extraArguments);
31
32         console.assert(timeline.type === WebInspector.TimelineRecord.Type.Network);
33
34         let columns = {name: {}, domain: {}, type: {}, method: {}, scheme: {}, statusCode: {}, cached: {}, size: {}, transferSize: {}, requestSent: {}, latency: {}, duration: {}};
35
36         columns.name.title = WebInspector.UIString("Name");
37         columns.name.icon = true;
38         columns.name.width = "10%";
39
40         columns.domain.title = WebInspector.UIString("Domain");
41         columns.domain.width = "10%";
42
43         columns.type.title = WebInspector.UIString("Type");
44         columns.type.width = "8%";
45
46         var typeToLabelMap = new Map;
47         for (var key in WebInspector.Resource.Type) {
48             var value = WebInspector.Resource.Type[key];
49             typeToLabelMap.set(value, WebInspector.Resource.displayNameForType(value, true));
50         }
51
52         columns.type.scopeBar = WebInspector.TimelineDataGrid.createColumnScopeBar("network", typeToLabelMap);
53         this._scopeBar = columns.type.scopeBar;
54
55         columns.method.title = WebInspector.UIString("Method");
56         columns.method.width = "6%";
57
58         columns.scheme.title = WebInspector.UIString("Scheme");
59         columns.scheme.width = "6%";
60
61         columns.statusCode.title = WebInspector.UIString("Status");
62         columns.statusCode.width = "6%";
63
64         columns.cached.title = WebInspector.UIString("Cached");
65         columns.cached.width = "6%";
66
67         columns.size.title = WebInspector.UIString("Size");
68         columns.size.width = "8%";
69         columns.size.aligned = "right";
70
71         columns.transferSize.title = WebInspector.UIString("Transferred");
72         columns.transferSize.width = "8%";
73         columns.transferSize.aligned = "right";
74
75         columns.requestSent.title = WebInspector.UIString("Start Time");
76         columns.requestSent.width = "9%";
77         columns.requestSent.aligned = "right";
78
79         columns.latency.title = WebInspector.UIString("Latency");
80         columns.latency.width = "9%";
81         columns.latency.aligned = "right";
82
83         columns.duration.title = WebInspector.UIString("Duration");
84         columns.duration.width = "9%";
85         columns.duration.aligned = "right";
86
87         for (var column in columns)
88             columns[column].sortable = true;
89
90         this._dataGrid = new WebInspector.TimelineDataGrid(columns);
91         this._dataGrid.addEventListener(WebInspector.TimelineDataGrid.Event.FiltersDidChange, this._dataGridFiltersDidChange, this);
92         this._dataGrid.addEventListener(WebInspector.DataGrid.Event.SelectedNodeChanged, this._dataGridNodeSelected, this);
93         this._dataGrid.sortDelegate = this;
94         this._dataGrid.sortColumnIdentifierSetting = new WebInspector.Setting("network-timeline-view-sort", "requestSent");
95         this._dataGrid.sortOrderSetting = new WebInspector.Setting("network-timeline-view-sort-order", WebInspector.DataGrid.SortOrder.Ascending);
96
97         this.element.classList.add("network");
98         this.addSubview(this._dataGrid);
99
100         timeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._networkTimelineRecordAdded, this);
101
102         this._pendingRecords = [];
103         this._resourceDataGridNodeMap = new Map;
104     }
105
106     // Public
107
108     get selectionPathComponents()
109     {
110         if (!this._dataGrid.selectedNode || this._dataGrid.selectedNode.hidden)
111             return null;
112
113         console.assert(this._dataGrid.selectedNode instanceof WebInspector.ResourceTimelineDataGridNode);
114
115         let pathComponent = new WebInspector.TimelineDataGridNodePathComponent(this._dataGrid.selectedNode, this._dataGrid.selectedNode.resource);
116         pathComponent.addEventListener(WebInspector.HierarchicalPathComponent.Event.SiblingWasSelected, this.dataGridNodePathComponentSelected, this);
117         return [pathComponent];
118     }
119
120     shown()
121     {
122         super.shown();
123
124         this._dataGrid.shown();
125     }
126
127     hidden()
128     {
129         this._dataGrid.hidden();
130
131         super.hidden();
132     }
133
134     closed()
135     {
136         console.assert(this.representedObject instanceof WebInspector.Timeline);
137         this.representedObject.removeEventListener(null, null, this);
138
139         this._dataGrid.closed();
140     }
141
142     matchTreeElementAgainstCustomFilters(treeElement)
143     {
144         return this._dataGrid.treeElementMatchesActiveScopeFilters(treeElement);
145     }
146
147     reset()
148     {
149         super.reset();
150
151         this._dataGrid.reset();
152
153         this._pendingRecords = [];
154     }
155
156     // TimelineDataGrid sort delegate
157
158     dataGridSortComparator(sortColumnIdentifier, sortDirection, node1, node2)
159     {
160         if (sortColumnIdentifier !== "name")
161             return null;
162
163         let displayName1 = node1.displayName();
164         let displayName2 = node2.displayName();
165         if (displayName1 !== displayName2)
166             return displayName1.localeCompare(displayName2) * sortDirection;
167
168         return node1.resource.url.localeCompare(node2.resource.url) * sortDirection;
169     }
170
171     // Protected
172
173     canShowContentViewForTreeElement(treeElement)
174     {
175         if (treeElement instanceof WebInspector.ResourceTreeElement || treeElement instanceof WebInspector.ScriptTreeElement)
176             return true;
177         return super.canShowContentViewForTreeElement(treeElement);
178     }
179
180     showContentViewForTreeElement(treeElement)
181     {
182         if (treeElement instanceof WebInspector.ResourceTreeElement || treeElement instanceof WebInspector.ScriptTreeElement) {
183             WebInspector.showSourceCode(treeElement.representedObject);
184             return;
185         }
186
187         console.error("Unknown tree element selected.", treeElement);
188     }
189
190     dataGridNodePathComponentSelected(event)
191     {
192         let pathComponent = event.data.pathComponent;
193         console.assert(pathComponent instanceof WebInspector.TimelineDataGridNodePathComponent);
194
195         let dataGridNode = pathComponent.timelineDataGridNode;
196         console.assert(dataGridNode.dataGrid === this._dataGrid);
197
198         dataGridNode.revealAndSelect();
199     }
200
201     layout()
202     {
203         this._processPendingRecords();
204     }
205
206     // Private
207
208     _processPendingRecords()
209     {
210         if (!this._pendingRecords.length)
211             return;
212
213         for (let resourceTimelineRecord of this._pendingRecords) {
214             // Skip the record if it already exists in the grid.
215             // FIXME: replace with this._dataGrid.findDataGridNode(resourceTimelineRecord.resource) once <https://webkit.org/b/155305> is fixed.
216             let dataGridNode = this._resourceDataGridNodeMap.get(resourceTimelineRecord.resource);
217             if (dataGridNode)
218                 continue;
219
220             dataGridNode = new WebInspector.ResourceTimelineDataGridNode(resourceTimelineRecord, false, this);
221             this._resourceDataGridNodeMap.set(resourceTimelineRecord.resource, dataGridNode);
222
223             this._dataGrid.addRowInSortOrder(null, dataGridNode);
224         }
225
226         this._pendingRecords = [];
227     }
228
229     _networkTimelineRecordAdded(event)
230     {
231         var resourceTimelineRecord = event.data.record;
232         console.assert(resourceTimelineRecord instanceof WebInspector.ResourceTimelineRecord);
233
234         this._pendingRecords.push(resourceTimelineRecord);
235
236         this.needsLayout();
237     }
238
239     _dataGridFiltersDidChange(event)
240     {
241         // FIXME: <https://webkit.org/b/154924> Web Inspector: hook up grid row filtering in the new Timelines UI
242     }
243
244     _dataGridNodeSelected(event)
245     {
246         this.dispatchEventToListeners(WebInspector.ContentView.Event.SelectionPathComponentsDidChange);
247     }
248 };