Diff
Modified: trunk/Source/WebInspectorUI/ChangeLog (224850 => 224851)
--- trunk/Source/WebInspectorUI/ChangeLog 2017-11-14 22:59:42 UTC (rev 224850)
+++ trunk/Source/WebInspectorUI/ChangeLog 2017-11-14 23:22:45 UTC (rev 224851)
@@ -1,3 +1,33 @@
+2017-11-14 Joseph Pecoraro <pecor...@apple.com>
+
+ Web Inspector: Network Detail Views - Split Metrics into Sizes and Timing
+ https://bugs.webkit.org/show_bug.cgi?id=179569
+ <rdar://problem/35484914>
+
+ Reviewed by Brian Burg.
+
+ * Localizations/en.lproj/localizedStrings.js:
+ * UserInterface/Main.html:
+ New resources and strings.
+
+ * UserInterface/Views/NetworkResourceDetailView.js:
+ (WI.NetworkResourceDetailView):
+ (WI.NetworkResourceDetailView.prototype.initialLayout):
+ (WI.NetworkResourceDetailView.prototype._showPreferredContentView):
+ (WI.NetworkResourceDetailView.prototype._showContentViewForNavigationItem):
+ (WI.NetworkResourceDetailView.prototype.sizesContentViewGoToHeaders): Renamed.
+ (WI.NetworkResourceDetailView.prototype.sizesContentViewGoToRequestBody): Renamed.
+ (WI.NetworkResourceDetailView.prototype.sizesContentViewGoToResponseBody): Renamed.
+ Split into two navigation items and views.
+
+ * UserInterface/Views/ResourceMetricsContentView.css: Removed.
+ * UserInterface/Views/ResourceMetricsContentView.js: Removed.
+ * UserInterface/Views/ResourceSizesContentView.css: Added.
+ * UserInterface/Views/ResourceSizesContentView.js: Added.
+ * UserInterface/Views/ResourceTimingContentView.css: Added.
+ * UserInterface/Views/ResourceTimingContentView.js: Added.
+ Split Metrics into two views.
+
2017-11-14 Matt Baker <mattba...@apple.com>
Web Inspector: Cleanup navigation bar dividers and separators
Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (224850 => 224851)
--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2017-11-14 22:59:42 UTC (rev 224850)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2017-11-14 23:22:45 UTC (rev 224851)
@@ -590,7 +590,6 @@
localizedStrings["Memory: %s"] = "Memory: %s";
localizedStrings["Message"] = "Message";
localizedStrings["Method"] = "Method";
-localizedStrings["Metrics"] = "Metrics";
localizedStrings["Microtask Dispatched"] = "Microtask Dispatched";
localizedStrings["Min"] = "Min";
localizedStrings["Missing Dependencies:%s"] = "Missing Dependencies:%s";
@@ -869,6 +868,7 @@
localizedStrings["Shrink"] = "Shrink";
localizedStrings["Size"] = "Size";
localizedStrings["Size of current object plus all objects it keeps alive"] = "Size of current object plus all objects it keeps alive";
+localizedStrings["Sizes"] = "Sizes";
localizedStrings["Sizing"] = "Sizing";
localizedStrings["Slice"] = "Slice";
localizedStrings["Snapshot %d"] = "Snapshot %d";
Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (224850 => 224851)
--- trunk/Source/WebInspectorUI/UserInterface/Main.html 2017-11-14 22:59:42 UTC (rev 224850)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.html 2017-11-14 23:22:45 UTC (rev 224851)
@@ -148,11 +148,12 @@
<link rel="stylesheet" href=""
<link rel="stylesheet" href=""
<link rel="stylesheet" href=""
- <link rel="stylesheet" href=""
<link rel="stylesheet" href=""
<link rel="stylesheet" href=""
<link rel="stylesheet" href=""
<link rel="stylesheet" href=""
+ <link rel="stylesheet" href=""
+ <link rel="stylesheet" href=""
<link rel="stylesheet" href=""
<link rel="stylesheet" href=""
<link rel="stylesheet" href=""
@@ -692,13 +693,14 @@
<script src=""
<script src=""
<script src=""
- <script src=""
<script src=""
<script src=""
<script src=""
<script src=""
+ <script src=""
<script src=""
<script src=""
+ <script src=""
<script src=""
<script src=""
<script src=""
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/NetworkResourceDetailView.js (224850 => 224851)
--- trunk/Source/WebInspectorUI/UserInterface/Views/NetworkResourceDetailView.js 2017-11-14 22:59:42 UTC (rev 224850)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/NetworkResourceDetailView.js 2017-11-14 23:22:45 UTC (rev 224851)
@@ -40,7 +40,8 @@
this._resourceContentView = null;
this._headersContentView = null;
this._cookiesContentView = null;
- this._metricsContentView = null;
+ this._sizesContentView = null;
+ this._timingContentView = null;
}
// Public
@@ -77,14 +78,14 @@
this._resourceContentView.showRequest();
}
- // ResourceMetricsContentView delegate
+ // ResourceSizesContentView delegate
- metricsContentViewGoToHeaders(metricsContentView)
+ sizesContentViewGoToHeaders(metricsContentView)
{
this._contentBrowser.navigationBar.selectedNavigationItem = this._headersNavigationItem;
}
- metricsContentViewGoToRequestBody(metricsContentView)
+ sizesContentViewGoToRequestBody(metricsContentView)
{
this._contentBrowser.navigationBar.selectedNavigationItem = this._previewNavigationItem;
@@ -91,7 +92,7 @@
this._resourceContentView.showRequest();
}
- metricsContentViewGoToResponseBody(metricsContentView)
+ sizesContentViewGoToResponseBody(metricsContentView)
{
this._contentBrowser.navigationBar.selectedNavigationItem = this._previewNavigationItem;
@@ -117,7 +118,8 @@
this._previewNavigationItem = new WI.RadioButtonNavigationItem("preview", WI.UIString("Preview"));
this._headersNavigationItem = new WI.RadioButtonNavigationItem("headers", WI.UIString("Headers"));
this._cookiesNavigationItem = new WI.RadioButtonNavigationItem("cookies", WI.UIString("Cookies"));
- this._metricsNavigationItem = new WI.RadioButtonNavigationItem("metrics", WI.UIString("Metrics"));
+ this._sizesNavigationItem = new WI.RadioButtonNavigationItem("sizes", WI.UIString("Sizes"));
+ this._timingNavigationItem = new WI.RadioButtonNavigationItem("timing", WI.UIString("Timing"));
// Insert all of our custom navigation items at the start of the ContentBrowser's NavigationBar.
let index = 0;
@@ -126,7 +128,8 @@
this._contentBrowser.navigationBar.insertNavigationItem(this._previewNavigationItem, index++);
this._contentBrowser.navigationBar.insertNavigationItem(this._headersNavigationItem, index++);
this._contentBrowser.navigationBar.insertNavigationItem(this._cookiesNavigationItem, index++);
- this._contentBrowser.navigationBar.insertNavigationItem(this._metricsNavigationItem, index++);
+ this._contentBrowser.navigationBar.insertNavigationItem(this._sizesNavigationItem, index++);
+ this._contentBrowser.navigationBar.insertNavigationItem(this._timingNavigationItem, index++);
this._contentBrowser.navigationBar.addEventListener(WI.NavigationBar.Event.NavigationItemSelected, this._navigationItemSelected, this);
this.addSubview(this._contentBrowser);
@@ -148,7 +151,8 @@
if (navigationItem !== this._previewNavigationItem
&& navigationItem !== this._headersNavigationItem
&& navigationItem !== this._cookiesNavigationItem
- && navigationItem !== this._metricsNavigationItem)
+ && navigationItem !== this._sizesNavigationItem
+ && navigationItem !== this._timingNavigationItem)
continue;
if (!firstNavigationItem)
@@ -182,11 +186,16 @@
this._cookiesContentView = new WI.ResourceCookiesContentView(this._resource);
this._contentBrowser.showContentView(this._cookiesContentView);
break;
- case "metrics":
- if (!this._metricsContentView)
- this._metricsContentView = new WI.ResourceMetricsContentView(this._resource, this);
- this._contentBrowser.showContentView(this._metricsContentView);
+ case "sizes":
+ if (!this._sizesContentView)
+ this._sizesContentView = new WI.ResourceSizesContentView(this._resource, this);
+ this._contentBrowser.showContentView(this._sizesContentView);
break;
+ case "timing":
+ if (!this._timingContentView)
+ this._timingContentView = new WI.ResourceTimingContentView(this._resource);
+ this._contentBrowser.showContentView(this._timingContentView);
+ break;
}
}
Deleted: trunk/Source/WebInspectorUI/UserInterface/Views/ResourceMetricsContentView.css (224850 => 224851)
--- trunk/Source/WebInspectorUI/UserInterface/Views/ResourceMetricsContentView.css 2017-11-14 22:59:42 UTC (rev 224850)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ResourceMetricsContentView.css 2017-11-14 23:22:45 UTC (rev 224851)
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-.resource-metrics {
- font-family: '-webkit-system-font';
-}
-
-.resource-metrics > .content {
- width: 550px;
- margin: 0 auto;
-}
-
-.resource-metrics > .content .label {
- color: gray;
-}
-
-.resource-metrics > .content > section {
- position: relative;
- padding: 10px 0;
-}
-
-.resource-metrics > .content > section .subtitle {
- margin-bottom: 10px;
- font-size: 14px;
- text-align: center;
- letter-spacing: 0.04em;
-}
-
-.resource-metrics > .content > section:not(:last-of-type) {
- border-bottom: 1px solid var(--border-color);
-}
-
-.resource-metrics > .content > section.split {
- display: flex;
- justify-content: center;
-}
-
-.resource-metrics > .content > section.split > .subsection {
- width: 160px;
- margin: 10px 0px;
-}
-
-.resource-metrics > .content > section.split > .subsection.large .icon {
- width: 32px;
- height: 32px;
-}
-
-.resource-metrics > .content > section.split > .subsection > table {
- margin: 0 auto;
-}
-
-.resource-metrics > .content > section.split > .divider {
- margin: 0 10px;
- border-right: 1px solid var(--border-color);
-}
-
-.resource-metrics > .content > section.network > .subsection > .container {
- display: flex;
- justify-content: center;
- margin-bottom: 8px;
-}
-
-.resource-metrics > .content > section.network .bytes-group {
- text-align: start;
-}
-
-.resource-metrics > .content > section.network .bytes {
- margin-top: 2px;
- font-size: 28px;
- display: inline-block;
-}
-
-.resource-metrics > .content > section.network table > tr > td.label {
- text-align: end;
-}
-
-.resource-metrics > .content > section.network .suffix {
- display: inline-block;
- margin: 13px 1px 0 1px;
- font-size: 15px;
-}
-
-.resource-metrics > .content > section.network img {
- width: 32px;
- height: 32px;
- margin: 3px;
-}
-
-.resource-metrics > .content > section.network .go-to-arrow {
- bottom: -1px;
- height: 12px;
- vertical-align: top;
-}
-
-.resource-metrics > .content > section.network .warning {
- display: inline-block;
- width: 10px;
- height: 10px;
- -webkit-margin-start: 3px;
-}
-
-.resource-metrics > .content > section.timing {
- padding: 20px 0;
-}
-
-.resource-metrics > .content > section.timing .subtitle {
- letter-spacing: 0.06em;
-}
-
-.resource-metrics > .content > section.timing > ul {
- margin: 0;
- padding: 0;
- list-style-type: none;
-}
-
-.resource-metrics > .content > section.timing > ul > li {
- position: relative;
- height: 20px;
- padding: 1px 0;
- line-height: 18px;
-}
-
-.resource-metrics > .content > section.timing > .waterfall {
- width: 500px;
- margin: auto;
-}
-
-.resource-metrics > .content > section.timing > .waterfall .block {
- top: 4px;
- min-width: 1px;
- height: 12px;
-}
-
-.resource-metrics > .content > section.timing > ul > li > .row-label {
- display: inline-block;
- min-width: 70px;
- color: black;
-}
-
-.resource-metrics > .content > section.timing > ul > li > .row-label {
- text-align: end;
-}
-
-.resource-metrics > .content > section.timing > ul > li > .time-label {
- position: absolute;
- top: 1px;
- color: gray;
-}
-
-.resource-metrics > .content > section.timing > ul > li.total .block {
- display: none;
-}
-
-.resource-metrics > .content > section.timing > ul > li.total .time-label {
- color: black;
-}
-
-.resource-metrics > .content > section.timing .indeterminate-progress-spinner {
- margin: 0 auto;
-}
-
-.resource-metrics > .content > section.timing .empty {
- text-align: center;
- color: gray;
-}
Deleted: trunk/Source/WebInspectorUI/UserInterface/Views/ResourceMetricsContentView.js (224850 => 224851)
--- trunk/Source/WebInspectorUI/UserInterface/Views/ResourceMetricsContentView.js 2017-11-14 22:59:42 UTC (rev 224850)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ResourceMetricsContentView.js 2017-11-14 23:22:45 UTC (rev 224851)
@@ -1,379 +0,0 @@
-/*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WI.ResourceMetricsContentView = class ResourceMetricsContentView extends WI.ContentView
-{
- constructor(resource, delegate)
- {
- super(null);
-
- console.assert(resource instanceof WI.Resource);
- console.assert(delegate);
-
- this._resource = resource;
- this._resource.addEventListener(WI.Resource.Event.SizeDidChange, this._resourceSizeDidChange, this);
- this._resource.addEventListener(WI.Resource.Event.TransferSizeDidChange, this._resourceTransferSizeDidChange, this);
- this._resource.addEventListener(WI.Resource.Event.MetricsDidChange, this._resourceMetricsDidChange, this);
- this._resource.addEventListener(WI.Resource.Event.TimestampsDidChange, this._resourceTimestampsDidChange, this);
-
- this._delegate = delegate;
-
- this.element.classList.add("resource-details", "resource-metrics");
-
- this._needsTransferSizesRefresh = false;
- this._needsResourceSizeRefresh = false;
- this._needsTimingRefresh = false;
- }
-
- // Protected
-
- initialLayout()
- {
- super.initialLayout();
-
- let contentElement = this.element.appendChild(document.createElement("div"));
- contentElement.className = "content";
-
- // Network.
-
- let networkSection = contentElement.appendChild(document.createElement("section"));
- networkSection.className = "network split";
-
- function createSizeComponents(parentElement, subtitle, imageSource, label1, label2) {
- let subtitleElement = parentElement.appendChild(document.createElement("div"));
- subtitleElement.className = "subtitle";
- subtitleElement.textContent = subtitle;
-
- let container = parentElement.appendChild(document.createElement("div"));
- container.className = "container";
-
- let imageElement = container.appendChild(document.createElement("img"));
- if (imageSource)
- imageElement.src = ""
-
- let groupElement = container.appendChild(document.createElement("div"));
- groupElement.className = "bytes-group";
-
- let bytesElement = groupElement.appendChild(document.createElement("div"));
- bytesElement.className = "bytes";
-
- let suffixElement = groupElement.appendChild(document.createElement("div"));
- suffixElement.className = "suffix";
-
- let table = parentElement.appendChild(document.createElement("table"));
- let headerRow = table.appendChild(document.createElement("tr"));
- let label1Element = headerRow.appendChild(document.createElement("td"));
- let value1Element = headerRow.appendChild(document.createElement("td"));
- let bodyRow = table.appendChild(document.createElement("tr"));
- let label2Element = bodyRow.appendChild(document.createElement("td"));
- let value2Element = bodyRow.appendChild(document.createElement("td"));
-
- label1Element.textContent = label1;
- label1Element.className = "label";
- label2Element.textContent = label2;
- label2Element.className = "label";
-
- return {
- container,
- bytesElement,
- suffixElement,
- imageElement,
- value1Element,
- value2Element,
- };
- }
-
- let sendingSection = networkSection.appendChild(document.createElement("div"));
- sendingSection.className = "subsection";
-
- let sendingComponents = createSizeComponents(sendingSection, WI.UIString("Bytes Sent"), "Images/Sending.svg", WI.UIString("Headers:"), WI.UIString("Body:"));
- this._sendingBytesElement = sendingComponents.bytesElement;
- this._sendingBytesSuffixElement = sendingComponents.suffixElement;
- this._sendingHeaderBytesElement = sendingComponents.value1Element;
- this._sendingBodyBytesElement = sendingComponents.value2Element;
-
- let bytesDivider = networkSection.appendChild(document.createElement("div"));
- bytesDivider.className = "divider";
-
- let receivingSection = networkSection.appendChild(document.createElement("div"));
- receivingSection.className = "subsection";
-
- let receivingComponents = createSizeComponents(receivingSection, WI.UIString("Bytes Received"), "Images/Receiving.svg", WI.UIString("Headers:"), WI.UIString("Body:"));
- this._receivingBytesElement = receivingComponents.bytesElement;
- this._receivingBytesSuffixElement = receivingComponents.suffixElement;
- this._receivingHeaderBytesElement = receivingComponents.value1Element;
- this._receivingBodyBytesElement = receivingComponents.value2Element;
-
- let resourceDivider = networkSection.appendChild(document.createElement("div"));
- resourceDivider.className = "divider";
-
- let resourceSection = networkSection.appendChild(document.createElement("div"));
- resourceSection.className = "subsection large";
-
- let resourceComponents = createSizeComponents(resourceSection, WI.UIString("Resource Size"), null, WI.UIString("Compression:"), WI.UIString("MIME Type:"));
- resourceComponents.container.classList.add(WI.ResourceTreeElement.ResourceIconStyleClassName, this._resource.type);
- resourceComponents.imageElement.classList.add("icon");
- this._resourceBytesElement = resourceComponents.bytesElement;
- this._resourceBytesSuffixElement = resourceComponents.suffixElement;
- this._compressionElement = resourceComponents.value1Element;
- this._contentTypeElement = resourceComponents.value2Element;
-
- // Timing.
-
- this._timingSection = contentElement.appendChild(document.createElement("section"));
- this._timingSection.className = "timing";
-
- this._timingSubtitle = document.createElement("div");
- this._timingSubtitle.className = "subtitle";
- this._timingSubtitle.textContent = WI.UIString("Timing");
-
- // Populate.
-
- this._refreshTransferSizeSections();
- this._refreshResourceSizeSection();
- this._refreshTimingSection();
-
- this._needsTransferSizesRefresh = false;
- this._needsResourceSizeRefresh = false;
- this._needsTimingRefresh = false;
- }
-
- layout()
- {
- super.layout();
-
- if (this._needsTransferSizesRefresh) {
- this._refreshTransferSizeSections();
- this._needsTransferSizesRefresh = false;
- }
-
- if (this._needsResourceSizeRefresh) {
- this._refreshResourceSizeSection();
- this._needsResourceSizeRefresh = false;
- }
-
- if (this._needsTimingRefresh) {
- this._refreshTimingSection();
- this._needsTimingRefresh = false;
- }
- }
-
- closed()
- {
- this._resource.removeEventListener(null, null, this);
-
- super.closed();
- }
-
- // Private
-
- _sizeComponents(bytes)
- {
- console.assert(bytes >= 0);
-
- // Prefer KB over B. And prefer 1 decimal point to keep sizes simple
- // but we will still need B if bytes is less than 0.1 KB.
- if (bytes < 103)
- return [bytes.toFixed(0), "B"];
-
- let kilobytes = bytes / 1024;
- if (kilobytes < 1024)
- return [kilobytes.toFixed(1), "KB"];
-
- let megabytes = kilobytes / 1024;
- if (megabytes < 1024)
- return [megabytes.toFixed(1), "MB"];
-
- let gigabytes = megabytes / 1024;
- return [gigabytes.toFixed(1), "GB"];
- }
-
- _refreshTransferSizeSections()
- {
- let bytesSentHeader = this._resource.requestHeadersTransferSize;
- let bytesSentBody = this._resource.requestBodyTransferSize;
- let bytesSent = bytesSentHeader + bytesSentBody;
-
- let bytesReceivedHeader = this._resource.responseHeadersTransferSize;
- let bytesReceivedBody = this._resource.responseBodyTransferSize;
- let bytesReceived = bytesReceivedHeader + bytesReceivedBody;
-
- let [sentValue, sentSuffix] = this._sizeComponents(bytesSent || 0);
- this._sendingBytesElement.textContent = sentValue;
- this._sendingBytesSuffixElement.textContent = sentSuffix;
-
- this._sendingHeaderBytesElement.textContent = bytesSentHeader ? Number.bytesToString(bytesSentHeader) : emDash;
- this._sendingBodyBytesElement.textContent = bytesSentBody ? Number.bytesToString(bytesSentBody) : emDash;
-
- let [receivedValue, receivedSuffix] = this._sizeComponents(bytesReceived || 0);
- this._receivingBytesElement.textContent = receivedValue;
- this._receivingBytesSuffixElement.textContent = receivedSuffix;
-
- this._receivingHeaderBytesElement.textContent = bytesReceivedHeader ? Number.bytesToString(bytesReceivedHeader) : emDash;
- this._receivingBodyBytesElement.textContent = bytesReceivedBody ? Number.bytesToString(bytesReceivedBody) : emDash;
-
- function appendGoToArrow(parentElement, handler) {
- let goToButton = parentElement.appendChild(WI.createGoToArrowButton());
- goToButton.addEventListener("click", handler);
- }
-
- if (bytesSentHeader)
- appendGoToArrow(this._sendingHeaderBytesElement, () => { this._delegate.metricsContentViewGoToHeaders(this); });
- if (bytesSentBody)
- appendGoToArrow(this._sendingBodyBytesElement, () => { this._delegate.metricsContentViewGoToRequestBody(this); });
- if (bytesReceivedHeader)
- appendGoToArrow(this._receivingHeaderBytesElement, () => { this._delegate.metricsContentViewGoToHeaders(this); });
- if (bytesReceivedBody)
- appendGoToArrow(this._receivingBodyBytesElement, () => { this._delegate.metricsContentViewGoToResponseBody(this); });
- }
-
- _refreshResourceSizeSection()
- {
- let encodedSize = !isNaN(this._resource.networkEncodedSize) ? this._resource.networkEncodedSize : this._resource.estimatedNetworkEncodedSize;
- let decodedSize = !isNaN(this._resource.networkDecodedSize) ? this._resource.networkDecodedSize : this._resource.size;
- let compressionRate = decodedSize / encodedSize;
- let compressionString = compressionRate > 0 && isFinite(compressionRate) ? WI.UIString("%.2f\u00d7").format(compressionRate) : WI.UIString("None");
-
- let [resourceSizeValue, resourceSizeSuffix] = this._sizeComponents(decodedSize || 0);
- this._resourceBytesElement.textContent = resourceSizeValue;
- this._resourceBytesSuffixElement.textContent = resourceSizeSuffix;
-
- let contentEncoding = this._resource.responseHeaders.valueForCaseInsensitiveKey("Content-Encoding");
- if (contentEncoding)
- compressionString += ` (${contentEncoding.toLowerCase()})`;
-
- this._compressionElement.textContent = compressionString;
- this._contentTypeElement.textContent = this._resource.mimeType || emDash;
-
- const minimumSizeBeforeWarning = 1024;
- if (compressionRate <= 1 && encodedSize >= minimumSizeBeforeWarning && WI.shouldTreatMIMETypeAsText(this._resource.mimeType))
- this._compressionElement.appendChild(WI.ImageUtilities.useSVGSymbol("Images/Warning.svg", "warning", WI.UIString("This text resource could benefit from compression")));
- }
-
- _refreshTimingSection()
- {
- this._timingSection.removeChildren();
-
- this._timingSection.appendChild(this._timingSubtitle);
-
- if (!this._resource.hasResponse()) {
- let spinner = new WI.IndeterminateProgressSpinner;
- this._timingSection.appendChild(spinner.element);
- return;
- }
-
- if (!this._resource.timingData.startTime || !this._resource.timingData.responseEnd) {
- let p = this._timingSection.appendChild(document.createElement("p"));
- p.className = "empty";
- p.textContent = WI.UIString("Resource does not have timing data");
- return;
- }
-
- // FIXME: Converge on using WI.ResourceTimingBreakdownView when a design is finalized.
-
- let listElement = this._timingSection.appendChild(document.createElement("ul"));
- listElement.className = "waterfall"; // Include waterfall block styles.
-
- const graphWidth = 380;
- const graphStartOffset = 80;
-
- let {startTime, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, responseStart, responseEnd} = this._resource.timingData;
- let graphStartTime = startTime;
- let graphEndTime = responseEnd;
- let secondsPerPixel = (responseEnd - startTime) / graphWidth;
-
- function createBlock(startTime, endTime, className, makeEmpty) {
- let startOffset = graphStartOffset + ((startTime - graphStartTime) / secondsPerPixel);
- let width = makeEmpty ? 1 : (endTime - startTime) / secondsPerPixel;
- let block = document.createElement("div");
- block.classList.add("block", className);
- let property = WI.resolvedLayoutDirection() === WI.LayoutDirection.RTL ? "right" : "left";
- block.style[property] = startOffset + "px";
- block.style.width = width + "px";
- return block;
- }
-
- function createTimeLabel(endTime, label) {
- let positionOffset = graphStartOffset + ((endTime - graphStartTime) / secondsPerPixel);
- positionOffset += 3;
- let timeLabel = document.createElement("div");
- timeLabel.className = "time-label";
- timeLabel.textContent = label;
- let property = WI.resolvedLayoutDirection() === WI.LayoutDirection.RTL ? "right" : "left";
- timeLabel.style[property] = positionOffset + "px";
- return timeLabel;
- }
-
- function createRow(label, startTime, endTime, className) {
- let row = document.createElement("li");
- let labelElement = row.appendChild(document.createElement("span"));
- labelElement.className = "row-label";
- labelElement.textContent = label;
- row.appendChild(createBlock(startTime, endTime, className));
- row.appendChild(createTimeLabel(endTime, Number.secondsToMillisecondsString(endTime - startTime)));
- return row;
- }
-
- listElement.appendChild(createRow(WI.UIString("Scheduled"), startTime, domainLookupStart || connectStart || requestStart, "queue"));
- if (domainLookupStart)
- listElement.appendChild(createRow(WI.UIString("DNS"), domainLookupStart, domainLookupEnd || connectStart || requestStart, "dns"));
- if (connectStart)
- listElement.appendChild(createRow(WI.UIString("TCP"), connectStart, connectEnd || requestStart, "connect"));
- if (secureConnectionStart)
- listElement.appendChild(createRow(WI.UIString("Secure"), secureConnectionStart, connectEnd || requestStart, "secure"));
- listElement.appendChild(createRow(WI.UIString("Request"), requestStart, responseStart, "request"));
- listElement.appendChild(createRow(WI.UIString("Response"), responseStart, responseEnd, "response"));
-
- let totalRow = createRow(WI.UIString("Total"), startTime, responseEnd, "total");
- listElement.appendChild(totalRow);
- totalRow.classList.add("total");
- }
-
- _resourceSizeDidChange(event)
- {
- this._needsTransferSizesRefresh = true;
- this.needsLayout();
- }
-
- _resourceTransferSizeDidChange(event)
- {
- this._needsTransferSizesRefresh = true;
- this.needsLayout();
- }
-
- _resourceMetricsDidChange(event)
- {
- this._needsTransferSizesRefresh = true;
- this._needsResourceSizeRefresh = true;
- this._needsTimingRefresh = true;
- this.needsLayout();
- }
-
- _resourceTimestampsDidChange(event)
- {
- this._needsTimingRefresh = true;
- this.needsLayout();
- }
-};
Added: trunk/Source/WebInspectorUI/UserInterface/Views/ResourceSizesContentView.css (0 => 224851)
--- trunk/Source/WebInspectorUI/UserInterface/Views/ResourceSizesContentView.css (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ResourceSizesContentView.css 2017-11-14 23:22:45 UTC (rev 224851)
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.resource-sizes {
+ font-family: '-webkit-system-font';
+}
+
+.resource-sizes > .content {
+ width: 550px;
+ margin: 0 auto;
+}
+
+.resource-sizes > .content .label {
+ color: gray;
+}
+
+.resource-sizes > .content > section {
+ position: relative;
+ padding: 10px 0;
+}
+
+.resource-sizes > .content > section .subtitle {
+ margin-bottom: 10px;
+ font-size: 14px;
+ text-align: center;
+ letter-spacing: 0.04em;
+}
+
+.resource-sizes > .content > section.split {
+ display: flex;
+ justify-content: center;
+}
+
+.resource-sizes > .content > section.split > .subsection {
+ width: 160px;
+ margin: 10px 0px;
+}
+
+.resource-sizes > .content > section.split > .subsection.large .icon {
+ width: 32px;
+ height: 32px;
+}
+
+.resource-sizes > .content > section.split > .subsection > table {
+ margin: 0 auto;
+}
+
+.resource-sizes > .content > section.split > .divider {
+ margin: 0 10px;
+ border-right: 1px solid var(--border-color);
+}
+
+.resource-sizes > .content > section.network > .subsection > .container {
+ display: flex;
+ justify-content: center;
+ margin-bottom: 8px;
+}
+
+.resource-sizes > .content > section.network .bytes-group {
+ text-align: start;
+}
+
+.resource-sizes > .content > section.network .bytes {
+ margin-top: 2px;
+ font-size: 28px;
+ display: inline-block;
+}
+
+.resource-sizes > .content > section.network table > tr > td.label {
+ text-align: end;
+}
+
+.resource-sizes > .content > section.network .suffix {
+ display: inline-block;
+ margin: 13px 1px 0 1px;
+ font-size: 15px;
+}
+
+.resource-sizes > .content > section.network img {
+ width: 32px;
+ height: 32px;
+ margin: 3px;
+}
+
+.resource-sizes > .content > section.network .go-to-arrow {
+ bottom: -1px;
+ height: 12px;
+ vertical-align: top;
+}
+
+.resource-sizes > .content > section.network .warning {
+ display: inline-block;
+ width: 10px;
+ height: 10px;
+ -webkit-margin-start: 3px;
+}
Copied: trunk/Source/WebInspectorUI/UserInterface/Views/ResourceSizesContentView.js (from rev 224850, trunk/Source/WebInspectorUI/UserInterface/Views/ResourceMetricsContentView.js) (0 => 224851)
--- trunk/Source/WebInspectorUI/UserInterface/Views/ResourceSizesContentView.js (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ResourceSizesContentView.js 2017-11-14 23:22:45 UTC (rev 224851)
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WI.ResourceSizesContentView = class ResourceSizesContentView extends WI.ContentView
+{
+ constructor(resource, delegate)
+ {
+ super(null);
+
+ console.assert(resource instanceof WI.Resource);
+ console.assert(delegate);
+
+ this._resource = resource;
+ this._resource.addEventListener(WI.Resource.Event.SizeDidChange, this._resourceSizeDidChange, this);
+ this._resource.addEventListener(WI.Resource.Event.TransferSizeDidChange, this._resourceTransferSizeDidChange, this);
+ this._resource.addEventListener(WI.Resource.Event.MetricsDidChange, this._resourceMetricsDidChange, this);
+
+ this._delegate = delegate;
+
+ this.element.classList.add("resource-details", "resource-sizes");
+
+ this._needsTransferSizesRefresh = false;
+ this._needsResourceSizeRefresh = false;
+ }
+
+ // Protected
+
+ initialLayout()
+ {
+ super.initialLayout();
+
+ let contentElement = this.element.appendChild(document.createElement("div"));
+ contentElement.className = "content";
+
+ let networkSection = contentElement.appendChild(document.createElement("section"));
+ networkSection.className = "network split";
+
+ function createSizeComponents(parentElement, subtitle, imageSource, label1, label2) {
+ let subtitleElement = parentElement.appendChild(document.createElement("div"));
+ subtitleElement.className = "subtitle";
+ subtitleElement.textContent = subtitle;
+
+ let container = parentElement.appendChild(document.createElement("div"));
+ container.className = "container";
+
+ let imageElement = container.appendChild(document.createElement("img"));
+ if (imageSource)
+ imageElement.src = ""
+
+ let groupElement = container.appendChild(document.createElement("div"));
+ groupElement.className = "bytes-group";
+
+ let bytesElement = groupElement.appendChild(document.createElement("div"));
+ bytesElement.className = "bytes";
+
+ let suffixElement = groupElement.appendChild(document.createElement("div"));
+ suffixElement.className = "suffix";
+
+ let table = parentElement.appendChild(document.createElement("table"));
+ let headerRow = table.appendChild(document.createElement("tr"));
+ let label1Element = headerRow.appendChild(document.createElement("td"));
+ let value1Element = headerRow.appendChild(document.createElement("td"));
+ let bodyRow = table.appendChild(document.createElement("tr"));
+ let label2Element = bodyRow.appendChild(document.createElement("td"));
+ let value2Element = bodyRow.appendChild(document.createElement("td"));
+
+ label1Element.textContent = label1;
+ label1Element.className = "label";
+ label2Element.textContent = label2;
+ label2Element.className = "label";
+
+ return {
+ container,
+ bytesElement,
+ suffixElement,
+ imageElement,
+ value1Element,
+ value2Element,
+ };
+ }
+
+ let sendingSection = networkSection.appendChild(document.createElement("div"));
+ sendingSection.className = "subsection";
+
+ let sendingComponents = createSizeComponents(sendingSection, WI.UIString("Bytes Sent"), "Images/Sending.svg", WI.UIString("Headers:"), WI.UIString("Body:"));
+ this._sendingBytesElement = sendingComponents.bytesElement;
+ this._sendingBytesSuffixElement = sendingComponents.suffixElement;
+ this._sendingHeaderBytesElement = sendingComponents.value1Element;
+ this._sendingBodyBytesElement = sendingComponents.value2Element;
+
+ let bytesDivider = networkSection.appendChild(document.createElement("div"));
+ bytesDivider.className = "divider";
+
+ let receivingSection = networkSection.appendChild(document.createElement("div"));
+ receivingSection.className = "subsection";
+
+ let receivingComponents = createSizeComponents(receivingSection, WI.UIString("Bytes Received"), "Images/Receiving.svg", WI.UIString("Headers:"), WI.UIString("Body:"));
+ this._receivingBytesElement = receivingComponents.bytesElement;
+ this._receivingBytesSuffixElement = receivingComponents.suffixElement;
+ this._receivingHeaderBytesElement = receivingComponents.value1Element;
+ this._receivingBodyBytesElement = receivingComponents.value2Element;
+
+ let resourceDivider = networkSection.appendChild(document.createElement("div"));
+ resourceDivider.className = "divider";
+
+ let resourceSection = networkSection.appendChild(document.createElement("div"));
+ resourceSection.className = "subsection large";
+
+ let resourceComponents = createSizeComponents(resourceSection, WI.UIString("Resource Size"), null, WI.UIString("Compression:"), WI.UIString("MIME Type:"));
+ resourceComponents.container.classList.add(WI.ResourceTreeElement.ResourceIconStyleClassName, this._resource.type);
+ resourceComponents.imageElement.classList.add("icon");
+ this._resourceBytesElement = resourceComponents.bytesElement;
+ this._resourceBytesSuffixElement = resourceComponents.suffixElement;
+ this._compressionElement = resourceComponents.value1Element;
+ this._contentTypeElement = resourceComponents.value2Element;
+
+ this._refreshTransferSizeSections();
+ this._refreshResourceSizeSection();
+
+ this._needsTransferSizesRefresh = false;
+ this._needsResourceSizeRefresh = false;
+ }
+
+ layout()
+ {
+ super.layout();
+
+ if (this._needsTransferSizesRefresh) {
+ this._refreshTransferSizeSections();
+ this._needsTransferSizesRefresh = false;
+ }
+
+ if (this._needsResourceSizeRefresh) {
+ this._refreshResourceSizeSection();
+ this._needsResourceSizeRefresh = false;
+ }
+ }
+
+ closed()
+ {
+ this._resource.removeEventListener(null, null, this);
+
+ super.closed();
+ }
+
+ // Private
+
+ _sizeComponents(bytes)
+ {
+ console.assert(bytes >= 0);
+
+ // Prefer KB over B. And prefer 1 decimal point to keep sizes simple
+ // but we will still need B if bytes is less than 0.1 KB.
+ if (bytes < 103)
+ return [bytes.toFixed(0), "B"];
+
+ let kilobytes = bytes / 1024;
+ if (kilobytes < 1024)
+ return [kilobytes.toFixed(1), "KB"];
+
+ let megabytes = kilobytes / 1024;
+ if (megabytes < 1024)
+ return [megabytes.toFixed(1), "MB"];
+
+ let gigabytes = megabytes / 1024;
+ return [gigabytes.toFixed(1), "GB"];
+ }
+
+ _refreshTransferSizeSections()
+ {
+ let bytesSentHeader = this._resource.requestHeadersTransferSize;
+ let bytesSentBody = this._resource.requestBodyTransferSize;
+ let bytesSent = bytesSentHeader + bytesSentBody;
+
+ let bytesReceivedHeader = this._resource.responseHeadersTransferSize;
+ let bytesReceivedBody = this._resource.responseBodyTransferSize;
+ let bytesReceived = bytesReceivedHeader + bytesReceivedBody;
+
+ let [sentValue, sentSuffix] = this._sizeComponents(bytesSent || 0);
+ this._sendingBytesElement.textContent = sentValue;
+ this._sendingBytesSuffixElement.textContent = sentSuffix;
+
+ this._sendingHeaderBytesElement.textContent = bytesSentHeader ? Number.bytesToString(bytesSentHeader) : emDash;
+ this._sendingBodyBytesElement.textContent = bytesSentBody ? Number.bytesToString(bytesSentBody) : emDash;
+
+ let [receivedValue, receivedSuffix] = this._sizeComponents(bytesReceived || 0);
+ this._receivingBytesElement.textContent = receivedValue;
+ this._receivingBytesSuffixElement.textContent = receivedSuffix;
+
+ this._receivingHeaderBytesElement.textContent = bytesReceivedHeader ? Number.bytesToString(bytesReceivedHeader) : emDash;
+ this._receivingBodyBytesElement.textContent = bytesReceivedBody ? Number.bytesToString(bytesReceivedBody) : emDash;
+
+ function appendGoToArrow(parentElement, handler) {
+ let goToButton = parentElement.appendChild(WI.createGoToArrowButton());
+ goToButton.addEventListener("click", handler);
+ }
+
+ if (bytesSentHeader)
+ appendGoToArrow(this._sendingHeaderBytesElement, () => { this._delegate.sizesContentViewGoToHeaders(this); });
+ if (bytesSentBody)
+ appendGoToArrow(this._sendingBodyBytesElement, () => { this._delegate.sizesContentViewGoToRequestBody(this); });
+ if (bytesReceivedHeader)
+ appendGoToArrow(this._receivingHeaderBytesElement, () => { this._delegate.sizesContentViewGoToHeaders(this); });
+ if (bytesReceivedBody)
+ appendGoToArrow(this._receivingBodyBytesElement, () => { this._delegate.sizesContentViewGoToResponseBody(this); });
+ }
+
+ _refreshResourceSizeSection()
+ {
+ let encodedSize = !isNaN(this._resource.networkEncodedSize) ? this._resource.networkEncodedSize : this._resource.estimatedNetworkEncodedSize;
+ let decodedSize = !isNaN(this._resource.networkDecodedSize) ? this._resource.networkDecodedSize : this._resource.size;
+ let compressionRate = decodedSize / encodedSize;
+ let compressionString = compressionRate > 0 && isFinite(compressionRate) ? WI.UIString("%.2f\u00d7").format(compressionRate) : WI.UIString("None");
+
+ let [resourceSizeValue, resourceSizeSuffix] = this._sizeComponents(decodedSize || 0);
+ this._resourceBytesElement.textContent = resourceSizeValue;
+ this._resourceBytesSuffixElement.textContent = resourceSizeSuffix;
+
+ let contentEncoding = this._resource.responseHeaders.valueForCaseInsensitiveKey("Content-Encoding");
+ if (contentEncoding)
+ compressionString += ` (${contentEncoding.toLowerCase()})`;
+
+ this._compressionElement.textContent = compressionString;
+ this._contentTypeElement.textContent = this._resource.mimeType || emDash;
+
+ const minimumSizeBeforeWarning = 1024;
+ if (compressionRate <= 1 && encodedSize >= minimumSizeBeforeWarning && WI.shouldTreatMIMETypeAsText(this._resource.mimeType))
+ this._compressionElement.appendChild(WI.ImageUtilities.useSVGSymbol("Images/Warning.svg", "warning", WI.UIString("This text resource could benefit from compression")));
+ }
+
+ _resourceSizeDidChange(event)
+ {
+ this._needsTransferSizesRefresh = true;
+ this.needsLayout();
+ }
+
+ _resourceTransferSizeDidChange(event)
+ {
+ this._needsTransferSizesRefresh = true;
+ this.needsLayout();
+ }
+
+ _resourceMetricsDidChange(event)
+ {
+ this._needsTransferSizesRefresh = true;
+ this._needsResourceSizeRefresh = true;
+ this.needsLayout();
+ }
+};
Added: trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimingContentView.css (0 => 224851)
--- trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimingContentView.css (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimingContentView.css 2017-11-14 23:22:45 UTC (rev 224851)
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.resource-timing {
+ font-family: '-webkit-system-font';
+}
+
+.resource-timing > .content {
+ width: 550px;
+ margin: 0 auto;
+}
+
+.resource-timing > .content .label {
+ color: gray;
+}
+
+.resource-timing > .content > section.timing {
+ padding: 20px 0;
+}
+
+.resource-timing > .content > section.timing > ul {
+ margin: 0;
+ padding: 0;
+ list-style-type: none;
+}
+
+.resource-timing > .content > section.timing > ul > li {
+ position: relative;
+ height: 20px;
+ padding: 1px 0;
+ line-height: 18px;
+}
+
+.resource-timing > .content > section.timing > .waterfall {
+ width: 500px;
+ margin: auto;
+}
+
+.resource-timing > .content > section.timing > .waterfall .block {
+ top: 4px;
+ min-width: 1px;
+ height: 12px;
+}
+
+.resource-timing > .content > section.timing > ul > li > .row-label {
+ display: inline-block;
+ min-width: 70px;
+ color: black;
+}
+
+.resource-timing > .content > section.timing > ul > li > .row-label {
+ text-align: end;
+}
+
+.resource-timing > .content > section.timing > ul > li > .time-label {
+ position: absolute;
+ top: 1px;
+ color: gray;
+}
+
+.resource-timing > .content > section.timing > ul > li.total .block {
+ display: none;
+}
+
+.resource-timing > .content > section.timing > ul > li.total .time-label {
+ color: black;
+}
+
+.resource-timing > .content > section.timing .indeterminate-progress-spinner {
+ margin: 0 auto;
+}
+
+.resource-timing > .content > section.timing .empty {
+ text-align: center;
+ color: gray;
+}
Added: trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimingContentView.js (0 => 224851)
--- trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimingContentView.js (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimingContentView.js 2017-11-14 23:22:45 UTC (rev 224851)
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WI.ResourceTimingContentView = class ResourceTimingContentView extends WI.ContentView
+{
+ constructor(resource)
+ {
+ super(null);
+
+ console.assert(resource instanceof WI.Resource);
+
+ this._resource = resource;
+ this._resource.addEventListener(WI.Resource.Event.MetricsDidChange, this._resourceMetricsDidChange, this);
+ this._resource.addEventListener(WI.Resource.Event.TimestampsDidChange, this._resourceTimestampsDidChange, this);
+
+ this.element.classList.add("resource-details", "resource-timing");
+
+ this._needsTimingRefresh = false;
+ }
+
+ // Protected
+
+ initialLayout()
+ {
+ super.initialLayout();
+
+ let contentElement = this.element.appendChild(document.createElement("div"));
+ contentElement.className = "content";
+
+ this._timingSection = contentElement.appendChild(document.createElement("section"));
+ this._timingSection.className = "timing";
+
+ this._refreshTimingSection();
+
+ this._needsTimingRefresh = false;
+ }
+
+ layout()
+ {
+ super.layout();
+
+ if (this._needsTimingRefresh) {
+ this._refreshTimingSection();
+ this._needsTimingRefresh = false;
+ }
+ }
+
+ closed()
+ {
+ this._resource.removeEventListener(null, null, this);
+
+ super.closed();
+ }
+
+ // Private
+
+ _refreshTimingSection()
+ {
+ this._timingSection.removeChildren();
+
+ if (!this._resource.hasResponse()) {
+ let spinner = new WI.IndeterminateProgressSpinner;
+ this._timingSection.appendChild(spinner.element);
+ return;
+ }
+
+ if (!this._resource.timingData.startTime || !this._resource.timingData.responseEnd) {
+ let p = this._timingSection.appendChild(document.createElement("p"));
+ p.className = "empty";
+ p.textContent = WI.UIString("Resource does not have timing data");
+ return;
+ }
+
+ // FIXME: Converge on using WI.ResourceTimingBreakdownView when a design is finalized.
+
+ let listElement = this._timingSection.appendChild(document.createElement("ul"));
+ listElement.className = "waterfall"; // Include waterfall block styles.
+
+ const graphWidth = 380;
+ const graphStartOffset = 80;
+
+ let {startTime, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, responseStart, responseEnd} = this._resource.timingData;
+ let graphStartTime = startTime;
+ let graphEndTime = responseEnd;
+ let secondsPerPixel = (responseEnd - startTime) / graphWidth;
+
+ function createBlock(startTime, endTime, className, makeEmpty) {
+ let startOffset = graphStartOffset + ((startTime - graphStartTime) / secondsPerPixel);
+ let width = makeEmpty ? 1 : (endTime - startTime) / secondsPerPixel;
+ let block = document.createElement("div");
+ block.classList.add("block", className);
+ let property = WI.resolvedLayoutDirection() === WI.LayoutDirection.RTL ? "right" : "left";
+ block.style[property] = startOffset + "px";
+ block.style.width = width + "px";
+ return block;
+ }
+
+ function createTimeLabel(endTime, label) {
+ let positionOffset = graphStartOffset + ((endTime - graphStartTime) / secondsPerPixel);
+ positionOffset += 3;
+ let timeLabel = document.createElement("div");
+ timeLabel.className = "time-label";
+ timeLabel.textContent = label;
+ let property = WI.resolvedLayoutDirection() === WI.LayoutDirection.RTL ? "right" : "left";
+ timeLabel.style[property] = positionOffset + "px";
+ return timeLabel;
+ }
+
+ function createRow(label, startTime, endTime, className) {
+ let row = document.createElement("li");
+ let labelElement = row.appendChild(document.createElement("span"));
+ labelElement.className = "row-label";
+ labelElement.textContent = label;
+ row.appendChild(createBlock(startTime, endTime, className));
+ row.appendChild(createTimeLabel(endTime, Number.secondsToMillisecondsString(endTime - startTime)));
+ return row;
+ }
+
+ listElement.appendChild(createRow(WI.UIString("Scheduled"), startTime, domainLookupStart || connectStart || requestStart, "queue"));
+ if (domainLookupStart)
+ listElement.appendChild(createRow(WI.UIString("DNS"), domainLookupStart, domainLookupEnd || connectStart || requestStart, "dns"));
+ if (connectStart)
+ listElement.appendChild(createRow(WI.UIString("TCP"), connectStart, connectEnd || requestStart, "connect"));
+ if (secureConnectionStart)
+ listElement.appendChild(createRow(WI.UIString("Secure"), secureConnectionStart, connectEnd || requestStart, "secure"));
+ listElement.appendChild(createRow(WI.UIString("Request"), requestStart, responseStart, "request"));
+ listElement.appendChild(createRow(WI.UIString("Response"), responseStart, responseEnd, "response"));
+
+ let totalRow = createRow(WI.UIString("Total"), startTime, responseEnd, "total");
+ listElement.appendChild(totalRow);
+ totalRow.classList.add("total");
+ }
+
+ _resourceMetricsDidChange(event)
+ {
+ this._needsTimingRefresh = true;
+ this.needsLayout();
+ }
+
+ _resourceTimestampsDidChange(event)
+ {
+ this._needsTimingRefresh = true;
+ this.needsLayout();
+ }
+};