| /* |
| * Copyright (C) 2015 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.FormattedValue = {}; |
| |
| WI.FormattedValue.hasSimpleDisplay = function(object) |
| { |
| switch (object.type) { |
| case "boolean": |
| case "number": |
| case "string": |
| case "symbol": |
| case "bigint": |
| case "undefined": |
| return true; |
| |
| case "function": |
| return false; |
| |
| case "object": |
| var subtype = object.subtype; |
| return subtype === "null" || subtype === "regexp" || subtype === "date"; |
| } |
| |
| console.assert(false, "All RemoteObject types should be handled above"); |
| return false; |
| }; |
| |
| WI.FormattedValue.classNameForTypes = function(type, subtype) |
| { |
| return "formatted-" + (subtype ? subtype : type); |
| }; |
| |
| WI.FormattedValue.classNameForObject = function(object) |
| { |
| return WI.FormattedValue.classNameForTypes(object.type, object.subtype); |
| }; |
| |
| WI.FormattedValue.createLinkifiedElementString = function(string) |
| { |
| var span = document.createElement("span"); |
| span.className = "formatted-string"; |
| span.append("\"", WI.linkifyStringAsFragment(string.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")), "\""); |
| return span; |
| }; |
| |
| WI.FormattedValue.createElementForNode = function(object) |
| { |
| var span = document.createElement("span"); |
| span.className = "formatted-node"; |
| |
| object.pushNodeToFrontend(function(nodeId) { |
| if (!nodeId) { |
| span.textContent = object.description; |
| return; |
| } |
| |
| var treeOutline = new WI.DOMTreeOutline; |
| treeOutline.setVisible(true); |
| treeOutline.rootDOMNode = WI.domManager.nodeForId(nodeId); |
| if (!treeOutline.children[0].hasChildren) |
| treeOutline.element.classList.add("single-node"); |
| span.appendChild(treeOutline.element); |
| }); |
| |
| return span; |
| }; |
| |
| WI.FormattedValue.createElementForError = function(object) |
| { |
| var span = document.createElement("span"); |
| span.classList.add("formatted-error"); |
| span.textContent = object.description; |
| |
| if (!object.preview) |
| return span; |
| |
| function previewToObject(preview) |
| { |
| var result = {}; |
| for (var property of preview.propertyPreviews) |
| result[property.name] = property.value; |
| |
| return result; |
| } |
| |
| var preview = previewToObject(object.preview); |
| if (!preview.sourceURL) |
| return span; |
| |
| var sourceLinkWithPrefix = WI.ErrorObjectView.makeSourceLinkWithPrefix(preview.sourceURL, preview.line, preview.column); |
| span.append(sourceLinkWithPrefix); |
| return span; |
| }; |
| |
| WI.FormattedValue.createElementForNodePreview = function(preview, {remoteObjectAccessor} = {}) |
| { |
| var value = preview.value || preview.description; |
| var span = document.createElement("span"); |
| span.className = "formatted-node-preview syntax-highlighted"; |
| |
| if (remoteObjectAccessor) { |
| let domNode = null; |
| |
| span.addEventListener("mouseenter", (event) => { |
| if (domNode) { |
| WI.domManager.highlightDOMNode(domNode.id, "all"); |
| return; |
| } |
| |
| remoteObjectAccessor((remoteObject) => { |
| remoteObject.pushNodeToFrontend((nodeId) => { |
| domNode = WI.domManager.nodeForId(nodeId); |
| if (domNode) |
| WI.domManager.highlightDOMNode(domNode.id, "all"); |
| }); |
| }); |
| }); |
| |
| span.addEventListener("mouseleave", (event) => { |
| WI.domManager.hideDOMNodeHighlight(); |
| }); |
| |
| span.addEventListener("contextmenu", (event) => { |
| if (!domNode) |
| return; |
| |
| let contextMenu = WI.ContextMenu.createFromEvent(event); |
| |
| WI.appendContextMenuItemsForDOMNode(contextMenu, domNode); |
| }); |
| } |
| |
| // Comment node preview. |
| if (value.startsWith("<!--")) { |
| var comment = span.appendChild(document.createElement("span")); |
| comment.className = "html-comment"; |
| comment.textContent = value; |
| return span; |
| } |
| |
| // Doctype node preview. |
| if (value.startsWith("<!DOCTYPE")) { |
| var doctype = span.appendChild(document.createElement("span")); |
| doctype.className = "html-doctype"; |
| doctype.textContent = value; |
| return span; |
| } |
| |
| // Element node previews have a very strict format, with at most a single attribute. |
| // We can style it up like a DOMNode without interactivity. |
| var matches = value.match(/^<(\S+?)(?: (\S+?)="(.*?)")?>$/); |
| |
| // Remaining node types are often #text, #document, etc, with attribute nodes potentially being any string. |
| if (!matches) { |
| console.assert(!value.startsWith("<"), "Unexpected node preview format: " + value); |
| span.textContent = value; |
| return span; |
| } |
| |
| var tag = document.createElement("span"); |
| tag.className = "html-tag"; |
| tag.append("<"); |
| |
| var tagName = tag.appendChild(document.createElement("span")); |
| tagName.className = "html-tag-name"; |
| tagName.textContent = matches[1]; |
| |
| if (matches[2]) { |
| tag.append(" "); |
| var attribute = tag.appendChild(document.createElement("span")); |
| attribute.className = "html-attribute"; |
| var attributeName = attribute.appendChild(document.createElement("span")); |
| attributeName.className = "html-attribute-name"; |
| attributeName.textContent = matches[2]; |
| attribute.append("=\""); |
| var attributeValue = attribute.appendChild(document.createElement("span")); |
| attributeValue.className = "html-attribute-value"; |
| attributeValue.textContent = matches[3]; |
| attribute.append("\""); |
| } |
| |
| tag.append(">"); |
| span.appendChild(tag); |
| |
| return span; |
| }; |
| |
| WI.FormattedValue.createElementForFunctionWithName = function(description) |
| { |
| var span = document.createElement("span"); |
| span.classList.add("formatted-function"); |
| span.textContent = description.substring(0, description.indexOf("(")); |
| return span; |
| }; |
| |
| WI.FormattedValue.createElementForTypesAndValue = function(type, subtype, displayString, size, isPreview, hadException) |
| { |
| var span = document.createElement("span"); |
| span.classList.add(WI.FormattedValue.classNameForTypes(type, subtype)); |
| |
| // Exception. |
| if (hadException) { |
| span.textContent = "[Exception: " + displayString + "]"; |
| return span; |
| } |
| |
| // String: quoted and replace newlines as nice unicode symbols. |
| if (type === "string") { |
| displayString = displayString.truncate(WI.FormattedValue.MAX_PREVIEW_STRING_LENGTH); |
| span.textContent = doubleQuotedString(displayString.replace(/\n/g, "\u21B5")); |
| return span; |
| } |
| |
| // Function: if class, show the description, otherwise elide in previews. |
| if (type === "function") { |
| if (subtype === "class") |
| span.textContent = displayString; |
| else |
| span.textContent = isPreview ? "function" : displayString; |
| return span; |
| } |
| |
| // Everything else, the description/value string. |
| span.textContent = displayString; |
| |
| // If there is a size, include it. |
| if (size !== undefined && (subtype === "array" || subtype === "set" || subtype === "map" || subtype === "weakmap" || subtype === "weakset")) { |
| var sizeElement = span.appendChild(document.createElement("span")); |
| sizeElement.className = "size"; |
| sizeElement.textContent = " (" + size + ")"; |
| } |
| |
| return span; |
| }; |
| |
| WI.FormattedValue.createElementForRemoteObject = function(object, hadException) |
| { |
| return WI.FormattedValue.createElementForTypesAndValue(object.type, object.subtype, object.description, object.size, false, hadException); |
| }; |
| |
| WI.FormattedValue.createElementForObjectPreview = function(objectPreview) |
| { |
| return WI.FormattedValue.createElementForTypesAndValue(objectPreview.type, objectPreview.subtype, objectPreview.description, objectPreview.size, true, false); |
| }; |
| |
| WI.FormattedValue.createElementForPropertyPreview = function(propertyPreview) |
| { |
| return WI.FormattedValue.createElementForTypesAndValue(propertyPreview.type, propertyPreview.subtype, propertyPreview.value, undefined, true, false); |
| }; |
| |
| WI.FormattedValue.createObjectPreviewOrFormattedValueForObjectPreview = function(objectPreview, previewViewMode) |
| { |
| if (objectPreview.subtype === "node") |
| return WI.FormattedValue.createElementForNodePreview(objectPreview); |
| |
| if (objectPreview.type === "function") |
| return WI.FormattedValue.createElementForFunctionWithName(objectPreview.description); |
| |
| const object = null; |
| return new WI.ObjectPreviewView(object, objectPreview, previewViewMode).element; |
| }; |
| |
| WI.FormattedValue.createObjectPreviewOrFormattedValueForRemoteObject = function(object, previewViewMode) |
| { |
| if (object.subtype === "node") |
| return WI.FormattedValue.createElementForNode(object); |
| |
| if (object.subtype === "error") |
| return WI.FormattedValue.createElementForError(object); |
| |
| if (object.preview) |
| return new WI.ObjectPreviewView(object, object.preview, previewViewMode); |
| |
| return WI.FormattedValue.createElementForRemoteObject(object); |
| }; |
| |
| WI.FormattedValue.createObjectTreeOrFormattedValueForRemoteObject = function(object, propertyPath, forceExpanding) |
| { |
| if (object.subtype === "node") |
| return WI.FormattedValue.createElementForNode(object); |
| |
| if (object.subtype === "null") |
| return WI.FormattedValue.createElementForRemoteObject(object); |
| |
| if (object.type === "object" || object.subtype === "class") { |
| var objectTree = new WI.ObjectTreeView(object, null, propertyPath, forceExpanding); |
| return objectTree.element; |
| } |
| |
| return WI.FormattedValue.createElementForRemoteObject(object); |
| }; |
| |
| WI.FormattedValue.MAX_PREVIEW_STRING_LENGTH = 140; |