53a5029eae64eda06725ae023072b5c618317423
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / TypePropertiesSection.js
1 /*
2  * Copyright (C) 2014 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.TypePropertiesSection = function(types, title, subtitle)
27 {
28     this.emptyPlaceholder = WebInspector.UIString("No Properties");
29     this.types = types;
30     this._typeSet = WebInspector.TypeSet.fromPayload(this.types);
31
32     WebInspector.PropertiesSection.call(this, title, subtitle);
33 };
34
35 WebInspector.TypePropertiesSection.prototype = {
36     constructor: WebInspector.TypePropertiesSection,
37     __proto__: WebInspector.PropertiesSection.prototype,
38
39     onpopulate: function()
40     {
41         this.propertiesTreeOutline.removeChildren();
42
43         var primitiveTypeNames = this._typeSet.primitiveTypeNames;
44         var structures = this.types.structures;
45         var properties = [];
46         for (var struct of structures) {
47             properties.push({
48                 name: struct.constructorName,
49                 structure: struct
50             });
51         }
52         for (var primitiveName of primitiveTypeNames) {
53             properties.push({
54                 name: primitiveName,
55                 structure: null
56             });
57         }
58
59         properties.sort(WebInspector.TypePropertiesSection.PropertyComparator);
60
61         if (this.types.isTruncated)
62             properties.push({name: "\u2026", structure: null});
63
64         for (var property of properties)
65             this.propertiesTreeOutline.appendChild(new WebInspector.TypePropertyTreeElement(property));
66
67         if (!this.propertiesTreeOutline.children.length) {
68             var title = document.createElement("div");
69             title.className = "info";
70             title.textContent = this.emptyPlaceholder;
71             var infoElement = new TreeElement(title, null, false);
72             this.propertiesTreeOutline.appendChild(infoElement);
73         }
74
75         this.dispatchEventToListeners(WebInspector.Section.Event.VisibleContentDidChange);
76
77         if (properties.length === 1)
78             this.propertiesTreeOutline.children[0].expandRecursively();
79     }
80 };
81
82 // This is mostly identical to ObjectPropertiesSection.compareProperties.
83 // But this checks for equality because we can have two objects named the same thing.
84 WebInspector.TypePropertiesSection.PropertyComparator = function(propertyA, propertyB)
85 {
86     var a = propertyA.name;
87     var b = propertyB.name;
88     if (a.indexOf("__proto__") !== -1)
89         return 1;
90     if (b.indexOf("__proto__") !== -1)
91         return -1;
92     if (a === b)
93         return 1;
94
95     var diff = 0;
96     var chunk = /^\d+|^\D+/;
97     var chunka, chunkb, anum, bnum;
98     while (diff === 0) {
99         if (!a && b)
100             return -1;
101         if (!b && a)
102             return 1;
103         chunka = a.match(chunk)[0];
104         chunkb = b.match(chunk)[0];
105         anum = !isNaN(chunka);
106         bnum = !isNaN(chunkb);
107         if (anum && !bnum)
108             return -1;
109         if (bnum && !anum)
110             return 1;
111         if (anum && bnum) {
112             diff = chunka - chunkb;
113             if (diff === 0 && chunka.length !== chunkb.length) {
114                 if (!+chunka && !+chunkb) // chunks are strings of all 0s (special case)
115                     return chunka.length - chunkb.length;
116                 else
117                     return chunkb.length - chunka.length;
118             }
119         } else if (chunka !== chunkb)
120             return (chunka < chunkb) ? -1 : 1;
121         a = a.substring(chunka.length);
122         b = b.substring(chunkb.length);
123     }
124
125     return diff;
126 };
127
128 WebInspector.TypePropertyTreeElement = function(property)
129 {
130     this.property = property;
131
132     this.nameElement = document.createElement("span");
133     this.nameElement.className = "name";
134     this.nameElement.textContent = this.property.name;
135
136     TreeElement.call(this, this.nameElement, null, false);
137
138     this.toggleOnClick = true;
139     this.hasChildren = !!this.property.structure;
140 };
141
142 WebInspector.TypePropertyTreeElement.prototype = {
143     constructor: WebInspector.TypePropertyTreeElement,
144     __proto__: TreeElement.prototype,
145
146     onpopulate: function()
147     {
148         this.removeChildren();
149
150         var properties = [];
151         for (var fieldName of this.property.structure.fields) {
152             properties.push({
153                 name: fieldName,
154                 structure: null
155             });
156         }
157
158         properties.sort(WebInspector.TypePropertiesSection.PropertyComparator);
159
160         for (var property of properties)
161             this.appendChild(new WebInspector.TypePropertyTreeElement(property));
162
163         properties = [];
164         for (var fieldName of this.property.structure.optionalFields) {
165             properties.push({
166                 name: fieldName + "?",
167                 structure: null
168             });
169         }
170
171         properties.sort(WebInspector.TypePropertiesSection.PropertyComparator);
172
173         if (this.property.structure.isImprecise)
174             properties.push({name: "\u2026", structure: null});
175
176         if (this.property.structure.prototypeStructure) {
177             properties.push({
178                 name: this.property.structure.prototypeStructure.constructorName + " (" + WebInspector.UIString("Prototype") + ")",
179                 structure: this.property.structure.prototypeStructure
180             });
181         }
182
183         for (var property of properties)
184             this.appendChild(new WebInspector.TypePropertyTreeElement(property));
185     }
186 };
187