2019-09-03 Devin Rousso <drousso@apple.com>
+ Web Inspector: provide a way to view XML/HTML/SVG resource responses as a DOM tree
+ https://bugs.webkit.org/show_bug.cgi?id=201046
+ <rdar://problem/54446087>
+
+ Reviewed by Joseph Pecoraro.
+
+ * UserInterface/Views/ResourceClusterContentView.js:
+ (WI.ResourceClusterContentView):
+ (WI.ResourceClusterContentView.prototype.showRequest):
+ (WI.ResourceClusterContentView.prototype.showResponse):
+ (WI.ResourceClusterContentView.prototype.get customRequestDOMContentView): Added.
+ (WI.ResourceClusterContentView.prototype.get customRequestJSONContentView): Added.
+ (WI.ResourceClusterContentView.prototype.get customResponseDOMContentView): Added.
+ (WI.ResourceClusterContentView.prototype.get customResponseJSONContentView): Added.
+ (WI.ResourceClusterContentView.prototype.get customResponseTextContentView): Added.
+ (WI.ResourceClusterContentView.prototype._createPathComponent): Added.
+ (WI.ResourceClusterContentView.prototype._canShowCustomRequestContentView):
+ (WI.ResourceClusterContentView.prototype._canShowCustomResponseContentView):
+ (WI.ResourceClusterContentView.prototype._contentViewForResourceType):
+ (WI.ResourceClusterContentView.prototype._pathComponentForContentView):
+ (WI.ResourceClusterContentView.prototype._identifierForContentView):
+ (WI.ResourceClusterContentView.prototype._showContentViewForIdentifier):
+ (WI.ResourceClusterContentView.prototype._resourceLoadingDidFinish):
+ (WI.ResourceClusterContentView.prototype._canUseDOMContentViewForContent): Added.
+ (WI.ResourceClusterContentView.prototype._normalizeMIMETypeForDOM): Added.
+ (WI.ResourceClusterContentView.prototype._tryEnableCustomRequestContentViews): Added.
+ (WI.ResourceClusterContentView.prototype._tryEnableCustomResponseContentViews): Added.
+ (WI.ResourceClusterContentView.createPathComponent): Deleted.
+ (WI.ResourceClusterContentView.prototype._tryEnableCustomRequestContentView): Deleted.
+ (WI.ResourceClusterContentView.prototype._tryEnableCustomResponseContentView): Deleted.
+ * UserInterface/Base/Main.js:
+ (WI.showResourceRequest):
+ * UserInterface/Views/PathComponentIcons.css:
+ (.object-icon .icon): Added.
+ * UserInterface/Main.html:
+ * UserInterface/Views/SVGImageResourceClusterContentView.js: Removed.
+ Reworked to allow more than one custom request/response content view at the same time. As
+ such, merge the `WI.SVGImageResourceClusterContentView` into this class.
+
+ * UserInterface/Views/LocalRemoteObjectContentView.js: Added.
+ (WI.LocalRemoteObjectContentView):
+ (WI.LocalRemoteObjectContentView.prototype.get expression):
+ (WI.LocalRemoteObjectContentView.prototype.renderRemoteObject):
+ (WI.LocalRemoteObjectContentView.prototype.initialLayout):
+ (WI.LocalRemoteObjectContentView.prototype.attached):
+ (WI.LocalRemoteObjectContentView.prototype.closed):
+ * UserInterface/Views/LocalRemoteObjectContentView.css: Added.
+ (.content-view.local-remote-object):
+ * UserInterface/Views/LocalDOMContentView.js: Added.
+ (WI.LocalDOMContentView):
+ (WI.LocalDOMContentView.prototype.get expression):
+ (WI.LocalDOMContentView.prototype.renderRemoteObject):
+ * UserInterface/Views/LocalJSONContentView.js: Added.
+ (WI.LocalJSONContentView):
+ (WI.LocalJSONContentView.prototype.get expression):
+ (WI.LocalJSONContentView.prototype.renderRemoteObject):
+ * UserInterface/Views/JSONContentView.js: Removed.
+ * UserInterface/Views/JSONContentView.css: Removed.
+ Rework `WI.JSONContentView` into a more generic set of classes that render an object we send
+ to the inspected page for instrumentation.
+
+ * UserInterface/Views/DOMTreeOutline.js:
+ (WI.DOMTreeOutline.prototype.populateContextMenu):
+ (WI.DOMTreeOutline.prototype._onmousemove):
+ (WI.DOMTreeOutline.prototype._onmouseout):
+ (WI.DOMTreeOutline.prototype._ondragstart):
+ (WI.DOMTreeOutline.prototype._ondragover):
+ (WI.DOMTreeOutline.prototype._ondragleave):
+ (WI.DOMTreeOutline.prototype._ondragend):
+ (WI.DOMTreeOutline.prototype._hideElements):
+ * UserInterface/Views/DOMTreeElement.js:
+ (WI.DOMTreeElement.prototype.populateDOMNodeContextMenu):
+ * UserInterface/Views/ContextMenuUtilities.js:
+ (WI.appendContextMenuItemsForDOMNode):
+ Ensure that interactions that would modify the DOM tree only happen when editable. If the
+ `WI.DOMTreeOutline` represents a "local" `WI.DOMNode` (one that's been sent to the inspected
+ page for instrumentation, and shouldn't be part of the main #document), don't allow any
+ editing actions to be performed.
+
+ * UserInterface/Views/TextContentView.js:
+ (WI.TextContentView):
+ Allow a `representedObject` object to be provided and used instead of the given `string`.
+
+ * Localizations/en.lproj/localizedStrings.js:
+ * UserInterface/Images/Object.svg: Added.
+
+2019-09-03 Devin Rousso <drousso@apple.com>
+
Web Inspector: implement blackboxing of script resources
https://bugs.webkit.org/show_bug.cgi?id=17240
<rdar://problem/5732847>
localizedStrings["Current"] = "Current";
localizedStrings["Current State"] = "Current State";
localizedStrings["Custom"] = "Custom";
-localizedStrings["Custom Request"] = "Custom Request";
-localizedStrings["Custom Response"] = "Custom Response";
localizedStrings["DNS"] = "DNS";
localizedStrings["DOM"] = "DOM";
localizedStrings["DOM Content Loaded \u2014 %s"] = "DOM Content Loaded \u2014 %s";
localizedStrings["Repeating Radial Gradient"] = "Repeating Radial Gradient";
localizedStrings["Request"] = "Request";
localizedStrings["Request & Response"] = "Request & Response";
-localizedStrings["Request (JSON)"] = "Request (JSON)";
+localizedStrings["Request (DOM Tree)"] = "Request (DOM Tree)";
+localizedStrings["Request (Object Tree)"] = "Request (Object Tree)";
localizedStrings["Request Cookies"] = "Request Cookies";
localizedStrings["Request Data"] = "Request Data";
localizedStrings["Request Headers"] = "Request Headers";
localizedStrings["Resource was served from the cache."] = "Resource was served from the cache.";
localizedStrings["Resources"] = "Resources";
localizedStrings["Response"] = "Response";
-localizedStrings["Response (JSON)"] = "Response (JSON)";
+localizedStrings["Response (DOM Tree)"] = "Response (DOM Tree)";
+localizedStrings["Response (Object Tree)"] = "Response (Object Tree)";
+localizedStrings["Response (Text)"] = "Response (Text)";
localizedStrings["Response Cookies"] = "Response Cookies";
localizedStrings["Response Headers"] = "Response Headers";
localizedStrings["Response:"] = "Response:";
WI.showResourceRequest = function(resource, options = {})
{
- WI.showRepresentedObject(resource, {[WI.ResourceClusterContentView.ContentViewIdentifierCookieKey]: WI.ResourceClusterContentView.CustomRequestIdentifier}, options);
+ WI.showRepresentedObject(resource, {[WI.ResourceClusterContentView.ContentViewIdentifierCookieKey]: WI.ResourceClusterContentView.Identifier.Request}, options);
};
WI.debuggerToggleBreakpoints = function(event)
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2019 Apple Inc. All rights reserved. -->
+<svg xmlns="http://www.w3.org/2000/svg" id="root" version="1.1" viewBox="0 0 16 16">
+ <path fill="rgb(246, 222, 146)" d="M 13 1 L 3 1 C 1.898438 1 1 1.898438 1 3 L 1 13 C 1 14.101562 1.898438 15 3 15 L 13 15 C 14.101562 15 15 14.101562 15 13 L 15 3 C 15 1.898438 14.101562 1 13 1 Z"/>
+ <path fill="rgb(204, 181, 108)" d="M 13 1 L 3 1 C 1.898438 1 1 1.898438 1 3 L 1 13 C 1 14.101562 1.898438 15 3 15 L 13 15 C 14.101562 15 15 14.101562 15 13 L 15 3 C 15 1.898438 14.101562 1 13 1 M 13 2 C 13.550781 2 14 2.449219 14 3 L 14 13 C 14 13.550781 13.550781 14 13 14 L 3 14 C 2.449219 14 2 13.550781 2 13 L 2 3 C 2 2.449219 2.449219 2 3 2 L 13 2"/>
+ <path fill="rgb(216, 193, 115)" d="M 7.984375 3 L 6.585938 3 C 6.101562 3 5.714844 3.050781 5.394531 3.160156 C 4.984375 3.296875 4.648438 3.527344 4.382812 3.84375 C 4.121094 4.160156 3.953125 4.546875 3.886719 4.984375 C 3.847656 5.265625 3.828125 5.636719 3.828125 6.152344 C 3.828125 6.21875 3.828125 6.277344 3.824219 6.332031 L 3 6.339844 L 3 9.652344 L 3.820312 9.683594 C 3.824219 9.796875 3.828125 9.941406 3.828125 10.136719 C 3.828125 10.8125 3.90625 11.308594 4.082031 11.691406 C 4.300781 12.1875 4.679688 12.558594 5.171875 12.777344 C 5.546875 12.941406 6.011719 13.023438 6.585938 13.023438 L 7.980469 13.023438 L 7.980469 9.652344 L 7.1875 9.652344 L 7.171875 9.316406 C 7.144531 8.789062 7.050781 8.363281 6.882812 8.015625 C 7.015625 7.730469 7.105469 7.433594 7.144531 7.121094 C 7.160156 7.015625 7.175781 6.820312 7.195312 6.363281 L 7.984375 6.363281 Z M 6.984375 4 L 6.984375 5.363281 L 6.785156 5.363281 C 6.367188 5.363281 6.277344 5.417969 6.265625 5.425781 C 6.265625 5.425781 6.21875 5.488281 6.214844 5.742188 C 6.199219 6.386719 6.175781 6.804688 6.152344 7 C 6.125 7.210938 6.0625 7.417969 5.964844 7.613281 C 5.894531 7.753906 5.789062 7.886719 5.644531 8.011719 C 5.78125 8.132812 5.890625 8.269531 5.96875 8.421875 C 6.085938 8.648438 6.152344 8.957031 6.171875 9.363281 L 6.226562 10.515625 C 6.234375 10.539062 6.257812 10.574219 6.296875 10.601562 C 6.308594 10.605469 6.394531 10.652344 6.78125 10.652344 L 6.980469 10.652344 L 6.980469 12.023438 L 6.585938 12.023438 C 6.152344 12.023438 5.820312 11.96875 5.574219 11.859375 C 5.308594 11.742188 5.113281 11.550781 4.992188 11.285156 C 4.882812 11.035156 4.828125 10.660156 4.828125 10.136719 C 4.828125 9.453125 4.796875 9.230469 4.78125 9.152344 C 4.753906 9.03125 4.699219 8.925781 4.617188 8.824219 C 4.554688 8.75 4.40625 8.703125 4.195312 8.695312 L 4 8.6875 L 4 7.328125 L 4.199219 7.328125 C 4.414062 7.324219 4.570312 7.265625 4.667969 7.144531 C 4.714844 7.085938 4.828125 6.875 4.828125 6.152344 C 4.828125 5.691406 4.84375 5.355469 4.878906 5.128906 C 4.914062 4.875 5.007812 4.65625 5.152344 4.484375 C 5.296875 4.3125 5.484375 4.183594 5.710938 4.105469 C 5.925781 4.035156 6.210938 4 6.585938 4 L 6.984375 4"/>
+ <path fill="rgb(216, 193, 115)" d="M 9.414062 3 L 8.015625 3 L 8.015625 6.363281 L 8.808594 6.363281 C 8.824219 6.804688 8.851562 7.113281 8.890625 7.328125 C 8.933594 7.570312 9.011719 7.804688 9.117188 8.019531 C 9 8.261719 8.921875 8.519531 8.878906 8.785156 C 8.851562 8.921875 8.828125 9.136719 8.808594 9.652344 L 8.019531 9.652344 L 8.019531 13.023438 L 9.421875 13.023438 C 9.90625 13.023438 10.296875 12.96875 10.617188 12.859375 C 11.003906 12.730469 11.355469 12.496094 11.617188 12.179688 C 11.886719 11.855469 12.054688 11.472656 12.117188 11.035156 C 12.15625 10.753906 12.171875 10.382812 12.171875 9.863281 C 12.171875 9.800781 12.175781 9.742188 12.175781 9.691406 L 13 9.683594 L 13 6.371094 L 12.179688 6.339844 C 12.175781 6.230469 12.171875 6.078125 12.171875 5.886719 C 12.171875 5.210938 12.09375 4.714844 11.921875 4.328125 C 11.699219 3.839844 11.324219 3.464844 10.828125 3.246094 C 10.453125 3.078125 9.988281 3 9.414062 3 M 9.414062 4 C 9.847656 4 10.179688 4.054688 10.425781 4.160156 C 10.691406 4.277344 10.886719 4.472656 11.007812 4.738281 C 11.117188 4.988281 11.171875 5.363281 11.171875 5.886719 C 11.171875 6.59375 11.203125 6.816406 11.222656 6.886719 C 11.253906 7.003906 11.308594 7.105469 11.390625 7.203125 C 11.425781 7.246094 11.523438 7.316406 11.808594 7.328125 L 12 7.335938 L 12 8.695312 L 11.800781 8.695312 C 11.585938 8.699219 11.433594 8.757812 11.332031 8.878906 C 11.273438 8.953125 11.171875 9.175781 11.171875 9.863281 C 11.171875 10.332031 11.15625 10.667969 11.125 10.894531 C 11.089844 11.144531 10.996094 11.363281 10.851562 11.539062 C 10.707031 11.714844 10.519531 11.839844 10.292969 11.914062 C 10.082031 11.984375 9.796875 12.023438 9.421875 12.023438 L 9.019531 12.023438 L 9.019531 10.652344 L 9.21875 10.652344 C 9.636719 10.652344 9.726562 10.59375 9.730469 10.59375 C 9.730469 10.59375 9.785156 10.53125 9.789062 10.277344 C 9.808594 9.582031 9.828125 9.148438 9.863281 8.945312 C 9.898438 8.730469 9.972656 8.527344 10.078125 8.339844 C 10.144531 8.21875 10.238281 8.109375 10.355469 8.007812 C 10.230469 7.902344 10.140625 7.796875 10.074219 7.6875 C 9.976562 7.523438 9.910156 7.34375 9.875 7.148438 C 9.839844 6.96875 9.816406 6.644531 9.800781 6.183594 C 9.78125 5.597656 9.761719 5.480469 9.757812 5.457031 C 9.695312 5.402344 9.609375 5.363281 9.214844 5.363281 L 9.015625 5.363281 L 9.015625 4 L 9.414062 4"/>
+ <path fill="white" d="M 6.585938 12.023438 C 6.152344 12.023438 5.820312 11.96875 5.574219 11.863281 C 5.308594 11.746094 5.113281 11.550781 4.992188 11.285156 C 4.882812 11.035156 4.828125 10.660156 4.828125 10.136719 C 4.828125 9.453125 4.796875 9.226562 4.78125 9.152344 C 4.753906 9.03125 4.699219 8.925781 4.617188 8.824219 C 4.558594 8.75 4.40625 8.703125 4.191406 8.695312 L 4 8.6875 L 4 7.328125 L 4.199219 7.328125 C 4.414062 7.324219 4.566406 7.265625 4.667969 7.144531 C 4.714844 7.085938 4.828125 6.875 4.828125 6.152344 C 4.828125 5.691406 4.84375 5.355469 4.878906 5.128906 C 4.914062 4.875 5.007812 4.660156 5.152344 4.484375 C 5.296875 4.308594 5.484375 4.183594 5.710938 4.109375 C 5.925781 4.035156 6.210938 4 6.585938 4 L 6.984375 4 L 6.984375 5.367188 L 6.785156 5.367188 C 6.363281 5.367188 6.273438 5.417969 6.265625 5.425781 C 6.265625 5.425781 6.21875 5.488281 6.214844 5.742188 C 6.199219 6.386719 6.175781 6.804688 6.152344 7 C 6.125 7.210938 6.0625 7.417969 5.964844 7.613281 C 5.894531 7.753906 5.789062 7.882812 5.644531 8.011719 C 5.78125 8.132812 5.890625 8.273438 5.96875 8.421875 C 6.085938 8.648438 6.152344 8.957031 6.171875 9.367188 L 6.226562 10.515625 C 6.234375 10.539062 6.257812 10.574219 6.300781 10.601562 C 6.308594 10.605469 6.394531 10.65625 6.78125 10.65625 L 6.980469 10.65625 L 6.980469 12.023438 Z"/>
+ <path fill="white" d="M 9.019531 12.023438 L 9.019531 10.65625 L 9.21875 10.65625 C 9.636719 10.65625 9.726562 10.59375 9.734375 10.589844 C 9.734375 10.589844 9.785156 10.53125 9.789062 10.277344 C 9.804688 9.582031 9.832031 9.148438 9.863281 8.945312 C 9.898438 8.730469 9.96875 8.527344 10.078125 8.339844 C 10.144531 8.21875 10.238281 8.109375 10.351562 8.007812 C 10.230469 7.902344 10.140625 7.796875 10.074219 7.6875 C 9.976562 7.523438 9.910156 7.34375 9.875 7.152344 C 9.839844 6.96875 9.816406 6.644531 9.800781 6.183594 C 9.78125 5.597656 9.761719 5.476562 9.757812 5.457031 C 9.695312 5.402344 9.609375 5.367188 9.214844 5.367188 L 9.015625 5.367188 L 9.015625 4 L 9.414062 4 C 9.847656 4 10.179688 4.050781 10.425781 4.160156 C 10.691406 4.277344 10.886719 4.472656 11.007812 4.738281 C 11.117188 4.988281 11.171875 5.363281 11.171875 5.886719 C 11.171875 6.589844 11.207031 6.816406 11.222656 6.886719 C 11.253906 7.003906 11.308594 7.105469 11.390625 7.203125 C 11.425781 7.246094 11.527344 7.316406 11.804688 7.328125 L 12 7.335938 L 12 8.695312 L 11.800781 8.695312 C 11.585938 8.699219 11.433594 8.757812 11.332031 8.878906 C 11.273438 8.953125 11.171875 9.175781 11.171875 9.867188 C 11.171875 10.332031 11.15625 10.667969 11.125 10.890625 C 11.089844 11.144531 11 11.363281 10.851562 11.539062 C 10.707031 11.710938 10.519531 11.839844 10.292969 11.914062 C 10.082031 11.988281 9.792969 12.023438 9.417969 12.023438 Z"/>
+</svg>
<link rel="stylesheet" href="Views/InlineSwatch.css">
<link rel="stylesheet" href="Views/InputPopover.css">
<link rel="stylesheet" href="Views/IssueTreeElement.css">
- <link rel="stylesheet" href="Views/JSONContentView.css">
<link rel="stylesheet" href="Views/LayerDetailsSidebarPanel.css">
<link rel="stylesheet" href="Views/LayerTreeDetailsSidebarPanel.css">
<link rel="stylesheet" href="Views/Layers3DContentView.css">
<link rel="stylesheet" href="Views/LayoutTimelineOverviewGraph.css">
<link rel="stylesheet" href="Views/LayoutTimelineView.css">
+ <link rel="stylesheet" href="Views/LocalRemoteObjectContentView.css">
<link rel="stylesheet" href="Views/LogContentView.css">
<link rel="stylesheet" href="Views/LogIcon.css">
<link rel="stylesheet" href="Views/MediaTimelineOverviewGraph.css">
<script src="Views/AuditTestContentView.js"></script>
<script src="Views/CollectionContentView.js"></script>
+ <script src="Views/LocalRemoteObjectContentView.js"></script>
<script src="Views/ActivateButtonNavigationItem.js"></script>
<script src="Views/ActivateButtonToolbarItem.js"></script>
<script src="Views/InlineSwatch.js"></script>
<script src="Views/InputPopover.js"></script>
<script src="Views/IssueTreeElement.js"></script>
- <script src="Views/JSONContentView.js"></script>
<script src="Views/LayerDetailsSidebarPanel.js"></script>
<script src="Views/LayerTreeDataGridNode.js"></script>
<script src="Views/LayerTreeDetailsSidebarPanel.js"></script>
<script src="Views/LayoutTimelineDataGridNode.js"></script>
<script src="Views/LayoutTimelineOverviewGraph.js"></script>
<script src="Views/LayoutTimelineView.js"></script>
+ <script src="Views/LocalDOMContentView.js"></script>
+ <script src="Views/LocalJSONContentView.js"></script>
<script src="Views/LogContentView.js"></script>
<script src="Views/MediaTimelineDataGridNode.js"></script>
<script src="Views/MediaTimelineOverviewGraph.js"></script>
<script src="Views/StyleOriginView.js"></script>
<script src="Views/SpringEditor.js"></script>
- <script src="Views/SVGImageResourceClusterContentView.js"></script>
<script src="Views/StackTraceView.js"></script>
<script src="Views/StackedAreaChart.js"></script>
<script src="Views/StackedColumnChart.js"></script>
contextMenu.appendSeparator();
- if (domNode.isCustomElement()) {
- contextMenu.appendItem(WI.UIString("Jump to Definition"), () => {
- function didGetFunctionDetails(error, response) {
- if (error)
- return;
-
- let location = response.location;
- let sourceCode = WI.debuggerManager.scriptForIdentifier(location.scriptId, WI.mainTarget);
- if (!sourceCode)
- return;
-
- let sourceCodeLocation = sourceCode.createSourceCodeLocation(location.lineNumber, location.columnNumber || 0);
- WI.showSourceCodeLocation(sourceCodeLocation, {
- ignoreNetworkTab: true,
- ignoreSearchTab: true,
- });
- }
-
- WI.RemoteObject.resolveNode(domNode).then((remoteObject) => {
- remoteObject.getProperty("constructor", (error, result, wasThrown) => {
+ if (!options.disallowEditing) {
+ if (domNode.isCustomElement()) {
+ contextMenu.appendItem(WI.UIString("Jump to Definition"), () => {
+ function didGetFunctionDetails(error, response) {
if (error)
return;
- if (result.type === "function")
- remoteObject.target.DebuggerAgent.getFunctionDetails(result.objectId, didGetFunctionDetails);
- result.release();
+
+ let location = response.location;
+ let sourceCode = WI.debuggerManager.scriptForIdentifier(location.scriptId, WI.mainTarget);
+ if (!sourceCode)
+ return;
+
+ let sourceCodeLocation = sourceCode.createSourceCodeLocation(location.lineNumber, location.columnNumber || 0);
+ WI.showSourceCodeLocation(sourceCodeLocation, {
+ ignoreNetworkTab: true,
+ ignoreSearchTab: true,
+ });
+ }
+
+ WI.RemoteObject.resolveNode(domNode).then((remoteObject) => {
+ remoteObject.getProperty("constructor", (error, result, wasThrown) => {
+ if (error)
+ return;
+ if (result.type === "function")
+ remoteObject.target.DebuggerAgent.getFunctionDetails(result.objectId, didGetFunctionDetails);
+ result.release();
+ });
+ remoteObject.release();
});
- remoteObject.release();
});
- });
- contextMenu.appendSeparator();
- }
+ contextMenu.appendSeparator();
+ }
- if (WI.cssManager.canForcePseudoClasses() && domNode.attached) {
- contextMenu.appendSeparator();
+ if (WI.cssManager.canForcePseudoClasses() && domNode.attached) {
+ contextMenu.appendSeparator();
- let pseudoSubMenu = contextMenu.appendSubMenuItem(WI.UIString("Forced Pseudo-Classes", "A context menu item to force (override) a DOM node's pseudo-classes"));
+ let pseudoSubMenu = contextMenu.appendSubMenuItem(WI.UIString("Forced Pseudo-Classes", "A context menu item to force (override) a DOM node's pseudo-classes"));
- let enabledPseudoClasses = domNode.enabledPseudoClasses;
- WI.CSSManager.ForceablePseudoClasses.forEach((pseudoClass) => {
- let enabled = enabledPseudoClasses.includes(pseudoClass);
- pseudoSubMenu.appendCheckboxItem(pseudoClass.capitalize(), () => {
- domNode.setPseudoClassEnabled(pseudoClass, !enabled);
- }, enabled);
- });
- }
+ let enabledPseudoClasses = domNode.enabledPseudoClasses;
+ WI.CSSManager.ForceablePseudoClasses.forEach((pseudoClass) => {
+ let enabled = enabledPseudoClasses.includes(pseudoClass);
+ pseudoSubMenu.appendCheckboxItem(pseudoClass.capitalize(), () => {
+ domNode.setPseudoClassEnabled(pseudoClass, !enabled);
+ }, enabled);
+ });
+ }
- if (WI.domDebuggerManager.supported && isElement && !domNode.isPseudoElement() && attached) {
- contextMenu.appendSeparator();
+ if (WI.domDebuggerManager.supported && isElement && !domNode.isPseudoElement() && attached) {
+ contextMenu.appendSeparator();
- WI.appendContextMenuItemsForDOMNodeBreakpoints(contextMenu, domNode, options);
- }
+ WI.appendContextMenuItemsForDOMNodeBreakpoints(contextMenu, domNode, options);
+ }
- contextMenu.appendSeparator();
+ contextMenu.appendSeparator();
- if (!options.excludeLogElement && !domNode.isInUserAgentShadowTree() && !domNode.isPseudoElement()) {
- let label = isElement ? WI.UIString("Log Element", "Log (print) DOM element to Console") : WI.UIString("Log Node", "Log (print) DOM node to Console");
- contextMenu.appendItem(label, () => {
- WI.RemoteObject.resolveNode(domNode, WI.RuntimeManager.ConsoleObjectGroup).then((remoteObject) => {
- let text = isElement ? WI.UIString("Selected Element", "Selected DOM element") : WI.UIString("Selected Node", "Selected DOM node");
- const addSpecialUserLogClass = true;
- WI.consoleLogViewController.appendImmediateExecutionWithResult(text, remoteObject, addSpecialUserLogClass);
+ if (!options.excludeLogElement && !domNode.isInUserAgentShadowTree() && !domNode.isPseudoElement()) {
+ let label = isElement ? WI.UIString("Log Element", "Log (print) DOM element to Console") : WI.UIString("Log Node", "Log (print) DOM node to Console");
+ contextMenu.appendItem(label, () => {
+ WI.RemoteObject.resolveNode(domNode, WI.RuntimeManager.ConsoleObjectGroup).then((remoteObject) => {
+ let text = isElement ? WI.UIString("Selected Element", "Selected DOM element") : WI.UIString("Selected Node", "Selected DOM node");
+ const addSpecialUserLogClass = true;
+ WI.consoleLogViewController.appendImmediateExecutionWithResult(text, remoteObject, addSpecialUserLogClass);
+ });
});
- });
- }
+ }
- if (!options.excludeRevealElement && window.DOMAgent && attached) {
- contextMenu.appendItem(WI.repeatedUIString.revealInDOMTree(), () => {
- WI.domManager.inspectElement(domNode.id);
- });
- }
+ if (!options.excludeRevealElement && window.DOMAgent && attached) {
+ contextMenu.appendItem(WI.repeatedUIString.revealInDOMTree(), () => {
+ WI.domManager.inspectElement(domNode.id);
+ });
+ }
- if (WI.settings.experimentalEnableLayersTab.value && window.LayerTreeAgent && attached) {
- contextMenu.appendItem(WI.UIString("Reveal in Layers Tab", "Open Layers tab and select the layer corresponding to this node"), () => {
- WI.showLayersTab({nodeToSelect: domNode});
- });
- }
+ if (WI.settings.experimentalEnableLayersTab.value && window.LayerTreeAgent && attached) {
+ contextMenu.appendItem(WI.UIString("Reveal in Layers Tab", "Open Layers tab and select the layer corresponding to this node"), () => {
+ WI.showLayersTab({nodeToSelect: domNode});
+ });
+ }
- if (window.PageAgent && attached) {
- contextMenu.appendItem(WI.UIString("Capture Screenshot", "Capture screenshot of the selected DOM node"), () => {
- PageAgent.snapshotNode(domNode.id, (error, dataURL) => {
- if (error) {
- const target = WI.mainTarget;
- const source = WI.ConsoleMessage.MessageSource.Other;
- const level = WI.ConsoleMessage.MessageLevel.Error;
- let consoleMessage = new WI.ConsoleMessage(target, source, level, error);
- consoleMessage.shouldRevealConsole = true;
-
- WI.consoleLogViewController.appendConsoleMessage(consoleMessage);
- return;
- }
+ if (window.PageAgent && attached) {
+ contextMenu.appendItem(WI.UIString("Capture Screenshot", "Capture screenshot of the selected DOM node"), () => {
+ PageAgent.snapshotNode(domNode.id, (error, dataURL) => {
+ if (error) {
+ const target = WI.mainTarget;
+ const source = WI.ConsoleMessage.MessageSource.Other;
+ const level = WI.ConsoleMessage.MessageLevel.Error;
+ let consoleMessage = new WI.ConsoleMessage(target, source, level, error);
+ consoleMessage.shouldRevealConsole = true;
+
+ WI.consoleLogViewController.appendConsoleMessage(consoleMessage);
+ return;
+ }
- WI.FileUtilities.save({
- url: WI.FileUtilities.inspectorURLForFilename(WI.FileUtilities.screenshotString() + ".png"),
- content: parseDataURL(dataURL).data,
- base64Encoded: true,
+ WI.FileUtilities.save({
+ url: WI.FileUtilities.inspectorURLForFilename(WI.FileUtilities.screenshotString() + ".png"),
+ content: parseDataURL(dataURL).data,
+ base64Encoded: true,
+ });
});
});
- });
- }
+ }
- if (isElement && attached) {
- contextMenu.appendItem(WI.UIString("Scroll into View", "Scroll selected DOM node into view on the inspected web page"), () => {
- domNode.scrollIntoView();
- });
- }
+ if (isElement && attached) {
+ contextMenu.appendItem(WI.UIString("Scroll into View", "Scroll selected DOM node into view on the inspected web page"), () => {
+ domNode.scrollIntoView();
+ });
+ }
- contextMenu.appendSeparator();
+ contextMenu.appendSeparator();
+ }
};
WI.appendContextMenuItemsForDOMNodeBreakpoints = function(contextMenu, domNode, options = {})
});
}
- if (attributeName && isNonShadowEditable) {
+ if (attributeName) {
subMenus.copy.appendItem(WI.UIString("Attribute"), () => {
let text = attributeName;
let attributeValue = this.representedObject.getAttribute(attributeName);
for (let subMenu of Object.values(subMenus))
contextMenu.pushItem(subMenu);
- if (this.selected && this.treeOutline && this.treeOutline.selectedTreeElements.length > 1) {
- let forceHidden = !this.treeOutline.selectedTreeElements.every((treeElement) => treeElement.isNodeHidden);
- let label = forceHidden ? WI.UIString("Hide Elements") : WI.UIString("Show Elements");
- contextMenu.appendItem(label, () => {
- this.treeOutline.toggleSelectedElementsVisibility(forceHidden);
- });
- } else {
- contextMenu.appendItem(WI.UIString("Toggle Visibility"), () => {
- this.toggleElementVisibility();
- });
+ if (this.treeOutline.editable) {
+ if (this.selected && this.treeOutline && this.treeOutline.selectedTreeElements.length > 1) {
+ let forceHidden = !this.treeOutline.selectedTreeElements.every((treeElement) => treeElement.isNodeHidden);
+ let label = forceHidden ? WI.UIString("Hide Elements") : WI.UIString("Show Elements");
+ contextMenu.appendItem(label, () => {
+ this.treeOutline.toggleSelectedElementsVisibility(forceHidden);
+ });
+ } else if (isEditableNode) {
+ contextMenu.appendItem(WI.UIString("Toggle Visibility"), () => {
+ this.toggleElementVisibility();
+ });
+ }
}
}
this._editable = false;
this._editing = false;
this._visible = false;
+ this._usingLocalDOMNode = false;
this._hideElementsKeyboardShortcut = new WI.KeyboardShortcut(null, "H", this._hideElements.bind(this), this.element);
this._hideElementsKeyboardShortcut.implicitlyPreventsDefault = false;
return this._isXMLMimeType;
}
+ markAsUsingLocalDOMNode()
+ {
+ this._editable = false;
+ this._usingLocalDOMNode = true;
+ }
+
selectedDOMNode()
{
return this._selectedDOMNode;
treeElement.populateDOMNodeContextMenu(contextMenu, subMenus, event, subMenus);
let options = {
+ disallowEditing: !this._editable,
excludeRevealElement: this._excludeRevealElementContextMenu,
copySubMenu: subMenus.copy,
};
_onmousemove(event)
{
+ if (this._usingLocalDOMNode)
+ return;
+
let element = this.treeElementFromEvent(event);
if (element && this._previousHoveredElement === element)
return;
_onmouseout(event)
{
+ if (this._usingLocalDOMNode)
+ return;
+
var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY);
if (nodeUnderMouse && this.element.contains(nodeUnderMouse))
return;
_ondragstart(event)
{
+ if (!this._editable)
+ return false;
+
let treeElement = this.treeElementFromEvent(event);
if (!treeElement)
return false;
_ondragover(event)
{
+ if (!this._editable)
+ return false;
+
if (event.dataTransfer.types.includes(WI.GeneralStyleDetailsSidebarPanel.ToggledClassesDragType)) {
event.preventDefault();
event.dataTransfer.dropEffect = "copy";
_ondragleave(event)
{
+ if (!this._editable)
+ return false;
+
this._clearDragOverTreeElementMarker();
event.preventDefault();
return false;
_ondrop(event)
{
+ if (!this._editable)
+ return;
+
event.preventDefault();
function callback(error, newNodeId)
_ondragend(event)
{
+ if (!this._editable)
+ return;
+
event.preventDefault();
this._clearDragOverTreeElementMarker();
delete this._nodeBeingDragged;
_hideElements(event, keyboardShortcut)
{
+ if (!this._editable)
+ return;
+
if (!this.selectedTreeElement || WI.isEditingAnyField())
return;
--- /dev/null
+/*
+ * 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.LocalDOMContentView = class LocalDOMContentView extends WI.LocalRemoteObjectContentView
+{
+ constructor(content, mimeType, representedObject)
+ {
+ console.assert(typeof content === "string");
+ console.assert(typeof mimeType === "string");
+
+ super(representedObject);
+
+ this._content = content;
+ this._mimeType = mimeType;
+ }
+
+ // Protected
+
+ get expression()
+ {
+ return `(new DOMParser).parseFromString(${JSON.stringify(this._content)}, ${JSON.stringify(this._mimeType)})`;
+ }
+
+ renderRemoteObject(remoteObject)
+ {
+ remoteObject.pushNodeToFrontend((nodeId) => {
+ let domNode = WI.domManager.nodeForId(nodeId);
+ console.assert(domNode);
+
+ domNode.getSubtree(3, () => {
+ let treeOutline = new WI.DOMTreeOutline({omitRootDOMNode: true, selectable: false});
+ treeOutline.markAsUsingLocalDOMNode();
+ treeOutline.setVisible(true);
+ treeOutline.rootDOMNode = domNode;
+ this.element.appendChild(treeOutline.element);
+ });
+ });
+ }
+};
--- /dev/null
+/*
+ * 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.LocalJSONContentView = class LocalJSONContentView extends WI.LocalRemoteObjectContentView
+{
+ constructor(json, representedObject)
+ {
+ console.assert(typeof json === "string" && json.isJSON());
+
+ super(representedObject);
+
+ this._json = json;
+ }
+
+ // Protected
+
+ get expression()
+ {
+ return this._json;
+ }
+
+ renderRemoteObject(remoteObject)
+ {
+ let objectTree = new WI.ObjectTreeView(remoteObject);
+ objectTree.showOnlyJSON();
+ objectTree.expand();
+
+ this.element.appendChild(objectTree.element);
+ }
+};
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-.content-view.json {
+.content-view.local-remote-object {
padding: 10px;
overflow: scroll;
}
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-WI.JSONContentView = class JSONContentView extends WI.ContentView
+WI.LocalRemoteObjectContentView = class LocalRemoteObjectContentView extends WI.ContentView
{
- constructor(json, representedObject)
+ constructor(representedObject)
{
- console.assert(typeof json === "string" && json.isJSON());
-
super(representedObject);
- this._json = json;
this._remoteObject = null;
this._spinnerTimeout = undefined;
- this.element.classList.add("json");
+ this.element.classList.add("local-remote-object");
}
// Protected
+ get expression()
+ {
+ throw WI.NotImplementedError.subclassMustOverride();
+ }
+
+ renderRemoteObject(remoteObject)
+ {
+ throw WI.NotImplementedError.subclassMustOverride();
+ }
+
initialLayout()
{
super.initialLayout();
- const options = {
- expression: "(" + this._json + ")",
+ let target = WI.assumingMainTarget();
+ let options = {
+ expression: "(" + this.expression + ")",
doNotPauseOnExceptionsAndMuteConsole: true,
generatePreview: true,
};
- RuntimeAgent.evaluate.invoke(options, (error, result, wasThrown) => {
+ target.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);
+
+ this.renderRemoteObject(this._remoteObject);
});
}
content: url(../Images/DOMNode.svg);
}
+.object-icon .icon {
+ content: url(../Images/Object.svg);
+}
+
.function-icon .icon {
content: url(../Images/Function.svg);
}
this._resource.addEventListener(WI.Resource.Event.TypeDidChange, this._resourceTypeDidChange, this);
this._resource.addEventListener(WI.Resource.Event.LoadingDidFinish, this._resourceLoadingDidFinish, this);
- function createPathComponent(displayName, className, identifier)
- {
- const textOnly = false;
- const showSelectorArrows = true;
- let pathComponent = new WI.HierarchicalPathComponent(displayName, className, identifier, textOnly, showSelectorArrows);
- pathComponent.addEventListener(WI.HierarchicalPathComponent.Event.SiblingWasSelected, this._pathComponentSelected, this);
- pathComponent.comparisonData = resource;
- return pathComponent;
- }
-
- this._requestContentView = null;
- this._responseContentView = null;
- this._customRequestContentView = null;
- this._customRequestContentViewInitializer = null;
- this._customResponseContentView = null;
- this._customResponseContentViewInitializer = null;
-
- this._requestPathComponent = createPathComponent.call(this, WI.UIString("Request"), WI.ResourceClusterContentView.RequestIconStyleClassName, WI.ResourceClusterContentView.RequestIdentifier);
- this._customRequestPathComponent = createPathComponent.call(this, WI.UIString("Custom Request"), WI.ResourceClusterContentView.RequestIconStyleClassName, WI.ResourceClusterContentView.CustomRequestIdentifier);
- this._responsePathComponent = createPathComponent.call(this, WI.UIString("Response"), WI.ResourceClusterContentView.ResponseIconStyleClassName, WI.ResourceClusterContentView.ResponseIdentifier);
- this._customResponsePathComponent = createPathComponent.call(this, WI.UIString("Custom Response"), WI.ResourceClusterContentView.ResponseIconStyleClassName, WI.ResourceClusterContentView.CustomResponseIdentifier);
+ this._responsePathComponent = this._createPathComponent({
+ displayName: WI.UIString("Response"),
+ identifier: ResourceClusterContentView.Identifier.Response,
+ styleClassNames: ["response-icon"],
+ });
if (this._canShowRequestContentView()) {
- this._requestPathComponent.nextSibling = this._responsePathComponent;
- this._responsePathComponent.previousSibling = this._requestPathComponent;
-
- this._tryEnableCustomRequestContentView();
+ this._requestPathComponent = this._createPathComponent({
+ displayName: WI.UIString("Request"),
+ identifier: ResourceClusterContentView.Identifier.Request,
+ styleClassNames: ["request-icon"],
+ nextSibling: this._responsePathComponent,
+ });
+
+ this._tryEnableCustomRequestContentViews();
}
// FIXME: Since a custom response content view may only become available after a response is received
// we need to figure out a way to restore / prefer the custom content view. For example if users
// always want to prefer the JSON view to the normal Response text view.
- this._currentContentViewSetting = new WI.Setting("resource-current-view-" + this._resource.url.hash, WI.ResourceClusterContentView.CustomResponseIdentifier);
+ this._currentContentViewSetting = new WI.Setting("resource-current-view-" + this._resource.url.hash, ResourceClusterContentView.Identifier.Response);
- this._tryEnableCustomResponseContentView();
+ this._tryEnableCustomResponseContentViews();
}
// Public
get resource() { return this._resource; }
- get requestContentView()
- {
- 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;
- }
-
- get responseContentView()
- {
- if (this._responseContentView)
- return this._responseContentView;
-
- this._responseContentView = this._contentViewForResourceType(this._resource.type);
- if (this._responseContentView)
- return this._responseContentView;
-
- let typeFromMIMEType = WI.Resource.typeFromMIMEType(this._resource.mimeType);
- this._responseContentView = this._contentViewForResourceType(typeFromMIMEType);
- if (this._responseContentView)
- return this._responseContentView;
-
- if (WI.shouldTreatMIMETypeAsText(this._resource.mimeType)) {
- this._responseContentView = new WI.TextResourceContentView(this._resource);
- return this._responseContentView;
- }
-
- this._responseContentView = new WI.GenericResourceContentView(this._resource);
- return this._responseContentView;
- }
-
- get customRequestContentView()
- {
- if (!this._customRequestContentView && this._customRequestContentViewInitializer) {
- this._customRequestContentView = this._customRequestContentViewInitializer();
- this._customRequestContentViewInitializer = null;
- }
- return this._customRequestContentView;
- }
-
- get customResponseContentView()
- {
- if (!this._customResponseContentView && this._customResponseContentViewInitializer) {
- this._customResponseContentView = this._customResponseContentViewInitializer();
- this._customResponseContentViewInitializer = null;
- }
- return this._customResponseContentView;
- }
-
get selectionPathComponents()
{
let currentContentView = this._contentViewContainer.currentContentView;
{
this._shownInitialContent = true;
- return this._showContentViewForIdentifier(WI.ResourceClusterContentView.CustomRequestIdentifier);
+ return this._showContentViewForIdentifier(ResourceClusterContentView.Identifier.Request);
}
showResponse(positionToReveal, textRangeToSelect, forceUnformatted)
this._forceUnformatted = forceUnformatted;
}
- let responseContentView = this._showContentViewForIdentifier(WI.ResourceClusterContentView.ResponseIdentifier);
+ let responseContentView = this._showContentViewForIdentifier(ResourceClusterContentView.Identifier.Response);
if (typeof responseContentView.revealPosition === "function")
responseContentView.revealPosition(positionToReveal, textRangeToSelect, forceUnformatted);
return responseContentView;
// Private
+ get requestContentView()
+ {
+ 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;
+ }
+
+ get responseContentView()
+ {
+ if (this._responseContentView)
+ return this._responseContentView;
+
+ this._responseContentView = this._contentViewForResourceType(this._resource.type);
+ if (this._responseContentView)
+ return this._responseContentView;
+
+ let typeFromMIMEType = WI.Resource.typeFromMIMEType(this._resource.mimeType);
+ this._responseContentView = this._contentViewForResourceType(typeFromMIMEType);
+ if (this._responseContentView)
+ return this._responseContentView;
+
+ if (WI.shouldTreatMIMETypeAsText(this._resource.mimeType)) {
+ this._responseContentView = new WI.TextResourceContentView(this._resource);
+ return this._responseContentView;
+ }
+
+ this._responseContentView = new WI.GenericResourceContentView(this._resource);
+ return this._responseContentView;
+ }
+
+ get customRequestDOMContentView()
+ {
+ if (!this._customRequestDOMContentView && this._customRequestDOMContentViewInitializer)
+ this._customRequestDOMContentView = this._customRequestDOMContentViewInitializer();
+ return this._customRequestDOMContentView;
+ }
+
+ get customRequestJSONContentView()
+ {
+ if (!this._customRequestJSONContentView && this._customRequestJSONContentViewInitializer)
+ this._customRequestJSONContentView = this._customRequestJSONContentViewInitializer();
+ return this._customRequestJSONContentView;
+ }
+
+ get customResponseDOMContentView()
+ {
+ if (!this._customResponseDOMContentView && this._customResponseDOMContentViewInitializer)
+ this._customResponseDOMContentView = this._customResponseDOMContentViewInitializer();
+ return this._customResponseDOMContentView;
+ }
+
+ get customResponseJSONContentView()
+ {
+ if (!this._customResponseJSONContentView && this._customResponseJSONContentViewInitializer)
+ this._customResponseJSONContentView = this._customResponseJSONContentViewInitializer();
+ return this._customResponseJSONContentView;
+ }
+
+ get customResponseTextContentView()
+ {
+ if (!this._customResponseTextContentView && this._customResponseTextContentViewInitializer)
+ this._customResponseTextContentView = this._customResponseTextContentViewInitializer();
+ return this._customResponseTextContentView;
+ }
+
+ _createPathComponent({displayName, styleClassNames, identifier, previousSibling, nextSibling})
+ {
+ const textOnly = false;
+ const showSelectorArrows = true;
+ let pathComponent = new WI.HierarchicalPathComponent(displayName, styleClassNames, identifier, textOnly, showSelectorArrows);
+ pathComponent.comparisonData = this._resource;
+
+ if (previousSibling) {
+ previousSibling.nextSibling = pathComponent;
+ pathComponent.previousSibling = previousSibling;
+ }
+
+ if (nextSibling) {
+ nextSibling.previousSibling = pathComponent;
+ pathComponent.nextSibling = nextSibling;
+ }
+
+ pathComponent.addEventListener(WI.HierarchicalPathComponent.Event.SiblingWasSelected, this._pathComponentSelected, this);
+
+ return pathComponent;
+ }
+
_canShowRequestContentView()
{
let requestData = this._resource.requestData;
_canShowCustomRequestContentView()
{
- return !!(this._customRequestContentView || this._customRequestContentViewInitializer);
+ return !!(this._customRequestDOMContentViewInitializer || this._customRequestJSONContentViewInitializer);
}
_canShowCustomResponseContentView()
{
- return !!(this._customResponseContentView || this._customResponseContentViewInitializer);
+ return !!(this._customResponseDOMContentViewInitializer || this._customResponseJSONContentViewInitializer || this._customResponseTextContentViewInitializer);
}
_contentViewForResourceType(type)
return new WI.TextResourceContentView(this._resource);
case WI.Resource.Type.Image:
- if (WI.fileExtensionForMIMEType(this._resource.mimeType) === "svg")
- return new WI.SVGImageResourceClusterContentView(this._resource);
return new WI.ImageResourceContentView(this._resource);
case WI.Resource.Type.Font:
_pathComponentForContentView(contentView)
{
- console.assert(contentView);
- if (!contentView)
- return null;
- if (contentView === this._requestContentView)
+ switch (contentView) {
+ case this._requestContentView:
return this._requestPathComponent;
- if (contentView === this._responseContentView)
+
+ case this._customRequestDOMContentView:
+ return this._customRequestDOMPathComponent;
+
+ case this._customRequestJSONContentView:
+ return this._customRequestJSONPathComponent;
+
+ case this._responseContentView:
return this._responsePathComponent;
- if (contentView === this._customRequestContentView)
- return this._customRequestPathComponent;
- if (contentView === this._customResponseContentView)
- return this._customResponsePathComponent;
- console.error("Unknown contentView.");
+
+ case this._customResponseDOMContentView:
+ return this._customResponseDOMPathComponent;
+
+ case this._customResponseJSONContentView:
+ return this._customResponseJSONPathComponent;
+
+ case this._customResponseTextContentView:
+ return this._customResponseTextPathComponent;
+ }
+
+ console.error("Unknown contentView", contentView);
return null;
}
_identifierForContentView(contentView)
{
console.assert(contentView);
- if (!contentView)
- return null;
- if (contentView === this._requestContentView)
- return WI.ResourceClusterContentView.RequestIdentifier;
- if (contentView === this._responseContentView)
- return WI.ResourceClusterContentView.ResponseIdentifier;
- if (contentView === this._customRequestContentView)
- return WI.ResourceClusterContentView.CustomRequestIdentifier;
- if (contentView === this._customResponseContentView)
- return WI.ResourceClusterContentView.CustomResponseIdentifier;
- console.error("Unknown contentView.");
+
+ switch (contentView) {
+ case this._requestContentView:
+ return ResourceClusterContentView.Identifier.Request;
+
+ case this._customRequestDOMContentView:
+ return ResourceClusterContentView.Identifier.RequestDOM;
+
+ case this._customRequestJSONContentView:
+ return ResourceClusterContentView.Identifier.RequestJSON;
+
+ case this._responseContentView:
+ return ResourceClusterContentView.Identifier.Response;
+
+ case this._customResponseDOMContentView:
+ return ResourceClusterContentView.Identifier.ResponseDOM;
+
+ case this._customResponseJSONContentView:
+ return ResourceClusterContentView.Identifier.ResponseJSON;
+
+ case this._customResponseTextContentView:
+ return ResourceClusterContentView.Identifier.ResponseText;
+ }
+
+ console.error("Unknown contentView", contentView);
return null;
}
// This is expected to fall through all the way to the `default`.
switch (identifier) {
- case WI.ResourceClusterContentView.CustomRequestIdentifier:
- contentViewToShow = this.customRequestContentView;
+ case ResourceClusterContentView.Identifier.RequestDOM:
+ contentViewToShow = this.customRequestDOMContentView;
+ if (contentViewToShow)
+ break;
+ // fallthrough
+ case ResourceClusterContentView.Identifier.RequestJSON:
+ contentViewToShow = this.customRequestJSONContentView;
if (contentViewToShow)
break;
// fallthrough
- case WI.ResourceClusterContentView.RequestIdentifier:
+ case ResourceClusterContentView.Identifier.Request:
contentViewToShow = this.requestContentView;
if (contentViewToShow)
break;
// fallthrough
- case WI.ResourceClusterContentView.CustomResponseIdentifier:
- contentViewToShow = this.customResponseContentView;
+ case ResourceClusterContentView.Identifier.ResponseDOM:
+ contentViewToShow = this.customResponseDOMContentView;
if (contentViewToShow)
break;
// fallthrough
- case WI.ResourceClusterContentView.ResponseIdentifier:
+ case ResourceClusterContentView.Identifier.ResponseJSON:
+ contentViewToShow = this.customResponseJSONContentView;
+ if (contentViewToShow)
+ break;
+ // fallthrough
+ case ResourceClusterContentView.Identifier.ResponseText:
+ contentViewToShow = this.customResponseTextContentView;
+ if (contentViewToShow)
+ break;
+ // fallthrough
+ case ResourceClusterContentView.Identifier.Response:
default:
contentViewToShow = this.responseContentView;
break;
_resourceLoadingDidFinish(event)
{
- this._tryEnableCustomResponseContentView();
+ this._tryEnableCustomResponseContentViews();
if ("_positionToReveal" in this) {
if (this._contentViewContainer.currentContentView === this._responseContentView)
return typeof content === "string" && content.isJSON((json) => json && (typeof json === "object" || Array.isArray(json)));
}
- _tryEnableCustomRequestContentView()
+ _canUseDOMContentViewForContent(content, mimeType)
+ {
+ if (typeof content !== "string")
+ return false;
+
+ switch (mimeType) {
+ case "text/html":
+ return true;
+
+ case "text/xml":
+ case "application/xml":
+ case "application/xhtml+xml":
+ case "image/svg+xml":
+ try {
+ let dom = (new DOMParser).parseFromString(content, mimeType);
+ return !dom.querySelector("parsererror");
+ } catch { }
+ return false;
+ }
+
+ return false;
+ }
+
+ _normalizeMIMETypeForDOM(mimeType)
{
- if (!this._canUseJSONContentViewForContent(this._resource.requestData))
+ mimeType = parseMIMEType(mimeType).type;
+
+ if (mimeType.endsWith("/html") || mimeType.endsWith("+html"))
+ return "text/html";
+
+ if (mimeType.endsWith("/xml") || mimeType.endsWith("+xml")) {
+ if (mimeType !== "application/xhtml+xml" && mimeType !== "image/svg+xml")
+ return "application/xml";
+ }
+
+ if (mimeType.endsWith("/xhtml") || mimeType.endsWith("+xhtml"))
+ return "application/xhtml+xml";
+
+ if (mimeType.endsWith("/svg") || mimeType.endsWith("+svg"))
+ return "image/svg+xml";
+
+ return mimeType;
+ }
+
+ _tryEnableCustomRequestContentViews()
+ {
+ let content = this._resource.requestData;
+
+ if (this._canUseJSONContentViewForContent(content)) {
+ this._customRequestJSONContentViewInitializer = () => new WI.LocalJSONContentView(content, this._resource);
+
+ this._customRequestJSONPathComponent = this._createPathComponent({
+ displayName: WI.UIString("Request (Object Tree)"),
+ styleClassNames: ["object-icon"],
+ identifier: ResourceClusterContentView.Identifier.RequestJSON,
+ previousSibling: this._requestPathComponent,
+ nextSibling: this._responsePathComponent,
+ });
+
+ this.dispatchEventToListeners(WI.ContentView.Event.SelectionPathComponentsDidChange);
return;
+ }
- this._customRequestContentViewInitializer = () => new WI.JSONContentView(this._resource.requestData, this._resource);
+ let mimeType = this._normalizeMIMETypeForDOM(this._resource.requestDataContentType);
- 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;
+ if (this._canUseDOMContentViewForContent(content, mimeType)) {
+ this._customRequestDOMContentViewInitializer = () => new WI.LocalDOMContentView(content, mimeType, this._resource);
+
+ this._customRequestDOMPathComponent = this._createPathComponent({
+ displayName: WI.UIString("Request (DOM Tree)"),
+ styleClassNames: ["dom-document-icon"],
+ identifier: ResourceClusterContentView.Identifier.RequestDOM,
+ previousSibling: this._requestPathComponent,
+ nextSibling: this._responsePathComponent,
+ });
+
+ this.dispatchEventToListeners(WI.ContentView.Event.SelectionPathComponentsDidChange);
+ return;
+ }
}
- _tryEnableCustomResponseContentView()
+ _tryEnableCustomResponseContentViews()
{
if (!this._resource.hasResponse())
return;
this._resource.requestContent()
.then(({error, content}) => {
- if (error || !content || !this._canUseJSONContentViewForContent(content))
+ if (error || typeof content !== "string")
return;
- this._customResponseContentViewInitializer = () => new WI.JSONContentView(content, this._resource);
+ if (this._canUseJSONContentViewForContent(content)) {
+ this._customResponseJSONContentViewInitializer = () => new WI.LocalJSONContentView(content, this._resource);
- this._customResponsePathComponent.displayName = WI.UIString("Response (JSON)");
- this._customResponsePathComponent.previousSibling = this._responsePathComponent;
- this._responsePathComponent.nextSibling = this._customResponsePathComponent;
+ this._customResponseJSONPathComponent = this._createPathComponent({
+ displayName: WI.UIString("Response (Object Tree)"),
+ styleClassNames: ["object-icon"],
+ identifier: ResourceClusterContentView.Identifier.ResponseJSON,
+ previousSibling: this._responsePathComponent,
+ });
- this.dispatchEventToListeners(WI.ContentView.Event.SelectionPathComponentsDidChange);
+ this.dispatchEventToListeners(WI.ContentView.Event.SelectionPathComponentsDidChange);
+ return;
+ }
+
+ let mimeType = this._normalizeMIMETypeForDOM(this._resource.mimeType);
+
+ if (this._canUseDOMContentViewForContent(content, mimeType)) {
+ if (mimeType === "image/svg+xml") {
+ this._customResponseTextContentViewInitializer = () => new WI.TextContentView(content, mimeType, this._resource);
+
+ this._customResponseTextPathComponent = this._createPathComponent({
+ displayName: WI.UIString("Response (Text)"),
+ styleClassNames: ["source-icon"],
+ identifier: ResourceClusterContentView.Identifier.ResponseText,
+ previousSibling: this._responsePathComponent,
+ });
+ }
+
+ this._customResponseDOMContentViewInitializer = () => new WI.LocalDOMContentView(content, mimeType, this._resource);
+
+ this._customResponseDOMPathComponent = this._createPathComponent({
+ displayName: WI.UIString("Response (DOM Tree)"),
+ styleClassNames: ["dom-document-icon"],
+ identifier: ResourceClusterContentView.Identifier.ResponseDOM,
+ previousSibling: this._customResponseTextPathComponent || this._responsePathComponent,
+ });
+
+ this.dispatchEventToListeners(WI.ContentView.Event.SelectionPathComponentsDidChange);
+ return;
+ }
});
}
};
WI.ResourceClusterContentView.ContentViewIdentifierCookieKey = "resource-cluster-content-view-identifier";
-WI.ResourceClusterContentView.RequestIconStyleClassName = "request-icon";
-WI.ResourceClusterContentView.ResponseIconStyleClassName = "response-icon";
-WI.ResourceClusterContentView.RequestIdentifier = "request";
-WI.ResourceClusterContentView.ResponseIdentifier = "response";
-WI.ResourceClusterContentView.CustomRequestIdentifier = "custom-request";
-WI.ResourceClusterContentView.CustomResponseIdentifier = "custom-response";
+WI.ResourceClusterContentView.Identifier = {
+ Request: "request",
+ RequestDOM: "request-dom",
+ RequestJSON: "request-json",
+ Response: "response",
+ ResponseDOM: "response-dom",
+ ResponseJSON: "response-json",
+ ResponseText: "response-text",
+};
+++ /dev/null
-/*
- * Copyright (C) 2017 Devin Rousso <webkit@devinrousso.com>. 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.SVGImageResourceClusterContentView = class SVGImageResourceClusterContentView extends WI.ClusterContentView
-{
- constructor(resource)
- {
- super(resource);
-
- this._resource = resource;
-
- let createPathComponent = (displayName, className, identifier) => {
- const textOnly = false;
- const showSelectorArrows = true;
- let pathComponent = new WI.HierarchicalPathComponent(displayName, className, identifier, textOnly, showSelectorArrows);
- pathComponent.addEventListener(WI.HierarchicalPathComponent.Event.SiblingWasSelected, this._pathComponentSelected, this);
- pathComponent.comparisonData = resource;
- return pathComponent;
- };
-
- this._imagePathComponent = createPathComponent(WI.UIString("Image"), "image-icon", WI.SVGImageResourceClusterContentView.Identifier.Image);
- this._sourcePathComponent = createPathComponent(WI.UIString("Source"), "source-icon", WI.SVGImageResourceClusterContentView.Identifier.Source);
-
- this._imagePathComponent.nextSibling = this._sourcePathComponent;
- this._sourcePathComponent.previousSibling = this._imagePathComponent;
-
- this._currentContentViewSetting = new WI.Setting("svg-image-resource-cluster-current-view-" + this._resource.url.hash, WI.SVGImageResourceClusterContentView.Identifier.Image);
- }
-
- // Public
-
- get resource() { return this._resource; }
-
- get selectionPathComponents()
- {
- let currentContentView = this._contentViewContainer.currentContentView;
- if (!currentContentView)
- return [];
-
- // Append the current view's path components to the path component representing the current view.
- let components = [this._pathComponentForContentView(currentContentView)];
- return components.concat(currentContentView.selectionPathComponents);
- }
-
- // Protected
-
- shown()
- {
- super.shown();
-
- if (this._shownInitialContent)
- return;
-
- this._showContentViewForIdentifier(this._currentContentViewSetting.value);
- }
-
- closed()
- {
- super.closed();
-
- this._shownInitialContent = false;
- }
-
- saveToCookie(cookie)
- {
- cookie[WI.SVGImageResourceClusterContentView.ContentViewIdentifierCookieKey] = this._currentContentViewSetting.value;
- }
-
- restoreFromCookie(cookie)
- {
- let contentView = this._showContentViewForIdentifier(cookie[WI.SVGImageResourceClusterContentView.ContentViewIdentifierCookieKey]);
- if (typeof contentView.revealPosition === "function" && "lineNumber" in cookie && "columnNumber" in cookie)
- contentView.revealPosition(new WI.SourceCodePosition(cookie.lineNumber, cookie.columnNumber));
- }
-
- // Private
-
- _pathComponentForContentView(contentView)
- {
- console.assert(contentView);
- if (!contentView)
- return null;
- if (contentView instanceof WI.ImageResourceContentView)
- return this._imagePathComponent;
- if (contentView instanceof WI.TextContentView)
- return this._sourcePathComponent;
- console.error("Unknown contentView.");
- return null;
- }
-
- _identifierForContentView(contentView)
- {
- console.assert(contentView);
- if (!contentView)
- return null;
- if (contentView instanceof WI.ImageResourceContentView)
- return WI.SVGImageResourceClusterContentView.Identifier.Image;
- if (contentView instanceof WI.TextContentView)
- return WI.SVGImageResourceClusterContentView.Identifier.Source;
- console.error("Unknown contentView.");
- return null;
- }
-
- _showContentViewForIdentifier(identifier)
- {
- let contentViewToShow = null;
-
- switch (identifier) {
- case WI.SVGImageResourceClusterContentView.Identifier.Image:
- contentViewToShow = new WI.ImageResourceContentView(this._resource);
- break;
-
- case WI.SVGImageResourceClusterContentView.Identifier.Source:
- contentViewToShow = new WI.TextContentView("", this._resource.mimeType);
-
- this._resource.requestContent().then((result) => {
- if (typeof result.content === "string") {
- contentViewToShow.textEditor.string = result.content;
- return;
- }
-
- blobAsText(result.content, (text) => {
- contentViewToShow.textEditor.string = text;
- });
- });
- break;
-
- default:
- // Default to showing the image.
- contentViewToShow = new WI.ImageResourceContentView(this._resource);
- break;
- }
-
- this._currentContentViewSetting.value = this._identifierForContentView(contentViewToShow);
-
- return this.contentViewContainer.showContentView(contentViewToShow);
- }
-
- _pathComponentSelected(event)
- {
- this._showContentViewForIdentifier(event.data.pathComponent.representedObject);
- }
-};
-
-WI.SVGImageResourceClusterContentView.ContentViewIdentifierCookieKey = "svg-image-resource-cluster-content-view-identifier";
-
-WI.SVGImageResourceClusterContentView.Identifier = {
- Image: "image",
- Source: "source",
-};
WI.TextContentView = class TextContentView extends WI.ContentView
{
- constructor(string, mimeType)
+ constructor(string, mimeType, representedObject)
{
- super(string);
+ super(representedObject || string);
this.element.classList.add("text");