test(browserTrigger): allow event bubbling

In some browsers, events don't bubble when they are dispatched on node inside
a detached tree. When this is the case, the bubbling is made manually.
This may be convenient when unit testing directives, for example.

Closes #5178
This commit is contained in:
Peter Bacon Darwin
2016-06-06 11:44:48 +01:00
parent 3ba8bb7109
commit c8bfbfc5d7
+54 -1
View File
@@ -119,7 +119,12 @@
return originalPreventDefault.apply(evnt, arguments);
};
element.dispatchEvent(evnt);
if (!eventData.bubbles || supportsEventBubblingInDetachedTree() || isAttachedToDocument(element)) {
element.dispatchEvent(evnt);
} else {
triggerForPath(element, evnt);
}
finalProcessDefault = !(angular['ff-684208-preventDefault'] || !fakeProcessDefault);
delete angular['ff-684208-preventDefault'];
@@ -157,4 +162,52 @@
return evnt;
}
function supportsEventBubblingInDetachedTree() {
if ('_cached' in supportsEventBubblingInDetachedTree) {
return supportsEventBubblingInDetachedTree._cached;
}
supportsEventBubblingInDetachedTree._cached = false;
var doc = window.document;
if (doc) {
var parent = doc.createElement('div'),
child = parent.cloneNode();
parent.appendChild(child);
parent.addEventListener('e', function() {
supportsEventBubblingInDetachedTree._cached = true;
});
var evnt = window.document.createEvent('Events');
evnt.initEvent('e', true, true);
child.dispatchEvent(evnt);
}
return supportsEventBubblingInDetachedTree._cached;
}
function triggerForPath(element, evnt) {
var stop = false;
var _stopPropagation = evnt.stopPropagation;
evnt.stopPropagation = function() {
stop = true;
_stopPropagation.apply(evnt, arguments);
};
patchEventTargetForBubbling(evnt, element);
do {
element.dispatchEvent(evnt);
} while (!stop && (element = element.parentNode));
}
function patchEventTargetForBubbling(event, target) {
event._target = target;
Object.defineProperty(event, "target", {get: function() { return this._target;}});
}
function isAttachedToDocument(element) {
while (element = element.parentNode) {
if (element === window) {
return true;
}
}
return false;
}
}());