frontend/devtools/components/EventListenersUtils.js
function frameworkEventListeners()
    {
        var errorLines = [];
        var eventListeners = [];
        var internalHandlers = [];
        var fetchers = [jQueryFetcher];
        try {
            if (self.devtoolsFrameworkEventListeners && isArrayLike(self.devtoolsFrameworkEventListeners))
                fetchers = fetchers.concat(self.devtoolsFrameworkEventListeners);
        } catch (e) {
            errorLines.push("devtoolsFrameworkEventListeners call produced error: " + toString(e));
        }

        for (var i = 0; i < fetchers.length; ++i) {
            try {
                var fetcherResult = fetchers[i](this);
                if (fetcherResult.eventListeners && isArrayLike(fetcherResult.eventListeners)) {
                    eventListeners = eventListeners.concat(fetcherResult.eventListeners.map(checkEventListener).filter(nonEmptyObject));
                }
                if (fetcherResult.internalHandlers && isArrayLike(fetcherResult.internalHandlers))
                    internalHandlers = internalHandlers.concat(fetcherResult.internalHandlers.map(checkInternalHandler).filter(nonEmptyObject));
            } catch (e) {
                errorLines.push("fetcher call produced error: " + toString(e));
            }
        }
        var result = {eventListeners: eventListeners};
        if (internalHandlers.length)
            result.internalHandlers = internalHandlers;
        if (errorLines.length) {
            var errorString = "Framework Event Listeners API Errors:\n\t" + errorLines.join("\n\t");
            errorString = errorString.substr(0, errorString.length - 1);
            result.errorString = errorString;
        }
        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;
        }

        /**
         * @param {*} eventListener
         * @return {?WebInspector.EventListenerObjectInInspectedPage}
         */
        function checkEventListener(eventListener)
        {
            try {
                var errorString = "";
                if (!eventListener)
                    errorString += "empty event listener, ";
                var type = eventListener.type;
                if (!type || (typeof type !== "string"))
                    errorString += "event listener's type isn't string or empty, ";
                var useCapture = eventListener.useCapture;
                if (typeof useCapture !== "boolean")
                    errorString += "event listener's useCapture isn't boolean or undefined, ";
                var passive = eventListener.passive;
                if (typeof passive !== "boolean")
                    errorString += "event listener's passive isn't boolean or undefined, ";
                var handler = eventListener.handler;
                if (!handler || (typeof handler !== "function"))
                    errorString += "event listener's handler isn't a function or empty, ";
                var remove = eventListener.remove;
                if (remove && (typeof remove !== "function"))
                    errorString += "event listener's remove isn't a function, ";
                if (!errorString){
                    return {type: type, useCapture: useCapture, passive: passive, handler: handler, remove: remove};
                } else {
                    errorLines.push(errorString.substr(0, errorString.length - 2));
                    return null;
                }
            } catch (e) {
                errorLines.push(toString(e));
                return null;
            }
        }

        /**
         * @param {*} handler
         * @return {function()|null}
         */
        function checkInternalHandler(handler)
        {
            if (handler && (typeof handler === "function"))
                return handler;
            errorLines.push("internal handler isn't a function or empty");
            return null;
        }

        /**
         * @param {*} obj
         * @return {string}
         * @suppress {uselessCode}
         */
        function toString(obj)
        {
            try {
                return "" + obj;
            } catch (e) {
                return "<error>";
            }
        }

        /**
         * @param {*} obj
         * @return {boolean}
         */
        function nonEmptyObject(obj)
        {
            return !!obj;
        }

        function jQueryFetcher(node)
        {
            if (!node || !(node instanceof Node))
                return {eventListeners: []};
            var jQuery = /** @type {?{fn,data,_data}}*/(window["jQuery"]);
            if (!jQuery || !jQuery.fn)
                return {eventListeners: []};
            var jQueryFunction = /** @type {function(!Node)} */(jQuery);
            var data = jQuery._data || jQuery.data;

            var eventListeners = [];
            var internalHandlers = [];

            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,
                                passive: false,
                                type: type
                            };
                            listener.remove = jQueryRemove.bind(node, frameworkListener.selector);
                            eventListeners.push(listener);
                        }
                    }
                }
                var nodeData = data(node);
                if (nodeData && typeof nodeData.handle === "function")
                    internalHandlers.push(nodeData.handle);
            }
            var entry = jQueryFunction(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,
                                passive: false,
                                type: type
                            };
                            // We don't support removing for old version < 1.4 of jQuery because it doesn't provide API for getting "selector".
                            eventListeners.push(listener);
                        }
                    }
                }
                if (entry && entry["$handle"])
                    internalHandlers.push(entry["$handle"]);
            }
            return {eventListeners: eventListeners, internalHandlers: internalHandlers};
        }

        /**
         * @param {string} selector
         * @param {string} type
         * @param {function()} handler
         * @this {?Object}
         */
        function jQueryRemove(selector, type, handler)
        {
            if (!this || !(this instanceof Node))
                return;
            var node = /** @type {!Node} */(this);
            var jQuery = /** @type {?{fn,data,_data}}*/(window["jQuery"]);
            if (!jQuery || !jQuery.fn)
                return;
            var jQueryFunction = /** @type {function(!Node)} */(jQuery);
            jQueryFunction(node).off(type, selector, handler);
        }
    }
