diff --git a/themes/src/main/node_modules/angular-cookies/angular-cookies.js b/themes/src/main/node_modules/angular-cookies/angular-cookies.js index 36a6a54c90..eff080d3c2 100644 --- a/themes/src/main/node_modules/angular-cookies/angular-cookies.js +++ b/themes/src/main/node_modules/angular-cookies/angular-cookies.js @@ -1,6 +1,6 @@ /** - * @license AngularJS v1.6.6 - * (c) 2010-2017 Google, Inc. http://angularjs.org + * @license AngularJS v1.6.10 + * (c) 2010-2018 Google, Inc. http://angularjs.org * License: MIT */ (function(window, angular) {'use strict'; @@ -10,19 +10,14 @@ * @name ngCookies * @description * - * # ngCookies - * * The `ngCookies` module provides a convenient wrapper for reading and writing browser cookies. * - * - *
- * * See {@link ngCookies.$cookies `$cookies`} for usage. */ angular.module('ngCookies', ['ng']). - info({ angularVersion: '1.6.6' }). + info({ angularVersion: '1.6.10' }). /** * @ngdoc provider * @name $cookiesProvider @@ -77,7 +72,7 @@ angular.module('ngCookies', ['ng']). * Provides read/write access to browser's cookies. * *
- * Up until Angular 1.3, `$cookies` exposed properties that represented the + * Up until AngularJS 1.3, `$cookies` exposed properties that represented the * current browser cookie values. In version 1.4, this behavior has changed, and * `$cookies` now provides a standard api of getters, setters etc. *
@@ -203,7 +198,7 @@ angular.module('ngCookies'). * @description * Provides a key-value (string-object) storage, that is backed by session cookies. * Objects put or retrieved from this storage are automatically serialized or - * deserialized by angular's toJson/fromJson. + * deserialized by AngularJS's `toJson`/`fromJson`. * * Requires the {@link ngCookies `ngCookies`} module to be installed. * diff --git a/themes/src/main/node_modules/angular-cookies/angular-cookies.min.js b/themes/src/main/node_modules/angular-cookies/angular-cookies.min.js index 40a21a4779..f1e70564ab 100644 --- a/themes/src/main/node_modules/angular-cookies/angular-cookies.min.js +++ b/themes/src/main/node_modules/angular-cookies/angular-cookies.min.js @@ -1,9 +1,9 @@ /* - AngularJS v1.6.6 - (c) 2010-2017 Google, Inc. http://angularjs.org + AngularJS v1.6.10 + (c) 2010-2018 Google, Inc. http://angularjs.org License: MIT */ (function(n,c){'use strict';function l(b,a,g){var d=g.baseHref(),k=b[0];return function(b,e,f){var g,h;f=f||{};h=f.expires;g=c.isDefined(f.path)?f.path:d;c.isUndefined(e)&&(h="Thu, 01 Jan 1970 00:00:00 GMT",e="");c.isString(h)&&(h=new Date(h));e=encodeURIComponent(b)+"="+encodeURIComponent(e);e=e+(g?";path="+g:"")+(f.domain?";domain="+f.domain:"");e+=h?";expires="+h.toUTCString():"";e+=f.secure?";secure":"";f=e.length+1;4096 4096 bytes)!");k.cookie=e}}c.module("ngCookies",["ng"]).info({angularVersion:"1.6.6"}).provider("$cookies",[function(){var b=this.defaults={};this.$get=["$$cookieReader","$$cookieWriter",function(a,g){return{get:function(d){return a()[d]},getObject:function(d){return(d=this.get(d))?c.fromJson(d):d},getAll:function(){return a()},put:function(d,a,m){g(d,a,m?c.extend({},b,m):b)},putObject:function(d,b,a){this.put(d,c.toJson(b),a)},remove:function(a,k){g(a,void 0,k?c.extend({},b,k):b)}}}]}]);c.module("ngCookies").factory("$cookieStore", +f+" > 4096 bytes)!");k.cookie=e}}c.module("ngCookies",["ng"]).info({angularVersion:"1.6.10"}).provider("$cookies",[function(){var b=this.defaults={};this.$get=["$$cookieReader","$$cookieWriter",function(a,g){return{get:function(d){return a()[d]},getObject:function(d){return(d=this.get(d))?c.fromJson(d):d},getAll:function(){return a()},put:function(d,a,m){g(d,a,m?c.extend({},b,m):b)},putObject:function(d,b,a){this.put(d,c.toJson(b),a)},remove:function(a,k){g(a,void 0,k?c.extend({},b,k):b)}}}]}]);c.module("ngCookies").factory("$cookieStore", ["$cookies",function(b){return{get:function(a){return b.getObject(a)},put:function(a,c){b.putObject(a,c)},remove:function(a){b.remove(a)}}}]);l.$inject=["$document","$log","$browser"];c.module("ngCookies").provider("$$cookieWriter",function(){this.$get=l})})(window,window.angular); //# sourceMappingURL=angular-cookies.min.js.map diff --git a/themes/src/main/node_modules/angular-cookies/angular-cookies.min.js.map b/themes/src/main/node_modules/angular-cookies/angular-cookies.min.js.map index a4278c4d39..18ae127ccf 100644 --- a/themes/src/main/node_modules/angular-cookies/angular-cookies.min.js.map +++ b/themes/src/main/node_modules/angular-cookies/angular-cookies.min.js.map @@ -2,7 +2,7 @@ "version":3, "file":"angular-cookies.min.js", "lineCount":8, -"mappings":"A;;;;;aAKC,SAAQ,CAACA,CAAD,CAASC,CAAT,CAAkB,CAoR3BC,QAASA,EAAc,CAACC,CAAD,CAAYC,CAAZ,CAAkBC,CAAlB,CAA4B,CACjD,IAAIC,EAAaD,CAAAE,SAAA,EAAjB,CACIC,EAAcL,CAAA,CAAU,CAAV,CAmClB,OAAO,SAAQ,CAACM,CAAD,CAAOC,CAAP,CAAcC,CAAd,CAAuB,CAjCW,IAC3CC,CAD2C,CACrCC,CACVF,EAAA,CAgCoDA,CAhCpD,EAAqB,EACrBE,EAAA,CAAUF,CAAAE,QACVD,EAAA,CAAOX,CAAAa,UAAA,CAAkBH,CAAAC,KAAlB,CAAA,CAAkCD,CAAAC,KAAlC,CAAiDN,CACpDL,EAAAc,YAAA,CAAoBL,CAApB,CAAJ,GACEG,CACA,CADU,+BACV,CAAAH,CAAA,CAAQ,EAFV,CAIIT,EAAAe,SAAA,CAAiBH,CAAjB,CAAJ,GACEA,CADF,CACY,IAAII,IAAJ,CAASJ,CAAT,CADZ,CAIIK,EAAAA,CAAMC,kBAAA,CAqB6BV,CArB7B,CAANS,CAAiC,GAAjCA,CAAuCC,kBAAA,CAAmBT,CAAnB,CAE3CQ,EAAA,CADAA,CACA,EADON,CAAA,CAAO,QAAP,CAAkBA,CAAlB,CAAyB,EAChC,GAAOD,CAAAS,OAAA,CAAiB,UAAjB,CAA8BT,CAAAS,OAA9B,CAA+C,EAAtD,CACAF,EAAA,EAAOL,CAAA,CAAU,WAAV,CAAwBA,CAAAQ,YAAA,EAAxB,CAAgD,EACvDH,EAAA,EAAOP,CAAAW,OAAA,CAAiB,SAAjB,CAA6B,EAMhCC,EAAAA,CAAeL,CAAAM,OAAfD,CAA4B,CACb,KAAnB,CAAIA,CAAJ,EACEnB,CAAAqB,KAAA,CAAU,UAAV,CASqChB,CATrC,CACE,6DADF;AAEEc,CAFF,CAEiB,iBAFjB,CASFf,EAAAkB,OAAA,CAJOR,CAG6B,CArCW,CAlQnDjB,CAAA0B,OAAA,CAAe,WAAf,CAA4B,CAAC,IAAD,CAA5B,CAAAC,KAAA,CACO,CAAEC,eAAgB,OAAlB,CADP,CAAAC,SAAA,CAQY,UARZ,CAQwB,CAAaC,QAAyB,EAAG,CAkC7D,IAAIC,EAAW,IAAAA,SAAXA,CAA2B,EAiC/B,KAAAC,KAAA,CAAY,CAAC,gBAAD,CAAmB,gBAAnB,CAAqC,QAAQ,CAACC,CAAD,CAAiBC,CAAjB,CAAiC,CACxF,MAAO,CAWLC,IAAKA,QAAQ,CAACC,CAAD,CAAM,CACjB,MAAOH,EAAA,EAAA,CAAiBG,CAAjB,CADU,CAXd,CAyBLC,UAAWA,QAAQ,CAACD,CAAD,CAAM,CAEvB,MAAO,CADH3B,CACG,CADK,IAAA0B,IAAA,CAASC,CAAT,CACL,EAAQpC,CAAAsC,SAAA,CAAiB7B,CAAjB,CAAR,CAAkCA,CAFlB,CAzBpB,CAuCL8B,OAAQA,QAAQ,EAAG,CACjB,MAAON,EAAA,EADU,CAvCd,CAuDLO,IAAKA,QAAQ,CAACJ,CAAD,CAAM3B,CAAN,CAAaC,CAAb,CAAsB,CACjCwB,CAAA,CAAeE,CAAf,CAAoB3B,CAApB,CAAuCC,CAvFpC,CAAUV,CAAAyC,OAAA,CAAe,EAAf,CAAmBV,CAAnB,CAuF0BrB,CAvF1B,CAAV,CAAkDqB,CAuFrD,CADiC,CAvD9B,CAuELW,UAAWA,QAAQ,CAACN,CAAD,CAAM3B,CAAN,CAAaC,CAAb,CAAsB,CACvC,IAAA8B,IAAA,CAASJ,CAAT,CAAcpC,CAAA2C,OAAA,CAAelC,CAAf,CAAd,CAAqCC,CAArC,CADuC,CAvEpC,CAsFLkC,OAAQA,QAAQ,CAACR,CAAD,CAAM1B,CAAN,CAAe,CAC7BwB,CAAA,CAAeE,CAAf,CAAoBS,IAAAA,EAApB,CAA2CnC,CAtHxC,CAAUV,CAAAyC,OAAA,CAAe,EAAf,CAAmBV,CAAnB,CAsH8BrB,CAtH9B,CAAV,CAAkDqB,CAsHrD,CAD6B,CAtF1B,CADiF,CAA9E,CAnEiD,CAAzC,CARxB,CAyKA/B,EAAA0B,OAAA,CAAe,WAAf,CAAAoB,QAAA,CA+BS,cA/BT;AA+ByB,CAAC,UAAD,CAAa,QAAQ,CAACC,CAAD,CAAW,CAErD,MAAO,CAWLZ,IAAKA,QAAQ,CAACC,CAAD,CAAM,CACjB,MAAOW,EAAAV,UAAA,CAAmBD,CAAnB,CADU,CAXd,CAyBLI,IAAKA,QAAQ,CAACJ,CAAD,CAAM3B,CAAN,CAAa,CACxBsC,CAAAL,UAAA,CAAmBN,CAAnB,CAAwB3B,CAAxB,CADwB,CAzBrB,CAsCLmC,OAAQA,QAAQ,CAACR,CAAD,CAAM,CACpBW,CAAAH,OAAA,CAAgBR,CAAhB,CADoB,CAtCjB,CAF8C,CAAhC,CA/BzB,CAmIAnC,EAAA+C,QAAA,CAAyB,CAAC,WAAD,CAAc,MAAd,CAAsB,UAAtB,CAEzBhD,EAAA0B,OAAA,CAAe,WAAf,CAAAG,SAAA,CAAqC,gBAArC,CAAoEoB,QAA+B,EAAG,CACpG,IAAAjB,KAAA,CAAY/B,CADwF,CAAtG,CAhU2B,CAA1B,CAAD,CAqUGF,MArUH,CAqUWA,MAAAC,QArUX;", +"mappings":"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", "sources":["angular-cookies.js"], "names":["window","angular","$$CookieWriter","$document","$log","$browser","cookiePath","baseHref","rawDocument","name","value","options","path","expires","isDefined","isUndefined","isString","Date","str","encodeURIComponent","domain","toUTCString","secure","cookieLength","length","warn","cookie","module","info","angularVersion","provider","$CookiesProvider","defaults","$get","$$cookieReader","$$cookieWriter","get","key","getObject","fromJson","getAll","put","extend","putObject","toJson","remove","undefined","factory","$cookies","$inject","$$CookieWriterProvider"] } diff --git a/themes/src/main/node_modules/angular-cookies/bower.json b/themes/src/main/node_modules/angular-cookies/bower.json index 4091468186..c124163108 100644 --- a/themes/src/main/node_modules/angular-cookies/bower.json +++ b/themes/src/main/node_modules/angular-cookies/bower.json @@ -1,10 +1,10 @@ { "name": "angular-cookies", - "version": "1.6.6", + "version": "1.6.10", "license": "MIT", "main": "./angular-cookies.js", "ignore": [], "dependencies": { - "angular": "1.6.6" + "angular": "1.6.10" } } diff --git a/themes/src/main/node_modules/angular-cookies/package.json b/themes/src/main/node_modules/angular-cookies/package.json index fa9ba99f60..4e443e0f63 100644 --- a/themes/src/main/node_modules/angular-cookies/package.json +++ b/themes/src/main/node_modules/angular-cookies/package.json @@ -1,27 +1,28 @@ { - "_from": "angular-cookies@1.6.6", - "_id": "angular-cookies@1.6.6", + "_from": "angular-cookies@1.6.10", + "_id": "angular-cookies@1.6.10", "_inBundle": false, - "_integrity": "sha1-MRZC2v28T/fNaSILiSW4g1n7oUg=", + "_integrity": "sha512-ADfbqXLhwcaecAiWIaxpl8XWFJgWsrDl/ksSEkYm5dSoXHYlj3HKlAhPbjBv/foYS7pdI0apmSGHWrBPqdjF/g==", "_location": "/angular-cookies", "_phantomChildren": {}, "_requested": { "type": "version", "registry": true, - "raw": "angular-cookies@1.6.6", + "raw": "angular-cookies@1.6.10", "name": "angular-cookies", "escapedName": "angular-cookies", - "rawSpec": "1.6.6", + "rawSpec": "1.6.10", "saveSpec": null, - "fetchSpec": "1.6.6" + "fetchSpec": "1.6.10" }, "_requiredBy": [ + "#USER", "/" ], - "_resolved": "https://registry.npmjs.org/angular-cookies/-/angular-cookies-1.6.6.tgz", - "_shasum": "311642dafdbc4ff7cd69220b8925b88359fba148", - "_spec": "angular-cookies@1.6.6", - "_where": "/home/st/dev/keycloak/themes/src/main", + "_resolved": "https://registry.npmjs.org/angular-cookies/-/angular-cookies-1.6.10.tgz", + "_shasum": "20a014d501242e2edacd21397c0e5480e08dee00", + "_spec": "angular-cookies@1.6.10", + "_where": "c:\\GitHub\\keycloak\\themes\\src\\main", "author": { "name": "Angular Core Team", "email": "angular-core+npm@google.com" @@ -59,5 +60,5 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, - "version": "1.6.6" + "version": "1.6.10" } diff --git a/themes/src/main/node_modules/angular-loader/angular-loader.js b/themes/src/main/node_modules/angular-loader/angular-loader.js index 7ea2e5012e..7f9b61b3ac 100644 --- a/themes/src/main/node_modules/angular-loader/angular-loader.js +++ b/themes/src/main/node_modules/angular-loader/angular-loader.js @@ -1,6 +1,6 @@ /** - * @license AngularJS v1.6.6 - * (c) 2010-2017 Google, Inc. http://angularjs.org + * @license AngularJS v1.6.10 + * (c) 2010-2018 Google, Inc. http://angularjs.org * License: MIT */ @@ -123,7 +123,7 @@ function isValidObjectMaxDepth(maxDepth) { * @description * * This object provides a utility for producing rich Error messages within - * Angular. It can be called as follows: + * AngularJS. It can be called as follows: * * var exampleMinErr = minErr('example'); * throw exampleMinErr('one', 'This {0} is {1}', foo, bar); @@ -151,6 +151,11 @@ function isValidObjectMaxDepth(maxDepth) { function minErr(module, ErrorConstructor) { ErrorConstructor = ErrorConstructor || Error; + + var url = 'https://errors.angularjs.org/1.6.10/'; + var regex = url.replace('.', '\\.') + '[\\s\\S]*'; + var errRegExp = new RegExp(regex, 'g'); + return function() { var code = arguments[0], template = arguments[1], @@ -160,18 +165,22 @@ function minErr(module, ErrorConstructor) { }), paramPrefix, i; + // A minErr message has two parts: the message itself and the url that contains the + // encoded message. + // The message's parameters can contain other error messages which also include error urls. + // To prevent the messages from getting too long, we strip the error urls from the parameters. + message += template.replace(/\{\d+\}/g, function(match) { var index = +match.slice(1, -1); if (index < templateArgs.length) { - return templateArgs[index]; + return templateArgs[index].replace(errRegExp, ''); } return match; }); - message += '\nhttp://errors.angularjs.org/1.6.6/' + - (module ? module + '/' : '') + code; + message += '\n' + url + (module ? module + '/' : '') + code; for (i = 0, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') { message += paramPrefix + 'p' + i + '=' + encodeURIComponent(templateArgs[i]); @@ -187,7 +196,7 @@ function minErr(module, ErrorConstructor) { * @module ng * @description * - * Interface for configuring angular {@link angular.module modules}. + * Interface for configuring AngularJS {@link angular.module modules}. */ function setupModuleLoader(window) { @@ -214,9 +223,9 @@ function setupModuleLoader(window) { * @module ng * @description * - * The `angular.module` is a global place for creating, registering and retrieving Angular + * The `angular.module` is a global place for creating, registering and retrieving AngularJS * modules. - * All modules (angular core or 3rd party) that should be available to an application must be + * All modules (AngularJS core or 3rd party) that should be available to an application must be * registered using this mechanism. * * Passing one argument retrieves an existing {@link angular.Module}, @@ -466,13 +475,13 @@ function setupModuleLoader(window) { * @ngdoc method * @name angular.Module#filter * @module ng - * @param {string} name Filter name - this must be a valid angular expression identifier + * @param {string} name Filter name - this must be a valid AngularJS expression identifier * @param {Function} filterFactory Factory function for creating new instance of filter. * @description * See {@link ng.$filterProvider#register $filterProvider.register()}. * *
- * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`. + * **Note:** Filter names must be valid AngularJS {@link expression} identifiers, such as `uppercase` or `orderBy`. * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores * (`myapp_subsection_filterx`). @@ -525,7 +534,13 @@ function setupModuleLoader(window) { * @param {Function} configFn Execute this function on module load. Useful for service * configuration. * @description - * Use this method to register work which needs to be performed on module loading. + * Use this method to configure services by injecting their + * {@link angular.Module#provider `providers`}, e.g. for adding routes to the + * {@link ngRoute.$routeProvider $routeProvider}. + * + * Note that you can only inject {@link angular.Module#provider `providers`} and + * {@link angular.Module#constant `constants`} into this function. + * * For more about how to configure services, see * {@link providers#provider-recipe Provider Recipe}. */ diff --git a/themes/src/main/node_modules/angular-loader/angular-loader.min.js b/themes/src/main/node_modules/angular-loader/angular-loader.min.js index fef9c561a0..5e22dfaad1 100644 --- a/themes/src/main/node_modules/angular-loader/angular-loader.min.js +++ b/themes/src/main/node_modules/angular-loader/angular-loader.min.js @@ -1,9 +1,9 @@ /* - AngularJS v1.6.6 - (c) 2010-2017 Google, Inc. http://angularjs.org + AngularJS v1.6.10 + (c) 2010-2018 Google, Inc. http://angularjs.org License: MIT */ -(function(){'use strict';function g(a,f){f=f||Error;return function(){var d=arguments[0],e;e="["+(a?a+":":"")+d+"] http://errors.angularjs.org/1.6.6/"+(a?a+"/":"")+d;for(d=1;d
- * * See {@link ngResource.$resourceProvider} and {@link ngResource.$resource} for usage. */ @@ -295,13 +290,13 @@ function shallowClearAndCopy(src, dst) { * * - `toJSON`: It returns a simple object without any of the extra properties added as part of * the Resource API. This object can be serialized through {@link angular.toJson} safely - * without attaching Angular-specific fields. Notice that `JSON.stringify` (and + * without attaching AngularJS-specific fields. Notice that `JSON.stringify` (and * `angular.toJson`) automatically use this method when serializing a Resource instance * (see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#toJSON%28%29_behavior)). * * @example * - * # Credit card resource + * ### Credit card resource * * ```js // Define CreditCard class @@ -346,7 +341,7 @@ function shallowClearAndCopy(src, dst) { * * @example * - * # User resource + * ### User resource * * When the data is returned from the server then the object is an instance of the resource type and * all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD @@ -387,7 +382,7 @@ function shallowClearAndCopy(src, dst) { * * @example * - * # Creating a custom 'PUT' request + * ### Creating a custom 'PUT' request * * In this example we create a custom method on our resource to make a PUT request * ```js @@ -419,7 +414,7 @@ function shallowClearAndCopy(src, dst) { * * @example * - * # Cancelling requests + * ### Cancelling requests * * If an action's configuration specifies that it is cancellable, you can cancel the request related * to an instance or collection (as long as it is a result of a "non-instance" call): @@ -446,7 +441,7 @@ function shallowClearAndCopy(src, dst) { * */ angular.module('ngResource', ['ng']). - info({ angularVersion: '1.6.6' }). + info({ angularVersion: '1.6.10' }). provider('$resource', function ResourceProvider() { var PROTOCOL_AND_IPV6_REGEX = /^https?:\/\/\[[^\]]*][^/]*/; @@ -851,11 +846,6 @@ angular.module('ngResource', ['ng']). }; }); - Resource.bind = function(additionalParamDefaults) { - var extendedParamDefaults = extend({}, paramDefaults, additionalParamDefaults); - return resourceFactory(url, extendedParamDefaults, actions, options); - }; - return Resource; } diff --git a/themes/src/main/node_modules/angular-resource/angular-resource.min.js b/themes/src/main/node_modules/angular-resource/angular-resource.min.js index 39095c9fb3..d9ce09db87 100644 --- a/themes/src/main/node_modules/angular-resource/angular-resource.min.js +++ b/themes/src/main/node_modules/angular-resource/angular-resource.min.js @@ -1,15 +1,15 @@ /* - AngularJS v1.6.6 - (c) 2010-2017 Google, Inc. http://angularjs.org + AngularJS v1.6.10 + (c) 2010-2018 Google, Inc. http://angularjs.org License: MIT */ -(function(W,b){'use strict';function L(q,g){g=g||{};b.forEach(g,function(b,h){delete g[h]});for(var h in q)!q.hasOwnProperty(h)||"$"===h.charAt(0)&&"$"===h.charAt(1)||(g[h]=q[h]);return g}var B=b.$$minErr("$resource"),Q=/^(\.[a-zA-Z_$@][0-9a-zA-Z_$@]*)+$/;b.module("ngResource",["ng"]).info({angularVersion:"1.6.6"}).provider("$resource",function(){var q=/^https?:\/\/\[[^\]]*][^/]*/,g=this;this.defaults={stripTrailingSlashes:!0,cancellable:!1,actions:{get:{method:"GET"},save:{method:"POST"},query:{method:"GET", -isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}}};this.$get=["$http","$log","$q","$timeout",function(h,P,G,M){function C(b,e){this.template=b;this.defaults=p({},g.defaults,e);this.urlParams={}}function y(D,e,u,n){function c(a,d){var c={};d=p({},e,d);t(d,function(d,l){z(d)&&(d=d(a));var f;if(d&&d.charAt&&"@"===d.charAt(0)){f=a;var k=d.substr(1);if(null==k||""===k||"hasOwnProperty"===k||!Q.test("."+k))throw B("badmember",k);for(var k=k.split("."),e=0,g=k.length;e */ /* global -ngRouteModule */ var ngRouteModule = angular. module('ngRoute', []). - info({ angularVersion: '1.6.6' }). + info({ angularVersion: '1.6.10' }). provider('$route', $RouteProvider). // Ensure `$route` will be instantiated in time to capture the initial `$locationChangeSuccess` // event (unless explicitly disabled). This is necessary in case `ngView` is included in an @@ -79,7 +75,7 @@ var isEagerInstantiationEnabled; * Used for configuring routes. * * ## Example - * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`. + * See {@link ngRoute.$route#examples $route} for an example of configuring and using `ngRoute`. * * ## Dependencies * Requires the {@link ngRoute `ngRoute`} module to be installed. @@ -641,7 +637,7 @@ function $RouteProvider() { // interpolate modifies newParams, only query params are left $location.search(newParams); } else { - throw $routeMinErr('norout', 'Tried updating route when with no current route'); + throw $routeMinErr('norout', 'Tried updating route with no current route'); } } }; @@ -951,7 +947,6 @@ ngRouteModule.directive('ngView', ngViewFillContentFactory); * @restrict ECA * * @description - * # Overview * `ngView` is a directive that complements the {@link ngRoute.$route $route} service by * including the rendered template of the current route into the main layout (`index.html`) file. * Every time the current route changes, the included view changes with it according to the diff --git a/themes/src/main/node_modules/angular-route/angular-route.min.js b/themes/src/main/node_modules/angular-route/angular-route.min.js index 8b42b72dea..7b908cecd0 100644 --- a/themes/src/main/node_modules/angular-route/angular-route.min.js +++ b/themes/src/main/node_modules/angular-route/angular-route.min.js @@ -1,11 +1,11 @@ /* - AngularJS v1.6.6 - (c) 2010-2017 Google, Inc. http://angularjs.org + AngularJS v1.6.10 + (c) 2010-2018 Google, Inc. http://angularjs.org License: MIT */ (function(J,d){'use strict';function A(d){k&&d.get("$route")}function B(t,u,g){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(a,f,b,c,m){function v(){l&&(g.cancel(l),l=null);n&&(n.$destroy(),n=null);p&&(l=g.leave(p),l.done(function(a){!1!==a&&(l=null)}),p=null)}function E(){var b=t.current&&t.current.locals;if(d.isDefined(b&&b.$template)){var b=a.$new(),c=t.current;p=m(b,function(b){g.enter(b,null,p||f).done(function(b){!1===b||!d.isDefined(w)||w&&!a.$eval(w)||u()}); v()});n=c.scope=b;n.$emit("$viewContentLoaded");n.$eval(k)}else v()}var n,p,l,w=b.autoscroll,k=b.onload||"";a.$on("$routeChangeSuccess",E);E()}}}function C(d,k,g){return{restrict:"ECA",priority:-400,link:function(a,f){var b=g.current,c=b.locals;f.html(c.$template);var m=d(f.contents());if(b.controller){c.$scope=a;var v=k(b.controller,c);b.controllerAs&&(a[b.controllerAs]=v);f.data("$ngControllerController",v);f.children().data("$ngControllerController",v)}a[b.resolveAs||"$resolve"]=c;m(a)}}}var x, -y,F,G,z=d.module("ngRoute",[]).info({angularVersion:"1.6.6"}).provider("$route",function(){function t(a,f){return d.extend(Object.create(a),f)}function u(a,d){var b=d.caseInsensitiveMatch,c={originalPath:a,regexp:a},g=c.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)(\*\?|[?*])?/g,function(a,b,d,c){a="?"===c||"*?"===c?"?":null;c="*"===c||"*?"===c?"*":null;g.push({name:d,optional:!!a});b=b||"";return""+(a?"":b)+"(?:"+(a?b:"")+(c&&"(.+?)"||"([^/]+)")+(a||"")+")"+(a||"")}).replace(/([/$*])/g, +y,F,G,z=d.module("ngRoute",[]).info({angularVersion:"1.6.10"}).provider("$route",function(){function t(a,f){return d.extend(Object.create(a),f)}function u(a,d){var b=d.caseInsensitiveMatch,c={originalPath:a,regexp:a},g=c.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)(\*\?|[?*])?/g,function(a,b,d,c){a="?"===c||"*?"===c?"?":null;c="*"===c||"*?"===c?"*":null;g.push({name:d,optional:!!a});b=b||"";return""+(a?"":b)+"(?:"+(a?b:"")+(c&&"(.+?)"||"([^/]+)")+(a||"")+")"+(a||"")}).replace(/([/$*])/g, "\\$1");c.regexp=new RegExp("^"+a+"$",b?"i":"");return c}x=d.isArray;y=d.isObject;F=d.isDefined;G=d.noop;var g={};this.when=function(a,f){var b;b=void 0;if(x(f)){b=b||[];for(var c=0,m=f.length;c - * * See {@link ngSanitize.$sanitize `$sanitize`} for usage. */ @@ -155,9 +151,11 @@ var htmlSanitizeWriter; * Creates and configures {@link $sanitize} instance. */ function $SanitizeProvider() { + var hasBeenInstantiated = false; var svgEnabled = false; this.$get = ['$$sanitizeUri', function($$sanitizeUri) { + hasBeenInstantiated = true; if (svgEnabled) { extend(validElements, svgElements); } @@ -198,7 +196,7 @@ function $SanitizeProvider() { * * * @param {boolean=} flag Enable or disable SVG support in the sanitizer. - * @returns {boolean|ng.$sanitizeProvider} Returns the currently configured value if called + * @returns {boolean|$sanitizeProvider} Returns the currently configured value if called * without an argument or self for chaining otherwise. */ this.enableSvg = function(enableSvg) { @@ -210,6 +208,105 @@ function $SanitizeProvider() { } }; + + /** + * @ngdoc method + * @name $sanitizeProvider#addValidElements + * @kind function + * + * @description + * Extends the built-in lists of valid HTML/SVG elements, i.e. elements that are considered safe + * and are not stripped off during sanitization. You can extend the following lists of elements: + * + * - `htmlElements`: A list of elements (tag names) to extend the current list of safe HTML + * elements. HTML elements considered safe will not be removed during sanitization. All other + * elements will be stripped off. + * + * - `htmlVoidElements`: This is similar to `htmlElements`, but marks the elements as + * "void elements" (similar to HTML + * [void elements](https://rawgit.com/w3c/html/html5.1-2/single-page.html#void-elements)). These + * elements have no end tag and cannot have content. + * + * - `svgElements`: This is similar to `htmlElements`, but for SVG elements. This list is only + * taken into account if SVG is {@link ngSanitize.$sanitizeProvider#enableSvg enabled} for + * `$sanitize`. + * + *
+ * This method must be called during the {@link angular.Module#config config} phase. Once the + * `$sanitize` service has been instantiated, this method has no effect. + *
+ * + *
+ * Keep in mind that extending the built-in lists of elements may expose your app to XSS or + * other vulnerabilities. Be very mindful of the elements you add. + *
+ * + * @param {Array|Object} elements - A list of valid HTML elements or an object with one or + * more of the following properties: + * - **htmlElements** - `{Array}` - A list of elements to extend the current list of + * HTML elements. + * - **htmlVoidElements** - `{Array}` - A list of elements to extend the current list of + * void HTML elements; i.e. elements that do not have an end tag. + * - **svgElements** - `{Array}` - A list of elements to extend the current list of SVG + * elements. The list of SVG elements is only taken into account if SVG is + * {@link ngSanitize.$sanitizeProvider#enableSvg enabled} for `$sanitize`. + * + * Passing an array (`[...]`) is equivalent to passing `{htmlElements: [...]}`. + * + * @return {$sanitizeProvider} Returns self for chaining. + */ + this.addValidElements = function(elements) { + if (!hasBeenInstantiated) { + if (isArray(elements)) { + elements = {htmlElements: elements}; + } + + addElementsTo(svgElements, elements.svgElements); + addElementsTo(voidElements, elements.htmlVoidElements); + addElementsTo(validElements, elements.htmlVoidElements); + addElementsTo(validElements, elements.htmlElements); + } + + return this; + }; + + + /** + * @ngdoc method + * @name $sanitizeProvider#addValidAttrs + * @kind function + * + * @description + * Extends the built-in list of valid attributes, i.e. attributes that are considered safe and are + * not stripped off during sanitization. + * + * **Note**: + * The new attributes will not be treated as URI attributes, which means their values will not be + * sanitized as URIs using `$compileProvider`'s + * {@link ng.$compileProvider#aHrefSanitizationWhitelist aHrefSanitizationWhitelist} and + * {@link ng.$compileProvider#imgSrcSanitizationWhitelist imgSrcSanitizationWhitelist}. + * + *
+ * This method must be called during the {@link angular.Module#config config} phase. Once the + * `$sanitize` service has been instantiated, this method has no effect. + *
+ * + *
+ * Keep in mind that extending the built-in list of attributes may expose your app to XSS or + * other vulnerabilities. Be very mindful of the attributes you add. + *
+ * + * @param {Array} attrs - A list of valid attributes. + * + * @returns {$sanitizeProvider} Returns self for chaining. + */ + this.addValidAttrs = function(attrs) { + if (!hasBeenInstantiated) { + extend(validAttrs, arrayToMap(attrs, true)); + } + return this; + }; + ////////////////////////////////////////////////////////////////////////////////////////////////// // Private stuff ////////////////////////////////////////////////////////////////////////////////////////////////// @@ -217,6 +314,7 @@ function $SanitizeProvider() { bind = angular.bind; extend = angular.extend; forEach = angular.forEach; + isArray = angular.isArray; isDefined = angular.isDefined; lowercase = angular.lowercase; noop = angular.noop; @@ -241,23 +339,23 @@ function $SanitizeProvider() { // Safe Void Elements - HTML5 // http://dev.w3.org/html5/spec/Overview.html#void-elements - var voidElements = toMap('area,br,col,hr,img,wbr'); + var voidElements = stringToMap('area,br,col,hr,img,wbr'); // Elements that you can, intentionally, leave open (and which close themselves) // http://dev.w3.org/html5/spec/Overview.html#optional-tags - var optionalEndTagBlockElements = toMap('colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr'), - optionalEndTagInlineElements = toMap('rp,rt'), + var optionalEndTagBlockElements = stringToMap('colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr'), + optionalEndTagInlineElements = stringToMap('rp,rt'), optionalEndTagElements = extend({}, optionalEndTagInlineElements, optionalEndTagBlockElements); // Safe Block Elements - HTML5 - var blockElements = extend({}, optionalEndTagBlockElements, toMap('address,article,' + + var blockElements = extend({}, optionalEndTagBlockElements, stringToMap('address,article,' + 'aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,' + 'h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul')); // Inline Elements - HTML5 - var inlineElements = extend({}, optionalEndTagInlineElements, toMap('a,abbr,acronym,b,' + + var inlineElements = extend({}, optionalEndTagInlineElements, stringToMap('a,abbr,acronym,b,' + 'bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,' + 'samp,small,span,strike,strong,sub,sup,time,tt,u,var')); @@ -265,12 +363,12 @@ function $SanitizeProvider() { // https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements // Note: the elements animate,animateColor,animateMotion,animateTransform,set are intentionally omitted. // They can potentially allow for arbitrary javascript to be executed. See #11290 - var svgElements = toMap('circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,' + + var svgElements = stringToMap('circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,' + 'hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,' + 'radialGradient,rect,stop,svg,switch,text,title,tspan'); // Blocked Elements (will be stripped) - var blockedElements = toMap('script,style'); + var blockedElements = stringToMap('script,style'); var validElements = extend({}, voidElements, @@ -279,9 +377,9 @@ function $SanitizeProvider() { optionalEndTagElements); //Attributes that have href and hence need to be sanitized - var uriAttrs = toMap('background,cite,href,longdesc,src,xlink:href'); + var uriAttrs = stringToMap('background,cite,href,longdesc,src,xlink:href,xml:base'); - var htmlAttrs = toMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' + + var htmlAttrs = stringToMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' + 'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,' + 'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,' + 'scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,' + @@ -289,7 +387,7 @@ function $SanitizeProvider() { // SVG attributes (without "id" and "name" attributes) // https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes - var svgAttrs = toMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' + + var svgAttrs = stringToMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' + 'baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,' + 'cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,' + 'font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,' + @@ -310,14 +408,24 @@ function $SanitizeProvider() { svgAttrs, htmlAttrs); - function toMap(str, lowercaseKeys) { - var obj = {}, items = str.split(','), i; + function stringToMap(str, lowercaseKeys) { + return arrayToMap(str.split(','), lowercaseKeys); + } + + function arrayToMap(items, lowercaseKeys) { + var obj = {}, i; for (i = 0; i < items.length; i++) { obj[lowercaseKeys ? lowercase(items[i]) : items[i]] = true; } return obj; } + function addElementsTo(elementsMap, newElements) { + if (newElements && newElements.length) { + extend(elementsMap, arrayToMap(newElements)); + } + } + /** * Create an inert document that contains the dirty HTML that needs sanitizing * Depending upon browser support we use one of three strategies for doing this. @@ -604,7 +712,7 @@ function sanitizeText(chars) { // define ngSanitize module and register $sanitize service angular.module('ngSanitize', []) .provider('$sanitize', $SanitizeProvider) - .info({ angularVersion: '1.6.6' }); + .info({ angularVersion: '1.6.10' }); /** * @ngdoc filter @@ -612,13 +720,13 @@ angular.module('ngSanitize', []) * @kind function * * @description - * Finds links in text input and turns them into html links. Supports `http/https/ftp/mailto` and + * Finds links in text input and turns them into html links. Supports `http/https/ftp/sftp/mailto` and * plain email address links. * * Requires the {@link ngSanitize `ngSanitize`} module to be installed. * * @param {string} text Input text. - * @param {string} target Window (`_blank|_self|_parent|_top`) or named frame to open links in. + * @param {string} [target] Window (`_blank|_self|_parent|_top`) or named frame to open links in. * @param {object|function(url)} [attributes] Add custom attributes to the link element. * * Can be one of: @@ -735,7 +843,7 @@ angular.module('ngSanitize', []) */ angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) { var LINKY_URL_REGEXP = - /((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i, + /((s?ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i, MAILTO_REGEXP = /^mailto:/i; var linkyMinErr = angular.$$minErr('linky'); diff --git a/themes/src/main/node_modules/angular-sanitize/angular-sanitize.min.js b/themes/src/main/node_modules/angular-sanitize/angular-sanitize.min.js index e92ccbf100..3e80aff2dd 100644 --- a/themes/src/main/node_modules/angular-sanitize/angular-sanitize.min.js +++ b/themes/src/main/node_modules/angular-sanitize/angular-sanitize.min.js @@ -1,17 +1,18 @@ /* - AngularJS v1.6.6 - (c) 2010-2017 Google, Inc. http://angularjs.org + AngularJS v1.6.10 + (c) 2010-2018 Google, Inc. http://angularjs.org License: MIT */ -(function(s,d){'use strict';function J(d){var k=[];w(k,B).chars(d);return k.join("")}var x=d.$$minErr("$sanitize"),C,k,D,E,p,B,F,G,w;d.module("ngSanitize",[]).provider("$sanitize",function(){function g(a,e){var c={},b=a.split(","),f;for(f=0;f/g,">")}function I(a){for(;a;){if(a.nodeType===s.Node.ELEMENT_NODE)for(var e=a.attributes,c=0,b=e.length;c"))},end:function(a){a=p(a);c||!0!==n[a]||!0===h[a]||(b(""));a==c&&(c=!1)},chars:function(a){c||b(H(a))}}};F=s.Node.prototype.contains||function(a){return!!(this.compareDocumentPosition(a)&16)};var L=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,M=/([^#-~ |!])/g,h=g("area,br,col,hr,img,wbr"),q=g("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),l=g("rp,rt"),r=k({},l,q),q=k({},q,g("address,article,aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul")), -l=k({},l,g("a,abbr,acronym,b,bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small,span,strike,strong,sub,sup,time,tt,u,var")),z=g("circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,radialGradient,rect,stop,svg,switch,text,title,tspan"),A=g("script,style"),n=k({},h,q,l,r),m=g("background,cite,href,longdesc,src,xlink:href"),r=g("abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,valign,value,vspace,width"), -l=g("accent-height,accumulate,additive,alphabetic,arabic-form,ascent,baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan", -!0),v=k({},m,l,r),u=function(a,e){function c(b){b=""+b;try{var c=(new a.DOMParser).parseFromString(b,"text/html").body;c.firstChild.remove();return c}catch(e){}}function b(a){d.innerHTML=a;e.documentMode&&I(d);return d}var h;if(e&&e.implementation)h=e.implementation.createHTMLDocument("inert");else throw x("noinert");var d=(h.documentElement||h.getDocumentElement()).querySelector("body");d.innerHTML='';return d.querySelector("svg")? -(d.innerHTML='

',d.querySelector("svg img")?c:b):function(b){b=""+b;try{b=encodeURI(b)}catch(c){return}var e=new a.XMLHttpRequest;e.responseType="document";e.open("GET","data:text/html;charset=utf-8,"+b,!1);e.send(null);b=e.response.body;b.firstChild.remove();return b}}(s,s.document)}).info({angularVersion:"1.6.6"});d.module("ngSanitize").filter("linky",["$sanitize",function(g){var k=/((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i, -p=/^mailto:/i,s=d.$$minErr("linky"),t=d.isDefined,y=d.isFunction,w=d.isObject,x=d.isString;return function(d,q,l){function r(a){a&&m.push(J(a))}function z(a,d){var c,b=A(a);m.push("');r(d);m.push("")}if(null==d||""===d)return d;if(!x(d))throw s("notstring",d);for(var A=y(l)?l:w(l)?function(){return l}:function(){return{}},n=d,m=[],v,u;d=n.match(k);)v=d[0],d[2]|| -d[4]||(v=(d[3]?"http://":"mailto:")+v),u=d.index,r(n.substr(0,u)),z(v,d[0].replace(p,"")),n=n.substring(u+d[0].length);r(n);return g(m.join(""))}}])})(window,window.angular); +(function(s,c){'use strict';function P(c){var h=[];C(h,E).chars(c);return h.join("")}var D=c.$$minErr("$sanitize"),F,h,G,H,I,q,E,J,K,C;c.module("ngSanitize",[]).provider("$sanitize",function(){function f(a,e){return B(a.split(","),e)}function B(a,e){var d={},b;for(b=0;b/g,">")}function A(a){for(;a;){if(a.nodeType===s.Node.ELEMENT_NODE)for(var e=a.attributes,d=0,b=e.length;d"))},end:function(a){a=q(a);d||!0!==m[a]||!0===r[a]||(b(""));a==d&&(d=!1)},chars:function(a){d||b(L(a))}}}; +J=s.Node.prototype.contains||function(a){return!!(this.compareDocumentPosition(a)&16)};var z=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,u=/([^#-~ |!])/g,r=f("area,br,col,hr,img,wbr"),x=f("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),p=f("rp,rt"),n=h({},p,x),x=h({},x,f("address,article,aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul")),p=h({},p,f("a,abbr,acronym,b,bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small,span,strike,strong,sub,sup,time,tt,u,var")), +l=f("circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,radialGradient,rect,stop,svg,switch,text,title,tspan"),w=f("script,style"),m=h({},r,x,p,n),O=f("background,cite,href,longdesc,src,xlink:href,xml:base"),n=f("abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,valign,value,vspace,width"), +p=f("accent-height,accumulate,additive,alphabetic,arabic-form,ascent,baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan", +!0),M=h({},O,p,n),N=function(a,e){function d(b){b=""+b;try{var d=(new a.DOMParser).parseFromString(b,"text/html").body;d.firstChild.remove();return d}catch(e){}}function b(a){c.innerHTML=a;e.documentMode&&A(c);return c}var g;if(e&&e.implementation)g=e.implementation.createHTMLDocument("inert");else throw D("noinert");var c=(g.documentElement||g.getDocumentElement()).querySelector("body");c.innerHTML='';return c.querySelector("svg")? +(c.innerHTML='

',c.querySelector("svg img")?d:b):function(b){b=""+b;try{b=encodeURI(b)}catch(d){return}var e=new a.XMLHttpRequest;e.responseType="document";e.open("GET","data:text/html;charset=utf-8,"+b,!1);e.send(null);b=e.response.body;b.firstChild.remove();return b}}(s,s.document)}).info({angularVersion:"1.6.10"});c.module("ngSanitize").filter("linky",["$sanitize",function(f){var h=/((s?ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i, +t=/^mailto:/i,q=c.$$minErr("linky"),s=c.isDefined,A=c.isFunction,v=c.isObject,y=c.isString;return function(c,z,u){function r(c){c&&l.push(P(c))}function x(c,g){var f,a=p(c);l.push("');r(g);l.push("")}if(null==c||""===c)return c;if(!y(c))throw q("notstring",c);for(var p=A(u)?u:v(u)?function(){return u}:function(){return{}},n=c,l=[],w,m;c=n.match(h);)w=c[0],c[2]|| +c[4]||(w=(c[3]?"http://":"mailto:")+w),m=c.index,r(n.substr(0,m)),x(w,c[0].replace(t,"")),n=n.substring(m+c[0].length);r(n);return f(l.join(""))}}])})(window,window.angular); //# sourceMappingURL=angular-sanitize.min.js.map diff --git a/themes/src/main/node_modules/angular-sanitize/angular-sanitize.min.js.map b/themes/src/main/node_modules/angular-sanitize/angular-sanitize.min.js.map index 475690d12b..6fbc51ce50 100644 --- a/themes/src/main/node_modules/angular-sanitize/angular-sanitize.min.js.map +++ b/themes/src/main/node_modules/angular-sanitize/angular-sanitize.min.js.map @@ -1,8 +1,8 @@ { "version":3, "file":"angular-sanitize.min.js", -"lineCount":16, -"mappings":"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", +"lineCount":17, +"mappings":"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", "sources":["angular-sanitize.js"], -"names":["window","angular","sanitizeText","chars","buf","htmlSanitizeWriter","writer","noop","join","$sanitizeMinErr","$$minErr","bind","extend","forEach","isDefined","lowercase","nodeContains","htmlParser","module","provider","$SanitizeProvider","toMap","str","lowercaseKeys","obj","items","split","i","length","attrToMap","attrs","map","ii","attr","name","value","encodeEntities","replace","SURROGATE_PAIR_REGEXP","hi","charCodeAt","low","NON_ALPHANUMERIC_REGEXP","stripCustomNsAttrs","node","nodeType","Node","ELEMENT_NODE","attributes","l","attrNode","attrName","toLowerCase","lastIndexOf","removeAttributeNode","nextNode","firstChild","getNonDescendant","propName","call","outerHTML","outerText","svgEnabled","$get","$$sanitizeUri","validElements","svgElements","html","uri","isImage","test","enableSvg","this.enableSvg","htmlParserImpl","handler","undefined","inertBodyElement","getInertBodyElement","mXSSAttempts","innerHTML","start","nodeName","textContent","end","removeChild","htmlSanitizeWriterImpl","uriValidator","ignoreCurrentElement","out","push","tag","blockedElements","key","lkey","validAttrs","uriAttrs","voidElements","prototype","contains","arg","compareDocumentPosition","optionalEndTagBlockElements","optionalEndTagInlineElements","optionalEndTagElements","blockElements","inlineElements","htmlAttrs","svgAttrs","document","getInertBodyElement_DOMParser","body","parseFromString","DOMParser","remove","e","getInertBodyElement_InertDocument","documentMode","inertDocument","implementation","createHTMLDocument","querySelector","documentElement","getDocumentElement","getInertBodyElement_XHR","encodeURI","xhr","XMLHttpRequest","responseType","open","send","response","info","angularVersion","filter","$sanitize","LINKY_URL_REGEXP","MAILTO_REGEXP","linkyMinErr","isFunction","isObject","isString","text","target","addText","addLink","url","linkAttributes","attributesFn","getAttributesObject","getEmptyAttributesObject","raw","match","index","substr","substring"] +"names":["window","angular","sanitizeText","chars","buf","htmlSanitizeWriter","writer","noop","join","$sanitizeMinErr","$$minErr","bind","extend","forEach","isArray","isDefined","lowercase","nodeContains","htmlParser","module","provider","$SanitizeProvider","stringToMap","str","lowercaseKeys","arrayToMap","split","items","obj","i","length","addElementsTo","elementsMap","newElements","attrToMap","attrs","map","ii","attr","name","value","encodeEntities","replace","SURROGATE_PAIR_REGEXP","hi","charCodeAt","low","NON_ALPHANUMERIC_REGEXP","stripCustomNsAttrs","node","nodeType","Node","ELEMENT_NODE","attributes","l","attrNode","attrName","toLowerCase","lastIndexOf","removeAttributeNode","nextNode","firstChild","getNonDescendant","propName","call","outerHTML","outerText","hasBeenInstantiated","svgEnabled","$get","$$sanitizeUri","validElements","svgElements","html","uri","isImage","test","enableSvg","this.enableSvg","addValidElements","this.addValidElements","elements","htmlElements","voidElements","htmlVoidElements","addValidAttrs","this.addValidAttrs","validAttrs","htmlParserImpl","handler","undefined","inertBodyElement","getInertBodyElement","mXSSAttempts","innerHTML","start","nodeName","textContent","end","removeChild","htmlSanitizeWriterImpl","uriValidator","ignoreCurrentElement","out","push","tag","blockedElements","key","lkey","uriAttrs","prototype","contains","arg","compareDocumentPosition","optionalEndTagBlockElements","optionalEndTagInlineElements","optionalEndTagElements","blockElements","inlineElements","htmlAttrs","svgAttrs","document","getInertBodyElement_DOMParser","body","parseFromString","DOMParser","remove","e","getInertBodyElement_InertDocument","documentMode","inertDocument","implementation","createHTMLDocument","querySelector","documentElement","getDocumentElement","getInertBodyElement_XHR","encodeURI","xhr","XMLHttpRequest","responseType","open","send","response","info","angularVersion","filter","$sanitize","LINKY_URL_REGEXP","MAILTO_REGEXP","linkyMinErr","isFunction","isObject","isString","text","target","addText","addLink","url","linkAttributes","attributesFn","getAttributesObject","getEmptyAttributesObject","raw","match","index","substr","substring"] } diff --git a/themes/src/main/node_modules/angular-sanitize/bower.json b/themes/src/main/node_modules/angular-sanitize/bower.json index 4dcf9b30ab..256e80123b 100644 --- a/themes/src/main/node_modules/angular-sanitize/bower.json +++ b/themes/src/main/node_modules/angular-sanitize/bower.json @@ -1,10 +1,10 @@ { "name": "angular-sanitize", - "version": "1.6.6", + "version": "1.6.10", "license": "MIT", "main": "./angular-sanitize.js", "ignore": [], "dependencies": { - "angular": "1.6.6" + "angular": "1.6.10" } } diff --git a/themes/src/main/node_modules/angular-sanitize/package.json b/themes/src/main/node_modules/angular-sanitize/package.json index 7ee8305cb1..5ae02fb109 100644 --- a/themes/src/main/node_modules/angular-sanitize/package.json +++ b/themes/src/main/node_modules/angular-sanitize/package.json @@ -1,27 +1,28 @@ { - "_from": "angular-sanitize@1.6.6", - "_id": "angular-sanitize@1.6.6", + "_from": "angular-sanitize@1.6.10", + "_id": "angular-sanitize@1.6.10", "_inBundle": false, - "_integrity": "sha1-D9BloZkxUX++zmZZbTJdcrbgYEE=", + "_integrity": "sha512-01i1Xoq9ykUrsoYQMSB6dWZmPp9Df5hfCqMAGGzJBWZ7L2WY0OtUphdI0YvR8ZF9lAsWtGNtsEFilObjq5nTgQ==", "_location": "/angular-sanitize", "_phantomChildren": {}, "_requested": { "type": "version", "registry": true, - "raw": "angular-sanitize@1.6.6", + "raw": "angular-sanitize@1.6.10", "name": "angular-sanitize", "escapedName": "angular-sanitize", - "rawSpec": "1.6.6", + "rawSpec": "1.6.10", "saveSpec": null, - "fetchSpec": "1.6.6" + "fetchSpec": "1.6.10" }, "_requiredBy": [ + "#USER", "/" ], - "_resolved": "https://registry.npmjs.org/angular-sanitize/-/angular-sanitize-1.6.6.tgz", - "_shasum": "0fd065a19931517fbece66596d325d72b6e06041", - "_spec": "angular-sanitize@1.6.6", - "_where": "/home/st/dev/keycloak/themes/src/main", + "_resolved": "https://registry.npmjs.org/angular-sanitize/-/angular-sanitize-1.6.10.tgz", + "_shasum": "635a362afb2dd040179f17d3a5455962b2c1918f", + "_spec": "angular-sanitize@1.6.10", + "_where": "c:\\GitHub\\keycloak\\themes\\src\\main", "author": { "name": "Angular Core Team", "email": "angular-core+npm@google.com" @@ -59,5 +60,5 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, - "version": "1.6.6" + "version": "1.6.10" } diff --git a/themes/src/main/node_modules/angular/angular.js b/themes/src/main/node_modules/angular/angular.js index 9a0594da53..c7666cbac4 100644 --- a/themes/src/main/node_modules/angular/angular.js +++ b/themes/src/main/node_modules/angular/angular.js @@ -1,6 +1,6 @@ /** - * @license AngularJS v1.6.6 - * (c) 2010-2017 Google, Inc. http://angularjs.org + * @license AngularJS v1.6.10 + * (c) 2010-2018 Google, Inc. http://angularjs.org * License: MIT */ (function(window) {'use strict'; @@ -59,7 +59,7 @@ function isValidObjectMaxDepth(maxDepth) { * @description * * This object provides a utility for producing rich Error messages within - * Angular. It can be called as follows: + * AngularJS. It can be called as follows: * * var exampleMinErr = minErr('example'); * throw exampleMinErr('one', 'This {0} is {1}', foo, bar); @@ -87,6 +87,11 @@ function isValidObjectMaxDepth(maxDepth) { function minErr(module, ErrorConstructor) { ErrorConstructor = ErrorConstructor || Error; + + var url = 'https://errors.angularjs.org/1.6.10/'; + var regex = url.replace('.', '\\.') + '[\\s\\S]*'; + var errRegExp = new RegExp(regex, 'g'); + return function() { var code = arguments[0], template = arguments[1], @@ -96,18 +101,22 @@ function minErr(module, ErrorConstructor) { }), paramPrefix, i; + // A minErr message has two parts: the message itself and the url that contains the + // encoded message. + // The message's parameters can contain other error messages which also include error urls. + // To prevent the messages from getting too long, we strip the error urls from the parameters. + message += template.replace(/\{\d+\}/g, function(match) { var index = +match.slice(1, -1); if (index < templateArgs.length) { - return templateArgs[index]; + return templateArgs[index].replace(errRegExp, ''); } return match; }); - message += '\nhttp://errors.angularjs.org/1.6.6/' + - (module ? module + '/' : '') + code; + message += '\n' + url + (module ? module + '/' : '') + code; for (i = 0, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') { message += paramPrefix + 'p' + i + '=' + encodeURIComponent(templateArgs[i]); @@ -192,6 +201,7 @@ function minErr(module, ErrorConstructor) { fromJson, convertTimezoneToLocal, timezoneToOffset, + addDateMinutes, startingTag, tryDecodeURIComponent, parseKeyValue, @@ -229,13 +239,11 @@ function minErr(module, ErrorConstructor) { * @installation * @description * - * # ng (core module) * The ng module is loaded by default when an AngularJS application is started. The module itself * contains the essential components for an AngularJS application to function. The table below * lists a high level breakdown of each of the services/factories, filters, directives and testing * components available within this core module. * - *

