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