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