Skip to content

Commit e704800

Browse files
Merge pull request #7 from angular/master
Update upstream
2 parents f865c95 + 617b361 commit e704800

File tree

6 files changed

+342
-168
lines changed

6 files changed

+342
-168
lines changed

CHANGELOG.md

+35
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,38 @@
1+
<a name="1.6.4"></a>
2+
# 1.6.4 phenomenal-footnote (2017-03-31)
3+
4+
5+
## Bug Fixes
6+
- **$parse:**
7+
- standardize one-time literal vs non-literal and interceptors
8+
([60394a](https://github.com/angular/angular.js/commit/60394a9d91dad8932fa900af7c8529837f1d4557),
9+
[#15858](https://github.com/angular/angular.js/issues/15858))
10+
- fix infinite digest errors when watching objects with .valueOf in literals
11+
([f5ddb1](https://github.com/angular/angular.js/commit/f5ddb10b56676c2ad912ce453acb87f0a7a94e01),
12+
[#15867](https://github.com/angular/angular.js/issues/15867))
13+
- **ngModel:** prevent internal scope reference from being copied
14+
([e1f8a6](https://github.com/angular/angular.js/commit/e1f8a6e82bb8a70079ef3db9a891b1c08b5bae31),
15+
[#15833](https://github.com/angular/angular.js/issues/15833))
16+
- **jqLite:** make jqLite invoke jqLite.cleanData as a method
17+
([9cde98](https://github.com/angular/angular.js/commit/9cde98cbc770f8d33fc074ba563b7ab6e2baaf8b),
18+
[#15846](https://github.com/angular/angular.js/issues/15846))
19+
- **$http:** throw more informative error on invalid JSON response
20+
([df8887](https://github.com/angular/angular.js/commit/df88873bb79213057057adb47151b626a7ec0e5d),
21+
[#15695](https://github.com/angular/angular.js/issues/15695),
22+
[#15724](https://github.com/angular/angular.js/issues/15724))
23+
- **dateFilter:** correctly handle newlines in `format` string
24+
([982271](https://github.com/angular/angular.js/commit/9822711ad2a401c2449239edc13d18b301714757),
25+
[#15794](https://github.com/angular/angular.js/issues/15794),
26+
[#15792](https://github.com/angular/angular.js/issues/15792))
27+
28+
29+
## New Features
30+
- **$resource:** add `hasBody` action configuration option
31+
([a9f987](https://github.com/angular/angular.js/commit/a9f987a0c9653246ea471a89197907d94c0cea2a),
32+
[#10128](https://github.com/angular/angular.js/issues/10128),
33+
[#12181](https://github.com/angular/angular.js/issues/12181))
34+
35+
136
<a name="1.6.3"></a>
237
# 1.6.3 scriptalicious-bootstrapping (2017-03-08)
338

src/ng/directive/ngClass.js

+8-45
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,6 @@ function classDirective(name, selector) {
1414
return {
1515
restrict: 'AC',
1616
link: function(scope, element, attr) {
17-
var expression = attr[name].trim();
18-
var isOneTime = (expression.charAt(0) === ':') && (expression.charAt(1) === ':');
19-
20-
var watchInterceptor = isOneTime ? toFlatValue : toClassString;
21-
var watchExpression = $parse(expression, watchInterceptor);
22-
var watchAction = isOneTime ? ngClassOneTimeWatchAction : ngClassWatchAction;
23-
2417
var classCounts = element.data('$classCounts');
2518
var oldModulo = true;
2619
var oldClassString;
@@ -43,7 +36,7 @@ function classDirective(name, selector) {
4336
scope.$watch(indexWatchExpression, ngClassIndexWatchAction);
4437
}
4538

46-
scope.$watch(watchExpression, watchAction, isOneTime);
39+
scope.$watch($parse(attr[name], toClassString), ngClassWatchAction);
4740

4841
function addClasses(classString) {
4942
classString = digestClassCounts(split(classString), 1);
@@ -85,9 +78,9 @@ function classDirective(name, selector) {
8578
}
8679

8780
function ngClassIndexWatchAction(newModulo) {
88-
// This watch-action should run before the `ngClass[OneTime]WatchAction()`, thus it
81+
// This watch-action should run before the `ngClassWatchAction()`, thus it
8982
// adds/removes `oldClassString`. If the `ngClass` expression has changed as well, the
90-
// `ngClass[OneTime]WatchAction()` will update the classes.
83+
// `ngClassWatchAction()` will update the classes.
9184
if (newModulo === selector) {
9285
addClasses(oldClassString);
9386
} else {
@@ -97,15 +90,13 @@ function classDirective(name, selector) {
9790
oldModulo = newModulo;
9891
}
9992

100-
function ngClassOneTimeWatchAction(newClassValue) {
101-
var newClassString = toClassString(newClassValue);
102-
103-
if (newClassString !== oldClassString) {
104-
ngClassWatchAction(newClassString);
93+
function ngClassWatchAction(newClassString) {
94+
// When using a one-time binding the newClassString will return
95+
// the pre-interceptor value until the one-time is complete
96+
if (!isString(newClassString)) {
97+
newClassString = toClassString(newClassString);
10598
}
106-
}
10799

108-
function ngClassWatchAction(newClassString) {
109100
if (oldModulo === selector) {
110101
updateClasses(oldClassString, newClassString);
111102
}
@@ -152,34 +143,6 @@ function classDirective(name, selector) {
152143

153144
return classString;
154145
}
155-
156-
function toFlatValue(classValue) {
157-
var flatValue = classValue;
158-
159-
if (isArray(classValue)) {
160-
flatValue = classValue.map(toFlatValue);
161-
} else if (isObject(classValue)) {
162-
var hasUndefined = false;
163-
164-
flatValue = Object.keys(classValue).filter(function(key) {
165-
var value = classValue[key];
166-
167-
if (!hasUndefined && isUndefined(value)) {
168-
hasUndefined = true;
169-
}
170-
171-
return value;
172-
});
173-
174-
if (hasUndefined) {
175-
// Prevent the `oneTimeLiteralWatchInterceptor` from unregistering
176-
// the watcher, by including at least one `undefined` value.
177-
flatValue.push(undefined);
178-
}
179-
}
180-
181-
return flatValue;
182-
}
183146
}
184147

185148
/**

src/ng/parse.js

+28-40
Original file line numberDiff line numberDiff line change
@@ -1765,8 +1765,8 @@ function $ParseProvider() {
17651765
if (parsedExpression.constant) {
17661766
parsedExpression.$$watchDelegate = constantWatchDelegate;
17671767
} else if (oneTime) {
1768-
parsedExpression.$$watchDelegate = parsedExpression.literal ?
1769-
oneTimeLiteralWatchDelegate : oneTimeWatchDelegate;
1768+
parsedExpression.oneTime = true;
1769+
parsedExpression.$$watchDelegate = oneTimeWatchDelegate;
17701770
} else if (parsedExpression.inputs) {
17711771
parsedExpression.$$watchDelegate = inputsWatchDelegate;
17721772
}
@@ -1788,14 +1788,14 @@ function $ParseProvider() {
17881788
return newValue === oldValueOfValue;
17891789
}
17901790

1791-
if (typeof newValue === 'object' && !compareObjectIdentity) {
1791+
if (typeof newValue === 'object') {
17921792

17931793
// attempt to convert the value to a primitive type
17941794
// TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can
17951795
// be cheaply dirty-checked
17961796
newValue = getValueOf(newValue);
17971797

1798-
if (typeof newValue === 'object') {
1798+
if (typeof newValue === 'object' && !compareObjectIdentity) {
17991799
// objects/arrays are not supported - deep-watching them would be too expensive
18001800
return false;
18011801
}
@@ -1852,6 +1852,7 @@ function $ParseProvider() {
18521852
}
18531853

18541854
function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression, prettyPrintExpression) {
1855+
var isDone = parsedExpression.literal ? isAllDefined : isDefined;
18551856
var unwatch, lastValue;
18561857
if (parsedExpression.inputs) {
18571858
unwatch = inputsWatchDelegate(scope, oneTimeListener, objectEquality, parsedExpression, prettyPrintExpression);
@@ -1868,41 +1869,22 @@ function $ParseProvider() {
18681869
if (isFunction(listener)) {
18691870
listener(value, old, scope);
18701871
}
1871-
if (isDefined(value)) {
1872+
if (isDone(value)) {
18721873
scope.$$postDigest(function() {
1873-
if (isDefined(lastValue)) {
1874+
if (isDone(lastValue)) {
18741875
unwatch();
18751876
}
18761877
});
18771878
}
18781879
}
18791880
}
18801881

1881-
function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
1882-
var unwatch, lastValue;
1883-
unwatch = scope.$watch(function oneTimeWatch(scope) {
1884-
return parsedExpression(scope);
1885-
}, function oneTimeListener(value, old, scope) {
1886-
lastValue = value;
1887-
if (isFunction(listener)) {
1888-
listener(value, old, scope);
1889-
}
1890-
if (isAllDefined(value)) {
1891-
scope.$$postDigest(function() {
1892-
if (isAllDefined(lastValue)) unwatch();
1893-
});
1894-
}
1895-
}, objectEquality);
1896-
1897-
return unwatch;
1898-
1899-
function isAllDefined(value) {
1900-
var allDefined = true;
1901-
forEach(value, function(val) {
1902-
if (!isDefined(val)) allDefined = false;
1903-
});
1904-
return allDefined;
1905-
}
1882+
function isAllDefined(value) {
1883+
var allDefined = true;
1884+
forEach(value, function(val) {
1885+
if (!isDefined(val)) allDefined = false;
1886+
});
1887+
return allDefined;
19061888
}
19071889

19081890
function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
@@ -1918,22 +1900,28 @@ function $ParseProvider() {
19181900
var watchDelegate = parsedExpression.$$watchDelegate;
19191901
var useInputs = false;
19201902

1921-
var regularWatch =
1922-
watchDelegate !== oneTimeLiteralWatchDelegate &&
1923-
watchDelegate !== oneTimeWatchDelegate;
1903+
var isDone = parsedExpression.literal ? isAllDefined : isDefined;
19241904

1925-
var fn = regularWatch ? function regularInterceptedExpression(scope, locals, assign, inputs) {
1905+
function regularInterceptedExpression(scope, locals, assign, inputs) {
19261906
var value = useInputs && inputs ? inputs[0] : parsedExpression(scope, locals, assign, inputs);
19271907
return interceptorFn(value, scope, locals);
1928-
} : function oneTimeInterceptedExpression(scope, locals, assign, inputs) {
1929-
var value = parsedExpression(scope, locals, assign, inputs);
1908+
}
1909+
1910+
function oneTimeInterceptedExpression(scope, locals, assign, inputs) {
1911+
var value = useInputs && inputs ? inputs[0] : parsedExpression(scope, locals, assign, inputs);
19301912
var result = interceptorFn(value, scope, locals);
19311913
// we only return the interceptor's result if the
19321914
// initial value is defined (for bind-once)
1933-
return isDefined(value) ? result : value;
1934-
};
1915+
return isDone(value) ? result : value;
1916+
}
1917+
1918+
var fn = parsedExpression.oneTime ? oneTimeInterceptedExpression : regularInterceptedExpression;
1919+
1920+
// Propogate the literal/oneTime attributes
1921+
fn.literal = parsedExpression.literal;
1922+
fn.oneTime = parsedExpression.oneTime;
19351923

1936-
// Propagate $$watchDelegates other then inputsWatchDelegate
1924+
// Propagate or create inputs / $$watchDelegates
19371925
useInputs = !parsedExpression.inputs;
19381926
if (watchDelegate && watchDelegate !== inputsWatchDelegate) {
19391927
fn.$$watchDelegate = watchDelegate;

src/ng/rootScope.js

+12-7
Original file line numberDiff line numberDiff line change
@@ -490,9 +490,8 @@ function $RootScopeProvider() {
490490
}
491491

492492
forEach(watchExpressions, function(expr, i) {
493-
var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) {
493+
var unwatchFn = self.$watch(expr, function watchGroupSubAction(value) {
494494
newValues[i] = value;
495-
oldValues[i] = oldValue;
496495
if (!changeReactionScheduled) {
497496
changeReactionScheduled = true;
498497
self.$evalAsync(watchGroupAction);
@@ -504,11 +503,17 @@ function $RootScopeProvider() {
504503
function watchGroupAction() {
505504
changeReactionScheduled = false;
506505

507-
if (firstRun) {
508-
firstRun = false;
509-
listener(newValues, newValues, self);
510-
} else {
511-
listener(newValues, oldValues, self);
506+
try {
507+
if (firstRun) {
508+
firstRun = false;
509+
listener(newValues, newValues, self);
510+
} else {
511+
listener(newValues, oldValues, self);
512+
}
513+
} finally {
514+
for (var i = 0; i < watchExpressions.length; i++) {
515+
oldValues[i] = newValues[i];
516+
}
512517
}
513518
}
514519

0 commit comments

Comments
 (0)