<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[248485] trunk/Source/WebInspectorUI</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/248485">248485</a></dd>
<dt>Author</dt> <dd>drousso@apple.com</dd>
<dt>Date</dt> <dd>2019-08-09 15:12:12 -0700 (Fri, 09 Aug 2019)</dd>
</dl>

<h3>Log Message</h3>
<pre>REGRESSION (Safari 6): Web Inspector: JSON may not be pretty printed if served as text/html
https://bugs.webkit.org/show_bug.cgi?id=122898
<rdar://problem/15241419>

Reviewed by Joseph Pecoraro.

Check the request/response data to see if it's JSON parsable. If so, allow the user to elect
to view the request/response as a JSON preview instead of raw (or pretty printed) text.

Prefer the JSON view wherever possible.

* UserInterface/Views/ResourceClusterContentView.js:
(WI.ResourceClusterContentView):
(WI.ResourceClusterContentView.prototype.get requestContentView):
(WI.ResourceClusterContentView.prototype.get customRequestContentView): Added.
(WI.ResourceClusterContentView.prototype.get customResponseContentView):
(WI.ResourceClusterContentView.prototype.get selectionPathComponents):
(WI.ResourceClusterContentView.prototype.showRequest):
(WI.ResourceClusterContentView.prototype._canShowCustomRequestContentView): Added.
(WI.ResourceClusterContentView.prototype._canShowCustomResponseContentView):
(WI.ResourceClusterContentView.prototype._contentViewForResourceType):
(WI.ResourceClusterContentView.prototype._pathComponentForContentView):
(WI.ResourceClusterContentView.prototype._identifierForContentView):
(WI.ResourceClusterContentView.prototype._showContentViewForIdentifier):
(WI.ResourceClusterContentView.prototype._canUseJSONContentViewForContent): Added.
(WI.ResourceClusterContentView.prototype._tryEnableCustomRequestContentView): Added.
(WI.ResourceClusterContentView.prototype._tryEnableCustomResponseContentView):
(WI.ResourceClusterContentView.prototype.saveToCookie): Deleted.
(WI.ResourceClusterContentView.prototype._customContentViewConstructorForResource): Deleted.
Since the current view is already saved in a `WI.Setting`, there's no need to save that
state to a cookie, as it'll be restored elsewhere.

* UserInterface/Base/Main.js:
(WI.showResourceRequest):

* UserInterface/Main.html:
* UserInterface/Views/JSONContentView.js: Added.
(WI.JSONContentView):
(WI.JSONContentView.prototype.initialLayout):
(WI.JSONContentView.prototype.attached):
(WI.JSONContentView.prototype.closed):
* UserInterface/Views/JSONContentView.css: Added.
(.content-view.json):
* Source/WebInspectorUI/UserInterface/Views/JSONResourceContentView.js: Deleted.
* Source/WebInspectorUI/UserInterface/Views/JSONResourceContentView.css: Deleted.
Create a more generic content view that shows a preview for the given JSON parsable string.

* UserInterface/Base/Utilities.js:
(String.prototype.isJSON): Added.
* UserInterface/Views/WebSocketDataGridNode.js:
(WI.WebSocketDataGridNode.prototype.appendContextMenuItems):
Utility function for checking if a string is JSON parsable.