function frameworkEventListeners()
    {
        var errorLines = [];
        var eventListeners = [];
        var internalHandlers = [];
        var fetchers = [jQueryFetcher];
        try {
            if (self.devtoolsFrameworkEventListeners && isArrayLike(self.devtoolsFrameworkEventListeners))
                fetchers = fetchers.concat(self.devtoolsFrameworkEventListeners);
        } catch (e) {
            errorLines.push("devtoolsFrameworkEventListeners call produced error: " + toString(e));
        }

        for (var i = 0; i < fetchers.length; ++i) {
            try {
                var fetcherResult = fetchers[i](this);
                if (fetcherResult.eventListeners && isArrayLike(fetcherResult.eventListeners)) {
                    eventListeners = eventListeners.concat(fetcherResult.eventListeners.map(checkEventListener).filter(nonEmptyObject));
                }
                if (fetcherResult.internalHandlers && isArrayLike(fetcherResult.internalHandlers))
                    internalHandlers = internalHandlers.concat(fetcherResult.internalHandlers.map(checkInternalHandler).filter(nonEmptyObject));
            } catch (e) {
                errorLines.push("fetcher call produced error: " + toString(e));
            }
        }
        var result = {eventListeners: eventListeners};
        if (internalHandlers.length)
            result.internalHandlers = internalHandlers;
        if (errorLines.length) {
            var errorString = "Framework Event Listeners API Errors:\n\t" + errorLines.join("\n\t");
            errorString = errorString.substr(0, errorString.length - 1);
            result.errorString = errorString;
        }
        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;
        }

        /**
         * @param {*} eventListener
         * @return {?WebInspector.EventListenerObjectInInspectedPage}
         */
        function checkEventListener(eventListener)
        {
            try {
                var errorString = "";
                if (!eventListener)
                    errorString += "empty event listener, ";
                var type = eventListener.type;
                if (!type || (typeof type !== "string"))
                    errorString += "event listener's type isn't string or empty, ";
                var useCapture = eventListener.useCapture;
                if (typeof useCapture !== "boolean")
                    errorString += "event listener's useCapture isn't boolean or undefined, ";
                var passive = eventListener.passive;
                if (typeof passive !== "boolean")
                    errorString += "event listener's passive isn't boolean or undefined, ";
                var handler = eventListener.handler;
                if (!handler || (typeof handler !== "function"))
                    errorString += "event listener's handler isn't a function or empty, ";
                var remove = eventListener.remove;
                if (remove && (typeof remove !== "function"))
                    errorString += "event listener's remove isn't a function, ";
                if (!errorString){
                    return {type: type, useCapture: useCapture, passive: passive, handler: handler, remove: remove};
                } else {
                    errorLines.push(errorString.substr(0, errorString.length - 2));
                    return null;
                }
            } catch (e) {
                errorLines.push(toString(e));
                return null;
            }
        }

        /**
         * @param {*} handler
         * @return {function()|null}
         */
        function checkInternalHandler(handler)
        {
            if (handler && (typeof handler === "function"))
                return handler;
            errorLines.push("internal handler isn't a function or empty");
            return null;
        }

        /**
         * @param {*} obj
         * @return {string}
         * @suppress {uselessCode}
         */
        function toString(obj)
        {
            try {
                return "" + obj;
            } catch (e) {
                return "<error>";
            }
        }

        /**
         * @param {*} obj
         * @return {boolean}
         */
        function nonEmptyObject(obj)
        {
            return !!obj;
        }

        function jQueryFetcher(node)
        {
            if (!node || !(node instanceof Node))
                return {eventListeners: []};
            var jQuery = /** @type {?{fn,data,_data}}*/(window["jQuery"]);
            if (!jQuery || !jQuery.fn)
                return {eventListeners: []};
            var jQueryFunction = /** @type {function(!Node)} */(jQuery);
            var data = jQuery._data || jQuery.data;

            var eventListeners = [];
            var internalHandlers = [];

            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,
                                passive: false,
                                type: type
                            };
                            listener.remove = jQueryRemove.bind(node, frameworkListener.selector);
                            eventListeners.push(listener);
                        }
                    }
                }
                var nodeData = data(node);
                if (nodeData && typeof nodeData.handle === "function")
                    internalHandlers.push(nodeData.handle);
            }
            var entry = jQueryFunction(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,
                                passive: false,
                                type: type
                            };
                            // We don't support removing for old version < 1.4 of jQuery because it doesn't provide API for getting "selector".
                            eventListeners.push(listener);
                        }
                    }
                }
                if (entry && entry["$handle"])
                    internalHandlers.push(entry["$handle"]);
            }
            return {eventListeners: eventListeners, internalHandlers: internalHandlers};
        }

        /**
         * @param {string} selector
         * @param {string} type
         * @param {function()} handler
         * @this {?Object}
         */
        function jQueryRemove(selector, type, handler)
        {
            if (!this || !(this instanceof Node))
                return;
            var node = /** @type {!Node} */(this);
            var jQuery = /** @type {?{fn,data,_data}}*/(window["jQuery"]);
            if (!jQuery || !jQuery.fn)
                return;
            var jQueryFunction = /** @type {function(!Node)} */(jQuery);
            jQueryFunction(node).off(type, selector, handler);
        }
    }
