0351a1b9f6814c57d4df315f4ee61eefe432334c
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / TypeTokenView.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.TypeTokenView = function(tokenAnnotator, shouldHaveRightMargin, shouldHaveLeftMargin, titleType, functionOrVariableName)
27 {
28     console.assert(titleType === WebInspector.TypeTokenView.TitleType.Variable  || titleType === WebInspector.TypeTokenView.TitleType.ReturnStatement);
29
30     WebInspector.Object.call(this);
31
32     var span = document.createElement("span");
33     span.classList.add("type-token");
34     if (shouldHaveRightMargin)
35         span.classList.add("type-token-right-spacing");
36     if (shouldHaveLeftMargin)
37         span.classList.add("type-token-left-spacing");
38
39     this.element = span;
40     this._tokenAnnotator = tokenAnnotator;
41     this._types = null;
42     this._colorClass = null;
43
44     this._popoverTitle = WebInspector.TypeTokenView.titleForPopover(titleType, functionOrVariableName);
45
46     this._setUpMouseoverHandlers();
47 };
48
49 WebInspector.TypeTokenView.titleForPopover = function(titleType, functionOrVariableName)
50 {
51     var titleString = null;
52     if (titleType === WebInspector.TypeTokenView.TitleType.Variable)
53         titleString = WebInspector.UIString("Type information for variable: %s").format(functionOrVariableName);
54     else {
55         if (functionOrVariableName)
56             titleString = WebInspector.UIString("Return type for function: %s").format(functionOrVariableName);
57         else
58             titleString = WebInspector.UIString("Return type for anonymous function");
59     }
60
61     return titleString;
62 };
63
64 WebInspector.TypeTokenView.TitleType = {
65     Variable: "title-type-variable",
66     ReturnStatement: "title-type-return-statement"
67 };
68
69 WebInspector.TypeTokenView.ColorClassForType = {
70     "String": "type-token-string",
71     "Function": "type-token-function",
72     "Number": "type-token-number",
73     "Integer": "type-token-number",
74     "Undefined": "type-token-empty",
75     "Null": "type-token-empty",
76     "(?)": "type-token-empty",
77     "Boolean": "type-token-boolean",
78     "(many)": "type-token-many"
79 };
80
81 WebInspector.TypeTokenView.DelayHoverTime = 350;
82
83 WebInspector.TypeTokenView.prototype = {
84     constructor: WebInspector.TypeTokenView,
85     __proto__: WebInspector.Object.prototype,
86
87     // Public
88
89     update: function(types)
90     {
91         this._types = types;
92
93         var title = this._displayTypeName();
94         this.element.textContent = title;
95         var hashString = title[title.length - 1] === "?" ? title.slice(0, title.length - 1) : title;
96
97         if (this._colorClass)
98             this.element.classList.remove(this._colorClass);
99
100         this._colorClass = WebInspector.TypeTokenView.ColorClassForType[hashString] || "type-token-default";
101         this.element.classList.add(this._colorClass);
102     },
103
104     // Private
105
106     _setUpMouseoverHandlers: function()
107     {
108         var timeoutID = null;
109
110         this.element.addEventListener("mouseover", function() {
111             function showPopoverAfterDelay()
112             {
113                 timeoutID = null;
114
115                 var domRect = this.element.getBoundingClientRect();
116                 var bounds = new WebInspector.Rect(domRect.left, domRect.top, domRect.width, domRect.height);
117                 this._tokenAnnotator.sourceCodeTextEditor.showPopoverForTypes(this._types, bounds, this._popoverTitle);
118             }
119
120             if (this._shouldShowPopover())
121                 timeoutID = setTimeout(showPopoverAfterDelay.bind(this), WebInspector.TypeTokenView.DelayHoverTime);
122         }.bind(this));
123
124         this.element.addEventListener("mouseout", function() {
125             if (timeoutID)
126                 clearTimeout(timeoutID);
127         }.bind(this));
128     },
129
130     _shouldShowPopover: function()
131     {
132         if (this._types.primitiveTypeNames && this._types.primitiveTypeNames.length > 1)
133             return true;
134
135         if (this._types.structures && this._types.structures.length)
136             return true;
137
138         return false;
139     },
140
141     _displayTypeName: function()
142     {
143         var typeSet = WebInspector.TypeSet.fromPayload(this._types);
144
145         if (this._types.leastCommonAncestor && !(this._types.primitiveTypeNames && this._types.primitiveTypeNames.length)) {
146             if (typeSet.isContainedIn(WebInspector.TypeSet.TypeBit.Object))
147                 return this._types.leastCommonAncestor;
148             if (typeSet.isContainedIn(WebInspector.TypeSet.TypeBit.Object | WebInspector.TypeSet.NullOrUndefinedTypeBits))
149                 return this._types.leastCommonAncestor + "?";
150         }
151
152         // The order of these checks are important. 
153         // For example, if a value is only a function, it is contained in TypeFunction, but it is also contained in (TypeFunction | TypeNull).
154         // Therefore, more specific types must be checked first.
155
156         // The strings returned here should match those in TypeTokenView.ColorClassForType
157         if (typeSet.isContainedIn(WebInspector.TypeSet.TypeBit.Function))
158             return "Function";
159         if (typeSet.isContainedIn(WebInspector.TypeSet.TypeBit.Undefined))
160             return "Undefined";
161         if (typeSet.isContainedIn(WebInspector.TypeSet.TypeBit.Null))
162             return "Null";
163         if (typeSet.isContainedIn(WebInspector.TypeSet.TypeBit.Boolean))
164             return "Boolean";
165         if (typeSet.isContainedIn(WebInspector.TypeSet.TypeBit.Integer))
166             return "Integer";
167         if (typeSet.isContainedIn(WebInspector.TypeSet.TypeBit.Number | WebInspector.TypeSet.TypeBit.Integer))
168             return "Number";
169         if (typeSet.isContainedIn(WebInspector.TypeSet.TypeBit.String))
170             return "String";
171
172         if (typeSet.isContainedIn(WebInspector.TypeSet.NullOrUndefinedTypeBits))
173             return "(?)";
174
175         if (typeSet.isContainedIn(WebInspector.TypeSet.TypeBit.Function | WebInspector.TypeSet.NullOrUndefinedTypeBits))
176             return "Function?";
177         if (typeSet.isContainedIn(WebInspector.TypeSet.TypeBit.Boolean | WebInspector.TypeSet.NullOrUndefinedTypeBits))
178             return "Boolean?";
179         if (typeSet.isContainedIn(WebInspector.TypeSet.TypeBit.Integer | WebInspector.TypeSet.NullOrUndefinedTypeBits))
180             return "Integer?";
181         if (typeSet.isContainedIn(WebInspector.TypeSet.TypeBit.Number | WebInspector.TypeSet.TypeBit.Integer | WebInspector.TypeSet.NullOrUndefinedTypeBits))
182             return "Number?";
183         if (typeSet.isContainedIn(WebInspector.TypeSet.TypeBit.String | WebInspector.TypeSet.NullOrUndefinedTypeBits))
184             return "String?";
185        
186         if (typeSet.isContainedIn(WebInspector.TypeSet.TypeBit.Object | WebInspector.TypeSet.TypeBit.Function | WebInspector.TypeSet.TypeBit.String))
187             return "Object";
188         if (typeSet.isContainedIn(WebInspector.TypeSet.TypeBit.Object | WebInspector.TypeSet.TypeBit.Function | WebInspector.TypeSet.TypeBit.String | WebInspector.TypeSet.NullOrUndefinedTypeBits))
189             return "Object?";
190
191         return WebInspector.UIString("(many)");
192     }
193 };