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 {!Element} anchorElement 66 * @param {!Element} popoverContentElement 67 * @param {?Protocol.Error} error 68 * @param {!DebuggerAgent.FunctionDetails} response 69 * @this {WebInspector.ObjectPopoverHelper} 70 */ 71 function didGetDetails(anchorElement, popoverContentElement, error, response) 72 { 73 if (error) { 74 console.error(error); 75 return; 76 } 77 var container = document.createElement("div"); 78 container.className = "inline-block"; 79 80 var title = container.createChild("div", "function-popover-title source-code"); 81 var functionName = title.createChild("span", "function-name"); 82 functionName.textContent = response.functionName || WebInspector.UIString("(anonymous function)"); 83 84 this._linkifier = new WebInspector.Linkifier(); 85 var rawLocation = /** @type {!WebInspector.DebuggerModel.Location} */ (response.location); 86 var link = this._linkifier.linkifyRawLocation(rawLocation, "function-location-link"); 87 if (link) 88 title.appendChild(link); 89 90 container.appendChild(popoverContentElement); 91 92 popover.show(container, anchorElement); 93 } 94 95 /** 96 * @param {!WebInspector.RemoteObject} result 97 * @param {boolean} wasThrown 98 * @param {!Element=} anchorOverride 99 * @this {WebInspector.ObjectPopoverHelper} 100 */ 101 function showObjectPopover(result, wasThrown, anchorOverride) 102 { 103 if (popover.disposed) 104 return; 105 if (wasThrown) { 106 this.hidePopover(); 107 return; 108 } 109 110 var anchorElement = anchorOverride || element; 111 var description = (this._remoteObjectFormatter && this._remoteObjectFormatter(result)) || result.description; 112 113 var popoverContentElement = null; 114 if (result.type !== "object") { 115 popoverContentElement = document.createElement("span"); 116 popoverContentElement.className = "monospace console-formatted-" + result.type; 117 popoverContentElement.style.whiteSpace = "pre"; 118 popoverContentElement.textContent = description; 119 if (result.type === "function") { 120 DebuggerAgent.getFunctionDetails(result.objectId, didGetDetails.bind(this, anchorElement, popoverContentElement)); 121 return; 122 } 123 if (result.type === "string") 124 popoverContentElement.textContent = "\"" + popoverContentElement.textContent + "\""; 125 popover.show(popoverContentElement, anchorElement); 126 } else { 127 if (result.subtype === "node") 128 result.highlightAsDOMNode(); 129 popoverContentElement = document.createElement("div"); 130 this._titleElement = document.createElement("div"); 131 this._titleElement.className = "source-frame-popover-title monospace"; 132 this._titleElement.textContent = description; 133 popoverContentElement.appendChild(this._titleElement); 134 135 var section = new WebInspector.ObjectPropertiesSection(result); 136 // For HTML DOM wrappers, append "#id" to title, if not empty. 137 if (description.substr(0, 4) === "HTML") { 138 this._sectionUpdateProperties = section.updateProperties.bind(section); 139 section.updateProperties = this._updateHTMLId.bind(this); 140 } 141 section.expanded = true; 142 section.element.classList.add("source-frame-popover-tree"); 143 section.headerElement.classList.add("hidden"); 144 popoverContentElement.appendChild(section.element); 145 146 const popoverWidth = 300; 147 const popoverHeight = 250; 148 popover.show(popoverContentElement, anchorElement, popoverWidth, popoverHeight); 149 } 150 } 151 this._queryObject(element, showObjectPopover.bind(this), this._popoverObjectGroup); 152 }, 153 154 _onHideObjectPopover: function() 155 { 156 WebInspector.domAgent.hideDOMNodeHighlight(); 157 if (this._linkifier) { 158 this._linkifier.reset(); 159 delete this._linkifier; 160 } 161 if (this._onHideCallback) 162 this._onHideCallback(); 163 RuntimeAgent.releaseObjectGroup(this._popoverObjectGroup); 164 }, 165 166 _updateHTMLId: function(properties, rootTreeElementConstructor, rootPropertyComparer) 167 { 168 for (var i = 0; i < properties.length; ++i) { 169 if (properties[i].name === "id") { 170 if (properties[i].value.description) 171 this._titleElement.textContent += "#" + properties[i].value.description; 172 break; 173 } 174 } 175 this._sectionUpdateProperties(properties, rootTreeElementConstructor, rootPropertyComparer); 176 }, 177 178 __proto__: WebInspector.PopoverHelper.prototype 179 } 180