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

Commit 25bddfa

Browse files
committed
remove when rootScope is destroyed, add + fix tests
1 parent 0d056cb commit 25bddfa

File tree

5 files changed

+69
-35
lines changed

5 files changed

+69
-35
lines changed

Diff for: src/ng/document.js

+14-4
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,27 @@ function $DocumentProvider() {
3232
}
3333

3434

35+
/**
36+
* @private
37+
* Listens for document visibility change and makes the current status accessible.
38+
*/
3539
function $$IsDocumentHiddenProvider() {
36-
this.$get = ['$document', function($document) {
40+
this.$get = ['$document', '$rootScope', function($document, $rootScope) {
3741
var doc = $document[0];
3842
var hidden = doc && doc.hidden;
3943

40-
$document.on('visibilitychange', function() {
41-
hidden = doc.hidden;
44+
$document.on('visibilitychange', changeListener);
45+
46+
$rootScope.$on('$destroy', function() {
47+
$document.off('visibilitychange', changeListener);
4248
});
4349

50+
function changeListener() {
51+
hidden = doc.hidden;
52+
}
53+
4454
return function() {
4555
return hidden;
4656
};
4757
}];
48-
}
58+
}

Diff for: src/ngAnimate/animateQueue.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -369,14 +369,14 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
369369

370370
var isStructural = ['enter', 'move', 'leave'].indexOf(event) >= 0;
371371

372-
var documentHidden = $document[0].hidden;
372+
var documentHidden = $$isDocumentHidden();
373373

374374
// this is a hard disable of all animations for the application or on
375375
// the element itself, therefore there is no need to continue further
376376
// past this point if not enabled
377377
// Animations are also disabled if the document is currently hidden (page is not visible
378378
// to the user), because browsers slow down or do not flush calls to requestAnimationFrame
379-
var skipAnimations = !animationsEnabled || $$isDocumentHidden() || disabledElementsLookup.get(node);
379+
var skipAnimations = !animationsEnabled || documentHidden || disabledElementsLookup.get(node);
380380
var existingAnimation = (!skipAnimations && activeAnimationsLookup.get(node)) || {};
381381
var hasExistingAnimation = !!existingAnimation.state;
382382

Diff for: test/ng/compileSpec.js

+21-22
Original file line numberDiff line numberDiff line change
@@ -7245,22 +7245,22 @@ describe('$compile', function() {
72457245
});
72467246

72477247
inject(function($compile, $rootScope) {
7248-
expect(jqLiteCacheSize()).toEqual(0);
7248+
var cacheSize = jqLiteCacheSize();
72497249

72507250
element = $compile('<div><div ng-repeat="x in xs" ng-if="x==1">{{x}}</div></div>')($rootScope);
7251-
expect(jqLiteCacheSize()).toEqual(1);
7251+
expect(jqLiteCacheSize()).toEqual(cacheSize + 1);
72527252

72537253
$rootScope.$apply('xs = [0,1]');
7254-
expect(jqLiteCacheSize()).toEqual(2);
7254+
expect(jqLiteCacheSize()).toEqual(cacheSize + 2);
72557255

72567256
$rootScope.$apply('xs = [0]');
7257-
expect(jqLiteCacheSize()).toEqual(1);
7257+
expect(jqLiteCacheSize()).toEqual(cacheSize + 1);
72587258

72597259
$rootScope.$apply('xs = []');
7260-
expect(jqLiteCacheSize()).toEqual(1);
7260+
expect(jqLiteCacheSize()).toEqual(cacheSize + 1);
72617261

72627262
element.remove();
7263-
expect(jqLiteCacheSize()).toEqual(0);
7263+
expect(jqLiteCacheSize()).toEqual(cacheSize + 0);
72647264
});
72657265
});
72667266

@@ -7277,22 +7277,22 @@ describe('$compile', function() {
72777277
});
72787278

72797279
inject(function($compile, $rootScope) {
7280-
expect(jqLiteCacheSize()).toEqual(0);
7280+
var cacheSize = jqLiteCacheSize();
72817281

72827282
element = $compile('<div><div ng-repeat="x in xs" ng-if="x==1">{{x}}</div></div>')($rootScope);
7283-
expect(jqLiteCacheSize()).toEqual(0);
7283+
expect(jqLiteCacheSize()).toEqual(cacheSize);
72847284

72857285
$rootScope.$apply('xs = [0,1]');
7286-
expect(jqLiteCacheSize()).toEqual(0);
7286+
expect(jqLiteCacheSize()).toEqual(cacheSize);
72877287

72887288
$rootScope.$apply('xs = [0]');
7289-
expect(jqLiteCacheSize()).toEqual(0);
7289+
expect(jqLiteCacheSize()).toEqual(cacheSize);
72907290

72917291
$rootScope.$apply('xs = []');
7292-
expect(jqLiteCacheSize()).toEqual(0);
7292+
expect(jqLiteCacheSize()).toEqual(cacheSize);
72937293

72947294
element.remove();
7295-
expect(jqLiteCacheSize()).toEqual(0);
7295+
expect(jqLiteCacheSize()).toEqual(cacheSize);
72967296
});
72977297
});
72987298

@@ -7308,26 +7308,26 @@ describe('$compile', function() {
73087308
});
73097309

