Commit 4f1dd1ef authored by Randall Leeds's avatar Randall Leeds

Upgrade AngularJS libs

parent 3e830f4f
/** /**
* @license AngularJS v1.2.22 * @license AngularJS v1.2.25
* (c) 2010-2014 Google, Inc. http://angularjs.org * (c) 2010-2014 Google, Inc. http://angularjs.org
* License: MIT * License: MIT
*/ */
......
/** /**
* @license AngularJS v1.2.22 * @license AngularJS v1.2.25
* (c) 2010-2014 Google, Inc. http://angularjs.org * (c) 2010-2014 Google, Inc. http://angularjs.org
* License: MIT * License: MIT
*/ */
...@@ -63,6 +63,8 @@ angular.mock.$Browser = function() { ...@@ -63,6 +63,8 @@ angular.mock.$Browser = function() {
return listener; return listener;
}; };
self.$$checkUrlChange = angular.noop;
self.cookieHash = {}; self.cookieHash = {};
self.lastCookieHash = {}; self.lastCookieHash = {};
self.deferredFns = []; self.deferredFns = [];
...@@ -2003,6 +2005,7 @@ if(window.jasmine || window.mocha) { ...@@ -2003,6 +2005,7 @@ if(window.jasmine || window.mocha) {
* @description * @description
* *
* *NOTE*: This function is also published on window for easy access.<br> * *NOTE*: This function is also published on window for easy access.<br>
* *NOTE*: This function is declared ONLY WHEN running tests with jasmine or mocha
* *
* This function registers a module configuration code. It collects the configuration information * This function registers a module configuration code. It collects the configuration information
* which will be used when the injector is created by {@link angular.mock.inject inject}. * which will be used when the injector is created by {@link angular.mock.inject inject}.
...@@ -2045,6 +2048,7 @@ if(window.jasmine || window.mocha) { ...@@ -2045,6 +2048,7 @@ if(window.jasmine || window.mocha) {
* @description * @description
* *
* *NOTE*: This function is also published on window for easy access.<br> * *NOTE*: This function is also published on window for easy access.<br>
* *NOTE*: This function is declared ONLY WHEN running tests with jasmine or mocha
* *
* The inject function wraps a function into an injectable function. The inject() creates new * The inject function wraps a function into an injectable function. The inject() creates new
* instance of {@link auto.$injector $injector} per test, which is then used for * instance of {@link auto.$injector $injector} per test, which is then used for
......
/** /**
* @license AngularJS v1.2.22 * @license AngularJS v1.2.25
* (c) 2010-2014 Google, Inc. http://angularjs.org * (c) 2010-2014 Google, Inc. http://angularjs.org
* License: MIT * License: MIT
*/ */
...@@ -129,10 +129,16 @@ function shallowClearAndCopy(src, dst) { ...@@ -129,10 +129,16 @@ function shallowClearAndCopy(src, dst) {
* `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` – * `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
* transform function or an array of such functions. The transform function takes the http * transform function or an array of such functions. The transform function takes the http
* request body and headers and returns its transformed (typically serialized) version. * request body and headers and returns its transformed (typically serialized) version.
* By default, transformRequest will contain one function that checks if the request data is
* an object and serializes to using `angular.toJson`. To prevent this behavior, set
* `transformRequest` to an empty array: `transformRequest: []`
* - **`transformResponse`** – * - **`transformResponse`** –
* `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` – * `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
* transform function or an array of such functions. The transform function takes the http * transform function or an array of such functions. The transform function takes the http
* response body and headers and returns its transformed (typically deserialized) version. * response body and headers and returns its transformed (typically deserialized) version.
* By default, transformResponse will contain one function that checks if the response looks like
* a JSON string and deserializes it using `angular.fromJson`. To prevent this behavior, set
* `transformResponse` to an empty array: `transformResponse: []`
* - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the * - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
* GET request, otherwise if a cache instance built with * GET request, otherwise if a cache instance built with
* {@link ng.$cacheFactory $cacheFactory}, this cache will be used for * {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
......
/** /**
* @license AngularJS v1.2.22 * @license AngularJS v1.2.25
* (c) 2010-2014 Google, Inc. http://angularjs.org * (c) 2010-2014 Google, Inc. http://angularjs.org
* License: MIT * License: MIT
*/ */
...@@ -771,7 +771,6 @@ ngRouteModule.directive('ngView', ngViewFillContentFactory); ...@@ -771,7 +771,6 @@ ngRouteModule.directive('ngView', ngViewFillContentFactory);
controllerAs: 'chapter' controllerAs: 'chapter'
}); });
// configure html5 to get links working on jsfiddle
$locationProvider.html5Mode(true); $locationProvider.html5Mode(true);
}]) }])
.controller('MainCtrl', ['$route', '$routeParams', '$location', .controller('MainCtrl', ['$route', '$routeParams', '$location',
......
/** /**
* @license AngularJS v1.2.22 * @license AngularJS v1.2.25
* (c) 2010-2014 Google, Inc. http://angularjs.org * (c) 2010-2014 Google, Inc. http://angularjs.org
* License: MIT * License: MIT
*/ */
...@@ -597,7 +597,7 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider); ...@@ -597,7 +597,7 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
*/ */
angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) { angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
var LINKY_URL_REGEXP = var LINKY_URL_REGEXP =
/((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>]/, /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"]/,
MAILTO_REGEXP = /^mailto:/; MAILTO_REGEXP = /^mailto:/;
return function(text, target) { return function(text, target) {
......
/** /**
* @license AngularJS v1.2.22 * @license AngularJS v1.2.25
* (c) 2010-2014 Google, Inc. http://angularjs.org * (c) 2010-2014 Google, Inc. http://angularjs.org
* License: MIT * License: MIT
*/ */
...@@ -68,7 +68,7 @@ function minErr(module) { ...@@ -68,7 +68,7 @@ function minErr(module) {
return match; return match;
}); });
message = message + '\nhttp://errors.angularjs.org/1.2.22/' + message = message + '\nhttp://errors.angularjs.org/1.2.25/' +
(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) + '=' +
...@@ -899,9 +899,13 @@ function copy(source, destination, stackSource, stackDest) { ...@@ -899,9 +899,13 @@ function copy(source, destination, stackSource, stackDest) {
} }
} else { } else {
var h = destination.$$hashKey; var h = destination.$$hashKey;
if (isArray(destination)) {
destination.length = 0;
} else {
forEach(destination, function(value, key) { forEach(destination, function(value, key) {
delete destination[key]; delete destination[key];
}); });
}
for ( var key in source) { for ( var key in source) {
result = copy(source[key], null, stackSource, stackDest); result = copy(source[key], null, stackSource, stackDest);
if (isObject(source[key])) { if (isObject(source[key])) {
...@@ -986,7 +990,8 @@ function equals(o1, o2) { ...@@ -986,7 +990,8 @@ function equals(o1, o2) {
return true; return true;
} }
} else if (isDate(o1)) { } else if (isDate(o1)) {
return isDate(o2) && o1.getTime() == o2.getTime(); if (!isDate(o2)) return false;
return (isNaN(o1.getTime()) && isNaN(o2.getTime())) || (o1.getTime() === o2.getTime());
} else if (isRegExp(o1) && isRegExp(o2)) { } else if (isRegExp(o1) && isRegExp(o2)) {
return o1.toString() == o2.toString(); return o1.toString() == o2.toString();
} else { } else {
...@@ -1424,7 +1429,11 @@ function bootstrap(element, modules) { ...@@ -1424,7 +1429,11 @@ function bootstrap(element, modules) {
if (element.injector()) { if (element.injector()) {
var tag = (element[0] === document) ? 'document' : startingTag(element); var tag = (element[0] === document) ? 'document' : startingTag(element);
throw ngMinErr('btstrpd', "App Already Bootstrapped with this Element '{0}'", tag); //Encode angle brackets to prevent input from being sanitized to empty string #8683
throw ngMinErr(
'btstrpd',
"App Already Bootstrapped with this Element '{0}'",
tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
} }
modules = modules || []; modules = modules || [];
...@@ -1688,7 +1697,7 @@ function setupModuleLoader(window) { ...@@ -1688,7 +1697,7 @@ function setupModuleLoader(window) {
* @ngdoc property * @ngdoc property
* @name angular.Module#requires * @name angular.Module#requires
* @module ng * @module ng
* @returns {Array.<string>} List of module names which must be loaded before this module. *
* @description * @description
* Holds the list of modules which the injector will load before the current module is * Holds the list of modules which the injector will load before the current module is
* loaded. * loaded.
...@@ -1699,8 +1708,9 @@ function setupModuleLoader(window) { ...@@ -1699,8 +1708,9 @@ function setupModuleLoader(window) {
* @ngdoc property * @ngdoc property
* @name angular.Module#name * @name angular.Module#name
* @module ng * @module ng
* @returns {string} Name of the module. *
* @description * @description
* Name of the module.
*/ */
name: name, name: name,
...@@ -1977,11 +1987,11 @@ function setupModuleLoader(window) { ...@@ -1977,11 +1987,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.2.22', // all of these placeholder strings will be replaced by grunt's full: '1.2.25', // all of these placeholder strings will be replaced by grunt's
major: 1, // package task major: 1, // package task
minor: 2, minor: 2,
dot: 22, dot: 25,
codeName: 'finicky-pleasure' codeName: 'hypnotic-gesticulation'
}; };
...@@ -4572,6 +4582,13 @@ function Browser(window, document, $log, $sniffer) { ...@@ -4572,6 +4582,13 @@ function Browser(window, document, $log, $sniffer) {
return callback; return callback;
}; };
/**
* Checks whether the url has changed outside of Angular.
* Needs to be exported to be able to check for changes that have been done in sync,
* as hashchange/popstate events fire in async.
*/
self.$$checkUrlChange = fireUrlChange;
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
// Misc API // Misc API
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
...@@ -4788,8 +4805,10 @@ function $BrowserProvider(){ ...@@ -4788,8 +4805,10 @@ function $BrowserProvider(){
$scope.keys = []; $scope.keys = [];
$scope.cache = $cacheFactory('cacheId'); $scope.cache = $cacheFactory('cacheId');
$scope.put = function(key, value) { $scope.put = function(key, value) {
$scope.cache.put(key, value); if ($scope.cache.get(key) === undefined) {
$scope.keys.push(key); $scope.keys.push(key);
}
$scope.cache.put(key, value === undefined ? null : value);
}; };
}]); }]);
</file> </file>
...@@ -5309,9 +5328,9 @@ function $TemplateCacheProvider() { ...@@ -5309,9 +5328,9 @@ function $TemplateCacheProvider() {
* *
* * (no prefix) - Locate the required controller on the current element. Throw an error if not found. * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
* * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found. * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
* * `^` - Locate the required controller by searching the element's parents. Throw an error if not found. * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
* * `?^` - Attempt to locate the required controller by searching the element's parents or pass `null` to the * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
* `link` fn if not found. * `null` to the `link` fn if not found.
* *
* *
* #### `controllerAs` * #### `controllerAs`
...@@ -7129,7 +7148,9 @@ function directiveNormalize(name) { ...@@ -7129,7 +7148,9 @@ function directiveNormalize(name) {
/** /**
* @ngdoc property * @ngdoc property
* @name $compile.directive.Attributes#$attr * @name $compile.directive.Attributes#$attr
* @returns {object} A map of DOM element attribute names to the normalized name. This is *
* @description
* A map of DOM element attribute names to the normalized name. This is
* needed to do reverse lookup from normalized name back to actual name. * needed to do reverse lookup from normalized name back to actual name.
*/ */
...@@ -7885,7 +7906,7 @@ function $HttpProvider() { ...@@ -7885,7 +7906,7 @@ function $HttpProvider() {
* that only JavaScript running on your domain could have sent the request. The token must be * that only JavaScript running on your domain could have sent the request. The token must be
* unique for each user and must be verifiable by the server (to prevent the JavaScript from * unique for each user and must be verifiable by the server (to prevent the JavaScript from
* making up its own tokens). We recommend that the token is a digest of your site's * making up its own tokens). We recommend that the token is a digest of your site's
* authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography)) * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
* for added security. * for added security.
* *
* The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
...@@ -8393,7 +8414,7 @@ function $HttpProvider() { ...@@ -8393,7 +8414,7 @@ function $HttpProvider() {
if (isObject(v)) { if (isObject(v)) {
if (isDate(v)){ if (isDate(v)){
v = v.toISOString(); v = v.toISOString();
} else if (isObject(v)) { } else {
v = toJson(v); v = toJson(v);
} }
} }
...@@ -8843,7 +8864,7 @@ function $InterpolateProvider() { ...@@ -8843,7 +8864,7 @@ function $InterpolateProvider() {
* @description * @description
* Symbol to denote the start of expression in the interpolated string. Defaults to `{{`. * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
* *
* Use {@link ng.$interpolateProvider#startSymbol $interpolateProvider#startSymbol} to change * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
* the symbol. * the symbol.
* *
* @returns {string} start symbol. * @returns {string} start symbol.
...@@ -8859,7 +8880,7 @@ function $InterpolateProvider() { ...@@ -8859,7 +8880,7 @@ function $InterpolateProvider() {
* @description * @description
* Symbol to denote the end of expression in the interpolated string. Defaults to `}}`. * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
* *
* Use {@link ng.$interpolateProvider#endSymbol $interpolateProvider#endSymbol} to change * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
* the symbol. * the symbol.
* *
* @returns {string} end symbol. * @returns {string} end symbol.
...@@ -8951,7 +8972,7 @@ function $IntervalProvider() { ...@@ -8951,7 +8972,7 @@ function $IntervalProvider() {
* }; * };
* *
* $scope.$on('$destroy', function() { * $scope.$on('$destroy', function() {
* // Make sure that the interval nis destroyed too * // Make sure that the interval is destroyed too
* $scope.stopFight(); * $scope.stopFight();
* }); * });
* }]) * }])
...@@ -9449,17 +9470,16 @@ LocationHashbangInHtml5Url.prototype = ...@@ -9449,17 +9470,16 @@ LocationHashbangInHtml5Url.prototype =
* Change path, search and hash, when called with parameter and return `$location`. * Change path, search and hash, when called with parameter and return `$location`.
* *
* @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`) * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
* @param {string=} replace The path that will be changed
* @return {string} url * @return {string} url
*/ */
url: function(url, replace) { url: function(url) {
if (isUndefined(url)) if (isUndefined(url))
return this.$$url; return this.$$url;
var match = PATH_MATCH.exec(url); var match = PATH_MATCH.exec(url);
if (match[1]) this.path(decodeURIComponent(match[1])); if (match[1]) this.path(decodeURIComponent(match[1]));
if (match[2] || match[1]) this.search(match[3] || ''); if (match[2] || match[1]) this.search(match[3] || '');
this.hash(match[5] || '', replace); this.hash(match[5] || '');
return this; return this;
}, },
...@@ -9517,10 +9537,11 @@ LocationHashbangInHtml5Url.prototype = ...@@ -9517,10 +9537,11 @@ LocationHashbangInHtml5Url.prototype =
* Note: Path should always begin with forward slash (/), this method will add the forward slash * Note: Path should always begin with forward slash (/), this method will add the forward slash
* if it is missing. * if it is missing.
* *
* @param {string=} path New path * @param {(string|number)=} path New path
* @return {string} path * @return {string} path
*/ */
path: locationGetterSetter('$$path', function(path) { path: locationGetterSetter('$$path', function(path) {
path = path ? path.toString() : '';
return path.charAt(0) == '/' ? path : '/' + path; return path.charAt(0) == '/' ? path : '/' + path;
}), }),
...@@ -9556,7 +9577,7 @@ LocationHashbangInHtml5Url.prototype = ...@@ -9556,7 +9577,7 @@ LocationHashbangInHtml5Url.prototype =
* If the argument is a hash object containing an array of values, these values will be encoded * If the argument is a hash object containing an array of values, these values will be encoded
* as duplicate search parameters in the url. * as duplicate search parameters in the url.
* *
* @param {(string|Array<string>|boolean)=} paramValue If `search` is a string, then `paramValue` * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
* will override only a single search property. * will override only a single search property.
* *
* If `paramValue` is an array, it will override the property of the `search` component of * If `paramValue` is an array, it will override the property of the `search` component of
...@@ -9575,7 +9596,8 @@ LocationHashbangInHtml5Url.prototype = ...@@ -9575,7 +9596,8 @@ LocationHashbangInHtml5Url.prototype =
case 0: case 0:
return this.$$search; return this.$$search;
case 1: case 1:
if (isString(search)) { if (isString(search) || isNumber(search)) {
search = search.toString();
this.$$search = parseKeyValue(search); this.$$search = parseKeyValue(search);
} else if (isObject(search)) { } else if (isObject(search)) {
// remove object undefined or null properties // remove object undefined or null properties
...@@ -9612,10 +9634,12 @@ LocationHashbangInHtml5Url.prototype = ...@@ -9612,10 +9634,12 @@ LocationHashbangInHtml5Url.prototype =
* *
* Change hash fragment when called with parameter and return `$location`. * Change hash fragment when called with parameter and return `$location`.
* *
* @param {string=} hash New hash fragment * @param {(string|number)=} hash New hash fragment
* @return {string} hash * @return {string} hash
*/ */
hash: locationGetterSetter('$$hash', identity), hash: locationGetterSetter('$$hash', function(hash) {
return hash ? hash.toString() : '';
}),
/** /**
* @ngdoc method * @ngdoc method
...@@ -9799,7 +9823,7 @@ function $LocationProvider(){ ...@@ -9799,7 +9823,7 @@ function $LocationProvider(){
// http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
var href = elm.attr('href') || elm.attr('xlink:href'); var href = elm.attr('href') || elm.attr('xlink:href');
if (href.indexOf('://') < 0) { // Ignore absolute URLs if (href && href.indexOf('://') < 0) { // Ignore absolute URLs
var prefix = '#' + hashPrefix; var prefix = '#' + hashPrefix;
if (href[0] == '/') { if (href[0] == '/') {
// absolute path - replace old path // absolute path - replace old path
...@@ -9811,6 +9835,7 @@ function $LocationProvider(){ ...@@ -9811,6 +9835,7 @@ function $LocationProvider(){
// relative path - join with current path // relative path - join with current path
var stack = $location.path().split("/"), var stack = $location.path().split("/"),
parts = href.split("/"); parts = href.split("/");
if (stack.length === 2 && !stack[1]) stack.length = 1;
for (var i=0; i<parts.length; i++) { for (var i=0; i<parts.length; i++) {
if (parts[i] == ".") if (parts[i] == ".")
continue; continue;
...@@ -10809,7 +10834,7 @@ Parser.prototype = { ...@@ -10809,7 +10834,7 @@ Parser.prototype = {
var context = contextGetter ? contextGetter(scope, locals) : scope; var context = contextGetter ? contextGetter(scope, locals) : scope;
for (var i = 0; i < argsFn.length; i++) { for (var i = 0; i < argsFn.length; i++) {
args.push(argsFn[i](scope, locals)); args.push(ensureSafeObject(argsFn[i](scope, locals), parser.text));
} }
var fnPtr = fn(scope, locals, context) || noop; var fnPtr = fn(scope, locals, context) || noop;
...@@ -10897,13 +10922,15 @@ Parser.prototype = { ...@@ -10897,13 +10922,15 @@ Parser.prototype = {
////////////////////////////////////////////////// //////////////////////////////////////////////////
function setter(obj, path, setValue, fullExp, options) { function setter(obj, path, setValue, fullExp, options) {
ensureSafeObject(obj, fullExp);
//needed? //needed?
options = options || {}; options = options || {};
var element = path.split('.'), key; var element = path.split('.'), key;
for (var i = 0; element.length > 1; i++) { for (var i = 0; element.length > 1; i++) {
key = ensureSafeMemberName(element.shift(), fullExp); key = ensureSafeMemberName(element.shift(), fullExp);
var propertyObj = obj[key]; var propertyObj = ensureSafeObject(obj[key], fullExp);
if (!propertyObj) { if (!propertyObj) {
propertyObj = {}; propertyObj = {};
obj[key] = propertyObj; obj[key] = propertyObj;
...@@ -10923,7 +10950,6 @@ function setter(obj, path, setValue, fullExp, options) { ...@@ -10923,7 +10950,6 @@ function setter(obj, path, setValue, fullExp, options) {
} }
} }
key = ensureSafeMemberName(element.shift(), fullExp); key = ensureSafeMemberName(element.shift(), fullExp);
ensureSafeObject(obj, fullExp);
ensureSafeObject(obj[key], fullExp); ensureSafeObject(obj[key], fullExp);
obj[key] = setValue; obj[key] = setValue;
return setValue; return setValue;
...@@ -11987,10 +12013,26 @@ function $RootScopeProvider(){ ...@@ -11987,10 +12013,26 @@ function $RootScopeProvider(){
/** /**
* @ngdoc property * @ngdoc property
* @name $rootScope.Scope#$id * @name $rootScope.Scope#$id
* @returns {number} Unique scope ID (monotonically increasing alphanumeric sequence) useful for *
* debugging. * @description
* Unique scope ID (monotonically increasing) useful for debugging.
*/
/**
* @ngdoc property
* @name $rootScope.Scope#$parent
*
* @description
* Reference to the parent scope.
*/ */
/**
* @ngdoc property
* @name $rootScope.Scope#$root
*
* @description
* Reference to the root scope.
*/
Scope.prototype = { Scope.prototype = {
constructor: Scope, constructor: Scope,
...@@ -12002,9 +12044,8 @@ function $RootScopeProvider(){ ...@@ -12002,9 +12044,8 @@ function $RootScopeProvider(){
* @description * @description
* Creates a new child {@link ng.$rootScope.Scope scope}. * Creates a new child {@link ng.$rootScope.Scope scope}.
* *
* The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} and * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
* {@link ng.$rootScope.Scope#$digest $digest()} events. The scope can be removed from the * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
* scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
* *
* {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
* desired for the scope and its child scopes to be permanently detached from the parent and * desired for the scope and its child scopes to be permanently detached from the parent and
...@@ -12457,6 +12498,8 @@ function $RootScopeProvider(){ ...@@ -12457,6 +12498,8 @@ function $RootScopeProvider(){
logIdx, logMsg, asyncTask; logIdx, logMsg, asyncTask;
beginPhase('$digest'); beginPhase('$digest');
// Check for changes to browser url that happened in sync before the call to $digest
$browser.$$checkUrlChange();
lastDirtyWatch = null; lastDirtyWatch = null;
...@@ -13003,7 +13046,7 @@ function $RootScopeProvider(){ ...@@ -13003,7 +13046,7 @@ function $RootScopeProvider(){
*/ */
function $$SanitizeUriProvider() { function $$SanitizeUriProvider() {
var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/, var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//; imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file):|data:image\/)/;
/** /**
* @description * @description
...@@ -14510,16 +14553,6 @@ function $WindowProvider(){ ...@@ -14510,16 +14553,6 @@ function $WindowProvider(){
* For more information about how angular filters work, and how to create your own filters, see * For more information about how angular filters work, and how to create your own filters, see
* {@link guide/filter Filters} in the Angular Developer Guide. * {@link guide/filter Filters} in the Angular Developer Guide.
*/ */
/**
* @ngdoc method
* @name $filterProvider#register
* @description
* Register filter factory function.
*
* @param {String} name Name of the filter.
* @param {Function} fn The filter factory function which is injectable.
*/
/** /**
* @ngdoc service * @ngdoc service
...@@ -14558,7 +14591,7 @@ function $FilterProvider($provide) { ...@@ -14558,7 +14591,7 @@ function $FilterProvider($provide) {
/** /**
* @ngdoc method * @ngdoc method
* @name $controllerProvider#register * @name $filterProvider#register
* @param {string|Object} name Name of the filter function, or an object map of filters where * @param {string|Object} name Name of the filter function, or an object map of filters where
* the keys are the filter names and the values are the filter factories. * the keys are the filter names and the values are the filter factories.
* @returns {Object} Registered filter instance, or if a map of filters was provided then a map * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
...@@ -14631,7 +14664,9 @@ function $FilterProvider($provide) { ...@@ -14631,7 +14664,9 @@ function $FilterProvider($provide) {
* which have property `name` containing "M" and property `phone` containing "1". A special * which have property `name` containing "M" and property `phone` containing "1". A special
* property name `$` can be used (as in `{$:"text"}`) to accept a match against any * property name `$` can be used (as in `{$:"text"}`) to accept a match against any
* property of the object. That's equivalent to the simple substring match with a `string` * property of the object. That's equivalent to the simple substring match with a `string`
* as described above. * as described above. The predicate can be negated by prefixing the string with `!`.
* For Example `{name: "!M"}` predicate will return an array of items which have property `name`
* not containing "M".
* *
* - `function(value)`: A predicate function can be used to write arbitrary filters. The function is * - `function(value)`: A predicate function can be used to write arbitrary filters. The function is
* called for each element of `array`. The final result is an array of those elements that * called for each element of `array`. The final result is an array of those elements that
...@@ -14980,6 +15015,10 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) { ...@@ -14980,6 +15015,10 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize); number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
if (number === 0) {
isNegative = false;
}
var fraction = ('' + number).split(DECIMAL_SEP); var fraction = ('' + number).split(DECIMAL_SEP);
var whole = fraction[0]; var whole = fraction[0];
fraction = fraction[1] || ''; fraction = fraction[1] || '';
...@@ -15149,8 +15188,8 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+ ...@@ -15149,8 +15188,8 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
* * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm) * * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm)
* * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm) * * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm)
* *
* `format` string can contain literal values. These need to be quoted with single quotes (e.g. * `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
* `"h 'in the morning'"`). In order to output single quote, use two single quotes in a sequence * `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
* (e.g. `"h 'o''clock'"`). * (e.g. `"h 'o''clock'"`).
* *
* @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
...@@ -15170,6 +15209,8 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+ ...@@ -15170,6 +15209,8 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
<span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br> <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
<span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>: <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
<span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br> <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
<span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
<span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
</file> </file>
<file name="protractor.js" type="protractor"> <file name="protractor.js" type="protractor">
it('should format date', function() { it('should format date', function() {
...@@ -15179,6 +15220,8 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+ ...@@ -15179,6 +15220,8 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/); toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()). expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/); toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
}); });
</file> </file>
</example> </example>
...@@ -15443,9 +15486,13 @@ function limitToFilter(){ ...@@ -15443,9 +15486,13 @@ function limitToFilter(){
* *
* - `function`: Getter function. The result of this function will be sorted using the * - `function`: Getter function. The result of this function will be sorted using the
* `<`, `=`, `>` operator. * `<`, `=`, `>` operator.
* - `string`: An Angular expression which evaluates to an object to order by, such as 'name' * - `string`: An Angular expression. The result of this expression is used to compare elements
* to sort by a property called 'name'. Optionally prefixed with `+` or `-` to control * (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by
* ascending or descending sort order (for example, +name or -name). * 3 first characters of a property called `name`). The result of a constant expression
* is interpreted as a property name to be used in comparisons (for example `"special name"`
* to sort object by the value of their `special name` property). An expression can be
* optionally prefixed with `+` or `-` to control ascending or descending sort order
* (for example, `+name` or `-name`).
* - `Array`: An array of function or string predicates. The first predicate in the array * - `Array`: An array of function or string predicates. The first predicate in the array
* is used for sorting, but when two items are equivalent, the next predicate is used. * is used for sorting, but when two items are equivalent, the next predicate is used.
* *
...@@ -15536,7 +15583,7 @@ function limitToFilter(){ ...@@ -15536,7 +15583,7 @@ function limitToFilter(){
orderByFilter.$inject = ['$parse']; orderByFilter.$inject = ['$parse'];
function orderByFilter($parse){ function orderByFilter($parse){
return function(array, sortPredicate, reverseOrder) { return function(array, sortPredicate, reverseOrder) {
if (!isArray(array)) return array; if (!(isArrayLike(array))) return array;
if (!sortPredicate) return array; if (!sortPredicate) return array;
sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate]; sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
sortPredicate = map(sortPredicate, function(predicate){ sortPredicate = map(sortPredicate, function(predicate){
...@@ -15813,7 +15860,7 @@ var htmlAnchorDirective = valueFn({ ...@@ -15813,7 +15860,7 @@ var htmlAnchorDirective = valueFn({
* *
* @description * @description
* *
* The following markup will make the button enabled on Chrome/Firefox but not on IE8 and older IEs: * We shouldn't do this, because it will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
* ```html * ```html
* <div ng-init="scope = { isDisabled: false }"> * <div ng-init="scope = { isDisabled: false }">
* <button disabled="{{scope.isDisabled}}">Disabled</button> * <button disabled="{{scope.isDisabled}}">Disabled</button>
...@@ -16033,8 +16080,12 @@ forEach(['src', 'srcset', 'href'], function(attrName) { ...@@ -16033,8 +16080,12 @@ forEach(['src', 'srcset', 'href'], function(attrName) {
} }
attr.$observe(normalized, function(value) { attr.$observe(normalized, function(value) {
if (!value) if (!value) {
if (attrName === 'href') {
attr.$set(name, null);
}
return; return;
}
attr.$set(name, value); attr.$set(name, value);
...@@ -16119,8 +16170,9 @@ function FormController(element, attrs, $scope, $animate) { ...@@ -16119,8 +16170,9 @@ function FormController(element, attrs, $scope, $animate) {
// convenience method for easy toggling of classes // convenience method for easy toggling of classes
function toggleValidCss(isValid, validationErrorKey) { function toggleValidCss(isValid, validationErrorKey) {
validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : ''; validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
$animate.removeClass(element, (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey); $animate.setClass(element,
$animate.addClass(element, (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey); (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey,
(isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
} }
/** /**
...@@ -16335,8 +16387,6 @@ function FormController(element, attrs, $scope, $animate) { ...@@ -16335,8 +16387,6 @@ function FormController(element, attrs, $scope, $animate) {
* hitting enter in any of the input fields will trigger the click handler on the *first* button or * hitting enter in any of the input fields will trigger the click handler on the *first* button or
* input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`) * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
* *
* @param {string=} name Name of the form. If specified, the form controller will be published into
* related scope, under this name.
* *
* ## Animation Hooks * ## Animation Hooks
* *
...@@ -16414,6 +16464,8 @@ function FormController(element, attrs, $scope, $animate) { ...@@ -16414,6 +16464,8 @@ function FormController(element, attrs, $scope, $animate) {
</file> </file>
</example> </example>
* *
* @param {string=} name Name of the form. If specified, the form controller will be published into
* related scope, under this name.
*/ */
var formDirectiveFactory = function(isNgForm) { var formDirectiveFactory = function(isNgForm) {
return ['$timeout', function($timeout) { return ['$timeout', function($timeout) {
...@@ -16492,7 +16544,9 @@ var inputType = { ...@@ -16492,7 +16544,9 @@ var inputType = {
* @name input[text] * @name input[text]
* *
* @description * @description
* Standard HTML text input with angular data binding. * Standard HTML text input with angular data binding, inherited by most of the `input` elements.
*
* *NOTE* Not every feature offered is available for all input types.
* *
* @param {string} ngModel Assignable angular expression to data-bind to. * @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published. * @param {string=} name Property name of the form under which the control is published.
...@@ -16510,6 +16564,8 @@ var inputType = { ...@@ -16510,6 +16564,8 @@ var inputType = {
* @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.
* This parameter is ignored for input[type=password] controls, which will never trim the
* input.
* *
* @example * @example
<example name="text-input-directive" module="textInputExample"> <example name="text-input-directive" module="textInputExample">
...@@ -16949,6 +17005,7 @@ function addNativeHtml5Validators(ctrl, validatorName, badFlags, ignoreFlags, va ...@@ -16949,6 +17005,7 @@ function addNativeHtml5Validators(ctrl, validatorName, badFlags, ignoreFlags, va
function textInputType(scope, element, attr, ctrl, $sniffer, $browser) { function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
var validity = element.prop(VALIDITY_STATE_PROPERTY); var validity = element.prop(VALIDITY_STATE_PROPERTY);
var placeholder = element[0].placeholder, noevent = {}; var placeholder = element[0].placeholder, noevent = {};
var type = lowercase(element[0].type);
ctrl.$$validityState = validity; ctrl.$$validityState = validity;
// In composition mode, users are still inputing intermediate text buffer, // In composition mode, users are still inputing intermediate text buffer,
...@@ -16982,8 +17039,8 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) { ...@@ -16982,8 +17039,8 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
// By default we will trim the value // By default we will trim the value
// If the attribute ng-trim exists we will avoid trimming // If the attribute ng-trim exists we will avoid trimming
// e.g. <input ng-model="foo" ng-trim="false"> // If input type is 'password', the value is never trimmed
if (toBoolean(attr.ngTrim || 'T')) { if (type !== 'password' && (toBoolean(attr.ngTrim || 'T'))) {
value = trim(value); value = trim(value);
} }
...@@ -16992,7 +17049,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) { ...@@ -16992,7 +17049,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
// a row. // a row.
var revalidate = validity && ctrl.$$hasNativeValidators; var revalidate = validity && ctrl.$$hasNativeValidators;
if (ctrl.$viewValue !== value || (value === '' && revalidate)) { if (ctrl.$viewValue !== value || (value === '' && revalidate)) {
if (scope.$$phase) { if (scope.$root.$$phase) {
ctrl.$setViewValue(value); ctrl.$setViewValue(value);
} else { } else {
scope.$apply(function() { scope.$apply(function() {
...@@ -17258,6 +17315,8 @@ function checkboxInputType(scope, element, attr, ctrl) { ...@@ -17258,6 +17315,8 @@ function checkboxInputType(scope, element, attr, ctrl) {
* HTML input element control with angular data-binding. Input control follows HTML5 input types * HTML input element control with angular data-binding. Input control follows HTML5 input types
* and polyfills the HTML5 validation behavior for older browsers. * and polyfills the HTML5 validation behavior for older browsers.
* *
* *NOTE* Not every feature offered is available for all input types.
*
* @param {string} ngModel Assignable angular expression to data-bind to. * @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published. * @param {string=} name Property name of the form under which the control is published.
* @param {string=} required Sets `required` validation error key if the value is not entered. * @param {string=} required Sets `required` validation error key if the value is not entered.
...@@ -17271,6 +17330,9 @@ function checkboxInputType(scope, element, attr, ctrl) { ...@@ -17271,6 +17330,9 @@ function checkboxInputType(scope, element, attr, ctrl) {
* patterns defined as scope expressions. * patterns defined as scope expressions.
* @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.
* This parameter is ignored for input[type=password] controls, which will never trim the
* input.
* *
* @example * @example
<example name="input-directive" module="inputExample"> <example name="input-directive" module="inputExample">
...@@ -18260,7 +18322,6 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) { ...@@ -18260,7 +18322,6 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
* @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate. * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
* *
* @example * @example
Try it here: enter text in text box and watch the greeting change.
<example module="bindHtmlExample" deps="angular-sanitize.js"> <example module="bindHtmlExample" deps="angular-sanitize.js">
<file name="index.html"> <file name="index.html">
...@@ -19030,7 +19091,9 @@ var ngControllerDirective = [function() { ...@@ -19030,7 +19091,9 @@ var ngControllerDirective = [function() {
<button ng-click="count = count + 1" ng-init="count=0"> <button ng-click="count = count + 1" ng-init="count=0">
Increment Increment
</button> </button>
<span>
count: {{count}} count: {{count}}
<span>
</file> </file>
<file name="protractor.js" type="protractor"> <file name="protractor.js" type="protractor">
it('should check ng-click', function() { it('should check ng-click', function() {
...@@ -19048,19 +19111,32 @@ var ngControllerDirective = [function() { ...@@ -19048,19 +19111,32 @@ var ngControllerDirective = [function() {
* Events that are handled via these handler are always configured not to propagate further. * Events that are handled via these handler are always configured not to propagate further.
*/ */
var ngEventDirectives = {}; var ngEventDirectives = {};
// For events that might fire synchronously during DOM manipulation
// we need to execute their event handlers asynchronously using $evalAsync,
// so that they are not executed in an inconsistent state.
var forceAsyncEvents = {
'blur': true,
'focus': true
};
forEach( forEach(
'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '), 'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
function(name) { function(eventName) {
var directiveName = directiveNormalize('ng-' + name); var directiveName = directiveNormalize('ng-' + eventName);
ngEventDirectives[directiveName] = ['$parse', function($parse) { ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
return { return {
compile: function($element, attr) { compile: function($element, attr) {
var fn = $parse(attr[directiveName]); var fn = $parse(attr[directiveName]);
return function ngEventHandler(scope, element) { return function ngEventHandler(scope, element) {
element.on(lowercase(name), function(event) { element.on(eventName, function(event) {
scope.$apply(function() { var callback = function() {
fn(scope, {$event:event}); fn(scope, {$event:event});
}); };
if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
scope.$evalAsync(callback);
} else {
scope.$apply(callback);
}
}); });
}; };
} }
...@@ -19377,6 +19453,10 @@ forEach( ...@@ -19377,6 +19453,10 @@ forEach(
* @description * @description
* Specify custom behavior on focus event. * Specify custom behavior on focus event.
* *
* Note: As the `focus` event is executed synchronously when calling `input.focus()`
* AngularJS executes the expression using `scope.$evalAsync` if the event is fired
* during an `$apply` to ensure a consistent state.
*
* @element window, input, select, textarea, a * @element window, input, select, textarea, a
* @priority 0 * @priority 0
* @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
...@@ -19393,6 +19473,14 @@ forEach( ...@@ -19393,6 +19473,14 @@ forEach(
* @description * @description
* Specify custom behavior on blur event. * Specify custom behavior on blur event.
* *
* A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
* an element has lost focus.
*
* Note: As the `blur` event is executed synchronously also during DOM manipulations
* (e.g. removing a focussed input),
* AngularJS executes the expression using `scope.$evalAsync` if the event is fired
* during an `$apply` to ensure a consistent state.
*
* @element window, input, select, textarea, a * @element window, input, select, textarea, a
* @priority 0 * @priority 0
* @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
...@@ -20473,8 +20561,9 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) { ...@@ -20473,8 +20561,9 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
if (block && block.scope) lastBlockMap[block.id] = block; if (block && block.scope) lastBlockMap[block.id] = block;
}); });
// This is a duplicate and we need to throw an error // This is a duplicate and we need to throw an error
throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}", throw ngRepeatMinErr('dupes',
expression, trackById); "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));
} else { } else {
// new never before seen block // new never before seen block
nextBlockOrder[index] = { id: trackById }; nextBlockOrder[index] = { id: trackById };
...@@ -20565,8 +20654,8 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) { ...@@ -20565,8 +20654,8 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
* *
* @description * @description
* The `ngShow` directive shows or hides the given HTML element based on the expression * The `ngShow` directive shows or hides the given HTML element based on the expression
* provided to the ngShow attribute. The element is shown or hidden by removing or adding * provided to the `ngShow` attribute. The element is shown or hidden by removing or adding
* the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined * the `.ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
* in AngularJS and sets the display style to none (using an !important flag). * in AngularJS and sets the display style to none (using an !important flag).
* For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}). * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
* *
...@@ -20578,8 +20667,8 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) { ...@@ -20578,8 +20667,8 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
* <div ng-show="myValue" class="ng-hide"></div> * <div ng-show="myValue" class="ng-hide"></div>
* ``` * ```
* *
* When the ngShow expression evaluates to false then the ng-hide CSS class is added to the class attribute * When the `ngShow` expression evaluates to false then the `.ng-hide` CSS class is added to the class attribute
* on the element causing it to become hidden. When true, the ng-hide CSS class is removed * on the element causing it to become hidden. When true, the `.ng-hide` CSS class is removed
* from the element causing the element not to appear hidden. * from the element causing the element not to appear hidden.
* *
* <div class="alert alert-warning"> * <div class="alert alert-warning">
...@@ -20589,7 +20678,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) { ...@@ -20589,7 +20678,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
* *
* ## Why is !important used? * ## Why is !important used?
* *
* You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
* can be easily overridden by heavier selectors. For example, something as simple * can be easily overridden by heavier selectors. For example, something as simple
* as changing the display style on a HTML list item would make hidden elements appear visible. * as changing the display style on a HTML list item would make hidden elements appear visible.
* This also becomes a bigger issue when dealing with CSS frameworks. * This also becomes a bigger issue when dealing with CSS frameworks.
...@@ -20598,7 +20687,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) { ...@@ -20598,7 +20687,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
* specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
* styling to change how to hide an element then it is just a matter of using !important in their own CSS code. * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
* *
* ### Overriding .ng-hide * ### Overriding `.ng-hide`
* *
* By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
* the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide` * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
...@@ -20616,7 +20705,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) { ...@@ -20616,7 +20705,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
* *
* By default you don't need to override in CSS anything and the animations will work around the display style. * By default you don't need to override in CSS anything and the animations will work around the display style.
* *
* ## A note about animations with ngShow * ## A note about animations with `ngShow`
* *
* Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
* is true and false. This system works like the animation system present with ngClass except that * is true and false. This system works like the animation system present with ngClass except that
...@@ -20641,8 +20730,8 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) { ...@@ -20641,8 +20730,8 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
* property to block during animation states--ngAnimate will handle the style toggling automatically for you. * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
* *
* @animations * @animations
* addClass: .ng-hide - happens after the ngShow expression evaluates to a truthy value and the just before contents are set to visible * addClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a truthy value and the just before contents are set to visible
* removeClass: .ng-hide - happens after the ngShow expression evaluates to a non truthy value and just before the contents are set to hidden * removeClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden
* *
* @element ANY * @element ANY
* @param {expression} ngShow If the {@link guide/expression expression} is truthy * @param {expression} ngShow If the {@link guide/expression expression} is truthy
...@@ -20722,7 +20811,7 @@ var ngShowDirective = ['$animate', function($animate) { ...@@ -20722,7 +20811,7 @@ var ngShowDirective = ['$animate', function($animate) {
* *
* @description * @description
* The `ngHide` directive shows or hides the given HTML element based on the expression * The `ngHide` directive shows or hides the given HTML element based on the expression
* provided to the ngHide attribute. The element is shown or hidden by removing or adding * provided to the `ngHide` attribute. The element is shown or hidden by removing or adding
* the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
* in AngularJS and sets the display style to none (using an !important flag). * in AngularJS and sets the display style to none (using an !important flag).
* For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}). * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
...@@ -20735,8 +20824,8 @@ var ngShowDirective = ['$animate', function($animate) { ...@@ -20735,8 +20824,8 @@ var ngShowDirective = ['$animate', function($animate) {
* <div ng-hide="myValue"></div> * <div ng-hide="myValue"></div>
* ``` * ```
* *
* When the ngHide expression evaluates to true then the .ng-hide CSS class is added to the class attribute * When the `.ngHide` expression evaluates to true then the `.ng-hide` CSS class is added to the class attribute
* on the element causing it to become hidden. When false, the ng-hide CSS class is removed * on the element causing it to become hidden. When false, the `.ng-hide` CSS class is removed
* from the element causing the element not to appear hidden. * from the element causing the element not to appear hidden.
* *
* <div class="alert alert-warning"> * <div class="alert alert-warning">
...@@ -20746,7 +20835,7 @@ var ngShowDirective = ['$animate', function($animate) { ...@@ -20746,7 +20835,7 @@ var ngShowDirective = ['$animate', function($animate) {
* *
* ## Why is !important used? * ## Why is !important used?
* *
* You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
* can be easily overridden by heavier selectors. For example, something as simple * can be easily overridden by heavier selectors. For example, something as simple
* as changing the display style on a HTML list item would make hidden elements appear visible. * as changing the display style on a HTML list item would make hidden elements appear visible.
* This also becomes a bigger issue when dealing with CSS frameworks. * This also becomes a bigger issue when dealing with CSS frameworks.
...@@ -20755,7 +20844,7 @@ var ngShowDirective = ['$animate', function($animate) { ...@@ -20755,7 +20844,7 @@ var ngShowDirective = ['$animate', function($animate) {
* specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
* styling to change how to hide an element then it is just a matter of using !important in their own CSS code. * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
* *
* ### Overriding .ng-hide * ### Overriding `.ng-hide`
* *
* By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
* the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide` * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
...@@ -20773,7 +20862,7 @@ var ngShowDirective = ['$animate', function($animate) { ...@@ -20773,7 +20862,7 @@ var ngShowDirective = ['$animate', function($animate) {
* *
* By default you don't need to override in CSS anything and the animations will work around the display style. * By default you don't need to override in CSS anything and the animations will work around the display style.
* *
* ## A note about animations with ngHide * ## A note about animations with `ngHide`
* *
* Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
* is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide` * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
...@@ -20797,8 +20886,8 @@ var ngShowDirective = ['$animate', function($animate) { ...@@ -20797,8 +20886,8 @@ var ngShowDirective = ['$animate', function($animate) {
* property to block during animation states--ngAnimate will handle the style toggling automatically for you. * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
* *
* @animations * @animations
* removeClass: .ng-hide - happens after the ngHide expression evaluates to a truthy value and just before the contents are set to hidden * removeClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden
* addClass: .ng-hide - happens after the ngHide expression evaluates to a non truthy value and just before the contents are set to visible * addClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a non truthy value and just before the contents are set to visible
* *
* @element ANY * @element ANY
* @param {expression} ngHide If the {@link guide/expression expression} is truthy then * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
...@@ -21651,6 +21740,19 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) { ...@@ -21651,6 +21740,19 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
ctrl.$render = render; ctrl.$render = render;
scope.$watchCollection(valuesFn, render); scope.$watchCollection(valuesFn, render);
scope.$watchCollection(function () {
var locals = {},
values = valuesFn(scope);
if (values) {
var toDisplay = new Array(values.length);
for (var i = 0, ii = values.length; i < ii; i++) {
locals[valueName] = values[i];
toDisplay[i] = displayFn(scope, locals);
}
return toDisplay;
}
}, render);
if ( multiple ) { if ( multiple ) {
scope.$watchCollection(function() { return ctrl.$modelValue; }, render); scope.$watchCollection(function() { return ctrl.$modelValue; }, render);
} }
......
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