/* * Copyright (C) 2014-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.TypeTokenView = class TypeTokenView extends WI.Object { constructor(tokenAnnotator, shouldHaveRightMargin, shouldHaveLeftMargin, titleType, functionOrVariableName) { console.assert(titleType === WI.TypeTokenView.TitleType.Variable || titleType === WI.TypeTokenView.TitleType.ReturnStatement); super(); var span = document.createElement("span"); span.classList.add("type-token"); if (shouldHaveRightMargin) span.classList.add("type-token-right-spacing"); if (shouldHaveLeftMargin) span.classList.add("type-token-left-spacing"); this.element = span; this._tokenAnnotator = tokenAnnotator; this._typeDescription = null; this._colorClass = null; this._popoverTitle = WI.TypeTokenView.titleForPopover(titleType, functionOrVariableName); this._setUpMouseoverHandlers(); } // Static static titleForPopover(titleType, functionOrVariableName) { if (titleType === WI.TypeTokenView.TitleType.Variable) return WI.UIString("Type information for variable: %s").format(functionOrVariableName); if (functionOrVariableName) return WI.UIString("Return type for function: %s").format(functionOrVariableName); return WI.UIString("Return type for anonymous function"); } // Public update(typeDescription) { console.assert(typeDescription instanceof WI.TypeDescription); this._typeDescription = typeDescription; var title = this._displayTypeName(); if (title === this.element.textContent) return; this.element.textContent = title; var hashString = title[title.length - 1] === "?" ? title.slice(0, title.length - 1) : title; if (this._colorClass) this.element.classList.remove(this._colorClass); this._colorClass = WI.TypeTokenView.ColorClassForType[hashString] || "type-token-default"; this.element.classList.add(this._colorClass); } // Private _setUpMouseoverHandlers() { var timeoutID = null; this.element.addEventListener("mouseover", function() { function showPopoverAfterDelay() { timeoutID = null; var domRect = this.element.getBoundingClientRect(); var bounds = new WI.Rect(domRect.left, domRect.top, domRect.width, domRect.height); this._tokenAnnotator.sourceCodeTextEditor.showPopoverForTypes(this._typeDescription, bounds, this._popoverTitle); } if (this._shouldShowPopover()) timeoutID = setTimeout(showPopoverAfterDelay.bind(this), WI.TypeTokenView.DelayHoverTime); }.bind(this)); this.element.addEventListener("mouseout", function() { if (timeoutID) clearTimeout(timeoutID); }); } _shouldShowPopover() { if (!this._typeDescription.valid) return false; if (this._typeDescription.typeSet.primitiveTypeNames.length > 1) return true; if (this._typeDescription.structures && this._typeDescription.structures.length) return true; return false; } _displayTypeName() { if (!this._typeDescription.valid) return ""; var typeSet = this._typeDescription.typeSet; if (this._typeDescription.leastCommonAncestor) { if (typeSet.isContainedIn(WI.TypeSet.TypeBit.Object)) return this._typeDescription.leastCommonAncestor; if (typeSet.isContainedIn(WI.TypeSet.TypeBit.Object | WI.TypeSet.NullOrUndefinedTypeBits)) return this._typeDescription.leastCommonAncestor + "?"; } // The order of these checks are important. // For example, if a value is only a function, it is contained in TypeFunction, but it is also contained in (TypeFunction | TypeNull). // Therefore, more specific types must be checked first. // The strings returned here should match those in TypeTokenView.ColorClassForType if (typeSet.isContainedIn(WI.TypeSet.TypeBit.Function)) return "Function"; if (typeSet.isContainedIn(WI.TypeSet.TypeBit.Undefined)) return "Undefined"; if (typeSet.isContainedIn(WI.TypeSet.TypeBit.Null)) return "Null"; if (typeSet.isContainedIn(WI.TypeSet.TypeBit.Boolean)) return "Boolean"; if (typeSet.isContainedIn(WI.TypeSet.TypeBit.Integer)) return "Integer"; if (typeSet.isContainedIn(WI.TypeSet.TypeBit.Number | WI.TypeSet.TypeBit.Integer)) return "Number"; if (typeSet.isContainedIn(WI.TypeSet.TypeBit.String)) return "String"; if (typeSet.isContainedIn(WI.TypeSet.TypeBit.Symbol)) return "Symbol"; if (typeSet.isContainedIn(WI.TypeSet.NullOrUndefinedTypeBits)) return "(?)"; if (typeSet.isContainedIn(WI.TypeSet.TypeBit.Function | WI.TypeSet.NullOrUndefinedTypeBits)) return "Function?"; if (typeSet.isContainedIn(WI.TypeSet.TypeBit.Boolean | WI.TypeSet.NullOrUndefinedTypeBits)) return "Boolean?"; if (typeSet.isContainedIn(WI.TypeSet.TypeBit.Integer | WI.TypeSet.NullOrUndefinedTypeBits)) return "Integer?"; if (typeSet.isContainedIn(WI.TypeSet.TypeBit.Number | WI.TypeSet.TypeBit.Integer | WI.TypeSet.NullOrUndefinedTypeBits)) return "Number?"; if (typeSet.isContainedIn(WI.TypeSet.TypeBit.String | WI.TypeSet.NullOrUndefinedTypeBits)) return "String?"; if (typeSet.isContainedIn(WI.TypeSet.TypeBit.Symbol | WI.TypeSet.NullOrUndefinedTypeBits)) return "Symbol?"; if (typeSet.isContainedIn(WI.TypeSet.TypeBit.Object | WI.TypeSet.TypeBit.Function | WI.TypeSet.TypeBit.String)) return "Object"; if (typeSet.isContainedIn(WI.TypeSet.TypeBit.Object | WI.TypeSet.TypeBit.Function | WI.TypeSet.TypeBit.String | WI.TypeSet.NullOrUndefinedTypeBits)) return "Object?"; return WI.UIString("(many)"); } }; WI.TypeTokenView.TitleType = { Variable: Symbol("title-type-variable"), ReturnStatement: Symbol("title-type-return-statement") }; WI.TypeTokenView.ColorClassForType = { "String": "type-token-string", "Symbol": "type-token-symbol", "Function": "type-token-function", "Number": "type-token-number", "Integer": "type-token-number", "Undefined": "type-token-empty", "Null": "type-token-empty", "(?)": "type-token-empty", "Boolean": "type-token-boolean", "(many)": "type-token-many" }; WI.TypeTokenView.DelayHoverTime = 350;