1 /* 2 * Copyright (C) 2011 Google 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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 /** 32 * @constructor 33 * @extends {WebInspector.PopoverHelper} 34 * @param {!Element} panelElement 35 * @param {function(!Element, !Event):!Element|undefined} getAnchor 36 * @param {function(!Element, function(!WebInspector.RemoteObject, boolean, !Element=):undefined, string):undefined} queryObject 37 * @param {function()=} onHide 38 * @param {boolean=} disableOnClick 39 */ 40 WebInspector.ObjectPopoverHelper = function(panelElement, getAnchor, queryObject, onHide, disableOnClick) 41 { 42 WebInspector.PopoverHelper.call(this, panelElement, getAnchor, this._showObjectPopover.bind(this), this._onHideObjectPopover.bind(this), disableOnClick); 43 this._queryObject = queryObject; 44 this._onHideCallback = onHide; 45 this._popoverObjectGroup = "popover"; 46 panelElement.addEventListener("scroll", this.hidePopover.bind(this), true); 47 }; 48 49 WebInspector.ObjectPopoverHelper.prototype = { 50 /** 51 * @param {function(!WebInspector.RemoteObject):string} formatter 52 */ 53 setRemoteObjectFormatter: function(formatter) 54 { 55 this._remoteObjectFormatter = formatter; 56 }, 57 58 /** 59 * @param {!Element} element 60 * @param {!WebInspector.Popover} popover 61 */ 62 _showObjectPopover: function(element, popover) 63 { 64 /** 65 * @param {!WebInspector.Target} target 66 * @param {!Element} anchorElement 67 * @param {!Element} popoverContentElement 68 * @param {?DebuggerAgent.FunctionDetails} response 69 * @this {WebInspector.ObjectPopoverHelper} 70 */ 71 function didGetDetails(target, anchorElement, popoverContentElement, response) 72 { 73 if (!response) 74 return; 75 76 var container = document.createElement("div"); 77 container.className = "inline-block"; 78 79 var title = container.createChild("div", "function-popover-title source-code"); 80 var functionName = title.createChild("span", "function-name"); 81 functionName.textContent = response.functionName || WebInspector.UIString("(anonymous function)"); 82 83 this._linkifier = new WebInspector.Linkifier(); 84 var rawLocation = WebInspector.DebuggerModel.Location.fromPayload(target, response.location); 85 var link = this._linkifier.linkifyRawLocation(rawLocation, "function-location-link"); 86 if (link) 87 title.appendChild(link); 88 89 container.appendChild(popoverContentElement); 90 91 popover.show(container, anchorElement); 92 } 93 94 /** 95 * @param {!WebInspector.RemoteObject} result 96 * @param {boolean} wasThrown 97 * @param {!Element=} anchorOverride 98 * @this {WebInspector.ObjectPopoverHelper} 99 */ 100 function showObjectPopover(result, wasThrown, anchorOverride) 101 { 102 if (popover.disposed) 103 return; 104 if (wasThrown) { 105 this.hidePopover(); 106 return; 107 } 108 109 var anchorElement = anchorOverride || element; 110 var description = (this._remoteObjectFormatter && this._remoteObjectFormatter(result)) || result.description; 111 112 var popoverContentElement = null; 113 if (result.type !== "object") { 114 popoverContentElement = document.createElement("span"); 115 popoverContentElement.className = "monospace console-formatted-" + result.type; 116 popoverContentElement.style.whiteSpace = "pre"; 117 popoverContentElement.textContent = description; 118 if (result.type === "function") { 119 result.functionDetails(didGetDetails.bind(this, result.target(), anchorElement, popoverContentElement)); 120 return; 121 } 122 if (result.type === "string") 123 popoverContentElement.textContent = "\"" + popoverContentElement.textContent + "\""; 124 popover.show(popoverContentElement, anchorElement); 125 } else { 126 if (result.subtype === "node") { 127 result.highlightAsDOMNode(); 128 this._resultHighlightedAsDOM = result; 129 } 130 popoverContentElement = document.createElement("div"); 131 this._titleElement = document.createElement("div"); 132 this._titleElement.className = "source-frame-popover-title monospace"; 133 this._titleElement.textContent = description; 134 popoverContentElement.appendChild(this._titleElement); 135 136 var section = new WebInspector.ObjectPropertiesSection(result); 137 // For HTML DOM wrappers, append "#id" to title, if not empty. 138 if (description.substr(0, 4) === "HTML") { 139 this._sectionUpdateProperties = section.updateProperties.bind(section); 140 section.updateProperties = this._updateHTMLId.bind(this); 141 } 142 section.expanded = true; 143 section.element.classList.add("source-frame-popover-tree"); 144 section.headerElement.classList.add("hidden"); 145 popoverContentElement.appendChild(section.element); 146 147 const popoverWidth = 300; 148 const popoverHeight = 250; 149 popover.show(popoverContentElement, anchorElement, popoverWidth, popoverHeight); 150 } 151 } 152 this._queryObject(element, showObjectPopover.bind(this), this._popoverObjectGroup); 153 }, 154 155 _onHideObjectPopover: function() 156 { 157 if (this._resultHighlightedAsDOM) { 158 this._resultHighlightedAsDOM.target().domModel.hideDOMNodeHighlight(); 159 delete this._resultHighlightedAsDOM; 160 } 161 if (this._linkifier) { 162 this._linkifier.reset(); 163 delete this._linkifier; 164 } 165 if (this._onHideCallback) 166 this._onHideCallback(); 167 RuntimeAgent.releaseObjectGroup(this._popoverObjectGroup); 168 }, 169 170 _updateHTMLId: function(properties, rootTreeElementConstructor, rootPropertyComparer) 171 { 172 for (var i = 0; i < properties.length; ++i) { 173 if (properties[i].name === "id") { 174 if (properties[i].value.description) 175 this._titleElement.textContent += "#" + properties[i].value.description; 176 break; 177 } 178 } 179 this._sectionUpdateProperties(properties, rootTreeElementConstructor, rootPropertyComparer); 180 }, 181 182 __proto__: WebInspector.PopoverHelper.prototype 183 } 184