Search code examples
javascripteventsdompolymeraddeventlistener

How to prevent Google Polymer from changing event.target?


I've been playing around with the Google Polymer Shop demo and noticed that polymer systematically changes DOM event targets to the top-level component (in this case <shop-app>).

  1. Go to https://shop.polymer-project.org/
  2. Open the console
  3. Paste the below event listener

document.addEventListener('click', function(event){ console.log('DOM click event target:',event.target); });

  1. Click around the demo and look at the console log

As you can see, polymer systematically returns <shop-app> as an event.target even if you click different elements:

enter image description here

The problem with this behaviour is that it breaks all external JavaScript libraries which use event listeners to retrieve information about the original event target (all they see is <shop-app> all the time).

As a workaround, I've been trying to retrieve the original event target (Polymer.dom(event).path[0]) and dispatch a new event with it (https://pastebin.com/WKhGMrfx) but for some reason, my new event doesn't dispatch (I know I would end up with duplicate events, but my external libraries would work as at least some of those events would have the proper - original - event target):

enter image description here

And my questions:

Q1: Is there a way to prevent polymer from overwriting event.target?

Q2: Is there a way to dispatch events with the original event target?


Solution

  • in this code event is not real event, but it is a cloned object

    function addEventListenerOverride(obj) {
        if(obj._addEventListener){
            obj.addEventListener = obj._addEventListener;
            obj.removeEventListener = obj._removeEventListener;
        }
        obj._addEventListener = obj.addEventListener;
        obj.addEventListener = function(a,b,c) {
            if(c==undefined)
                c=false;
            this._addEventListener(a,b,c);
            if(!this.eventListenerList)
                this.eventListenerList = {};
            if(!this.eventListenerList[a])
                this.eventListenerList[a] = [];
            //this.removeEventListener(a,b,c); // TODO - handle duplicates..
            this.eventListenerList[a].push({listener:b,useCapture:c});
        };
    
        obj.getEventListeners = function(a){
            if(!this.eventListenerList)
                this.eventListenerList = {};
            if(a==undefined)
                return this.eventListenerList;
            return this.eventListenerList[a];
        };
        obj.clearEventListeners = function(a){
            if(!this.eventListenerList)
                this.eventListenerList = {};
            if(a==undefined){
                for(var x in (this.getEventListeners()))
                    this.clearEventListeners(x);
                return;
            }
            var el = this.getEventListeners(a);
            if(el==undefined)
                return;
            for(var i = el.length - 1; i >= 0; --i) {
                var ev = el[i];
                this.removeEventListener(a, ev.listener, ev.useCapture);
            }
        };
    
        obj._removeEventListener = obj.removeEventListener;
        obj.removeEventListener = function(a,b,c) {
            if(c==undefined)
                c=false;
            this._removeEventListener(a,b,c);
            if(!this.eventListenerList)
                this.eventListenerList = {};
            if(!this.eventListenerList[a])
                this.eventListenerList[a] = [];
    
        // Find the event in the list
        for(var i=0;i<this.eventListenerList[a].length;i++){
            if(this.eventListenerList[a][i].listener==b, this.eventListenerList[a][i].useCapture==c){ // Hmm..
                this.eventListenerList[a].splice(i, 1);
                break;
            }
        }
        if(this.eventListenerList[a].length==0)
            delete this.eventListenerList[a];
        };
    }
    
    //addEventListenerOverride(Element.prototype);
    addEventListenerOverride(document);
    //addEventListenerOverride(document.body);
    
    
    
    function onDocumentClick(event){
        if(event.isCustomized)
            return
        event.stopPropagation();
        //event.preventDefault();
        event.stopImmediatePropagation();
        var normalizedEvent = Polymer.dom(event);
    
        var eventClone = {};
        for(var c in event){
            eventClone[c] = event[c];
        }
    
        eventClone.target = normalizedEvent.rootTarget;
        eventClone.isCustomized = true;
        var eventType = event.type;
    
        console.log("target should be: ", eventClone.target)
    
        var listeners = document.getEventListeners(eventType);
        if(listeners && listeners.length){
            for(var i=0; i<listeners.length;i++){
                listeners[i].listener(eventClone)
            }
        }
    }
    document.addEventListener('click', onDocumentClick);
    
    document.addEventListener('click', function(event){
        console.log('DOM click event:', event, 'target:', event.target);
    });