Diff
Modified: trunk/Source/WebInspectorUI/ChangeLog (203842 => 203843)
--- trunk/Source/WebInspectorUI/ChangeLog 2016-07-28 21:19:06 UTC (rev 203842)
+++ trunk/Source/WebInspectorUI/ChangeLog 2016-07-28 21:38:50 UTC (rev 203843)
@@ -1,3 +1,56 @@
+2016-07-28 Johan K. Jensen <[email protected]>
+
+ Web Inspector: Waterfall view should be visible in Network tab and Network Timeline
+ https://bugs.webkit.org/show_bug.cgi?id=160061
+
+ Reviewed by Joseph Pecoraro.
+
+ Adds a Timeline-column (waterfall) to the Network tab and Network Timeline.
+
+ * Localizations/en.lproj/localizedStrings.js:
+ Add "Timeline" localized string.
+
+ * UserInterface/Views/NetworkGridContentView.js:
+ (WebInspector.NetworkGridContentView):
+ Add the Timeline-column with a TimelineRuler as the headerview,
+ and properties for updating current time.
+
+ (WebInspector.NetworkGridContentView.prototype.get secondsPerPixel):
+ (WebInspector.NetworkGridContentView.prototype.get startTime):
+ (WebInspector.NetworkGridContentView.prototype.get currentTime):
+ (WebInspector.NetworkGridContentView.prototype.get endTime):
+ Acting as a graphDataSource used by TimelineDataGridNode.
+
+ (WebInspector.NetworkGridContentView.prototype.shown):
+ (WebInspector.NetworkGridContentView.prototype.reset):
+ (WebInspector.NetworkGridContentView.prototype.layout):
+ Refresh graphs and update the TimelineRuler on layout changes.
+
+ (WebInspector.NetworkGridContentView.prototype._networkTimelineRecordAdded):
+ Add listeners for when resources are finished to stop the timer.
+
+ (WebInspector.NetworkGridContentView.prototype._update):
+ (WebInspector.NetworkGridContentView.prototype._startUpdatingCurrentTime):
+ (WebInspector.NetworkGridContentView.prototype._stopUpdatingCurrentTime):
+ Adding a timer which updates the TimelineRuler and the layout
+ if any non-finished requests are running.
+
+ * UserInterface/Views/NetworkTimelineView.js:
+ (WebInspector.NetworkTimelineView):
+ Add the Timeline-column with a TimelineRuler as the headerview.
+
+ (WebInspector.NetworkTimelineView.prototype.get secondsPerPixel):
+ (WebInspector.NetworkTimelineView.prototype.layout):
+ Refresh graphs on layout changes.
+
+ * UserInterface/Views/TimelineDataGrid.css:
+ (.tree-outline.timeline-data-grid .item:hover .subtitle):
+ (.data-grid.timeline th):
+ (.data-grid.timeline th.graph-column > .timeline-ruler):
+ (.data-grid.timeline td.graph-column):
+ (.data-grid.timeline td.graph-column > .cell-content):
+ (.data-grid.timeline td.graph-column .timeline-record-bar):
+
2016-07-28 Chris Dumez <[email protected]>
Parameter to table.deleteRow() / body.deleteRow() should be mandatory
Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (203842 => 203843)
--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2016-07-28 21:19:06 UTC (rev 203842)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2016-07-28 21:38:50 UTC (rev 203843)
@@ -706,6 +706,7 @@
localizedStrings["This property needs a value.\nClick to open autocomplete."] = "This property needs a value.\nClick to open autocomplete.";
localizedStrings["Time"] = "Time";
localizedStrings["Time until the load event fired, click to show the Network Requests timeline"] = "Time until the load event fired, click to show the Network Requests timeline";
+localizedStrings["Timeline"] = "Timeline";
localizedStrings["Timeline Recording %d"] = "Timeline Recording %d";
localizedStrings["Timelines"] = "Timelines";
localizedStrings["Timer %s Fired"] = "Timer %s Fired";
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/NetworkGridContentView.js (203842 => 203843)
--- trunk/Source/WebInspectorUI/UserInterface/Views/NetworkGridContentView.js 2016-07-28 21:19:06 UTC (rev 203842)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/NetworkGridContentView.js 2016-07-28 21:38:50 UTC (rev 203843)
@@ -37,7 +37,7 @@
this._contentTreeOutline = this._networkSidebarPanel.contentTreeOutline;
this._contentTreeOutline.addEventListener(WebInspector.TreeOutline.Event.SelectionDidChange, this._treeSelectionDidChange, this);
- var columns = {domain: {}, type: {}, method: {}, scheme: {}, statusCode: {}, cached: {}, size: {}, transferSize: {}, requestSent: {}, latency: {}, duration: {}};
+ var columns = {domain: {}, type: {}, method: {}, scheme: {}, statusCode: {}, cached: {}, size: {}, transferSize: {}, requestSent: {}, latency: {}, duration: {}, graph: {}};
columns.domain.title = WebInspector.UIString("Domain");
columns.domain.width = "10%";
@@ -80,6 +80,14 @@
for (var column in columns)
columns[column].sortable = true;
+ this._timelineRuler = new WebInspector.TimelineRuler;
+ this._timelineRuler.allowsClippedLabels = true;
+
+ columns.graph.title = WebInspector.UIString("Timeline");
+ columns.graph.width = "15%";
+ columns.graph.headerView = this._timelineRuler;
+ columns.graph.sortable = false;
+
this._dataGrid = new WebInspector.TimelineDataGrid(columns, this._contentTreeOutline);
this._dataGrid.addEventListener(WebInspector.DataGrid.Event.SelectedNodeChanged, this._dataGridNodeSelected, this);
this._dataGrid.sortColumnIdentifier = "requestSent";
@@ -97,10 +105,18 @@
this._clearNetworkItemsNavigationItem.addEventListener(WebInspector.ButtonNavigationItem.Event.Clicked, this._clearNetworkItems, this);
this._pendingRecords = [];
+ this._loadingResourceCount = 0;
+ this._lastUpdateTimestamp = NaN;
+ this._scheduledCurrentTimeUpdateIdentifier = undefined;
}
// Public
+ get secondsPerPixel() { return this._timelineRuler.secondsPerPixel; }
+ get startTime() { return this._timelineRuler.startTime; }
+ get currentTime() { return this.endTime || this.startTime; }
+ get endTime() { return this._timelineRuler.endTime; }
+
get selectionPathComponents()
{
if (!this._contentTreeOutline.selectedTreeElement || this._contentTreeOutline.selectedTreeElement.hidden)
@@ -126,6 +142,9 @@
super.shown();
this._dataGrid.shown();
+
+ if (this._loadingResourceCount && !this._scheduledCurrentTimeUpdateIdentifier)
+ this._startUpdatingCurrentTime();
}
hidden()
@@ -144,6 +163,15 @@
{
this._contentTreeOutline.removeChildren();
this._dataGrid.reset();
+
+ if (this._scheduledCurrentTimeUpdateIdentifier)
+ this._stopUpdatingCurrentTime();
+
+ this._loadingResourceCount = 0;
+ this._lastUpdateTimestamp = NaN;
+
+ this._timelineRuler.startTime = 0;
+ this._timelineRuler.endTime = 0;
}
// Protected
@@ -150,6 +178,12 @@
layout()
{
+ this._timelineRuler.zeroTime = this.zeroTime;
+ this._timelineRuler.startTime = this.zeroTime;
+
+ for (let dataGridNode of this._dataGrid.children)
+ dataGridNode.refreshGraph();
+
this._processPendingRecords();
}
@@ -185,9 +219,35 @@
var resourceTimelineRecord = event.data.record;
console.assert(resourceTimelineRecord instanceof WebInspector.ResourceTimelineRecord);
+ let update = (event) => {
+ if (event.target[WebInspector.NetworkGridContentView.ResourceDidFinishOrFail])
+ return;
+
+ event.target.removeEventListener(null, null, this);
+ event.target[WebInspector.NetworkGridContentView.ResourceDidFinishOrFail] = true;
+
+ this._loadingResourceCount--;
+ if (this._loadingResourceCount)
+ return;
+
+ this.debounce(250)._stopUpdatingCurrentTime();
+ };
+
this._pendingRecords.push(resourceTimelineRecord);
this.needsLayout();
+
+ let resource = resourceTimelineRecord.resource;
+ if (resource.finished || resource.failed || resource.canceled)
+ return;
+
+ resource[WebInspector.NetworkGridContentView.ResourceDidFinishOrFail] = false;
+ resource.addEventListener(WebInspector.Resource.Event.LoadingDidFinish, update, this);
+ resource.addEventListener(WebInspector.Resource.Event.LoadingDidFail, update, this);
+
+ this._loadingResourceCount++;
+ if (this._loadingResourceCount && !this._scheduledCurrentTimeUpdateIdentifier)
+ this._startUpdatingCurrentTime();
}
_treeElementPathComponentSelected(event)
@@ -222,4 +282,50 @@
_clearNetworkItems(event) {
this.reset();
}
+
+ _update(timestamp)
+ {
+ console.assert(this._scheduledCurrentTimeUpdateIdentifier);
+
+ let startTime = this.startTime;
+ let currentTime = this.currentTime;
+ let endTime = this.endTime;
+ let timespanSinceLastUpdate = (timestamp - this._lastUpdateTimestamp) / 1000 || 0;
+
+ currentTime += timespanSinceLastUpdate;
+
+ this._timelineRuler.endTime = currentTime;
+ this._lastUpdateTimestamp = timestamp;
+ this.updateLayout();
+
+ this._scheduledCurrentTimeUpdateIdentifier = requestAnimationFrame(this._updateCallback);
+ }
+
+ _startUpdatingCurrentTime()
+ {
+ console.assert(!this._scheduledCurrentTimeUpdateIdentifier);
+ if (this._scheduledCurrentTimeUpdateIdentifier)
+ return;
+
+ // Don't update the current time if the Inspector is not visible, as the requestAnimationFrames won't work.
+ if (!WebInspector.visible)
+ return;
+
+ if (!this._updateCallback)
+ this._updateCallback = this._update.bind(this);
+
+ this._scheduledCurrentTimeUpdateIdentifier = requestAnimationFrame(this._updateCallback);
+ }
+
+ _stopUpdatingCurrentTime()
+ {
+ console.assert(this._scheduledCurrentTimeUpdateIdentifier);
+ if (!this._scheduledCurrentTimeUpdateIdentifier)
+ return;
+
+ cancelAnimationFrame(this._scheduledCurrentTimeUpdateIdentifier);
+ this._scheduledCurrentTimeUpdateIdentifier = undefined;
+ }
};
+
+WebInspector.NetworkGridContentView.ResourceDidFinishOrFail = Symbol("ResourceDidFinishOrFail");
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTimelineView.js (203842 => 203843)
--- trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTimelineView.js 2016-07-28 21:19:06 UTC (rev 203842)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTimelineView.js 2016-07-28 21:38:50 UTC (rev 203843)
@@ -31,7 +31,7 @@
console.assert(timeline.type === WebInspector.TimelineRecord.Type.Network);
- let columns = {name: {}, domain: {}, type: {}, method: {}, scheme: {}, statusCode: {}, cached: {}, size: {}, transferSize: {}, requestSent: {}, latency: {}, duration: {}};
+ let columns = {name: {}, domain: {}, type: {}, method: {}, scheme: {}, statusCode: {}, cached: {}, size: {}, transferSize: {}, requestSent: {}, latency: {}, duration: {}, graph: {}};
columns.name.title = WebInspector.UIString("Name");
columns.name.icon = true;
@@ -39,10 +39,10 @@
columns.name.locked = true;
columns.domain.title = WebInspector.UIString("Domain");
- columns.domain.width = "10%";
+ columns.domain.width = "8%";
columns.type.title = WebInspector.UIString("Type");
- columns.type.width = "8%";
+ columns.type.width = "7%";
var typeToLabelMap = new Map;
for (var key in WebInspector.Resource.Type) {
@@ -54,16 +54,16 @@
this._scopeBar = columns.type.scopeBar;
columns.method.title = WebInspector.UIString("Method");
- columns.method.width = "6%";
+ columns.method.width = "4%";
columns.scheme.title = WebInspector.UIString("Scheme");
- columns.scheme.width = "6%";
+ columns.scheme.width = "4%";
columns.statusCode.title = WebInspector.UIString("Status");
- columns.statusCode.width = "6%";
+ columns.statusCode.width = "4%";
columns.cached.title = WebInspector.UIString("Cached");
- columns.cached.width = "6%";
+ columns.cached.width = "4%";
columns.size.title = WebInspector.UIString("Size");
columns.size.width = "8%";
@@ -88,6 +88,14 @@
for (var column in columns)
columns[column].sortable = true;
+ this._timelineRuler = new WebInspector.TimelineRuler;
+ this._timelineRuler.allowsClippedLabels = true;
+
+ columns.graph.title = WebInspector.UIString("Timeline");
+ columns.graph.width = "15%";
+ columns.graph.headerView = this._timelineRuler;
+ columns.graph.sortable = false;
+
this._dataGrid = new WebInspector.TimelineDataGrid(columns);
this._dataGrid.sortDelegate = this;
this._dataGrid.sortColumnIdentifier = "requestSent";
@@ -107,6 +115,8 @@
// Public
+ get secondsPerPixel() { return this._timelineRuler.secondsPerPixel; }
+
get selectionPathComponents()
{
if (!this._dataGrid.selectedNode || this._dataGrid.selectedNode.hidden)
@@ -197,6 +207,15 @@
layout()
{
+ this.endTime = Math.min(this.endTime, this.currentTime);
+
+ this._timelineRuler.zeroTime = this.zeroTime;
+ this._timelineRuler.startTime = this.startTime;
+ this._timelineRuler.endTime = this.endTime;
+
+ for (let dataGridNode of this._resourceDataGridNodeMap.values())
+ dataGridNode.refreshGraph();
+
this._processPendingRecords();
}
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineDataGrid.css (203842 => 203843)
--- trunk/Source/WebInspectorUI/UserInterface/Views/TimelineDataGrid.css 2016-07-28 21:19:06 UTC (rev 203842)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TimelineDataGrid.css 2016-07-28 21:38:50 UTC (rev 203843)
@@ -35,4 +35,26 @@
.tree-outline.timeline-data-grid .item:hover .subtitle {
color: white;
-}
\ No newline at end of file
+}
+
+.data-grid.timeline th {
+ border-top: none;
+}
+
+.data-grid.timeline th.graph-column > .timeline-ruler {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+}
+
+.data-grid.timeline td.graph-column {
+ padding: 2px 0;
+}
+
+.data-grid.timeline td.graph-column > .cell-content {
+ position: relative;
+}
+
+.data-grid.timeline td.graph-column .timeline-record-bar {
+ top: 2px;
+}