cloning javascript event object

Solution 1:

Above code will not copy any getters/setters properly. Try:

function cloneEvent(e) {
    if (e===undefined || e===null) return undefined;
    function ClonedEvent() {};  
    let clone=new ClonedEvent();
    for (let p in e) {
        let d=Object.getOwnPropertyDescriptor(e, p);
        if (d && (d.get || d.set)) Object.defineProperty(clone, p, d); else clone[p] = e[p];
    }
    Object.setPrototypeOf(clone, e);
    return clone;
}

Solution 2:

For your purposes I'd just make it a prototype of a new object constructor and override the ones you want changed. Cloning in JS gets messy due to the circular reference issue so it may not be the quick and dirty solution you were hoping for.

function cloneEventObj(eventObj, overrideObj){

   if(!overrideObj){ overrideObj = {}; }

   function EventCloneFactory(overProps){
       for(var x in overProps){
           this[x] = overProps[x];
       }
    }

    EventCloneFactory.prototype = eventObj;

    return new EventCloneFactory(overrideObj);

}

//So add your override properties via an object
$el.click(function(e){
    var newEventObj = cloneEventObj(
        e,
        { target:document.body }
    );
    doSomething(newEventObj);
});

//or just stick 'em on manually after spitting the object out
/*...
var newEventObj = cloneEventObj(e);
newEventObj.target = document.body
...*/

In this case the 'cloned' object is the prototype object of the new object. 'this.' properties are checked for before the prototype object so these will override. Or you could just attach properties after the object is built.

Solution 3:

Option 1: Making a new event with modification

You could make an Object.assign-alike using proxies and construct a new event without modifying the original event

Example:

function EventModifier (evt, obj) {
  const proxy = new Proxy(evt, {
    get: (target, prop) => obj[prop] || target[prop]
  })
  return new evt.constructor(evt.type, proxy)
}

onclick = evt => {
  evt = new EventModifier(evt, { altKey: true })
  // Dispatch the new event on something else
  console.log('clicked with alt key:', evt.altKey) // always true
}

This way you will use the same options as the original event that includes bubble, cancelable, key modifier, etc (doe it don't include any target as you are meant to dispatch the modified event on something else)

Option 2: Define new properties

Keeping the original event but override a key using Object.defineProperty you could use defineProperties if you want to add more than just one.

onclick = evt => {
  Object.defineProperty(evt, 'target', { value: document.querySelector('script') })
  console.log('target:', evt.target)
}