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 WebInspector.EventListenersSidebarPane = function() 31 { 32 WebInspector.SidebarPane.call(this, WebInspector.UIString("Event Listeners")); 33 this.bodyElement.addStyleClass("events-pane"); 34 35 this.sections = []; 36 37 this.settingsSelectElement = document.createElement("select"); 38 39 var option = document.createElement("option"); 40 option.value = "all"; 41 option.label = WebInspector.UIString("All Nodes"); 42 this.settingsSelectElement.appendChild(option); 43 44 option = document.createElement("option"); 45 option.value = "selected"; 46 option.label = WebInspector.UIString("Selected Node Only"); 47 this.settingsSelectElement.appendChild(option); 48 49 var filter = WebInspector.settings.eventListenersFilter; 50 if (filter === "all") 51 this.settingsSelectElement[0].selected = true; 52 else if (filter === "selected") 53 this.settingsSelectElement[1].selected = true; 54 this.settingsSelectElement.addEventListener("click", function(event) { event.stopPropagation() }, false); 55 this.settingsSelectElement.addEventListener("change", this._changeSetting.bind(this), false); 56 57 this.titleElement.appendChild(this.settingsSelectElement); 58 } 59 60 WebInspector.EventListenersSidebarPane.prototype = { 61 update: function(node) 62 { 63 var body = this.bodyElement; 64 body.removeChildren(); 65 this.sections = []; 66 67 var self = this; 68 function callback(error, eventListeners) { 69 if (error) 70 return; 71 72 var sectionNames = []; 73 var sectionMap = {}; 74 for (var i = 0; i < eventListeners.length; ++i) { 75 var eventListener = eventListeners[i]; 76 eventListener.node = WebInspector.domAgent.nodeForId(eventListener.nodeId); 77 delete eventListener.nodeId; // no longer needed 78 if (/^function _inspectorCommandLineAPI_logEvent\(/.test(eventListener.listenerBody.toString())) 79 continue; // ignore event listeners generated by monitorEvent 80 var type = eventListener.type; 81 var section = sectionMap[type]; 82 if (!section) { 83 section = new WebInspector.EventListenersSection(type, node.id); 84 sectionMap[type] = section; 85 sectionNames.push(type); 86 self.sections.push(section); 87 } 88 section.addListener(eventListener); 89 } 90 91 if (sectionNames.length === 0) { 92 var div = document.createElement("div"); 93 div.className = "info"; 94 div.textContent = WebInspector.UIString("No Event Listeners"); 95 body.appendChild(div); 96 return; 97 } 98 99 sectionNames.sort(); 100 for (var i = 0; i < sectionNames.length; ++i) { 101 var section = sectionMap[sectionNames[i]]; 102 section.update(); 103 body.appendChild(section.element); 104 } 105 } 106 107 if (node) 108 node.eventListeners(callback); 109 }, 110 111 _changeSetting: function(event) 112 { 113 var selectedOption = this.settingsSelectElement[this.settingsSelectElement.selectedIndex]; 114 WebInspector.settings.eventListenersFilter = selectedOption.value; 115 116 for (var i = 0; i < this.sections.length; ++i) 117 this.sections[i].update(); 118 } 119 } 120 121 WebInspector.EventListenersSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype; 122 123 WebInspector.EventListenersSection = function(title, nodeId) 124 { 125 this.eventListeners = []; 126 this._nodeId = nodeId; 127 WebInspector.PropertiesSection.call(this, title); 128 129 // Changed from a Properties List 130 this.propertiesElement.parentNode.removeChild(this.propertiesElement); 131 delete this.propertiesElement; 132 delete this.propertiesTreeOutline; 133 134 this.eventBars = document.createElement("div"); 135 this.eventBars.className = "event-bars"; 136 this.element.appendChild(this.eventBars); 137 } 138 139 WebInspector.EventListenersSection.prototype = { 140 update: function() 141 { 142 // A Filtered Array simplifies when to create connectors 143 var filteredEventListeners = this.eventListeners; 144 if (WebInspector.settings.eventListenersFilter === "selected") { 145 filteredEventListeners = []; 146 for (var i = 0; i < this.eventListeners.length; ++i) { 147 var eventListener = this.eventListeners[i]; 148 if (eventListener.node.id === this._nodeId) 149 filteredEventListeners.push(eventListener); 150 } 151 } 152 153 this.eventBars.removeChildren(); 154 var length = filteredEventListeners.length; 155 for (var i = 0; i < length; ++i) { 156 var eventListener = filteredEventListeners[i]; 157 var eventListenerBar = new WebInspector.EventListenerBar(eventListener, this._nodeId); 158 this.eventBars.appendChild(eventListenerBar.element); 159 } 160 }, 161 162 addListener: function(eventListener) 163 { 164 this.eventListeners.push(eventListener); 165 } 166 } 167 168 WebInspector.EventListenersSection.prototype.__proto__ = WebInspector.PropertiesSection.prototype; 169 170 WebInspector.EventListenerBar = function(eventListener, nodeId) 171 { 172 this.eventListener = eventListener; 173 this._nodeId = nodeId; 174 WebInspector.ObjectPropertiesSection.call(this); 175 this._setNodeTitle(); 176 this._setFunctionSubtitle(); 177 this.editable = false; 178 this.element.className = "event-bar"; /* Changed from "section" */ 179 this.headerElement.addStyleClass("source-code"); 180 this.propertiesElement.className = "event-properties properties-tree source-code"; /* Changed from "properties" */ 181 } 182 183 WebInspector.EventListenerBar.prototype = { 184 update: function() 185 { 186 function updateWithNodeObject(nodeObject) 187 { 188 var properties = []; 189 if (nodeObject) 190 properties.push(new WebInspector.RemoteObjectProperty("node", nodeObject)); 191 192 for (var propertyName in this.eventListener) { 193 var value = WebInspector.RemoteObject.fromPrimitiveValue(this.eventListener[propertyName]); 194 properties.push(new WebInspector.RemoteObjectProperty(propertyName, value)); 195 } 196 this.updateProperties(properties); 197 if (nodeObject) 198 nodeObject.release(); 199 } 200 var node = this.eventListener.node; 201 delete this.eventListener.node; 202 WebInspector.RemoteObject.resolveNode(node, updateWithNodeObject.bind(this)); 203 }, 204 205 _setNodeTitle: function() 206 { 207 var node = this.eventListener.node; 208 if (!node) 209 return; 210 211 if (node.nodeType() === Node.DOCUMENT_NODE) { 212 this.titleElement.textContent = "document"; 213 return; 214 } 215 216 if (node.id === this._nodeId) { 217 this.titleElement.textContent = node.appropriateSelectorFor(); 218 return; 219 } 220 221 this.titleElement.removeChildren(); 222 this.titleElement.appendChild(WebInspector.panels.elements.linkifyNodeReference(this.eventListener.node)); 223 }, 224 225 _setFunctionSubtitle: function() 226 { 227 // Requires that Function.toString() return at least the function's signature. 228 if (this.eventListener.sourceName) { 229 this.subtitleElement.removeChildren(); 230 this.subtitleElement.appendChild(WebInspector.linkifyResourceAsNode(this.eventListener.sourceName, "scripts", this.eventListener.lineNumber)); 231 } else { 232 var match = this.eventListener.listenerBody.match(/function ([^\(]+?)\(/); 233 if (match) 234 this.subtitleElement.textContent = match[1]; 235 else 236 this.subtitleElement.textContent = WebInspector.UIString("(anonymous function)"); 237 } 238 } 239 } 240 241 WebInspector.EventListenerBar.prototype.__proto__ = WebInspector.ObjectPropertiesSection.prototype; 242