1 /* 2 * Copyright (C) 2007 Apple Inc. All rights reserved. 3 * Copyright (C) 2009 Joseph Pecoraro 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /** 31 * @constructor 32 * @extends {WebInspector.SidebarPane} 33 */ 34 WebInspector.EventListenersSidebarPane = function() 35 { 36 WebInspector.SidebarPane.call(this, WebInspector.UIString("Event Listeners")); 37 this.bodyElement.addStyleClass("events-pane"); 38 39 this.sections = []; 40 41 this.settingsSelectElement = document.createElement("select"); 42 this.settingsSelectElement.className = "select-filter"; 43 44 var option = document.createElement("option"); 45 option.value = "all"; 46 option.label = WebInspector.UIString("All Nodes"); 47 this.settingsSelectElement.appendChild(option); 48 49 option = document.createElement("option"); 50 option.value = "selected"; 51 option.label = WebInspector.UIString("Selected Node Only"); 52 this.settingsSelectElement.appendChild(option); 53 54 var filter = WebInspector.settings.eventListenersFilter.get(); 55 if (filter === "all") 56 this.settingsSelectElement[0].selected = true; 57 else if (filter === "selected") 58 this.settingsSelectElement[1].selected = true; 59 this.settingsSelectElement.addEventListener("click", function(event) { event.consume() }, false); 60 this.settingsSelectElement.addEventListener("change", this._changeSetting.bind(this), false); 61 62 this.titleElement.appendChild(this.settingsSelectElement); 63 64 this._linkifier = new WebInspector.Linkifier(); 65 } 66 67 WebInspector.EventListenersSidebarPane._objectGroupName = "event-listeners-sidebar-pane"; 68 69 WebInspector.EventListenersSidebarPane.prototype = { 70 update: function(node) 71 { 72 RuntimeAgent.releaseObjectGroup(WebInspector.EventListenersSidebarPane._objectGroupName); 73 this._linkifier.reset(); 74 75 var body = this.bodyElement; 76 body.removeChildren(); 77 this.sections = []; 78 79 var self = this; 80 function callback(error, eventListeners) { 81 if (error) 82 return; 83 84 var selectedNodeOnly = "selected" === WebInspector.settings.eventListenersFilter.get(); 85 var sectionNames = []; 86 var sectionMap = {}; 87 for (var i = 0; i < eventListeners.length; ++i) { 88 var eventListener = eventListeners[i]; 89 if (selectedNodeOnly && (node.id !== eventListener.nodeId)) 90 continue; 91 eventListener.node = WebInspector.domAgent.nodeForId(eventListener.nodeId); 92 delete eventListener.nodeId; // no longer needed 93 if (/^function _inspectorCommandLineAPI_logEvent\(/.test(eventListener.handlerBody.toString())) 94 continue; // ignore event listeners generated by monitorEvent 95 var type = eventListener.type; 96 var section = sectionMap[type]; 97 if (!section) { 98 section = new WebInspector.EventListenersSection(type, node.id, self._linkifier); 99 sectionMap[type] = section; 100 sectionNames.push(type); 101 self.sections.push(section); 102 } 103 section.addListener(eventListener); 104 } 105 106 if (sectionNames.length === 0) { 107 var div = document.createElement("div"); 108 div.className = "info"; 109 div.textContent = WebInspector.UIString("No Event Listeners"); 110 body.appendChild(div); 111 return; 112 } 113 114 sectionNames.sort(); 115 for (var i = 0; i < sectionNames.length; ++i) { 116 var section = sectionMap[sectionNames[i]]; 117 body.appendChild(section.element); 118 } 119 } 120 121 if (node) 122 node.eventListeners(WebInspector.EventListenersSidebarPane._objectGroupName, callback); 123 this._selectedNode = node; 124 }, 125 126 willHide: function() 127 { 128 delete this._selectedNode; 129 }, 130 131 _changeSetting: function() 132 { 133 var selectedOption = this.settingsSelectElement[this.settingsSelectElement.selectedIndex]; 134 WebInspector.settings.eventListenersFilter.set(selectedOption.value); 135 this.update(this._selectedNode); 136 }, 137 138 __proto__: WebInspector.SidebarPane.prototype 139 } 140 141 /** 142 * @constructor 143 * @extends {WebInspector.PropertiesSection} 144 */ 145 WebInspector.EventListenersSection = function(title, nodeId, linkifier) 146 { 147 this.eventListeners = []; 148 this._nodeId = nodeId; 149 this._linkifier = linkifier; 150 WebInspector.PropertiesSection.call(this, title); 151 152 // Changed from a Properties List 153 this.propertiesElement.remove(); 154 delete this.propertiesElement; 155 delete this.propertiesTreeOutline; 156 157 this._eventBars = document.createElement("div"); 158 this._eventBars.className = "event-bars"; 159 this.element.appendChild(this._eventBars); 160 } 161 162 WebInspector.EventListenersSection.prototype = { 163 addListener: function(eventListener) 164 { 165 var eventListenerBar = new WebInspector.EventListenerBar(eventListener, this._nodeId, this._linkifier); 166 this._eventBars.appendChild(eventListenerBar.element); 167 }, 168 169 __proto__: WebInspector.PropertiesSection.prototype 170 } 171 172 /** 173 * @constructor 174 * @extends {WebInspector.ObjectPropertiesSection} 175 */ 176 WebInspector.EventListenerBar = function(eventListener, nodeId, linkifier) 177 { 178 WebInspector.ObjectPropertiesSection.call(this, WebInspector.RemoteObject.fromPrimitiveValue("")); 179 180 this.eventListener = eventListener; 181 this._nodeId = nodeId; 182 this._setNodeTitle(); 183 this._setFunctionSubtitle(linkifier); 184 this.editable = false; 185 this.element.className = "event-bar"; /* Changed from "section" */ 186 this.headerElement.addStyleClass("source-code"); 187 this.propertiesElement.className = "event-properties properties-tree source-code"; /* Changed from "properties" */ 188 } 189 190 WebInspector.EventListenerBar.prototype = { 191 update: function() 192 { 193 function updateWithNodeObject(nodeObject) 194 { 195 var properties = []; 196 197 if (this.eventListener.type) 198 properties.push(WebInspector.RemoteObjectProperty.fromPrimitiveValue("type", this.eventListener.type)); 199 if (typeof this.eventListener.useCapture !== "undefined") 200 properties.push(WebInspector.RemoteObjectProperty.fromPrimitiveValue("useCapture", this.eventListener.useCapture)); 201 if (typeof this.eventListener.isAttribute !== "undefined") 202 properties.push(WebInspector.RemoteObjectProperty.fromPrimitiveValue("isAttribute", this.eventListener.isAttribute)); 203 if (nodeObject) 204 properties.push(new WebInspector.RemoteObjectProperty("node", nodeObject)); 205 if (typeof this.eventListener.handler !== "undefined") { 206 var remoteObject = WebInspector.RemoteObject.fromPayload(this.eventListener.handler); 207 properties.push(new WebInspector.RemoteObjectProperty("handler", remoteObject)); 208 } 209 if (typeof this.eventListener.handlerBody !== "undefined") 210 properties.push(WebInspector.RemoteObjectProperty.fromPrimitiveValue("listenerBody", this.eventListener.handlerBody)); 211 if (this.eventListener.sourceName) 212 properties.push(WebInspector.RemoteObjectProperty.fromPrimitiveValue("sourceName", this.eventListener.sourceName)); 213 if (this.eventListener.location) 214 properties.push(WebInspector.RemoteObjectProperty.fromPrimitiveValue("lineNumber", this.eventListener.location.lineNumber + 1)); 215 216 this.updateProperties(properties); 217 } 218 WebInspector.RemoteObject.resolveNode(this.eventListener.node, WebInspector.EventListenersSidebarPane._objectGroupName, updateWithNodeObject.bind(this)); 219 }, 220 221 _setNodeTitle: function() 222 { 223 var node = this.eventListener.node; 224 if (!node) 225 return; 226 227 if (node.nodeType() === Node.DOCUMENT_NODE) { 228 this.titleElement.textContent = "document"; 229 return; 230 } 231 232 if (node.id === this._nodeId) { 233 this.titleElement.textContent = node.appropriateSelectorFor(); 234 return; 235 } 236 237 this.titleElement.removeChildren(); 238 this.titleElement.appendChild(WebInspector.DOMPresentationUtils.linkifyNodeReference(this.eventListener.node)); 239 }, 240 241 _setFunctionSubtitle: function(linkifier) 242 { 243 // Requires that Function.toString() return at least the function's signature. 244 if (this.eventListener.location) { 245 this.subtitleElement.removeChildren(); 246 var urlElement; 247 if (this.eventListener.location.scriptId) 248 urlElement = linkifier.linkifyRawLocation(this.eventListener.location); 249 if (!urlElement) { 250 var url = this.eventListener.sourceName; 251 var lineNumber = this.eventListener.location.lineNumber; 252 var columnNumber = 0; 253 urlElement = linkifier.linkifyLocation(url, lineNumber, columnNumber); 254 } 255 this.subtitleElement.appendChild(urlElement); 256 } else { 257 var match = this.eventListener.handlerBody.match(/function ([^\(]+?)\(/); 258 if (match) 259 this.subtitleElement.textContent = match[1]; 260 else 261 this.subtitleElement.textContent = WebInspector.UIString("(anonymous function)"); 262 } 263 }, 264 265 __proto__: WebInspector.ObjectPropertiesSection.prototype 266 } 267