choojs / nanomorph

🚅 - Hyper fast diffing algorithm for real DOM nodes

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

copy over events

yoshuawuyts opened this issue · comments

commented

Whenever we morph elements we should probs be copying over the events. From yo-yo:

// update-events.js
module.exports = [
  // attribute events (can be set with attributes)
  'onclick',
  'ondblclick',
  'onmousedown',
  'onmouseup',
  'onmouseover',
  'onmousemove',
  'onmouseout',
  'ondragstart',
  'ondrag',
  'ondragenter',
  'ondragleave',
  'ondragover',
  'ondrop',
  'ondragend',
  'onkeydown',
  'onkeypress',
  'onkeyup',
  'onunload',
  'onabort',
  'onerror',
  'onresize',
  'onscroll',
  'onselect',
  'onchange',
  'onsubmit',
  'onreset',
  'onfocus',
  'onblur',
  'oninput',
  // other common events
  'oncontextmenu',
  'onfocusin',
  'onfocusout'
]
// copy.js
  function copier (f, t) {
    // copy events:
    var events = opts.events || defaultEvents
    for (var i = 0; i < events.length; i++) {
      var ev = events[i]
      if (t[ev]) { // if new element has a whitelisted attribute
        f[ev] = t[ev] // update existing element
      } else if (f[ev]) { // if existing element has it and new one doesnt
        f[ev] = undefined // remove it from existing element
      }
    }
    // copy values for form elements
    if ((f.nodeName === 'INPUT' && f.type !== 'file') || f.nodeName === 'TEXTAREA' || f.nodeName === 'SELECT') {
      if (t.getAttribute('value') === null) t.value = f.value
    }
  }

How would you plan to make this customizable? Assembling a list of custom events to pass to the differ is a pain and it's pretty much impossible to maintain an authoritative list when you consider browser differences.

What do you think about initially iterating over an element once (even document.body) and getting a list of keys that match /^on/?

On Chrome that gets me:

["onblur", "onerror", "onfocus", "onload", "onresize", "onscroll", "onbeforeunload", "onhashchange", "onlanguagechange", "onmessage", "onoffline", "ononline", "onpagehide", "onpageshow", "onpopstate", "onstorage", "onunload", "onrejectionhandled", "onunhandledrejection", "onabort", "oncancel", "oncanplay", "oncanplaythrough", "onchange", "onclick", "onclose", "oncontextmenu", "oncuechange", "ondblclick", "ondrag", "ondragend", "ondragenter", "ondragleave", "ondragover", "ondragstart", "ondrop", "ondurationchange", "onemptied", "onended", "oninput", "oninvalid", "onkeydown", "onkeypress", "onkeyup", "onloadeddata", "onloadedmetadata", "onloadstart", "onmousedown", "onmouseenter", "onmouseleave", "onmousemove", "onmouseout", "onmouseover", "onmouseup", "onmousewheel", "onpause", "onplay", "onplaying", "onprogress", "onratechange", "onreset", "onseeked", "onseeking", "onselect", "onshow", "onstalled", "onsubmit", "onsuspend", "ontimeupdate", "ontoggle", "onvolumechange", "onwaiting", "onbeforecopy", "onbeforecut", "onbeforepaste", "oncopy", "oncut", "onpaste", "onsearch", "onselectstart", "onwheel", "onwebkitfullscreenchange", "onwebkitfullscreenerror"]

The only existing events not caught by that method:

["onfocusin", "onfocusout"]
commented

Looks like you can copy over only the events being used by an element, but it requires looping over the elements keys. That may be faster than iterating over a longer list of event types, but I am not sure. https://github.com/kristoferjoseph/nanomorph/blob/master/morph.js#L16

commented

We could take a page out of the backbone playbook and allow the user to pass in an events array as an option.

commented

I kinda like the initial approach you took for that; looping over ^on should be fast-ish I think hmmm - it's hard to tell without having benches

If it's only done on a single element and then cached there shouldn't be any meaningful perf difference. That assumes all elements are identical and caching document.body would get the same results as iterating through any other element. I'm not actually sure that's true, haven't tested it.

commented

Hmm interesting thought. Not sure how we would go about doing that without holding onto a reference internally since update is handed two previously created nodes it seems like we would have to run this loop on every update otherwise.

commented

@kristoferjoseph looping should be rare tho; if we implement morphdom's .isSameNode() trick then only the hot path will ever be looped for equal nodes only which even pessimistically isn't that many nodes.

Optimistically it should be fine I think; doing the existing approach of yo-yo we're already miles ahead of every rendering engine in terms of perf so I'm not too worried for real world perf, even though from a purist standpoint I wholly agree with what you're saying - maybe mark it as something to revisit later?

commented

This should work now! ✨