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