The issue

We currently lack effective methods to avoid collisions between different event behaviours.

If one module sets an onclick behaviour for an element like this

  elt.on click = function() { alert('hello');};

, it may be overwriting a behaviour added already by a different module, or may itself be overwridden.

Current approach

In our current drupal.js, we use workarounds for two specific cases of attaching events: the window.onload event and the onsubmit event of forms. Functions addSubmitEvent and addLoadEvent basically string together the new event with any existing event. They more or less work, but somewhat awkwardly, and of course only for load and submit events. They don't provide a way of removing events.

Options

The obvious solution is the standards-compliant addEventListener method, which allows us to attach more than one behaviour to a given page element.

The problem is that IE doesn't support addEventListener. Hence the common approach of substituting IE's (more limited) proprietary method, attachEvent.

Draft solution

So here (in the attached patch) is a draft solution. I've added addEvent and removeEvent methods, using addEventListener where available and attachEvent where needed. I've removed addLoadEvent and addSubmitEvent and replaced their calls with calls to addEvent. Some quick testing in IE and Firefox suggests this should work.

Issues

But there are remaining issues, mainly that IE loses the this target element reference on behaviours attached with attachEvent, see this contest.

The best solution may simply be to use event object target detection, so we explicitly fetch the target of events before acting on them. So I've included a returnTarget() method.

I've adapted addEvent() and returnTarget()from another open source project I participate in, Community Mapbuilder, where they've been working away without issues.

Using this or a similar solution would help streamline our code and prevent collisions as different modules each attach behaviours.

CommentFileSizeAuthor
js-event-listeners.patch4.42 KBnedjo
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Steven’s picture

How does addEventListener deal with events that need to return values (such as onSubmit)?

Thox’s picture

Peter-Paul Koch (quirksmode.org) held a content to decide what was the best way to add events with cross browser compatibility, minimal code, and without memory leaks. Here's the "winner" - which was debated in the comments:

http://www.quirksmode.org/blog/archives/2005/10/_and_the_winner_1.html

nedjo’s picture

Thanks for these initial comments.

Steven, I'm thinking that addEventListener just attaches the events and so isn't directly involved in the returned values. Return values should come back just the same as when attaching through elt.on-change = functionName. Can you think of a specific example that maybe I could test?

Thox, the main issue addressed by the quirksmode contest seemed to be the loss of an object reference in the IE attachEvent. I tend just to fetch the reference explicitly as the event target when I need one. So, using the returnTarget() function in the above patch, we might use something like:


var img = document.getElementById('test-image');
addEvent(img, 'click', showSource);

function showSource(evt) {
  var img = returnTarget(evt);
  alert('source: ' + img.src);
}

But maybe I'm just lazily trying not to have to follow the intricacies of the quirksmode debates :)

ChrisKennedy’s picture

Version: x.y.z » 5.x-dev
Status: Needs review » Fixed

Not an issue anymore now that jQuery is in core.

Anonymous’s picture

Status: Fixed » Closed (fixed)