Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1845)

Unified Diff: Source/devtools/front_end/components/EventListenersUtils.js

Issue 1268353005: [DevTools] Support JQuery event listeners (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Source/devtools/front_end/components/EventListenersUtils.js
diff --git a/Source/devtools/front_end/components/EventListenersUtils.js b/Source/devtools/front_end/components/EventListenersUtils.js
new file mode 100644
index 0000000000000000000000000000000000000000..6b3b5fa915cfc323a789c130648b59f523265573
--- /dev/null
+++ b/Source/devtools/front_end/components/EventListenersUtils.js
@@ -0,0 +1,289 @@
+// 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.
+
+/**
+ * @param {!WebInspector.RemoteObject} object
+ * @param {function(this:Object):{eventListeners:!Array<!{type:string, handler:(function()|!Object), useCapture:boolean}>, internalHandlers:?Array<function()>}} getter
+ * @return {!Promise<!{eventListeners:!Array<!WebInspector.EventListener>, internalHandlers:?WebInspector.RemoteArray}>}
+ */
+WebInspector.frameworkEventListeners = function(object, getter)
pfeldman 2015/09/02 02:58:52 Please don't put anything on the global WebInspect
pfeldman 2015/09/02 02:58:52 What is getter?
kozy 2015/09/02 17:34:13 Moved to WebInspector.EventListener
kozy 2015/09/02 17:34:13 Getter is moved into this function.
+{
+ var listenersResult = {eventListeners: []};
+ return object.callFunctionPromise(getter, undefined)
+ .then(assertCallFunctionResult)
+ .then(getterCallback)
+ .then(propertiesCallback)
+ .then(returnResult);
+
+ /**
+ * @param {!WebInspector.RemoteObject} object
+ * @return {!Promise<!{properties: ?Array<!WebInspector.RemoteObjectProperty>, internalProperties: ?Array<!WebInspector.RemoteObjectProperty>}>}
+ */
+ function getterCallback(object)
+ {
+ return object.getOwnPropertiesPromise();
+ }
+
+ /**
+ * @param {!{properties: ?Array<!WebInspector.RemoteObjectProperty>, internalProperties: ?Array<!WebInspector.RemoteObjectProperty>}} result
+ * @return {!Promise<void>}
+ */
+ function propertiesCallback(result)
+ {
+ if (!result.properties)
+ return Promise.resolve();
+ var promises = [];
+ for (var property of result.properties) {
+ if (property.name === "eventListeners" && property.value) {
pfeldman 2015/09/02 02:58:52 Could you explain the structure of the objects you
kozy 2015/09/02 17:34:13 Added before frameworkEventListenersGetter functio
+ promises.push(WebInspector.RemoteArray.createFromObject(property.value)
+ .map(toEventListener)
+ .then(nonEmptyObjects)
+ .then(storeResultTo.bind(null, listenersResult, "eventListeners")));
+ }
+ if (property.name === "internalHandlers" && property.value) {
+ promises.push(WebInspector.RemoteArray.createFromObject(property.value)
+ .map(toTargetFunction)
+ .then(WebInspector.RemoteArray.createFromArray)
+ .then(storeResultTo.bind(null, listenersResult, "internalHandlers")));
+ }
+ }
+ return /** @type {!Promise<void>} */(Promise.all(promises));
+
+ /**
+ * @param {!WebInspector.RemoteObject} listenerObject
+ * @return {!Promise<?WebInspector.EventListener>}
+ */
+ function toEventListener(listenerObject)
+ {
+ /** @type {?} */
+ var eventListenerData = {};
+ var promises = [];
+
+ promises.push(listenerObject.callFunctionJSONPromise(identity, undefined).then(storeResultTo.bind(null, eventListenerData, "jsonData")));
+ promises.push(listenerObject.callFunctionPromise(listenerEffectiveFunction).then(assertCallFunctionResult)
+ .then(toTargetFunction)
+ .then(storeFunctionWithDetails));
+ return Promise.all(promises).then(createEventListener.bind(null, eventListenerData)).catchException(/** @type {?WebInspector.EventListener} */(null));
+
+ /**
+ * @suppressReceiverCheck
+ * @this {T}
+ * @return {T}
+ * @template T
+ */
+ function identity()
+ {
+ return this;
+ }
+
+ /**
+ * @suppressReceiverCheck
+ * @return {function()}
+ * @this {Object}
+ */
+ function listenerEffectiveFunction()
+ {
+ if (typeof this.handler === "function")
+ return this.handler;
+ return typeof this.handler === "object" ? (this.handler.handlerEvent || this.handler.constructor) : null;
+ }
+
+ /**
+ * @param {!WebInspector.RemoteObject} functionObject
+ * @return {!Promise<void>}
+ */
+ function storeFunctionWithDetails(functionObject)
+ {
+ eventListenerData.handlerFunction = functionObject;
+ return /** @type {!Promise<void>} */(functionObject.functionDetailsPromise().then(storeResultTo.bind(null, eventListenerData, "handlerDetails")));
+ }
+
+ /**
+ * @param {!{jsonData: {type:string, useCapture:boolean, handler:function()}, handlerFunction: !WebInspector.RemoteObject, handlerDetails: !WebInspector.DebuggerModel.FunctionDetails}} eventListenerData
+ * @return {!WebInspector.EventListener}
+ */
+ function createEventListener(eventListenerData)
+ {
+ return new WebInspector.EventListener(eventListenerData.handlerFunction._target,
+ eventListenerData.jsonData.type,
+ eventListenerData.jsonData.useCapture,
+ eventListenerData.handlerFunction,
+ /** @type {!WebInspector.DebuggerModel.Location}} */ (eventListenerData.handlerDetails.location),
+ "frameworkUser");
+ }
+ }
+
+ /**
+ * @param {!WebInspector.RemoteObject} functionObject
+ * @return {!Promise<!WebInspector.RemoteObject>}
+ */
+ function toTargetFunction(functionObject)
+ {
+ return WebInspector.RemoteFunction.createFromObject(functionObject).targetFunction();
+ }
+
+ /**
+ * @param {!Array<?T>} objects
+ * @return {!Array<!T>}
+ * @template T
+ */
+ function nonEmptyObjects(objects)
+ {
+ return objects.filter(filterOutEmpty);
+
+ /**
+ * @param {?T} object
+ * @return {boolean}
+ * @template T
+ */
+ function filterOutEmpty(object)
+ {
+ return !!object;
+ }
+ }
+ }
+
+ /**
+ * @return {!{eventListeners:!Array<!WebInspector.EventListener>, internalHandlers:?WebInspector.RemoteArray}}
+ */
+ function returnResult()
+ {
+ return /**@type {!{eventListeners:!Array<!WebInspector.EventListener>, internalHandlers:?WebInspector.RemoteArray}} */(listenersResult);
+ }
+
+ /**
+ * @param {!WebInspector.CallFunctionResult} result
+ * @return {!WebInspector.RemoteObject}
+ */
+ function assertCallFunctionResult(result)
+ {
+ if (result.wasThrown || !result.object)
+ throw new Error("Exception in callFunction or empty result");
+ return result.object;
+ }
+}
+
+/**
+ * @this {Object}
+ */
+WebInspector._frameworkEventListenersGetter = function()
pfeldman 2015/09/02 02:58:51 Where is this used?
kozy 2015/09/02 17:34:13 Moved to WebInspector.EventListener.frameworkEvent
+{
+ var eventListeners = [];
+ var internalHandlers = [];
+ var getters = [jQueryGetter];
+ try {
+ if (self.devtoolsFrameworkEventListeners && isArrayLike(self.devtoolsFrameworkEventListeners))
+ getters = getters.concat(self.devtoolsFrameworkEventListeners);
+ } catch (e) {
+ }
+
+ for (var i = 0; i < getters.length; ++i) {
+ try {
+ var getterResult = getters[i](this);
+ eventListeners = eventListeners.concat(getterResult.eventListeners);
+ internalHandlers = internalHandlers.concat(getterResult.internalHandlers);
+ } catch (e) {
+ }
+ }
+ var result = {eventListeners: eventListeners};
+ if (internalHandlers.length)
+ result.internalHandlers = internalHandlers;
+ return result;
+
+ /**
+ * @param {?Object} obj
+ * @return {boolean}
+ */
+ function isArrayLike(obj)
+ {
+ if (!obj || typeof obj !== "object")
+ return false;
+ try {
+ if (typeof obj.splice === "function") {
+ var len = obj.length;
+ return typeof len === "number" && (len >>> 0 === len && (len > 0 || 1 / len > 0));
+ }
+ } catch (e) {
+ }
+ return false;
+ }
+
+ function jQueryGetter(node)
+ {
+ return {eventListeners: jQueryEventListeners(node), internalHandlers: jQueryInternalHandlers(node)};
+ }
+
+ /**
+ * @param {?Object} node
+ * @return {!Array<!{handler:function(), useCapture: boolean, type:string}>}
+ */
+ function jQueryEventListeners(node)
+ {
+ if (!node || !(node instanceof Node))
+ return [];
+ var hasJQuery = (typeof jQuery !== 'undefined') && jQuery.fn;
+ if (!hasJQuery)
+ return [];
+ var listeners = [];
+ var data = jQuery._data || jQuery.data;
+ if (typeof data === "function") {
+ var events = data(node, "events");
+ for (var type in events) {
+ for (var key in events[type]) {
+ var frameworkListener = events[type][key];
+ if (typeof frameworkListener === "object" || typeof frameworkListener === "function") {
+ var listener = {
+ handler: frameworkListener.handler || frameworkListener,
+ useCapture: true,
+ type: type
+ };
+ listeners.push(listener);
+ }
+ }
+ }
+ }
+ var entry = jQuery(node)[0];
+ if (entry) {
+ var entryEvents = entry["$events"];
+ for (var type in entryEvents) {
+ var events = entryEvents[type];
+ for (var key in events) {
+ if (typeof events[key] === "function") {
+ var listener = {
+ handler: events[key],
+ useCapture: true,
+ type: type
+ };
+ listeners.push(listener);
+ }
+ }
+ }
+ }
+ return listeners;
+ }
+
+ /**
+ * @param {?Object} node
+ * @return {!Array<function()>}
+ */
+ function jQueryInternalHandlers(node)
+ {
+ if (!(node instanceof Node))
+ return [];
+ var hasJQuery = (typeof jQuery !== 'undefined') && jQuery.fn;
+ if (!hasJQuery)
+ return [];
+ var handlers = [];
+ var data = jQuery._data || jQuery.data;
+ if (typeof data === "function") {
+ var nodeData = data(node);
+ if (typeof nodeData.handle === "function")
+ handlers.push(nodeData.handle);
+ }
+ var entry = jQuery(node)[0];
+ if (entry && entry["$handle"])
+ handlers.push(entry["$handle"]);
+ return handlers;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698