* Localizations/en.lproj/localizedStrings.js:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUILocalizationsenlprojlocalizedStringsjs">trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceBaseMainjs">trunk/Source/WebInspectorUI/UserInterface/Base/Main.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceBaseUtilitiesjs">trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceMainhtml">trunk/Source/WebInspectorUI/UserInterface/Main.html</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsResourceClusterContentViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/ResourceClusterContentView.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsWebSocketDataGridNodejs">trunk/Source/WebInspectorUI/UserInterface/Views/WebSocketDataGridNode.js</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsJSONContentViewcss">trunk/Source/WebInspectorUI/UserInterface/Views/JSONContentView.css</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsJSONContentViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/JSONContentView.js</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsJSONResourceContentViewcss">trunk/Source/WebInspectorUI/UserInterface/Views/JSONResourceContentView.css</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsJSONResourceContentViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/JSONResourceContentView.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (248484 => 248485)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/ChangeLog    2019-08-09 22:09:22 UTC (rev 248484)
+++ trunk/Source/WebInspectorUI/ChangeLog       2019-08-09 22:12:12 UTC (rev 248485)
</span><span class="lines">@@ -1,5 +1,62 @@
</span><span class="cx"> 2019-08-09  Devin Rousso  <drousso@apple.com>
</span><span class="cx"> 
</span><ins>+        REGRESSION (Safari 6): Web Inspector: JSON may not be pretty printed if served as text/html
+        https://bugs.webkit.org/show_bug.cgi?id=122898
+        <rdar://problem/15241419>
+
+        Reviewed by Joseph Pecoraro.
+
+        Check the request/response data to see if it's JSON parsable. If so, allow the user to elect
+        to view the request/response as a JSON preview instead of raw (or pretty printed) text.
+
+        Prefer the JSON view wherever possible.
+
+        * UserInterface/Views/ResourceClusterContentView.js:
+        (WI.ResourceClusterContentView):
+        (WI.ResourceClusterContentView.prototype.get requestContentView):
+        (WI.ResourceClusterContentView.prototype.get customRequestContentView): Added.
+        (WI.ResourceClusterContentView.prototype.get customResponseContentView):
+        (WI.ResourceClusterContentView.prototype.get selectionPathComponents):
+        (WI.ResourceClusterContentView.prototype.showRequest):
+        (WI.ResourceClusterContentView.prototype._canShowCustomRequestContentView): Added.
+        (WI.ResourceClusterContentView.prototype._canShowCustomResponseContentView):
+        (WI.ResourceClusterContentView.prototype._contentViewForResourceType):
+        (WI.ResourceClusterContentView.prototype._pathComponentForContentView):
+        (WI.ResourceClusterContentView.prototype._identifierForContentView):
+        (WI.ResourceClusterContentView.prototype._showContentViewForIdentifier):
+        (WI.ResourceClusterContentView.prototype._canUseJSONContentViewForContent): Added.
+        (WI.ResourceClusterContentView.prototype._tryEnableCustomRequestContentView): Added.
+        (WI.ResourceClusterContentView.prototype._tryEnableCustomResponseContentView):
+        (WI.ResourceClusterContentView.prototype.saveToCookie): Deleted.
+        (WI.ResourceClusterContentView.prototype._customContentViewConstructorForResource): Deleted.
+        Since the current view is already saved in a `WI.Setting`, there's no need to save that
+        state to a cookie, as it'll be restored elsewhere.
+
+        * UserInterface/Base/Main.js:
+        (WI.showResourceRequest):
+
+        * UserInterface/Main.html:
+        * UserInterface/Views/JSONContentView.js: Added.
+        (WI.JSONContentView):
+        (WI.JSONContentView.prototype.initialLayout):
+        (WI.JSONContentView.prototype.attached):
+        (WI.JSONContentView.prototype.closed):
+        * UserInterface/Views/JSONContentView.css: Added.
+        (.content-view.json):
+        * Source/WebInspectorUI/UserInterface/Views/JSONResourceContentView.js: Deleted.
+        * Source/WebInspectorUI/UserInterface/Views/JSONResourceContentView.css: Deleted.
+        Create a more generic content view that shows a preview for the given JSON parsable string.
+
+        * UserInterface/Base/Utilities.js:
+        (String.prototype.isJSON): Added.
+        * UserInterface/Views/WebSocketDataGridNode.js:
+        (WI.WebSocketDataGridNode.prototype.appendContextMenuItems):
+        Utility function for checking if a string is JSON parsable.
+
+        * Localizations/en.lproj/localizedStrings.js:
+
+2019-08-09  Devin Rousso  <drousso@apple.com>
+
</ins><span class="cx">         Web Inspector: Sources: increase the vertical space allocated to the call stack when paused
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=200236
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebInspectorUILocalizationsenlprojlocalizedStringsjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (248484 => 248485)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js   2019-08-09 22:09:22 UTC (rev 248484)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js      2019-08-09 22:12:12 UTC (rev 248485)
</span><span class="lines">@@ -305,6 +305,8 @@
</span><span class="cx"> localizedStrings["Current"] = "Current";
</span><span class="cx"> localizedStrings["Current State"] = "Current State";
</span><span class="cx"> localizedStrings["Custom"] = "Custom";
</span><ins>+localizedStrings["Custom Request"] = "Custom Request";
+localizedStrings["Custom Response"] = "Custom Response";
</ins><span class="cx"> localizedStrings["DNS"] = "DNS";
</span><span class="cx"> localizedStrings["DOM"] = "DOM";
</span><span class="cx"> localizedStrings["DOM Content Loaded \u2014 %s"] = "DOM Content Loaded \u2014 %s";
</span><span class="lines">@@ -615,7 +617,6 @@
</span><span class="cx"> localizedStrings["Invoke getter"] = "Invoke getter";
</span><span class="cx"> localizedStrings["JP2"] = "JP2";
</span><span class="cx"> localizedStrings["JPEG"] = "JPEG";
</span><del>-localizedStrings["JSON"] = "JSON";
</del><span class="cx"> localizedStrings["JavaScript"] = "JavaScript";
</span><span class="cx"> localizedStrings["JavaScript & Events"] = "JavaScript & Events";
</span><span class="cx"> localizedStrings["JavaScript Allocations"] = "JavaScript Allocations";
</span><span class="lines">@@ -869,6 +870,7 @@
</span><span class="cx"> localizedStrings["Repeating Radial Gradient"] = "Repeating Radial Gradient";
</span><span class="cx"> localizedStrings["Request"] = "Request";
</span><span class="cx"> localizedStrings["Request & Response"] = "Request & Response";
</span><ins>+localizedStrings["Request (JSON)"] = "Request (JSON)";
</ins><span class="cx"> localizedStrings["Request Cookies"] = "Request Cookies";
</span><span class="cx"> localizedStrings["Request Data"] = "Request Data";
</span><span class="cx"> localizedStrings["Request Headers"] = "Request Headers";
</span><span class="lines">@@ -885,6 +887,7 @@
</span><span class="cx"> localizedStrings["Resource was served from the cache."] = "Resource was served from the cache.";
</span><span class="cx"> localizedStrings["Resources"] = "Resources";
</span><span class="cx"> localizedStrings["Response"] = "Response";
</span><ins>+localizedStrings["Response (JSON)"] = "Response (JSON)";
</ins><span class="cx"> localizedStrings["Response Cookies"] = "Response Cookies";
</span><span class="cx"> localizedStrings["Response Headers"] = "Response Headers";
</span><span class="cx"> localizedStrings["Response:"] = "Response:";
</span><span class="lines">@@ -1175,7 +1178,6 @@
</span><span class="cx"> localizedStrings["URL"] = "URL";
</span><span class="cx"> localizedStrings["URL Breakpoint\u2026"] = "URL Breakpoint\u2026";
</span><span class="cx"> localizedStrings["Unable to determine path to property from root"] = "Unable to determine path to property from root";
</span><del>-localizedStrings["Unable to parse as JSON: %s"] = "Unable to parse as JSON: %s";
</del><span class="cx"> localizedStrings["Unable to show certificate for \u201C%s\u201D"] = "Unable to show certificate for \u201C%s\u201D";
</span><span class="cx"> /* Break (pause) on uncaught (unhandled) exceptions */
</span><span class="cx"> localizedStrings["Uncaught Exceptions"] = "Uncaught Exceptions";
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceBaseMainjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Base/Main.js (248484 => 248485)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Base/Main.js   2019-08-09 22:09:22 UTC (rev 248484)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/Main.js      2019-08-09 22:12:12 UTC (rev 248485)
</span><span class="lines">@@ -1405,7 +1405,7 @@
</span><span class="cx"> 
</span><span class="cx"> WI.showResourceRequest = function(resource, options = {})
</span><span class="cx"> {
</span><del>-    WI.showRepresentedObject(resource, {[WI.ResourceClusterContentView.ContentViewIdentifierCookieKey]: WI.ResourceClusterContentView.RequestIdentifier}, options);
</del><ins>+    WI.showRepresentedObject(resource, {[WI.ResourceClusterContentView.ContentViewIdentifierCookieKey]: WI.ResourceClusterContentView.CustomRequestIdentifier}, options);
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> WI.debuggerToggleBreakpoints = function(event)
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceBaseUtilitiesjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js (248484 => 248485)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js      2019-08-09 22:09:22 UTC (rev 248484)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js 2019-08-09 22:12:12 UTC (rev 248485)
</span><span class="lines">@@ -734,6 +734,18 @@
</span><span class="cx">     }
</span><span class="cx"> });
</span><span class="cx"> 
</span><ins>+Object.defineProperty(String.prototype, "isJSON",
+{
+    value(predicate)
+    {
+        try {
+            let json = JSON.parse(this);
+            return !predicate || predicate(json);
+        } catch { }
+        return false;
+    }
+});
+
</ins><span class="cx"> Object.defineProperty(String.prototype, "truncateStart",
</span><span class="cx"> {
</span><span class="cx">     value(maxLength)
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceMainhtml"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (248484 => 248485)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Main.html      2019-08-09 22:09:22 UTC (rev 248484)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.html 2019-08-09 22:12:12 UTC (rev 248485)
</span><span class="lines">@@ -123,7 +123,7 @@
</span><span class="cx">     <link rel="stylesheet" href="Views/InlineSwatch.css">
</span><span class="cx">     <link rel="stylesheet" href="Views/InputPopover.css">
</span><span class="cx">     <link rel="stylesheet" href="Views/IssueTreeElement.css">
</span><del>-    <link rel="stylesheet" href="Views/JSONResourceContentView.css">
</del><ins>+    <link rel="stylesheet" href="Views/JSONContentView.css">
</ins><span class="cx">     <link rel="stylesheet" href="Views/LayerDetailsSidebarPanel.css">
</span><span class="cx">     <link rel="stylesheet" href="Views/LayerTreeDetailsSidebarPanel.css">
</span><span class="cx">     <link rel="stylesheet" href="Views/Layers3DContentView.css">
</span><span class="lines">@@ -706,7 +706,7 @@
</span><span class="cx">     <script src="Views/InlineSwatch.js"></script>
</span><span class="cx">     <script src="Views/InputPopover.js"></script>
</span><span class="cx">     <script src="Views/IssueTreeElement.js"></script>
</span><del>-    <script src="Views/JSONResourceContentView.js"></script>
</del><ins>+    <script src="Views/JSONContentView.js"></script>
</ins><span class="cx">     <script src="Views/LayerDetailsSidebarPanel.js"></script>
</span><span class="cx">     <script src="Views/LayerTreeDataGridNode.js"></script>
</span><span class="cx">     <script src="Views/LayerTreeDetailsSidebarPanel.js"></script>
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsJSONContentViewcssfromrev248481trunkSourceWebInspectorUIUserInterfaceViewsJSONResourceContentViewcss"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebInspectorUI/UserInterface/Views/JSONContentView.css (from rev 248481, trunk/Source/WebInspectorUI/UserInterface/Views/JSONResourceContentView.css) (0 => 248485)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/JSONContentView.css                              (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/JSONContentView.css 2019-08-09 22:12:12 UTC (rev 248485)
</span><span class="lines">@@ -0,0 +1,29 @@
</span><ins>+/*
+ * Copyright (C) 2019 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.
+ */
+
+.content-view.json {
+    padding: 10px;
+    overflow: scroll;
+}
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsJSONContentViewjsfromrev248481trunkSourceWebInspectorUIUserInterfaceViewsJSONResourceContentViewjs"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebInspectorUI/UserInterface/Views/JSONContentView.js (from rev 248481, trunk/Source/WebInspectorUI/UserInterface/Views/JSONResourceContentView.js) (0 => 248485)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/JSONContentView.js                               (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/JSONContentView.js  2019-08-09 22:12:12 UTC (rev 248485)
</span><span class="lines">@@ -0,0 +1,98 @@
</span><ins>+/*
+ * Copyright (C) 2019 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.JSONContentView = class JSONContentView extends WI.ContentView
+{
+    constructor(json, representedObject)
+    {
+        console.assert(typeof json === "string" && json.isJSON());
+
+        super(representedObject);
+
+        this._json = json;
+        this._remoteObject = null;
+        this._spinnerTimeout = undefined;
+
+        this.element.classList.add("json");
+    }
+
+    // Protected
+
+    initialLayout()
+    {
+        super.initialLayout();
+
+        const options = {
+            expression: "(" + this._json + ")",
+            doNotPauseOnExceptionsAndMuteConsole: true,
+            generatePreview: true,
+        };
+        RuntimeAgent.evaluate.invoke(options, (error, result, wasThrown) => {
+            console.assert(!error);
+            console.assert(!wasThrown);
+
+            this._remoteObject = WI.RemoteObject.fromPayload(result);
+
+            let objectTree = new WI.ObjectTreeView(this._remoteObject);
+            objectTree.showOnlyJSON();
+            objectTree.expand();
+
+            if (this._spinnerTimeout) {
+                clearTimeout(this._spinnerTimeout);
+                this._spinnerTimeout = undefined;
+            }
+
+            this.element.removeChildren();
+            this.element.appendChild(objectTree.element);
+        });
+    }
+
+    attached()
+    {
+        super.attached();
+
+        if (this._spinnerTimeout || this._remoteObject)
+            return;
+
+        this._spinnerTimeout = setTimeout(() => {
+            console.assert(this._spinnerTimeout);
+
+            let spinner = new WI.IndeterminateProgressSpinner;
+            this.element.appendChild(spinner.element);
+
+            this._spinnerTimeout = undefined;
+        }, 100);
+    }
+
+    closed()
+    {
+        super.closed();
+
+        if (this._remoteObject) {
+            this._remoteObject.release();
+            this._remoteObject = null;
+        }
+    }
+};
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsJSONResourceContentViewcss"></a>
<div class="delfile"><h4>Deleted: trunk/Source/WebInspectorUI/UserInterface/Views/JSONResourceContentView.css (248484 => 248485)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/JSONResourceContentView.css      2019-08-09 22:09:22 UTC (rev 248484)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/JSONResourceContentView.css 2019-08-09 22:12:12 UTC (rev 248485)
</span><span class="lines">@@ -1,29 +0,0 @@
</span><del>-/*
- * 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.
- */
-
-.content-view.resource.json {
-    padding: 10px;
-    overflow: scroll;
-}
</del></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsJSONResourceContentViewjs"></a>
<div class="delfile"><h4>Deleted: trunk/Source/WebInspectorUI/UserInterface/Views/JSONResourceContentView.js (248484 => 248485)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/JSONResourceContentView.js       2019-08-09 22:09:22 UTC (rev 248484)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/JSONResourceContentView.js  2019-08-09 22:12:12 UTC (rev 248485)
</span><span class="lines">@@ -1,86 +0,0 @@
</span><del>-/*
- * 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.JSONResourceContentView = class JSONResourceContentView extends WI.ResourceContentView
-{
-    constructor(resource)
-    {
-        super(resource, "json");
-
-        this._remoteObject = null;
-    }
-
-    // Static
-
-    static customContentViewDisplayName()
-    {
-        return WI.UIString("JSON");
-    }
-
-    // Protected
-
-    contentAvailable(content, base64Encoded)
-    {
-        try {
-            JSON.parse(content);
-        } catch (e) {
-            this.showMessage(WI.UIString("Unable to parse as JSON: %s").format(e.message));
-            return;
-        }
-
-        const options = {
-            expression: "(" + content + ")",
-            includeCommandLineAPI: false,
-            doNotPauseOnExceptionsAndMuteConsole: true,
-            contextId: undefined,
-            returnByValue: false,
-            generatePreview: true,
-        };
-        this.resource.target.RuntimeAgent.evaluate.invoke(options, (error, result, wasThrown) => {
-            if (error || wasThrown) {
-                this.showMessage(WI.UIString("Unable to parse as JSON: %s").format(result.description));
-                return;
-            }
-
-            this.removeLoadingIndicator();
-
-            this._remoteObject = WI.RemoteObject.fromPayload(result, this.resource.target);
-
-            let objectTree = new WI.ObjectTreeView(this._remoteObject);
-            objectTree.showOnlyJSON();
-            objectTree.expand();
-
-            this.element.appendChild(objectTree.element);
-        }, this.resource.target);
-    }
-
-    closed()
-    {
-        if (this._remoteObject) {
-            this._remoteObject.release();
-            this._remoteObject = null;
-        }
-    }
-};
</del></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsResourceClusterContentViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ResourceClusterContentView.js (248484 => 248485)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/ResourceClusterContentView.js    2019-08-09 22:09:22 UTC (rev 248484)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ResourceClusterContentView.js       2019-08-09 22:12:12 UTC (rev 248485)
</span><span class="lines">@@ -35,7 +35,9 @@
</span><span class="cx"> 
</span><span class="cx">         function createPathComponent(displayName, className, identifier)
</span><span class="cx">         {
</span><del>-            let pathComponent = new WI.HierarchicalPathComponent(displayName, className, identifier, false, true);
</del><ins>+            const textOnly = false;
+            const showSelectorArrows = true;
+            let pathComponent = new WI.HierarchicalPathComponent(displayName, className, identifier, textOnly, showSelectorArrows);
</ins><span class="cx">             pathComponent.addEventListener(WI.HierarchicalPathComponent.Event.SiblingWasSelected, this._pathComponentSelected, this);
</span><span class="cx">             pathComponent.comparisonData = resource;
</span><span class="cx">             return pathComponent;
</span><span class="lines">@@ -43,16 +45,21 @@
</span><span class="cx"> 
</span><span class="cx">         this._requestContentView = null;
</span><span class="cx">         this._responseContentView = null;
</span><ins>+        this._customRequestContentView = null;
+        this._customRequestContentViewInitializer = null;
</ins><span class="cx">         this._customResponseContentView = null;
</span><del>-        this._customResponseContentViewConstructor = null;
</del><ins>+        this._customResponseContentViewInitializer = null;
</ins><span class="cx"> 
</span><span class="cx">         this._requestPathComponent = createPathComponent.call(this, WI.UIString("Request"), WI.ResourceClusterContentView.RequestIconStyleClassName, WI.ResourceClusterContentView.RequestIdentifier);
</span><ins>+        this._customRequestPathComponent = createPathComponent.call(this, WI.UIString("Custom Request"), WI.ResourceClusterContentView.RequestIconStyleClassName, WI.ResourceClusterContentView.CustomRequestIdentifier);
</ins><span class="cx">         this._responsePathComponent = createPathComponent.call(this, WI.UIString("Response"), WI.ResourceClusterContentView.ResponseIconStyleClassName, WI.ResourceClusterContentView.ResponseIdentifier);
</span><del>-        this._customResponsePathComponent = createPathComponent.call(this, WI.UIString("Custom"), WI.ResourceClusterContentView.ResponseIconStyleClassName, WI.ResourceClusterContentView.CustomResponseIdentifier);
</del><ins>+        this._customResponsePathComponent = createPathComponent.call(this, WI.UIString("Custom Response"), WI.ResourceClusterContentView.ResponseIconStyleClassName, WI.ResourceClusterContentView.CustomResponseIdentifier);
</ins><span class="cx"> 
</span><span class="cx">         if (this._canShowRequestContentView()) {
</span><span class="cx">             this._requestPathComponent.nextSibling = this._responsePathComponent;
</span><span class="cx">             this._responsePathComponent.previousSibling = this._requestPathComponent;
</span><ins>+
+            this._tryEnableCustomRequestContentView();
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // FIXME: Since a custom response content view may only become available after a response is received
</span><span class="lines">@@ -59,7 +66,7 @@
</span><span class="cx">         // we need to figure out a way to restore / prefer the custom content view. For example if users
</span><span class="cx">         // always want to prefer the JSON view to the normal Response text view.
</span><span class="cx"> 
</span><del>-        this._currentContentViewSetting = new WI.Setting("resource-current-view-" + this._resource.url.hash, WI.ResourceClusterContentView.ResponseIdentifier);
</del><ins>+        this._currentContentViewSetting = new WI.Setting("resource-current-view-" + this._resource.url.hash, WI.ResourceClusterContentView.CustomResponseIdentifier);
</ins><span class="cx"> 
</span><span class="cx">         this._tryEnableCustomResponseContentView();
</span><span class="cx">     }
</span><span class="lines">@@ -66,9 +73,19 @@
</span><span class="cx"> 
</span><span class="cx">     // Public
</span><span class="cx"> 
</span><del>-    get resource()
</del><ins>+    get resource() { return this._resource; }
+
+    get requestContentView()
</ins><span class="cx">     {
</span><del>-        return this._resource;
</del><ins>+        if (!this._canShowRequestContentView())
+            return null;
+
+        if (this._requestContentView)
+            return this._requestContentView;
+
+        this._requestContentView = new WI.TextContentView(this._resource.requestData || "", this._resource.requestDataContentType);
+
+        return this._requestContentView;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     get responseContentView()
</span><span class="lines">@@ -94,27 +111,21 @@
</span><span class="cx">         return this._responseContentView;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    get requestContentView()
</del><ins>+    get customRequestContentView()
</ins><span class="cx">     {
</span><del>-        if (!this._canShowRequestContentView())
-            return null;
-
-        if (this._requestContentView)
-            return this._requestContentView;
-
-        this._requestContentView = new WI.TextContentView(this._resource.requestData || "", this._resource.requestDataContentType);
-
-        return this._requestContentView;
</del><ins>+        if (!this._customRequestContentView && this._customRequestContentViewInitializer) {
+            this._customRequestContentView = this._customRequestContentViewInitializer();
+            this._customRequestContentViewInitializer = null;
+        }
+        return this._customRequestContentView;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     get customResponseContentView()
</span><span class="cx">     {
</span><del>-        if (!this._canShowCustomResponseContentView())
-            return null;
-
-        if (!this._customResponseContentView)
-            this._customResponseContentView = new this._customResponseContentViewConstructor(this._resource);
-
</del><ins>+        if (!this._customResponseContentView && this._customResponseContentViewInitializer) {
+            this._customResponseContentView = this._customResponseContentViewInitializer();
+            this._customResponseContentViewInitializer = null;
+        }
</ins><span class="cx">         return this._customResponseContentView;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -124,7 +135,7 @@
</span><span class="cx">         if (!currentContentView)
</span><span class="cx">             return [];
</span><span class="cx"> 
</span><del>-        if (!this._canShowRequestContentView() && !this._canShowCustomResponseContentView())
</del><ins>+        if (!this._canShowRequestContentView() && !this._canShowCustomRequestContentView() && !this._canShowCustomResponseContentView())
</ins><span class="cx">             return currentContentView.selectionPathComponents;
</span><span class="cx"> 
</span><span class="cx">         // Append the current view's path components to the path component representing the current view.
</span><span class="lines">@@ -149,11 +160,6 @@
</span><span class="cx">         this._shownInitialContent = false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    saveToCookie(cookie)
-    {
-        cookie[WI.ResourceClusterContentView.ContentViewIdentifierCookieKey] = this._currentContentViewSetting.value;
-    }
-
</del><span class="cx">     restoreFromCookie(cookie)
</span><span class="cx">     {
</span><span class="cx">         let contentView = this._showContentViewForIdentifier(cookie[WI.ResourceClusterContentView.ContentViewIdentifierCookieKey]);
</span><span class="lines">@@ -165,7 +171,7 @@
</span><span class="cx">     {
</span><span class="cx">         this._shownInitialContent = true;
</span><span class="cx"> 
</span><del>-        return this._showContentViewForIdentifier(WI.ResourceClusterContentView.RequestIdentifier);
</del><ins>+        return this._showContentViewForIdentifier(WI.ResourceClusterContentView.CustomRequestIdentifier);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     showResponse(positionToReveal, textRangeToSelect, forceUnformatted)
</span><span class="lines">@@ -198,9 +204,14 @@
</span><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    _canShowCustomRequestContentView()
+    {
+        return !!(this._customRequestContentView || this._customRequestContentViewInitializer);
+    }
+
</ins><span class="cx">     _canShowCustomResponseContentView()
</span><span class="cx">     {
</span><del>-        return !!this._customResponseContentViewConstructor;
</del><ins>+        return !!(this._customResponseContentView || this._customResponseContentViewInitializer);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _contentViewForResourceType(type)
</span><span class="lines">@@ -212,7 +223,7 @@
</span><span class="cx">             return new WI.TextResourceContentView(this._resource);
</span><span class="cx"> 
</span><span class="cx">         case WI.Resource.Type.Image:
</span><del>-            if (this._resource.mimeTypeComponents.type === "image/svg+xml")
</del><ins>+            if (WI.fileExtensionForMIMEType(this._resource.mimeType) === "svg")
</ins><span class="cx">                 return new WI.SVGImageResourceClusterContentView(this._resource);
</span><span class="cx">             return new WI.ImageResourceContentView(this._resource);
</span><span class="cx"> 
</span><span class="lines">@@ -236,6 +247,8 @@
</span><span class="cx">             return this._requestPathComponent;
</span><span class="cx">         if (contentView === this._responseContentView)
</span><span class="cx">             return this._responsePathComponent;
</span><ins>+        if (contentView === this._customRequestContentView)
+            return this._customRequestPathComponent;
</ins><span class="cx">         if (contentView === this._customResponseContentView)
</span><span class="cx">             return this._customResponsePathComponent;
</span><span class="cx">         console.error("Unknown contentView.");
</span><span class="lines">@@ -251,6 +264,8 @@
</span><span class="cx">             return WI.ResourceClusterContentView.RequestIdentifier;
</span><span class="cx">         if (contentView === this._responseContentView)
</span><span class="cx">             return WI.ResourceClusterContentView.ResponseIdentifier;
</span><ins>+        if (contentView === this._customRequestContentView)
+            return WI.ResourceClusterContentView.CustomRequestIdentifier;
</ins><span class="cx">         if (contentView === this._customResponseContentView)
</span><span class="cx">             return WI.ResourceClusterContentView.CustomResponseIdentifier;
</span><span class="cx">         console.error("Unknown contentView.");
</span><span class="lines">@@ -261,21 +276,29 @@
</span><span class="cx">     {
</span><span class="cx">         let contentViewToShow = null;
</span><span class="cx"> 
</span><ins>+        // This is expected to fall through all the way to the `default`.
</ins><span class="cx">         switch (identifier) {
</span><ins>+        case WI.ResourceClusterContentView.CustomRequestIdentifier:
+            contentViewToShow = this.customRequestContentView;
+            if (contentViewToShow)
+                break;
+            // fallthrough
</ins><span class="cx">         case WI.ResourceClusterContentView.RequestIdentifier:
</span><span class="cx">             contentViewToShow = this.requestContentView;
</span><del>-            break;
</del><ins>+            if (contentViewToShow)
+                break;
+            // fallthrough
+        case WI.ResourceClusterContentView.CustomResponseIdentifier:
+            contentViewToShow = this.customResponseContentView;
+            if (contentViewToShow)
+                break;
+            // fallthrough
</ins><span class="cx">         case WI.ResourceClusterContentView.ResponseIdentifier:
</span><ins>+        default:
</ins><span class="cx">             contentViewToShow = this.responseContentView;
</span><span class="cx">             break;
</span><del>-        case WI.ResourceClusterContentView.CustomResponseIdentifier:
-            contentViewToShow = this.customResponseContentView;
-            break;
</del><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (!contentViewToShow)
-            contentViewToShow = this.responseContentView;
-
</del><span class="cx">         console.assert(contentViewToShow);
</span><span class="cx"> 
</span><span class="cx">         this._currentContentViewSetting.value = this._identifierForContentView(contentViewToShow);
</span><span class="lines">@@ -317,32 +340,43 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    _tryEnableCustomResponseContentView()
</del><ins>+    _canUseJSONContentViewForContent(content)
</ins><span class="cx">     {
</span><del>-        if (!this._resource.hasResponse())
-            return;
</del><ins>+        return content.isJSON((json) => json && (typeof json === "object" || Array.isArray(json)));
+    }
</ins><span class="cx"> 
</span><del>-        this._customResponseContentViewConstructor = this._customContentViewConstructorForResource(this._resource);
-        if (!this._customResponseContentViewConstructor)
</del><ins>+    _tryEnableCustomRequestContentView()
+    {
+        if (!this._canUseJSONContentViewForContent(this._resource.requestData))
</ins><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        console.assert(this._customResponseContentViewConstructor.customContentViewDisplayName, "Custom Response ContentViews should have a static customContentViewDisplayName method.", this._customResponseContentViewConstructor);
</del><ins>+        this._customRequestContentViewInitializer = () => new WI.JSONContentView(this._resource.requestData, this._resource);
</ins><span class="cx"> 
</span><del>-        this._responsePathComponent.nextSibling = this._customResponsePathComponent;
-        this._customResponsePathComponent.previousSibling = this._responsePathComponent;
-        this._customResponsePathComponent.displayName = this._customResponseContentViewConstructor.customContentViewDisplayName();
-
-        this.dispatchEventToListeners(WI.ContentView.Event.SelectionPathComponentsDidChange);
</del><ins>+        this._customRequestPathComponent.displayName = WI.UIString("Request (JSON)");
+        this._customRequestPathComponent.previousSibling = this._requestPathComponent;
+        this._customRequestPathComponent.nextSibling = this._responsePathComponent;
+        this._requestPathComponent.nextSibling = this._customRequestPathComponent;
+        this._responsePathComponent.previousSibling = this._customRequestPathComponent;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    _customContentViewConstructorForResource(resource)
</del><ins>+    _tryEnableCustomResponseContentView()
</ins><span class="cx">     {
</span><del>-        let mimeType = this._resource.mimeType;
-        let fileExtension = WI.fileExtensionForMIMEType(mimeType);
-        if (fileExtension === "json")
-            return WI.JSONResourceContentView;
</del><ins>+        if (!this._resource.hasResponse())
+            return;
</ins><span class="cx"> 
</span><del>-        return null;
</del><ins>+        this._resource.requestContent()
+        .then(({error, content}) => {
+            if (error || !content || !this._canUseJSONContentViewForContent(content))
+                return;
+
+            this._customResponseContentViewInitializer = () => new WI.JSONContentView(content, this._resource);
+
+            this._customResponsePathComponent.displayName = WI.UIString("Response (JSON)");
+            this._customResponsePathComponent.previousSibling = this._responsePathComponent;
+            this._responsePathComponent.nextSibling = this._customResponsePathComponent;
+
+            this.dispatchEventToListeners(WI.ContentView.Event.SelectionPathComponentsDidChange);
+        });
</ins><span class="cx">     }
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="lines">@@ -352,4 +386,5 @@
</span><span class="cx"> WI.ResourceClusterContentView.ResponseIconStyleClassName = "response-icon";
</span><span class="cx"> WI.ResourceClusterContentView.RequestIdentifier = "request";
</span><span class="cx"> WI.ResourceClusterContentView.ResponseIdentifier = "response";
</span><ins>+WI.ResourceClusterContentView.CustomRequestIdentifier = "custom-request";
</ins><span class="cx"> WI.ResourceClusterContentView.CustomResponseIdentifier = "custom-response";
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsWebSocketDataGridNodejs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/WebSocketDataGridNode.js (248484 => 248485)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/WebSocketDataGridNode.js 2019-08-09 22:09:22 UTC (rev 248484)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/WebSocketDataGridNode.js    2019-08-09 22:12:12 UTC (rev 248485)
</span><span class="lines">@@ -66,11 +66,7 @@
</span><span class="cx">                 });
</span><span class="cx">             });
</span><span class="cx"> 
</span><del>-            try {
-                // The result of this is unnecessary, as we just need the string to evaluate.
-                // We still need to execute this, however, in order to try-catch if it fails.
-                JSON.parse(this._data.data);
-
</del><ins>+            if (this._data.data.isJSON()) {
</ins><span class="cx">                 contextMenu.appendItem(WI.UIString("Log Frame Value"), () => {
</span><span class="cx">                     const options = {
</span><span class="cx">                         objectGroup: WI.RuntimeManager.ConsoleObjectGroup,
</span><span class="lines">@@ -82,7 +78,7 @@
</span><span class="cx">                     let expression = "(" + this._data.data + ")";
</span><span class="cx">                     WI.runtimeManager.evaluateInInspectedWindow(expression, options, logResult);
</span><span class="cx">                 });
</span><del>-            } catch { }
</del><ins>+            }
</ins><span class="cx"> 
</span><span class="cx">             contextMenu.appendSeparator();
</span><span class="cx">         }
</span></span></pre>
</div>
</div>

</body>
</html>