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

Commit 3ba25d6

Browse files
committed
fix($rootScope): fix potential memory leak when removing scope listeners
Previously the array entry for listeners was set to null but the array size was not trimmed until the event was broadcasted again
1 parent 817ac56 commit 3ba25d6

File tree

2 files changed

+90
-2
lines changed

2 files changed

+90
-2
lines changed

src/ng/compile.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -3637,7 +3637,7 @@ function SimpleChange(previous, current) {
36373637
SimpleChange.prototype.isFirstChange = function() { return this.previousValue === _UNINITIALIZED_VALUE; };
36383638

36393639

3640-
var PREFIX_REGEXP = /^((?:x|data)[:\-_])/i;
3640+
var PREFIX_REGEXP = /^((?:x|data)*[:\-_])/i;
36413641
var SPECIAL_CHARS_REGEXP = /[:\-_]+(.)/g;
36423642

36433643
/**

test/ng/compileSpec.js

+89-1
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,27 @@ describe('$compile', function() {
294294
inject(function($compile) {});
295295
});
296296

297+
it('should omit special chars before processing directive name', function() {
298+
module(function() {
299+
directive('t', function(log) {
300+
return {
301+
restrict: 'ECA',
302+
link: {
303+
pre: log.fn('pre'),
304+
post: log.fn('post')
305+
}
306+
};
307+
});
308+
});
309+
inject(function($compile, $rootScope, log) {
310+
element = $compile('<div _t></div>')($rootScope);
311+
element = $compile('<div -t></div>')($rootScope);
312+
element = $compile('<div :t></div>')($rootScope);
313+
element = $compile('<_t></_t>')($rootScope);
314+
expect(log).toEqual('pre; post; pre; post; pre; post; pre; post');
315+
});
316+
});
317+
297318
it('should throw an exception if the directive factory is not defined', function() {
298319
module(function() {
299320
expect(function() {
@@ -10638,7 +10659,10 @@ describe('$compile', function() {
1063810659
template:
1063910660
'<div class="a" ng-transclude="ng-transclude"></div>' +
1064010661
'<div class="b" ng:transclude="ng:transclude"></div>' +
10641-
'<div class="c" data-ng-transclude="data-ng-transclude"></div>'
10662+
'<div class="c" data-ng-transclude="data-ng-transclude"></div>'+
10663+
'<div class="d" -ng-transclude="-ng-transclude"></div>'+
10664+
'<div class="e" _ng_transclude="_ng_transclude"></div>'+
10665+
'<div class="f" :ng:transclude=":ng:transclude"></div>'
1064210666
};
1064310667
});
1064410668
});
@@ -10653,12 +10677,21 @@ describe('$compile', function() {
1065310677
var a = element.children().eq(0);
1065410678
var b = element.children().eq(1);
1065510679
var c = element.children().eq(2);
10680+
var d = element.children().eq(3);
10681+
var e = element.children().eq(4);
10682+
var f = element.children().eq(5);
1065610683
expect(a).toHaveClass('a');
1065710684
expect(b).toHaveClass('b');
1065810685
expect(c).toHaveClass('c');
10686+
expect(d).toHaveClass('d');
10687+
expect(e).toHaveClass('e');
10688+
expect(f).toHaveClass('f');
1065910689
expect(a.text()).toEqual('stuartbobkevin');
1066010690
expect(b.text()).toEqual('stuartbobkevin');
1066110691
expect(c.text()).toEqual('stuartbobkevin');
10692+
expect(d.text()).toEqual('stuartbobkevin');
10693+
expect(e.text()).toEqual('stuartbobkevin');
10694+
expect(f.text()).toEqual('stuartbobkevin');
1066210695
});
1066310696
});
1066410697

@@ -11710,6 +11743,18 @@ describe('$compile', function() {
1171011743
expect(element.attr('dash-test4')).toBe('JamieMason');
1171111744
}));
1171211745

11746+
it('should work if they are prefixed with special chars', inject(function() {
11747+
$rootScope.name = 'JamieMason';
11748+
element = $compile('<span -ng-attr-dash-test2="{{name}}" _ng-attr-dash-test3="{{name}}" :ng:attr-dash-test4="{{name}}"></span>')($rootScope);
11749+
expect(element.attr('dash-test2')).toBeUndefined();
11750+
expect(element.attr('dash-test3')).toBeUndefined();
11751+
expect(element.attr('dash-test4')).toBeUndefined();
11752+
$rootScope.$digest();
11753+
expect(element.attr('dash-test2')).toBe('JamieMason');
11754+
expect(element.attr('dash-test3')).toBe('JamieMason');
11755+
expect(element.attr('dash-test4')).toBe('JamieMason');
11756+
}));
11757+
1171311758
it('should keep attributes ending with -start single-element directives', function() {
1171411759
module(function($compileProvider) {
1171511760
$compileProvider.directive('dashStarter', function(log) {
@@ -11774,6 +11819,27 @@ describe('$compile', function() {
1177411819
expect(element.find('feDiffuseLighting').attr('surfaceScale')).toBe('1');
1177511820
expect(element.find('feSpecularLighting').attr('surfaceScale')).toBe('1');
1177611821
}));
11822+
11823+
it('should work if they are prefixed with special chars', inject(function($compile, $rootScope) {
11824+
$rootScope.dimensions = '0 0 0 0';
11825+
$rootScope.number = 0.42;
11826+
$rootScope.scale = 1;
11827+
$rootScope.x
11828+
element = $compile('<svg -ng-attr-view_box="{{dimensions}}">' +
11829+
'<filter _ng-attr-filter_units="{{number}}">' +
11830+
'<feDiffuseLighting -ng:attr_surface_scale="{{scale}}"' +
11831+
':ng:attr_diffuse_constant="{{number}}"></feDiffuseLighting>' +
11832+
'<feSpecularLighting _ng:attr_surface_scale="{{scale}}"' +
11833+
':ng-attr_diffuse_constant="{{number}}"></feSpecularLighting>')($rootScope);
11834+
expect(element.attr('viewBox')).toBeUndefined();
11835+
$rootScope.$digest();
11836+
expect(element.attr('viewBox')).toBe('0 0 0 0');
11837+
expect(element.find('filter').attr('filterUnits')).toBe('0.42');
11838+
expect(element.find('feDiffuseLighting').attr('surfaceScale')).toBe('1');
11839+
expect(element.find('feDiffuseLighting').attr('diffuseConstant')).toBe('0.42');
11840+
expect(element.find('feSpecularLighting').attr('surfaceScale')).toBe('1');
11841+
expect(element.find('feSpecularLighting').attr('diffuseConstant')).toBe('0.42');
11842+
}));
1177711843
});
1177811844

1177911845
describe('multi-element directive', function() {
@@ -12129,6 +12195,28 @@ describe('$compile', function() {
1212912195
expect(spans.eq(2)).toBeHidden();
1213012196
expect(spans.eq(3)).toBeHidden();
1213112197
}));
12198+
12199+
12200+
it('should support special char prefix', inject(function($compile, $rootScope) {
12201+
$rootScope.show = false;
12202+
element = $compile(
12203+
'<div>' +
12204+
'<span -ng-show-start="show"></span>' +
12205+
'<span -ng-show-end></span>' +
12206+
'<span :ng-show-start="show"></span>' +
12207+
'<span :ng-show-end></span>' +
12208+
'<span _ng-show-start="show"></span>' +
12209+
'<span _ng-show-end></span>' +
12210+
'</div>')($rootScope);
12211+
$rootScope.$digest();
12212+
var spans = element.find('span');
12213+
expect(spans.eq(0)).toBeHidden();
12214+
expect(spans.eq(1)).toBeHidden();
12215+
expect(spans.eq(2)).toBeHidden();
12216+
expect(spans.eq(3)).toBeHidden();
12217+
expect(spans.eq(4)).toBeHidden();
12218+
expect(spans.eq(5)).toBeHidden();
12219+
}));
1213212220
});
1213312221

1213412222
describe('$animate animation hooks', function() {

0 commit comments

Comments
 (0)