73107310
inject(function($compile, $rootScope) {
7311-
expect(jqLiteCacheSize()).toEqual(0);
7311+
var cacheSize = jqLiteCacheSize();
73127312
element = $compile('<div><div ng-repeat="x in xs" ng-if="val">{{x}}</div></div>')($rootScope);
73137313

73147314
$rootScope.$apply('xs = [0,1]');
73157315
// At this point we have a bunch of comment placeholders but no real transcluded elements
73167316
// So the cache only contains the root element's data
7317-
expect(jqLiteCacheSize()).toEqual(1);
7317+
expect(jqLiteCacheSize()).toEqual(cacheSize + 1);
73187318

73197319
$rootScope.$apply('val = true');
73207320
// Now we have two concrete transcluded elements plus some comments so two more cache items
7321-
expect(jqLiteCacheSize()).toEqual(3);
7321+
expect(jqLiteCacheSize()).toEqual(cacheSize + 3);
73227322

73237323
$rootScope.$apply('val = false');
73247324
// Once again we only have comments so no transcluded elements and the cache is back to just
73257325
// the root element
7326-
expect(jqLiteCacheSize()).toEqual(1);
7326+
expect(jqLiteCacheSize()).toEqual(cacheSize + 1);
73277327

73287328
element.remove();
73297329
// Now we've even removed the root element along with its cache
7330-
expect(jqLiteCacheSize()).toEqual(0);
7330+
expect(jqLiteCacheSize()).toEqual(cacheSize + 0);
73317331
});
73327332
});
73337333

@@ -7364,6 +7364,7 @@ describe('$compile', function() {
73647364
});
73657365

73667366
inject(function($compile, $rootScope, $httpBackend, $timeout, $templateCache) {
7367+
var cacheSize = jqLiteCacheSize();
73677368
$httpBackend.whenGET('red.html').respond('<p>red.html</p>');
73687369
var template = $compile(
73697370
'<div ng-controller="Leak">' +
@@ -7378,7 +7379,7 @@ describe('$compile', function() {
73787379
$timeout.flush();
73797380
$httpBackend.flush();
73807381
expect(linkFn).not.toHaveBeenCalled();
7381-
expect(jqLiteCacheSize()).toEqual(2);
7382+
expect(jqLiteCacheSize()).toEqual(cacheSize + 2);
73827383

73837384
$templateCache.removeAll();
73847385
var destroyedScope = $rootScope.$new();
@@ -8161,9 +8162,7 @@ describe('$compile', function() {
81618162

81628163
it('should not leak memory with nested transclusion', function() {
81638164
inject(function($compile, $rootScope) {
8164-
var size;
8165-
8166-
expect(jqLiteCacheSize()).toEqual(0);
8165+
var size, initialSize = jqLiteCacheSize();
81678166

81688167
element = jqLite('<div><ul><li ng-repeat="n in nums">{{n}} => <i ng-if="0 === n%2">Even</i><i ng-if="1 === n%2">Odd</i></li></ul></div>');
81698168
$compile(element)($rootScope.$new());
@@ -8177,7 +8176,7 @@ describe('$compile', function() {
81778176
expect(jqLiteCacheSize()).toEqual(size);
81788177

81798178
element.remove();
8180-
expect(jqLiteCacheSize()).toEqual(0);
8179+
expect(jqLiteCacheSize()).toEqual(initialSize);
81818180
});
81828181
});
81838182
});

Diff for: test/ng/documentSpec.js

+24
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,27 @@ describe('$document', function() {
2727
});
2828
});
2929
});
30+
31+
32+
describe('$$isDocumentHidden', function() {
33+
it('should listen on the visibilitychange event', function() {
34+
var doc;
35+
36+
var spy = spyOn(document, 'addEventListener').and.callThrough();
37+
38+
inject(function($$isDocumentHidden, $document) {
39+
expect(spy).toHaveBeenCalledWith('visibilitychange', jasmine.any(Function));
40+
expect($$isDocumentHidden()).toBe(false);
41+
});
42+
43+
});
44+
45+
it('should remove the listener when the $rootScope is destroyed', function() {
46+
var spy = spyOn(document, 'removeEventListener').and.callThrough();
47+
48+
inject(function($$isDocumentHidden, $rootScope) {
49+
$rootScope.$destroy();
50+
expect(spy).toHaveBeenCalledWith('visibilitychange', jasmine.any(Function));
51+
});
52+
});
53+
});

Diff for: test/ngAnimate/animateSpec.js

+8-7
Original file line numberDiff line numberDiff line change
@@ -2501,18 +2501,19 @@ describe("animations", function() {
25012501

25022502

25032503
describe('because the document is hidden', function() {
2504-
beforeEach(module(function($provide) {
2505-
var doc = jqLite({
2506-
body: document.body,
2507-
hidden: true
2504+
var hidden = true;
2505+
2506+
beforeEach(function() {
2507+
module(function($provide) {
2508+
$provide.value('$$isDocumentHidden', function() {
2509+
return hidden;
2510+
});
25082511
});
2509-
$provide.value('$document', doc);
2510-
}));
2512+
});
25112513

25122514
it('should trigger callbacks for an enter animation',
25132515
inject(function($animate, $rootScope, $rootElement, $document) {
25142516

2515-
var callbackTriggered = false;
25162517
var spy = jasmine.createSpy();
25172518
$animate.on('enter', jqLite($document[0].body), spy);
25182519

0 commit comments

Comments
 (0)