Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/angular/angular.js into 6749
Browse files Browse the repository at this point in the history
* 'master' of https://github.com/angular/angular.js:
  fix($rootScope): ng-repeat can't handle NaN values. angular#4605
  test(ngMock): workaround issue with negative timestamps
  fix(select): avoid checking option element selected properties in render
  fix(orderBy): support string predicates containing non-ident characters
  fix(ngCookie): convert non-string values to string
  fix(ngTouch): update workaround for desktop Webkit quirk
  fix($httpBackend): don't error when JSONP callback called with no parameter
  fix($$RAFProvider): check for webkitCancelRequestAnimationFrame
  docs(tutorial/step_05): fix services link
  docs(tutorial/step_05): removed stray "a"
  style(ngMocks): remove ws
  feat(ngMock.$httpBackend): added support for function as URL matcher
  feat($compile): add support for $observer deregistration
  fix(Scope): $watchCollection should call listener with oldValue
  chore(log): add `log.empty()`  method to the testing logger
  • Loading branch information
auser committed Mar 19, 2014
2 parents 111ad4f + fb6062f commit 614891b
Show file tree
Hide file tree
Showing 20 changed files with 449 additions and 223 deletions.
3 changes: 1 addition & 2 deletions docs/content/tutorial/step_05.ngdoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@


Enough of building an app with three phones in a hard-coded dataset! Let's fetch a larger dataset
from our server using one of Angular's built-in {@link guide/dev_guide.services services} called {@link
from our server using one of Angular's built-in {@link guide/services services} called {@link
ng.$http $http}. We will use Angular's {@link guide/di dependency
injection (DI)} to provide the service to the `PhoneListCtrl` controller.

Expand All @@ -20,7 +20,6 @@ You should now see a list of 20 phones.
The most important changes are listed below. You can see the full diff on [GitHub](https://github.com/angular/angular-phonecat/compare/step-4...step-5):

## Data
a
The `app/phones/phones.json` file in your project is a dataset that contains a larger list of phones
stored in the JSON format.

Expand Down
7 changes: 5 additions & 2 deletions src/ng/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -775,7 +775,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
* @param {function(interpolatedValue)} fn Function that will be called whenever
the interpolated value of the attribute changes.
* See the {@link guide/directive#Attributes Directives} guide for more info.
* @returns {function()} the `fn` parameter.
* @returns {function()} Returns a deregistration function for this observer.
*/
$observe: function(key, fn) {
var attrs = this,
Expand All @@ -789,7 +789,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
fn(attrs[key]);
}
});
return fn;

return function() {
arrayRemove(listeners, fn);
};
}
};

Expand Down
8 changes: 7 additions & 1 deletion src/ng/directive/select.js
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,12 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
value = valueFn(scope, locals);
}
}
// Update the null option's selected property here so $render cleans it up correctly
if (optionGroupsCache[0].length > 1) {
if (optionGroupsCache[0][1].id !== key) {
optionGroupsCache[0][1].selected = false;
}
}
}
ctrl.$setViewValue(value);
});
Expand Down Expand Up @@ -531,7 +537,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
lastElement.val(existingOption.id = option.id);
}
// lastElement.prop('selected') provided by jQuery has side-effects
if (lastElement[0].selected !== option.selected) {
if (existingOption.selected !== option.selected) {
lastElement.prop('selected', (existingOption.selected = option.selected));
}
} else {
Expand Down
6 changes: 6 additions & 0 deletions src/ng/filter/orderBy.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ function orderByFilter($parse){
predicate = predicate.substring(1);
}
get = $parse(predicate);
if (get.constant) {
var key = get();
return reverseComparator(function(a,b) {
return compare(a[key], b[key]);
}, descending);
}
}
return reverseComparator(function(a,b){
return compare(get(a),get(b));
Expand Down
59 changes: 31 additions & 28 deletions src/ng/httpBackend.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,13 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
var callbackId = '_' + (callbacks.counter++).toString(36);
callbacks[callbackId] = function(data) {
callbacks[callbackId].data = data;
callbacks[callbackId].called = true;
};

var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
function() {
if (callbacks[callbackId].data) {
completeRequest(callback, 200, callbacks[callbackId].data);
} else {
completeRequest(callback, status || -2);
}
callbacks[callbackId] = angular.noop;
callbackId, function(status, text) {
completeRequest(callback, status, callbacks[callbackId].data, "", text);
callbacks[callbackId] = noop;
});
} else {

Expand Down Expand Up @@ -158,33 +155,39 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
}
};

