Web Inspector: Create Separate Model and View Objects for RemoteObjects / ObjectPrevi...
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / ObjectPreviewView.js
1 /*
2  * Copyright (C) 2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 WebInspector.ObjectPreviewView = function(preview, mode)
27 {
28     WebInspector.Object.call(this);
29
30     console.assert(preview instanceof WebInspector.ObjectPreview);
31
32     this._preview = preview;
33     this._mode = mode || WebInspector.ObjectPreviewView.Mode.Full;
34
35     this._element = document.createElement("span");
36     this._element.className = "object-preview";
37     this._lossless = this._appendPreview(this._element, this._preview);
38
39     if (this._lossless)
40         this._element.classList.add("lossless");
41 };
42
43 WebInspector.ObjectPreviewView.Mode = {
44     Brief: Symbol("object-preview-brief"),
45     Full: Symbol("object-preview-full"),
46 };
47
48 WebInspector.ObjectPreviewView.prototype = {
49     constructor: WebInspector.ObjectPreviewView,
50     __proto__: WebInspector.Object,
51
52     // Public
53
54     get preview()
55     {
56         return this._preview;
57     },
58
59     get element()
60     {
61         return this._element;
62     },
63
64     get mode()
65     {
66         return this._mode;
67     },
68
69     get lossless()
70     {
71         return this._lossless;
72     },
73
74     // Private
75
76     _numberOfPropertiesToShowInMode: function()
77     {
78         return this._mode === WebInspector.ObjectPreviewView.Mode.Brief ? 3 : Infinity;
79     },
80
81     _appendPreview: function(element, preview)
82     {
83         // Class name for non-array object types.
84         if (preview.type === "object" && preview.subtype !== "null" && preview.subtype !== "array" && preview.description !== "Object") {
85             var nameElement = element.appendChild(document.createElement("span"));
86             nameElement.className = "object-preview-name";
87             nameElement.textContent = preview.description + " ";
88         }
89
90         // Content.
91         var bodyElement = element.appendChild(document.createElement("span"));
92         bodyElement.className = "object-preview-body";
93         if (preview.collectionEntryPreviews)
94             return this._appendEntryPreviews(bodyElement, preview);
95         if (preview.propertyPreviews)
96             return this._appendPropertyPreviews(bodyElement, preview);
97         return this._appendValuePreview(bodyElement, preview);
98     },
99
100     _appendEntryPreviews: function(element, preview)
101     {
102         var lossless = preview.lossless && !preview.propertyPreviews.length;
103
104         element.appendChild(document.createTextNode("{"));
105
106         var limit = Math.min(preview.collectionEntryPreviews.length, this._numberOfPropertiesToShowInMode());
107         for (var i = 0; i < limit; ++i) {
108             if (i > 0)
109                 element.appendChild(document.createTextNode(", "));
110
111             var entry = preview.collectionEntryPreviews[i];
112             if (entry.keyPreview) {
113                 this._appendPreview(element, entry.keyPreview);
114                 element.appendChild(document.createTextNode(" => "));
115             }
116
117             this._appendPreview(element, entry.valuePreview);
118         }
119
120         if (preview.overflow)
121             element.appendChild(document.createTextNode("\u2026"));
122         element.appendChild(document.createTextNode("}"));
123
124         return lossless;
125     },
126
127     _appendPropertyPreviews: function(element, preview)
128     {
129         var isArray = preview.subtype === "array";
130
131         element.appendChild(document.createTextNode(isArray ? "[" : "{"));
132
133         var numberAdded = 0;
134         var limit = this._numberOfPropertiesToShowInMode();
135         for (var i = 0; i < preview.propertyPreviews.length && numberAdded < limit; ++i) {
136             var property = preview.propertyPreviews[i];
137
138             // FIXME: Better handle getter/setter accessors. Should we show getters in previews?
139             if (property.type === "accessor")
140                 continue;
141
142             // Constructor name is often already visible, so don't show it as a property.
143             if (property.name === "constructor")
144                 continue;
145
146             if (numberAdded++ > 0)
147                 element.appendChild(document.createTextNode(", "));
148
149             if (!isArray || property.name != i) {
150                 var nameElement = element.appendChild(document.createElement("span"));
151                 nameElement.className = "name";
152                 nameElement.textContent = property.name;
153                 element.appendChild(document.createTextNode(": "));
154             }
155
156             element.appendChild(this._formattedObjectElementForPreview(property, property.value));
157         }
158
159         if (preview.overflow)
160             element.appendChild(document.createTextNode("\u2026"));
161
162         element.appendChild(document.createTextNode(isArray ? "]" : "}"));
163
164         return preview.lossless;
165     },
166
167     _appendValuePreview: function(element, preview)
168     {
169         element.appendChild(this._formattedObjectElementForPreview(preview, preview.description));
170         return true;
171     },
172
173     _formattedObjectElementForPreview: function(propertyPreviewOrObjectPreview, value)
174     {
175         var span = document.createElement("span");
176         span.classList.add(WebInspector.ObjectTreeView.classNameForObject(propertyPreviewOrObjectPreview));
177
178         if (propertyPreviewOrObjectPreview.type === "string") {
179             span.textContent = "\"" + value.replace(/\n/g, "\u21B5").replace(/"/g, "\\\"") + "\"";
180             return span;
181         }
182
183         if (propertyPreviewOrObjectPreview.type === "function") {
184             span.textContent = "function";
185             return span;
186         }
187
188         span.textContent = value;
189         return span;
190     }
191 };