Chromium Code Reviews| Index: Source/devtools/front_end/sdk/EventListenerUtils.js |
| diff --git a/Source/devtools/front_end/sdk/EventListenerUtils.js b/Source/devtools/front_end/sdk/EventListenerUtils.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..48ef66eccc3e46542338667aa46191e379cface3 |
| --- /dev/null |
| +++ b/Source/devtools/front_end/sdk/EventListenerUtils.js |
| @@ -0,0 +1,342 @@ |
| +// 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} functionObject |
| + * @return {!Promise<!WebInspector.RemoteObject>} |
| + */ |
| +WebInspector.targetFunction = function(functionObject) |
| +{ |
| + return new Promise(promiseConstructor); |
| + |
| + /** |
| + * @param {function(?)} fulfill |
| + * @param {function(*)} reject |
| + */ |
| + function promiseConstructor(fulfill, reject) |
| + { |
| + functionObject.getOwnProperties(ownPropertiesCallback); |
|
pfeldman
2015/08/24 23:29:44
You should promisify the getOwnProperties instead,
|
| + function ownPropertiesCallback(properties, internalProperties) |
| + { |
| + if (internalProperties) { |
| + for (var i = 0; i < internalProperties.length; ++i) { |
| + if (internalProperties[i].name === "[[TargetFunction]]") { |
| + fulfill(internalProperties[i].value); |
| + return; |
| + } |
| + } |
| + } |
| + fulfill(functionObject); |
| + } |
| + } |
| +} |
| + |
| +/** |
| + * @param {!WebInspector.RemoteObject} functionObject |
| + * @return {!Promise<{functionObject: !WebInspector.RemoteObject, functionDetails: ?WebInspector.DebuggerModel.FunctionDetails}>} |
| + */ |
| +WebInspector.functionDetails = function(functionObject) |
| +{ |
| + return new Promise(promiseConstructor); |
| + |
| + /** |
| + * @param {function(?)} fulfill |
| + * @param {function(*)} reject |
| + */ |
| + function promiseConstructor(fulfill, reject) |
| + { |
| + if (!functionObject) { |
| + fulfill({functionObject: null, functionDetails: null}); |
| + return; |
| + } |
| + functionObject.functionDetails(functionDetailsCallback); |
|
pfeldman
2015/08/24 23:29:44
ditto, pure promisification required.
|
| + /** |
| + * @param {?WebInspector.DebuggerModel.FunctionDetails} functionDetails |
| + */ |
| + function functionDetailsCallback(functionDetails) |
| + { |
| + fulfill({functionObject: functionObject, functionDetails: functionDetails}); |
| + } |
| + } |
| +} |
| + |
| +/** |
| + * @param {!WebInspector.RemoteObject} frameworkEventListener |
| + * @return {!Promise<!WebInspector.EventListener>} |
| + */ |
| +WebInspector.buildEventListener = function(frameworkEventListener) |
|
pfeldman
2015/08/24 23:29:44
This should be a part of the event listeners view
|
| +{ |
| + var promises = [frameworkEventListener.callFunctionJSONPromise(function(){ return this; }, undefined)]; |
|
pfeldman
2015/08/24 23:29:44
Also hard to parse what it does, it uses inline fu
|
| + promises.push(frameworkEventListener.callFunctionPromise(effectiveFunction, undefined).then(targetFunction).then(WebInspector.functionDetails)); |
| + return Promise.all(promises).then(frameworkEventListenerCallback); |
| + |
| + /** |
| + * @param {!{object: ?WebInspector.RemoteObject, wasThrown: (boolean|undefined)}} result |
| + * @return {!Promise<!WebInspector.RemoteObject>} |
| + */ |
| + function targetFunction(result) |
| + { |
| + return WebInspector.targetFunction(/** @type {!WebInspector.RemoteObject} */(result.object)); |
| + } |
| + |
| + /** |
| + * @suppressReceiverCheck |
| + * @this {Object} |
| + * @return {function()} |
| + */ |
| + function effectiveFunction() |
| + { |
| + if (typeof this.handler === "function") |
| + return this.handler; |
| + return typeof this.handler === "object" ? (this.handler.handlerEvent || this.handler.constructor) : null; |
| + } |
| + |
| + /** |
| + * @param {!Array<*>} data |
| + * @return {!WebInspector.EventListener} |
| + */ |
| + function frameworkEventListenerCallback(data) |
| + { |
| + var listenerJSON = data[0]; |
| + var targetFunction = data[1]; |
| + return new WebInspector.EventListener(frameworkEventListener.target(), listenerJSON.type, listenerJSON.useCapture, targetFunction.functionDetails.location, targetFunction.functionObject, targetFunction.functionDetails.sourceURL); |
| + } |
| +} |
| + |
| +/** |
| + * @param {!{object: ?WebInspector.RemoteObject, wasThrown: (boolean|undefined)}} frameworkListenersResult |
| + * @return {!Promise<?Array<!WebInspector.EventListener>>} |
| + */ |
| +WebInspector.castEventListeners = function(frameworkListenersResult) |
|
pfeldman
2015/08/24 23:29:43
move into widget, also impossible to tell what lay
|
| +{ |
| + if (frameworkListenersResult.wasThrown) |
| + return /** @type{!Promise<?Array<!WebInspector.EventListener>>} */(Promise.resolve(null)); |
| + var frameworkListeners = frameworkListenersResult.object; |
| + var promises = []; |
| + for (var i = 0; i < frameworkListeners.arrayLength(); ++i) |
| + promises.push(frameworkListeners.callFunctionPromise(function(idx){ return this[idx]; }, [WebInspector.RemoteObject.toCallArgument(i)]).then(buildEventListener)); |
| + return /** @type{!Promise<?Array<!WebInspector.EventListener>>} */(Promise.all(promises)); |
| + |
| + /** |
| + * @param {!{object: ?WebInspector.RemoteObject, wasThrown: (boolean|undefined)}} result |
| + * @return {!Promise<!WebInspector.EventListener>} |
| + */ |
| + function buildEventListener(result) |
| + { |
| + return WebInspector.buildEventListener(/** @type {!WebInspector.RemoteObject} */(result.object)); |
| + } |
| +} |
| + |
| + |
| +/** |
| + * @param {!{object: ?WebInspector.RemoteObject, wasThrown: (boolean|undefined)}} frameworkHandlersResult |
| + * @return {!Promise<?Array<function()>>} |
| + */ |
| +WebInspector.castEventHandlers = function(frameworkHandlersResult) |
|
pfeldman
2015/08/24 23:29:44
ditto
|
| +{ |
| + var frameworkHandlers = frameworkHandlersResult.object; |
| + return new Promise(promiseConstructor); |
| + |
| + /** |
| + * @param {function(?)} fulfill |
| + * @param {function(*)} reject |
| + */ |
| + function promiseConstructor(fulfill, reject) |
| + { |
| + frameworkHandlers.callFunctionPromise(function(){ return new Set(); }, undefined).then(setCreated); |
| + |
| + /** |
| + * @param {!{object: ?WebInspector.RemoteObject, wasThrown: (boolean|undefined)}} setResult |
| + */ |
| + function setCreated(setResult) |
| + { |
| + if (setResult.wasThrown) { |
| + fulfill(null); |
| + return; |
| + } |
| + var setObject = setResult.object; |
| + var promises = []; |
| + for (var i = 0; i < frameworkHandlers.arrayLength(); ++i) |
| + promises.push(frameworkHandlers.callFunctionPromise(function(idx){ return this[idx]; }, [WebInspector.RemoteObject.toCallArgument(i)]).then(targetFunction).then(addToSet)); |
| + Promise.all(promises).then(returnSet); |
| + |
| + /** |
| + * @param {!{object: ?WebInspector.RemoteObject, wasThrown: (boolean|undefined)}} result |
| + */ |
| + function targetFunction(result) |
| + { |
| + return WebInspector.targetFunction(/** @type {!WebInspector.RemoteObject}*/(result.object)); |
| + } |
| + |
| + /** |
| + * @param {!WebInspector.RemoteObject} targetFunctionObject |
| + */ |
| + function addToSet(targetFunctionObject) |
| + { |
| + return setObject.callFunctionPromise(function(f){ this.add(f); }, [WebInspector.RemoteObject.toCallArgument(targetFunctionObject)]); |
| + } |
| + |
| + function returnSet() |
| + { |
| + fulfill(setObject); |
| + } |
| + } |
| + } |
| +} |
| + |
| + |
| +/** |
| + * @return {!Array<!{handler:function(), useCapture: boolean, type:string}>} |
| + * @this {Object} |
| + */ |
| +function devtoolsFrameworkEventListeners() |
|
pfeldman
2015/08/24 23:29:44
ditto
|
| +{ |
| + var listeners = []; |
| + var getters = [jQueryEventListeners]; |
| + try { |
| + if (isArrayLike(self.devtoolsFrameworkEventListeners)) |
| + getters = getters.concat(self.devtoolsFrameworkEventListeners); |
| + } catch (e) { |
| + } |
| + |
| + for (var i = 0; i < getters.length; ++i) { |
| + try { |
| + listeners = listeners.concat(getters[i](this)); |
| + } catch (e) { |
| + } |
| + } |
| + return listeners; |
| + |
| + /** |
| + * @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; |
| + } |
| + |
| + /** |
| + * @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; |
| + } |
| +} |
| + |
| +/** |
| + * @return {!Array<function()>} |
| + * @this {Object} |
| + */ |
| +function devtoolsFrameworkInternalHandlers() |
|
pfeldman
2015/08/24 23:29:44
ditto
|
| +{ |
| + var handlers = []; |
| + var getters = [jQueryInternalHandlers]; |
| + try { |
| + if (isArrayLike(self.devtoolsFrameworkInternalHandlers)) |
| + getters = getters.concat(self.devtoolsFrameworkInternalHandlers); |
| + } catch (e) { |
| + } |
| + |
| + for (var i = 0; i < getters.length; ++i) { |
| + try { |
| + handlers = handlers.concat(getters[i](this)); |
| + } catch (e) { |
| + } |
| + } |
| + return handlers; |
| + |
| + /** |
| + * @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; |
| + } |
| + |
| + /** |
| + * @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; |
| + } |
| +} |