Skip to content
This repository has been archived by the owner on Mar 13, 2018. It is now read-only.

Commit

Permalink
Dispatch native events at all times
Browse files Browse the repository at this point in the history
If there are no listeners in a disconnected tree we add a temporary
listener on the target which allows us to take over later in the
process.

Fixes #335
  • Loading branch information
arv committed Dec 17, 2013
1 parent dbf6292 commit 496f0a7
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 1 deletion.
54 changes: 53 additions & 1 deletion src/wrappers/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -656,10 +656,62 @@
}
},
dispatchEvent: function(event) {
dispatchEvent(event, this);
// We want to use the native dispatchEvent because it triggers the default
// actions (like checking a checkbox). However, if there are no listeners
// in the composed tree then there are no events that will trigger and
// listeners in the non composed tree that are part of the event path are
// not notified.
//
// If we find out that there are no listeners in the composed tree we add
// a temporary listener to the target which makes us get called back even
// in that case.

var nativeEvent = unwrap(event);
var eventType = nativeEvent.type;

// Allow dispatching the same event again. This is safe because if user
// code calls this during an existing dispatch of the same event the
// native dispatchEvent throws (that is required by the spec).
handledEventsTable.set(nativeEvent, false);

// Force rendering since we prefer native dispatch and that works on the
// composed tree.
scope.renderAllPending();

var tempListener;
if (!hasListenerInAncestors(this, eventType)) {
tempListener = function() {};
this.addEventListener(eventType, tempListener, true);
}

try {
return unwrap(this).dispatchEvent_(nativeEvent);
} finally {
if (tempListener)
this.removeEventListener(eventType, tempListener, true);
}
}
};

function hasListener(node, type) {
var listeners = listenersTable.get(node);
if (listeners) {
for (var i = 0; i < listeners.length; i++) {
if (!listeners[i].removed && listeners[i].type === type)
return true;
}
}
return false;
}

function hasListenerInAncestors(target, type) {
for (var node = unwrap(target); node; node = node.parentNode) {
if (hasListener(wrap(node), type))
return true;
}
return false;
}

if (OriginalEventTarget)
registerWrapper(OriginalEventTarget, EventTarget);

Expand Down
24 changes: 24 additions & 0 deletions test/js/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -1361,4 +1361,28 @@ test('retarget order (multiple shadow roots)', function() {
assert.equal(data, 'b');
});

test('dispatch should trigger default actions', function() {
var div = document.createElement('div');
div.innerHTML = '<input type="checkbox">';
var checkbox = div.firstChild;
assert.isFalse(checkbox.checked);
checkbox.dispatchEvent(new MouseEvent('click'));
assert.isTrue(checkbox.checked);
});

test('dispatch should trigger default actions 2', function() {
var div = document.createElement('div');
div.innerHTML = '<input type="checkbox">';
var checkbox = div.firstChild;
var sr = div.createShadowRoot();

assert.isFalse(checkbox.checked);
checkbox.dispatchEvent(new MouseEvent('click'));
assert.isTrue(checkbox.checked);

div.offsetWidth;
checkbox.dispatchEvent(new MouseEvent('click'));
assert.isFalse(checkbox.checked);
});

});

0 comments on commit 496f0a7

Please sign in to comment.