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