Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

fix(ngAnimate): ensure animations are not attempted on text nodes #11803

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/ngAnimate/animateQueue.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,11 +221,14 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
};

function queueAnimation(element, event, options) {
var node, parent;
element = stripCommentsFromElement(element);
var node = element[0];
if (element) {
node = element[0];
parent = element.parent();
}

options = prepareAnimationOptions(options);
var parent = element.parent();

// we create a fake runner with a working promise.
// These methods will become available after the digest has passed
Expand All @@ -235,7 +238,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
// a jqLite wrapper that contains only comment nodes... If this
// happens then there is no way we can perform an animation
if (!node) {
runner.end();
close();
return runner;
}

Expand Down
31 changes: 21 additions & 10 deletions src/ngAnimate/shared.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,29 @@ function removeFromArray(arr, val) {
}

function stripCommentsFromElement(element) {
if (element.nodeType === ELEMENT_NODE) {
return jqLite(element);
if (element instanceof jqLite) {
switch (element.length) {
case 0:
return [];
break;

case 1:
// there is no point of stripping anything if the element
// is the only element within the jqLite wrapper.
// (it's important that we retain the element instance.)
if (element[0].nodeType === ELEMENT_NODE) {
return element;
}
break;

default:
return jqLite(extractElementNode(element));
break;
}
}
if (element.length === 0) return [];

// there is no point of stripping anything if the element
// is the only element within the jqLite wrapper.
// (it's important that we retain the element instance.)
if (element.length === 1) {
return element[0].nodeType === ELEMENT_NODE && element;
} else {
return jqLite(extractElementNode(element));
if (element.nodeType === ELEMENT_NODE) {
return jqLite(element);
}
}

Expand Down
41 changes: 41 additions & 0 deletions test/ngAnimate/animateSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,47 @@ describe("animations", function() {
expect(capturedAnimation).toBeFalsy();
}));

it('should not attempt to perform an animation on a text node element',
inject(function($rootScope, $animate) {

element.html('hello there');
var textNode = jqLite(element[0].firstChild);

$animate.addClass(textNode, 'some-class');
$rootScope.$digest();

expect(capturedAnimation).toBeFalsy();
}));

it('should perform the leave domOperation if a text node is used',
inject(function($rootScope, $animate) {

element.html('hello there');
var textNode = jqLite(element[0].firstChild);
var parentNode = textNode[0].parentNode;

$animate.leave(textNode);
$rootScope.$digest();
expect(capturedAnimation).toBeFalsy();
expect(textNode[0].parentNode).not.toBe(parentNode);
}));

it('should perform the leave domOperation if a comment node is used',
inject(function($rootScope, $animate, $document) {

var doc = $document[0];

element.html('hello there');
var commentNode = jqLite(doc.createComment('test comment'));
var parentNode = element[0];
parentNode.appendChild(commentNode[0]);

$animate.leave(commentNode);
$rootScope.$digest();
expect(capturedAnimation).toBeFalsy();
expect(commentNode[0].parentNode).not.toBe(parentNode);
}));

it('enter() should issue an enter animation and fire the DOM operation right away before the animation kicks off', inject(function($animate, $rootScope) {
expect(parent.children().length).toBe(0);

Expand Down