*/ var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/; @@ -976,7 +984,7 @@ function arrayRemove(array, value) {
form = {{user | json}}
-
master = {{master | json}}
+
leader = {{leader | json}}
@@ -984,16 +992,16 @@ function arrayRemove(array, value) { angular. module('copyExample', []). controller('ExampleController', ['$scope', function($scope) { - $scope.master = {}; + $scope.leader = {}; $scope.reset = function() { // Example with 1 argument - $scope.user = angular.copy($scope.master); + $scope.user = angular.copy($scope.leader); }; $scope.update = function(user) { // Example with 2 arguments - angular.copy(user, $scope.master); + angular.copy(user, $scope.leader); }; $scope.reset(); @@ -1304,7 +1312,7 @@ var csp = function() { * used to force either jqLite by leaving ng-jq blank or setting the name of * the jquery variable under window (eg. jQuery). * - * Since angular looks for this directive when it is loaded (doesn't wait for the + * Since AngularJS looks for this directive when it is loaded (doesn't wait for the * DOMContentLoaded event), it must be placed on an element that comes before the script * which loads angular. Also, only the first instance of `ng-jq` will be used and all * others ignored. @@ -1417,7 +1425,7 @@ function toJsonReplacer(key, value) { * * @description * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be - * stripped since angular uses this notation internally. + * stripped since AngularJS uses this notation internally. * * @param {Object|Array|Date|string|number|boolean} obj Input to be serialized into JSON. * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace. @@ -1503,7 +1511,7 @@ function convertTimezoneToLocal(date, timezone, reverse) { */ function startingTag(element) { element = jqLite(element).clone().empty(); - var elemHtml = jqLite('
').append(element).html(); + var elemHtml = jqLite('
').append(element).html(); try { return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) : elemHtml. @@ -1729,6 +1737,10 @@ var isAutoBootstrapAllowed = allowAutoBootstrap(window.document); * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}` * would not be resolved to `3`. * + * @example + * + * ### Simple Usage + * * `ngApp` is the easiest, and most common way to bootstrap an application. * @@ -1745,6 +1757,10 @@ var isAutoBootstrapAllowed = allowAutoBootstrap(window.document); * + * @example + * + * ### With `ngStrictDi` + * * Using `ngStrictDi`, you would see something like this: * @@ -1847,7 +1863,7 @@ function angularInit(element, bootstrap) { }); if (appElement) { if (!isAutoBootstrapAllowed) { - window.console.error('Angular: disabling automatic bootstrap. @@ -7943,11 +8024,11 @@ function $TemplateCacheProvider() { it('should auto compile', function() { var textarea = $('textarea'); var output = $('div[compile]'); - // The initial state reads 'Hello Angular'. - expect(output.getText()).toBe('Hello Angular'); + // The initial state reads 'Hello AngularJS'. + expect(output.getText()).toBe('Hello AngularJS'); textarea.clear(); textarea.sendKeys('{{name}}!'); - expect(output.getText()).toBe('Angular!'); + expect(output.getText()).toBe('AngularJS!'); }); @@ -8001,7 +8082,7 @@ function $TemplateCacheProvider() { * element passed in, or the clone of the element if the `cloneAttachFn` is provided. * * After linking the view is not updated until after a call to $digest which typically is done by - * Angular automatically. + * AngularJS automatically. * * If you need access to the bound view, there are two ways to do it: * @@ -8027,7 +8108,7 @@ function $TemplateCacheProvider() { * * * For information on how the compiler works, see the - * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide. + * {@link guide/compiler AngularJS HTML Compiler} section of the Developer Guide. * * @knownIssue * @@ -8037,6 +8118,59 @@ function $TemplateCacheProvider() { compiled again. This is an undesired effect and can lead to misbehaving directives, performance issues, and memory leaks. Refer to the Compiler Guide {@link guide/compiler#double-compilation-and-how-to-avoid-it section on double compilation} for an in-depth explanation and ways to avoid it. + + * @knownIssue + + ### Issues with `replace: true` + * + *
+ * **Note**: {@link $compile#-replace- `replace: true`} is deprecated and not recommended to use, + * mainly due to the issues listed here. It has been completely removed in the new Angular. + *
+ * + * #### Attribute values are not merged + * + * When a `replace` directive encounters the same attribute on the original and the replace node, + * it will simply deduplicate the attribute and join the values with a space or with a `;` in case of + * the `style` attribute. + * ```html + * Original Node: + * Replace Template: + * Result: + * ``` + * + * That means attributes that contain AngularJS expressions will not be merged correctly, e.g. + * {@link ngShow} or {@link ngClass} will cause a {@link $parse} error: + * + * ```html + * Original Node: + * Replace Template: + * Result: + * ``` + * + * See issue [#5695](https://github.com/angular/angular.js/issues/5695). + * + * #### Directives are not deduplicated before compilation + * + * When the original node and the replace template declare the same directive(s), they will be + * {@link guide/compiler#double-compilation-and-how-to-avoid-it compiled twice} because the compiler + * does not deduplicate them. In many cases, this is not noticable, but e.g. {@link ngModel} will + * attach `$formatters` and `$parsers` twice. + * + * See issue [#2573](https://github.com/angular/angular.js/issues/2573). + * + * #### `transclude: element` in the replace template root can have + * unexpected effects + * + * When the replace template has a directive at the root node that uses + * {@link $compile#-transclude- `transclude: element`}, e.g. + * {@link ngIf} or {@link ngRepeat}, the DOM structure or scope inheritance can be incorrect. + * See the following issues: + * + * - Incorrect scope on replaced element: + * [#9837](https://github.com/angular/angular.js/issues/9837) + * - Different DOM between `template` and `templateUrl`: + * [#10612](https://github.com/angular/angular.js/issues/14326) * */ @@ -8068,11 +8202,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { var bindingCache = createMap(); function parseIsolateBindings(scope, directiveName, isController) { - var LOCAL_REGEXP = /^\s*([@&<]|=(\*?))(\??)\s*([\w$]*)\s*$/; + var LOCAL_REGEXP = /^([@&<]|=(\*?))(\??)\s*([\w$]*)$/; var bindings = createMap(); forEach(scope, function(definition, scopeName) { + definition = definition.trim(); + if (definition in bindingCache) { bindings[scopeName] = bindingCache[definition]; return; @@ -8351,7 +8487,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { // TODO(pete) remove the following `forEach` before we release 1.6.0 // The component-router@0.2.0 looks for the annotations on the controller constructor - // Nothing in Angular looks for annotations on the factory function but we can't remove + // Nothing in AngularJS looks for annotations on the factory function but we can't remove // it from 1.5.x yet. // Copy any annotation properties (starting with $) over to the factory and controller constructor functions @@ -8444,7 +8580,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { * binding information and a reference to the current scope on to DOM elements. * If enabled, the compiler will add the following to DOM elements that have been bound to the scope * * `ng-binding` CSS class + * * `ng-scope` and `ng-isolated-scope` CSS classes * * `$binding` data property containing an array of the binding expressions + * * Data properties used by the {@link angular.element#methods `scope()`/`isolateScope()` methods} to return + * the element's scope. + * * Placeholder comments will contain information about what directive and binding caused the placeholder. + * E.g. ``. * * You may want to disable this in production for a significant performance boost. See * {@link guide/production#disabling-debug-data Disabling Debug Data} for more. @@ -8637,19 +8778,15 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { } // We must run this hook in an apply since the $$postDigest runs outside apply $rootScope.$apply(function() { - var errors = []; for (var i = 0, ii = onChangesQueue.length; i < ii; ++i) { try { onChangesQueue[i](); } catch (e) { - errors.push(e); + $exceptionHandler(e); } } // Reset the queue to trigger a new schedule next time there is a change onChangesQueue = undefined; - if (errors.length) { - throw errors; - } }); } finally { onChangesTtl++; @@ -8795,7 +8932,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { if ((nodeName === 'a' && (key === 'href' || key === 'xlinkHref')) || (nodeName === 'img' && key === 'src')) { // sanitize a[href] and img[src] values - this[key] = value = $$sanitizeUri(value, key === 'src'); + this[key] = value = (value == null) ? value : $$sanitizeUri(value, key === 'src'); } else if (nodeName === 'img' && key === 'srcset' && isDefined(value)) { // sanitize img[srcset] values var result = ''; @@ -8833,7 +8970,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { } if (writeAttr !== false) { - if (value === null || isUndefined(value)) { + if (value == null) { this.$$element.removeAttr(attrName); } else { if (SIMPLE_ATTR_NAME.test(attrName)) { @@ -9017,7 +9154,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { // for call to the link function. // Note: This will already clone the nodes... $linkNode = jqLite( - wrapTemplate(namespace, jqLite('
').append($compileNodes).html()) + wrapTemplate(namespace, jqLite('
').append($compileNodes).html()) ); } else if (cloneConnectFn) { // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart @@ -10513,7 +10650,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { } if (jqLite.hasData(firstElementToRemove)) { - // Copy over user data (that includes Angular's $scope etc.). Don't copy private + // Copy over user data (that includes AngularJS's $scope etc.). Don't copy private // data here because there's no public interface in jQuery to do that and copying over // event listeners (which is the main use of private data) wouldn't work anyway. jqLite.data(newNode, jqLite.data(firstElementToRemove)); @@ -10591,7 +10728,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { // the value is there for use in the link fn destination[scopeName] = $interpolate(lastValue)(scope); } else if (isBoolean(lastValue)) { - // If the attributes is one of the BOOLEAN_ATTR then Angular will have converted + // If the attributes is one of the BOOLEAN_ATTR then AngularJS will have converted // the value to boolean rather than a string, so we special case this situation destination[scopeName] = lastValue; } @@ -10745,7 +10882,9 @@ var SPECIAL_CHARS_REGEXP = /[:\-_]+(.)/g; function directiveNormalize(name) { return name .replace(PREFIX_REGEXP, '') - .replace(SPECIAL_CHARS_REGEXP, fnCamelCaseReplace); + .replace(SPECIAL_CHARS_REGEXP, function(_, letter, offset) { + return offset ? letter.toUpperCase() : letter; + }); } /** @@ -10755,7 +10894,7 @@ function directiveNormalize(name) { * @description * A shared object between directive compile / linking functions which contains normalized DOM * element attributes. The values reflect current binding state `{{ }}`. The normalization is - * needed since all of these are treated as equivalent in Angular: + * needed since all of these are treated as equivalent in AngularJS: * * ``` * @@ -10861,7 +11000,7 @@ function identifierForController(controller, ident) { * @this * * @description - * The {@link ng.$controller $controller service} is used by Angular to create new + * The {@link ng.$controller $controller service} is used by AngularJS to create new * controllers. * * This provider allows controller registration via the @@ -11099,7 +11238,7 @@ function $$IsDocumentHiddenProvider() { * @this * * @description - * Any uncaught exception in angular expressions is delegated to this service. + * Any uncaught exception in AngularJS expressions is delegated to this service. * The default implementation simply delegates to `$log.error` which logs it into * the browser console. * @@ -11201,7 +11340,7 @@ function $HttpParamSerializerProvider() { * * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D` (stringified and encoded representation of an object) * * Note that serializer will sort the request parameters alphabetically. - * */ + */ this.$get = function() { return function ngParamSerializer(params) { @@ -11268,7 +11407,7 @@ function $HttpParamSerializerJQLikeProvider() { * }); * ``` * - * */ + */ this.$get = function() { return function jQueryLikeParamSerializer(params) { if (!params) return ''; @@ -11425,7 +11564,7 @@ function isSuccess(status) { * * @description * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service. - * */ + */ function $HttpProvider() { /** * @ngdoc property @@ -11479,7 +11618,7 @@ function $HttpProvider() { * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the * XSRF token. Defaults value is `'X-XSRF-TOKEN'`. * - **/ + */ var defaults = this.defaults = { // transform incoming response data transformResponse: [defaultHttpResponseTransform], @@ -11526,7 +11665,7 @@ function $HttpProvider() { * * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining. * otherwise, returns the current configured value. - **/ + */ this.useApplyAsync = function(value) { if (isDefined(value)) { useApplyAsync = !!value; @@ -11547,9 +11686,51 @@ function $HttpProvider() { * array, on request, but reverse order, on response. * * {@link ng.$http#interceptors Interceptors detailed info} - **/ + */ var interceptorFactories = this.interceptors = []; + /** + * @ngdoc property + * @name $httpProvider#xsrfWhitelistedOrigins + * @description + * + * Array containing URLs whose origins are trusted to receive the XSRF token. See the + * {@link ng.$http#security-considerations Security Considerations} sections for more details on + * XSRF. + * + * **Note:** An "origin" consists of the [URI scheme](https://en.wikipedia.org/wiki/URI_scheme), + * the [hostname](https://en.wikipedia.org/wiki/Hostname) and the + * [port number](https://en.wikipedia.org/wiki/Port_(computer_networking). For `http:` and + * `https:`, the port number can be omitted if using th default ports (80 and 443 respectively). + * Examples: `http://example.com`, `https://api.example.com:9876` + * + *
+ * It is not possible to whitelist specific URLs/paths. The `path`, `query` and `fragment` parts + * of a URL will be ignored. For example, `https://foo.com/path/bar?query=baz#fragment` will be + * treated as `https://foo.com`, meaning that **all** requests to URLs starting with + * `https://foo.com/` will include the XSRF token. + *
+ * + * @example + * + * ```js + * // App served from `https://example.com/`. + * angular. + * module('xsrfWhitelistedOriginsExample', []). + * config(['$httpProvider', function($httpProvider) { + * $httpProvider.xsrfWhitelistedOrigins.push('https://api.example.com'); + * }]). + * run(['$http', function($http) { + * // The XSRF token will be sent. + * $http.get('https://api.example.com/preferences').then(...); + * + * // The XSRF token will NOT be sent. + * $http.get('https://stats.example.com/activity').then(...); + * }]); + * ``` + */ + var xsrfWhitelistedOrigins = this.xsrfWhitelistedOrigins = []; + this.$get = ['$browser', '$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector', '$sce', function($browser, $httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector, $sce) { @@ -11573,6 +11754,11 @@ function $HttpProvider() { ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory)); }); + /** + * A function to check request URLs against a list of allowed origins. + */ + var urlIsAllowedOrigin = urlIsAllowedOriginFactory(xsrfWhitelistedOrigins); + /** * @ngdoc service * @kind function @@ -11584,7 +11770,7 @@ function $HttpProvider() { * @requires $injector * * @description - * The `$http` service is a core Angular service that facilitates communication with the remote + * The `$http` service is a core AngularJS service that facilitates communication with the remote * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest) * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP). * @@ -11601,7 +11787,9 @@ function $HttpProvider() { * * ## General usage * The `$http` service is a function which takes a single argument — a {@link $http#usage configuration object} — - * that is used to generate an HTTP request and returns a {@link ng.$q promise}. + * that is used to generate an HTTP request and returns a {@link ng.$q promise} that is + * resolved (request success) or rejected (request failure) with a + * {@link ng.$http#$http-returns response} object. * * ```js * // Simple GET request example: @@ -11617,24 +11805,6 @@ function $HttpProvider() { * }); * ``` * - * The response object has these properties: - * - * - **data** – `{string|Object}` – The response body transformed with the transform - * functions. - * - **status** – `{number}` – HTTP status code of the response. - * - **headers** – `{function([headerName])}` – Header getter function. - * - **config** – `{Object}` – The configuration object that was used to generate the request. - * - **statusText** – `{string}` – HTTP status text of the response. - * - **xhrStatus** – `{string}` – Status of the XMLHttpRequest (`complete`, `error`, `timeout` or `abort`). - * - * A response status code between 200 and 299 is considered a success status and will result in - * the success callback being called. Any response status code outside of that range is - * considered an error status and will result in the error callback being called. - * Also, status codes less than -1 are normalized to zero. -1 usually means the request was - * aborted, e.g. using a `config.timeout`. - * Note that if the response is a redirect, XMLHttpRequest will transparently follow it, meaning - * that the outcome (success or error) will be determined by the final response status code. - * * * ## Shortcut methods * @@ -11723,7 +11893,7 @@ function $HttpProvider() { * which allows you to `push` or `unshift` a new transformation function into the transformation chain. * *
- * **Note:** Angular does not make a copy of the `data` parameter before it is passed into the `transformRequest` pipeline. + * **Note:** AngularJS does not make a copy of the `data` parameter before it is passed into the `transformRequest` pipeline. * That means changes to the properties of `data` are not local to the transform function (since Javascript passes objects by reference). * For example, when calling `$http.get(url, $scope.myObject)`, modifications to the object's properties in a transformRequest * function will be reflected on the scope and in any templates where the object is data-bound. @@ -11740,7 +11910,7 @@ function $HttpProvider() { * You can augment or replace the default transformations by modifying these properties by adding to or * replacing the array. * - * Angular provides the following default transformations: + * AngularJS provides the following default transformations: * * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`) is * an array with one function that does the following: @@ -11913,7 +12083,7 @@ function $HttpProvider() { * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx) * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) * - * Both server and the client must cooperate in order to eliminate these threats. Angular comes + * Both server and the client must cooperate in order to eliminate these threats. AngularJS comes * pre-configured with strategies that address these issues, but for this to work backend server * cooperation is required. * @@ -11923,7 +12093,7 @@ function $HttpProvider() { * allows third party website to turn your JSON resource URL into * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To * counter this your server can prefix all JSON requests with following string `")]}',\n"`. - * Angular will automatically strip the prefix before processing it as JSON. + * AngularJS will automatically strip the prefix before processing it as JSON. * * For example if your server needs to return: * ```js @@ -11936,34 +12106,51 @@ function $HttpProvider() { * ['one','two'] * ``` * - * Angular will strip the prefix, before processing the JSON. + * AngularJS will strip the prefix, before processing the JSON. * * * ### Cross Site Request Forgery (XSRF) Protection * * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is an attack technique by * which the attacker can trick an authenticated user into unknowingly executing actions on your - * website. Angular provides a mechanism to counter XSRF. When performing XHR requests, the + * website. AngularJS provides a mechanism to counter XSRF. When performing XHR requests, the * $http service reads a token from a cookie (by default, `XSRF-TOKEN`) and sets it as an HTTP - * header (`X-XSRF-TOKEN`). Since only JavaScript that runs on your domain could read the - * cookie, your server can be assured that the XHR came from JavaScript running on your domain. - * The header will not be set for cross-domain requests. + * header (by default `X-XSRF-TOKEN`). Since only JavaScript that runs on your domain could read + * the cookie, your server can be assured that the XHR came from JavaScript running on your + * domain. * * To take advantage of this, your server needs to set a token in a JavaScript readable session * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the - * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure - * 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 + * server can verify that the cookie matches the `X-XSRF-TOKEN` HTTP header, and therefore be + * sure 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 * 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)) * for added security. * - * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName - * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time, - * or the per-request config object. + * The header will — by default — **not** be set for cross-domain requests. This + * prevents unauthorized servers (e.g. malicious or compromised 3rd-party APIs) from gaining + * access to your users' XSRF tokens and exposing them to Cross Site Request Forgery. If you + * want to, you can whitelist additional origins to also receive the XSRF token, by adding them + * to {@link ng.$httpProvider#xsrfWhitelistedOrigins xsrfWhitelistedOrigins}. This might be + * useful, for example, if your application, served from `example.com`, needs to access your API + * at `api.example.com`. + * See {@link ng.$httpProvider#xsrfWhitelistedOrigins $httpProvider.xsrfWhitelistedOrigins} for + * more details. + * + *
+ * **Warning**
+ * Only whitelist origins that you have control over and make sure you understand the + * implications of doing so. + *
+ * + * The name of the cookie and the header can be specified using the `xsrfCookieName` and + * `xsrfHeaderName` properties of either `$httpProvider.defaults` at config-time, + * `$http.defaults` at run-time, or the per-request config object. + * + * In order to prevent collisions in environments where multiple AngularJS apps share the + * same domain or subdomain, we recommend that each application uses a unique cookie name. * - * In order to prevent collisions in environments where multiple Angular apps share the - * same domain or subdomain, we recommend that each application uses unique cookie name. * * @param {object} config Object describing the request to be made and how it should be * processed. The object has following properties: @@ -12009,14 +12196,44 @@ function $HttpProvider() { * See {@link $http#caching $http Caching} for more information. * - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} * that should abort the request when resolved. + * + * A numerical timeout or a promise returned from {@link ng.$timeout $timeout}, will set + * the `xhrStatus` in the {@link $http#$http-returns response} to "timeout", and any other + * resolved promise will set it to "abort", following standard XMLHttpRequest behavior. + * * - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the * XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials) * for more information. * - **responseType** - `{string}` - see * [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype). * - * @returns {HttpPromise} Returns a {@link ng.$q `Promise}` that will be resolved to a response object - * when the request succeeds or fails. + * @returns {HttpPromise} A {@link ng.$q `Promise}` that will be resolved (request success) + * or rejected (request failure) with a response object. + * + * The response object has these properties: + * + * - **data** – `{string|Object}` – The response body transformed with + * the transform functions. + * - **status** – `{number}` – HTTP status code of the response. + * - **headers** – `{function([headerName])}` – Header getter function. + * - **config** – `{Object}` – The configuration object that was used + * to generate the request. + * - **statusText** – `{string}` – HTTP status text of the response. + * - **xhrStatus** – `{string}` – Status of the XMLHttpRequest + * (`complete`, `error`, `timeout` or `abort`). + * + * + * A response status code between 200 and 299 is considered a success status + * and will result in the success callback being called. Any response status + * code outside of that range is considered an error status and will result + * in the error callback being called. + * Also, status codes less than -1 are normalized to zero. -1 usually means + * the request was aborted, e.g. using a `config.timeout`. More information + * about the status might be available in the `xhrStatus` property. + * + * Note that if the response is a redirect, XMLHttpRequest will transparently + * follow it, meaning that the outcome (success or error) will be determined + * by the final response status code. * * * @property {Array.} pendingRequests Array of config objects for currently pending @@ -12266,8 +12483,9 @@ function $HttpProvider() { * * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested; * or an object created by a call to `$sce.trustAsResourceUrl(url)`. - * @param {Object=} config Optional configuration object - * @returns {HttpPromise} Future object + * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}. + * @returns {HttpPromise} A Promise that will be resolved or rejected with a response object. + * See {@link ng.$http#$http-returns `$http()` return value}. */ /** @@ -12279,8 +12497,9 @@ function $HttpProvider() { * * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested; * or an object created by a call to `$sce.trustAsResourceUrl(url)`. - * @param {Object=} config Optional configuration object - * @returns {HttpPromise} Future object + * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}. + * @returns {HttpPromise} A Promise that will be resolved or rejected with a response object. + * See {@link ng.$http#$http-returns `$http()` return value}. */ /** @@ -12292,8 +12511,9 @@ function $HttpProvider() { * * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested; * or an object created by a call to `$sce.trustAsResourceUrl(url)`. - * @param {Object=} config Optional configuration object - * @returns {HttpPromise} Future object + * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}. + * @returns {HttpPromise} A Promise that will be resolved or rejected with a response object. + * See {@link ng.$http#$http-returns `$http()` return value}. */ /** @@ -12309,6 +12529,10 @@ function $HttpProvider() { * {@link $sceDelegateProvider#resourceUrlWhitelist `$sceDelegateProvider.resourceUrlWhitelist`} or * by explicitly trusting the URL via {@link $sce#trustAsResourceUrl `$sce.trustAsResourceUrl(url)`}. * + * You should avoid generating the URL for the JSONP request from user provided data. + * Provide additional query parameters via `params` property of the `config` parameter, rather than + * modifying the URL itself. + * * JSONP requests must specify a callback to be used in the response from the server. This callback * is passed as a query parameter in the request. You must specify the name of this parameter by * setting the `jsonpCallbackParam` property on the request config object. @@ -12330,8 +12554,9 @@ function $HttpProvider() { * * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested; * or an object created by a call to `$sce.trustAsResourceUrl(url)`. - * @param {Object=} config Optional configuration object - * @returns {HttpPromise} Future object + * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}. + * @returns {HttpPromise} A Promise that will be resolved or rejected with a response object. + * See {@link ng.$http#$http-returns `$http()` return value}. */ createShortMethods('get', 'delete', 'head', 'jsonp'); @@ -12344,8 +12569,9 @@ function $HttpProvider() { * * @param {string} url Relative or absolute URL specifying the destination of the request * @param {*} data Request content - * @param {Object=} config Optional configuration object - * @returns {HttpPromise} Future object + * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}. + * @returns {HttpPromise} A Promise that will be resolved or rejected with a response object. + * See {@link ng.$http#$http-returns `$http()` return value}. */ /** @@ -12357,8 +12583,9 @@ function $HttpProvider() { * * @param {string} url Relative or absolute URL specifying the destination of the request * @param {*} data Request content - * @param {Object=} config Optional configuration object - * @returns {HttpPromise} Future object + * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}. + * @returns {HttpPromise} A Promise that will be resolved or rejected with a response object. + * See {@link ng.$http#$http-returns `$http()` return value}. */ /** @@ -12370,8 +12597,9 @@ function $HttpProvider() { * * @param {string} url Relative or absolute URL specifying the destination of the request * @param {*} data Request content - * @param {Object=} config Optional configuration object - * @returns {HttpPromise} Future object + * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}. + * @returns {HttpPromise} A Promise that will be resolved or rejected with a response object. + * See {@link ng.$http#$http-returns `$http()` return value}. */ createShortMethodsWithData('post', 'put', 'patch'); @@ -12482,7 +12710,7 @@ function $HttpProvider() { // if we won't have the response in cache, set the xsrf headers and // send the request to the backend if (isUndefined(cachedResp)) { - var xsrfValue = urlIsSameOrigin(config.url) + var xsrfValue = urlIsAllowedOrigin(config.url) ? $$cookieReader()[config.xsrfCookieName || defaults.xsrfCookieName] : undefined; if (xsrfValue) { @@ -12584,20 +12812,26 @@ function $HttpProvider() { return url; } - function sanitizeJsonpCallbackParam(url, key) { - if (/[&?][^=]+=JSON_CALLBACK/.test(url)) { - // Throw if the url already contains a reference to JSON_CALLBACK - throw $httpMinErr('badjsonp', 'Illegal use of JSON_CALLBACK in url, "{0}"', url); - } - - var callbackParamRegex = new RegExp('[&?]' + key + '='); - if (callbackParamRegex.test(url)) { - // Throw if the callback param was already provided - throw $httpMinErr('badjsonp', 'Illegal use of callback param, "{0}", in url, "{1}"', key, url); + function sanitizeJsonpCallbackParam(url, cbKey) { + var parts = url.split('?'); + if (parts.length > 2) { + // Throw if the url contains more than one `?` query indicator + throw $httpMinErr('badjsonp', 'Illegal use more than one "?", in url, "{1}"', url); } + var params = parseKeyValue(parts[1]); + forEach(params, function(value, key) { + if (value === 'JSON_CALLBACK') { + // Throw if the url already contains a reference to JSON_CALLBACK + throw $httpMinErr('badjsonp', 'Illegal use of JSON_CALLBACK in url, "{0}"', url); + } + if (key === cbKey) { + // Throw if the callback param was already provided + throw $httpMinErr('badjsonp', 'Illegal use of callback param, "{0}", in url, "{1}"', cbKey, url); + } + }); // Add in the JSON_CALLBACK callback param value - url += ((url.indexOf('?') === -1) ? '?' : '&') + key + '=JSON_CALLBACK'; + url += ((url.indexOf('?') === -1) ? '?' : '&') + cbKey + '=JSON_CALLBACK'; return url; } @@ -12674,6 +12908,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc } else { var xhr = createXhr(method, url); + var abortedByTimeout = false; xhr.open(method, url, true); forEach(headers, function(value, key) { @@ -12714,7 +12949,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc }; var requestAborted = function() { - completeRequest(callback, -1, null, null, '', 'abort'); + completeRequest(callback, -1, null, null, '', abortedByTimeout ? 'timeout' : 'abort'); }; var requestTimeout = function() { @@ -12724,11 +12959,11 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc }; xhr.onerror = requestError; - xhr.onabort = requestAborted; xhr.ontimeout = requestTimeout; + xhr.onabort = requestAborted; forEach(eventHandlers, function(value, key) { - xhr.addEventListener(key, value); + xhr.addEventListener(key, value); }); forEach(uploadEventHandlers, function(value, key) { @@ -12759,14 +12994,26 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc xhr.send(isUndefined(post) ? null : post); } + // Since we are using xhr.abort() when a request times out, we have to set a flag that + // indicates to requestAborted if the request timed out or was aborted. + // + // http.timeout = numerical timeout timeout + // http.timeout = $timeout timeout + // http.timeout = promise abort + // xhr.abort() abort (The xhr object is normally inaccessible, but + // can be exposed with the xhrFactory) if (timeout > 0) { - var timeoutId = $browserDefer(timeoutRequest, timeout); + var timeoutId = $browserDefer(function() { + timeoutRequest('timeout'); + }, timeout); } else if (isPromiseLike(timeout)) { - timeout.then(timeoutRequest); + timeout.then(function() { + timeoutRequest(isDefined(timeout.$$timeoutId) ? 'timeout' : 'abort'); + }); } - - function timeoutRequest() { + function timeoutRequest(reason) { + abortedByTimeout = reason === 'timeout'; if (jsonpDone) { jsonpDone(); } @@ -12846,9 +13093,9 @@ $interpolateMinErr.interr = function(text, err) { * Used for configuring the interpolation markup. Defaults to `{{` and `}}`. * *
- * This feature is sometimes used to mix different markup languages, e.g. to wrap an Angular + * This feature is sometimes used to mix different markup languages, e.g. to wrap an AngularJS * template within a Python Jinja template (or any other template language). Mixing templating - * languages is **very dangerous**. The embedding template language will not safely escape Angular + * languages is **very dangerous**. The embedding template language will not safely escape AngularJS * expressions, so any user-controlled values in the template will cause Cross Site Scripting (XSS) * security bugs! *
@@ -12964,7 +13211,7 @@ function $InterpolateProvider() { * ```js * var $interpolate = ...; // injected * var exp = $interpolate('Hello {{name | uppercase}}!'); - * expect(exp({name:'Angular'})).toEqual('Hello ANGULAR!'); + * expect(exp({name:'AngularJS'})).toEqual('Hello ANGULAR!'); * ``` * * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is @@ -12982,8 +13229,8 @@ function $InterpolateProvider() { * // "allOrNothing" mode * exp = $interpolate('{{greeting}} {{name}}!', false, null, true); * expect(exp(context)).toBeUndefined(); - * context.name = 'Angular'; - * expect(exp(context)).toEqual('Hello Angular!'); + * context.name = 'AngularJS'; + * expect(exp(context)).toEqual('Hello AngularJS!'); * ``` * * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior. @@ -13157,9 +13404,7 @@ function $InterpolateProvider() { var lastValue; return scope.$watchGroup(parseFns, /** @this */ function interpolateFnWatcher(values, oldValues) { var currValue = compute(values); - if (isFunction(listener)) { - listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope); - } + listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope); lastValue = currValue; }); } @@ -13219,132 +13464,132 @@ function $IntervalProvider() { var intervals = {}; - /** - * @ngdoc service - * @name $interval - * - * @description - * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay` - * milliseconds. - * - * The return value of registering an interval function is a promise. This promise will be - * notified upon each tick of the interval, and will be resolved after `count` iterations, or - * run indefinitely if `count` is not defined. The value of the notification will be the - * number of iterations that have run. - * To cancel an interval, call `$interval.cancel(promise)`. - * - * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to - * move forward by `millis` milliseconds and trigger any functions scheduled to run in that - * time. - * - *
- * **Note**: Intervals created by this service must be explicitly destroyed when you are finished - * with them. In particular they are not automatically destroyed when a controller's scope or a - * directive's element are destroyed. - * You should take this into consideration and make sure to always cancel the interval at the - * appropriate moment. See the example below for more details on how and when to do this. - *
- * - * @param {function()} fn A function that should be called repeatedly. If no additional arguments - * are passed (see below), the function is called with the current iteration count. - * @param {number} delay Number of milliseconds between each function call. - * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat - * indefinitely. - * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise - * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block. - * @param {...*=} Pass additional parameters to the executed function. - * @returns {promise} A promise which will be notified on each iteration. It will resolve once all iterations of the interval complete. - * - * @example - * - * - * - * - *
- *
- *
- * Current time is: - *
- * Blood 1 : {{blood_1}} - * Blood 2 : {{blood_2}} - * - * - * - *
- *
- * - *
- *
- */ + /** + * @ngdoc service + * @name $interval + * + * @description + * AngularJS's wrapper for `window.setInterval`. The `fn` function is executed every `delay` + * milliseconds. + * + * The return value of registering an interval function is a promise. This promise will be + * notified upon each tick of the interval, and will be resolved after `count` iterations, or + * run indefinitely if `count` is not defined. The value of the notification will be the + * number of iterations that have run. + * To cancel an interval, call `$interval.cancel(promise)`. + * + * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to + * move forward by `millis` milliseconds and trigger any functions scheduled to run in that + * time. + * + *
+ * **Note**: Intervals created by this service must be explicitly destroyed when you are finished + * with them. In particular they are not automatically destroyed when a controller's scope or a + * directive's element are destroyed. + * You should take this into consideration and make sure to always cancel the interval at the + * appropriate moment. See the example below for more details on how and when to do this. + *
+ * + * @param {function()} fn A function that should be called repeatedly. If no additional arguments + * are passed (see below), the function is called with the current iteration count. + * @param {number} delay Number of milliseconds between each function call. + * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat + * indefinitely. + * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise + * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block. + * @param {...*=} Pass additional parameters to the executed function. + * @returns {promise} A promise which will be notified on each iteration. It will resolve once all iterations of the interval complete. + * + * @example + * + * + * + * + *
+ *
+ *
+ * Current time is: + *
+ * Blood 1 : {{blood_1}} + * Blood 2 : {{blood_2}} + * + * + * + *
+ *
+ * + *
+ *
+ */ function interval(fn, delay, count, invokeApply) { var hasParams = arguments.length > 4, args = hasParams ? sliceArgs(arguments, 4) : [], @@ -13389,16 +13634,16 @@ function $IntervalProvider() { } - /** - * @ngdoc method - * @name $interval#cancel - * - * @description - * Cancels a task associated with the `promise`. - * - * @param {Promise=} promise returned by the `$interval` function. - * @returns {boolean} Returns `true` if the task was successfully canceled. - */ + /** + * @ngdoc method + * @name $interval#cancel + * + * @description + * Cancels a task associated with the `promise`. + * + * @param {Promise=} promise returned by the `$interval` function. + * @returns {boolean} Returns `true` if the task was successfully canceled. + */ interval.cancel = function(promise) { if (promise && promise.$$intervalId in intervals) { // Interval cancels should not report as unhandled promise. @@ -13501,7 +13746,7 @@ var $jsonpCallbacksProvider = /** @this */ function() { * @name $locale * * @description - * $locale service provides localization rules for various Angular components. As of right now the + * $locale service provides localization rules for various AngularJS components. As of right now the * only public api is: * * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`) @@ -13523,7 +13768,23 @@ function encodePath(path) { i = segments.length; while (i--) { - segments[i] = encodeUriSegment(segments[i]); + // decode forward slashes to prevent them from being double encoded + segments[i] = encodeUriSegment(segments[i].replace(/%2F/g, '/')); + } + + return segments.join('/'); +} + +function decodePath(path, html5Mode) { + var segments = path.split('/'), + i = segments.length; + + while (i--) { + segments[i] = decodeURIComponent(segments[i]); + if (html5Mode) { + // encode forward slashes to prevent them from being mistaken for path separators + segments[i] = segments[i].replace(/\//g, '%2F'); + } } return segments.join('/'); @@ -13538,7 +13799,7 @@ function parseAbsoluteUrl(absoluteUrl, locationObj) { } var DOUBLE_SLASH_REGEX = /^\s*[\\/]{2,}/; -function parseAppUrl(url, locationObj) { +function parseAppUrl(url, locationObj, html5Mode) { if (DOUBLE_SLASH_REGEX.test(url)) { throw $locationMinErr('badpath', 'Invalid url "{0}".', url); @@ -13549,8 +13810,8 @@ function parseAppUrl(url, locationObj) { url = '/' + url; } var match = urlResolve(url); - locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ? - match.pathname.substring(1) : match.pathname); + var path = prefixed && match.pathname.charAt(0) === '/' ? match.pathname.substring(1) : match.pathname; + locationObj.$$path = decodePath(path, html5Mode); locationObj.$$search = parseKeyValue(match.search); locationObj.$$hash = decodeURIComponent(match.hash); @@ -13625,7 +13886,7 @@ function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) { appBaseNoFile); } - parseAppUrl(pathUrl, this); + parseAppUrl(pathUrl, this, true); if (!this.$$path) { this.$$path = '/'; @@ -13728,7 +13989,7 @@ function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) { } } - parseAppUrl(withoutHashUrl, this); + parseAppUrl(withoutHashUrl, this, false); this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase); @@ -13742,7 +14003,7 @@ function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) { * * a.setAttribute('href', '/foo') * * a.pathname === '/C:/foo' //true * - * Inside of Angular, we're always using pathnames that + * Inside of AngularJS, we're always using pathnames that * do not include drive names for routing. */ function removeWindowsDriveName(path, url, base) { @@ -13949,7 +14210,7 @@ var locationPrototype = { * * Return host of current URL. * - * Note: compared to the non-angular version `location.host` which returns `hostname:port`, this returns the `hostname` portion only. + * Note: compared to the non-AngularJS version `location.host` which returns `hostname:port`, this returns the `hostname` portion only. * * * ```js @@ -14422,7 +14683,7 @@ function $LocationProvider() { if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) { if ($location.$$parseLinkUrl(absHref, relHref)) { - // We do a preventDefault for all urls that are part of the angular application, + // We do a preventDefault for all urls that are part of the AngularJS application, // in html5mode and also without, so that we are able to abort navigation without // getting double entries in the location history. event.preventDefault(); @@ -14718,12 +14979,12 @@ var $parseMinErr = minErr('$parse'); var objectValueOf = {}.constructor.prototype.valueOf; -// Sandboxing Angular Expressions +// Sandboxing AngularJS Expressions // ------------------------------ -// Angular expressions are no longer sandboxed. So it is now even easier to access arbitrary JS code by +// AngularJS expressions are no longer sandboxed. So it is now even easier to access arbitrary JS code by // various means such as obtaining a reference to native JS functions like the Function constructor. // -// As an example, consider the following Angular expression: +// As an example, consider the following AngularJS expression: // // {}.toString.constructor('alert("evil JS code")') // @@ -16347,11 +16608,26 @@ Parser.prototype = { constructor: Parser, parse: function(text) { - var ast = this.ast.ast(text); - var fn = this.astCompiler.compile(ast); - fn.literal = isLiteral(ast); - fn.constant = isConstant(ast); + var ast = this.getAst(text); + var fn = this.astCompiler.compile(ast.ast); + fn.literal = isLiteral(ast.ast); + fn.constant = isConstant(ast.ast); + fn.oneTime = ast.oneTime; return fn; + }, + + getAst: function(exp) { + var oneTime = false; + exp = exp.trim(); + + if (exp.charAt(0) === ':' && exp.charAt(1) === ':') { + oneTime = true; + exp = exp.substring(2); + } + return { + ast: this.ast.ast(exp), + oneTime: oneTime + }; } }; @@ -16368,15 +16644,15 @@ function getValueOf(value) { * * @description * - * Converts Angular {@link guide/expression expression} into a function. + * Converts AngularJS {@link guide/expression expression} into a function. * * ```js * var getter = $parse('user.name'); * var setter = getter.assign; - * var context = {user:{name:'angular'}}; + * var context = {user:{name:'AngularJS'}}; * var locals = {user:{name:'local'}}; * - * expect(getter(context)).toEqual('angular'); + * expect(getter(context)).toEqual('AngularJS'); * setter(context, 'newValue'); * expect(context.user.name).toEqual('newValue'); * expect(getter(context, locals)).toEqual('local'); @@ -16442,7 +16718,7 @@ function $ParseProvider() { * * @description * - * Allows defining the set of characters that are allowed in Angular expressions. The function + * Allows defining the set of characters that are allowed in AngularJS expressions. The function * `identifierStart` will get called to know if a given character is a valid character to be the * first character for an identifier. The function `identifierContinue` will get called to know if * a given character is a valid character to be a follow-up identifier character. The functions @@ -16474,10 +16750,11 @@ function $ParseProvider() { isIdentifierStart: isFunction(identStart) && identStart, isIdentifierContinue: isFunction(identContinue) && identContinue }; + $parse.$$getAst = $$getAst; return $parse; function $parse(exp, interceptorFn) { - var parsedExpression, oneTime, cacheKey; + var parsedExpression, cacheKey; switch (typeof exp) { case 'string': @@ -16487,16 +16764,12 @@ function $ParseProvider() { parsedExpression = cache[cacheKey]; if (!parsedExpression) { - if (exp.charAt(0) === ':' && exp.charAt(1) === ':') { - oneTime = true; - exp = exp.substring(2); - } var lexer = new Lexer($parseOptions); var parser = new Parser(lexer, $filter, $parseOptions); parsedExpression = parser.parse(exp); if (parsedExpression.constant) { parsedExpression.$$watchDelegate = constantWatchDelegate; - } else if (oneTime) { + } else if (parsedExpression.oneTime) { parsedExpression.$$watchDelegate = parsedExpression.literal ? oneTimeLiteralWatchDelegate : oneTimeWatchDelegate; } else if (parsedExpression.inputs) { @@ -16514,6 +16787,12 @@ function $ParseProvider() { } } + function $$getAst(exp) { + var lexer = new Lexer($parseOptions); + var parser = new Parser(lexer, $filter, $parseOptions); + return parser.getAst(exp).ast; + } + function expressionInputDirtyCheck(newValue, oldValueOfValue, compareObjectIdentity) { if (newValue == null || oldValueOfValue == null) { // null/undefined @@ -16707,7 +16986,7 @@ function $ParseProvider() { * $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 (ES2015) promises to some degree. * - * # $q constructor + * ## $q constructor * * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver` * function as the first argument. This is similar to the native Promise implementation from ES6, @@ -16795,7 +17074,7 @@ function $ParseProvider() { * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the * section on serial or parallel joining of promises. * - * # The Deferred API + * ## The Deferred API * * A new instance of deferred is constructed by calling `$q.defer()`. * @@ -16817,7 +17096,7 @@ function $ParseProvider() { * - promise – `{Promise}` – promise object associated with this deferred. * * - * # The Promise API + * ## The Promise API * * A new promise instance is created when a deferred instance is created and can be retrieved by * calling `deferred.promise`. @@ -16849,7 +17128,7 @@ function $ParseProvider() { * specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for * more information. * - * # Chaining promises + * ## Chaining promises * * Because calling the `then` method of a promise returns a new derived promise, it is easily * possible to create a chain of promises: @@ -16869,17 +17148,17 @@ function $ParseProvider() { * $http's response interceptors. * * - * # Differences between Kris Kowal's Q and $q + * ## Differences between Kris Kowal's Q and $q * * There are two main differences: * * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation - * mechanism in angular, which means faster propagation of resolution or rejection into your + * mechanism in AngularJS, which means faster propagation of resolution or rejection into your * models and avoiding unnecessary browser repaints, which would result in flickering UI. * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains * all the important functionality needed for common async tasks. * - * # Testing + * ## Testing * * ```js * it('should simulate promise', inject(function($q, $rootScope) { @@ -17056,6 +17335,10 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) { } } catch (e) { rejectPromise(promise, e); + // This error is explicitly marked for being passed to the $exceptionHandler + if (e && e.$$passToExceptionHandler === true) { + exceptionHandler(e); + } } } } finally { @@ -17496,6 +17779,7 @@ function $RootScopeProvider() { this.$$watchersCount = 0; this.$id = nextUid(); this.$$ChildScope = null; + this.$$suspended = false; } ChildScope.prototype = parent; return ChildScope; @@ -17548,7 +17832,7 @@ function $RootScopeProvider() { * an in-depth introduction and usage examples. * * - * # Inheritance + * ## Inheritance * A scope can inherit from a parent scope, as in this example: * ```js var parent = $rootScope; @@ -17583,6 +17867,7 @@ function $RootScopeProvider() { this.$$childHead = this.$$childTail = null; this.$root = this; this.$$destroyed = false; + this.$$suspended = false; this.$$listeners = {}; this.$$listenerCount = {}; this.$$watchersCount = 0; @@ -17723,7 +18008,7 @@ function $RootScopeProvider() { * * * - * # Example + * @example * ```js // let's assume that scope was dependency injected as the $rootScope var scope = $rootScope; @@ -17799,14 +18084,15 @@ function $RootScopeProvider() { */ $watch: function(watchExp, listener, objectEquality, prettyPrintExpression) { var get = $parse(watchExp); + var fn = isFunction(listener) ? listener : noop; if (get.$$watchDelegate) { - return get.$$watchDelegate(this, listener, objectEquality, get, watchExp); + return get.$$watchDelegate(this, fn, objectEquality, get, watchExp); } var scope = this, array = scope.$$watchers, watcher = { - fn: listener, + fn: fn, last: initWatchVal, get: get, exp: prettyPrintExpression || watchExp, @@ -17815,10 +18101,6 @@ function $RootScopeProvider() { lastDirtyWatch = null; - if (!isFunction(listener)) { - watcher.fn = noop; - } - if (!array) { array = scope.$$watchers = []; array.$$digestWatchIndex = -1; @@ -17974,7 +18256,7 @@ function $RootScopeProvider() { * adding, removing, and moving items belonging to an object or array. * * - * # Example + * @example * ```js $scope.names = ['igor', 'matias', 'misko', 'james']; $scope.dataCount = 4; @@ -18172,7 +18454,7 @@ function $RootScopeProvider() { * * In unit tests, you may need to call `$digest()` to simulate the scope life cycle. * - * # Example + * @example * ```js var scope = ...; scope.name = 'misko'; @@ -18240,7 +18522,7 @@ function $RootScopeProvider() { traverseScopesLoop: do { // "traverse the scopes" loop - if ((watchers = current.$$watchers)) { + if ((watchers = !current.$$suspended && current.$$watchers)) { // process our watches watchers.$$digestWatchIndex = watchers.length; while (watchers.$$digestWatchIndex--) { @@ -18284,7 +18566,9 @@ function $RootScopeProvider() { // Insanity Warning: scope depth-first traversal // yes, this code is a bit crazy, but it works and we have tests to prove it! // this piece should be kept in sync with the traversal in $broadcast - if (!(next = ((current.$$watchersCount && current.$$childHead) || + // (though it differs due to having the extra check for $$suspended and does not + // check $$listenerCount) + if (!(next = ((!current.$$suspended && current.$$watchersCount && current.$$childHead) || (current !== target && current.$$nextSibling)))) { while (current !== target && !(next = current.$$nextSibling)) { current = current.$parent; @@ -18321,6 +18605,95 @@ function $RootScopeProvider() { $browser.$$checkUrlChange(); }, + /** + * @ngdoc method + * @name $rootScope.Scope#$suspend + * @kind function + * + * @description + * Suspend watchers of this scope subtree so that they will not be invoked during digest. + * + * This can be used to optimize your application when you know that running those watchers + * is redundant. + * + * **Warning** + * + * Suspending scopes from the digest cycle can have unwanted and difficult to debug results. + * Only use this approach if you are confident that you know what you are doing and have + * ample tests to ensure that bindings get updated as you expect. + * + * Some of the things to consider are: + * + * * Any external event on a directive/component will not trigger a digest while the hosting + * scope is suspended - even if the event handler calls `$apply()` or `$rootScope.$digest()`. + * * Transcluded content exists on a scope that inherits from outside a directive but exists + * as a child of the directive's containing scope. If the containing scope is suspended the + * transcluded scope will also be suspended, even if the scope from which the transcluded + * scope inherits is not suspended. + * * Multiple directives trying to manage the suspended status of a scope can confuse each other: + * * A call to `$suspend()` on an already suspended scope is a no-op. + * * A call to `$resume()` on a non-suspended scope is a no-op. + * * If two directives suspend a scope, then one of them resumes the scope, the scope will no + * longer be suspended. This could result in the other directive believing a scope to be + * suspended when it is not. + * * If a parent scope is suspended then all its descendants will be also excluded from future + * digests whether or not they have been suspended themselves. Note that this also applies to + * isolate child scopes. + * * Calling `$digest()` directly on a descendant of a suspended scope will still run the watchers + * for that scope and its descendants. When digesting we only check whether the current scope is + * locally suspended, rather than checking whether it has a suspended ancestor. + * * Calling `$resume()` on a scope that has a suspended ancestor will not cause the scope to be + * included in future digests until all its ancestors have been resumed. + * * Resolved promises, e.g. from explicit `$q` deferreds and `$http` calls, trigger `$apply()` + * against the `$rootScope` and so will still trigger a global digest even if the promise was + * initiated by a component that lives on a suspended scope. + */ + $suspend: function() { + this.$$suspended = true; + }, + + /** + * @ngdoc method + * @name $rootScope.Scope#$isSuspended + * @kind function + * + * @description + * Call this method to determine if this scope has been explicitly suspended. It will not + * tell you whether an ancestor has been suspended. + * To determine if this scope will be excluded from a digest triggered at the $rootScope, + * for example, you must check all its ancestors: + * + * ``` + * function isExcludedFromDigest(scope) { + * while(scope) { + * if (scope.$isSuspended()) return true; + * scope = scope.$parent; + * } + * return false; + * ``` + * + * Be aware that a scope may not be included in digests if it has a suspended ancestor, + * even if `$isSuspended()` returns false. + * + * @returns true if the current scope has been suspended. + */ + $isSuspended: function() { + return this.$$suspended; + }, + + /** + * @ngdoc method + * @name $rootScope.Scope#$resume + * @kind function + * + * @description + * Resume watchers of this scope subtree in case it was suspended. + * + * See {@link $rootScope.Scope#$suspend} for information about the dangers of using this approach. + */ + $resume: function() { + this.$$suspended = false; + }, /** * @ngdoc event @@ -18398,10 +18771,10 @@ function $RootScopeProvider() { * * @description * Executes the `expression` on the current scope and returns the result. Any exceptions in - * the expression are propagated (uncaught). This is useful when evaluating Angular + * the expression are propagated (uncaught). This is useful when evaluating AngularJS * expressions. * - * # Example + * @example * ```js var scope = ng.$rootScope.Scope(); scope.a = 1; @@ -18411,7 +18784,7 @@ function $RootScopeProvider() { expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3); * ``` * - * @param {(string|function())=} expression An angular expression to be executed. + * @param {(string|function())=} expression An AngularJS expression to be executed. * * - `string`: execute using the rules as defined in {@link guide/expression expression}. * - `function(scope)`: execute the function with the current `scope` parameter. @@ -18446,7 +18819,7 @@ function $RootScopeProvider() { * will be scheduled. However, it is encouraged to always call code that changes the model * from within an `$apply` call. That includes code evaluated via `$evalAsync`. * - * @param {(string|function())=} expression An angular expression to be executed. + * @param {(string|function())=} expression An AngularJS expression to be executed. * * - `string`: execute using the rules as defined in {@link guide/expression expression}. * - `function(scope)`: execute the function with the current `scope` parameter. @@ -18477,15 +18850,14 @@ function $RootScopeProvider() { * @kind function * * @description - * `$apply()` is used to execute an expression in angular from outside of the angular + * `$apply()` is used to execute an expression in AngularJS from outside of the AngularJS * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries). - * Because we are calling into the angular framework we need to perform proper scope life + * Because we are calling into the AngularJS framework we need to perform proper scope life * cycle of {@link ng.$exceptionHandler exception handling}, * {@link ng.$rootScope.Scope#$digest executing watches}. * - * ## Life cycle + * **Life cycle: Pseudo-Code of `$apply()`** * - * # Pseudo-Code of `$apply()` * ```js function $apply(expr) { try { @@ -18509,7 +18881,7 @@ function $RootScopeProvider() { * expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method. * * - * @param {(string|function())=} exp An angular expression to be executed. + * @param {(string|function())=} exp An AngularJS expression to be executed. * * - `string`: execute using the rules as defined in {@link guide/expression expression}. * - `function(scope)`: execute the function with current `scope` parameter. @@ -18549,7 +18921,7 @@ function $RootScopeProvider() { * This can be used to queue up multiple expressions which need to be evaluated in the same * digest. * - * @param {(string|function())=} exp An angular expression to be executed. + * @param {(string|function())=} exp An AngularJS expression to be executed. * * - `string`: execute using the rules as defined in {@link guide/expression expression}. * - `function(scope)`: execute the function with current `scope` parameter. @@ -18613,7 +18985,10 @@ function $RootScopeProvider() { return function() { var indexOfListener = namedListeners.indexOf(listener); if (indexOfListener !== -1) { - namedListeners[indexOfListener] = null; + // Use delete in the hope of the browser deallocating the memory for the array entry, + // while not shifting the array indexes of other listeners. + // See issue https://github.com/angular/angular.js/issues/16135 + delete namedListeners[indexOfListener]; decrementListenerCount(self, 1, name); } }; @@ -18680,8 +19055,7 @@ function $RootScopeProvider() { } //if any listener on the current scope stops propagation, prevent bubbling if (stopPropagation) { - event.currentScope = null; - return event; + break; } //traverse upwards scope = scope.$parent; @@ -18755,7 +19129,8 @@ function $RootScopeProvider() { // Insanity Warning: scope depth-first traversal // yes, this code is a bit crazy, but it works and we have tests to prove it! // this piece should be kept in sync with the traversal in $digest - // (though it differs due to having the extra check for $$listenerCount) + // (though it differs due to having the extra check for $$listenerCount and + // does not check $$suspended) if (!(next = ((current.$$listenerCount[name] && current.$$childHead) || (current !== target && current.$$nextSibling)))) { while (current !== target && !(next = current.$$nextSibling)) { @@ -18841,7 +19216,7 @@ function $RootScopeProvider() { * @name $rootElement * * @description - * The root element of Angular application. This is either the element where {@link + * The root element of AngularJS application. This is either the element where {@link * ng.directive:ngApp ngApp} was declared or the element passed into * {@link angular.bootstrap}. The element represents the root element of application. It is also the * location where the application's {@link auto.$injector $injector} service gets @@ -18857,7 +19232,7 @@ function $RootScopeProvider() { * Private service to sanitize uris for links and images. Used by $compile and $sanitize. */ function $$SanitizeUriProvider() { - var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/, + var aHrefSanitizationWhitelist = /^\s*(https?|s?ftp|mailto|tel|file):/, imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/; /** @@ -18913,7 +19288,7 @@ function $$SanitizeUriProvider() { return function sanitizeUri(uri, isImage) { var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist; var normalizedVal; - normalizedVal = urlResolve(uri).href; + normalizedVal = urlResolve(uri && uri.trim()).href; if (normalizedVal !== '' && !normalizedVal.match(regex)) { return 'unsafe:' + normalizedVal; } @@ -19058,7 +19433,7 @@ function adjustMatchers(matchers) { * and * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}, * - * For the general details about this service in Angular, read the main page for {@link ng.$sce + * For the general details about this service in AngularJS, read the main page for {@link ng.$sce * Strict Contextual Escaping (SCE)}. * * **Example**: Consider the following case. @@ -19385,13 +19760,13 @@ function $SceDelegateProvider() { * * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS. * - * # Strict Contextual Escaping + * ## Strict Contextual Escaping * * Strict Contextual Escaping (SCE) is a mode in which AngularJS constrains bindings to only render * trusted values. Its goal is to assist in writing code in a way that (a) is secure by default, and * (b) makes auditing for security vulnerabilities such as XSS, clickjacking, etc. a lot easier. * - * ## Overview + * ### Overview * * To systematically block XSS security bugs, AngularJS treats all values as untrusted by default in * HTML or sensitive URL bindings. When binding untrusted values, AngularJS will automatically @@ -19407,7 +19782,7 @@ function $SceDelegateProvider() { * * As of version 1.2, AngularJS ships with SCE enabled by default. * - * ## In practice + * ### In practice * * Here's an example of a binding in a privileged context: * @@ -19444,7 +19819,7 @@ function $SceDelegateProvider() { * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to * build the trusted versions of your values. * - * ## How does it work? + * ### How does it work? * * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted * $sce.getTrusted(context, value)} rather than to the value directly. Think of this function as @@ -19468,12 +19843,12 @@ function $SceDelegateProvider() { * }]; * ``` * - * ## Impact on loading templates + * ### Impact on loading templates * * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as * `templateUrl`'s specified by {@link guide/directive directives}. * - * By default, Angular only loads templates from the same domain and protocol as the application + * By default, AngularJS only loads templates from the same domain and protocol as the application * document. This is done by calling {@link ng.$sce#getTrustedResourceUrl * $sce.getTrustedResourceUrl} on the template URL. To load templates from other domains and/or * protocols, you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist @@ -19488,7 +19863,7 @@ function $SceDelegateProvider() { * won't work on all browsers. Also, loading templates from `file://` URL does not work on some * browsers. * - * ## This feels like too much overhead + * ### This feels like too much overhead * * It's important to remember that SCE only applies to interpolation expressions. * @@ -19512,7 +19887,7 @@ function $SceDelegateProvider() { * security onto an application later. * * - * ## What trusted context types are supported? + * ### What trusted context types are supported? * * | Context | Notes | * |---------------------|----------------| @@ -19528,7 +19903,7 @@ function $SceDelegateProvider() { * in AngularJS currently, so their corresponding `$sce.trustAs` functions aren't useful yet. This * might evolve. * - * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} + * ### Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} * * Each element in these arrays must be one of the following: * @@ -19575,7 +19950,7 @@ function $SceDelegateProvider() { * * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example. * - * ## Show me an example using SCE. + * ### Show me an example using SCE. * * * @@ -19770,7 +20145,7 @@ function $SceProvider() { * @name $sce#parseAs * * @description - * Converts Angular {@link guide/expression expression} into a function. This is like {@link + * Converts AngularJS {@link guide/expression expression} into a function. This is like {@link * ng.$parse $parse} and is identical when the expression is a literal constant. Otherwise, it * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*, * *result*)} @@ -20205,6 +20580,12 @@ function $TemplateRequestProvider() { * If you want to pass custom options to the `$http` service, such as setting the Accept header you * can configure this via {@link $templateRequestProvider#httpOptions}. * + * `$templateRequest` is used internally by {@link $compile}, {@link ngRoute.$route}, and directives such + * as {@link ngInclude} to download and cache templates. + * + * 3rd party modules should use `$templateRequest` if their services or directives are loading + * templates. + * * @param {string|TrustedResourceUrl} tpl The HTTP request template URL * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty * @@ -20220,7 +20601,7 @@ function $TemplateRequestProvider() { // We consider the template cache holds only trusted templates, so // there's no need to go through whitelisting again for keys that already - // are included in there. This also makes Angular accept any script + // are included in there. This also makes AngularJS accept any script // directive, no matter its name. However, we still need to unwrap trusted // types. if (!isString(tpl) || isUndefined($templateCache.get(tpl))) { @@ -20393,35 +20774,35 @@ function $TimeoutProvider() { var deferreds = {}; - /** - * @ngdoc service - * @name $timeout - * - * @description - * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch - * block and delegates any exceptions to - * {@link ng.$exceptionHandler $exceptionHandler} service. - * - * The return value of calling `$timeout` is a promise, which will be resolved when - * the delay has passed and the timeout function, if provided, is executed. - * - * To cancel a timeout request, call `$timeout.cancel(promise)`. - * - * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to - * synchronously flush the queue of deferred functions. - * - * If you only want a promise that will be resolved after some specified delay - * then you can call `$timeout` without the `fn` function. - * - * @param {function()=} fn A function, whose execution should be delayed. - * @param {number=} [delay=0] Delay in milliseconds. - * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise - * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block. - * @param {...*=} Pass additional parameters to the executed function. - * @returns {Promise} Promise that will be resolved when the timeout is reached. The promise - * will be resolved with the return value of the `fn` function. - * - */ + /** + * @ngdoc service + * @name $timeout + * + * @description + * AngularJS's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch + * block and delegates any exceptions to + * {@link ng.$exceptionHandler $exceptionHandler} service. + * + * The return value of calling `$timeout` is a promise, which will be resolved when + * the delay has passed and the timeout function, if provided, is executed. + * + * To cancel a timeout request, call `$timeout.cancel(promise)`. + * + * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to + * synchronously flush the queue of deferred functions. + * + * If you only want a promise that will be resolved after some specified delay + * then you can call `$timeout` without the `fn` function. + * + * @param {function()=} fn A function, whose execution should be delayed. + * @param {number=} [delay=0] Delay in milliseconds. + * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise + * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block. + * @param {...*=} Pass additional parameters to the executed function. + * @returns {Promise} Promise that will be resolved when the timeout is reached. The promise + * will be resolved with the return value of the `fn` function. + * + */ function timeout(fn, delay, invokeApply) { if (!isFunction(fn)) { invokeApply = delay; @@ -20455,18 +20836,18 @@ function $TimeoutProvider() { } - /** - * @ngdoc method - * @name $timeout#cancel - * - * @description - * Cancels a task associated with the `promise`. As a result of this, the promise will be - * resolved with a rejection. - * - * @param {Promise=} promise Promise returned by the `$timeout` function. - * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully - * canceled. - */ + /** + * @ngdoc method + * @name $timeout#cancel + * + * @description + * Cancels a task associated with the `promise`. As a result of this, the promise will be + * resolved with a rejection. + * + * @param {Promise=} promise Promise returned by the `$timeout` function. + * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully + * canceled. + */ timeout.cancel = function(promise) { if (promise && promise.$$timeoutId in deferreds) { // Timeout cancels should not report an unhandled promise. @@ -20522,7 +20903,8 @@ var originUrl = urlResolve(window.location.href); * http://james.padolsey.com/javascript/parsing-urls-with-the-dom/ * * @kind function - * @param {string} url The URL to be parsed. + * @param {string|object} url The URL to be parsed. If `url` is not a string, it will be returned + * unchanged. * @description Normalizes and parses a URL. * @returns {object} Returns the normalized URL as a dictionary. * @@ -20539,6 +20921,8 @@ var originUrl = urlResolve(window.location.href); * */ function urlResolve(url) { + if (!isString(url)) return url; + var href = url; // Support: IE 9-11 only @@ -20567,16 +20951,61 @@ function urlResolve(url) { } /** - * Parse a request URL and determine whether this is a same-origin request as the application document. + * Parse a request URL and determine whether this is a same-origin request as the application + * document. * * @param {string|object} requestUrl The url of the request as a string that will be resolved * or a parsed URL object. * @returns {boolean} Whether the request is for the same origin as the application document. */ function urlIsSameOrigin(requestUrl) { - var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl; - return (parsed.protocol === originUrl.protocol && - parsed.host === originUrl.host); + return urlsAreSameOrigin(requestUrl, originUrl); +} + +/** + * Create a function that can check a URL's origin against a list of allowed/whitelisted origins. + * The current location's origin is implicitly trusted. + * + * @param {string[]} whitelistedOriginUrls - A list of URLs (strings), whose origins are trusted. + * + * @returns {Function} - A function that receives a URL (string or parsed URL object) and returns + * whether it is of an allowed origin. + */ +function urlIsAllowedOriginFactory(whitelistedOriginUrls) { + var parsedAllowedOriginUrls = [originUrl].concat(whitelistedOriginUrls.map(urlResolve)); + + /** + * Check whether the specified URL (string or parsed URL object) has an origin that is allowed + * based on a list of whitelisted-origin URLs. The current location's origin is implicitly + * trusted. + * + * @param {string|Object} requestUrl - The URL to be checked (provided as a string that will be + * resolved or a parsed URL object). + * + * @returns {boolean} - Whether the specified URL is of an allowed origin. + */ + return function urlIsAllowedOrigin(requestUrl) { + var parsedUrl = urlResolve(requestUrl); + return parsedAllowedOriginUrls.some(urlsAreSameOrigin.bind(null, parsedUrl)); + }; +} + +/** + * Determine if two URLs share the same origin. + * + * @param {string|Object} url1 - First URL to compare as a string or a normalized URL in the form of + * a dictionary object returned by `urlResolve()`. + * @param {string|object} url2 - Second URL to compare as a string or a normalized URL in the form + * of a dictionary object returned by `urlResolve()`. + * + * @returns {boolean} - True if both URLs have the same origin, and false otherwise. + */ +function urlsAreSameOrigin(url1, url2) { + url1 = urlResolve(url1); + url2 = urlResolve(url2); + + return (url1.protocol === url2.protocol && + url1.host === url2.host); } /** @@ -20587,7 +21016,7 @@ function urlIsSameOrigin(requestUrl) { * @description * A reference to the browser's `window` object. While `window` * is globally available in JavaScript, it causes testability problems, because - * it is a global variable. In angular we always refer to it through the + * it is a global variable. In AngularJS we always refer to it through the * `$window` service, so it may be overridden, removed or mocked for testing. * * Expressions, like the one defined for the `ngClick` directive in the example @@ -20710,7 +21139,7 @@ function $$CookieReaderProvider() { * annotated with dependencies and is responsible for creating a filter function. * *
- * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`. + * **Note:** Filter names must be valid AngularJS {@link expression} identifiers, such as `uppercase` or `orderBy`. * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores * (`myapp_subsection_filterx`). @@ -20753,8 +21182,8 @@ function $$CookieReaderProvider() { * ``` * * - * 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. + * For more information about how AngularJS filters work, and how to create your own filters, see + * {@link guide/filter Filters} in the AngularJS Developer Guide. */ /** @@ -20764,7 +21193,7 @@ function $$CookieReaderProvider() { * @description * Filters are used for formatting data displayed to the user. * - * They can be used in view templates, controllers or services.Angular comes + * They can be used in view templates, controllers or services. AngularJS comes * with a collection of [built-in filters](api/ng/filter), but it is easy to * define your own as well. * @@ -20806,7 +21235,7 @@ function $FilterProvider($provide) { * the keys are the filter names and the values are the filter factories. * *
- * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`. + * **Note:** Filter names must be valid AngularJS {@link expression} identifiers, such as `uppercase` or `orderBy`. * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores * (`myapp_subsection_filterx`). @@ -21194,11 +21623,14 @@ function currencyFilter($locale) { fractionSize = formats.PATTERNS[1].maxFrac; } + // If the currency symbol is empty, trim whitespace around the symbol + var currencySymbolRe = !currencySymbol ? /\s*\u00A4\s*/g : /\u00A4/g; + // if null or undefined pass it through return (amount == null) ? amount : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize). - replace(/\u00A4/g, currencySymbol); + replace(currencySymbolRe, currencySymbol); }; } @@ -22091,7 +22523,7 @@ function sliceFn(input, begin, end) { * * - `Function`: A getter function. This function will be called with each item as argument and * the return value will be used for sorting. - * - `string`: An Angular expression. This expression will be evaluated against each item and the + * - `string`: An AngularJS expression. This expression will be evaluated against each item and the * result will be used for sorting. For example, use `'label'` to sort by a property called * `label` or `'label.substring(0, 3)'` to sort by the first 3 characters of the `label` * property.
@@ -22737,10 +23169,10 @@ var htmlAnchorDirective = valueFn({ * @priority 99 * * @description - * Using Angular markup like `{{hash}}` in an href attribute will + * Using AngularJS markup like `{{hash}}` in an href attribute will * make the link go to the wrong URL if the user clicks it before - * Angular has a chance to replace the `{{hash}}` markup with its - * value. Until Angular replaces the markup the link will be broken + * AngularJS has a chance to replace the `{{hash}}` markup with its + * value. Until AngularJS replaces the markup the link will be broken * and will most likely return a 404 error. The `ngHref` directive * solves this problem. * @@ -22788,7 +23220,7 @@ var htmlAnchorDirective = valueFn({ element(by.id('link-3')).click(); - // At this point, we navigate away from an Angular page, so we need + // At this point, we navigate away from an AngularJS page, so we need // to use browser.driver to get the base webdriver. browser.wait(function() { @@ -22817,7 +23249,7 @@ var htmlAnchorDirective = valueFn({ element(by.id('link-6')).click(); - // At this point, we navigate away from an Angular page, so we need + // At this point, we navigate away from an AngularJS page, so we need // to use browser.driver to get the base webdriver. browser.wait(function() { return browser.driver.getCurrentUrl().then(function(url) { @@ -22836,9 +23268,9 @@ var htmlAnchorDirective = valueFn({ * @priority 99 * * @description - * Using Angular markup like `{{hash}}` in a `src` attribute doesn't + * Using AngularJS markup like `{{hash}}` in a `src` attribute doesn't * work right: The browser will fetch from the URL with the literal - * text `{{hash}}` until Angular replaces the expression inside + * text `{{hash}}` until AngularJS replaces the expression inside * `{{hash}}`. The `ngSrc` directive solves this problem. * * The buggy way to write it: @@ -22862,9 +23294,9 @@ var htmlAnchorDirective = valueFn({ * @priority 99 * * @description - * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't + * Using AngularJS markup like `{{hash}}` in a `srcset` attribute doesn't * work right: The browser will fetch from the URL with the literal - * text `{{hash}}` until Angular replaces the expression inside + * text `{{hash}}` until AngularJS replaces the expression inside * `{{hash}}`. The `ngSrcset` directive solves this problem. * * The buggy way to write it: @@ -22935,14 +23367,14 @@ var htmlAnchorDirective = valueFn({ * @example -
- +
+
it('should check both checkBoxes', function() { - expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy(); - element(by.model('master')).click(); - expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy(); + expect(element(by.id('checkFollower')).getAttribute('checked')).toBeFalsy(); + element(by.model('leader')).click(); + expect(element(by.id('checkFollower')).getAttribute('checked')).toBeTruthy(); });
@@ -22972,7 +23404,7 @@ var htmlAnchorDirective = valueFn({
- +
it('should toggle readonly attr', function() { @@ -23537,15 +23969,15 @@ addSetValidityMethod({ * If the `name` attribute is specified, the form controller is published onto the current scope under * this name. * - * # Alias: {@link ng.directive:ngForm `ngForm`} + * ## Alias: {@link ng.directive:ngForm `ngForm`} * - * In Angular, forms can be nested. This means that the outer form is valid when all of the child + * In AngularJS, forms can be nested. This means that the outer form is valid when all of the child * forms are valid as well. However, browsers do not allow nesting of `
` elements, so - * Angular provides the {@link ng.directive:ngForm `ngForm`} directive, which behaves identically to + * AngularJS provides the {@link ng.directive:ngForm `ngForm`} directive, which behaves identically to * `form` but can be nested. Nested forms can be useful, for example, if the validity of a sub-group * of controls needs to be determined. * - * # CSS classes + * ## CSS classes * - `ng-valid` is set if the form is valid. * - `ng-invalid` is set if the form is invalid. * - `ng-pending` is set if the form is pending. @@ -23556,14 +23988,14 @@ addSetValidityMethod({ * Keep in mind that ngAnimate can detect each of these classes when added and removed. * * - * # Submitting a form and preventing the default action + * ## Submitting a form and preventing the default action * - * Since the role of forms in client-side Angular applications is different than in classical + * Since the role of forms in client-side AngularJS applications is different than in classical * roundtrip apps, it is desirable for the browser not to translate the form submission into a full * page reload that sends the data to the server. Instead some javascript logic should be triggered * to handle the form submission in an application-specific way. * - * For this reason, Angular prevents the default action (form submission to the server) unless the + * For this reason, AngularJS prevents the default action (form submission to the server) unless the * `` element has an `action` attribute specified. * * You can use one of the following two ways to specify what javascript method should be called when @@ -23589,8 +24021,7 @@ addSetValidityMethod({ * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit` * to have access to the updated model. * - * ## Animation Hooks - * + * @animations * Animations in ngForm are triggered when any of the associated CSS classes are added and removed. * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any * other validations that are performed within the form. Animations in ngForm are similar to how @@ -23902,10 +24333,10 @@ var inputType = { * @name input[text] * * @description - * Standard HTML text input with angular data binding, inherited by most of the `input` elements. + * Standard HTML text input with AngularJS data binding, inherited by most of the `input` elements. * * - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} required Adds `required` validation error key if the value is not entered. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to @@ -23920,7 +24351,7 @@ var inputType = { * that contains the regular expression body that will be converted to a regular expression * as in the ngPattern directive. * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue} - * does not match a RegExp found by evaluating the Angular expression given in the attribute value. + * does not match a RegExp found by evaluating the AngularJS expression given in the attribute value. * If the expression evaluates to a RegExp object, then this is used directly. * If the expression evaluates to a string, then it will be converted to a RegExp * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to @@ -23928,9 +24359,9 @@ var inputType = { * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to * start at the index of the last search's match, thus not taking the whole input value into * account. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * 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 AngularJS will not automatically trim the input. * This parameter is ignored for input[type=password] controls, which will never trim the * input. * @@ -24004,13 +24435,13 @@ var inputType = { * modern browsers do not yet support this input type, it is important to provide cues to users on the * expected input format via a placeholder or label. * - * The model must always be a Date object, otherwise Angular will throw an error. + * The model must always be a Date object, otherwise AngularJS will throw an error. * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. * * The timezone to be used to read/write the `Date` instance in the model can be defined using * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. * - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a * valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute @@ -24028,7 +24459,7 @@ var inputType = { * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * interaction with the input element. * * @example @@ -24106,13 +24537,13 @@ var inputType = { * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`. * - * The model must always be a Date object, otherwise Angular will throw an error. + * The model must always be a Date object, otherwise AngularJS will throw an error. * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. * * The timezone to be used to read/write the `Date` instance in the model can be defined using * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. * - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. * This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation @@ -24130,7 +24561,7 @@ var inputType = { * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * interaction with the input element. * * @example @@ -24209,13 +24640,13 @@ var inputType = { * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`. * - * The model must always be a Date object, otherwise Angular will throw an error. + * The model must always be a Date object, otherwise AngularJS will throw an error. * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. * * The timezone to be used to read/write the `Date` instance in the model can be defined using * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. * - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. * This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this @@ -24233,7 +24664,7 @@ var inputType = { * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * interaction with the input element. * * @example @@ -24311,13 +24742,13 @@ var inputType = { * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 * week format (yyyy-W##), for example: `2013-W02`. * - * The model must always be a Date object, otherwise Angular will throw an error. + * The model must always be a Date object, otherwise AngularJS will throw an error. * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. * * The timezone to be used to read/write the `Date` instance in the model can be defined using * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. * - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. * This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this @@ -24335,7 +24766,7 @@ var inputType = { * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * interaction with the input element. * * @example @@ -24413,7 +24844,7 @@ var inputType = { * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 * month format (yyyy-MM), for example: `2009-01`. * - * The model must always be a Date object, otherwise Angular will throw an error. + * The model must always be a Date object, otherwise AngularJS will throw an error. * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. * If the model is not set to the first of the month, the next view to model update will set it * to the first of the month. @@ -24421,7 +24852,7 @@ var inputType = { * The timezone to be used to read/write the `Date` instance in the model can be defined using * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. * - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. * This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this @@ -24440,7 +24871,7 @@ var inputType = { * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * interaction with the input element. * * @example @@ -24518,7 +24949,7 @@ var inputType = { * error if not a valid number. * *
- * The model must always be of type `number` otherwise Angular will throw an error. + * The model must always be of type `number` otherwise AngularJS will throw an error. * Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt} * error docs for more information and an example of how to convert your model if necessary. *
@@ -24533,7 +24964,7 @@ var inputType = { * will also be an empty string. * * - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. * Can be interpolated. @@ -24560,7 +24991,7 @@ var inputType = { * that contains the regular expression body that will be converted to a regular expression * as in the ngPattern directive. * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue} - * does not match a RegExp found by evaluating the Angular expression given in the attribute value. + * does not match a RegExp found by evaluating the AngularJS expression given in the attribute value. * If the expression evaluates to a RegExp object, then this is used directly. * If the expression evaluates to a string, then it will be converted to a RegExp * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to @@ -24568,7 +24999,7 @@ var inputType = { * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to * start at the index of the last search's match, thus not taking the whole input value into * account. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * interaction with the input element. * * @example @@ -24643,7 +25074,7 @@ var inputType = { * the built-in validators (see the {@link guide/forms Forms guide}) *
* - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @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=} ngRequired Adds `required` attribute and `required` validation constraint to @@ -24658,7 +25089,7 @@ var inputType = { * that contains the regular expression body that will be converted to a regular expression * as in the ngPattern directive. * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue} - * does not match a RegExp found by evaluating the Angular expression given in the attribute value. + * does not match a RegExp found by evaluating the AngularJS expression given in the attribute value. * If the expression evaluates to a RegExp object, then this is used directly. * If the expression evaluates to a string, then it will be converted to a RegExp * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to @@ -24666,7 +25097,7 @@ var inputType = { * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to * start at the index of the last search's match, thus not taking the whole input value into * account. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * interaction with the input element. * * @example @@ -24742,7 +25173,7 @@ var inputType = { * use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide}) *
* - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @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=} ngRequired Adds `required` attribute and `required` validation constraint to @@ -24757,7 +25188,7 @@ var inputType = { * that contains the regular expression body that will be converted to a regular expression * as in the ngPattern directive. * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue} - * does not match a RegExp found by evaluating the Angular expression given in the attribute value. + * does not match a RegExp found by evaluating the AngularJS expression given in the attribute value. * If the expression evaluates to a RegExp object, then this is used directly. * If the expression evaluates to a string, then it will be converted to a RegExp * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to @@ -24765,7 +25196,7 @@ var inputType = { * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to * start at the index of the last search's match, thus not taking the whole input value into * account. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * interaction with the input element. * * @example @@ -24833,14 +25264,41 @@ var inputType = { * @description * HTML radio button. * - * @param {string} ngModel Assignable angular expression to data-bind to. + * **Note:**
+ * All inputs controlled by {@link ngModel ngModel} (including those of type `radio`) will use the + * value of their `name` attribute to determine the property under which their + * {@link ngModel.NgModelController NgModelController} will be published on the parent + * {@link form.FormController FormController}. Thus, if you use the same `name` for multiple + * inputs of a form (e.g. a group of radio inputs), only _one_ `NgModelController` will be + * published on the parent `FormController` under that name. The rest of the controllers will + * continue to work as expected, but you won't be able to access them as properties on the parent + * `FormController`. + * + *
+ *

+ * In plain HTML forms, the `name` attribute is used to identify groups of radio inputs, so + * that the browser can manage their state (checked/unchecked) based on the state of other + * inputs in the same group. + *

+ *

+ * In AngularJS forms, this is not necessary. The input's state will be updated based on the + * value of the underlying model data. + *

+ *
+ * + *
+ * If you omit the `name` attribute on a radio input, `ngModel` will automatically assign it a + * unique name. + *
+ * + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @param {string} value The value to which the `ngModel` expression should be set when selected. * Note that `value` only supports `string` values, i.e. the scope model needs to be a string, * too. Use `ngValue` if you need complex models (`number`, `object`, ...). * @param {string=} name Property name of the form under which the control is published. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * interaction with the input element. - * @param {string} ngValue Angular expression to which `ngModel` will be be set when the radio + * @param {string} ngValue AngularJS expression to which `ngModel` will be be set when the radio * is selected. Should be used instead of the `value` attribute if you need * a non-string `ngModel` (`boolean`, `array`, ...). * @@ -24918,34 +25376,34 @@ var inputType = { * See the [HTML Spec on input[type=range]](https://www.w3.org/TR/html5/forms.html#range-state-(type=range)) * for more info. * - * This has the following consequences for Angular: + * This has the following consequences for AngularJS: * * Since the element value should always reflect the current model value, a range input * will set the bound ngModel expression to the value that the browser has set for the * input element. For example, in the following input ``, * if the application sets `model.value = null`, the browser will set the input to `'50'`. - * Angular will then set the model to `50`, to prevent input and model value being out of sync. + * AngularJS will then set the model to `50`, to prevent input and model value being out of sync. * * That means the model for range will immediately be set to `50` after `ngModel` has been * initialized. It also means a range input can never have the required error. * * This does not only affect changes to the model value, but also to the values of the `min`, * `max`, and `step` attributes. When these change in a way that will cause the browser to modify - * the input value, Angular will also update the model value. + * the input value, AngularJS will also update the model value. * * Automatic value adjustment also means that a range input element can never have the `required`, * `min`, or `max` errors. * * However, `step` is currently only fully implemented by Firefox. Other browsers have problems * when the step value changes dynamically - they do not adjust the element value correctly, but - * instead may set the `stepMismatch` error. If that's the case, the Angular will set the `step` + * instead may set the `stepMismatch` error. If that's the case, the AngularJS will set the `step` * error on the input, and set the model to `undefined`. * * Note that `input[range]` is not compatible with`ngMax`, `ngMin`, and `ngStep`, because they do * not set the `min` and `max` attributes, which means that the browser won't automatically adjust * the input value based on their values, and will always assume min = 0, max = 100, and step = 1. * - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} min Sets the `min` validation to ensure that the value entered is greater * than `min`. Can be interpolated. @@ -24953,7 +25411,7 @@ var inputType = { * Can be interpolated. * @param {string=} step Sets the `step` validation to ensure that the value entered matches the `step` * Can be interpolated. - * @param {string=} ngChange Angular expression to be executed when the ngModel value changes due + * @param {string=} ngChange AngularJS expression to be executed when the ngModel value changes due * to user interaction with the input element. * @param {expression=} ngChecked If the expression is truthy, then the `checked` attribute will be set on the * element. **Note** : `ngChecked` should not be used alongside `ngModel`. @@ -25020,11 +25478,11 @@ var inputType = { * @description * HTML checkbox. * - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {expression=} ngTrueValue The value to which the expression should be set when selected. * @param {expression=} ngFalseValue The value to which the expression should be set when not selected. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * interaction with the input element. * * @example @@ -25101,6 +25559,16 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) { composing = true; }); + // Support: IE9+ + element.on('compositionupdate', function(ev) { + // End composition when ev.data is empty string on 'compositionupdate' event. + // When the input de-focusses (e.g. by clicking away), IE triggers 'compositionupdate' + // instead of 'compositionend'. + if (isUndefined(ev.data) || ev.data === '') { + composing = false; + } + }); + element.on('compositionend', function() { composing = false; listener(); @@ -25159,9 +25627,9 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) { deferListener(event, this, this.value); }); - // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it + // if user modifies input value using context menu in IE, we need "paste", "cut" and "drop" events to catch it if ($sniffer.hasEvent('paste')) { - element.on('paste cut', deferListener); + element.on('paste cut drop', deferListener); } } @@ -25284,21 +25752,18 @@ function createDateInputType(type, regexp, parseDate, format) { return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) { badInputChecker(scope, element, attr, ctrl); baseInputType(scope, element, attr, ctrl, $sniffer, $browser); - var timezone = ctrl && ctrl.$options.getOption('timezone'); var previousDate; + var previousTimezone; ctrl.$$parserName = type; ctrl.$parsers.push(function(value) { if (ctrl.$isEmpty(value)) return null; + if (regexp.test(value)) { // Note: We cannot read ctrl.$modelValue, as there might be a different // parser/formatter in the processing chain so that the model // contains some different data format! - var parsedDate = parseDate(value, previousDate); - if (timezone) { - parsedDate = convertTimezoneToLocal(parsedDate, timezone); - } - return parsedDate; + return parseDateAndConvertTimeZoneToLocal(value, previousDate); } return undefined; }); @@ -25309,12 +25774,15 @@ function createDateInputType(type, regexp, parseDate, format) { } if (isValidDate(value)) { previousDate = value; - if (previousDate && timezone) { + var timezone = ctrl.$options.getOption('timezone'); + if (timezone) { + previousTimezone = timezone; previousDate = convertTimezoneToLocal(previousDate, timezone, true); } return $filter('date')(value, format, timezone); } else { previousDate = null; + previousTimezone = null; return ''; } }); @@ -25347,7 +25815,24 @@ function createDateInputType(type, regexp, parseDate, format) { } function parseObservedDateValue(val) { - return isDefined(val) && !isDate(val) ? parseDate(val) || undefined : val; + return isDefined(val) && !isDate(val) ? parseDateAndConvertTimeZoneToLocal(val) || undefined : val; + } + + function parseDateAndConvertTimeZoneToLocal(value, previousDate) { + var timezone = ctrl.$options.getOption('timezone'); + + if (previousTimezone && previousTimezone !== timezone) { + // If the timezone has changed, adjust the previousDate to the default timezone + // so that the new date is converted with the correct timezone offset + previousDate = addDateMinutes(previousDate, timezoneToOffset(previousTimezone)); + } + + var parsedDate = parseDate(value, previousDate); + + if (!isNaN(parsedDate) && timezone) { + parsedDate = convertTimezoneToLocal(parsedDate, timezone); + } + return parsedDate; } }; } @@ -25736,11 +26221,11 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt * @restrict E * * @description - * HTML textarea element control with angular data-binding. The data-binding and validation + * HTML textarea element control with AngularJS data-binding. The data-binding and validation * properties of this element are exactly the same as those of the * {@link ng.directive:input input element}. * - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @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=} ngRequired Adds `required` attribute and `required` validation constraint to @@ -25752,7 +26237,7 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any * length. * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue} - * does not match a RegExp found by evaluating the Angular expression given in the attribute value. + * does not match a RegExp found by evaluating the AngularJS expression given in the attribute value. * If the expression evaluates to a RegExp object, then this is used directly. * If the expression evaluates to a string, then it will be converted to a RegExp * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to @@ -25760,15 +26245,15 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to * start at the index of the last search's match, thus not taking the whole input value into * account. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * 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 AngularJS will not automatically trim the input. * * @knownIssue * * When specifying the `placeholder` attribute of ` @@ -28343,8 +28985,6 @@ var ngInitDirective = ngDirective({ *
*
* - * @element input - * @param {string=} ngList optional delimiter that should be used to split the value. */ var ngListDirective = function() { return { @@ -28415,7 +29055,6 @@ var ngModelMinErr = minErr('ngModel'); /** * @ngdoc type * @name ngModel.NgModelController - * * @property {*} $viewValue The actual value from the control's view. For `input` elements, this is a * String. See {@link ngModel.NgModelController#$setViewValue} for information about when the $viewValue * is set. @@ -28516,8 +29155,10 @@ var ngModelMinErr = minErr('ngModel'); * }; * ``` * - * @property {Array.} $viewChangeListeners Array of functions to execute whenever the - * view value has changed. It is called with no arguments, and its return value is ignored. + * @property {Array.} $viewChangeListeners Array of functions to execute whenever + * a change to {@link ngModel.NgModelController#$viewValue `$viewValue`} has caused a change + * to {@link ngModel.NgModelController#$modelValue `$modelValue`}. + * It is called with no arguments, and its return value is ignored. * This can be used in place of additional $watches against the model value. * * @property {Object} $error An object hash with all failing validator ids as keys. @@ -28539,7 +29180,7 @@ var ngModelMinErr = minErr('ngModel'); * listening to DOM events. * Such DOM related logic should be provided by other directives which make use of * `NgModelController` for data-binding to control elements. - * Angular provides this DOM logic for most {@link input `input`} elements. + * AngularJS provides this DOM logic for most {@link input `input`} elements. * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example * custom control example} that uses `ngModelController` to bind to `contenteditable` elements. * @@ -28659,6 +29300,9 @@ function NgModelController($scope, $exceptionHandler, $attr, $element, $parse, $ this.$name = $interpolate($attr.name || '', false)($scope); this.$$parentForm = nullFormCtrl; this.$options = defaultModelOptions; + this.$$updateEvents = ''; + // Attach the correct context to the event handler function for updateOn + this.$$updateEventHandler = this.$$updateEventHandler.bind(this); this.$$parsedNgModel = $parse($attr.ngModel); this.$$parsedNgModelAssign = this.$$parsedNgModel.assign; @@ -28855,13 +29499,14 @@ NgModelController.prototype = { * and reset the input to the last committed view value. * * It is also possible that you run into difficulties if you try to update the ngModel's `$modelValue` - * programmatically before these debounced/future events have resolved/occurred, because Angular's + * programmatically before these debounced/future events have resolved/occurred, because AngularJS's * dirty checking mechanism is not able to tell whether the model has actually changed or not. * * The `$rollbackViewValue()` method should be called before programmatically changing the model of an * input which may have such events pending. This is important in order to make sure that the * input field will be updated with the new model value and any pending operations are cancelled. * + * @example * * * angular.module('cancel-update-example', []) @@ -29263,11 +29908,184 @@ NgModelController.prototype = { * See {@link ngModelOptions} for information about what options can be specified * and how model option inheritance works. * + *
+ * **Note:** this function only affects the options set on the `ngModelController`, + * and not the options on the {@link ngModelOptions} directive from which they might have been + * obtained initially. + *
+ * + *
+ * **Note:** it is not possible to override the `getterSetter` option. + *
+ * * @param {Object} options a hash of settings to override the previous options * */ $overrideModelOptions: function(options) { this.$options = this.$options.createChild(options); + this.$$setUpdateOnEvents(); + }, + + /** + * @ngdoc method + * + * @name ngModel.NgModelController#$processModelValue + + * @description + * + * Runs the model -> view pipeline on the current + * {@link ngModel.NgModelController#$modelValue $modelValue}. + * + * The following actions are performed by this method: + * + * - the `$modelValue` is run through the {@link ngModel.NgModelController#$formatters $formatters} + * and the result is set to the {@link ngModel.NgModelController#$viewValue $viewValue} + * - the `ng-empty` or `ng-not-empty` class is set on the element + * - if the `$viewValue` has changed: + * - {@link ngModel.NgModelController#$render $render} is called on the control + * - the {@link ngModel.NgModelController#$validators $validators} are run and + * the validation status is set. + * + * This method is called by ngModel internally when the bound scope value changes. + * Application developers usually do not have to call this function themselves. + * + * This function can be used when the `$viewValue` or the rendered DOM value are not correctly + * formatted and the `$modelValue` must be run through the `$formatters` again. + * + * @example + * Consider a text input with an autocomplete list (for fruit), where the items are + * objects with a name and an id. + * A user enters `ap` and then selects `Apricot` from the list. + * Based on this, the autocomplete widget will call `$setViewValue({name: 'Apricot', id: 443})`, + * but the rendered value will still be `ap`. + * The widget can then call `ctrl.$processModelValue()` to run the model -> view + * pipeline again, which formats the object to the string `Apricot`, + * then updates the `$viewValue`, and finally renders it in the DOM. + * + * + +
+
+ Search Fruit: + +
+
+ Model:
+
{{selectedFruit | json}}
+
+
+
+ + angular.module('inputExample', []) + .controller('inputController', function($scope) { + $scope.items = [ + {name: 'Apricot', id: 443}, + {name: 'Clementine', id: 972}, + {name: 'Durian', id: 169}, + {name: 'Jackfruit', id: 982}, + {name: 'Strawberry', id: 863} + ]; + }) + .component('basicAutocomplete', { + bindings: { + items: '<', + onSelect: '&' + }, + templateUrl: 'autocomplete.html', + controller: function($element, $scope) { + var that = this; + var ngModel; + + that.$postLink = function() { + ngModel = $element.find('input').controller('ngModel'); + + ngModel.$formatters.push(function(value) { + return (value && value.name) || value; + }); + + ngModel.$parsers.push(function(value) { + var match = value; + for (var i = 0; i < that.items.length; i++) { + if (that.items[i].name === value) { + match = that.items[i]; + break; + } + } + + return match; + }); + }; + + that.selectItem = function(item) { + ngModel.$setViewValue(item); + ngModel.$processModelValue(); + that.onSelect({item: item}); + }; + } + }); + + +
+ +
    +
  • + +
  • +
+
+
+ *
+ * + */ + $processModelValue: function() { + var viewValue = this.$$format(); + + if (this.$viewValue !== viewValue) { + this.$$updateEmptyClasses(viewValue); + this.$viewValue = this.$$lastCommittedViewValue = viewValue; + this.$render(); + // It is possible that model and view value have been updated during render + this.$$runValidators(this.$modelValue, this.$viewValue, noop); + } + }, + + /** + * This method is called internally to run the $formatters on the $modelValue + */ + $$format: function() { + var formatters = this.$formatters, + idx = formatters.length; + + var viewValue = this.$modelValue; + while (idx--) { + viewValue = formatters[idx](viewValue); + } + + return viewValue; + }, + + /** + * This method is called internally when the bound scope value changes. + */ + $$setModelValue: function(modelValue) { + this.$modelValue = this.$$rawModelValue = modelValue; + this.$$parserValid = undefined; + this.$processModelValue(); + }, + + $$setUpdateOnEvents: function() { + if (this.$$updateEvents) { + this.$$element.off(this.$$updateEvents, this.$$updateEventHandler); + } + + this.$$updateEvents = this.$options.getOption('updateOn'); + if (this.$$updateEvents) { + this.$$element.on(this.$$updateEvents, this.$$updateEventHandler); + } + }, + + $$updateEventHandler: function(ev) { + this.$$debounceViewValueCommit(ev && ev.type); } }; @@ -29284,30 +30102,14 @@ function setupModelWatcher(ctrl) { var modelValue = ctrl.$$ngModelGet(scope); // if scope model value and ngModel value are out of sync - // TODO(perf): why not move this to the action fn? + // This cannot be moved to the action function, because it would not catch the + // case where the model is changed in the ngChange function or the model setter if (modelValue !== ctrl.$modelValue && - // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator - // eslint-disable-next-line no-self-compare - (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue) + // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator + // eslint-disable-next-line no-self-compare + (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue) ) { - ctrl.$modelValue = ctrl.$$rawModelValue = modelValue; - ctrl.$$parserValid = undefined; - - var formatters = ctrl.$formatters, - idx = formatters.length; - - var viewValue = modelValue; - while (idx--) { - viewValue = formatters[idx](viewValue); - } - if (ctrl.$viewValue !== viewValue) { - ctrl.$$updateEmptyClasses(viewValue); - ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue; - ctrl.$render(); - - // It is possible that model and view value have been updated during render - ctrl.$$runValidators(ctrl.$modelValue, ctrl.$viewValue, noop); - } + ctrl.$$setModelValue(modelValue); } return modelValue; @@ -29333,7 +30135,7 @@ function setupModelWatcher(ctrl) { * classes and can be bound to as `{{ someForm.someControl.$error.myError }}`. * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined), * or skipped (null). Pending is used for unfulfilled `$asyncValidators`. - * Skipped is used by Angular when validators do not run because of parse errors and + * Skipped is used by AngularJS when validators do not run because of parse errors and * when `$asyncValidators` do not run because any of the `$validators` failed. */ addSetValidityMethod({ @@ -29350,9 +30152,9 @@ addSetValidityMethod({ /** * @ngdoc directive * @name ngModel - * - * @element input + * @restrict A * @priority 1 + * @param {expression} ngModel assignable {@link guide/expression Expression} to bind to. * * @description * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a @@ -29394,7 +30196,7 @@ addSetValidityMethod({ * - {@link ng.directive:select select} * - {@link ng.directive:textarea textarea} * - * # Complex Models (objects or collections) + * ## Complex Models (objects or collections) * * By default, `ngModel` watches the model by reference, not value. This is important to know when * binding inputs to models that are objects (e.g. `Date`) or collections (e.g. arrays). If only properties of the @@ -29410,7 +30212,7 @@ addSetValidityMethod({ * first level of the object (or only changing the properties of an item in the collection if it's an array) will still * not trigger a re-rendering of the model. * - * # CSS classes + * ## CSS classes * The following CSS classes are added and removed on the associated input/select/textarea element * depending on the validity of the model. * @@ -29429,8 +30231,7 @@ addSetValidityMethod({ * * Keep in mind that ngAnimate can detect each of these classes when added and removed. * - * ## Animation Hooks - * + * @animations * Animations within models are triggered when any of the associated CSS classes are added and removed * on the input element which is attached to the model. These classes include: `.ng-pristine`, `.ng-dirty`, * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself. @@ -29454,6 +30255,7 @@ addSetValidityMethod({ * * * @example + * ### Basic Usage * @@ -7943,11 +8024,11 @@ function $TemplateCacheProvider() { it('should auto compile', function() { var textarea = $('textarea'); var output = $('div[compile]'); - // The initial state reads 'Hello Angular'. - expect(output.getText()).toBe('Hello Angular'); + // The initial state reads 'Hello AngularJS'. + expect(output.getText()).toBe('Hello AngularJS'); textarea.clear(); textarea.sendKeys('{{name}}!'); - expect(output.getText()).toBe('Angular!'); + expect(output.getText()).toBe('AngularJS!'); }); @@ -8001,7 +8082,7 @@ function $TemplateCacheProvider() { * element passed in, or the clone of the element if the `cloneAttachFn` is provided. * * After linking the view is not updated until after a call to $digest which typically is done by - * Angular automatically. + * AngularJS automatically. * * If you need access to the bound view, there are two ways to do it: * @@ -8027,7 +8108,7 @@ function $TemplateCacheProvider() { * * * For information on how the compiler works, see the - * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide. + * {@link guide/compiler AngularJS HTML Compiler} section of the Developer Guide. * * @knownIssue * @@ -8037,6 +8118,59 @@ function $TemplateCacheProvider() { compiled again. This is an undesired effect and can lead to misbehaving directives, performance issues, and memory leaks. Refer to the Compiler Guide {@link guide/compiler#double-compilation-and-how-to-avoid-it section on double compilation} for an in-depth explanation and ways to avoid it. + + * @knownIssue + + ### Issues with `replace: true` + * + *
+ * **Note**: {@link $compile#-replace- `replace: true`} is deprecated and not recommended to use, + * mainly due to the issues listed here. It has been completely removed in the new Angular. + *
+ * + * #### Attribute values are not merged + * + * When a `replace` directive encounters the same attribute on the original and the replace node, + * it will simply deduplicate the attribute and join the values with a space or with a `;` in case of + * the `style` attribute. + * ```html + * Original Node: + * Replace Template: + * Result: + * ``` + * + * That means attributes that contain AngularJS expressions will not be merged correctly, e.g. + * {@link ngShow} or {@link ngClass} will cause a {@link $parse} error: + * + * ```html + * Original Node: + * Replace Template: + * Result: + * ``` + * + * See issue [#5695](https://github.com/angular/angular.js/issues/5695). + * + * #### Directives are not deduplicated before compilation + * + * When the original node and the replace template declare the same directive(s), they will be + * {@link guide/compiler#double-compilation-and-how-to-avoid-it compiled twice} because the compiler + * does not deduplicate them. In many cases, this is not noticable, but e.g. {@link ngModel} will + * attach `$formatters` and `$parsers` twice. + * + * See issue [#2573](https://github.com/angular/angular.js/issues/2573). + * + * #### `transclude: element` in the replace template root can have + * unexpected effects + * + * When the replace template has a directive at the root node that uses + * {@link $compile#-transclude- `transclude: element`}, e.g. + * {@link ngIf} or {@link ngRepeat}, the DOM structure or scope inheritance can be incorrect. + * See the following issues: + * + * - Incorrect scope on replaced element: + * [#9837](https://github.com/angular/angular.js/issues/9837) + * - Different DOM between `template` and `templateUrl`: + * [#10612](https://github.com/angular/angular.js/issues/14326) * */ @@ -8068,11 +8202,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { var bindingCache = createMap(); function parseIsolateBindings(scope, directiveName, isController) { - var LOCAL_REGEXP = /^\s*([@&<]|=(\*?))(\??)\s*([\w$]*)\s*$/; + var LOCAL_REGEXP = /^([@&<]|=(\*?))(\??)\s*([\w$]*)$/; var bindings = createMap(); forEach(scope, function(definition, scopeName) { + definition = definition.trim(); + if (definition in bindingCache) { bindings[scopeName] = bindingCache[definition]; return; @@ -8351,7 +8487,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { // TODO(pete) remove the following `forEach` before we release 1.6.0 // The component-router@0.2.0 looks for the annotations on the controller constructor - // Nothing in Angular looks for annotations on the factory function but we can't remove + // Nothing in AngularJS looks for annotations on the factory function but we can't remove // it from 1.5.x yet. // Copy any annotation properties (starting with $) over to the factory and controller constructor functions @@ -8444,7 +8580,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { * binding information and a reference to the current scope on to DOM elements. * If enabled, the compiler will add the following to DOM elements that have been bound to the scope * * `ng-binding` CSS class + * * `ng-scope` and `ng-isolated-scope` CSS classes * * `$binding` data property containing an array of the binding expressions + * * Data properties used by the {@link angular.element#methods `scope()`/`isolateScope()` methods} to return + * the element's scope. + * * Placeholder comments will contain information about what directive and binding caused the placeholder. + * E.g. ``. * * You may want to disable this in production for a significant performance boost. See * {@link guide/production#disabling-debug-data Disabling Debug Data} for more. @@ -8637,19 +8778,15 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { } // We must run this hook in an apply since the $$postDigest runs outside apply $rootScope.$apply(function() { - var errors = []; for (var i = 0, ii = onChangesQueue.length; i < ii; ++i) { try { onChangesQueue[i](); } catch (e) { - errors.push(e); + $exceptionHandler(e); } } // Reset the queue to trigger a new schedule next time there is a change onChangesQueue = undefined; - if (errors.length) { - throw errors; - } }); } finally { onChangesTtl++; @@ -8795,7 +8932,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { if ((nodeName === 'a' && (key === 'href' || key === 'xlinkHref')) || (nodeName === 'img' && key === 'src')) { // sanitize a[href] and img[src] values - this[key] = value = $$sanitizeUri(value, key === 'src'); + this[key] = value = (value == null) ? value : $$sanitizeUri(value, key === 'src'); } else if (nodeName === 'img' && key === 'srcset' && isDefined(value)) { // sanitize img[srcset] values var result = ''; @@ -8833,7 +8970,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { } if (writeAttr !== false) { - if (value === null || isUndefined(value)) { + if (value == null) { this.$$element.removeAttr(attrName); } else { if (SIMPLE_ATTR_NAME.test(attrName)) { @@ -9017,7 +9154,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { // for call to the link function. // Note: This will already clone the nodes... $linkNode = jqLite( - wrapTemplate(namespace, jqLite('
').append($compileNodes).html()) + wrapTemplate(namespace, jqLite('
').append($compileNodes).html()) ); } else if (cloneConnectFn) { // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart @@ -10513,7 +10650,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { } if (jqLite.hasData(firstElementToRemove)) { - // Copy over user data (that includes Angular's $scope etc.). Don't copy private + // Copy over user data (that includes AngularJS's $scope etc.). Don't copy private // data here because there's no public interface in jQuery to do that and copying over // event listeners (which is the main use of private data) wouldn't work anyway. jqLite.data(newNode, jqLite.data(firstElementToRemove)); @@ -10591,7 +10728,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { // the value is there for use in the link fn destination[scopeName] = $interpolate(lastValue)(scope); } else if (isBoolean(lastValue)) { - // If the attributes is one of the BOOLEAN_ATTR then Angular will have converted + // If the attributes is one of the BOOLEAN_ATTR then AngularJS will have converted // the value to boolean rather than a string, so we special case this situation destination[scopeName] = lastValue; } @@ -10745,7 +10882,9 @@ var SPECIAL_CHARS_REGEXP = /[:\-_]+(.)/g; function directiveNormalize(name) { return name .replace(PREFIX_REGEXP, '') - .replace(SPECIAL_CHARS_REGEXP, fnCamelCaseReplace); + .replace(SPECIAL_CHARS_REGEXP, function(_, letter, offset) { + return offset ? letter.toUpperCase() : letter; + }); } /** @@ -10755,7 +10894,7 @@ function directiveNormalize(name) { * @description * A shared object between directive compile / linking functions which contains normalized DOM * element attributes. The values reflect current binding state `{{ }}`. The normalization is - * needed since all of these are treated as equivalent in Angular: + * needed since all of these are treated as equivalent in AngularJS: * * ``` * @@ -10861,7 +11000,7 @@ function identifierForController(controller, ident) { * @this * * @description - * The {@link ng.$controller $controller service} is used by Angular to create new + * The {@link ng.$controller $controller service} is used by AngularJS to create new * controllers. * * This provider allows controller registration via the @@ -11099,7 +11238,7 @@ function $$IsDocumentHiddenProvider() { * @this * * @description - * Any uncaught exception in angular expressions is delegated to this service. + * Any uncaught exception in AngularJS expressions is delegated to this service. * The default implementation simply delegates to `$log.error` which logs it into * the browser console. * @@ -11201,7 +11340,7 @@ function $HttpParamSerializerProvider() { * * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D` (stringified and encoded representation of an object) * * Note that serializer will sort the request parameters alphabetically. - * */ + */ this.$get = function() { return function ngParamSerializer(params) { @@ -11268,7 +11407,7 @@ function $HttpParamSerializerJQLikeProvider() { * }); * ``` * - * */ + */ this.$get = function() { return function jQueryLikeParamSerializer(params) { if (!params) return ''; @@ -11425,7 +11564,7 @@ function isSuccess(status) { * * @description * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service. - * */ + */ function $HttpProvider() { /** * @ngdoc property @@ -11479,7 +11618,7 @@ function $HttpProvider() { * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the * XSRF token. Defaults value is `'X-XSRF-TOKEN'`. * - **/ + */ var defaults = this.defaults = { // transform incoming response data transformResponse: [defaultHttpResponseTransform], @@ -11526,7 +11665,7 @@ function $HttpProvider() { * * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining. * otherwise, returns the current configured value. - **/ + */ this.useApplyAsync = function(value) { if (isDefined(value)) { useApplyAsync = !!value; @@ -11547,9 +11686,51 @@ function $HttpProvider() { * array, on request, but reverse order, on response. * * {@link ng.$http#interceptors Interceptors detailed info} - **/ + */ var interceptorFactories = this.interceptors = []; + /** + * @ngdoc property + * @name $httpProvider#xsrfWhitelistedOrigins + * @description + * + * Array containing URLs whose origins are trusted to receive the XSRF token. See the + * {@link ng.$http#security-considerations Security Considerations} sections for more details on + * XSRF. + * + * **Note:** An "origin" consists of the [URI scheme](https://en.wikipedia.org/wiki/URI_scheme), + * the [hostname](https://en.wikipedia.org/wiki/Hostname) and the + * [port number](https://en.wikipedia.org/wiki/Port_(computer_networking). For `http:` and + * `https:`, the port number can be omitted if using th default ports (80 and 443 respectively). + * Examples: `http://example.com`, `https://api.example.com:9876` + * + *
+ * It is not possible to whitelist specific URLs/paths. The `path`, `query` and `fragment` parts + * of a URL will be ignored. For example, `https://foo.com/path/bar?query=baz#fragment` will be + * treated as `https://foo.com`, meaning that **all** requests to URLs starting with + * `https://foo.com/` will include the XSRF token. + *
+ * + * @example + * + * ```js + * // App served from `https://example.com/`. + * angular. + * module('xsrfWhitelistedOriginsExample', []). + * config(['$httpProvider', function($httpProvider) { + * $httpProvider.xsrfWhitelistedOrigins.push('https://api.example.com'); + * }]). + * run(['$http', function($http) { + * // The XSRF token will be sent. + * $http.get('https://api.example.com/preferences').then(...); + * + * // The XSRF token will NOT be sent. + * $http.get('https://stats.example.com/activity').then(...); + * }]); + * ``` + */ + var xsrfWhitelistedOrigins = this.xsrfWhitelistedOrigins = []; + this.$get = ['$browser', '$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector', '$sce', function($browser, $httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector, $sce) { @@ -11573,6 +11754,11 @@ function $HttpProvider() { ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory)); }); + /** + * A function to check request URLs against a list of allowed origins. + */ + var urlIsAllowedOrigin = urlIsAllowedOriginFactory(xsrfWhitelistedOrigins); + /** * @ngdoc service * @kind function @@ -11584,7 +11770,7 @@ function $HttpProvider() { * @requires $injector * * @description - * The `$http` service is a core Angular service that facilitates communication with the remote + * The `$http` service is a core AngularJS service that facilitates communication with the remote * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest) * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP). * @@ -11601,7 +11787,9 @@ function $HttpProvider() { * * ## General usage * The `$http` service is a function which takes a single argument — a {@link $http#usage configuration object} — - * that is used to generate an HTTP request and returns a {@link ng.$q promise}. + * that is used to generate an HTTP request and returns a {@link ng.$q promise} that is + * resolved (request success) or rejected (request failure) with a + * {@link ng.$http#$http-returns response} object. * * ```js * // Simple GET request example: @@ -11617,24 +11805,6 @@ function $HttpProvider() { * }); * ``` * - * The response object has these properties: - * - * - **data** – `{string|Object}` – The response body transformed with the transform - * functions. - * - **status** – `{number}` – HTTP status code of the response. - * - **headers** – `{function([headerName])}` – Header getter function. - * - **config** – `{Object}` – The configuration object that was used to generate the request. - * - **statusText** – `{string}` – HTTP status text of the response. - * - **xhrStatus** – `{string}` – Status of the XMLHttpRequest (`complete`, `error`, `timeout` or `abort`). - * - * A response status code between 200 and 299 is considered a success status and will result in - * the success callback being called. Any response status code outside of that range is - * considered an error status and will result in the error callback being called. - * Also, status codes less than -1 are normalized to zero. -1 usually means the request was - * aborted, e.g. using a `config.timeout`. - * Note that if the response is a redirect, XMLHttpRequest will transparently follow it, meaning - * that the outcome (success or error) will be determined by the final response status code. - * * * ## Shortcut methods * @@ -11723,7 +11893,7 @@ function $HttpProvider() { * which allows you to `push` or `unshift` a new transformation function into the transformation chain. * *
- * **Note:** Angular does not make a copy of the `data` parameter before it is passed into the `transformRequest` pipeline. + * **Note:** AngularJS does not make a copy of the `data` parameter before it is passed into the `transformRequest` pipeline. * That means changes to the properties of `data` are not local to the transform function (since Javascript passes objects by reference). * For example, when calling `$http.get(url, $scope.myObject)`, modifications to the object's properties in a transformRequest * function will be reflected on the scope and in any templates where the object is data-bound. @@ -11740,7 +11910,7 @@ function $HttpProvider() { * You can augment or replace the default transformations by modifying these properties by adding to or * replacing the array. * - * Angular provides the following default transformations: + * AngularJS provides the following default transformations: * * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`) is * an array with one function that does the following: @@ -11913,7 +12083,7 @@ function $HttpProvider() { * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx) * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) * - * Both server and the client must cooperate in order to eliminate these threats. Angular comes + * Both server and the client must cooperate in order to eliminate these threats. AngularJS comes * pre-configured with strategies that address these issues, but for this to work backend server * cooperation is required. * @@ -11923,7 +12093,7 @@ function $HttpProvider() { * allows third party website to turn your JSON resource URL into * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To * counter this your server can prefix all JSON requests with following string `")]}',\n"`. - * Angular will automatically strip the prefix before processing it as JSON. + * AngularJS will automatically strip the prefix before processing it as JSON. * * For example if your server needs to return: * ```js @@ -11936,34 +12106,51 @@ function $HttpProvider() { * ['one','two'] * ``` * - * Angular will strip the prefix, before processing the JSON. + * AngularJS will strip the prefix, before processing the JSON. * * * ### Cross Site Request Forgery (XSRF) Protection * * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is an attack technique by * which the attacker can trick an authenticated user into unknowingly executing actions on your - * website. Angular provides a mechanism to counter XSRF. When performing XHR requests, the + * website. AngularJS provides a mechanism to counter XSRF. When performing XHR requests, the * $http service reads a token from a cookie (by default, `XSRF-TOKEN`) and sets it as an HTTP - * header (`X-XSRF-TOKEN`). Since only JavaScript that runs on your domain could read the - * cookie, your server can be assured that the XHR came from JavaScript running on your domain. - * The header will not be set for cross-domain requests. + * header (by default `X-XSRF-TOKEN`). Since only JavaScript that runs on your domain could read + * the cookie, your server can be assured that the XHR came from JavaScript running on your + * domain. * * To take advantage of this, your server needs to set a token in a JavaScript readable session * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the - * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure - * 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 + * server can verify that the cookie matches the `X-XSRF-TOKEN` HTTP header, and therefore be + * sure 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 * 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)) * for added security. * - * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName - * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time, - * or the per-request config object. + * The header will — by default — **not** be set for cross-domain requests. This + * prevents unauthorized servers (e.g. malicious or compromised 3rd-party APIs) from gaining + * access to your users' XSRF tokens and exposing them to Cross Site Request Forgery. If you + * want to, you can whitelist additional origins to also receive the XSRF token, by adding them + * to {@link ng.$httpProvider#xsrfWhitelistedOrigins xsrfWhitelistedOrigins}. This might be + * useful, for example, if your application, served from `example.com`, needs to access your API + * at `api.example.com`. + * See {@link ng.$httpProvider#xsrfWhitelistedOrigins $httpProvider.xsrfWhitelistedOrigins} for + * more details. + * + *
+ * **Warning**
+ * Only whitelist origins that you have control over and make sure you understand the + * implications of doing so. + *
+ * + * The name of the cookie and the header can be specified using the `xsrfCookieName` and + * `xsrfHeaderName` properties of either `$httpProvider.defaults` at config-time, + * `$http.defaults` at run-time, or the per-request config object. + * + * In order to prevent collisions in environments where multiple AngularJS apps share the + * same domain or subdomain, we recommend that each application uses a unique cookie name. * - * In order to prevent collisions in environments where multiple Angular apps share the - * same domain or subdomain, we recommend that each application uses unique cookie name. * * @param {object} config Object describing the request to be made and how it should be * processed. The object has following properties: @@ -12009,14 +12196,44 @@ function $HttpProvider() { * See {@link $http#caching $http Caching} for more information. * - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} * that should abort the request when resolved. + * + * A numerical timeout or a promise returned from {@link ng.$timeout $timeout}, will set + * the `xhrStatus` in the {@link $http#$http-returns response} to "timeout", and any other + * resolved promise will set it to "abort", following standard XMLHttpRequest behavior. + * * - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the * XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials) * for more information. * - **responseType** - `{string}` - see * [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype). * - * @returns {HttpPromise} Returns a {@link ng.$q `Promise}` that will be resolved to a response object - * when the request succeeds or fails. + * @returns {HttpPromise} A {@link ng.$q `Promise}` that will be resolved (request success) + * or rejected (request failure) with a response object. + * + * The response object has these properties: + * + * - **data** – `{string|Object}` – The response body transformed with + * the transform functions. + * - **status** – `{number}` – HTTP status code of the response. + * - **headers** – `{function([headerName])}` – Header getter function. + * - **config** – `{Object}` – The configuration object that was used + * to generate the request. + * - **statusText** – `{string}` – HTTP status text of the response. + * - **xhrStatus** – `{string}` – Status of the XMLHttpRequest + * (`complete`, `error`, `timeout` or `abort`). + * + * + * A response status code between 200 and 299 is considered a success status + * and will result in the success callback being called. Any response status + * code outside of that range is considered an error status and will result + * in the error callback being called. + * Also, status codes less than -1 are normalized to zero. -1 usually means + * the request was aborted, e.g. using a `config.timeout`. More information + * about the status might be available in the `xhrStatus` property. + * + * Note that if the response is a redirect, XMLHttpRequest will transparently + * follow it, meaning that the outcome (success or error) will be determined + * by the final response status code. * * * @property {Array.} pendingRequests Array of config objects for currently pending @@ -12266,8 +12483,9 @@ function $HttpProvider() { * * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested; * or an object created by a call to `$sce.trustAsResourceUrl(url)`. - * @param {Object=} config Optional configuration object - * @returns {HttpPromise} Future object + * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}. + * @returns {HttpPromise} A Promise that will be resolved or rejected with a response object. + * See {@link ng.$http#$http-returns `$http()` return value}. */ /** @@ -12279,8 +12497,9 @@ function $HttpProvider() { * * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested; * or an object created by a call to `$sce.trustAsResourceUrl(url)`. - * @param {Object=} config Optional configuration object - * @returns {HttpPromise} Future object + * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}. + * @returns {HttpPromise} A Promise that will be resolved or rejected with a response object. + * See {@link ng.$http#$http-returns `$http()` return value}. */ /** @@ -12292,8 +12511,9 @@ function $HttpProvider() { * * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested; * or an object created by a call to `$sce.trustAsResourceUrl(url)`. - * @param {Object=} config Optional configuration object - * @returns {HttpPromise} Future object + * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}. + * @returns {HttpPromise} A Promise that will be resolved or rejected with a response object. + * See {@link ng.$http#$http-returns `$http()` return value}. */ /** @@ -12309,6 +12529,10 @@ function $HttpProvider() { * {@link $sceDelegateProvider#resourceUrlWhitelist `$sceDelegateProvider.resourceUrlWhitelist`} or * by explicitly trusting the URL via {@link $sce#trustAsResourceUrl `$sce.trustAsResourceUrl(url)`}. * + * You should avoid generating the URL for the JSONP request from user provided data. + * Provide additional query parameters via `params` property of the `config` parameter, rather than + * modifying the URL itself. + * * JSONP requests must specify a callback to be used in the response from the server. This callback * is passed as a query parameter in the request. You must specify the name of this parameter by * setting the `jsonpCallbackParam` property on the request config object. @@ -12330,8 +12554,9 @@ function $HttpProvider() { * * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested; * or an object created by a call to `$sce.trustAsResourceUrl(url)`. - * @param {Object=} config Optional configuration object - * @returns {HttpPromise} Future object + * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}. + * @returns {HttpPromise} A Promise that will be resolved or rejected with a response object. + * See {@link ng.$http#$http-returns `$http()` return value}. */ createShortMethods('get', 'delete', 'head', 'jsonp'); @@ -12344,8 +12569,9 @@ function $HttpProvider() { * * @param {string} url Relative or absolute URL specifying the destination of the request * @param {*} data Request content - * @param {Object=} config Optional configuration object - * @returns {HttpPromise} Future object + * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}. + * @returns {HttpPromise} A Promise that will be resolved or rejected with a response object. + * See {@link ng.$http#$http-returns `$http()` return value}. */ /** @@ -12357,8 +12583,9 @@ function $HttpProvider() { * * @param {string} url Relative or absolute URL specifying the destination of the request * @param {*} data Request content - * @param {Object=} config Optional configuration object - * @returns {HttpPromise} Future object + * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}. + * @returns {HttpPromise} A Promise that will be resolved or rejected with a response object. + * See {@link ng.$http#$http-returns `$http()` return value}. */ /** @@ -12370,8 +12597,9 @@ function $HttpProvider() { * * @param {string} url Relative or absolute URL specifying the destination of the request * @param {*} data Request content - * @param {Object=} config Optional configuration object - * @returns {HttpPromise} Future object + * @param {Object=} config Optional configuration object. See {@link ng.$http#$http-arguments `$http()` arguments}. + * @returns {HttpPromise} A Promise that will be resolved or rejected with a response object. + * See {@link ng.$http#$http-returns `$http()` return value}. */ createShortMethodsWithData('post', 'put', 'patch'); @@ -12482,7 +12710,7 @@ function $HttpProvider() { // if we won't have the response in cache, set the xsrf headers and // send the request to the backend if (isUndefined(cachedResp)) { - var xsrfValue = urlIsSameOrigin(config.url) + var xsrfValue = urlIsAllowedOrigin(config.url) ? $$cookieReader()[config.xsrfCookieName || defaults.xsrfCookieName] : undefined; if (xsrfValue) { @@ -12584,20 +12812,26 @@ function $HttpProvider() { return url; } - function sanitizeJsonpCallbackParam(url, key) { - if (/[&?][^=]+=JSON_CALLBACK/.test(url)) { - // Throw if the url already contains a reference to JSON_CALLBACK - throw $httpMinErr('badjsonp', 'Illegal use of JSON_CALLBACK in url, "{0}"', url); - } - - var callbackParamRegex = new RegExp('[&?]' + key + '='); - if (callbackParamRegex.test(url)) { - // Throw if the callback param was already provided - throw $httpMinErr('badjsonp', 'Illegal use of callback param, "{0}", in url, "{1}"', key, url); + function sanitizeJsonpCallbackParam(url, cbKey) { + var parts = url.split('?'); + if (parts.length > 2) { + // Throw if the url contains more than one `?` query indicator + throw $httpMinErr('badjsonp', 'Illegal use more than one "?", in url, "{1}"', url); } + var params = parseKeyValue(parts[1]); + forEach(params, function(value, key) { + if (value === 'JSON_CALLBACK') { + // Throw if the url already contains a reference to JSON_CALLBACK + throw $httpMinErr('badjsonp', 'Illegal use of JSON_CALLBACK in url, "{0}"', url); + } + if (key === cbKey) { + // Throw if the callback param was already provided + throw $httpMinErr('badjsonp', 'Illegal use of callback param, "{0}", in url, "{1}"', cbKey, url); + } + }); // Add in the JSON_CALLBACK callback param value - url += ((url.indexOf('?') === -1) ? '?' : '&') + key + '=JSON_CALLBACK'; + url += ((url.indexOf('?') === -1) ? '?' : '&') + cbKey + '=JSON_CALLBACK'; return url; } @@ -12674,6 +12908,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc } else { var xhr = createXhr(method, url); + var abortedByTimeout = false; xhr.open(method, url, true); forEach(headers, function(value, key) { @@ -12714,7 +12949,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc }; var requestAborted = function() { - completeRequest(callback, -1, null, null, '', 'abort'); + completeRequest(callback, -1, null, null, '', abortedByTimeout ? 'timeout' : 'abort'); }; var requestTimeout = function() { @@ -12724,11 +12959,11 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc }; xhr.onerror = requestError; - xhr.onabort = requestAborted; xhr.ontimeout = requestTimeout; + xhr.onabort = requestAborted; forEach(eventHandlers, function(value, key) { - xhr.addEventListener(key, value); + xhr.addEventListener(key, value); }); forEach(uploadEventHandlers, function(value, key) { @@ -12759,14 +12994,26 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc xhr.send(isUndefined(post) ? null : post); } + // Since we are using xhr.abort() when a request times out, we have to set a flag that + // indicates to requestAborted if the request timed out or was aborted. + // + // http.timeout = numerical timeout timeout + // http.timeout = $timeout timeout + // http.timeout = promise abort + // xhr.abort() abort (The xhr object is normally inaccessible, but + // can be exposed with the xhrFactory) if (timeout > 0) { - var timeoutId = $browserDefer(timeoutRequest, timeout); + var timeoutId = $browserDefer(function() { + timeoutRequest('timeout'); + }, timeout); } else if (isPromiseLike(timeout)) { - timeout.then(timeoutRequest); + timeout.then(function() { + timeoutRequest(isDefined(timeout.$$timeoutId) ? 'timeout' : 'abort'); + }); } - - function timeoutRequest() { + function timeoutRequest(reason) { + abortedByTimeout = reason === 'timeout'; if (jsonpDone) { jsonpDone(); } @@ -12846,9 +13093,9 @@ $interpolateMinErr.interr = function(text, err) { * Used for configuring the interpolation markup. Defaults to `{{` and `}}`. * *
- * This feature is sometimes used to mix different markup languages, e.g. to wrap an Angular + * This feature is sometimes used to mix different markup languages, e.g. to wrap an AngularJS * template within a Python Jinja template (or any other template language). Mixing templating - * languages is **very dangerous**. The embedding template language will not safely escape Angular + * languages is **very dangerous**. The embedding template language will not safely escape AngularJS * expressions, so any user-controlled values in the template will cause Cross Site Scripting (XSS) * security bugs! *
@@ -12964,7 +13211,7 @@ function $InterpolateProvider() { * ```js * var $interpolate = ...; // injected * var exp = $interpolate('Hello {{name | uppercase}}!'); - * expect(exp({name:'Angular'})).toEqual('Hello ANGULAR!'); + * expect(exp({name:'AngularJS'})).toEqual('Hello ANGULAR!'); * ``` * * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is @@ -12982,8 +13229,8 @@ function $InterpolateProvider() { * // "allOrNothing" mode * exp = $interpolate('{{greeting}} {{name}}!', false, null, true); * expect(exp(context)).toBeUndefined(); - * context.name = 'Angular'; - * expect(exp(context)).toEqual('Hello Angular!'); + * context.name = 'AngularJS'; + * expect(exp(context)).toEqual('Hello AngularJS!'); * ``` * * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior. @@ -13157,9 +13404,7 @@ function $InterpolateProvider() { var lastValue; return scope.$watchGroup(parseFns, /** @this */ function interpolateFnWatcher(values, oldValues) { var currValue = compute(values); - if (isFunction(listener)) { - listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope); - } + listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope); lastValue = currValue; }); } @@ -13219,132 +13464,132 @@ function $IntervalProvider() { var intervals = {}; - /** - * @ngdoc service - * @name $interval - * - * @description - * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay` - * milliseconds. - * - * The return value of registering an interval function is a promise. This promise will be - * notified upon each tick of the interval, and will be resolved after `count` iterations, or - * run indefinitely if `count` is not defined. The value of the notification will be the - * number of iterations that have run. - * To cancel an interval, call `$interval.cancel(promise)`. - * - * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to - * move forward by `millis` milliseconds and trigger any functions scheduled to run in that - * time. - * - *
- * **Note**: Intervals created by this service must be explicitly destroyed when you are finished - * with them. In particular they are not automatically destroyed when a controller's scope or a - * directive's element are destroyed. - * You should take this into consideration and make sure to always cancel the interval at the - * appropriate moment. See the example below for more details on how and when to do this. - *
- * - * @param {function()} fn A function that should be called repeatedly. If no additional arguments - * are passed (see below), the function is called with the current iteration count. - * @param {number} delay Number of milliseconds between each function call. - * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat - * indefinitely. - * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise - * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block. - * @param {...*=} Pass additional parameters to the executed function. - * @returns {promise} A promise which will be notified on each iteration. It will resolve once all iterations of the interval complete. - * - * @example - * - * - * - * - *
- *
- *
- * Current time is: - *
- * Blood 1 : {{blood_1}} - * Blood 2 : {{blood_2}} - * - * - * - *
- *
- * - *
- *
- */ + /** + * @ngdoc service + * @name $interval + * + * @description + * AngularJS's wrapper for `window.setInterval`. The `fn` function is executed every `delay` + * milliseconds. + * + * The return value of registering an interval function is a promise. This promise will be + * notified upon each tick of the interval, and will be resolved after `count` iterations, or + * run indefinitely if `count` is not defined. The value of the notification will be the + * number of iterations that have run. + * To cancel an interval, call `$interval.cancel(promise)`. + * + * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to + * move forward by `millis` milliseconds and trigger any functions scheduled to run in that + * time. + * + *
+ * **Note**: Intervals created by this service must be explicitly destroyed when you are finished + * with them. In particular they are not automatically destroyed when a controller's scope or a + * directive's element are destroyed. + * You should take this into consideration and make sure to always cancel the interval at the + * appropriate moment. See the example below for more details on how and when to do this. + *
+ * + * @param {function()} fn A function that should be called repeatedly. If no additional arguments + * are passed (see below), the function is called with the current iteration count. + * @param {number} delay Number of milliseconds between each function call. + * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat + * indefinitely. + * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise + * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block. + * @param {...*=} Pass additional parameters to the executed function. + * @returns {promise} A promise which will be notified on each iteration. It will resolve once all iterations of the interval complete. + * + * @example + * + * + * + * + *
+ *
+ *
+ * Current time is: + *
+ * Blood 1 : {{blood_1}} + * Blood 2 : {{blood_2}} + * + * + * + *
+ *
+ * + *
+ *
+ */ function interval(fn, delay, count, invokeApply) { var hasParams = arguments.length > 4, args = hasParams ? sliceArgs(arguments, 4) : [], @@ -13389,16 +13634,16 @@ function $IntervalProvider() { } - /** - * @ngdoc method - * @name $interval#cancel - * - * @description - * Cancels a task associated with the `promise`. - * - * @param {Promise=} promise returned by the `$interval` function. - * @returns {boolean} Returns `true` if the task was successfully canceled. - */ + /** + * @ngdoc method + * @name $interval#cancel + * + * @description + * Cancels a task associated with the `promise`. + * + * @param {Promise=} promise returned by the `$interval` function. + * @returns {boolean} Returns `true` if the task was successfully canceled. + */ interval.cancel = function(promise) { if (promise && promise.$$intervalId in intervals) { // Interval cancels should not report as unhandled promise. @@ -13501,7 +13746,7 @@ var $jsonpCallbacksProvider = /** @this */ function() { * @name $locale * * @description - * $locale service provides localization rules for various Angular components. As of right now the + * $locale service provides localization rules for various AngularJS components. As of right now the * only public api is: * * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`) @@ -13523,7 +13768,23 @@ function encodePath(path) { i = segments.length; while (i--) { - segments[i] = encodeUriSegment(segments[i]); + // decode forward slashes to prevent them from being double encoded + segments[i] = encodeUriSegment(segments[i].replace(/%2F/g, '/')); + } + + return segments.join('/'); +} + +function decodePath(path, html5Mode) { + var segments = path.split('/'), + i = segments.length; + + while (i--) { + segments[i] = decodeURIComponent(segments[i]); + if (html5Mode) { + // encode forward slashes to prevent them from being mistaken for path separators + segments[i] = segments[i].replace(/\//g, '%2F'); + } } return segments.join('/'); @@ -13538,7 +13799,7 @@ function parseAbsoluteUrl(absoluteUrl, locationObj) { } var DOUBLE_SLASH_REGEX = /^\s*[\\/]{2,}/; -function parseAppUrl(url, locationObj) { +function parseAppUrl(url, locationObj, html5Mode) { if (DOUBLE_SLASH_REGEX.test(url)) { throw $locationMinErr('badpath', 'Invalid url "{0}".', url); @@ -13549,8 +13810,8 @@ function parseAppUrl(url, locationObj) { url = '/' + url; } var match = urlResolve(url); - locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ? - match.pathname.substring(1) : match.pathname); + var path = prefixed && match.pathname.charAt(0) === '/' ? match.pathname.substring(1) : match.pathname; + locationObj.$$path = decodePath(path, html5Mode); locationObj.$$search = parseKeyValue(match.search); locationObj.$$hash = decodeURIComponent(match.hash); @@ -13625,7 +13886,7 @@ function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) { appBaseNoFile); } - parseAppUrl(pathUrl, this); + parseAppUrl(pathUrl, this, true); if (!this.$$path) { this.$$path = '/'; @@ -13728,7 +13989,7 @@ function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) { } } - parseAppUrl(withoutHashUrl, this); + parseAppUrl(withoutHashUrl, this, false); this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase); @@ -13742,7 +14003,7 @@ function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) { * * a.setAttribute('href', '/foo') * * a.pathname === '/C:/foo' //true * - * Inside of Angular, we're always using pathnames that + * Inside of AngularJS, we're always using pathnames that * do not include drive names for routing. */ function removeWindowsDriveName(path, url, base) { @@ -13949,7 +14210,7 @@ var locationPrototype = { * * Return host of current URL. * - * Note: compared to the non-angular version `location.host` which returns `hostname:port`, this returns the `hostname` portion only. + * Note: compared to the non-AngularJS version `location.host` which returns `hostname:port`, this returns the `hostname` portion only. * * * ```js @@ -14422,7 +14683,7 @@ function $LocationProvider() { if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) { if ($location.$$parseLinkUrl(absHref, relHref)) { - // We do a preventDefault for all urls that are part of the angular application, + // We do a preventDefault for all urls that are part of the AngularJS application, // in html5mode and also without, so that we are able to abort navigation without // getting double entries in the location history. event.preventDefault(); @@ -14718,12 +14979,12 @@ var $parseMinErr = minErr('$parse'); var objectValueOf = {}.constructor.prototype.valueOf; -// Sandboxing Angular Expressions +// Sandboxing AngularJS Expressions // ------------------------------ -// Angular expressions are no longer sandboxed. So it is now even easier to access arbitrary JS code by +// AngularJS expressions are no longer sandboxed. So it is now even easier to access arbitrary JS code by // various means such as obtaining a reference to native JS functions like the Function constructor. // -// As an example, consider the following Angular expression: +// As an example, consider the following AngularJS expression: // // {}.toString.constructor('alert("evil JS code")') // @@ -16347,11 +16608,26 @@ Parser.prototype = { constructor: Parser, parse: function(text) { - var ast = this.ast.ast(text); - var fn = this.astCompiler.compile(ast); - fn.literal = isLiteral(ast); - fn.constant = isConstant(ast); + var ast = this.getAst(text); + var fn = this.astCompiler.compile(ast.ast); + fn.literal = isLiteral(ast.ast); + fn.constant = isConstant(ast.ast); + fn.oneTime = ast.oneTime; return fn; + }, + + getAst: function(exp) { + var oneTime = false; + exp = exp.trim(); + + if (exp.charAt(0) === ':' && exp.charAt(1) === ':') { + oneTime = true; + exp = exp.substring(2); + } + return { + ast: this.ast.ast(exp), + oneTime: oneTime + }; } }; @@ -16368,15 +16644,15 @@ function getValueOf(value) { * * @description * - * Converts Angular {@link guide/expression expression} into a function. + * Converts AngularJS {@link guide/expression expression} into a function. * * ```js * var getter = $parse('user.name'); * var setter = getter.assign; - * var context = {user:{name:'angular'}}; + * var context = {user:{name:'AngularJS'}}; * var locals = {user:{name:'local'}}; * - * expect(getter(context)).toEqual('angular'); + * expect(getter(context)).toEqual('AngularJS'); * setter(context, 'newValue'); * expect(context.user.name).toEqual('newValue'); * expect(getter(context, locals)).toEqual('local'); @@ -16442,7 +16718,7 @@ function $ParseProvider() { * * @description * - * Allows defining the set of characters that are allowed in Angular expressions. The function + * Allows defining the set of characters that are allowed in AngularJS expressions. The function * `identifierStart` will get called to know if a given character is a valid character to be the * first character for an identifier. The function `identifierContinue` will get called to know if * a given character is a valid character to be a follow-up identifier character. The functions @@ -16474,10 +16750,11 @@ function $ParseProvider() { isIdentifierStart: isFunction(identStart) && identStart, isIdentifierContinue: isFunction(identContinue) && identContinue }; + $parse.$$getAst = $$getAst; return $parse; function $parse(exp, interceptorFn) { - var parsedExpression, oneTime, cacheKey; + var parsedExpression, cacheKey; switch (typeof exp) { case 'string': @@ -16487,16 +16764,12 @@ function $ParseProvider() { parsedExpression = cache[cacheKey]; if (!parsedExpression) { - if (exp.charAt(0) === ':' && exp.charAt(1) === ':') { - oneTime = true; - exp = exp.substring(2); - } var lexer = new Lexer($parseOptions); var parser = new Parser(lexer, $filter, $parseOptions); parsedExpression = parser.parse(exp); if (parsedExpression.constant) { parsedExpression.$$watchDelegate = constantWatchDelegate; - } else if (oneTime) { + } else if (parsedExpression.oneTime) { parsedExpression.$$watchDelegate = parsedExpression.literal ? oneTimeLiteralWatchDelegate : oneTimeWatchDelegate; } else if (parsedExpression.inputs) { @@ -16514,6 +16787,12 @@ function $ParseProvider() { } } + function $$getAst(exp) { + var lexer = new Lexer($parseOptions); + var parser = new Parser(lexer, $filter, $parseOptions); + return parser.getAst(exp).ast; + } + function expressionInputDirtyCheck(newValue, oldValueOfValue, compareObjectIdentity) { if (newValue == null || oldValueOfValue == null) { // null/undefined @@ -16707,7 +16986,7 @@ function $ParseProvider() { * $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 (ES2015) promises to some degree. * - * # $q constructor + * ## $q constructor * * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver` * function as the first argument. This is similar to the native Promise implementation from ES6, @@ -16795,7 +17074,7 @@ function $ParseProvider() { * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the * section on serial or parallel joining of promises. * - * # The Deferred API + * ## The Deferred API * * A new instance of deferred is constructed by calling `$q.defer()`. * @@ -16817,7 +17096,7 @@ function $ParseProvider() { * - promise – `{Promise}` – promise object associated with this deferred. * * - * # The Promise API + * ## The Promise API * * A new promise instance is created when a deferred instance is created and can be retrieved by * calling `deferred.promise`. @@ -16849,7 +17128,7 @@ function $ParseProvider() { * specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for * more information. * - * # Chaining promises + * ## Chaining promises * * Because calling the `then` method of a promise returns a new derived promise, it is easily * possible to create a chain of promises: @@ -16869,17 +17148,17 @@ function $ParseProvider() { * $http's response interceptors. * * - * # Differences between Kris Kowal's Q and $q + * ## Differences between Kris Kowal's Q and $q * * There are two main differences: * * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation - * mechanism in angular, which means faster propagation of resolution or rejection into your + * mechanism in AngularJS, which means faster propagation of resolution or rejection into your * models and avoiding unnecessary browser repaints, which would result in flickering UI. * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains * all the important functionality needed for common async tasks. * - * # Testing + * ## Testing * * ```js * it('should simulate promise', inject(function($q, $rootScope) { @@ -17056,6 +17335,10 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) { } } catch (e) { rejectPromise(promise, e); + // This error is explicitly marked for being passed to the $exceptionHandler + if (e && e.$$passToExceptionHandler === true) { + exceptionHandler(e); + } } } } finally { @@ -17496,6 +17779,7 @@ function $RootScopeProvider() { this.$$watchersCount = 0; this.$id = nextUid(); this.$$ChildScope = null; + this.$$suspended = false; } ChildScope.prototype = parent; return ChildScope; @@ -17548,7 +17832,7 @@ function $RootScopeProvider() { * an in-depth introduction and usage examples. * * - * # Inheritance + * ## Inheritance * A scope can inherit from a parent scope, as in this example: * ```js var parent = $rootScope; @@ -17583,6 +17867,7 @@ function $RootScopeProvider() { this.$$childHead = this.$$childTail = null; this.$root = this; this.$$destroyed = false; + this.$$suspended = false; this.$$listeners = {}; this.$$listenerCount = {}; this.$$watchersCount = 0; @@ -17723,7 +18008,7 @@ function $RootScopeProvider() { * * * - * # Example + * @example * ```js // let's assume that scope was dependency injected as the $rootScope var scope = $rootScope; @@ -17799,14 +18084,15 @@ function $RootScopeProvider() { */ $watch: function(watchExp, listener, objectEquality, prettyPrintExpression) { var get = $parse(watchExp); + var fn = isFunction(listener) ? listener : noop; if (get.$$watchDelegate) { - return get.$$watchDelegate(this, listener, objectEquality, get, watchExp); + return get.$$watchDelegate(this, fn, objectEquality, get, watchExp); } var scope = this, array = scope.$$watchers, watcher = { - fn: listener, + fn: fn, last: initWatchVal, get: get, exp: prettyPrintExpression || watchExp, @@ -17815,10 +18101,6 @@ function $RootScopeProvider() { lastDirtyWatch = null; - if (!isFunction(listener)) { - watcher.fn = noop; - } - if (!array) { array = scope.$$watchers = []; array.$$digestWatchIndex = -1; @@ -17974,7 +18256,7 @@ function $RootScopeProvider() { * adding, removing, and moving items belonging to an object or array. * * - * # Example + * @example * ```js $scope.names = ['igor', 'matias', 'misko', 'james']; $scope.dataCount = 4; @@ -18172,7 +18454,7 @@ function $RootScopeProvider() { * * In unit tests, you may need to call `$digest()` to simulate the scope life cycle. * - * # Example + * @example * ```js var scope = ...; scope.name = 'misko'; @@ -18240,7 +18522,7 @@ function $RootScopeProvider() { traverseScopesLoop: do { // "traverse the scopes" loop - if ((watchers = current.$$watchers)) { + if ((watchers = !current.$$suspended && current.$$watchers)) { // process our watches watchers.$$digestWatchIndex = watchers.length; while (watchers.$$digestWatchIndex--) { @@ -18284,7 +18566,9 @@ function $RootScopeProvider() { // Insanity Warning: scope depth-first traversal // yes, this code is a bit crazy, but it works and we have tests to prove it! // this piece should be kept in sync with the traversal in $broadcast - if (!(next = ((current.$$watchersCount && current.$$childHead) || + // (though it differs due to having the extra check for $$suspended and does not + // check $$listenerCount) + if (!(next = ((!current.$$suspended && current.$$watchersCount && current.$$childHead) || (current !== target && current.$$nextSibling)))) { while (current !== target && !(next = current.$$nextSibling)) { current = current.$parent; @@ -18321,6 +18605,95 @@ function $RootScopeProvider() { $browser.$$checkUrlChange(); }, + /** + * @ngdoc method + * @name $rootScope.Scope#$suspend + * @kind function + * + * @description + * Suspend watchers of this scope subtree so that they will not be invoked during digest. + * + * This can be used to optimize your application when you know that running those watchers + * is redundant. + * + * **Warning** + * + * Suspending scopes from the digest cycle can have unwanted and difficult to debug results. + * Only use this approach if you are confident that you know what you are doing and have + * ample tests to ensure that bindings get updated as you expect. + * + * Some of the things to consider are: + * + * * Any external event on a directive/component will not trigger a digest while the hosting + * scope is suspended - even if the event handler calls `$apply()` or `$rootScope.$digest()`. + * * Transcluded content exists on a scope that inherits from outside a directive but exists + * as a child of the directive's containing scope. If the containing scope is suspended the + * transcluded scope will also be suspended, even if the scope from which the transcluded + * scope inherits is not suspended. + * * Multiple directives trying to manage the suspended status of a scope can confuse each other: + * * A call to `$suspend()` on an already suspended scope is a no-op. + * * A call to `$resume()` on a non-suspended scope is a no-op. + * * If two directives suspend a scope, then one of them resumes the scope, the scope will no + * longer be suspended. This could result in the other directive believing a scope to be + * suspended when it is not. + * * If a parent scope is suspended then all its descendants will be also excluded from future + * digests whether or not they have been suspended themselves. Note that this also applies to + * isolate child scopes. + * * Calling `$digest()` directly on a descendant of a suspended scope will still run the watchers + * for that scope and its descendants. When digesting we only check whether the current scope is + * locally suspended, rather than checking whether it has a suspended ancestor. + * * Calling `$resume()` on a scope that has a suspended ancestor will not cause the scope to be + * included in future digests until all its ancestors have been resumed. + * * Resolved promises, e.g. from explicit `$q` deferreds and `$http` calls, trigger `$apply()` + * against the `$rootScope` and so will still trigger a global digest even if the promise was + * initiated by a component that lives on a suspended scope. + */ + $suspend: function() { + this.$$suspended = true; + }, + + /** + * @ngdoc method + * @name $rootScope.Scope#$isSuspended + * @kind function + * + * @description + * Call this method to determine if this scope has been explicitly suspended. It will not + * tell you whether an ancestor has been suspended. + * To determine if this scope will be excluded from a digest triggered at the $rootScope, + * for example, you must check all its ancestors: + * + * ``` + * function isExcludedFromDigest(scope) { + * while(scope) { + * if (scope.$isSuspended()) return true; + * scope = scope.$parent; + * } + * return false; + * ``` + * + * Be aware that a scope may not be included in digests if it has a suspended ancestor, + * even if `$isSuspended()` returns false. + * + * @returns true if the current scope has been suspended. + */ + $isSuspended: function() { + return this.$$suspended; + }, + + /** + * @ngdoc method + * @name $rootScope.Scope#$resume + * @kind function + * + * @description + * Resume watchers of this scope subtree in case it was suspended. + * + * See {@link $rootScope.Scope#$suspend} for information about the dangers of using this approach. + */ + $resume: function() { + this.$$suspended = false; + }, /** * @ngdoc event @@ -18398,10 +18771,10 @@ function $RootScopeProvider() { * * @description * Executes the `expression` on the current scope and returns the result. Any exceptions in - * the expression are propagated (uncaught). This is useful when evaluating Angular + * the expression are propagated (uncaught). This is useful when evaluating AngularJS * expressions. * - * # Example + * @example * ```js var scope = ng.$rootScope.Scope(); scope.a = 1; @@ -18411,7 +18784,7 @@ function $RootScopeProvider() { expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3); * ``` * - * @param {(string|function())=} expression An angular expression to be executed. + * @param {(string|function())=} expression An AngularJS expression to be executed. * * - `string`: execute using the rules as defined in {@link guide/expression expression}. * - `function(scope)`: execute the function with the current `scope` parameter. @@ -18446,7 +18819,7 @@ function $RootScopeProvider() { * will be scheduled. However, it is encouraged to always call code that changes the model * from within an `$apply` call. That includes code evaluated via `$evalAsync`. * - * @param {(string|function())=} expression An angular expression to be executed. + * @param {(string|function())=} expression An AngularJS expression to be executed. * * - `string`: execute using the rules as defined in {@link guide/expression expression}. * - `function(scope)`: execute the function with the current `scope` parameter. @@ -18477,15 +18850,14 @@ function $RootScopeProvider() { * @kind function * * @description - * `$apply()` is used to execute an expression in angular from outside of the angular + * `$apply()` is used to execute an expression in AngularJS from outside of the AngularJS * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries). - * Because we are calling into the angular framework we need to perform proper scope life + * Because we are calling into the AngularJS framework we need to perform proper scope life * cycle of {@link ng.$exceptionHandler exception handling}, * {@link ng.$rootScope.Scope#$digest executing watches}. * - * ## Life cycle + * **Life cycle: Pseudo-Code of `$apply()`** * - * # Pseudo-Code of `$apply()` * ```js function $apply(expr) { try { @@ -18509,7 +18881,7 @@ function $RootScopeProvider() { * expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method. * * - * @param {(string|function())=} exp An angular expression to be executed. + * @param {(string|function())=} exp An AngularJS expression to be executed. * * - `string`: execute using the rules as defined in {@link guide/expression expression}. * - `function(scope)`: execute the function with current `scope` parameter. @@ -18549,7 +18921,7 @@ function $RootScopeProvider() { * This can be used to queue up multiple expressions which need to be evaluated in the same * digest. * - * @param {(string|function())=} exp An angular expression to be executed. + * @param {(string|function())=} exp An AngularJS expression to be executed. * * - `string`: execute using the rules as defined in {@link guide/expression expression}. * - `function(scope)`: execute the function with current `scope` parameter. @@ -18613,7 +18985,10 @@ function $RootScopeProvider() { return function() { var indexOfListener = namedListeners.indexOf(listener); if (indexOfListener !== -1) { - namedListeners[indexOfListener] = null; + // Use delete in the hope of the browser deallocating the memory for the array entry, + // while not shifting the array indexes of other listeners. + // See issue https://github.com/angular/angular.js/issues/16135 + delete namedListeners[indexOfListener]; decrementListenerCount(self, 1, name); } }; @@ -18680,8 +19055,7 @@ function $RootScopeProvider() { } //if any listener on the current scope stops propagation, prevent bubbling if (stopPropagation) { - event.currentScope = null; - return event; + break; } //traverse upwards scope = scope.$parent; @@ -18755,7 +19129,8 @@ function $RootScopeProvider() { // Insanity Warning: scope depth-first traversal // yes, this code is a bit crazy, but it works and we have tests to prove it! // this piece should be kept in sync with the traversal in $digest - // (though it differs due to having the extra check for $$listenerCount) + // (though it differs due to having the extra check for $$listenerCount and + // does not check $$suspended) if (!(next = ((current.$$listenerCount[name] && current.$$childHead) || (current !== target && current.$$nextSibling)))) { while (current !== target && !(next = current.$$nextSibling)) { @@ -18841,7 +19216,7 @@ function $RootScopeProvider() { * @name $rootElement * * @description - * The root element of Angular application. This is either the element where {@link + * The root element of AngularJS application. This is either the element where {@link * ng.directive:ngApp ngApp} was declared or the element passed into * {@link angular.bootstrap}. The element represents the root element of application. It is also the * location where the application's {@link auto.$injector $injector} service gets @@ -18857,7 +19232,7 @@ function $RootScopeProvider() { * Private service to sanitize uris for links and images. Used by $compile and $sanitize. */ function $$SanitizeUriProvider() { - var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/, + var aHrefSanitizationWhitelist = /^\s*(https?|s?ftp|mailto|tel|file):/, imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/; /** @@ -18913,7 +19288,7 @@ function $$SanitizeUriProvider() { return function sanitizeUri(uri, isImage) { var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist; var normalizedVal; - normalizedVal = urlResolve(uri).href; + normalizedVal = urlResolve(uri && uri.trim()).href; if (normalizedVal !== '' && !normalizedVal.match(regex)) { return 'unsafe:' + normalizedVal; } @@ -19058,7 +19433,7 @@ function adjustMatchers(matchers) { * and * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}, * - * For the general details about this service in Angular, read the main page for {@link ng.$sce + * For the general details about this service in AngularJS, read the main page for {@link ng.$sce * Strict Contextual Escaping (SCE)}. * * **Example**: Consider the following case. @@ -19385,13 +19760,13 @@ function $SceDelegateProvider() { * * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS. * - * # Strict Contextual Escaping + * ## Strict Contextual Escaping * * Strict Contextual Escaping (SCE) is a mode in which AngularJS constrains bindings to only render * trusted values. Its goal is to assist in writing code in a way that (a) is secure by default, and * (b) makes auditing for security vulnerabilities such as XSS, clickjacking, etc. a lot easier. * - * ## Overview + * ### Overview * * To systematically block XSS security bugs, AngularJS treats all values as untrusted by default in * HTML or sensitive URL bindings. When binding untrusted values, AngularJS will automatically @@ -19407,7 +19782,7 @@ function $SceDelegateProvider() { * * As of version 1.2, AngularJS ships with SCE enabled by default. * - * ## In practice + * ### In practice * * Here's an example of a binding in a privileged context: * @@ -19444,7 +19819,7 @@ function $SceDelegateProvider() { * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to * build the trusted versions of your values. * - * ## How does it work? + * ### How does it work? * * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted * $sce.getTrusted(context, value)} rather than to the value directly. Think of this function as @@ -19468,12 +19843,12 @@ function $SceDelegateProvider() { * }]; * ``` * - * ## Impact on loading templates + * ### Impact on loading templates * * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as * `templateUrl`'s specified by {@link guide/directive directives}. * - * By default, Angular only loads templates from the same domain and protocol as the application + * By default, AngularJS only loads templates from the same domain and protocol as the application * document. This is done by calling {@link ng.$sce#getTrustedResourceUrl * $sce.getTrustedResourceUrl} on the template URL. To load templates from other domains and/or * protocols, you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist @@ -19488,7 +19863,7 @@ function $SceDelegateProvider() { * won't work on all browsers. Also, loading templates from `file://` URL does not work on some * browsers. * - * ## This feels like too much overhead + * ### This feels like too much overhead * * It's important to remember that SCE only applies to interpolation expressions. * @@ -19512,7 +19887,7 @@ function $SceDelegateProvider() { * security onto an application later. * * - * ## What trusted context types are supported? + * ### What trusted context types are supported? * * | Context | Notes | * |---------------------|----------------| @@ -19528,7 +19903,7 @@ function $SceDelegateProvider() { * in AngularJS currently, so their corresponding `$sce.trustAs` functions aren't useful yet. This * might evolve. * - * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} + * ### Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} * * Each element in these arrays must be one of the following: * @@ -19575,7 +19950,7 @@ function $SceDelegateProvider() { * * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example. * - * ## Show me an example using SCE. + * ### Show me an example using SCE. * * * @@ -19770,7 +20145,7 @@ function $SceProvider() { * @name $sce#parseAs * * @description - * Converts Angular {@link guide/expression expression} into a function. This is like {@link + * Converts AngularJS {@link guide/expression expression} into a function. This is like {@link * ng.$parse $parse} and is identical when the expression is a literal constant. Otherwise, it * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*, * *result*)} @@ -20205,6 +20580,12 @@ function $TemplateRequestProvider() { * If you want to pass custom options to the `$http` service, such as setting the Accept header you * can configure this via {@link $templateRequestProvider#httpOptions}. * + * `$templateRequest` is used internally by {@link $compile}, {@link ngRoute.$route}, and directives such + * as {@link ngInclude} to download and cache templates. + * + * 3rd party modules should use `$templateRequest` if their services or directives are loading + * templates. + * * @param {string|TrustedResourceUrl} tpl The HTTP request template URL * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty * @@ -20220,7 +20601,7 @@ function $TemplateRequestProvider() { // We consider the template cache holds only trusted templates, so // there's no need to go through whitelisting again for keys that already - // are included in there. This also makes Angular accept any script + // are included in there. This also makes AngularJS accept any script // directive, no matter its name. However, we still need to unwrap trusted // types. if (!isString(tpl) || isUndefined($templateCache.get(tpl))) { @@ -20393,35 +20774,35 @@ function $TimeoutProvider() { var deferreds = {}; - /** - * @ngdoc service - * @name $timeout - * - * @description - * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch - * block and delegates any exceptions to - * {@link ng.$exceptionHandler $exceptionHandler} service. - * - * The return value of calling `$timeout` is a promise, which will be resolved when - * the delay has passed and the timeout function, if provided, is executed. - * - * To cancel a timeout request, call `$timeout.cancel(promise)`. - * - * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to - * synchronously flush the queue of deferred functions. - * - * If you only want a promise that will be resolved after some specified delay - * then you can call `$timeout` without the `fn` function. - * - * @param {function()=} fn A function, whose execution should be delayed. - * @param {number=} [delay=0] Delay in milliseconds. - * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise - * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block. - * @param {...*=} Pass additional parameters to the executed function. - * @returns {Promise} Promise that will be resolved when the timeout is reached. The promise - * will be resolved with the return value of the `fn` function. - * - */ + /** + * @ngdoc service + * @name $timeout + * + * @description + * AngularJS's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch + * block and delegates any exceptions to + * {@link ng.$exceptionHandler $exceptionHandler} service. + * + * The return value of calling `$timeout` is a promise, which will be resolved when + * the delay has passed and the timeout function, if provided, is executed. + * + * To cancel a timeout request, call `$timeout.cancel(promise)`. + * + * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to + * synchronously flush the queue of deferred functions. + * + * If you only want a promise that will be resolved after some specified delay + * then you can call `$timeout` without the `fn` function. + * + * @param {function()=} fn A function, whose execution should be delayed. + * @param {number=} [delay=0] Delay in milliseconds. + * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise + * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block. + * @param {...*=} Pass additional parameters to the executed function. + * @returns {Promise} Promise that will be resolved when the timeout is reached. The promise + * will be resolved with the return value of the `fn` function. + * + */ function timeout(fn, delay, invokeApply) { if (!isFunction(fn)) { invokeApply = delay; @@ -20455,18 +20836,18 @@ function $TimeoutProvider() { } - /** - * @ngdoc method - * @name $timeout#cancel - * - * @description - * Cancels a task associated with the `promise`. As a result of this, the promise will be - * resolved with a rejection. - * - * @param {Promise=} promise Promise returned by the `$timeout` function. - * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully - * canceled. - */ + /** + * @ngdoc method + * @name $timeout#cancel + * + * @description + * Cancels a task associated with the `promise`. As a result of this, the promise will be + * resolved with a rejection. + * + * @param {Promise=} promise Promise returned by the `$timeout` function. + * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully + * canceled. + */ timeout.cancel = function(promise) { if (promise && promise.$$timeoutId in deferreds) { // Timeout cancels should not report an unhandled promise. @@ -20522,7 +20903,8 @@ var originUrl = urlResolve(window.location.href); * http://james.padolsey.com/javascript/parsing-urls-with-the-dom/ * * @kind function - * @param {string} url The URL to be parsed. + * @param {string|object} url The URL to be parsed. If `url` is not a string, it will be returned + * unchanged. * @description Normalizes and parses a URL. * @returns {object} Returns the normalized URL as a dictionary. * @@ -20539,6 +20921,8 @@ var originUrl = urlResolve(window.location.href); * */ function urlResolve(url) { + if (!isString(url)) return url; + var href = url; // Support: IE 9-11 only @@ -20567,16 +20951,61 @@ function urlResolve(url) { } /** - * Parse a request URL and determine whether this is a same-origin request as the application document. + * Parse a request URL and determine whether this is a same-origin request as the application + * document. * * @param {string|object} requestUrl The url of the request as a string that will be resolved * or a parsed URL object. * @returns {boolean} Whether the request is for the same origin as the application document. */ function urlIsSameOrigin(requestUrl) { - var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl; - return (parsed.protocol === originUrl.protocol && - parsed.host === originUrl.host); + return urlsAreSameOrigin(requestUrl, originUrl); +} + +/** + * Create a function that can check a URL's origin against a list of allowed/whitelisted origins. + * The current location's origin is implicitly trusted. + * + * @param {string[]} whitelistedOriginUrls - A list of URLs (strings), whose origins are trusted. + * + * @returns {Function} - A function that receives a URL (string or parsed URL object) and returns + * whether it is of an allowed origin. + */ +function urlIsAllowedOriginFactory(whitelistedOriginUrls) { + var parsedAllowedOriginUrls = [originUrl].concat(whitelistedOriginUrls.map(urlResolve)); + + /** + * Check whether the specified URL (string or parsed URL object) has an origin that is allowed + * based on a list of whitelisted-origin URLs. The current location's origin is implicitly + * trusted. + * + * @param {string|Object} requestUrl - The URL to be checked (provided as a string that will be + * resolved or a parsed URL object). + * + * @returns {boolean} - Whether the specified URL is of an allowed origin. + */ + return function urlIsAllowedOrigin(requestUrl) { + var parsedUrl = urlResolve(requestUrl); + return parsedAllowedOriginUrls.some(urlsAreSameOrigin.bind(null, parsedUrl)); + }; +} + +/** + * Determine if two URLs share the same origin. + * + * @param {string|Object} url1 - First URL to compare as a string or a normalized URL in the form of + * a dictionary object returned by `urlResolve()`. + * @param {string|object} url2 - Second URL to compare as a string or a normalized URL in the form + * of a dictionary object returned by `urlResolve()`. + * + * @returns {boolean} - True if both URLs have the same origin, and false otherwise. + */ +function urlsAreSameOrigin(url1, url2) { + url1 = urlResolve(url1); + url2 = urlResolve(url2); + + return (url1.protocol === url2.protocol && + url1.host === url2.host); } /** @@ -20587,7 +21016,7 @@ function urlIsSameOrigin(requestUrl) { * @description * A reference to the browser's `window` object. While `window` * is globally available in JavaScript, it causes testability problems, because - * it is a global variable. In angular we always refer to it through the + * it is a global variable. In AngularJS we always refer to it through the * `$window` service, so it may be overridden, removed or mocked for testing. * * Expressions, like the one defined for the `ngClick` directive in the example @@ -20710,7 +21139,7 @@ function $$CookieReaderProvider() { * annotated with dependencies and is responsible for creating a filter function. * *
- * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`. + * **Note:** Filter names must be valid AngularJS {@link expression} identifiers, such as `uppercase` or `orderBy`. * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores * (`myapp_subsection_filterx`). @@ -20753,8 +21182,8 @@ function $$CookieReaderProvider() { * ``` * * - * 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. + * For more information about how AngularJS filters work, and how to create your own filters, see + * {@link guide/filter Filters} in the AngularJS Developer Guide. */ /** @@ -20764,7 +21193,7 @@ function $$CookieReaderProvider() { * @description * Filters are used for formatting data displayed to the user. * - * They can be used in view templates, controllers or services.Angular comes + * They can be used in view templates, controllers or services. AngularJS comes * with a collection of [built-in filters](api/ng/filter), but it is easy to * define your own as well. * @@ -20806,7 +21235,7 @@ function $FilterProvider($provide) { * the keys are the filter names and the values are the filter factories. * *
- * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`. + * **Note:** Filter names must be valid AngularJS {@link expression} identifiers, such as `uppercase` or `orderBy`. * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores * (`myapp_subsection_filterx`). @@ -21194,11 +21623,14 @@ function currencyFilter($locale) { fractionSize = formats.PATTERNS[1].maxFrac; } + // If the currency symbol is empty, trim whitespace around the symbol + var currencySymbolRe = !currencySymbol ? /\s*\u00A4\s*/g : /\u00A4/g; + // if null or undefined pass it through return (amount == null) ? amount : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize). - replace(/\u00A4/g, currencySymbol); + replace(currencySymbolRe, currencySymbol); }; } @@ -22091,7 +22523,7 @@ function sliceFn(input, begin, end) { * * - `Function`: A getter function. This function will be called with each item as argument and * the return value will be used for sorting. - * - `string`: An Angular expression. This expression will be evaluated against each item and the + * - `string`: An AngularJS expression. This expression will be evaluated against each item and the * result will be used for sorting. For example, use `'label'` to sort by a property called * `label` or `'label.substring(0, 3)'` to sort by the first 3 characters of the `label` * property.
@@ -22737,10 +23169,10 @@ var htmlAnchorDirective = valueFn({ * @priority 99 * * @description - * Using Angular markup like `{{hash}}` in an href attribute will + * Using AngularJS markup like `{{hash}}` in an href attribute will * make the link go to the wrong URL if the user clicks it before - * Angular has a chance to replace the `{{hash}}` markup with its - * value. Until Angular replaces the markup the link will be broken + * AngularJS has a chance to replace the `{{hash}}` markup with its + * value. Until AngularJS replaces the markup the link will be broken * and will most likely return a 404 error. The `ngHref` directive * solves this problem. * @@ -22788,7 +23220,7 @@ var htmlAnchorDirective = valueFn({ element(by.id('link-3')).click(); - // At this point, we navigate away from an Angular page, so we need + // At this point, we navigate away from an AngularJS page, so we need // to use browser.driver to get the base webdriver. browser.wait(function() { @@ -22817,7 +23249,7 @@ var htmlAnchorDirective = valueFn({ element(by.id('link-6')).click(); - // At this point, we navigate away from an Angular page, so we need + // At this point, we navigate away from an AngularJS page, so we need // to use browser.driver to get the base webdriver. browser.wait(function() { return browser.driver.getCurrentUrl().then(function(url) { @@ -22836,9 +23268,9 @@ var htmlAnchorDirective = valueFn({ * @priority 99 * * @description - * Using Angular markup like `{{hash}}` in a `src` attribute doesn't + * Using AngularJS markup like `{{hash}}` in a `src` attribute doesn't * work right: The browser will fetch from the URL with the literal - * text `{{hash}}` until Angular replaces the expression inside + * text `{{hash}}` until AngularJS replaces the expression inside * `{{hash}}`. The `ngSrc` directive solves this problem. * * The buggy way to write it: @@ -22862,9 +23294,9 @@ var htmlAnchorDirective = valueFn({ * @priority 99 * * @description - * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't + * Using AngularJS markup like `{{hash}}` in a `srcset` attribute doesn't * work right: The browser will fetch from the URL with the literal - * text `{{hash}}` until Angular replaces the expression inside + * text `{{hash}}` until AngularJS replaces the expression inside * `{{hash}}`. The `ngSrcset` directive solves this problem. * * The buggy way to write it: @@ -22935,14 +23367,14 @@ var htmlAnchorDirective = valueFn({ * @example -
- +
+
it('should check both checkBoxes', function() { - expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy(); - element(by.model('master')).click(); - expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy(); + expect(element(by.id('checkFollower')).getAttribute('checked')).toBeFalsy(); + element(by.model('leader')).click(); + expect(element(by.id('checkFollower')).getAttribute('checked')).toBeTruthy(); });
@@ -22972,7 +23404,7 @@ var htmlAnchorDirective = valueFn({
- +
it('should toggle readonly attr', function() { @@ -23537,15 +23969,15 @@ addSetValidityMethod({ * If the `name` attribute is specified, the form controller is published onto the current scope under * this name. * - * # Alias: {@link ng.directive:ngForm `ngForm`} + * ## Alias: {@link ng.directive:ngForm `ngForm`} * - * In Angular, forms can be nested. This means that the outer form is valid when all of the child + * In AngularJS, forms can be nested. This means that the outer form is valid when all of the child * forms are valid as well. However, browsers do not allow nesting of `` elements, so - * Angular provides the {@link ng.directive:ngForm `ngForm`} directive, which behaves identically to + * AngularJS provides the {@link ng.directive:ngForm `ngForm`} directive, which behaves identically to * `form` but can be nested. Nested forms can be useful, for example, if the validity of a sub-group * of controls needs to be determined. * - * # CSS classes + * ## CSS classes * - `ng-valid` is set if the form is valid. * - `ng-invalid` is set if the form is invalid. * - `ng-pending` is set if the form is pending. @@ -23556,14 +23988,14 @@ addSetValidityMethod({ * Keep in mind that ngAnimate can detect each of these classes when added and removed. * * - * # Submitting a form and preventing the default action + * ## Submitting a form and preventing the default action * - * Since the role of forms in client-side Angular applications is different than in classical + * Since the role of forms in client-side AngularJS applications is different than in classical * roundtrip apps, it is desirable for the browser not to translate the form submission into a full * page reload that sends the data to the server. Instead some javascript logic should be triggered * to handle the form submission in an application-specific way. * - * For this reason, Angular prevents the default action (form submission to the server) unless the + * For this reason, AngularJS prevents the default action (form submission to the server) unless the * `` element has an `action` attribute specified. * * You can use one of the following two ways to specify what javascript method should be called when @@ -23589,8 +24021,7 @@ addSetValidityMethod({ * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit` * to have access to the updated model. * - * ## Animation Hooks - * + * @animations * Animations in ngForm are triggered when any of the associated CSS classes are added and removed. * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any * other validations that are performed within the form. Animations in ngForm are similar to how @@ -23902,10 +24333,10 @@ var inputType = { * @name input[text] * * @description - * Standard HTML text input with angular data binding, inherited by most of the `input` elements. + * Standard HTML text input with AngularJS data binding, inherited by most of the `input` elements. * * - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} required Adds `required` validation error key if the value is not entered. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to @@ -23920,7 +24351,7 @@ var inputType = { * that contains the regular expression body that will be converted to a regular expression * as in the ngPattern directive. * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue} - * does not match a RegExp found by evaluating the Angular expression given in the attribute value. + * does not match a RegExp found by evaluating the AngularJS expression given in the attribute value. * If the expression evaluates to a RegExp object, then this is used directly. * If the expression evaluates to a string, then it will be converted to a RegExp * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to @@ -23928,9 +24359,9 @@ var inputType = { * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to * start at the index of the last search's match, thus not taking the whole input value into * account. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * 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 AngularJS will not automatically trim the input. * This parameter is ignored for input[type=password] controls, which will never trim the * input. * @@ -24004,13 +24435,13 @@ var inputType = { * modern browsers do not yet support this input type, it is important to provide cues to users on the * expected input format via a placeholder or label. * - * The model must always be a Date object, otherwise Angular will throw an error. + * The model must always be a Date object, otherwise AngularJS will throw an error. * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. * * The timezone to be used to read/write the `Date` instance in the model can be defined using * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. * - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a * valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute @@ -24028,7 +24459,7 @@ var inputType = { * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * interaction with the input element. * * @example @@ -24106,13 +24537,13 @@ var inputType = { * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`. * - * The model must always be a Date object, otherwise Angular will throw an error. + * The model must always be a Date object, otherwise AngularJS will throw an error. * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. * * The timezone to be used to read/write the `Date` instance in the model can be defined using * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. * - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. * This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation @@ -24130,7 +24561,7 @@ var inputType = { * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * interaction with the input element. * * @example @@ -24209,13 +24640,13 @@ var inputType = { * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`. * - * The model must always be a Date object, otherwise Angular will throw an error. + * The model must always be a Date object, otherwise AngularJS will throw an error. * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. * * The timezone to be used to read/write the `Date` instance in the model can be defined using * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. * - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. * This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this @@ -24233,7 +24664,7 @@ var inputType = { * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * interaction with the input element. * * @example @@ -24311,13 +24742,13 @@ var inputType = { * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 * week format (yyyy-W##), for example: `2013-W02`. * - * The model must always be a Date object, otherwise Angular will throw an error. + * The model must always be a Date object, otherwise AngularJS will throw an error. * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. * * The timezone to be used to read/write the `Date` instance in the model can be defined using * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. * - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. * This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this @@ -24335,7 +24766,7 @@ var inputType = { * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * interaction with the input element. * * @example @@ -24413,7 +24844,7 @@ var inputType = { * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 * month format (yyyy-MM), for example: `2009-01`. * - * The model must always be a Date object, otherwise Angular will throw an error. + * The model must always be a Date object, otherwise AngularJS will throw an error. * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. * If the model is not set to the first of the month, the next view to model update will set it * to the first of the month. @@ -24421,7 +24852,7 @@ var inputType = { * The timezone to be used to read/write the `Date` instance in the model can be defined using * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. * - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. * This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this @@ -24440,7 +24871,7 @@ var inputType = { * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * interaction with the input element. * * @example @@ -24518,7 +24949,7 @@ var inputType = { * error if not a valid number. * *
- * The model must always be of type `number` otherwise Angular will throw an error. + * The model must always be of type `number` otherwise AngularJS will throw an error. * Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt} * error docs for more information and an example of how to convert your model if necessary. *
@@ -24533,7 +24964,7 @@ var inputType = { * will also be an empty string. * * - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. * Can be interpolated. @@ -24560,7 +24991,7 @@ var inputType = { * that contains the regular expression body that will be converted to a regular expression * as in the ngPattern directive. * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue} - * does not match a RegExp found by evaluating the Angular expression given in the attribute value. + * does not match a RegExp found by evaluating the AngularJS expression given in the attribute value. * If the expression evaluates to a RegExp object, then this is used directly. * If the expression evaluates to a string, then it will be converted to a RegExp * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to @@ -24568,7 +24999,7 @@ var inputType = { * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to * start at the index of the last search's match, thus not taking the whole input value into * account. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * interaction with the input element. * * @example @@ -24643,7 +25074,7 @@ var inputType = { * the built-in validators (see the {@link guide/forms Forms guide}) *
* - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @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=} ngRequired Adds `required` attribute and `required` validation constraint to @@ -24658,7 +25089,7 @@ var inputType = { * that contains the regular expression body that will be converted to a regular expression * as in the ngPattern directive. * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue} - * does not match a RegExp found by evaluating the Angular expression given in the attribute value. + * does not match a RegExp found by evaluating the AngularJS expression given in the attribute value. * If the expression evaluates to a RegExp object, then this is used directly. * If the expression evaluates to a string, then it will be converted to a RegExp * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to @@ -24666,7 +25097,7 @@ var inputType = { * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to * start at the index of the last search's match, thus not taking the whole input value into * account. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * interaction with the input element. * * @example @@ -24742,7 +25173,7 @@ var inputType = { * use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide}) *
* - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @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=} ngRequired Adds `required` attribute and `required` validation constraint to @@ -24757,7 +25188,7 @@ var inputType = { * that contains the regular expression body that will be converted to a regular expression * as in the ngPattern directive. * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue} - * does not match a RegExp found by evaluating the Angular expression given in the attribute value. + * does not match a RegExp found by evaluating the AngularJS expression given in the attribute value. * If the expression evaluates to a RegExp object, then this is used directly. * If the expression evaluates to a string, then it will be converted to a RegExp * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to @@ -24765,7 +25196,7 @@ var inputType = { * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to * start at the index of the last search's match, thus not taking the whole input value into * account. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * interaction with the input element. * * @example @@ -24833,14 +25264,41 @@ var inputType = { * @description * HTML radio button. * - * @param {string} ngModel Assignable angular expression to data-bind to. + * **Note:**
+ * All inputs controlled by {@link ngModel ngModel} (including those of type `radio`) will use the + * value of their `name` attribute to determine the property under which their + * {@link ngModel.NgModelController NgModelController} will be published on the parent + * {@link form.FormController FormController}. Thus, if you use the same `name` for multiple + * inputs of a form (e.g. a group of radio inputs), only _one_ `NgModelController` will be + * published on the parent `FormController` under that name. The rest of the controllers will + * continue to work as expected, but you won't be able to access them as properties on the parent + * `FormController`. + * + *
+ *

+ * In plain HTML forms, the `name` attribute is used to identify groups of radio inputs, so + * that the browser can manage their state (checked/unchecked) based on the state of other + * inputs in the same group. + *

+ *

+ * In AngularJS forms, this is not necessary. The input's state will be updated based on the + * value of the underlying model data. + *

+ *
+ * + *
+ * If you omit the `name` attribute on a radio input, `ngModel` will automatically assign it a + * unique name. + *
+ * + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @param {string} value The value to which the `ngModel` expression should be set when selected. * Note that `value` only supports `string` values, i.e. the scope model needs to be a string, * too. Use `ngValue` if you need complex models (`number`, `object`, ...). * @param {string=} name Property name of the form under which the control is published. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * interaction with the input element. - * @param {string} ngValue Angular expression to which `ngModel` will be be set when the radio + * @param {string} ngValue AngularJS expression to which `ngModel` will be be set when the radio * is selected. Should be used instead of the `value` attribute if you need * a non-string `ngModel` (`boolean`, `array`, ...). * @@ -24918,34 +25376,34 @@ var inputType = { * See the [HTML Spec on input[type=range]](https://www.w3.org/TR/html5/forms.html#range-state-(type=range)) * for more info. * - * This has the following consequences for Angular: + * This has the following consequences for AngularJS: * * Since the element value should always reflect the current model value, a range input * will set the bound ngModel expression to the value that the browser has set for the * input element. For example, in the following input ``, * if the application sets `model.value = null`, the browser will set the input to `'50'`. - * Angular will then set the model to `50`, to prevent input and model value being out of sync. + * AngularJS will then set the model to `50`, to prevent input and model value being out of sync. * * That means the model for range will immediately be set to `50` after `ngModel` has been * initialized. It also means a range input can never have the required error. * * This does not only affect changes to the model value, but also to the values of the `min`, * `max`, and `step` attributes. When these change in a way that will cause the browser to modify - * the input value, Angular will also update the model value. + * the input value, AngularJS will also update the model value. * * Automatic value adjustment also means that a range input element can never have the `required`, * `min`, or `max` errors. * * However, `step` is currently only fully implemented by Firefox. Other browsers have problems * when the step value changes dynamically - they do not adjust the element value correctly, but - * instead may set the `stepMismatch` error. If that's the case, the Angular will set the `step` + * instead may set the `stepMismatch` error. If that's the case, the AngularJS will set the `step` * error on the input, and set the model to `undefined`. * * Note that `input[range]` is not compatible with`ngMax`, `ngMin`, and `ngStep`, because they do * not set the `min` and `max` attributes, which means that the browser won't automatically adjust * the input value based on their values, and will always assume min = 0, max = 100, and step = 1. * - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {string=} min Sets the `min` validation to ensure that the value entered is greater * than `min`. Can be interpolated. @@ -24953,7 +25411,7 @@ var inputType = { * Can be interpolated. * @param {string=} step Sets the `step` validation to ensure that the value entered matches the `step` * Can be interpolated. - * @param {string=} ngChange Angular expression to be executed when the ngModel value changes due + * @param {string=} ngChange AngularJS expression to be executed when the ngModel value changes due * to user interaction with the input element. * @param {expression=} ngChecked If the expression is truthy, then the `checked` attribute will be set on the * element. **Note** : `ngChecked` should not be used alongside `ngModel`. @@ -25020,11 +25478,11 @@ var inputType = { * @description * HTML checkbox. * - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. * @param {expression=} ngTrueValue The value to which the expression should be set when selected. * @param {expression=} ngFalseValue The value to which the expression should be set when not selected. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * interaction with the input element. * * @example @@ -25101,6 +25559,16 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) { composing = true; }); + // Support: IE9+ + element.on('compositionupdate', function(ev) { + // End composition when ev.data is empty string on 'compositionupdate' event. + // When the input de-focusses (e.g. by clicking away), IE triggers 'compositionupdate' + // instead of 'compositionend'. + if (isUndefined(ev.data) || ev.data === '') { + composing = false; + } + }); + element.on('compositionend', function() { composing = false; listener(); @@ -25159,9 +25627,9 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) { deferListener(event, this, this.value); }); - // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it + // if user modifies input value using context menu in IE, we need "paste", "cut" and "drop" events to catch it if ($sniffer.hasEvent('paste')) { - element.on('paste cut', deferListener); + element.on('paste cut drop', deferListener); } } @@ -25284,21 +25752,18 @@ function createDateInputType(type, regexp, parseDate, format) { return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) { badInputChecker(scope, element, attr, ctrl); baseInputType(scope, element, attr, ctrl, $sniffer, $browser); - var timezone = ctrl && ctrl.$options.getOption('timezone'); var previousDate; + var previousTimezone; ctrl.$$parserName = type; ctrl.$parsers.push(function(value) { if (ctrl.$isEmpty(value)) return null; + if (regexp.test(value)) { // Note: We cannot read ctrl.$modelValue, as there might be a different // parser/formatter in the processing chain so that the model // contains some different data format! - var parsedDate = parseDate(value, previousDate); - if (timezone) { - parsedDate = convertTimezoneToLocal(parsedDate, timezone); - } - return parsedDate; + return parseDateAndConvertTimeZoneToLocal(value, previousDate); } return undefined; }); @@ -25309,12 +25774,15 @@ function createDateInputType(type, regexp, parseDate, format) { } if (isValidDate(value)) { previousDate = value; - if (previousDate && timezone) { + var timezone = ctrl.$options.getOption('timezone'); + if (timezone) { + previousTimezone = timezone; previousDate = convertTimezoneToLocal(previousDate, timezone, true); } return $filter('date')(value, format, timezone); } else { previousDate = null; + previousTimezone = null; return ''; } }); @@ -25347,7 +25815,24 @@ function createDateInputType(type, regexp, parseDate, format) { } function parseObservedDateValue(val) { - return isDefined(val) && !isDate(val) ? parseDate(val) || undefined : val; + return isDefined(val) && !isDate(val) ? parseDateAndConvertTimeZoneToLocal(val) || undefined : val; + } + + function parseDateAndConvertTimeZoneToLocal(value, previousDate) { + var timezone = ctrl.$options.getOption('timezone'); + + if (previousTimezone && previousTimezone !== timezone) { + // If the timezone has changed, adjust the previousDate to the default timezone + // so that the new date is converted with the correct timezone offset + previousDate = addDateMinutes(previousDate, timezoneToOffset(previousTimezone)); + } + + var parsedDate = parseDate(value, previousDate); + + if (!isNaN(parsedDate) && timezone) { + parsedDate = convertTimezoneToLocal(parsedDate, timezone); + } + return parsedDate; } }; } @@ -25736,11 +26221,11 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt * @restrict E * * @description - * HTML textarea element control with angular data-binding. The data-binding and validation + * HTML textarea element control with AngularJS data-binding. The data-binding and validation * properties of this element are exactly the same as those of the * {@link ng.directive:input input element}. * - * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} ngModel Assignable AngularJS expression to data-bind to. * @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=} ngRequired Adds `required` attribute and `required` validation constraint to @@ -25752,7 +26237,7 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any * length. * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue} - * does not match a RegExp found by evaluating the Angular expression given in the attribute value. + * does not match a RegExp found by evaluating the AngularJS expression given in the attribute value. * If the expression evaluates to a RegExp object, then this is used directly. * If the expression evaluates to a string, then it will be converted to a RegExp * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to @@ -25760,15 +26245,15 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to * start at the index of the last search's match, thus not taking the whole input value into * account. - * @param {string=} ngChange Angular expression to be executed when input changes due to user + * @param {string=} ngChange AngularJS expression to be executed when input changes due to user * 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 AngularJS will not automatically trim the input. * * @knownIssue * * When specifying the `placeholder` attribute of ` @@ -28343,8 +28985,6 @@ var ngInitDirective = ngDirective({ *
*
* - * @element input - * @param {string=} ngList optional delimiter that should be used to split the value. */ var ngListDirective = function() { return { @@ -28415,7 +29055,6 @@ var ngModelMinErr = minErr('ngModel'); /** * @ngdoc type * @name ngModel.NgModelController - * * @property {*} $viewValue The actual value from the control's view. For `input` elements, this is a * String. See {@link ngModel.NgModelController#$setViewValue} for information about when the $viewValue * is set. @@ -28516,8 +29155,10 @@ var ngModelMinErr = minErr('ngModel'); * }; * ``` * - * @property {Array.} $viewChangeListeners Array of functions to execute whenever the - * view value has changed. It is called with no arguments, and its return value is ignored. + * @property {Array.} $viewChangeListeners Array of functions to execute whenever + * a change to {@link ngModel.NgModelController#$viewValue `$viewValue`} has caused a change + * to {@link ngModel.NgModelController#$modelValue `$modelValue`}. + * It is called with no arguments, and its return value is ignored. * This can be used in place of additional $watches against the model value. * * @property {Object} $error An object hash with all failing validator ids as keys. @@ -28539,7 +29180,7 @@ var ngModelMinErr = minErr('ngModel'); * listening to DOM events. * Such DOM related logic should be provided by other directives which make use of * `NgModelController` for data-binding to control elements. - * Angular provides this DOM logic for most {@link input `input`} elements. + * AngularJS provides this DOM logic for most {@link input `input`} elements. * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example * custom control example} that uses `ngModelController` to bind to `contenteditable` elements. * @@ -28659,6 +29300,9 @@ function NgModelController($scope, $exceptionHandler, $attr, $element, $parse, $ this.$name = $interpolate($attr.name || '', false)($scope); this.$$parentForm = nullFormCtrl; this.$options = defaultModelOptions; + this.$$updateEvents = ''; + // Attach the correct context to the event handler function for updateOn + this.$$updateEventHandler = this.$$updateEventHandler.bind(this); this.$$parsedNgModel = $parse($attr.ngModel); this.$$parsedNgModelAssign = this.$$parsedNgModel.assign; @@ -28855,13 +29499,14 @@ NgModelController.prototype = { * and reset the input to the last committed view value. * * It is also possible that you run into difficulties if you try to update the ngModel's `$modelValue` - * programmatically before these debounced/future events have resolved/occurred, because Angular's + * programmatically before these debounced/future events have resolved/occurred, because AngularJS's * dirty checking mechanism is not able to tell whether the model has actually changed or not. * * The `$rollbackViewValue()` method should be called before programmatically changing the model of an * input which may have such events pending. This is important in order to make sure that the * input field will be updated with the new model value and any pending operations are cancelled. * + * @example * * * angular.module('cancel-update-example', []) @@ -29263,11 +29908,184 @@ NgModelController.prototype = { * See {@link ngModelOptions} for information about what options can be specified * and how model option inheritance works. * + *
+ * **Note:** this function only affects the options set on the `ngModelController`, + * and not the options on the {@link ngModelOptions} directive from which they might have been + * obtained initially. + *
+ * + *
+ * **Note:** it is not possible to override the `getterSetter` option. + *
+ * * @param {Object} options a hash of settings to override the previous options * */ $overrideModelOptions: function(options) { this.$options = this.$options.createChild(options); + this.$$setUpdateOnEvents(); + }, + + /** + * @ngdoc method + * + * @name ngModel.NgModelController#$processModelValue + + * @description + * + * Runs the model -> view pipeline on the current + * {@link ngModel.NgModelController#$modelValue $modelValue}. + * + * The following actions are performed by this method: + * + * - the `$modelValue` is run through the {@link ngModel.NgModelController#$formatters $formatters} + * and the result is set to the {@link ngModel.NgModelController#$viewValue $viewValue} + * - the `ng-empty` or `ng-not-empty` class is set on the element + * - if the `$viewValue` has changed: + * - {@link ngModel.NgModelController#$render $render} is called on the control + * - the {@link ngModel.NgModelController#$validators $validators} are run and + * the validation status is set. + * + * This method is called by ngModel internally when the bound scope value changes. + * Application developers usually do not have to call this function themselves. + * + * This function can be used when the `$viewValue` or the rendered DOM value are not correctly + * formatted and the `$modelValue` must be run through the `$formatters` again. + * + * @example + * Consider a text input with an autocomplete list (for fruit), where the items are + * objects with a name and an id. + * A user enters `ap` and then selects `Apricot` from the list. + * Based on this, the autocomplete widget will call `$setViewValue({name: 'Apricot', id: 443})`, + * but the rendered value will still be `ap`. + * The widget can then call `ctrl.$processModelValue()` to run the model -> view + * pipeline again, which formats the object to the string `Apricot`, + * then updates the `$viewValue`, and finally renders it in the DOM. + * + * + +
+
+ Search Fruit: + +
+
+ Model:
+
{{selectedFruit | json}}
+
+
+
+ + angular.module('inputExample', []) + .controller('inputController', function($scope) { + $scope.items = [ + {name: 'Apricot', id: 443}, + {name: 'Clementine', id: 972}, + {name: 'Durian', id: 169}, + {name: 'Jackfruit', id: 982}, + {name: 'Strawberry', id: 863} + ]; + }) + .component('basicAutocomplete', { + bindings: { + items: '<', + onSelect: '&' + }, + templateUrl: 'autocomplete.html', + controller: function($element, $scope) { + var that = this; + var ngModel; + + that.$postLink = function() { + ngModel = $element.find('input').controller('ngModel'); + + ngModel.$formatters.push(function(value) { + return (value && value.name) || value; + }); + + ngModel.$parsers.push(function(value) { + var match = value; + for (var i = 0; i < that.items.length; i++) { + if (that.items[i].name === value) { + match = that.items[i]; + break; + } + } + + return match; + }); + }; + + that.selectItem = function(item) { + ngModel.$setViewValue(item); + ngModel.$processModelValue(); + that.onSelect({item: item}); + }; + } + }); + + +
+ +
    +
  • + +
  • +
+
+
+ *
+ * + */ + $processModelValue: function() { + var viewValue = this.$$format(); + + if (this.$viewValue !== viewValue) { + this.$$updateEmptyClasses(viewValue); + this.$viewValue = this.$$lastCommittedViewValue = viewValue; + this.$render(); + // It is possible that model and view value have been updated during render + this.$$runValidators(this.$modelValue, this.$viewValue, noop); + } + }, + + /** + * This method is called internally to run the $formatters on the $modelValue + */ + $$format: function() { + var formatters = this.$formatters, + idx = formatters.length; + + var viewValue = this.$modelValue; + while (idx--) { + viewValue = formatters[idx](viewValue); + } + + return viewValue; + }, + + /** + * This method is called internally when the bound scope value changes. + */ + $$setModelValue: function(modelValue) { + this.$modelValue = this.$$rawModelValue = modelValue; + this.$$parserValid = undefined; + this.$processModelValue(); + }, + + $$setUpdateOnEvents: function() { + if (this.$$updateEvents) { + this.$$element.off(this.$$updateEvents, this.$$updateEventHandler); + } + + this.$$updateEvents = this.$options.getOption('updateOn'); + if (this.$$updateEvents) { + this.$$element.on(this.$$updateEvents, this.$$updateEventHandler); + } + }, + + $$updateEventHandler: function(ev) { + this.$$debounceViewValueCommit(ev && ev.type); } }; @@ -29284,30 +30102,14 @@ function setupModelWatcher(ctrl) { var modelValue = ctrl.$$ngModelGet(scope); // if scope model value and ngModel value are out of sync - // TODO(perf): why not move this to the action fn? + // This cannot be moved to the action function, because it would not catch the + // case where the model is changed in the ngChange function or the model setter if (modelValue !== ctrl.$modelValue && - // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator - // eslint-disable-next-line no-self-compare - (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue) + // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator + // eslint-disable-next-line no-self-compare + (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue) ) { - ctrl.$modelValue = ctrl.$$rawModelValue = modelValue; - ctrl.$$parserValid = undefined; - - var formatters = ctrl.$formatters, - idx = formatters.length; - - var viewValue = modelValue; - while (idx--) { - viewValue = formatters[idx](viewValue); - } - if (ctrl.$viewValue !== viewValue) { - ctrl.$$updateEmptyClasses(viewValue); - ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue; - ctrl.$render(); - - // It is possible that model and view value have been updated during render - ctrl.$$runValidators(ctrl.$modelValue, ctrl.$viewValue, noop); - } + ctrl.$$setModelValue(modelValue); } return modelValue; @@ -29333,7 +30135,7 @@ function setupModelWatcher(ctrl) { * classes and can be bound to as `{{ someForm.someControl.$error.myError }}`. * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined), * or skipped (null). Pending is used for unfulfilled `$asyncValidators`. - * Skipped is used by Angular when validators do not run because of parse errors and + * Skipped is used by AngularJS when validators do not run because of parse errors and * when `$asyncValidators` do not run because any of the `$validators` failed. */ addSetValidityMethod({ @@ -29350,9 +30152,9 @@ addSetValidityMethod({ /** * @ngdoc directive * @name ngModel - * - * @element input + * @restrict A * @priority 1 + * @param {expression} ngModel assignable {@link guide/expression Expression} to bind to. * * @description * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a @@ -29394,7 +30196,7 @@ addSetValidityMethod({ * - {@link ng.directive:select select} * - {@link ng.directive:textarea textarea} * - * # Complex Models (objects or collections) + * ## Complex Models (objects or collections) * * By default, `ngModel` watches the model by reference, not value. This is important to know when * binding inputs to models that are objects (e.g. `Date`) or collections (e.g. arrays). If only properties of the @@ -29410,7 +30212,7 @@ addSetValidityMethod({ * first level of the object (or only changing the properties of an item in the collection if it's an array) will still * not trigger a re-rendering of the model. * - * # CSS classes + * ## CSS classes * The following CSS classes are added and removed on the associated input/select/textarea element * depending on the validity of the model. * @@ -29429,8 +30231,7 @@ addSetValidityMethod({ * * Keep in mind that ngAnimate can detect each of these classes when added and removed. * - * ## Animation Hooks - * + * @animations * Animations within models are triggered when any of the associated CSS classes are added and removed * on the input element which is attached to the model. These classes include: `.ng-pristine`, `.ng-dirty`, * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself. @@ -29454,6 +30255,7 @@ addSetValidityMethod({ * * * @example + * ### Basic Usage *