function frameworkEventListeners ( ) { var errorLines = [ ] ; var eventListeners = [ ] ; var internalHandlers = [ ] ; var fetchers = [ jQueryFetcher ] ; try { if ( self . devtoolsFrameworkEventListeners && isArrayLike ( self . devtoolsFrameworkEventListeners ) ) fetchers = fetchers . concat ( self . devtoolsFrameworkEventListeners ) ; } catch ( e ) { errorLines . push ( "devtoolsFrameworkEventListeners call produced error: " + toString ( e ) ) ; } for ( var i = 0 ; i < fetchers . length ; ++ i ) { try { var fetcherResult = fetchers [ i ] ( this ) ; if ( fetcherResult . eventListeners && isArrayLike ( fetcherResult . eventListeners ) ) { eventListeners = eventListeners . concat ( fetcherResult . eventListeners . map ( checkEventListener ) . filter ( nonEmptyObject ) ) ; } if ( fetcherResult . internalHandlers && isArrayLike ( fetcherResult . internalHandlers ) ) internalHandlers = internalHandlers . concat ( fetcherResult . internalHandlers . map ( checkInternalHandler ) . filter ( nonEmptyObject ) ) ; } catch ( e ) { errorLines . push ( "fetcher call produced error: " + toString ( e ) ) ; } } var result = { eventListeners : eventListeners } ; if ( internalHandlers . length ) result . internalHandlers = internalHandlers ; if ( errorLines . length ) { var errorString = "Framework Event Listeners API Errors:\n\t" + errorLines . join ( "\n\t" ) ; errorString = errorString . substr ( 0 , errorString . length - 1 ) ; result . errorString = errorString ; } 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 ; } /**
         * @param {*} eventListener
         * @return {?WebInspector.EventListenerObjectInInspectedPage}
         */ function checkEventListener ( eventListener ) { try { var errorString = "" ; if ( ! eventListener ) errorString += "empty event listener, " ; var type = eventListener . type ; if ( ! type || ( typeof type !== "string" ) ) errorString += "event listener's type isn't string or empty, " ; var useCapture = eventListener . useCapture ; if ( typeof useCapture !== "boolean" ) errorString += "event listener's useCapture isn't boolean or undefined, " ; var passive = eventListener . passive ; if ( typeof passive !== "boolean" ) errorString += "event listener's passive isn't boolean or undefined, " ; var handler = eventListener . handler ; if ( ! handler || ( typeof handler !== "function" ) ) errorString += "event listener's handler isn't a function or empty, " ; var remove = eventListener . remove ; if ( remove && ( typeof remove !== "function" ) ) errorString += "event listener's remove isn't a function, " ; if ( ! errorString ) { return { type : type , useCapture : useCapture , passive : passive , handler : handler , remove : remove } ; } else { errorLines . push ( errorString . substr ( 0 , errorString . length - 2 ) ) ; return null ; } } catch ( e ) { errorLines . push ( toString ( e ) ) ; return null ; } } /**
         * @param {*} handler
         * @return {function()|null}
         */ function checkInternalHandler ( handler ) { if ( handler && ( typeof handler === "function" ) ) return handler ; errorLines . push ( "internal handler isn't a function or empty" ) ; return null ; } /**
         * @param {*} obj
         * @return {string}
         * @suppress {uselessCode}
         */ function toString ( obj ) { try { return "" + obj ; } catch ( e ) { return "<error>" ; } } /**
         * @param {*} obj
         * @return {boolean}
         */ function nonEmptyObject ( obj ) { return ! ! obj ; } function jQueryFetcher ( node ) { if ( ! node || ! ( node instanceof Node ) ) return { eventListeners : [ ] } ; var jQuery = /** @type {?{fn,data,_data}}*/ ( window [ "jQuery" ] ) ; if ( ! jQuery || ! jQuery . fn ) return { eventListeners : [ ] } ; var jQueryFunction = /** @type {function(!Node)} */ ( jQuery ) ; var data = jQuery . _data || jQuery . data ; var eventListeners = [ ] ; var internalHandlers = [ ] ; 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 , passive : false , type : type } ; listener . remove = jQueryRemove . bind ( node , frameworkListener . selector ) ; eventListeners . push ( listener ) ; } } } var nodeData = data ( node ) ; if ( nodeData && typeof nodeData . handle === "function" ) internalHandlers . push ( nodeData . handle ) ; } var entry = jQueryFunction ( 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 , passive : false , type : type } ; // We don't support removing for old version < 1.4 of jQuery because it doesn't provide API for getting "selector". eventListeners . push ( listener ) ; } } } if ( entry && entry [ "$handle" ] ) internalHandlers . push ( entry [ "$handle" ] ) ; } return { eventListeners : eventListeners , internalHandlers : internalHandlers } ; } /**
         * @param {string} selector
         * @param {string} type
         * @param {function()} handler
         * @this {?Object}
         */ function jQueryRemove ( selector , type , handler ) { if ( ! this || ! ( this instanceof Node ) ) return ; var node = /** @type {!Node} */ ( this ) ; var jQuery = /** @type {?{fn,data,_data}}*/ ( window [ "jQuery" ] ) ; if ( ! jQuery || ! jQuery . fn ) return ; var jQueryFunction = /** @type {function(!Node)} */ ( jQuery ) ; jQueryFunction ( node ) . off ( type , selector , handler ) ; } }
/*
frameworkEventListeners fetcher functions should produce following output:
{
framework event listeners
"eventListeners": [
{
"handler": function(),
"useCapture": true,
"passive": false,
"type": "change",
"remove": function(type, handler, useCapture, passive)
},
...
],
internal framework event handlers
"internalHandlers": [
function(),
function(),
...
]
}
 
@suppressReceiverCheck
@return {!{eventListeners:!Array<!WebInspector.EventListenerObjectInInspectedPage>, internalHandlers:?Array<function()>}}
@this {Object}
/ * frameworkEventListeners fetcher functions should produce following output : { framework event listeners eventListeners : [ { handler : function () useCapture : true passive : false type : change remove : function ( type handler useCapture passive ) } ... ] internal framework event handlers internalHandlers : [ function () function () ... ] }