Commit b9c3b488 authored by Pascal Hartig's avatar Pascal Hartig

Angular Perf: Upgrade to 1.3.3

parent 88b5de99
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
"name": "todomvc-angular-perf", "name": "todomvc-angular-perf",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"angular": "1.3.2", "angular": "1.3.3",
"todomvc-common": "~0.3.0" "todomvc-common": "~0.3.0"
} }
} }
/** /**
* @license AngularJS v1.3.2 * @license AngularJS v1.3.3
* (c) 2010-2014 Google, Inc. http://angularjs.org * (c) 2010-2014 Google, Inc. http://angularjs.org
* License: MIT * License: MIT
*/ */
...@@ -42,40 +42,23 @@ function minErr(module, ErrorConstructor) { ...@@ -42,40 +42,23 @@ function minErr(module, ErrorConstructor) {
prefix = '[' + (module ? module + ':' : '') + code + '] ', prefix = '[' + (module ? module + ':' : '') + code + '] ',
template = arguments[1], template = arguments[1],
templateArgs = arguments, templateArgs = arguments,
stringify = function(obj) {
if (typeof obj === 'function') {
return obj.toString().replace(/ \{[\s\S]*$/, '');
} else if (typeof obj === 'undefined') {
return 'undefined';
} else if (typeof obj !== 'string') {
return JSON.stringify(obj);
}
return obj;
},
message, i; message, i;
message = prefix + template.replace(/\{\d+\}/g, function(match) { message = prefix + template.replace(/\{\d+\}/g, function(match) {
var index = +match.slice(1, -1), arg; var index = +match.slice(1, -1), arg;
if (index + 2 < templateArgs.length) { if (index + 2 < templateArgs.length) {
arg = templateArgs[index + 2]; return toDebugString(templateArgs[index + 2]);
if (typeof arg === 'function') {
return arg.toString().replace(/ ?\{[\s\S]*$/, '');
} else if (typeof arg === 'undefined') {
return 'undefined';
} else if (typeof arg !== 'string') {
return toJson(arg);
}
return arg;
} }
return match; return match;
}); });
message = message + '\nhttp://errors.angularjs.org/1.3.2/' + message = message + '\nhttp://errors.angularjs.org/1.3.3/' +
(module ? module + '/' : '') + code; (module ? module + '/' : '') + code;
for (i = 2; i < arguments.length; i++) { for (i = 2; i < arguments.length; i++) {
message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' + message = message + (i == 2 ? '?' : '&') + 'p' + (i - 2) + '=' +
encodeURIComponent(stringify(arguments[i])); encodeURIComponent(toDebugString(arguments[i]));
} }
return new ErrorConstructor(message); return new ErrorConstructor(message);
}; };
...@@ -715,7 +698,7 @@ function includes(array, obj) { ...@@ -715,7 +698,7 @@ function includes(array, obj) {
function arrayRemove(array, value) { function arrayRemove(array, value) {
var index = array.indexOf(value); var index = array.indexOf(value);
if (index >=0) if (index >= 0)
array.splice(index, 1); array.splice(index, 1);
return value; return value;
} }
...@@ -916,7 +899,7 @@ function equals(o1, o2) { ...@@ -916,7 +899,7 @@ function equals(o1, o2) {
if (isArray(o1)) { if (isArray(o1)) {
if (!isArray(o2)) return false; if (!isArray(o2)) return false;
if ((length = o1.length) == o2.length) { if ((length = o1.length) == o2.length) {
for (key=0; key<length; key++) { for (key = 0; key < length; key++) {
if (!equals(o1[key], o2[key])) return false; if (!equals(o1[key], o2[key])) return false;
} }
return true; return true;
...@@ -1002,7 +985,7 @@ function bind(self, fn) { ...@@ -1002,7 +985,7 @@ function bind(self, fn) {
return curryArgs.length return curryArgs.length
? function() { ? function() {
return arguments.length return arguments.length
? fn.apply(self, curryArgs.concat(slice.call(arguments, 0))) ? fn.apply(self, concat(curryArgs, arguments, 0))
: fn.apply(self, curryArgs); : fn.apply(self, curryArgs);
} }
: function() { : function() {
...@@ -1202,7 +1185,7 @@ var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-']; ...@@ -1202,7 +1185,7 @@ var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
function getNgAttribute(element, ngAttr) { function getNgAttribute(element, ngAttr) {
var attr, i, ii = ngAttrPrefixes.length; var attr, i, ii = ngAttrPrefixes.length;
element = jqLite(element); element = jqLite(element);
for (i=0; i<ii; ++i) { for (i = 0; i < ii; ++i) {
attr = ngAttrPrefixes[i] + ngAttr; attr = ngAttrPrefixes[i] + ngAttr;
if (isString(attr = element.attr(attr))) { if (isString(attr = element.attr(attr))) {
return attr; return attr;
...@@ -1987,6 +1970,34 @@ function setupModuleLoader(window) { ...@@ -1987,6 +1970,34 @@ function setupModuleLoader(window) {
} }
/* global: toDebugString: true */
function serializeObject(obj) {
var seen = [];
return JSON.stringify(obj, function(key, val) {
val = toJsonReplacer(key, val);
if (isObject(val)) {
if (seen.indexOf(val) >= 0) return '<<already seen>>';
seen.push(val);
}
return val;
});
}
function toDebugString(obj) {
if (typeof obj === 'function') {
return obj.toString().replace(/ \{[\s\S]*$/, '');
} else if (typeof obj === 'undefined') {
return 'undefined';
} else if (typeof obj !== 'string') {
return serializeObject(obj);
}
return obj;
}
/* global angularModule: true, /* global angularModule: true,
version: true, version: true,
...@@ -2089,11 +2100,11 @@ function setupModuleLoader(window) { ...@@ -2089,11 +2100,11 @@ function setupModuleLoader(window) {
* - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat". * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
*/ */
var version = { var version = {
full: '1.3.2', // all of these placeholder strings will be replaced by grunt's full: '1.3.3', // all of these placeholder strings will be replaced by grunt's
major: 1, // package task major: 1, // package task
minor: 3, minor: 3,
dot: 2, dot: 3,
codeName: 'cardiovasculatory-magnification' codeName: 'undersea-arithmetic'
}; };
...@@ -2826,7 +2837,7 @@ forEach({ ...@@ -2826,7 +2837,7 @@ forEach({
} }
} else { } else {
return (element[name] || return (element[name] ||
(element.attributes.getNamedItem(name)|| noop).specified) (element.attributes.getNamedItem(name) || noop).specified)
? lowercasedName ? lowercasedName
: undefined; : undefined;
} }
...@@ -4162,7 +4173,7 @@ function $AnchorScrollProvider() { ...@@ -4162,7 +4173,7 @@ function $AnchorScrollProvider() {
* @name $anchorScrollProvider#disableAutoScrolling * @name $anchorScrollProvider#disableAutoScrolling
* *
* @description * @description
* By default, {@link ng.$anchorScroll $anchorScroll()} will automatically will detect changes to * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
* {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br /> * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
* Use this method to disable automatic scrolling. * Use this method to disable automatic scrolling.
* *
...@@ -4811,8 +4822,7 @@ function $$AsyncCallbackProvider() { ...@@ -4811,8 +4822,7 @@ function $$AsyncCallbackProvider() {
/** /**
* @param {object} window The global window object. * @param {object} window The global window object.
* @param {object} document jQuery wrapped document. * @param {object} document jQuery wrapped document.
* @param {function()} XHR XMLHttpRequest constructor. * @param {object} $log window.console or an object with the same interface.
* @param {object} $log console.log or an object with the same interface.
* @param {object} $sniffer $sniffer service * @param {object} $sniffer $sniffer service
*/ */
function Browser(window, document, $log, $sniffer) { function Browser(window, document, $log, $sniffer) {
...@@ -5162,8 +5172,8 @@ function Browser(window, document, $log, $sniffer) { ...@@ -5162,8 +5172,8 @@ function Browser(window, document, $log, $sniffer) {
// - 20 cookies per unique domain // - 20 cookies per unique domain
// - 4096 bytes per cookie // - 4096 bytes per cookie
if (cookieLength > 4096) { if (cookieLength > 4096) {
$log.warn("Cookie '"+ name + $log.warn("Cookie '" + name +
"' possibly not set or overflowed because it was too large ("+ "' possibly not set or overflowed because it was too large (" +
cookieLength + " > 4096 bytes)!"); cookieLength + " > 4096 bytes)!");
} }
} }
...@@ -5828,7 +5838,7 @@ function $TemplateCacheProvider() { ...@@ -5828,7 +5838,7 @@ function $TemplateCacheProvider() {
* *
* *
* #### `bindToController` * #### `bindToController`
* When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController` will * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController: true` will
* allow a component to have its properties bound to the controller, rather than to scope. When the controller * allow a component to have its properties bound to the controller, rather than to scope. When the controller
* is instantiated, the initial values of the isolate scope bindings are already available. * is instantiated, the initial values of the isolate scope bindings are already available.
* *
...@@ -6677,16 +6687,16 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { ...@@ -6677,16 +6687,16 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
// for each tuples // for each tuples
var nbrUrisWith2parts = Math.floor(rawUris.length / 2); var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
for (var i=0; i<nbrUrisWith2parts; i++) { for (var i = 0; i < nbrUrisWith2parts; i++) {
var innerIdx = i*2; var innerIdx = i * 2;
// sanitize the uri // sanitize the uri
result += $$sanitizeUri(trim(rawUris[innerIdx]), true); result += $$sanitizeUri(trim(rawUris[innerIdx]), true);
// add the descriptor // add the descriptor
result += (" " + trim(rawUris[innerIdx+1])); result += (" " + trim(rawUris[innerIdx + 1]));
} }
// split the last item into uri and descriptor // split the last item into uri and descriptor
var lastTuple = trim(rawUris[i*2]).split(/\s/); var lastTuple = trim(rawUris[i * 2]).split(/\s/);
// sanitize the last uri // sanitize the last uri
result += $$sanitizeUri(trim(lastTuple[0]), true); result += $$sanitizeUri(trim(lastTuple[0]), true);
...@@ -6880,7 +6890,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { ...@@ -6880,7 +6890,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
if (!node) { if (!node) {
return 'html'; return 'html';
} else { } else {
return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg': 'html'; return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg' : 'html';
} }
} }
...@@ -7693,7 +7703,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { ...@@ -7693,7 +7703,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
var match = null; var match = null;
if (hasDirectives.hasOwnProperty(name)) { if (hasDirectives.hasOwnProperty(name)) {
for (var directive, directives = $injector.get(name + Suffix), for (var directive, directives = $injector.get(name + Suffix),
i = 0, ii = directives.length; i<ii; i++) { i = 0, ii = directives.length; i < ii; i++) {
try { try {
directive = directives[i]; directive = directives[i];
if ((maxPriority === undefined || maxPriority > directive.priority) && if ((maxPriority === undefined || maxPriority > directive.priority) &&
...@@ -7722,7 +7732,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { ...@@ -7722,7 +7732,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
function directiveIsMultiElement(name) { function directiveIsMultiElement(name) {
if (hasDirectives.hasOwnProperty(name)) { if (hasDirectives.hasOwnProperty(name)) {
for (var directive, directives = $injector.get(name + Suffix), for (var directive, directives = $injector.get(name + Suffix),
i = 0, ii = directives.length; i<ii; i++) { i = 0, ii = directives.length; i < ii; i++) {
directive = directives[i]; directive = directives[i];
if (directive.multiElement) { if (directive.multiElement) {
return true; return true;
...@@ -7941,7 +7951,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { ...@@ -7941,7 +7951,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
case 'svg': case 'svg':
case 'math': case 'math':
var wrapper = document.createElement('div'); var wrapper = document.createElement('div');
wrapper.innerHTML = '<'+type+'>'+template+'</'+type+'>'; wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
return wrapper.childNodes[0].childNodes; return wrapper.childNodes[0].childNodes;
default: default:
return template; return template;
...@@ -8298,6 +8308,10 @@ function $ControllerProvider() { ...@@ -8298,6 +8308,10 @@ function $ControllerProvider() {
* * if $controllerProvider#allowGlobals, check `window[constructor]` on the global * * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
* `window` object (not recommended) * `window` object (not recommended)
* *
* The string can use the `controller as property` syntax, where the controller instance is published
* as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
* to work correctly.
*
* @param {Object} locals Injection locals for Controller. * @param {Object} locals Injection locals for Controller.
* @return {Object} Instance of given controller. * @return {Object} Instance of given controller.
* *
...@@ -8472,7 +8486,7 @@ function defaultHttpResponseTransform(data, headers) { ...@@ -8472,7 +8486,7 @@ function defaultHttpResponseTransform(data, headers) {
// strip json vulnerability protection prefix // strip json vulnerability protection prefix
data = data.replace(JSON_PROTECTION_PREFIX, ''); data = data.replace(JSON_PROTECTION_PREFIX, '');
var contentType = headers('Content-Type'); var contentType = headers('Content-Type');
if ((contentType && contentType.indexOf(APPLICATION_JSON) === 0) || if ((contentType && contentType.indexOf(APPLICATION_JSON) === 0 && data.trim()) ||
(JSON_START.test(data) && JSON_END.test(data))) { (JSON_START.test(data) && JSON_END.test(data))) {
data = fromJson(data); data = fromJson(data);
} }
...@@ -10043,7 +10057,8 @@ function $InterpolateProvider() { ...@@ -10043,7 +10057,8 @@ function $InterpolateProvider() {
function parseStringifyInterceptor(value) { function parseStringifyInterceptor(value) {
try { try {
return stringify(getValue(value)); value = getValue(value);
return allOrNothing && !isDefined(value) ? value : stringify(value);
} catch (err) { } catch (err) {
var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text, var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
err.toString()); err.toString());
...@@ -10367,8 +10382,8 @@ function encodePath(path) { ...@@ -10367,8 +10382,8 @@ function encodePath(path) {
return segments.join('/'); return segments.join('/');
} }
function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) { function parseAbsoluteUrl(absoluteUrl, locationObj) {
var parsedUrl = urlResolve(absoluteUrl, appBase); var parsedUrl = urlResolve(absoluteUrl);
locationObj.$$protocol = parsedUrl.protocol; locationObj.$$protocol = parsedUrl.protocol;
locationObj.$$host = parsedUrl.hostname; locationObj.$$host = parsedUrl.hostname;
...@@ -10376,12 +10391,12 @@ function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) { ...@@ -10376,12 +10391,12 @@ function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
} }
function parseAppUrl(relativeUrl, locationObj, appBase) { function parseAppUrl(relativeUrl, locationObj) {
var prefixed = (relativeUrl.charAt(0) !== '/'); var prefixed = (relativeUrl.charAt(0) !== '/');
if (prefixed) { if (prefixed) {
relativeUrl = '/' + relativeUrl; relativeUrl = '/' + relativeUrl;
} }
var match = urlResolve(relativeUrl, appBase); var match = urlResolve(relativeUrl);
locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ? locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
match.pathname.substring(1) : match.pathname); match.pathname.substring(1) : match.pathname);
locationObj.$$search = parseKeyValue(match.search); locationObj.$$search = parseKeyValue(match.search);
...@@ -10436,7 +10451,7 @@ function LocationHtml5Url(appBase, basePrefix) { ...@@ -10436,7 +10451,7 @@ function LocationHtml5Url(appBase, basePrefix) {
this.$$html5 = true; this.$$html5 = true;
basePrefix = basePrefix || ''; basePrefix = basePrefix || '';
var appBaseNoFile = stripFile(appBase); var appBaseNoFile = stripFile(appBase);
parseAbsoluteUrl(appBase, this, appBase); parseAbsoluteUrl(appBase, this);
/** /**
...@@ -10451,7 +10466,7 @@ function LocationHtml5Url(appBase, basePrefix) { ...@@ -10451,7 +10466,7 @@ function LocationHtml5Url(appBase, basePrefix) {
appBaseNoFile); appBaseNoFile);
} }
parseAppUrl(pathUrl, this, appBase); parseAppUrl(pathUrl, this);
if (!this.$$path) { if (!this.$$path) {
this.$$path = '/'; this.$$path = '/';
...@@ -10514,7 +10529,7 @@ function LocationHtml5Url(appBase, basePrefix) { ...@@ -10514,7 +10529,7 @@ function LocationHtml5Url(appBase, basePrefix) {
function LocationHashbangUrl(appBase, hashPrefix) { function LocationHashbangUrl(appBase, hashPrefix) {
var appBaseNoFile = stripFile(appBase); var appBaseNoFile = stripFile(appBase);
parseAbsoluteUrl(appBase, this, appBase); parseAbsoluteUrl(appBase, this);
/** /**
...@@ -10534,7 +10549,7 @@ function LocationHashbangUrl(appBase, hashPrefix) { ...@@ -10534,7 +10549,7 @@ function LocationHashbangUrl(appBase, hashPrefix) {
throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url, throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
hashPrefix); hashPrefix);
} }
parseAppUrl(withoutHashUrl, this, appBase); parseAppUrl(withoutHashUrl, this);
this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase); this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
...@@ -11174,11 +11189,19 @@ function $LocationProvider() { ...@@ -11174,11 +11189,19 @@ function $LocationProvider() {
$rootScope.$evalAsync(function() { $rootScope.$evalAsync(function() {
var oldUrl = $location.absUrl(); var oldUrl = $location.absUrl();
var oldState = $location.$$state; var oldState = $location.$$state;
var defaultPrevented;
$location.$$parse(newUrl); $location.$$parse(newUrl);
$location.$$state = newState; $location.$$state = newState;
if ($rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
newState, oldState).defaultPrevented) { defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
newState, oldState).defaultPrevented;
// if the location was changed by a `$locationChangeStart` handler then stop
// processing this location change
if ($location.absUrl() !== newUrl) return;
if (defaultPrevented) {
$location.$$parse(oldUrl); $location.$$parse(oldUrl);
$location.$$state = oldState; $location.$$state = oldState;
setBrowserUrlWithFallback(oldUrl, false, oldState); setBrowserUrlWithFallback(oldUrl, false, oldState);
...@@ -11202,13 +11225,20 @@ function $LocationProvider() { ...@@ -11202,13 +11225,20 @@ function $LocationProvider() {
initializing = false; initializing = false;
$rootScope.$evalAsync(function() { $rootScope.$evalAsync(function() {
if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl, var newUrl = $location.absUrl();
$location.$$state, oldState).defaultPrevented) { var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
$location.$$state, oldState).defaultPrevented;
// if the location was changed by a `$locationChangeStart` handler then stop
// processing this location change
if ($location.absUrl() !== newUrl) return;
if (defaultPrevented) {
$location.$$parse(oldUrl); $location.$$parse(oldUrl);
$location.$$state = oldState; $location.$$state = oldState;
} else { } else {
if (urlOrStateChanged) { if (urlOrStateChanged) {
setBrowserUrlWithFallback($location.absUrl(), currentReplace, setBrowserUrlWithFallback(newUrl, currentReplace,
oldState === $location.$$state ? null : $location.$$state); oldState === $location.$$state ? null : $location.$$state);
} }
afterLocationChange(oldUrl, oldState); afterLocationChange(oldUrl, oldState);
...@@ -11398,7 +11428,7 @@ var $parseMinErr = minErr('$parse'); ...@@ -11398,7 +11428,7 @@ var $parseMinErr = minErr('$parse');
// Sandboxing Angular Expressions // Sandboxing Angular Expressions
// ------------------------------ // ------------------------------
// Angular expressions are generally considered safe because these expressions only have direct // Angular expressions are generally considered safe because these expressions only have direct
// access to $scope and locals. However, one can obtain the ability to execute arbitrary JS code by // access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by
// obtaining a reference to native JS functions such as the Function constructor. // obtaining a reference to native JS functions such as the Function constructor.
// //
// As an example, consider the following Angular expression: // As an example, consider the following Angular expression:
...@@ -11407,7 +11437,7 @@ var $parseMinErr = minErr('$parse'); ...@@ -11407,7 +11437,7 @@ var $parseMinErr = minErr('$parse');
// //
// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits // This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
// against the expression language, but not to prevent exploits that were enabled by exposing // against the expression language, but not to prevent exploits that were enabled by exposing
// sensitive JavaScript or browser apis on Scope. Exposing such objects on a Scope is never a good // sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good
// practice and therefore we are not even trying to protect against interaction with an object // practice and therefore we are not even trying to protect against interaction with an object
// explicitly exposed in this way. // explicitly exposed in this way.
// //
...@@ -11415,6 +11445,8 @@ var $parseMinErr = minErr('$parse'); ...@@ -11415,6 +11445,8 @@ var $parseMinErr = minErr('$parse');
// window or some DOM object that has a reference to window is published onto a Scope. // window or some DOM object that has a reference to window is published onto a Scope.
// Similarly we prevent invocations of function known to be dangerous, as well as assignments to // Similarly we prevent invocations of function known to be dangerous, as well as assignments to
// native objects. // native objects.
//
// See https://docs.angularjs.org/guide/security
function ensureSafeMemberName(name, fullExpression) { function ensureSafeMemberName(name, fullExpression) {
...@@ -11423,7 +11455,7 @@ function ensureSafeMemberName(name, fullExpression) { ...@@ -11423,7 +11455,7 @@ function ensureSafeMemberName(name, fullExpression) {
|| name === "__proto__") { || name === "__proto__") {
throw $parseMinErr('isecfld', throw $parseMinErr('isecfld',
'Attempting to access a disallowed field in Angular expressions! ' 'Attempting to access a disallowed field in Angular expressions! '
+'Expression: {0}', fullExpression); + 'Expression: {0}', fullExpression);
} }
return name; return name;
} }
...@@ -11500,24 +11532,24 @@ var OPERATORS = extend(createMap(), { ...@@ -11500,24 +11532,24 @@ var OPERATORS = extend(createMap(), {
} }
return a; return a;
} }
return isDefined(b)?b:undefined;}, return isDefined(b) ? b : undefined;},
'-':function(self, locals, a, b) { '-':function(self, locals, a, b) {
a=a(self, locals); b=b(self, locals); a=a(self, locals); b=b(self, locals);
return (isDefined(a)?a:0)-(isDefined(b)?b:0); return (isDefined(a) ? a : 0) - (isDefined(b) ? b : 0);
}, },
'*':function(self, locals, a, b) {return a(self, locals)*b(self, locals);}, '*':function(self, locals, a, b) {return a(self, locals) * b(self, locals);},
'/':function(self, locals, a, b) {return a(self, locals)/b(self, locals);}, '/':function(self, locals, a, b) {return a(self, locals) / b(self, locals);},
'%':function(self, locals, a, b) {return a(self, locals)%b(self, locals);}, '%':function(self, locals, a, b) {return a(self, locals) % b(self, locals);},
'===':function(self, locals, a, b) {return a(self, locals)===b(self, locals);}, '===':function(self, locals, a, b) {return a(self, locals) === b(self, locals);},
'!==':function(self, locals, a, b) {return a(self, locals)!==b(self, locals);}, '!==':function(self, locals, a, b) {return a(self, locals) !== b(self, locals);},
'==':function(self, locals, a, b) {return a(self, locals)==b(self, locals);}, '==':function(self, locals, a, b) {return a(self, locals) == b(self, locals);},
'!=':function(self, locals, a, b) {return a(self, locals)!=b(self, locals);}, '!=':function(self, locals, a, b) {return a(self, locals) != b(self, locals);},
'<':function(self, locals, a, b) {return a(self, locals)<b(self, locals);}, '<':function(self, locals, a, b) {return a(self, locals) < b(self, locals);},
'>':function(self, locals, a, b) {return a(self, locals)>b(self, locals);}, '>':function(self, locals, a, b) {return a(self, locals) > b(self, locals);},
'<=':function(self, locals, a, b) {return a(self, locals)<=b(self, locals);}, '<=':function(self, locals, a, b) {return a(self, locals) <= b(self, locals);},
'>=':function(self, locals, a, b) {return a(self, locals)>=b(self, locals);}, '>=':function(self, locals, a, b) {return a(self, locals) >= b(self, locals);},
'&&':function(self, locals, a, b) {return a(self, locals)&&b(self, locals);}, '&&':function(self, locals, a, b) {return a(self, locals) && b(self, locals);},
'||':function(self, locals, a, b) {return a(self, locals)||b(self, locals);}, '||':function(self, locals, a, b) {return a(self, locals) || b(self, locals);},
'!':function(self, locals, a) {return !a(self, locals);}, '!':function(self, locals, a) {return !a(self, locals);},
//Tokenized as operators but parsed as assignment/filters //Tokenized as operators but parsed as assignment/filters
...@@ -11543,44 +11575,31 @@ Lexer.prototype = { ...@@ -11543,44 +11575,31 @@ Lexer.prototype = {
lex: function(text) { lex: function(text) {
this.text = text; this.text = text;
this.index = 0; this.index = 0;
this.ch = undefined;
this.tokens = []; this.tokens = [];
while (this.index < this.text.length) { while (this.index < this.text.length) {
this.ch = this.text.charAt(this.index); var ch = this.text.charAt(this.index);
if (this.is('"\'')) { if (ch === '"' || ch === "'") {
this.readString(this.ch); this.readString(ch);
} else if (this.isNumber(this.ch) || this.is('.') && this.isNumber(this.peek())) { } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
this.readNumber(); this.readNumber();
} else if (this.isIdent(this.ch)) { } else if (this.isIdent(ch)) {
this.readIdent(); this.readIdent();
} else if (this.is('(){}[].,;:?')) { } else if (this.is(ch, '(){}[].,;:?')) {
this.tokens.push({ this.tokens.push({index: this.index, text: ch});
index: this.index,
text: this.ch
});
this.index++; this.index++;
} else if (this.isWhitespace(this.ch)) { } else if (this.isWhitespace(ch)) {
this.index++; this.index++;
} else { } else {
var ch2 = this.ch + this.peek(); var ch2 = ch + this.peek();
var ch3 = ch2 + this.peek(2); var ch3 = ch2 + this.peek(2);
var fn = OPERATORS[this.ch]; var op1 = OPERATORS[ch];
var fn2 = OPERATORS[ch2]; var op2 = OPERATORS[ch2];
var fn3 = OPERATORS[ch3]; var op3 = OPERATORS[ch3];
if (fn3) { if (op1 || op2 || op3) {
this.tokens.push({index: this.index, text: ch3, fn: fn3}); var token = op3 ? ch3 : (op2 ? ch2 : ch);
this.index += 3; this.tokens.push({index: this.index, text: token, operator: true});
} else if (fn2) { this.index += token.length;
this.tokens.push({index: this.index, text: ch2, fn: fn2});
this.index += 2;
} else if (fn) {
this.tokens.push({
index: this.index,
text: this.ch,
fn: fn
});
this.index += 1;
} else { } else {
this.throwError('Unexpected next character ', this.index, this.index + 1); this.throwError('Unexpected next character ', this.index, this.index + 1);
} }
...@@ -11589,8 +11608,8 @@ Lexer.prototype = { ...@@ -11589,8 +11608,8 @@ Lexer.prototype = {
return this.tokens; return this.tokens;
}, },
is: function(chars) { is: function(ch, chars) {
return chars.indexOf(this.ch) !== -1; return chars.indexOf(ch) !== -1;
}, },
peek: function(i) { peek: function(i) {
...@@ -11599,7 +11618,7 @@ Lexer.prototype = { ...@@ -11599,7 +11618,7 @@ Lexer.prototype = {
}, },
isNumber: function(ch) { isNumber: function(ch) {
return ('0' <= ch && ch <= '9'); return ('0' <= ch && ch <= '9') && typeof ch === "string";
}, },
isWhitespace: function(ch) { isWhitespace: function(ch) {
...@@ -11652,79 +11671,28 @@ Lexer.prototype = { ...@@ -11652,79 +11671,28 @@ Lexer.prototype = {
} }
this.index++; this.index++;
} }
number = 1 * number;
this.tokens.push({ this.tokens.push({
index: start, index: start,
text: number, text: number,
constant: true, constant: true,
fn: function() { return number; } value: Number(number)
}); });
}, },
readIdent: function() { readIdent: function() {
var expression = this.text;
var ident = '';
var start = this.index; var start = this.index;
var lastDot, peekIndex, methodName, ch;
while (this.index < this.text.length) { while (this.index < this.text.length) {
ch = this.text.charAt(this.index); var ch = this.text.charAt(this.index);
if (ch === '.' || this.isIdent(ch) || this.isNumber(ch)) { if (!(this.isIdent(ch) || this.isNumber(ch))) {
if (ch === '.') lastDot = this.index;
ident += ch;
} else {
break; break;
} }
this.index++; this.index++;
} }
//check if the identifier ends with . and if so move back one char
if (lastDot && ident[ident.length - 1] === '.') {
this.index--;
ident = ident.slice(0, -1);
lastDot = ident.lastIndexOf('.');
if (lastDot === -1) {
lastDot = undefined;
}
}
//check if this is not a method invocation and if it is back out to last dot
if (lastDot) {
peekIndex = this.index;
while (peekIndex < this.text.length) {
ch = this.text.charAt(peekIndex);
if (ch === '(') {
methodName = ident.substr(lastDot - start + 1);
ident = ident.substr(0, lastDot - start);
this.index = peekIndex;
break;
}
if (this.isWhitespace(ch)) {
peekIndex++;
} else {
break;
}
}
}
this.tokens.push({ this.tokens.push({
index: start, index: start,
text: ident, text: this.text.slice(start, this.index),
fn: CONSTANTS[ident] || getterFn(ident, this.options, expression) identifier: true
}); });
if (methodName) {
this.tokens.push({
index: lastDot,
text: '.'
});
this.tokens.push({
index: lastDot + 1,
text: methodName
});
}
}, },
readString: function(quote) { readString: function(quote) {
...@@ -11755,9 +11723,8 @@ Lexer.prototype = { ...@@ -11755,9 +11723,8 @@ Lexer.prototype = {
this.tokens.push({ this.tokens.push({
index: start, index: start,
text: rawString, text: rawString,
string: string,
constant: true, constant: true,
fn: function() { return string; } value: string
}); });
return; return;
} else { } else {
...@@ -11818,16 +11785,12 @@ Parser.prototype = { ...@@ -11818,16 +11785,12 @@ Parser.prototype = {
primary = this.arrayDeclaration(); primary = this.arrayDeclaration();
} else if (this.expect('{')) { } else if (this.expect('{')) {
primary = this.object(); primary = this.object();
} else if (this.peek().identifier) {
primary = this.identifier();
} else if (this.peek().constant) {
primary = this.constant();
} else { } else {
var token = this.expect(); this.throwError('not a primary expression', this.peek());
primary = token.fn;
if (!primary) {
this.throwError('not a primary expression', token);
}
if (token.constant) {
primary.constant = true;
primary.literal = true;
}
} }
var next, context; var next, context;
...@@ -11861,8 +11824,11 @@ Parser.prototype = { ...@@ -11861,8 +11824,11 @@ Parser.prototype = {
}, },
peek: function(e1, e2, e3, e4) { peek: function(e1, e2, e3, e4) {
if (this.tokens.length > 0) { return this.peekAhead(0, e1, e2, e3, e4);
var token = this.tokens[0]; },
peekAhead: function(i, e1, e2, e3, e4) {
if (this.tokens.length > i) {
var token = this.tokens[i];
var t = token.text; var t = token.text;
if (t === e1 || t === e2 || t === e3 || t === e4 || if (t === e1 || t === e2 || t === e3 || t === e4 ||
(!e1 && !e2 && !e3 && !e4)) { (!e1 && !e2 && !e3 && !e4)) {
...@@ -11882,12 +11848,19 @@ Parser.prototype = { ...@@ -11882,12 +11848,19 @@ Parser.prototype = {
}, },
consume: function(e1) { consume: function(e1) {
if (!this.expect(e1)) { if (this.tokens.length === 0) {
throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
}
var token = this.expect(e1);
if (!token) {
this.throwError('is unexpected, expecting [' + e1 + ']', this.peek()); this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
} }
return token;
}, },
unaryFn: function(fn, right) { unaryFn: function(op, right) {
var fn = OPERATORS[op];
return extend(function $parseUnaryFn(self, locals) { return extend(function $parseUnaryFn(self, locals) {
return fn(self, locals, right); return fn(self, locals, right);
}, { }, {
...@@ -11896,7 +11869,8 @@ Parser.prototype = { ...@@ -11896,7 +11869,8 @@ Parser.prototype = {
}); });
}, },
binaryFn: function(left, fn, right, isBranching) { binaryFn: function(left, op, right, isBranching) {
var fn = OPERATORS[op];
return extend(function $parseBinaryFn(self, locals) { return extend(function $parseBinaryFn(self, locals) {
return fn(self, locals, left, right); return fn(self, locals, left, right);
}, { }, {
...@@ -11905,6 +11879,28 @@ Parser.prototype = { ...@@ -11905,6 +11879,28 @@ Parser.prototype = {
}); });
}, },
identifier: function() {
var id = this.consume().text;
//Continue reading each `.identifier` unless it is a method invocation
while (this.peek('.') && this.peekAhead(1).identifier && !this.peekAhead(2, '(')) {
id += this.consume().text + this.consume().text;
}
return CONSTANTS[id] || getterFn(id, this.options, this.text);
},
constant: function() {
var value = this.consume().value;
return extend(function $parseConstant() {
return value;
}, {
constant: true,
literal: true
});
},
statements: function() { statements: function() {
var statements = []; var statements = [];
while (true) { while (true) {
...@@ -11936,8 +11932,7 @@ Parser.prototype = { ...@@ -11936,8 +11932,7 @@ Parser.prototype = {
}, },
filter: function(inputFn) { filter: function(inputFn) {
var token = this.expect(); var fn = this.$filter(this.consume().text);
var fn = this.$filter(token.text);
var argsFn; var argsFn;
var args; var args;
...@@ -12000,7 +11995,7 @@ Parser.prototype = { ...@@ -12000,7 +11995,7 @@ Parser.prototype = {
var token; var token;
if ((token = this.expect('?'))) { if ((token = this.expect('?'))) {
middle = this.assignment(); middle = this.assignment();
if ((token = this.expect(':'))) { if (this.consume(':')) {
var right = this.assignment(); var right = this.assignment();
return extend(function $parseTernary(self, locals) { return extend(function $parseTernary(self, locals) {
...@@ -12008,9 +12003,6 @@ Parser.prototype = { ...@@ -12008,9 +12003,6 @@ Parser.prototype = {
}, { }, {
constant: left.constant && middle.constant && right.constant constant: left.constant && middle.constant && right.constant
}); });
} else {
this.throwError('expected :', token);
} }
} }
...@@ -12021,7 +12013,7 @@ Parser.prototype = { ...@@ -12021,7 +12013,7 @@ Parser.prototype = {
var left = this.logicalAND(); var left = this.logicalAND();
var token; var token;
while ((token = this.expect('||'))) { while ((token = this.expect('||'))) {
left = this.binaryFn(left, token.fn, this.logicalAND(), true); left = this.binaryFn(left, token.text, this.logicalAND(), true);
} }
return left; return left;
}, },
...@@ -12030,7 +12022,7 @@ Parser.prototype = { ...@@ -12030,7 +12022,7 @@ Parser.prototype = {
var left = this.equality(); var left = this.equality();
var token; var token;
if ((token = this.expect('&&'))) { if ((token = this.expect('&&'))) {
left = this.binaryFn(left, token.fn, this.logicalAND(), true); left = this.binaryFn(left, token.text, this.logicalAND(), true);
} }
return left; return left;
}, },
...@@ -12039,7 +12031,7 @@ Parser.prototype = { ...@@ -12039,7 +12031,7 @@ Parser.prototype = {
var left = this.relational(); var left = this.relational();
var token; var token;
if ((token = this.expect('==','!=','===','!=='))) { if ((token = this.expect('==','!=','===','!=='))) {
left = this.binaryFn(left, token.fn, this.equality()); left = this.binaryFn(left, token.text, this.equality());
} }
return left; return left;
}, },
...@@ -12048,7 +12040,7 @@ Parser.prototype = { ...@@ -12048,7 +12040,7 @@ Parser.prototype = {
var left = this.additive(); var left = this.additive();
var token; var token;
if ((token = this.expect('<', '>', '<=', '>='))) { if ((token = this.expect('<', '>', '<=', '>='))) {
left = this.binaryFn(left, token.fn, this.relational()); left = this.binaryFn(left, token.text, this.relational());
} }
return left; return left;
}, },
...@@ -12057,7 +12049,7 @@ Parser.prototype = { ...@@ -12057,7 +12049,7 @@ Parser.prototype = {
var left = this.multiplicative(); var left = this.multiplicative();
var token; var token;
while ((token = this.expect('+','-'))) { while ((token = this.expect('+','-'))) {
left = this.binaryFn(left, token.fn, this.multiplicative()); left = this.binaryFn(left, token.text, this.multiplicative());
} }
return left; return left;
}, },
...@@ -12066,7 +12058,7 @@ Parser.prototype = { ...@@ -12066,7 +12058,7 @@ Parser.prototype = {
var left = this.unary(); var left = this.unary();
var token; var token;
while ((token = this.expect('*','/','%'))) { while ((token = this.expect('*','/','%'))) {
left = this.binaryFn(left, token.fn, this.unary()); left = this.binaryFn(left, token.text, this.unary());
} }
return left; return left;
}, },
...@@ -12076,9 +12068,9 @@ Parser.prototype = { ...@@ -12076,9 +12068,9 @@ Parser.prototype = {
if (this.expect('+')) { if (this.expect('+')) {
return this.primary(); return this.primary();
} else if ((token = this.expect('-'))) { } else if ((token = this.expect('-'))) {
return this.binaryFn(Parser.ZERO, token.fn, this.unary()); return this.binaryFn(Parser.ZERO, token.text, this.unary());
} else if ((token = this.expect('!'))) { } else if ((token = this.expect('!'))) {
return this.unaryFn(token.fn, this.unary()); return this.unaryFn(token.text, this.unary());
} else { } else {
return this.primary(); return this.primary();
} }
...@@ -12086,7 +12078,7 @@ Parser.prototype = { ...@@ -12086,7 +12078,7 @@ Parser.prototype = {
fieldAccess: function(object) { fieldAccess: function(object) {
var expression = this.text; var expression = this.text;
var field = this.expect().text; var field = this.consume().text;
var getter = getterFn(field, this.options, expression); var getter = getterFn(field, this.options, expression);
return extend(function $parseFieldAccess(scope, locals, self) { return extend(function $parseFieldAccess(scope, locals, self) {
...@@ -12171,8 +12163,7 @@ Parser.prototype = { ...@@ -12171,8 +12163,7 @@ Parser.prototype = {
// Support trailing commas per ES5.1. // Support trailing commas per ES5.1.
break; break;
} }
var elementFn = this.expression(); elementFns.push(this.expression());
elementFns.push(elementFn);
} while (this.expect(',')); } while (this.expect(','));
} }
this.consume(']'); this.consume(']');
...@@ -12198,11 +12189,16 @@ Parser.prototype = { ...@@ -12198,11 +12189,16 @@ Parser.prototype = {
// Support trailing commas per ES5.1. // Support trailing commas per ES5.1.
break; break;
} }
var token = this.expect(); var token = this.consume();
keys.push(token.string || token.text); if (token.constant) {
keys.push(token.value);
} else if (token.identifier) {
keys.push(token.text);
} else {
this.throwError("invalid key", token);
}
this.consume(':'); this.consume(':');
var value = this.expression(); valueFns.push(this.expression());
valueFns.push(value);
} while (this.expect(',')); } while (this.expect(','));
} }
this.consume('}'); this.consume('}');
...@@ -12644,13 +12640,21 @@ function $ParseProvider() { ...@@ -12644,13 +12640,21 @@ function $ParseProvider() {
function addInterceptor(parsedExpression, interceptorFn) { function addInterceptor(parsedExpression, interceptorFn) {
if (!interceptorFn) return parsedExpression; if (!interceptorFn) return parsedExpression;
var watchDelegate = parsedExpression.$$watchDelegate;
var fn = function interceptedExpression(scope, locals) { var regularWatch =
watchDelegate !== oneTimeLiteralWatchDelegate &&
watchDelegate !== oneTimeWatchDelegate;
var fn = regularWatch ? function regularInterceptedExpression(scope, locals) {
var value = parsedExpression(scope, locals);
return interceptorFn(value, scope, locals);
} : function oneTimeInterceptedExpression(scope, locals) {
var value = parsedExpression(scope, locals); var value = parsedExpression(scope, locals);
var result = interceptorFn(value, scope, locals); var result = interceptorFn(value, scope, locals);
// we only return the interceptor's result if the // we only return the interceptor's result if the
// initial value is defined (for bind-once) // initial value is defined (for bind-once)
return isDefined(value) || interceptorFn.$stateful ? result : value; return isDefined(value) ? result : value;
}; };
// Propagate $$watchDelegates other then inputsWatchDelegate // Propagate $$watchDelegates other then inputsWatchDelegate
...@@ -12675,7 +12679,11 @@ function $ParseProvider() { ...@@ -12675,7 +12679,11 @@ function $ParseProvider() {
* @requires $rootScope * @requires $rootScope
* *
* @description * @description
* A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q). * A service that helps you run functions asynchronously, and use their return values (or exceptions)
* when they are done processing.
*
* This is an implementation of promises/deferred objects inspired by
* [Kris Kowal's Q](https://github.com/kriskowal/q).
* *
* $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
* implementations, and the other which resembles ES6 promises to some degree. * implementations, and the other which resembles ES6 promises to some degree.
...@@ -12811,16 +12819,12 @@ function $ParseProvider() { ...@@ -12811,16 +12819,12 @@ function $ParseProvider() {
* *
* - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)` * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
* *
* - `finally(callback)` – allows you to observe either the fulfillment or rejection of a promise, * - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise,
* but to do so without modifying the final value. This is useful to release resources or do some * but to do so without modifying the final value. This is useful to release resources or do some
* clean-up that needs to be done whether the promise was rejected or resolved. See the [full * clean-up that needs to be done whether the promise was rejected or resolved. See the [full
* specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for * specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
* more information. * more information.
* *
* Because `finally` is a reserved word in JavaScript and reserved keywords are not supported as
* property names by ES3, you'll need to invoke the method like `promise['finally'](callback)` to
* make your code IE8 and Android 2.x compatible.
*
* # Chaining promises * # Chaining promises
* *
* Because calling the `then` method of a promise returns a new derived promise, it is easily * Because calling the `then` method of a promise returns a new derived promise, it is easily
...@@ -14043,11 +14047,11 @@ function $RootScopeProvider() { ...@@ -14043,11 +14047,11 @@ function $RootScopeProvider() {
if (ttl < 5) { if (ttl < 5) {
logIdx = 4 - ttl; logIdx = 4 - ttl;
if (!watchLog[logIdx]) watchLog[logIdx] = []; if (!watchLog[logIdx]) watchLog[logIdx] = [];
logMsg = (isFunction(watch.exp)) watchLog[logIdx].push({
? 'fn: ' + (watch.exp.name || watch.exp.toString()) msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
: watch.exp; newVal: value,
logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last); oldVal: last
watchLog[logIdx].push(logMsg); });
} }
} else if (watch === lastDirtyWatch) { } else if (watch === lastDirtyWatch) {
// If the most recently dirty watcher is now clean, short circuit since the remaining watchers // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
...@@ -14080,7 +14084,7 @@ function $RootScopeProvider() { ...@@ -14080,7 +14084,7 @@ function $RootScopeProvider() {
throw $rootScopeMinErr('infdig', throw $rootScopeMinErr('infdig',
'{0} $digest() iterations reached. Aborting!\n' + '{0} $digest() iterations reached. Aborting!\n' +
'Watchers fired in the last 5 iterations: {1}', 'Watchers fired in the last 5 iterations: {1}',
TTL, toJson(watchLog)); TTL, watchLog);
} }
} while (dirty || asyncQueue.length); } while (dirty || asyncQueue.length);
...@@ -14431,7 +14435,7 @@ function $RootScopeProvider() { ...@@ -14431,7 +14435,7 @@ function $RootScopeProvider() {
do { do {
namedListeners = scope.$$listeners[name] || empty; namedListeners = scope.$$listeners[name] || empty;
event.currentScope = scope; event.currentScope = scope;
for (i=0, length=namedListeners.length; i<length; i++) { for (i = 0, length = namedListeners.length; i < length; i++) {
// if listeners were deregistered, defragment the array // if listeners were deregistered, defragment the array
if (!namedListeners[i]) { if (!namedListeners[i]) {
...@@ -14505,7 +14509,7 @@ function $RootScopeProvider() { ...@@ -14505,7 +14509,7 @@ function $RootScopeProvider() {
while ((current = next)) { while ((current = next)) {
event.currentScope = current; event.currentScope = current;
listeners = current.$$listeners[name] || []; listeners = current.$$listeners[name] || [];
for (i=0, length = listeners.length; i<length; i++) { for (i = 0, length = listeners.length; i < length; i++) {
// if listeners were deregistered, defragment the array // if listeners were deregistered, defragment the array
if (!listeners[i]) { if (!listeners[i]) {
listeners.splice(i, 1); listeners.splice(i, 1);
...@@ -14661,7 +14665,7 @@ function $$SanitizeUriProvider() { ...@@ -14661,7 +14665,7 @@ function $$SanitizeUriProvider() {
var normalizedVal; var normalizedVal;
normalizedVal = urlResolve(uri).href; normalizedVal = urlResolve(uri).href;
if (normalizedVal !== '' && !normalizedVal.match(regex)) { if (normalizedVal !== '' && !normalizedVal.match(regex)) {
return 'unsafe:'+normalizedVal; return 'unsafe:' + normalizedVal;
} }
return uri; return uri;
}; };
...@@ -15760,7 +15764,7 @@ function $SnifferProvider() { ...@@ -15760,7 +15764,7 @@ function $SnifferProvider() {
transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle)); transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
animations = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle)); animations = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
if (android && (!transitions||!animations)) { if (android && (!transitions || !animations)) {
transitions = isString(document.body.style.webkitTransition); transitions = isString(document.body.style.webkitTransition);
animations = isString(document.body.style.webkitAnimation); animations = isString(document.body.style.webkitAnimation);
} }
...@@ -15831,7 +15835,7 @@ function $TemplateRequestProvider() { ...@@ -15831,7 +15835,7 @@ function $TemplateRequestProvider() {
if (isArray(transformResponse)) { if (isArray(transformResponse)) {
var original = transformResponse; var original = transformResponse;
transformResponse = []; transformResponse = [];
for (var i=0; i<original.length; ++i) { for (var i = 0; i < original.length; ++i) {
var transformer = original[i]; var transformer = original[i];
if (transformer !== defaultHttpResponseTransform) { if (transformer !== defaultHttpResponseTransform) {
transformResponse.push(transformer); transformResponse.push(transformer);
...@@ -16075,7 +16079,7 @@ function $TimeoutProvider() { ...@@ -16075,7 +16079,7 @@ function $TimeoutProvider() {
// exactly the behavior needed here. There is little value is mocking these out for this // exactly the behavior needed here. There is little value is mocking these out for this
// service. // service.
var urlParsingNode = document.createElement("a"); var urlParsingNode = document.createElement("a");
var originUrl = urlResolve(window.location.href, true); var originUrl = urlResolve(window.location.href);
/** /**
...@@ -16130,7 +16134,7 @@ var originUrl = urlResolve(window.location.href, true); ...@@ -16130,7 +16134,7 @@ var originUrl = urlResolve(window.location.href, true);
* | pathname | The pathname, beginning with "/" * | pathname | The pathname, beginning with "/"
* *
*/ */
function urlResolve(url, base) { function urlResolve(url) {
var href = url; var href = url;
if (msie) { if (msie) {
...@@ -16510,8 +16514,8 @@ function filterFilter() { ...@@ -16510,8 +16514,8 @@ function filterFilter() {
} }
return false; return false;
} }
text = (''+text).toLowerCase(); text = ('' + text).toLowerCase();
return (''+obj).toLowerCase().indexOf(text) > -1; return ('' + obj).toLowerCase().indexOf(text) > -1;
}; };
} }
} }
...@@ -16771,7 +16775,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) { ...@@ -16771,7 +16775,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
if (whole.length >= (lgroup + group)) { if (whole.length >= (lgroup + group)) {
pos = whole.length - lgroup; pos = whole.length - lgroup;
for (i = 0; i < pos; i++) { for (i = 0; i < pos; i++) {
if ((pos - i)%group === 0 && i !== 0) { if ((pos - i) % group === 0 && i !== 0) {
formatedText += groupSep; formatedText += groupSep;
} }
formatedText += whole.charAt(i); formatedText += whole.charAt(i);
...@@ -16779,7 +16783,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) { ...@@ -16779,7 +16783,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
} }
for (i = pos; i < whole.length; i++) { for (i = pos; i < whole.length; i++) {
if ((whole.length - i)%lgroup === 0 && i !== 0) { if ((whole.length - i) % lgroup === 0 && i !== 0) {
formatedText += groupSep; formatedText += groupSep;
} }
formatedText += whole.charAt(i); formatedText += whole.charAt(i);
...@@ -17019,10 +17023,10 @@ function dateFilter($locale) { ...@@ -17019,10 +17023,10 @@ function dateFilter($locale) {
tzMin = int(match[9] + match[11]); tzMin = int(match[9] + match[11]);
} }
dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3])); dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
var h = int(match[4]||0) - tzHour; var h = int(match[4] || 0) - tzHour;
var m = int(match[5]||0) - tzMin; var m = int(match[5] || 0) - tzMin;
var s = int(match[6]||0); var s = int(match[6] || 0);
var ms = Math.round(parseFloat('0.' + (match[7]||0)) * 1000); var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
timeSetter.call(date, h, m, s, ms); timeSetter.call(date, h, m, s, ms);
return date; return date;
} }
...@@ -17254,7 +17258,7 @@ function limitToFilter() { ...@@ -17254,7 +17258,7 @@ function limitToFilter() {
n = input.length; n = input.length;
} }
for (; i<n; i++) { for (; i < n; i++) {
out.push(input[i]); out.push(input[i]);
} }
...@@ -17381,7 +17385,7 @@ orderByFilter.$inject = ['$parse']; ...@@ -17381,7 +17385,7 @@ orderByFilter.$inject = ['$parse'];
function orderByFilter($parse) { function orderByFilter($parse) {
return function(array, sortPredicate, reverseOrder) { return function(array, sortPredicate, reverseOrder) {
if (!(isArrayLike(array))) return array; if (!(isArrayLike(array))) return array;
sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate]; sortPredicate = isArray(sortPredicate) ? sortPredicate : [sortPredicate];
if (sortPredicate.length === 0) { sortPredicate = ['+']; } if (sortPredicate.length === 0) { sortPredicate = ['+']; }
sortPredicate = sortPredicate.map(function(predicate) { sortPredicate = sortPredicate.map(function(predicate) {
var descending = false, get = predicate || identity; var descending = false, get = predicate || identity;
...@@ -17408,9 +17412,7 @@ function orderByFilter($parse) { ...@@ -17408,9 +17412,7 @@ function orderByFilter($parse) {
return compare(get(a),get(b)); return compare(get(a),get(b));
}, descending); }, descending);
}); });
var arrayCopy = []; return slice.call(array).sort(reverseComparator(comparator, reverseOrder));
for (var i = 0; i < array.length; i++) { arrayCopy.push(array[i]); }
return arrayCopy.sort(reverseComparator(comparator, reverseOrder));
function comparator(o1, o2) { function comparator(o1, o2) {
for (var i = 0; i < sortPredicate.length; i++) { for (var i = 0; i < sortPredicate.length; i++) {
...@@ -18472,9 +18474,14 @@ var inputType = { ...@@ -18472,9 +18474,14 @@ var inputType = {
* minlength. * minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
* maxlength. * maxlength.
* @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for * that contains the regular expression body that will be converted to a regular expression
* patterns defined as scope expressions. * as in the ngPattern directive.
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
* a RegExp found by evaluating the Angular expression given in the attribute value.
* If the expression evaluates to a RegExp object then this is used directly.
* If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
* characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
* @param {string=} ngChange Angular expression to be executed when input changes due to user * @param {string=} ngChange Angular expression to be executed when input changes due to user
* interaction with the input element. * interaction with the input element.
* @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input. * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
...@@ -19015,9 +19022,14 @@ var inputType = { ...@@ -19015,9 +19022,14 @@ var inputType = {
* minlength. * minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
* maxlength. * maxlength.
* @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for * that contains the regular expression body that will be converted to a regular expression
* patterns defined as scope expressions. * as in the ngPattern directive.
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
* a RegExp found by evaluating the Angular expression given in the attribute value.
* If the expression evaluates to a RegExp object then this is used directly.
* If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
* characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
* @param {string=} ngChange Angular expression to be executed when input changes due to user * @param {string=} ngChange Angular expression to be executed when input changes due to user
* interaction with the input element. * interaction with the input element.
* *
...@@ -19097,9 +19109,14 @@ var inputType = { ...@@ -19097,9 +19109,14 @@ var inputType = {
* minlength. * minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
* maxlength. * maxlength.
* @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for * that contains the regular expression body that will be converted to a regular expression
* patterns defined as scope expressions. * as in the ngPattern directive.
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
* a RegExp found by evaluating the Angular expression given in the attribute value.
* If the expression evaluates to a RegExp object then this is used directly.
* If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
* characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
* @param {string=} ngChange Angular expression to be executed when input changes due to user * @param {string=} ngChange Angular expression to be executed when input changes due to user
* interaction with the input element. * interaction with the input element.
* *
...@@ -19180,9 +19197,14 @@ var inputType = { ...@@ -19180,9 +19197,14 @@ var inputType = {
* minlength. * minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
* maxlength. * maxlength.
* @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for * that contains the regular expression body that will be converted to a regular expression
* patterns defined as scope expressions. * as in the ngPattern directive.
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
* a RegExp found by evaluating the Angular expression given in the attribute value.
* If the expression evaluates to a RegExp object then this is used directly.
* If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
* characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
* @param {string=} ngChange Angular expression to be executed when input changes due to user * @param {string=} ngChange Angular expression to be executed when input changes due to user
* interaction with the input element. * interaction with the input element.
* *
...@@ -19493,8 +19515,8 @@ function createDateParser(regexp, mapping) { ...@@ -19493,8 +19515,8 @@ function createDateParser(regexp, mapping) {
// When a date is JSON'ified to wraps itself inside of an extra // When a date is JSON'ified to wraps itself inside of an extra
// set of double quotes. This makes the date parsing code unable // set of double quotes. This makes the date parsing code unable
// to match the date string and parse it as a date. // to match the date string and parse it as a date.
if (iso.charAt(0) == '"' && iso.charAt(iso.length-1) == '"') { if (iso.charAt(0) == '"' && iso.charAt(iso.length - 1) == '"') {
iso = iso.substring(1, iso.length-1); iso = iso.substring(1, iso.length - 1);
} }
if (ISO_DATE_REGEXP.test(iso)) { if (ISO_DATE_REGEXP.test(iso)) {
return new Date(iso); return new Date(iso);
...@@ -19941,12 +19963,17 @@ var VALID_CLASS = 'ng-valid', ...@@ -19941,12 +19963,17 @@ var VALID_CLASS = 'ng-valid',
* @property {string} $viewValue Actual string value in the view. * @property {string} $viewValue Actual string value in the view.
* @property {*} $modelValue The value in the model that the control is bound to. * @property {*} $modelValue The value in the model that the control is bound to.
* @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
the control reads value from the DOM. The functions are called in array order, each passing the value the control reads value from the DOM. The functions are called in array order, each passing
through to the next. The last return value is forwarded to the $validators collection. its return value through to the next. The last return value is forwarded to the
Used to sanitize / convert the value. {@link ngModel.NgModelController#$validators `$validators`} collection.
Returning undefined from a parser means a parse error occurred. No $validators will
run and the 'ngModel' will not be updated until the parse error is resolved. The parse error is stored Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
in 'ngModel.$error.parse'. `$viewValue`}.
Returning `undefined` from a parser means a parse error occurred. In that case,
no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
is set to `true`. The parse error is stored in `ngModel.$error.parse`.
* *
* @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
...@@ -20071,7 +20098,7 @@ var VALID_CLASS = 'ng-valid', ...@@ -20071,7 +20098,7 @@ var VALID_CLASS = 'ng-valid',
// Listen for change events to enable binding // Listen for change events to enable binding
element.on('blur keyup change', function() { element.on('blur keyup change', function() {
scope.$apply(read); scope.$evalAsync(read);
}); });
read(); // initialize read(); // initialize
...@@ -21007,7 +21034,7 @@ var patternDirective = function() { ...@@ -21007,7 +21034,7 @@ var patternDirective = function() {
var regexp, patternExp = attr.ngPattern || attr.pattern; var regexp, patternExp = attr.ngPattern || attr.pattern;
attr.$observe('pattern', function(regex) { attr.$observe('pattern', function(regex) {
if (isString(regex) && regex.length > 0) { if (isString(regex) && regex.length > 0) {
regex = new RegExp(regex); regex = new RegExp('^' + regex + '$');
} }
if (regex && !regex.test) { if (regex && !regex.test) {
...@@ -21298,7 +21325,7 @@ var ngValueDirective = function() { ...@@ -21298,7 +21325,7 @@ var ngValueDirective = function() {
* `ngModelOptions` has an effect on the element it's declared on and its descendants. * `ngModelOptions` has an effect on the element it's declared on and its descendants.
* *
* @param {Object} ngModelOptions options to apply to the current model. Valid keys are: * @param {Object} ngModelOptions options to apply to the current model. Valid keys are:
* - `updateOn`: string specifying which event should be the input bound to. You can set several * - `updateOn`: string specifying which event should the input be bound to. You can set several
* events using an space delimited list. There is a special event called `default` that * events using an space delimited list. There is a special event called `default` that
* matches the default events belonging of the control. * matches the default events belonging of the control.
* - `debounce`: integer value which contains the debounce model update value in milliseconds. A * - `debounce`: integer value which contains the debounce model update value in milliseconds. A
...@@ -24166,7 +24193,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) { ...@@ -24166,7 +24193,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
}); });
throw ngRepeatMinErr('dupes', throw ngRepeatMinErr('dupes',
"Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}", "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
expression, trackById, toJson(value)); expression, trackById, value);
} else { } else {
// new never before seen block // new never before seen block
nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined}; nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
...@@ -24972,7 +24999,7 @@ var ngOptionsMinErr = minErr('ngOptions'); ...@@ -24972,7 +24999,7 @@ var ngOptionsMinErr = minErr('ngOptions');
* In many cases, `ngRepeat` can be used on `<option>` elements instead of `ngOptions` to achieve a * In many cases, `ngRepeat` can be used on `<option>` elements instead of `ngOptions` to achieve a
* similar result. However, the `ngOptions` provides some benefits such as reducing memory and * similar result. However, the `ngOptions` provides some benefits such as reducing memory and
* increasing speed by not creating a new scope for each repeated instance, as well as providing * increasing speed by not creating a new scope for each repeated instance, as well as providing
* more flexibility in how the `select`'s model is assigned via `select as`. `ngOptions should be * more flexibility in how the `select`'s model is assigned via `select as`. `ngOptions` should be
* used when the `select` model needs to be bound to a non-string value. This is because an option * used when the `select` model needs to be bound to a non-string value. This is because an option
* element can only be bound to string values at present. * element can only be bound to string values at present.
* *
...@@ -25570,13 +25597,14 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) { ...@@ -25570,13 +25597,14 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
lastElement = null; // start at the beginning lastElement = null; // start at the beginning
for (index = 0, length = optionGroup.length; index < length; index++) { for (index = 0, length = optionGroup.length; index < length; index++) {
option = optionGroup[index]; option = optionGroup[index];
if ((existingOption = existingOptions[index+1])) { if ((existingOption = existingOptions[index + 1])) {
// reuse elements // reuse elements
lastElement = existingOption.element; lastElement = existingOption.element;
if (existingOption.label !== option.label) { if (existingOption.label !== option.label) {
updateLabelMap(labelMap, existingOption.label, false); updateLabelMap(labelMap, existingOption.label, false);
updateLabelMap(labelMap, option.label, true); updateLabelMap(labelMap, option.label, true);
lastElement.text(existingOption.label = option.label); lastElement.text(existingOption.label = option.label);
lastElement.prop('label', existingOption.label);
} }
if (existingOption.id !== option.id) { if (existingOption.id !== option.id) {
lastElement.val(existingOption.id = option.id); lastElement.val(existingOption.id = option.id);
...@@ -25606,6 +25634,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) { ...@@ -25606,6 +25634,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
.val(option.id) .val(option.id)
.prop('selected', option.selected) .prop('selected', option.selected)
.attr('selected', option.selected) .attr('selected', option.selected)
.prop('label', option.label)
.text(option.label); .text(option.label);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment