Added SDK
This commit is contained in:
@@ -0,0 +1,568 @@
|
||||
/*
|
||||
* 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.ResourceHeadersContentView = class ResourceHeadersContentView 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.MetricsDidChange, this._resourceMetricsDidChange, this);
|
||||
this._resource.addEventListener(WI.Resource.Event.RequestHeadersDidChange, this._resourceRequestHeadersDidChange, this);
|
||||
this._resource.addEventListener(WI.Resource.Event.ResponseReceived, this._resourceResponseReceived, this);
|
||||
|
||||
this._delegate = delegate;
|
||||
|
||||
this._searchQuery = null;
|
||||
this._searchResults = null;
|
||||
this._searchDOMChanges = [];
|
||||
this._searchIndex = -1;
|
||||
this._automaticallyRevealFirstSearchResult = false;
|
||||
this._bouncyHighlightElement = null;
|
||||
this._popover = null;
|
||||
this._popoverCallStackIconElement = null;
|
||||
|
||||
this._redirectDetailsSections = [];
|
||||
|
||||
this.element.classList.add("resource-details", "resource-headers");
|
||||
this.element.tabIndex = 0;
|
||||
|
||||
this._needsSummaryRefresh = false;
|
||||
this._needsRedirectHeadersRefresh = false;
|
||||
this._needsRequestHeadersRefresh = false;
|
||||
this._needsResponseHeadersRefresh = false;
|
||||
}
|
||||
|
||||
// Protected
|
||||
|
||||
initialLayout()
|
||||
{
|
||||
super.initialLayout();
|
||||
|
||||
this._summarySection = new WI.ResourceDetailsSection(WI.UIString("Summary"), "summary");
|
||||
this.element.appendChild(this._summarySection.element);
|
||||
this._refreshSummarySection();
|
||||
|
||||
this._refreshRedirectHeadersSections();
|
||||
|
||||
this._requestHeadersSection = new WI.ResourceDetailsSection(WI.UIString("Request"), "headers");
|
||||
this.element.appendChild(this._requestHeadersSection.element);
|
||||
this._refreshRequestHeadersSection();
|
||||
|
||||
this._responseHeadersSection = new WI.ResourceDetailsSection(WI.UIString("Response"), "headers");
|
||||
this.element.appendChild(this._responseHeadersSection.element);
|
||||
this._refreshResponseHeadersSection();
|
||||
|
||||
if (this._resource.urlComponents.queryString) {
|
||||
this._queryStringSection = new WI.ResourceDetailsSection(WI.UIString("Query String Parameters"));
|
||||
this.element.appendChild(this._queryStringSection.element);
|
||||
this._refreshQueryStringSection();
|
||||
}
|
||||
|
||||
if (this._resource.requestData) {
|
||||
this._requestDataSection = new WI.ResourceDetailsSection(WI.UIString("Request Data"));
|
||||
this.element.appendChild(this._requestDataSection.element);
|
||||
this._refreshRequestDataSection();
|
||||
}
|
||||
|
||||
this._needsSummaryRefresh = false;
|
||||
this._needsRedirectHeadersRefresh = false;
|
||||
this._needsRequestHeadersRefresh = false;
|
||||
this._needsResponseHeadersRefresh = false;
|
||||
}
|
||||
|
||||
layout()
|
||||
{
|
||||
super.layout();
|
||||
|
||||
if (this._needsSummaryRefresh) {
|
||||
this._refreshSummarySection();
|
||||
this._needsSummaryRefresh = false;
|
||||
}
|
||||
|
||||
if (this._needsRedirectHeadersRefresh) {
|
||||
this._refreshRedirectHeadersSections();
|
||||
this._needsRedirectHeadersRefresh = false;
|
||||
}
|
||||
|
||||
if (this._needsRequestHeadersRefresh) {
|
||||
this._refreshRequestHeadersSection();
|
||||
this._needsRequestHeadersRefresh = false;
|
||||
}
|
||||
|
||||
if (this._needsResponseHeadersRefresh) {
|
||||
this._refreshResponseHeadersSection();
|
||||
this._needsResponseHeadersRefresh = false;
|
||||
}
|
||||
}
|
||||
|
||||
detached()
|
||||
{
|
||||
if (this._popover)
|
||||
this._popover.dismiss();
|
||||
|
||||
super.detached();
|
||||
}
|
||||
|
||||
closed()
|
||||
{
|
||||
this._resource.removeEventListener(WI.Resource.Event.MetricsDidChange, this._resourceMetricsDidChange, this);
|
||||
this._resource.removeEventListener(WI.Resource.Event.RequestHeadersDidChange, this._resourceRequestHeadersDidChange, this);
|
||||
this._resource.removeEventListener(WI.Resource.Event.ResponseReceived, this._resourceResponseReceived, this);
|
||||
|
||||
super.closed();
|
||||
}
|
||||
|
||||
get supportsSearch()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
get numberOfSearchResults()
|
||||
{
|
||||
return this._searchResults ? this._searchResults.length : null;
|
||||
}
|
||||
|
||||
get hasPerformedSearch()
|
||||
{
|
||||
return this._searchResults !== null;
|
||||
}
|
||||
|
||||
set automaticallyRevealFirstSearchResult(reveal)
|
||||
{
|
||||
this._automaticallyRevealFirstSearchResult = reveal;
|
||||
|
||||
// If we haven't shown a search result yet, reveal one now.
|
||||
if (this._automaticallyRevealFirstSearchResult && this.numberOfSearchResults > 0) {
|
||||
if (this._searchIndex === -1)
|
||||
this.revealNextSearchResult();
|
||||
}
|
||||
}
|
||||
|
||||
performSearch(query)
|
||||
{
|
||||
if (query === this._searchQuery)
|
||||
return;
|
||||
|
||||
WI.revertDOMChanges(this._searchDOMChanges);
|
||||
|
||||
this._searchQuery = query;
|
||||
this._searchResults = [];
|
||||
this._searchDOMChanges = [];
|
||||
this._searchIndex = -1;
|
||||
|
||||
this._perfomSearchOnKeyValuePairs();
|
||||
|
||||
this.dispatchEventToListeners(WI.ContentView.Event.NumberOfSearchResultsDidChange);
|
||||
|
||||
if (this._automaticallyRevealFirstSearchResult && this._searchResults.length > 0)
|
||||
this.revealNextSearchResult();
|
||||
}
|
||||
|
||||
searchCleared()
|
||||
{
|
||||
WI.revertDOMChanges(this._searchDOMChanges);
|
||||
|
||||
this._searchQuery = null;
|
||||
this._searchResults = null;
|
||||
this._searchDOMChanges = [];
|
||||
this._searchIndex = -1;
|
||||
}
|
||||
|
||||
revealPreviousSearchResult(changeFocus)
|
||||
{
|
||||
if (!this.numberOfSearchResults)
|
||||
return;
|
||||
|
||||
if (this._searchIndex > 0)
|
||||
--this._searchIndex;
|
||||
else
|
||||
this._searchIndex = this._searchResults.length - 1;
|
||||
|
||||
this._revealSearchResult(this._searchIndex, changeFocus);
|
||||
}
|
||||
|
||||
revealNextSearchResult(changeFocus)
|
||||
{
|
||||
if (!this.numberOfSearchResults)
|
||||
return;
|
||||
|
||||
if (this._searchIndex + 1 < this._searchResults.length)
|
||||
++this._searchIndex;
|
||||
else
|
||||
this._searchIndex = 0;
|
||||
|
||||
this._revealSearchResult(this._searchIndex, changeFocus);
|
||||
}
|
||||
|
||||
// Private
|
||||
|
||||
_responseSourceDisplayString(responseSource)
|
||||
{
|
||||
switch (responseSource) {
|
||||
case WI.Resource.ResponseSource.Network:
|
||||
return WI.UIString("Network");
|
||||
case WI.Resource.ResponseSource.MemoryCache:
|
||||
return WI.UIString("Memory Cache");
|
||||
case WI.Resource.ResponseSource.DiskCache:
|
||||
return WI.UIString("Disk Cache");
|
||||
case WI.Resource.ResponseSource.ServiceWorker:
|
||||
return WI.UIString("Service Worker");
|
||||
case WI.Resource.ResponseSource.InspectorOverride:
|
||||
return WI.UIString("Local Override");
|
||||
case WI.Resource.ResponseSource.Unknown:
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
_createSortedArrayForHeaders(headers)
|
||||
{
|
||||
return Object.entries(headers).sort((a, b) => a[0].toLowerCase().extendedLocaleCompare(b[0].toLowerCase()));
|
||||
}
|
||||
|
||||
_refreshSummarySection()
|
||||
{
|
||||
let detailsElement = this._summarySection.detailsElement;
|
||||
detailsElement.removeChildren();
|
||||
|
||||
this._summarySection.toggleError(this._resource.hadLoadingError());
|
||||
|
||||
for (let redirect of this._resource.redirects)
|
||||
this._summarySection.appendKeyValuePair(WI.UIString("URL"), redirect.url.insertWordBreakCharacters(), "url");
|
||||
this._summarySection.appendKeyValuePair(WI.UIString("URL"), this._resource.displayURL.insertWordBreakCharacters(), "url");
|
||||
|
||||
let status = emDash;
|
||||
if (!isNaN(this._resource.statusCode))
|
||||
status = this._resource.statusCode + (this._resource.statusText ? " " + this._resource.statusText : "");
|
||||
this._summarySection.appendKeyValuePair(WI.UIString("Status"), status);
|
||||
|
||||
// FIXME: <https://webkit.org/b/178827> Web Inspector: Should be able to link directly to the ServiceWorker that handled a particular load
|
||||
|
||||
let source = this._responseSourceDisplayString(this._resource.responseSource) || emDash;
|
||||
this._summarySection.appendKeyValuePair(WI.UIString("Source"), source);
|
||||
|
||||
if (this._resource.remoteAddress)
|
||||
this._summarySection.appendKeyValuePair(WI.UIString("Address"), this._resource.displayRemoteAddress);
|
||||
|
||||
let initiatorLocation = this._resource.initiatorSourceCodeLocation;
|
||||
if (initiatorLocation) {
|
||||
|
||||
let fragment = document.createDocumentFragment();
|
||||
|
||||
const options = {
|
||||
dontFloat: true,
|
||||
ignoreSearchTab: true,
|
||||
ignoreNetworkTab: true,
|
||||
};
|
||||
let link = WI.createSourceCodeLocationLink(initiatorLocation, options);
|
||||
fragment.appendChild(link);
|
||||
|
||||
if (this._resource.initiatorStackTrace) {
|
||||
this._popoverCallStackIconElement = document.createElement("img");
|
||||
this._popoverCallStackIconElement.className = "call-stack";
|
||||
fragment.appendChild(this._popoverCallStackIconElement);
|
||||
|
||||
this._popoverCallStackIconElement.addEventListener("click", (event) => {
|
||||
if (!this._popover) {
|
||||
this._popover = new WI.Popover(this);
|
||||
this._popover.windowResizeHandler = () => { this._presentPopoverBelowCallStackElement(); };
|
||||
}
|
||||
|
||||
const selectable = false;
|
||||
let callFramesTreeOutline = new WI.TreeOutline(selectable);
|
||||
callFramesTreeOutline.disclosureButtons = false;
|
||||
let callFrameTreeController = new WI.StackTraceTreeController(callFramesTreeOutline);
|
||||
callFrameTreeController.stackTrace = this._resource.initiatorStackTrace;
|
||||
|
||||
let popoverContent = document.createElement("div");
|
||||
popoverContent.appendChild(callFrameTreeController.treeOutline.element);
|
||||
this._popover.content = popoverContent;
|
||||
|
||||
this._presentPopoverBelowCallStackElement();
|
||||
});
|
||||
}
|
||||
|
||||
let pair = this._summarySection.appendKeyValuePair(WI.UIString("Initiator"), fragment);
|
||||
pair.classList.add("initiator");
|
||||
|
||||
if (this._popover && this._popover.visible)
|
||||
this._presentPopoverBelowCallStackElement();
|
||||
}
|
||||
}
|
||||
|
||||
_refreshRedirectHeadersSections()
|
||||
{
|
||||
let referenceElement = this._redirectDetailsSections.length ? this._redirectDetailsSections.lastValue.element : this._summarySection.element;
|
||||
|
||||
for (let i = this._redirectDetailsSections.length; i < this._resource.redirects.length; ++i) {
|
||||
let redirect = this._resource.redirects[i];
|
||||
|
||||
let redirectRequestSection = new WI.ResourceDetailsSection(WI.UIString("Request"), "redirect");
|
||||
|
||||
// FIXME: <https://webkit.org/b/190214> Web Inspector: expose full load metrics for redirect requests
|
||||
redirectRequestSection.appendKeyValuePair(`${redirect.requestMethod} ${redirect.urlComponents.path}`, null, "h1-status");
|
||||
|
||||
for (let [key, value] of this._createSortedArrayForHeaders(redirect.requestHeaders))
|
||||
redirectRequestSection.appendKeyValuePair(key, value, "header");
|
||||
|
||||
referenceElement = this.element.insertBefore(redirectRequestSection.element, referenceElement.nextElementSibling);
|
||||
this._redirectDetailsSections.push(redirectRequestSection);
|
||||
|
||||
let redirectResponseSection = new WI.ResourceDetailsSection(WI.UIString("Redirect Response"), "redirect");
|
||||
|
||||
// FIXME: <https://webkit.org/b/190214> Web Inspector: expose full load metrics for redirect requests
|
||||
redirectResponseSection.appendKeyValuePair(`${redirect.responseStatusCode} ${redirect.responseStatusText}`, null, "h1-status");
|
||||
|
||||
for (let [key, value] of this._createSortedArrayForHeaders(redirect.responseHeaders))
|
||||
redirectResponseSection.appendKeyValuePair(key, value, "header");
|
||||
|
||||
referenceElement = this.element.insertBefore(redirectResponseSection.element, referenceElement.nextElementSibling);
|
||||
this._redirectDetailsSections.push(redirectResponseSection);
|
||||
}
|
||||
}
|
||||
|
||||
_refreshRequestHeadersSection()
|
||||
{
|
||||
let detailsElement = this._requestHeadersSection.detailsElement;
|
||||
detailsElement.removeChildren();
|
||||
|
||||
// A revalidation request still sends a request even though we served from cache, so show the request.
|
||||
if (this._resource.statusCode !== 304) {
|
||||
if (this._resource.responseSource === WI.Resource.ResponseSource.MemoryCache) {
|
||||
this._requestHeadersSection.markIncompleteSectionWithMessage(WI.UIString("No request, served from the memory cache."));
|
||||
return;
|
||||
}
|
||||
if (this._resource.responseSource === WI.Resource.ResponseSource.DiskCache) {
|
||||
this._requestHeadersSection.markIncompleteSectionWithMessage(WI.UIString("No request, served from the disk cache."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let protocol = this._resource.protocol || "";
|
||||
let urlComponents = this._resource.urlComponents;
|
||||
if (protocol.startsWith("http/1")) {
|
||||
// HTTP/1.1 request line:
|
||||
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1
|
||||
let requestLine = `${this._resource.requestMethod} ${urlComponents.path} ${protocol.toUpperCase()}`;
|
||||
this._requestHeadersSection.appendKeyValuePair(requestLine, null, "h1-status");
|
||||
} else if (protocol === "h2") {
|
||||
// HTTP/2 Request pseudo headers:
|
||||
// https://tools.ietf.org/html/rfc7540#section-8.1.2.3
|
||||
this._requestHeadersSection.appendKeyValuePair(":method", this._resource.requestMethod, "h2-pseudo-header");
|
||||
this._requestHeadersSection.appendKeyValuePair(":scheme", urlComponents.scheme, "h2-pseudo-header");
|
||||
this._requestHeadersSection.appendKeyValuePair(":authority", WI.h2Authority(urlComponents), "h2-pseudo-header");
|
||||
this._requestHeadersSection.appendKeyValuePair(":path", WI.h2Path(urlComponents), "h2-pseudo-header");
|
||||
}
|
||||
|
||||
for (let [key, value] of this._createSortedArrayForHeaders(this._resource.requestHeaders))
|
||||
this._requestHeadersSection.appendKeyValuePair(key, value, "header");
|
||||
|
||||
if (!detailsElement.firstChild)
|
||||
this._requestHeadersSection.markIncompleteSectionWithMessage(WI.UIString("No request headers"));
|
||||
}
|
||||
|
||||
_refreshResponseHeadersSection()
|
||||
{
|
||||
let detailsElement = this._responseHeadersSection.detailsElement;
|
||||
detailsElement.removeChildren();
|
||||
|
||||
if (!this._resource.hasResponse()) {
|
||||
this._responseHeadersSection.markIncompleteSectionWithLoadingIndicator();
|
||||
return;
|
||||
}
|
||||
|
||||
this._responseHeadersSection.toggleIncomplete(false);
|
||||
|
||||
let protocol = this._resource.protocol || "";
|
||||
if (protocol.startsWith("http/1")) {
|
||||
// HTTP/1.1 response status line:
|
||||
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1
|
||||
let responseLine = `${protocol.toUpperCase()} ${this._resource.statusCode} ${this._resource.statusText}`;
|
||||
this._responseHeadersSection.appendKeyValuePair(responseLine, null, "h1-status");
|
||||
} else if (protocol === "h2") {
|
||||
// HTTP/2 Response pseudo headers:
|
||||
// https://tools.ietf.org/html/rfc7540#section-8.1.2.4
|
||||
this._responseHeadersSection.appendKeyValuePair(":status", this._resource.statusCode, "h2-pseudo-header");
|
||||
}
|
||||
|
||||
for (let [key, value] of this._createSortedArrayForHeaders(this._resource.responseHeaders)) {
|
||||
// Split multiple Set-Cookie response headers out into their multiple headers instead of as a combined value.
|
||||
if (key.toLowerCase() === "set-cookie") {
|
||||
let responseCookies = this._resource.responseCookies;
|
||||
console.assert(responseCookies.length > 0);
|
||||
for (let cookie of responseCookies)
|
||||
this._responseHeadersSection.appendKeyValuePair(key, cookie.header, "header");
|
||||
continue;
|
||||
}
|
||||
|
||||
this._responseHeadersSection.appendKeyValuePair(key, value, "header");
|
||||
}
|
||||
|
||||
if (!detailsElement.firstChild)
|
||||
this._responseHeadersSection.markIncompleteSectionWithMessage(WI.UIString("No response headers"));
|
||||
}
|
||||
|
||||
_refreshQueryStringSection()
|
||||
{
|
||||
if (!this._queryStringSection)
|
||||
return;
|
||||
|
||||
let detailsElement = this._queryStringSection.detailsElement;
|
||||
detailsElement.removeChildren();
|
||||
|
||||
let queryString = this._resource.urlComponents.queryString;
|
||||
let queryStringPairs = parseQueryString(queryString, true);
|
||||
for (let {name, value} of queryStringPairs)
|
||||
this._queryStringSection.appendKeyValuePair(name, value);
|
||||
}
|
||||
|
||||
_refreshRequestDataSection()
|
||||
{
|
||||
if (!this._requestDataSection)
|
||||
return;
|
||||
|
||||
let detailsElement = this._requestDataSection.detailsElement;
|
||||
detailsElement.removeChildren();
|
||||
|
||||
let requestData = this._resource.requestData;
|
||||
let requestDataContentType = this._resource.requestDataContentType || "";
|
||||
|
||||
if (requestDataContentType && requestDataContentType.match(/^application\/x-www-form-urlencoded\s*(;.*)?$/i)) {
|
||||
// Simple form data that should be parsable like a query string.
|
||||
this._requestDataSection.appendKeyValuePair(WI.UIString("MIME Type"), requestDataContentType);
|
||||
let queryStringPairs = parseQueryString(requestData, true);
|
||||
for (let {name, value} of queryStringPairs)
|
||||
this._requestDataSection.appendKeyValuePair(name, value);
|
||||
return;
|
||||
}
|
||||
|
||||
let mimeTypeComponents = parseMIMEType(requestDataContentType);
|
||||
let mimeType = mimeTypeComponents.type;
|
||||
let boundary = mimeTypeComponents.boundary;
|
||||
let encoding = mimeTypeComponents.encoding;
|
||||
|
||||
this._requestDataSection.appendKeyValuePair(WI.UIString("MIME Type"), mimeType);
|
||||
if (boundary)
|
||||
this._requestDataSection.appendKeyValuePair(WI.UIString("Boundary"), boundary);
|
||||
if (encoding)
|
||||
this._requestDataSection.appendKeyValuePair(WI.UIString("Encoding"), encoding);
|
||||
|
||||
let goToButton = detailsElement.appendChild(WI.createGoToArrowButton());
|
||||
goToButton.addEventListener("click", () => { this._delegate.headersContentViewGoToRequestData(this); });
|
||||
this._requestDataSection.appendKeyValuePair(WI.UIString("Request Data"), goToButton);
|
||||
}
|
||||
|
||||
_perfomSearchOnKeyValuePairs()
|
||||
{
|
||||
let searchRegex = WI.SearchUtilities.searchRegExpForString(this._searchQuery, WI.SearchUtilities.defaultSettings);
|
||||
if (!searchRegex) {
|
||||
this.searchCleared();
|
||||
this.dispatchEventToListeners(WI.TextEditor.Event.NumberOfSearchResultsDidChange);
|
||||
return;
|
||||
}
|
||||
|
||||
let elements = this.element.querySelectorAll(".key, .value");
|
||||
for (let element of elements) {
|
||||
let matchRanges = [];
|
||||
let text = element.textContent;
|
||||
let match;
|
||||
while (match = searchRegex.exec(text))
|
||||
matchRanges.push({offset: match.index, length: match[0].length});
|
||||
|
||||
if (matchRanges.length) {
|
||||
let highlightedNodes = WI.highlightRangesWithStyleClass(element, matchRanges, "search-highlight", this._searchDOMChanges);
|
||||
this._searchResults.pushAll(highlightedNodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_revealSearchResult(index, changeFocus)
|
||||
{
|
||||
let highlightElement = this._searchResults[index];
|
||||
if (!highlightElement)
|
||||
return;
|
||||
|
||||
highlightElement.scrollIntoViewIfNeeded();
|
||||
|
||||
if (!this._bouncyHighlightElement) {
|
||||
this._bouncyHighlightElement = document.createElement("div");
|
||||
this._bouncyHighlightElement.className = "bouncy-highlight";
|
||||
this._bouncyHighlightElement.addEventListener("animationend", (event) => {
|
||||
this._bouncyHighlightElement.remove();
|
||||
});
|
||||
}
|
||||
|
||||
this._bouncyHighlightElement.remove();
|
||||
|
||||
let computedStyles = window.getComputedStyle(highlightElement);
|
||||
let highlightElementRect = highlightElement.getBoundingClientRect();
|
||||
let contentViewRect = this.element.getBoundingClientRect();
|
||||
let contentViewScrollTop = this.element.scrollTop;
|
||||
let contentViewScrollLeft = this.element.scrollLeft;
|
||||
|
||||
this._bouncyHighlightElement.textContent = highlightElement.textContent;
|
||||
this._bouncyHighlightElement.style.top = (highlightElementRect.top - contentViewRect.top + contentViewScrollTop) + "px";
|
||||
this._bouncyHighlightElement.style.left = (highlightElementRect.left - contentViewRect.left + contentViewScrollLeft) + "px";
|
||||
this._bouncyHighlightElement.style.fontWeight = computedStyles.fontWeight;
|
||||
|
||||
this.element.appendChild(this._bouncyHighlightElement);
|
||||
}
|
||||
|
||||
_presentPopoverBelowCallStackElement()
|
||||
{
|
||||
let bounds = WI.Rect.rectFromClientRect(this._popoverCallStackIconElement.getBoundingClientRect());
|
||||
this._popover.present(bounds.pad(2), [WI.RectEdge.MAX_Y, WI.RectEdge.MIN_Y, WI.RectEdge.MAX_X]);
|
||||
}
|
||||
|
||||
_resourceMetricsDidChange(event)
|
||||
{
|
||||
this._needsSummaryRefresh = true;
|
||||
this._needsRequestHeadersRefresh = true;
|
||||
this._needsResponseHeadersRefresh = true;
|
||||
this.needsLayout();
|
||||
}
|
||||
|
||||
_resourceRequestHeadersDidChange(event)
|
||||
{
|
||||
this._needsSummaryRefresh = true;
|
||||
this._needsRedirectHeadersRefresh = true;
|
||||
this._needsRequestHeadersRefresh = true;
|
||||
this.needsLayout();
|
||||
}
|
||||
|
||||
_resourceResponseReceived(event)
|
||||
{
|
||||
this._needsSummaryRefresh = true;
|
||||
this._needsResponseHeadersRefresh = true;
|
||||
this.needsLayout();
|
||||
}
|
||||
};
|
||||
|
||||
WI.ResourceHeadersContentView.ReferencePage = WI.ReferencePage.NetworkTab.HeadersPane;
|
||||
Reference in New Issue
Block a user