Skip to content

Commit c0b10d0

Browse files
committed
fix($animateQueue): handle listeners on containers without a .contains() method
When registering an animation listener (via `$animate.on()`), the container's `.contains()` method was used to determine if the animated element is a child of the container. This resulted in errors in IE, when `document` was used as a container, because IE does not define `.contains()` on `Node`'s prototype (as prescribed by the spec), but on `HTMLElement`'s prototype instead. This is not an issue on other DOM elements, because they inherit from both `Node` and `HTMLElement`, but it is on `document`, which is not an instance of `HTMLElement`. This change provides a way to determine if the animated element is a child of the container, even if the latter does not have a `.contains()` method. Fixes angular#13548
1 parent f7eab8d commit c0b10d0

File tree

2 files changed

+30
-2
lines changed

2 files changed

+30
-2
lines changed

src/ngAnimate/animateQueue.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,9 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
179179
var entries = callbackRegistry[event];
180180
if (entries) {
181181
forEach(entries, function(entry) {
182-
if (entry.node.contains(targetNode)) {
182+
if (entry.contains(targetNode)) {
183183
matches.push(entry.callback);
184-
} else if (event === 'leave' && entry.node.contains(targetParentNode)) {
184+
} else if (event === 'leave' && entry.contains(targetParentNode)) {
185185
matches.push(entry.callback);
186186
}
187187
});
@@ -196,6 +196,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
196196
callbackRegistry[event] = callbackRegistry[event] || [];
197197
callbackRegistry[event].push({
198198
node: node,
199+
contains: (node.contains || fallbackContainsFn).bind(node),
199200
callback: callback
200201
});
201202
},
@@ -649,5 +650,12 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
649650
: details;
650651
activeAnimationsLookup.put(node, newValue);
651652
}
653+
654+
function fallbackContainsFn(arg) {
655+
//jshint bitwise: false, validthis: true
656+
return (this === arg) || !!(this.compareDocumentPosition(arg) & 16);
657+
//jshint bitwise: true, validthis: false
658+
}
659+
652660
}];
653661
}];

test/ngAnimate/animateSpec.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1620,6 +1620,26 @@ describe("animations", function() {
16201620
expect(callbackTriggered).toBe(true);
16211621
}));
16221622

1623+
it('should handle containers that do not have a `contains()` method (e.g. `document` on IE)',
1624+
inject(function($animate, $rootElement, $rootScope) {
1625+
var rootNode = $rootElement[0];
1626+
rootNode.contains = undefined;
1627+
1628+
var callbackTriggered = false;
1629+
1630+
$animate.on('enter', rootNode, function() {
1631+
callbackTriggered = true;
1632+
});
1633+
1634+
element = jqLite('<div></div>');
1635+
$animate.enter(element, $rootElement);
1636+
$rootScope.$digest();
1637+
$animate.flush();
1638+
1639+
expect(callbackTriggered).toBe(true);
1640+
})
1641+
);
1642+
16231643
it('should remove all the event-based event listeners when $animate.off(event) is called',
16241644
inject(function($animate, $rootScope, $rootElement, $document) {
16251645

0 commit comments

Comments
 (0)