Skip to content

Commit cd3f1be

Browse files
Merge pull request #139 from angular/master
Update upstream
2 parents 2c0b712 + 10a229c commit cd3f1be

File tree

7 files changed

+183
-7
lines changed

7 files changed

+183
-7
lines changed

src/ng/compile.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,11 @@
339339
* One-way binding is useful if you do not plan to propagate changes to your isolated scope bindings
340340
* back to the parent. However, it does not make this completely impossible.
341341
*
342+
* By default, the {@link ng.$rootScope.Scope#$watch `$watch`}
343+
* method is used for tracking changes, and the equality check is based on object identity.
344+
* It's also possible to watch the evaluated value shallowly with
345+
* {@link ng.$rootScope.Scope#$watchCollection `$watchCollection`}: use `<*` or `<*attr`
346+
*
342347
* * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope. If
343348
* no `attr` name is specified then the attribute name is assumed to be the same as the local name.
344349
* Given `<my-component my-attr="count = count + value">` and the isolate scope definition `scope: {
@@ -1068,7 +1073,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
10681073
var bindingCache = createMap();
10691074

10701075
function parseIsolateBindings(scope, directiveName, isController) {
1071-
var LOCAL_REGEXP = /^([@&<]|=(\*?))(\??)\s*([\w$]*)$/;
1076+
var LOCAL_REGEXP = /^([@&]|[=<](\*?))(\??)\s*([\w$]*)$/;
10721077

10731078
var bindings = createMap();
10741079

@@ -3615,7 +3620,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
36153620
var initialValue = destination[scopeName] = parentGet(scope);
36163621
initialChanges[scopeName] = new SimpleChange(_UNINITIALIZED_VALUE, destination[scopeName]);
36173622

3618-
removeWatch = scope.$watch(parentGet, function parentValueWatchAction(newValue, oldValue) {
3623+
removeWatch = scope[definition.collection ? '$watchCollection' : '$watch'](parentGet, function parentValueWatchAction(newValue, oldValue) {
36193624
if (oldValue === newValue) {
36203625
if (oldValue === initialValue || (isLiteral && equals(oldValue, initialValue))) {
36213626
return;

src/ngAnimate/ngAnimateSwap.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
* </file>
8888
* </example>
8989
*/
90-
var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $rootScope) {
90+
var ngAnimateSwapDirective = ['$animate', function($animate) {
9191
return {
9292
restrict: 'A',
9393
transclude: 'element',
@@ -104,10 +104,10 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
104104
previousScope = null;
105105
}
106106
if (value || value === 0) {
107-
previousScope = scope.$new();
108-
$transclude(previousScope, function(element) {
109-
previousElement = element;
110-
$animate.enter(element, null, $element);
107+
$transclude(function(clone, childScope) {
108+
previousElement = clone;
109+
previousScope = childScope;
110+
$animate.enter(clone, null, $element);
111111
});
112112
}
113113
});

src/ngCookies/cookieWriter.js

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ function $$CookieWriter($document, $log, $browser) {
3333
str += options.domain ? ';domain=' + options.domain : '';
3434
str += expires ? ';expires=' + expires.toUTCString() : '';
3535
str += options.secure ? ';secure' : '';
36+
str += options.samesite ? ';samesite=' + options.samesite : '';
3637

3738
// per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
3839
// - 300 cookies

src/ngCookies/cookies.js

+4
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ angular.module('ngCookies', ['ng']).
3838
* or a Date object indicating the exact date/time this cookie will expire.
3939
* - **secure** - `{boolean}` - If `true`, then the cookie will only be available through a
4040
* secured connection.
41+
* - **samesite** - `{string}` - prevents the browser from sending the cookie along with cross-site requests.
42+
* Accepts the values `lax` and `strict`. See the [OWASP Wiki](https://www.owasp.org/index.php/SameSite)
43+
* for more info. Note that as of May 2018, not all browsers support `SameSite`,
44+
* so it cannot be used as a single measure against Cross-Site-Request-Forgery (CSRF) attacks.
4145
*
4246
* Note: By default, the address that appears in your `<base>` tag will be used as the path.
4347
* This is important so that cookies will be visible for all routes when html5mode is enabled.

test/ng/compileSpec.js

+109
Original file line numberDiff line numberDiff line change
@@ -5148,6 +5148,9 @@ describe('$compile', function() {
51485148
owOptref: '<?',
51495149
owOptrefAlias: '<? owOptref',
51505150
$owOptrefAlias: '<? $owOptref$',
5151+
owColref: '<*',
5152+
owColrefAlias: '<* owColref',
5153+
$owColrefAlias: '<* $owColref$',
51515154
expr: '&',
51525155
optExpr: '&?',
51535156
exprAlias: '&expr',
@@ -6327,6 +6330,112 @@ describe('$compile', function() {
63276330
});
63286331
});
63296332

6333+
describe('one-way collection bindings', function() {
6334+
it('should update isolate scope when origin scope changes', inject(function() {
6335+
$rootScope.collection = [{
6336+
name: 'Gabriel',
6337+
value: 18
6338+
}, {
6339+
name: 'Tony',
6340+
value: 91
6341+
}];
6342+
$rootScope.query = '';
6343+
$rootScope.$apply();
6344+
6345+
compile('<div><span my-component ow-colref="collection | filter:query" $ow-colref$="collection | filter:query">');
6346+
6347+
expect(componentScope.owColref).toEqual($rootScope.collection);
6348+
expect(componentScope.owColrefAlias).toEqual(componentScope.owColref);
6349+
expect(componentScope.$owColrefAlias).toEqual(componentScope.owColref);
6350+
6351+
$rootScope.query = 'Gab';
6352+
$rootScope.$apply();
6353+
6354+
expect(componentScope.owColref).toEqual([$rootScope.collection[0]]);
6355+
expect(componentScope.owColrefAlias).toEqual([$rootScope.collection[0]]);
6356+
expect(componentScope.$owColrefAlias).toEqual([$rootScope.collection[0]]);
6357+
}));
6358+
6359+
it('should not update isolate scope when deep state within origin scope changes', inject(function() {
6360+
$rootScope.collection = [{
6361+
name: 'Gabriel',
6362+
value: 18
6363+
}, {
6364+
name: 'Tony',
6365+
value: 91
6366+
}];
6367+
$rootScope.$apply();
6368+
6369+
compile('<div><span my-component ow-colref="collection" $ow-colref$="collection">');
6370+
6371+
expect(componentScope.owColref).toEqual($rootScope.collection);
6372+
expect(componentScope.owColrefAlias).toEqual(componentScope.owColref);
6373+
expect(componentScope.$owColrefAlias).toEqual(componentScope.owColref);
6374+
6375+
componentScope.owColref = componentScope.owColrefAlias = componentScope.$owColrefAlias = undefined;
6376+
$rootScope.collection[0].name = 'Joe';
6377+
$rootScope.$apply();
6378+
6379+
expect(componentScope.owColref).toBeUndefined();
6380+
expect(componentScope.owColrefAlias).toBeUndefined();
6381+
expect(componentScope.$owColrefAlias).toBeUndefined();
6382+
}));
6383+
6384+
it('should update isolate scope when origin scope changes', inject(function() {
6385+
$rootScope.gab = {
6386+
name: 'Gabriel',
6387+
value: 18
6388+
};
6389+
$rootScope.tony = {
6390+
name: 'Tony',
6391+
value: 91
6392+
};
6393+
$rootScope.query = '';
6394+
$rootScope.$apply();
6395+
6396+
compile('<div><span my-component ow-colref="[gab, tony] | filter:query" $ow-colref$="[gab, tony] | filter:query">');
6397+
6398+
expect(componentScope.owColref).toEqual([$rootScope.gab, $rootScope.tony]);
6399+
expect(componentScope.owColrefAlias).toEqual([$rootScope.gab, $rootScope.tony]);
6400+
expect(componentScope.$owColrefAlias).toEqual([$rootScope.gab, $rootScope.tony]);
6401+
6402+
$rootScope.query = 'Gab';
6403+
$rootScope.$apply();
6404+
6405+
expect(componentScope.owColref).toEqual([$rootScope.gab]);
6406+
expect(componentScope.owColrefAlias).toEqual([$rootScope.gab]);
6407+
expect(componentScope.$owColrefAlias).toEqual([$rootScope.gab]);
6408+
}));
6409+
6410+
it('should update isolate scope when origin literal object content changes', inject(function() {
6411+
$rootScope.gab = {
6412+
name: 'Gabriel',
6413+
value: 18
6414+
};
6415+
$rootScope.tony = {
6416+
name: 'Tony',
6417+
value: 91
6418+
};
6419+
$rootScope.$apply();
6420+
6421+
compile('<div><span my-component ow-colref="[gab, tony]" $ow-colref$="[gab, tony]">');
6422+
6423+
expect(componentScope.owColref).toEqual([$rootScope.gab, $rootScope.tony]);
6424+
expect(componentScope.owColrefAlias).toEqual([$rootScope.gab, $rootScope.tony]);
6425+
expect(componentScope.$owColrefAlias).toEqual([$rootScope.gab, $rootScope.tony]);
6426+
6427+
$rootScope.tony = {
6428+
name: 'Bob',
6429+
value: 42
6430+
};
6431+
$rootScope.$apply();
6432+
6433+
expect(componentScope.owColref).toEqual([$rootScope.gab, $rootScope.tony]);
6434+
expect(componentScope.owColrefAlias).toEqual([$rootScope.gab, $rootScope.tony]);
6435+
expect(componentScope.$owColrefAlias).toEqual([$rootScope.gab, $rootScope.tony]);
6436+
}));
6437+
});
6438+
63306439
describe('executable expression', function() {
63316440
it('should allow expression execution with locals', inject(function() {
63326441
compile('<div><span my-component expr="count = count + offset" $expr$="count = count + offset">');

test/ngAnimate/ngAnimateSwapSpec.js

+47
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,53 @@ describe('ngAnimateSwap', function() {
132132
expect(two).toBeTruthy();
133133
}));
134134

135+
it('should create a new (non-isolate) scope for each inserted clone', inject(function() {
136+
var parentScope = $rootScope.$new();
137+
parentScope.foo = 'bar';
138+
139+
element = $compile('<div><div ng-animate-swap="value">{{ value }}</div></div>')(parentScope);
140+
141+
$rootScope.$apply('value = 1');
142+
var scopeOne = element.find('div').eq(0).scope();
143+
expect(scopeOne.foo).toBe('bar');
144+
145+
$rootScope.$apply('value = 2');
146+
var scopeTwo = element.find('div').eq(0).scope();
147+
expect(scopeTwo.foo).toBe('bar');
148+
149+
expect(scopeOne).not.toBe(scopeTwo);
150+
}));
151+
152+
it('should destroy the previous scope when removing the element', inject(function() {
153+
element = $compile('<div><div ng-animate-swap="value">{{ value }}</div></div>')($rootScope);
154+
155+
$rootScope.$apply('value = 1');
156+
var scopeOne = element.find('div').eq(0).scope();
157+
expect(scopeOne.$$destroyed).toBe(false);
158+
159+
// Swapping the old element with a new one.
160+
$rootScope.$apply('value = 2');
161+
expect(scopeOne.$$destroyed).toBe(true);
162+
163+
var scopeTwo = element.find('div').eq(0).scope();
164+
expect(scopeTwo.$$destroyed).toBe(false);
165+
166+
// Removing the old element (without inserting a new one).
167+
$rootScope.$apply('value = null');
168+
expect(scopeTwo.$$destroyed).toBe(true);
169+
}));
170+
171+
it('should destroy the previous scope when swapping elements', inject(function() {
172+
element = $compile('<div><div ng-animate-swap="value">{{ value }}</div></div>')($rootScope);
173+
174+
$rootScope.$apply('value = 1');
175+
var scopeOne = element.find('div').eq(0).scope();
176+
expect(scopeOne.$$destroyed).toBe(false);
177+
178+
$rootScope.$apply('value = 2');
179+
expect(scopeOne.$$destroyed).toBe(true);
180+
}));
181+
135182

136183
describe('animations', function() {
137184
it('should trigger a leave animation followed by an enter animation upon swap',

test/ngCookies/cookieWriterSpec.js

+10
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,16 @@ describe('cookie options', function() {
181181
expect(getLastCookieAssignment('secure')).toBe(true);
182182
});
183183

184+
it('should accept samesite option when value is lax', function() {
185+
$$cookieWriter('name', 'value', {samesite: 'lax'});
186+
expect(getLastCookieAssignment('samesite')).toBe('lax');
187+
});
188+
189+
it('should accept samesite option when value is strict', function() {
190+
$$cookieWriter('name', 'value', {samesite: 'strict'});
191+
expect(getLastCookieAssignment('samesite')).toBe('strict');
192+
});
193+
184194
it('should accept expires option on set', function() {
185195
$$cookieWriter('name', 'value', {expires: 'Fri, 19 Dec 2014 00:00:00 GMT'});
186196
expect(getLastCookieAssignment('expires')).toMatch(/^Fri, 19 Dec 2014 00:00:00 (UTC|GMT)$/);

0 commit comments

Comments
 (0)