javascript - Obtener los escuchadores de eventos adjuntos a un nodo usando addEventListener
Ya he mirado estas preguntas:
- ¿Cómo encontrar los escuchadores de eventos en un nodo DOM al depurar o desde el código JavaScript?
- ¿Puedo examinar y modificar programáticamente los controladores de eventos de Javascript en elementos HTML?
- Cómo depurar enlaces de eventos de JavaScript/jQuery con Firebug (o herramienta similar)
sin embargo, ninguno de ellos responde cómo obtener una lista de los oyentes de eventos adjuntos a un nodo usando addEventListener, sin modificar el prototipo de addEventListener antes de que se creen los oyentes de eventos.
VisualEvent no muestra todos los escuchadores de eventos (específicos de iPhone) y quiero hacer esto (algo) programáticamente.
Respuesta #1
Chrome DevTools, Safari Inspector y Firebug soportan getEventListeners(node).
Respuesta #2
No puedes.
La única manera de obtener una lista de todos los oyentes de eventos adjuntos a un nodo es interceptar la llamada de asignación del oyente.
DOM4 addEventListener
Dice
Agrega un oyente de eventos a la lista asociada de oyentes de eventos con el tipo establecido en type, el oyente establecido en listener y la captura establecida en capture, a menos que ya exista un oyente de eventos en esa lista con el mismo tipo, oyente y captura.
Significando que se agrega un listener de eventos a la "lista de listeners de eventos". Eso es todo. No existe ninguna noción de cuál debería ser esta lista ni de cómo deberías acceder a ella.
Respuesta #3
Dado que no hay una manera nativa de hacer esto, aquí está la solución menos intrusiva que encontré (no agregues ningún método de prototipo 'antiguo'):
var ListenerTracker=new function(){
var targets=[];
// listener tracking datas
var _elements_ =[];
var _listeners_ =[];
this.init=function(){
this.listen(Element,window);
};
this.listen=function(){
for(var i=0;i<arguments.length;i++){
if(targets.indexOf(arguments[i])===-1){
targets.push(arguments[i]);//avoid duplicate call
intercep_events_listeners(arguments[i]);
}
}
};
// register individual element an returns its corresponding listeners
var register_element=function(element){
if(_elements_.indexOf(element)==-1){
// NB : split by useCapture to make listener easier to find when removing
var elt_listeners=[{/*useCapture=false*/},{/*useCapture=true*/}];
_elements_.push(element);
_listeners_.push(elt_listeners);
}
return _listeners_[_elements_.indexOf(element)];
};
var intercep_events_listeners = function(target){
var _target=target;
if(target.prototype)_target=target.prototype;
if(_target.getEventListeners)return;
if(typeof(_target.addEventListener)!=='function'||typeof(_target.removeEventListener)!=='function'){
console.log('target=',target);
throw('\nListenerTracker Error:\nUnwrappable target.');
}
// backup overrided methods
var _super_={
"addEventListener" : _target.addEventListener,
"removeEventListener" : _target.removeEventListener
};
_target["addEventListener"]=function(type, listener, useCapture){
var listeners=register_element(this);
// add event before to avoid registering if an error is thrown
_super_["addEventListener"].apply(this,arguments);
// adapt to 'elt_listeners' index
var uc=(typeof(useCapture)==='object'?useCapture.useCapture:useCapture)?1:0;
if(!listeners[uc][type])listeners[uc][type]=[];
listeners[uc][type].push({cb:listener,args:arguments});
};
_target["removeEventListener"]=function(type, listener, useCapture){
var listeners=register_element(this);
// add event before to avoid registering if an error is thrown
_super_["removeEventListener"].apply(this,arguments);
// adapt to 'elt_listeners' index
useCapture=(typeof(useCapture)==='object'?useCapture.useCapture:useCapture)?1:0;
if(!listeners[useCapture][type])return;
var lid = listeners[useCapture][type].findIndex(obj=>obj.cb===listener);
if(lid>-1)listeners[useCapture][type].splice(lid,1);
};
_target["getEventListeners"]=function(type){
var listeners=register_element(this);
// convert to listener datas list
var result=[];
for(var useCapture=0,list;list=listeners[useCapture];useCapture++){
if(typeof(type)=="string"){// filtered by type
if(list[type]){
for(var id in list[type]){
result.push({
"type":type,
"listener":list[type][id].cb,
"args":list[type][id].args,
"useCapture":!!useCapture
});
}
}
}else{// all
for(var _type in list){
for(var id in list[_type]){
result.push({
"type":_type,
"listener":list[_type][id].cb,
"args":list[_type][id].args,
"useCapture":!!useCapture
});
}
}
}
}
return result;
};
};
}();
ListenerTracker.init();
EDITAR
Sugerencia de @mplungjan: modificado para escuchar objetivos envolvibles (singleton|constructor). 'init' sigue Element y window.
ejemplo con otro objetivo envolvible:
ListenerTracker.listen(XMLHttpRequest);
Sugerencia de @kodfire: Puedes obtener argumentos opcionales con la propiedad args.