function jsonpReq(url, done) {
function jsonpReq(url, callbackId, done) {
// we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
// - fetches local scripts via XHR and evals them
// - adds and immediately removes script elements from the document
var script = rawDocument.createElement('script'),
doneWrapper = function() {
script.onreadystatechange = script.onload = script.onerror = null;
rawDocument.body.removeChild(script);
if (done) done();
};

script.type = 'text/javascript';
var script = rawDocument.createElement('script'), callback = null;
script.type = "text/javascript";
script.src = url;

if (msie && msie <= 8) {
script.onreadystatechange = function() {
if (/loaded|complete/.test(script.readyState)) {
doneWrapper();
script.async = true;

callback = function(event) {
removeEventListenerFn(script, "load", callback);
removeEventListenerFn(script, "error", callback);
rawDocument.body.removeChild(script);
script = null;
var status = -1;
var text = "unknown";

if (event) {
if (event.type === "load" && !callbacks[callbackId].called) {
event = { type: "error" };
}
};
} else {
script.onload = script.onerror = function() {
doneWrapper();
};
}
text = event.type;
status = event.type === "error" ? 404 : 200;
}

if (done) {
done(status, text);
}
};

addEventListenerFn(script, "load", callback);
addEventListenerFn(script, "error", callback);
rawDocument.body.appendChild(script);
return doneWrapper;
return callback;
}
}
3 changes: 2 additions & 1 deletion src/ng/raf.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ function $$RAFProvider(){ //rAF

var cancelAnimationFrame = $window.cancelAnimationFrame ||
$window.webkitCancelAnimationFrame ||
$window.mozCancelAnimationFrame;
$window.mozCancelAnimationFrame ||
$window.webkitCancelRequestAnimationFrame;

var rafSupported = !!requestAnimationFrame;
var raf = rafSupported
Expand Down
55 changes: 46 additions & 9 deletions src/ng/rootScope.js
Original file line number Diff line number Diff line change
Expand Up @@ -398,30 +398,40 @@ function $RootScopeProvider(){
* {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
* collection will trigger a call to the `listener`.
*
* @param {function(newCollection, oldCollection, scope)} listener a callback function that is
* fired with both the `newCollection` and `oldCollection` as parameters.
* The `newCollection` object is the newly modified data obtained from the `obj` expression
* and the `oldCollection` object is a copy of the former collection data.
* The `scope` refers to the current scope.
* @param {function(newCollection, oldCollection, scope)} listener a callback function called
* when a change is detected.
* - The `newCollection` object is the newly modified data obtained from the `obj` expression
* - The `oldCollection` object is a copy of the former collection data.
* Due to performance considerations, the`oldCollection` value is computed only if the
* `listener` function declares two or more arguments.
* - The `scope` argument refers to the current scope.
*
* @returns {function()} Returns a de-registration function for this listener. When the
* de-registration function is executed, the internal watch operation is terminated.
*/
$watchCollection: function(obj, listener) {
var self = this;
var oldValue;
// the current value, updated on each dirty-check run
var newValue;
// a shallow copy of the newValue from the last dirty-check run,
// updated to match newValue during dirty-check run
var oldValue;
// a shallow copy of the newValue from when the last change happened
var veryOldValue;
// only track veryOldValue if the listener is asking for it
var trackVeryOldValue = (listener.length > 1);
var changeDetected = 0;
var objGetter = $parse(obj);
var internalArray = [];
var internalObject = {};
var initRun = true;
var oldLength = 0;

function $watchCollectionWatch() {
newValue = objGetter(self);
var newLength, key;

if (!isObject(newValue)) {
if (!isObject(newValue)) { // if primitive
if (oldValue !== newValue) {
oldValue = newValue;
changeDetected++;
Expand All @@ -443,7 +453,9 @@ function $RootScopeProvider(){
}
// copy the items to oldValue and look for changes.
for (var i = 0; i < newLength; i++) {
if (oldValue[i] !== newValue[i]) {
var bothNaN = (oldValue[i] !== oldValue[i]) &&
(newValue[i] !== newValue[i]);
if (!bothNaN && (oldValue[i] !== newValue[i])) {
changeDetected++;
oldValue[i] = newValue[i];
}
Expand Down Expand Up @@ -487,7 +499,32 @@ function $RootScopeProvider(){
}

function $watchCollectionAction() {
listener(newValue, oldValue, self);
if (initRun) {
initRun = false;
listener(newValue, newValue, self);
} else {
listener(newValue, veryOldValue, self);
}

// make a copy for the next time a collection is changed
if (trackVeryOldValue) {
if (!isObject(newValue)) {
//primitive
veryOldValue = newValue;
} else if (isArrayLike(newValue)) {
veryOldValue = new Array(newValue.length);
for (var i = 0; i < newValue.length; i++) {
veryOldValue[i] = newValue[i];
}
} else { // if object
veryOldValue = {};
for (var key in newValue) {
if (hasOwnProperty.call(newValue, key)) {
veryOldValue[key] = newValue[key];
}
}
}
}
}

return this.$watch($watchCollectionWatch, $watchCollectionAction);
Expand Down
10 changes: 4 additions & 6 deletions src/ngCookies/cookies.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,10 @@ angular.module('ngCookies', ['ng']).
for(name in cookies) {
value = cookies[name];
if (!angular.isString(value)) {
if (angular.isDefined(lastCookies[name])) {
cookies[name] = lastCookies[name];
} else {
delete cookies[name];
}
} else if (value !== lastCookies[name]) {
value = '' + value;
cookies[name] = value;
}
if (value !== lastCookies[name]) {
$browser.cookies(name, value);
updated = true;
}
Expand Down
Loading

0 comments on commit 614891b

Please sign in to comment.