| Index: Source/devtools/front_end/components/EventListenersTreeOutline.js
|
| diff --git a/Source/devtools/front_end/components/EventListenersTreeOutline.js b/Source/devtools/front_end/components/EventListenersTreeOutline.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a56b4c133d830b29f32fbd6d339f57f3092b77ea
|
| --- /dev/null
|
| +++ b/Source/devtools/front_end/components/EventListenersTreeOutline.js
|
| @@ -0,0 +1,406 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +/** @typedef {WebInspector.DOMModel.DOMEventListener|WebInspector.RuntimeModel.ObjectEventListener} */
|
| +WebInspector.ModelEventListener;
|
| +
|
| +/**
|
| + * @constructor
|
| + * @param {!Element} element
|
| + */
|
| +WebInspector.EventListenersTreeOutline = function(element)
|
| +{
|
| + this._element = element;
|
| +
|
| + this._treeOutline = new TreeOutline(true);
|
| + this._treeOutline.element.classList.add("event-listener-tree", "outline-disclosure", "monospace");
|
| + element.appendChild(this._treeOutline.element);
|
| +
|
| + this._linkifier = new WebInspector.Linkifier();
|
| + this._lastProviders = [];
|
| +}
|
| +
|
| +WebInspector.EventListenersTreeOutline.prototype = {
|
| + /**
|
| + * @param {?function()} finishCallback
|
| + * @param {?Array<!WebInspector.ModelEventListener>} eventListeners
|
| + */
|
| + _onEventListeners: function(finishCallback, eventListeners)
|
| + {
|
| + if (!eventListeners) {
|
| + if (finishCallback)
|
| + finishCallback();
|
| + return;
|
| + }
|
| +
|
| + var treeItemMap = new Map();
|
| + eventListeners.stableSort(compareListeners);
|
| +
|
| + /**
|
| + * @param {!WebInspector.ModelEventListener} a
|
| + * @param {!WebInspector.ModelEventListener} b
|
| + * @return {number}
|
| + */
|
| + function compareListeners(a, b)
|
| + {
|
| + var aType = a.type();
|
| + var bType = b.type();
|
| + return aType === bType ? 0 :
|
| + aType > bType ? 1 : -1;
|
| + }
|
| +
|
| + for (var i = 0; i < eventListeners.length; ++i) {
|
| + var eventListener = eventListeners[i];
|
| + var type = eventListener.type();
|
| + var treeItem = treeItemMap.get(type);
|
| + if (!treeItem) {
|
| + treeItem = new WebInspector.EventListenersTreeElement(type, this._linkifier);
|
| + treeItemMap.set(type, treeItem);
|
| + this._treeOutline.appendChild(treeItem);
|
| + }
|
| + treeItem.addListener(eventListener);
|
| + }
|
| + if (treeItemMap.size === 0)
|
| + this._element.createChild("div", "info").textContent = WebInspector.UIString("No Event Listeners");
|
| + else
|
| + this._element.appendChild(this._treeOutline.element);
|
| +
|
| + if (finishCallback)
|
| + finishCallback();
|
| + },
|
| +
|
| + /**
|
| + * @param {?function()} finishCallback
|
| + * @param {?Array<!WebInspector.EventListenersProvider>} providers
|
| + */
|
| + runProviders: function(finishCallback, providers)
|
| + {
|
| + this._lastProviders = providers;
|
| +
|
| + /**
|
| + * @this {!WebInspector.EventListenersTreeOutline}
|
| + * @param {!Array<?Array<!WebInspector.ModelEventListener>>} listeners
|
| + */
|
| + function onEventListeners(listeners)
|
| + {
|
| + listeners = listeners.filter(function(x){
|
| + return x;
|
| + });
|
| + var allListeners = [];
|
| + this._onEventListeners(finishCallback, allListeners.concat.apply(allListeners, listeners));
|
| + }
|
| +
|
| + Promise.all(providers.map(function(provider){
|
| + return provider.getFilteredEventListenersPromise();
|
| + })).then(onEventListeners.bind(this));
|
| + },
|
| +
|
| + reset: function()
|
| + {
|
| + this._element.removeChildren();
|
| + this._treeOutline.removeChildren();
|
| +
|
| + this._linkifier.reset();
|
| + for (var i = 0; i < this._lastProviders.length; ++i)
|
| + this._lastProviders[i].releaseListeners();
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * @constructor
|
| + * @extends {TreeElement}
|
| + * @param {string} type
|
| + * @param {!WebInspector.Linkifier} linkifier
|
| + */
|
| +WebInspector.EventListenersTreeElement = function(type, linkifier)
|
| +{
|
| + this._linkifier = linkifier;
|
| +
|
| + TreeElement.call(this, type);
|
| + this.toggleOnClick = true;
|
| + this.selectable = false;
|
| +}
|
| +
|
| +WebInspector.EventListenersTreeElement.prototype = {
|
| + /**
|
| + * @param {!WebInspector.ModelEventListener} eventListener
|
| + */
|
| + addListener: function(eventListener)
|
| + {
|
| + var treeElement;
|
| + if (eventListener.isDOMEventListener()) {
|
| + treeElement = new WebInspector.DOMEventListenerBar(/** @type {!WebInspector.DOMModel.DOMEventListener} */ (eventListener), this._linkifier);
|
| + } else if (eventListener.isObjectEventListener()) {
|
| + treeElement = new WebInspector.ObjectEventListenerBar(/** @type {!WebInspector.RuntimeModel.ObjectEventListener} */ (eventListener), this._linkifier);
|
| + }
|
| + this.appendChild(/** @type {!TreeElement} */ (treeElement));
|
| + },
|
| +
|
| + __proto__: TreeElement.prototype
|
| +}
|
| +
|
| +/**
|
| + * @constructor
|
| + * @template EventListener
|
| + * @param {?Array<string>} allowedTypes
|
| + */
|
| +WebInspector.EventListenersProvider = function(allowedTypes)
|
| +{
|
| + this._allowedTypes = allowedTypes ? new Set(allowedTypes) : null;
|
| +}
|
| +
|
| +WebInspector.EventListenersProvider.prototype = {
|
| + /**
|
| + * @param {function(?Array<!EventListener>)} callback
|
| + */
|
| + getFilteredEventListeners: function(callback)
|
| + {
|
| + /**
|
| + * @this {!WebInspector.EventListenersProvider}
|
| + * @param {?Array<!EventListener>} listeners
|
| + */
|
| + function mycallback(listeners)
|
| + {
|
| + if (!listeners) {
|
| + callback(null);
|
| + return;
|
| + }
|
| +
|
| + callback(listeners.filter(this._filterEventListener.bind(this)));
|
| + }
|
| + this._getEventListeners(mycallback.bind(this));
|
| + },
|
| +
|
| + /**
|
| + * @return {!Promise<?Array<!EventListener>>}
|
| + */
|
| + getFilteredEventListenersPromise: function()
|
| + {
|
| + return new Promise(this.getFilteredEventListeners.bind(this));
|
| + },
|
| +
|
| + /**
|
| + * @param {function(?Array.<!EventListener>)} callback
|
| + */
|
| + _getEventListeners: function(callback)
|
| + {
|
| + },
|
| +
|
| + /**
|
| + * @param {!EventListener} eventListener
|
| + */
|
| + _filterEventListener: function(eventListener)
|
| + {
|
| + if (eventListener.location().script().isInternalScript())
|
| + return false;
|
| + if (this._allowedTypes && !this._allowedTypes.has(eventListener.type()))
|
| + return false;
|
| + return true;
|
| + },
|
| +
|
| + releaseListeners: function()
|
| + {
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * @constructor
|
| + * @extends {WebInspector.EventListenersProvider<!WebInspector.DOMModel.DOMEventListener>}
|
| + * @param {?Array<string>} allowedTypes
|
| + * @param {!WebInspector.DOMNode} node
|
| + * @param {?WebInspector.DOMNode} selectedNode
|
| + */
|
| +WebInspector.DOMEventListenersProvider = function(allowedTypes, node, selectedNode)
|
| +{
|
| + WebInspector.EventListenersProvider.call(this, allowedTypes);
|
| + this._node = node;
|
| + this._selectedNode = selectedNode;
|
| +}
|
| +
|
| +WebInspector.DOMEventListenersProvider._objectGroupName = "dom-event-listeners";
|
| +
|
| +WebInspector.DOMEventListenersProvider.prototype = {
|
| + /**
|
| + * @override
|
| + * @param {function(?Array<!WebInspector.DOMModel.DOMEventListener>)} callback
|
| + */
|
| + _getEventListeners: function(callback)
|
| + {
|
| + /**
|
| + * @param {?Array<!WebInspector.DOMModel.DOMEventListener>} listeners
|
| + */
|
| + function mycallback(listeners)
|
| + {
|
| + if (!listeners) {
|
| + callback(null);
|
| + return;
|
| + }
|
| + listeners = listeners.map(function(listener){
|
| + listener.isSelected = this._selectedNode && this._selectedNode.id === listener.payload().nodeId;
|
| + return listener
|
| + });
|
| + callback(listeners);
|
| + }
|
| + this._node.eventListeners(WebInspector.DOMEventListenersProvider._objectGroupName, callback);
|
| + },
|
| +
|
| + /**
|
| + * @override
|
| + * @param {!WebInspector.DOMModel.DOMEventListener} eventListener
|
| + */
|
| + _filterEventListener: function(eventListener)
|
| + {
|
| + if (!WebInspector.EventListenersProvider.prototype._filterEventListener.call(this, eventListener))
|
| + return false;
|
| + if (this._selectedNode && this._selectedNode.id !== eventListener.payload().nodeId)
|
| + return false;
|
| + return true;
|
| + },
|
| +
|
| + releaseListeners: function()
|
| + {
|
| + this._node.target().runtimeAgent().releaseObjectGroup(WebInspector.DOMEventListenersProvider._objectGroupName);
|
| + },
|
| +
|
| + __proto__: WebInspector.EventListenersProvider.prototype
|
| +}
|
| +
|
| +/**
|
| + * @constructor
|
| + * @extends {WebInspector.EventListenersProvider<!WebInspector.RuntimeModel.ObjectEventListener>}
|
| + * @param {?Array<string>} allowedTypes
|
| + * @param {!WebInspector.RemoteObject} object
|
| + */
|
| +WebInspector.ObjectEventListenersProvider = function(allowedTypes, object)
|
| +{
|
| + WebInspector.EventListenersProvider.call(this, allowedTypes);
|
| + this._object = object;
|
| +}
|
| +
|
| +WebInspector.ObjectEventListenersProvider.objectGroupName = "object-event-listeners";
|
| +
|
| +WebInspector.ObjectEventListenersProvider.prototype = {
|
| + /**
|
| + * @override
|
| + * @param {function(?Array.<!WebInspector.RuntimeModel.ObjectEventListener>)} callback
|
| + */
|
| + _getEventListeners: function(callback)
|
| + {
|
| + this._object.getEventListeners(WebInspector.ObjectEventListenersProvider.objectGroupName, callback);
|
| + },
|
| +
|
| + releaseListeners: function()
|
| + {
|
| + this._object.target().runtimeAgent().releaseObjectGroup(WebInspector.ObjectEventListenersProvider.objectGroupName);
|
| + },
|
| +
|
| + __proto__: WebInspector.EventListenersProvider.prototype
|
| +}
|
| +
|
| +/**
|
| + * @constructor
|
| + * @extends {TreeElement}
|
| + * @param {!WebInspector.DOMModel.DOMEventListener} eventListener
|
| + * @param {!WebInspector.Linkifier} linkifier
|
| + */
|
| +WebInspector.DOMEventListenerBar = function(eventListener, linkifier)
|
| +{
|
| + TreeElement.call(this, "", true);
|
| +
|
| + var target = eventListener.target();
|
| + this._runtimeModel = target.runtimeModel;
|
| + this._eventListener = eventListener;
|
| + this._setNodeTitle(linkifier);
|
| + this.editable = false;
|
| +}
|
| +
|
| +WebInspector.DOMEventListenerBar.prototype = {
|
| + onpopulate: function()
|
| + {
|
| + /**
|
| + * @this {!WebInspector.DOMEventListenerBar}
|
| + * @param {!Array<!WebInspector.RemoteObjectProperty>} properties
|
| + */
|
| + function populate(properties)
|
| + {
|
| + WebInspector.ObjectPropertyTreeElement.populateWithProperties(this, properties, [], true, null);
|
| + }
|
| + this._eventListener.getProperties(populate.bind(this), WebInspector.DOMEventListenersProvider._objectGroupName);
|
| + },
|
| +
|
| + /**
|
| + * @param {!WebInspector.Linkifier} linkifier
|
| + */
|
| + _setNodeTitle: function(linkifier)
|
| + {
|
| + var node = this._eventListener.node();
|
| + if (!node)
|
| + return;
|
| +
|
| + this.listItemElement.removeChildren();
|
| + var title = this.listItemElement.createChild("span");
|
| + var subtitle = this.listItemElement.createChild("span", "event-listener-tree-subtitle");
|
| + subtitle.appendChild(linkifier.linkifyRawLocation(this._eventListener.location(), this._eventListener.sourceName()));
|
| +
|
| + if (node.nodeType() === Node.DOCUMENT_NODE) {
|
| + title.textContent = "document";
|
| + return;
|
| + }
|
| +
|
| + if (this._eventListener.isSelected) {
|
| + title.textContent = WebInspector.DOMPresentationUtils.simpleSelector(node);
|
| + return;
|
| + }
|
| +
|
| + title.appendChild(WebInspector.DOMPresentationUtils.linkifyNodeReference(node));
|
| + },
|
| +
|
| + __proto__: TreeElement.prototype
|
| +}
|
| +
|
| +/**
|
| + * @constructor
|
| + * @extends {TreeElement}
|
| + * @param {!WebInspector.RuntimeModel.ObjectEventListener} eventListener
|
| + * @param {!WebInspector.Linkifier} linkifier
|
| + */
|
| +WebInspector.ObjectEventListenerBar = function(eventListener, linkifier)
|
| +{
|
| + TreeElement.call(this, "", true);
|
| +
|
| + var target = eventListener.target();
|
| + this._runtimeModel = target.runtimeModel;
|
| + this._eventListener = eventListener;
|
| + this._setNodeTitle(linkifier);
|
| + this.editable = false;
|
| +}
|
| +
|
| +WebInspector.ObjectEventListenerBar.prototype = {
|
| + onpopulate: function()
|
| + {
|
| + /**
|
| + * @this {!WebInspector.ObjectEventListenerBar}
|
| + * @param {!Array<!WebInspector.RemoteObjectProperty>} properties
|
| + */
|
| + function populate(properties)
|
| + {
|
| + WebInspector.ObjectPropertyTreeElement.populateWithProperties(this, properties, [], true, null);
|
| + }
|
| + this._eventListener.getProperties(populate.bind(this), WebInspector.ObjectEventListenersProvider.objectGroupName);
|
| + },
|
| +
|
| + /**
|
| + * @param {!WebInspector.Linkifier} linkifier
|
| + */
|
| + _setNodeTitle: function(linkifier)
|
| + {
|
| + this.listItemElement.removeChildren();
|
| + var title = this.listItemElement.createChild("span");
|
| + var subtitle = this.listItemElement.createChild("span", "event-listener-tree-subtitle");
|
| + subtitle.appendChild(linkifier.linkifyRawLocation(this._eventListener.location(), this._eventListener.sourceName()));
|
| + title.textContent = this._eventListener.description();
|
| + },
|
| +
|
| + __proto__: TreeElement.prototype
|
| +}
|
|
|