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.classList.add("events-pane"); 38 39 this.sections = []; 40 41 var refreshButton = this.titleElement.createChild("button", "pane-title-button refresh"); 42 refreshButton.addEventListener("click", this._refreshButtonClicked.bind(this), false); 43 refreshButton.title = WebInspector.UIString("Refresh"); 44 45 this.settingsSelectElement = this.titleElement.createChild("select", "select-filter"); 46 47 var option = this.settingsSelectElement.createChild("option"); 48 option.value = "all"; 49 option.label = WebInspector.UIString("All Nodes"); 50 51 option = this.settingsSelectElement.createChild("option"); 52 option.value = "selected"; 53 option.label = WebInspector.UIString("Selected Node Only"); 54 55 var filter = WebInspector.settings.eventListenersFilter.get(); 56 if (filter === "all") 57 this.settingsSelectElement[0].selected = true; 58 else if (filter === "selected") 59 this.settingsSelectElement[1].selected = true; 60 this.settingsSelectElement.addEventListener("click", consumeEvent, false); 61 this.settingsSelectElement.addEventListener("change", this._changeSetting.bind(this), false); 62 63 this._linkifier = new WebInspector.Linkifier(); 64 this._refreshThrottler = new WebInspector.Throttler(0); 65 } 66 67 WebInspector.EventListenersSidebarPane._objectGroupName = "event-listeners-sidebar-pane"; 68 69 WebInspector.EventListenersSidebarPane.prototype = { 70 /** 71 * @param {?WebInspector.DOMNode} node 72 */ 73 update: function(node) 74 { 75 this._selectedNode = node; 76 this._refreshThrottler.schedule(this._refreshView.bind(this)); 77 }, 78 79 /** 80 * @param {!WebInspector.Throttler.FinishCallback} finishCallback 81 */ 82 _refreshView: function(finishCallback) 83 { 84 if (this._lastRequestedNode) { 85 this._lastRequestedNode.target().runtimeAgent().releaseObjectGroup(WebInspector.EventListenersSidebarPane._objectGroupName); 86 delete this._lastRequestedNode; 87 } 88 89 this._linkifier.reset(); 90 91 var body = this.bodyElement; 92 body.removeChildren(); 93 this.sections = []; 94 95 var node = this._selectedNode; 96 if (!node) { 97 finishCallback(); 98 return; 99 } 100 101 this._lastRequestedNode = node; 102 node.eventListeners(WebInspector.EventListenersSidebarPane._objectGroupName, callback.bind(this)); 103 104 /** 105 * @param {?Array.<!WebInspector.DOMModel.EventListener>} eventListeners 106 * @this {WebInspector.EventListenersSidebarPane} 107 */ 108 function callback(eventListeners) 109 { 110 if (!eventListeners) { 111 finishCallback(); 112 return; 113 } 114 115 var selectedNodeOnly = "selected" === WebInspector.settings.eventListenersFilter.get(); 116 var sectionNames = []; 117 var sectionMap = {}; 118 for (var i = 0; i < eventListeners.length; ++i) { 119 var eventListener = eventListeners[i]; 120 if (selectedNodeOnly && (node.id !== eventListener.payload().nodeId)) 121 continue; 122 if (/^function _inspectorCommandLineAPI_logEvent\(/.test(eventListener.payload().handlerBody.toString())) 123 continue; // ignore event listeners generated by monitorEvent 124 var type = eventListener.payload().type; 125 var section = sectionMap[type]; 126 if (!section) { 127 section = new WebInspector.EventListenersSection(type, node.id, this._linkifier); 128 sectionMap[type] = section; 129 sectionNames.push(type); 130 this.sections.push(section); 131 } 132 section.addListener(eventListener); 133 } 134 135 if (sectionNames.length === 0) { 136 body.createChild("div", "info").textContent = WebInspector.UIString("No Event Listeners"); 137 } else { 138 sectionNames.sort(); 139 for (var i = 0; i < sectionNames.length; ++i) { 140 var section = sectionMap[sectionNames[i]]; 141 body.appendChild(section.element); 142 } 143 } 144 145 finishCallback(); 146 } 147 }, 148 149 _refreshButtonClicked: function() 150 { 151 if (!this._selectedNode) 152 return; 153 this.update(this._selectedNode); 154 }, 155 156 _changeSetting: function() 157 { 158 var selectedOption = this.settingsSelectElement[this.settingsSelectElement.selectedIndex]; 159 WebInspector.settings.eventListenersFilter.set(selectedOption.value); 160 this.update(this._selectedNode); 161 }, 162 163 __proto__: WebInspector.SidebarPane.prototype 164 } 165 166 /** 167 * @constructor 168 * @extends {WebInspector.PropertiesSection} 169 */ 170 WebInspector.EventListenersSection = function(title, nodeId, linkifier) 171 { 172 this._nodeId = nodeId; 173 this._linkifier = linkifier; 174 WebInspector.PropertiesSection.call(this, title); 175 176 // Changed from a Properties List 177 this.propertiesElement.remove(); 178 delete this.propertiesElement; 179 delete this.propertiesTreeOutline; 180 181 this._eventBars = this.element.createChild("div", "event-bars"); 182 } 183 184 WebInspector.EventListenersSection.prototype = { 185 /** 186 * @param {!WebInspector.DOMModel.EventListener} eventListener 187 */ 188 addListener: function(eventListener) 189 { 190 var eventListenerBar = new WebInspector.EventListenerBar(eventListener, this._nodeId, this._linkifier); 191 this._eventBars.appendChild(eventListenerBar.element); 192 }, 193 194 __proto__: WebInspector.PropertiesSection.prototype 195 } 196 197 /** 198 * @constructor 199 * @extends {WebInspector.ObjectPropertiesSection} 200 * @param {!WebInspector.DOMModel.EventListener} eventListener 201 * @param {!DOMAgent.NodeId} nodeId 202 * @param {!WebInspector.Linkifier} linkifier 203 */ 204 WebInspector.EventListenerBar = function(eventListener, nodeId, linkifier) 205 { 206 var target = eventListener.target(); 207 WebInspector.ObjectPropertiesSection.call(this, target.runtimeModel.createRemoteObjectFromPrimitiveValue("")); 208 209 this._runtimeModel = target.runtimeModel; 210 this._eventListener = eventListener; 211 this._nodeId = nodeId; 212 this._setNodeTitle(); 213 this._setFunctionSubtitle(linkifier); 214 this.editable = false; 215 this.element.className = "event-bar"; /* Changed from "section" */ 216 this.headerElement.classList.add("source-code"); 217 this.propertiesElement.className = "event-properties properties-tree source-code"; /* Changed from "properties" */ 218 } 219 220 WebInspector.EventListenerBar.prototype = { 221 update: function() 222 { 223 /** 224 * @param {?WebInspector.RemoteObject} nodeObject 225 * @this {WebInspector.EventListenerBar} 226 */ 227 function updateWithNodeObject(nodeObject) 228 { 229 var properties = []; 230 var payload = this._eventListener.payload(); 231 232 properties.push(this._runtimeModel.createRemotePropertyFromPrimitiveValue("type", payload.type)); 233 properties.push(this._runtimeModel.createRemotePropertyFromPrimitiveValue("useCapture", payload.useCapture)); 234 properties.push(this._runtimeModel.createRemotePropertyFromPrimitiveValue("isAttribute", payload.isAttribute)); 235 if (nodeObject) 236 properties.push(new WebInspector.RemoteObjectProperty("node", nodeObject)); 237 if (typeof payload.handler !== "undefined") { 238 var remoteObject = this._runtimeModel.createRemoteObject(payload.handler); 239 properties.push(new WebInspector.RemoteObjectProperty("handler", remoteObject)); 240 } 241 properties.push(this._runtimeModel.createRemotePropertyFromPrimitiveValue("listenerBody", payload.handlerBody)); 242 if (payload.sourceName) 243 properties.push(this._runtimeModel.createRemotePropertyFromPrimitiveValue("sourceName", payload.sourceName)); 244 properties.push(this._runtimeModel.createRemotePropertyFromPrimitiveValue("lineNumber", payload.location.lineNumber + 1)); 245 246 this.updateProperties(properties); 247 } 248 this._eventListener.node().resolveToObject(WebInspector.EventListenersSidebarPane._objectGroupName, updateWithNodeObject.bind(this)); 249 }, 250 251 _setNodeTitle: function() 252 { 253 var node = this._eventListener.node(); 254 if (!node) 255 return; 256 257 if (node.nodeType() === Node.DOCUMENT_NODE) { 258 this.titleElement.textContent = "document"; 259 return; 260 } 261 262 if (node.id === this._nodeId) { 263 this.titleElement.textContent = WebInspector.DOMPresentationUtils.simpleSelector(node); 264 return; 265 } 266 267 this.titleElement.removeChildren(); 268 this.titleElement.appendChild(WebInspector.DOMPresentationUtils.linkifyNodeReference(node)); 269 }, 270 271 /** 272 * @param {!WebInspector.Linkifier} linkifier 273 */ 274 _setFunctionSubtitle: function(linkifier) 275 { 276 this.subtitleElement.removeChildren(); 277 var link = linkifier.linkifyRawLocation(this._eventListener.location(), this._eventListener.sourceName()); 278 this.subtitleElement.appendChild(link); 279 }, 280 281 __proto__: WebInspector.ObjectPropertiesSection.prototype 282 } 283