1/* 2 * Copyright (C) 2014 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 26WebInspector.NetworkTimelineView = function(recording) 27{ 28 WebInspector.TimelineView.call(this); 29 30 this.navigationSidebarTreeOutline.onselect = this._treeElementSelected.bind(this); 31 this.navigationSidebarTreeOutline.ondeselect = this._treeElementDeselected.bind(this); 32 this.navigationSidebarTreeOutline.element.classList.add(WebInspector.NavigationSidebarPanel.HideDisclosureButtonsStyleClassName); 33 this.navigationSidebarTreeOutline.element.classList.add(WebInspector.NetworkTimelineView.TreeOutlineStyleClassName); 34 35 var columns = {domain: {}, type: {}, method: {}, scheme: {}, statusCode: {}, cached: {}, size: {}, transferSize: {}, requestSent: {}, latency: {}, duration: {}}; 36 37 columns.domain.title = WebInspector.UIString("Domain"); 38 columns.domain.width = "10%"; 39 40 columns.type.title = WebInspector.UIString("Type"); 41 columns.type.width = "8%"; 42 columns.type.scopeBar = WebInspector.TimelineDataGrid.createColumnScopeBar("network", WebInspector.Resource.Type); 43 44 columns.method.title = WebInspector.UIString("Method"); 45 columns.method.width = "6%"; 46 47 columns.scheme.title = WebInspector.UIString("Scheme"); 48 columns.scheme.width = "6%"; 49 50 columns.statusCode.title = WebInspector.UIString("Status"); 51 columns.statusCode.width = "6%"; 52 53 columns.cached.title = WebInspector.UIString("Cached"); 54 columns.cached.width = "6%"; 55 56 columns.size.title = WebInspector.UIString("Size"); 57 columns.size.width = "8%"; 58 columns.size.aligned = "right"; 59 60 columns.transferSize.title = WebInspector.UIString("Transfered"); 61 columns.transferSize.width = "8%"; 62 columns.transferSize.aligned = "right"; 63 64 columns.requestSent.title = WebInspector.UIString("Start Time"); 65 columns.requestSent.width = "9%"; 66 columns.requestSent.aligned = "right"; 67 68 columns.latency.title = WebInspector.UIString("Latency"); 69 columns.latency.width = "9%"; 70 columns.latency.aligned = "right"; 71 72 columns.duration.title = WebInspector.UIString("Duration"); 73 columns.duration.width = "9%"; 74 columns.duration.aligned = "right"; 75 76 for (var column in columns) 77 columns[column].sortable = true; 78 79 this._dataGrid = new WebInspector.TimelineDataGrid(this.navigationSidebarTreeOutline, columns); 80 this._dataGrid.addEventListener(WebInspector.TimelineDataGrid.Event.FiltersDidChange, this._dataGridFiltersDidChange, this); 81 this._dataGrid.addEventListener(WebInspector.DataGrid.Event.SelectedNodeChanged, this._dataGridNodeSelected, this); 82 this._dataGrid.sortColumnIdentifier = "requestSent"; 83 this._dataGrid.sortOrder = WebInspector.DataGrid.SortOrder.Ascending; 84 85 this.element.classList.add(WebInspector.NetworkTimelineView.StyleClassName); 86 this.element.appendChild(this._dataGrid.element); 87 88 var networkTimeline = recording.timelines.get(WebInspector.TimelineRecord.Type.Network); 89 networkTimeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._networkTimelineRecordAdded, this); 90 91 this._pendingRecords = []; 92}; 93 94WebInspector.NetworkTimelineView.StyleClassName = "network"; 95WebInspector.NetworkTimelineView.TreeOutlineStyleClassName = "network"; 96 97WebInspector.NetworkTimelineView.prototype = { 98 constructor: WebInspector.NetworkTimelineView, 99 __proto__: WebInspector.TimelineView.prototype, 100 101 // Public 102 103 get navigationSidebarTreeOutlineLabel() 104 { 105 return WebInspector.UIString("Resources"); 106 }, 107 108 shown: function() 109 { 110 WebInspector.TimelineView.prototype.shown.call(this); 111 112 this._dataGrid.shown(); 113 }, 114 115 hidden: function() 116 { 117 this._dataGrid.hidden(); 118 119 WebInspector.TimelineView.prototype.hidden.call(this); 120 }, 121 122 updateLayout: function() 123 { 124 WebInspector.TimelineView.prototype.updateLayout.call(this); 125 126 this._dataGrid.updateLayout(); 127 128 this._processPendingRecords(); 129 }, 130 131 matchTreeElementAgainstCustomFilters: function(treeElement) 132 { 133 return this._dataGrid.treeElementMatchesActiveScopeFilters(treeElement); 134 }, 135 136 reset: function() 137 { 138 WebInspector.TimelineView.prototype.reset.call(this); 139 140 this._dataGrid.reset(); 141 }, 142 143 // Protected 144 145 treeElementPathComponentSelected: function(event) 146 { 147 var dataGridNode = this._dataGrid.dataGridNodeForTreeElement(event.data.pathComponent.generalTreeElement); 148 if (!dataGridNode) 149 return; 150 dataGridNode.revealAndSelect(); 151 }, 152 153 // Private 154 155 _processPendingRecords: function() 156 { 157 if (!this._pendingRecords.length) 158 return; 159 160 for (var resourceTimelineRecord of this._pendingRecords) { 161 // Skip the record if it already exists in the tree. 162 var treeElement = this.navigationSidebarTreeOutline.findTreeElement(resourceTimelineRecord.resource); 163 if (treeElement) 164 continue; 165 166 treeElement = new WebInspector.ResourceTreeElement(resourceTimelineRecord.resource); 167 var dataGridNode = new WebInspector.ResourceTimelineDataGridNode(resourceTimelineRecord, false, this); 168 169 this._dataGrid.addRowInSortOrder(treeElement, dataGridNode); 170 } 171 172 this._pendingRecords = []; 173 }, 174 175 _networkTimelineRecordAdded: function(event) 176 { 177 var resourceTimelineRecord = event.data.record; 178 console.assert(resourceTimelineRecord instanceof WebInspector.ResourceTimelineRecord); 179 180 this._pendingRecords.push(resourceTimelineRecord); 181 182 this.needsLayout(); 183 }, 184 185 _dataGridFiltersDidChange: function(event) 186 { 187 WebInspector.timelineSidebarPanel.updateFilter(); 188 }, 189 190 _dataGridNodeSelected: function(event) 191 { 192 this.dispatchEventToListeners(WebInspector.TimelineView.Event.SelectionPathComponentsDidChange); 193 }, 194 195 _treeElementDeselected: function(treeElement) 196 { 197 if (treeElement.status) 198 treeElement.status = ""; 199 }, 200 201 _treeElementSelected: function(treeElement, selectedByUser) 202 { 203 if (this._dataGrid.shouldIgnoreSelectionEvent()) 204 return; 205 206 if (!WebInspector.timelineSidebarPanel.canShowDifferentContentView()) 207 return; 208 209 if (treeElement instanceof WebInspector.FolderTreeElement) 210 return; 211 212 if (treeElement instanceof WebInspector.ResourceTreeElement || treeElement instanceof WebInspector.ScriptTreeElement) { 213 WebInspector.resourceSidebarPanel.showSourceCode(treeElement.representedObject); 214 this._updateTreeElementWithCloseButton(treeElement); 215 return; 216 } 217 218 console.error("Unknown tree element selected."); 219 }, 220 221 _updateTreeElementWithCloseButton: function(treeElement) 222 { 223 if (this._closeStatusButton) { 224 treeElement.status = this._closeStatusButton.element; 225 return; 226 } 227 228 wrappedSVGDocument(platformImagePath("Close.svg"), null, WebInspector.UIString("Close resource view"), function(element) { 229 this._closeStatusButton = new WebInspector.TreeElementStatusButton(element); 230 this._closeStatusButton.addEventListener(WebInspector.TreeElementStatusButton.Event.Clicked, this._closeStatusButtonClicked, this); 231 if (treeElement === this.navigationSidebarTreeOutline.selectedTreeElement) 232 this._updateTreeElementWithCloseButton(treeElement); 233 }.bind(this)); 234 }, 235 236 _closeStatusButtonClicked: function(event) 237 { 238 this.navigationSidebarTreeOutline.selectedTreeElement.deselect(); 239 WebInspector.timelineSidebarPanel.showTimelineView(WebInspector.TimelineRecord.Type.Network); 240 } 241}; 242