',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(""),b(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) {
SAVE
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
- *
- *
- *
- *
- *
- *
- * Date format:
- * Current time is:
- *
- * Blood 1 : {{blood_1}}
- * Blood 2 : {{blood_2}}
- * Fight
- * StopFight
- * resetFight
- *
- *
- *
- *
- *
- */
+ /**
+ * @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
+ *
+ *
+ *
+ *
+ *
+ *
+ * Date format:
+ * Current time is:
+ *
+ * Blood 1 : {{blood_1}}
+ * Blood 2 : {{blood_2}}
+ * Fight
+ * StopFight
+ * resetFight
+ *
+ *
+ *
+ *
+ *
+ */
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
- Check me to check both:
-
+ Check me to check both:
+
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({
Check me to make text readonly:
-
+
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 `
*
- * @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 `
*
- * @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 {boolean=} ngRequired Sets `required` attribute if set to true
@@ -25805,7 +26290,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}
- * value does not match a RegExp found by evaluating the Angular expression given in the attribute value.
+ * 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
@@ -25813,9 +26298,9 @@ 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.
* This parameter is ignored for input[type=password] controls, which will never trim the
* input.
*
@@ -25939,6 +26424,8 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
/**
* @ngdoc directive
* @name ngValue
+ * @restrict A
+ * @priority 100
*
* @description
* Binds the given expression to the value of the element.
@@ -25951,8 +26438,8 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
* It can also be used to achieve one-way binding of a given expression to an input element
* such as an `input[text]` or a `textarea`, when that element does not use ngModel.
*
- * @element input
- * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
+ * @element ANY
+ * @param {string=} ngValue AngularJS expression, whose value will be bound to the `value` attribute
* and `value` property of the element.
*
* @example
@@ -26032,7 +26519,7 @@ var ngValueDirective = function() {
* @restrict AC
*
* @description
- * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
+ * The `ngBind` attribute tells AngularJS to replace the text content of the specified HTML element
* with the value of a given expression, and to update the text content when the value of that
* expression changes.
*
@@ -26040,7 +26527,7 @@ var ngValueDirective = function() {
* `{{ expression }}` which is similar but less verbose.
*
* It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
- * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
+ * displayed by the browser in its raw state before AngularJS compiles it. Since `ngBind` is an
* element attribute, it makes the bindings invisible to the user while the page is loading.
*
* An alternative solution to this problem would be using the
@@ -26170,7 +26657,7 @@ var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate
* Evaluates the expression and inserts the resulting HTML into the element in a secure way. By default,
* the resulting HTML content will be sanitized using the {@link ngSanitize.$sanitize $sanitize} service.
* To utilize this functionality, ensure that `$sanitize` is available, for example, by including {@link
- * ngSanitize} in your module's dependencies (not in core Angular). In order to use {@link ngSanitize}
+ * ngSanitize} in your module's dependencies (not in core AngularJS). In order to use {@link ngSanitize}
* in your module's dependencies, you need to include "angular-sanitize.js" in your application.
*
* You may also bypass sanitization for values you know are safe. To do so, bind to
@@ -26236,6 +26723,7 @@ var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse,
/**
* @ngdoc directive
* @name ngChange
+ * @restrict A
*
* @description
* Evaluate the given expression when the user changes the input.
@@ -26254,7 +26742,7 @@ var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse,
*
* Note, this directive requires `ngModel` to be present.
*
- * @element input
+ * @element ANY
* @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
* in input value.
*
@@ -26496,6 +26984,7 @@ function classDirective(name, selector) {
* @ngdoc directive
* @name ngClass
* @restrict AC
+ * @element ANY
*
* @description
* The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
@@ -26531,14 +27020,21 @@ function classDirective(name, selector) {
* | {@link ng.$animate#addClass addClass} | just before the class is applied to the element |
* | {@link ng.$animate#removeClass removeClass} | just before the class is removed from the element |
*
- * @element ANY
+ * ### ngClass and pre-existing CSS3 Transitions/Animations
+ The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
+ Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
+ any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
+ to view the step by step details of {@link $animate#addClass $animate.addClass} and
+ {@link $animate#removeClass $animate.removeClass}.
+ *
* @param {expression} ngClass {@link guide/expression Expression} to eval. The result
* of the evaluation can be a string representing space delimited class
* names, an array, or a map of class names to boolean values. In the case of a map, the
* names of the properties whose values are truthy will be added as css classes to the
* element.
*
- * @example Example that demonstrates basic bindings via ngClass directive.
+ * @example
+ * ### Basic
Map Syntax Example
@@ -26628,7 +27124,8 @@ function classDirective(name, selector) {
- ## Animations
+ @example
+ ### Animations
The example below demonstrates how to perform animations using ngClass.
@@ -26666,14 +27163,6 @@ function classDirective(name, selector) {
});
-
-
- ## ngClass and pre-existing CSS3 Transitions/Animations
- The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
- Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
- any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
- to view the step by step details of {@link $animate#addClass $animate.addClass} and
- {@link $animate#removeClass $animate.removeClass}.
*/
var ngClassDirective = classDirective('', true);
@@ -26690,6 +27179,12 @@ var ngClassDirective = classDirective('', true);
* This directive can be applied only within the scope of an
* {@link ng.directive:ngRepeat ngRepeat}.
*
+ * @animations
+ * | Animation | Occurs |
+ * |----------------------------------|-------------------------------------|
+ * | {@link ng.$animate#addClass addClass} | just before the class is applied to the element |
+ * | {@link ng.$animate#removeClass removeClass} | just before the class is removed from the element |
+ *
* @element ANY
* @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
* of the evaluation can be a string representing space delimited class names or an array.
@@ -26722,6 +27217,62 @@ var ngClassDirective = classDirective('', true);
});
+ *
+ *
+ * @example
+ * An example on how to implement animations using `ngClassOdd`:
+ *
+
+
+
+
+
+ .odd {
+ background: rgba(255, 255, 0, 0.25);
+ }
+
+ .odd-add, .odd-remove {
+ transition: 1.5s;
+ }
+
+
+ it('should add new entries to the beginning of the list', function() {
+ var button = element(by.buttonText('Add item'));
+ var rows = element.all(by.repeater('item in items'));
+
+ expect(rows.count()).toBe(4);
+ expect(rows.get(0).getText()).toBe('Item 3');
+ expect(rows.get(1).getText()).toBe('Item 2');
+
+ button.click();
+
+ expect(rows.count()).toBe(5);
+ expect(rows.get(0).getText()).toBe('Item 4');
+ expect(rows.get(1).getText()).toBe('Item 3');
+ });
+
+ it('should add odd class to odd entries', function() {
+ var button = element(by.buttonText('Add item'));
+ var rows = element.all(by.repeater('item in items'));
+
+ expect(rows.get(0).getAttribute('class')).toMatch(/odd/);
+ expect(rows.get(1).getAttribute('class')).not.toMatch(/odd/);
+
+ button.click();
+
+ expect(rows.get(0).getAttribute('class')).toMatch(/odd/);
+ expect(rows.get(1).getAttribute('class')).not.toMatch(/odd/);
+ });
+
+
*/
var ngClassOddDirective = classDirective('Odd', 0);
@@ -26738,6 +27289,12 @@ var ngClassOddDirective = classDirective('Odd', 0);
* This directive can be applied only within the scope of an
* {@link ng.directive:ngRepeat ngRepeat}.
*
+ * @animations
+ * | Animation | Occurs |
+ * |----------------------------------|-------------------------------------|
+ * | {@link ng.$animate#addClass addClass} | just before the class is applied to the element |
+ * | {@link ng.$animate#removeClass removeClass} | just before the class is removed from the element |
+ *
* @element ANY
* @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
* result of the evaluation can be a string representing space delimited class names or an array.
@@ -26770,6 +27327,62 @@ var ngClassOddDirective = classDirective('Odd', 0);
});
+ *
+ *
+ * @example
+ * An example on how to implement animations using `ngClassEven`:
+ *
+
+
+
+
+
+ .even {
+ background: rgba(255, 255, 0, 0.25);
+ }
+
+ .even-add, .even-remove {
+ transition: 1.5s;
+ }
+
+
+ it('should add new entries to the beginning of the list', function() {
+ var button = element(by.buttonText('Add item'));
+ var rows = element.all(by.repeater('item in items'));
+
+ expect(rows.count()).toBe(4);
+ expect(rows.get(0).getText()).toBe('Item 3');
+ expect(rows.get(1).getText()).toBe('Item 2');
+
+ button.click();
+
+ expect(rows.count()).toBe(5);
+ expect(rows.get(0).getText()).toBe('Item 4');
+ expect(rows.get(1).getText()).toBe('Item 3');
+ });
+
+ it('should add even class to even entries', function() {
+ var button = element(by.buttonText('Add item'));
+ var rows = element.all(by.repeater('item in items'));
+
+ expect(rows.get(0).getAttribute('class')).not.toMatch(/even/);
+ expect(rows.get(1).getAttribute('class')).toMatch(/even/);
+
+ button.click();
+
+ expect(rows.get(0).getAttribute('class')).not.toMatch(/even/);
+ expect(rows.get(1).getAttribute('class')).toMatch(/even/);
+ });
+
+
*/
var ngClassEvenDirective = classDirective('Even', 1);
@@ -26779,7 +27392,7 @@ var ngClassEvenDirective = classDirective('Even', 1);
* @restrict AC
*
* @description
- * The `ngCloak` directive is used to prevent the Angular html template from being briefly
+ * The `ngCloak` directive is used to prevent the AngularJS html template from being briefly
* displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
* directive to avoid the undesirable flicker effect caused by the html template display.
*
@@ -26798,7 +27411,7 @@ var ngClassEvenDirective = classDirective('Even', 1);
* ```
*
* When this css rule is loaded by the browser, all html elements (including their children) that
- * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
+ * are tagged with the `ngCloak` directive are hidden. When AngularJS encounters this directive
* during the compilation of the template it deletes the `ngCloak` element attribute, making
* the compiled element visible.
*
@@ -26870,7 +27483,7 @@ var ngCloakDirective = ngDirective({
* @example
* Here is a simple form for editing user contact information. Adding, removing, clearing, and
* greeting are methods declared on the controller (see source tab). These methods can
- * easily be called from the angular markup. Any changes to the data are automatically reflected
+ * easily be called from the AngularJS markup. Any changes to the data are automatically reflected
* in the View without the need for a manual update.
*
* Two different declaration styles are included below:
@@ -26880,7 +27493,7 @@ var ngCloakDirective = ngDirective({
* * one injects `$scope` into the controller:
* `ng-controller="SettingsController2"`
*
- * The second option is more common in the Angular community, and is generally used in boilerplates
+ * The second option is more common in the AngularJS community, and is generally used in boilerplates
* and in this guide. However, there are advantages to binding properties directly to the controller
* and avoiding scope.
*
@@ -27077,31 +27690,31 @@ var ngControllerDirective = [function() {
* @element ANY
* @description
*
- * Angular has some features that can conflict with certain restrictions that are applied when using
+ * AngularJS has some features that can conflict with certain restrictions that are applied when using
* [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) rules.
*
- * If you intend to implement CSP with these rules then you must tell Angular not to use these
+ * If you intend to implement CSP with these rules then you must tell AngularJS not to use these
* features.
*
* This is necessary when developing things like Google Chrome Extensions or Universal Windows Apps.
*
*
- * The following default rules in CSP affect Angular:
+ * The following default rules in CSP affect AngularJS:
*
* * The use of `eval()`, `Function(string)` and similar functions to dynamically create and execute
- * code from strings is forbidden. Angular makes use of this in the {@link $parse} service to
- * provide a 30% increase in the speed of evaluating Angular expressions. (This CSP rule can be
+ * code from strings is forbidden. AngularJS makes use of this in the {@link $parse} service to
+ * provide a 30% increase in the speed of evaluating AngularJS expressions. (This CSP rule can be
* disabled with the CSP keyword `unsafe-eval`, but it is generally not recommended as it would
* weaken the protections offered by CSP.)
*
* * The use of inline resources, such as inline `
@@ -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
- *
- *
- *
- *
- *
- *
- * Date format:
- * Current time is:
- *
- * Blood 1 : {{blood_1}}
- * Blood 2 : {{blood_2}}
- * Fight
- * StopFight
- * resetFight
- *
- *
- *
- *
- *
- */
+ /**
+ * @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
+ *
+ *
+ *
+ *
+ *
+ *
+ * Date format:
+ * Current time is:
+ *
+ * Blood 1 : {{blood_1}}
+ * Blood 2 : {{blood_2}}
+ * Fight
+ * StopFight
+ * resetFight
+ *
+ *
+ *
+ *
+ *
+ */
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
- Check me to check both:
-
+ Check me to check both:
+
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({
Check me to make text readonly:
-
+
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 `
*
- * @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 `
*
- * @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 {boolean=} ngRequired Sets `required` attribute if set to true
@@ -25805,7 +26290,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}
- * value does not match a RegExp found by evaluating the Angular expression given in the attribute value.
+ * 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
@@ -25813,9 +26298,9 @@ 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.
* This parameter is ignored for input[type=password] controls, which will never trim the
* input.
*
@@ -25939,6 +26424,8 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
/**
* @ngdoc directive
* @name ngValue
+ * @restrict A
+ * @priority 100
*
* @description
* Binds the given expression to the value of the element.
@@ -25951,8 +26438,8 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
* It can also be used to achieve one-way binding of a given expression to an input element
* such as an `input[text]` or a `textarea`, when that element does not use ngModel.
*
- * @element input
- * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
+ * @element ANY
+ * @param {string=} ngValue AngularJS expression, whose value will be bound to the `value` attribute
* and `value` property of the element.
*
* @example
@@ -26032,7 +26519,7 @@ var ngValueDirective = function() {
* @restrict AC
*
* @description
- * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
+ * The `ngBind` attribute tells AngularJS to replace the text content of the specified HTML element
* with the value of a given expression, and to update the text content when the value of that
* expression changes.
*
@@ -26040,7 +26527,7 @@ var ngValueDirective = function() {
* `{{ expression }}` which is similar but less verbose.
*
* It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
- * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
+ * displayed by the browser in its raw state before AngularJS compiles it. Since `ngBind` is an
* element attribute, it makes the bindings invisible to the user while the page is loading.
*
* An alternative solution to this problem would be using the
@@ -26170,7 +26657,7 @@ var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate
* Evaluates the expression and inserts the resulting HTML into the element in a secure way. By default,
* the resulting HTML content will be sanitized using the {@link ngSanitize.$sanitize $sanitize} service.
* To utilize this functionality, ensure that `$sanitize` is available, for example, by including {@link
- * ngSanitize} in your module's dependencies (not in core Angular). In order to use {@link ngSanitize}
+ * ngSanitize} in your module's dependencies (not in core AngularJS). In order to use {@link ngSanitize}
* in your module's dependencies, you need to include "angular-sanitize.js" in your application.
*
* You may also bypass sanitization for values you know are safe. To do so, bind to
@@ -26236,6 +26723,7 @@ var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse,
/**
* @ngdoc directive
* @name ngChange
+ * @restrict A
*
* @description
* Evaluate the given expression when the user changes the input.
@@ -26254,7 +26742,7 @@ var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse,
*
* Note, this directive requires `ngModel` to be present.
*
- * @element input
+ * @element ANY
* @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
* in input value.
*
@@ -26496,6 +26984,7 @@ function classDirective(name, selector) {
* @ngdoc directive
* @name ngClass
* @restrict AC
+ * @element ANY
*
* @description
* The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
@@ -26531,14 +27020,21 @@ function classDirective(name, selector) {
* | {@link ng.$animate#addClass addClass} | just before the class is applied to the element |
* | {@link ng.$animate#removeClass removeClass} | just before the class is removed from the element |
*
- * @element ANY
+ * ### ngClass and pre-existing CSS3 Transitions/Animations
+ The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
+ Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
+ any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
+ to view the step by step details of {@link $animate#addClass $animate.addClass} and
+ {@link $animate#removeClass $animate.removeClass}.
+ *
* @param {expression} ngClass {@link guide/expression Expression} to eval. The result
* of the evaluation can be a string representing space delimited class
* names, an array, or a map of class names to boolean values. In the case of a map, the
* names of the properties whose values are truthy will be added as css classes to the
* element.
*
- * @example Example that demonstrates basic bindings via ngClass directive.
+ * @example
+ * ### Basic
Map Syntax Example
@@ -26628,7 +27124,8 @@ function classDirective(name, selector) {
- ## Animations
+ @example
+ ### Animations
The example below demonstrates how to perform animations using ngClass.
@@ -26666,14 +27163,6 @@ function classDirective(name, selector) {
});
-
-
- ## ngClass and pre-existing CSS3 Transitions/Animations
- The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
- Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
- any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
- to view the step by step details of {@link $animate#addClass $animate.addClass} and
- {@link $animate#removeClass $animate.removeClass}.
*/
var ngClassDirective = classDirective('', true);
@@ -26690,6 +27179,12 @@ var ngClassDirective = classDirective('', true);
* This directive can be applied only within the scope of an
* {@link ng.directive:ngRepeat ngRepeat}.
*
+ * @animations
+ * | Animation | Occurs |
+ * |----------------------------------|-------------------------------------|
+ * | {@link ng.$animate#addClass addClass} | just before the class is applied to the element |
+ * | {@link ng.$animate#removeClass removeClass} | just before the class is removed from the element |
+ *
* @element ANY
* @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
* of the evaluation can be a string representing space delimited class names or an array.
@@ -26722,6 +27217,62 @@ var ngClassDirective = classDirective('', true);
});
+ *
+ *
+ * @example
+ * An example on how to implement animations using `ngClassOdd`:
+ *
+
+
+
+
+
+ .odd {
+ background: rgba(255, 255, 0, 0.25);
+ }
+
+ .odd-add, .odd-remove {
+ transition: 1.5s;
+ }
+
+
+ it('should add new entries to the beginning of the list', function() {
+ var button = element(by.buttonText('Add item'));
+ var rows = element.all(by.repeater('item in items'));
+
+ expect(rows.count()).toBe(4);
+ expect(rows.get(0).getText()).toBe('Item 3');
+ expect(rows.get(1).getText()).toBe('Item 2');
+
+ button.click();
+
+ expect(rows.count()).toBe(5);
+ expect(rows.get(0).getText()).toBe('Item 4');
+ expect(rows.get(1).getText()).toBe('Item 3');
+ });
+
+ it('should add odd class to odd entries', function() {
+ var button = element(by.buttonText('Add item'));
+ var rows = element.all(by.repeater('item in items'));
+
+ expect(rows.get(0).getAttribute('class')).toMatch(/odd/);
+ expect(rows.get(1).getAttribute('class')).not.toMatch(/odd/);
+
+ button.click();
+
+ expect(rows.get(0).getAttribute('class')).toMatch(/odd/);
+ expect(rows.get(1).getAttribute('class')).not.toMatch(/odd/);
+ });
+
+
*/
var ngClassOddDirective = classDirective('Odd', 0);
@@ -26738,6 +27289,12 @@ var ngClassOddDirective = classDirective('Odd', 0);
* This directive can be applied only within the scope of an
* {@link ng.directive:ngRepeat ngRepeat}.
*
+ * @animations
+ * | Animation | Occurs |
+ * |----------------------------------|-------------------------------------|
+ * | {@link ng.$animate#addClass addClass} | just before the class is applied to the element |
+ * | {@link ng.$animate#removeClass removeClass} | just before the class is removed from the element |
+ *
* @element ANY
* @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
* result of the evaluation can be a string representing space delimited class names or an array.
@@ -26770,6 +27327,62 @@ var ngClassOddDirective = classDirective('Odd', 0);
});
+ *
+ *
+ * @example
+ * An example on how to implement animations using `ngClassEven`:
+ *
+
+
+
+
+
+ .even {
+ background: rgba(255, 255, 0, 0.25);
+ }
+
+ .even-add, .even-remove {
+ transition: 1.5s;
+ }
+
+
+ it('should add new entries to the beginning of the list', function() {
+ var button = element(by.buttonText('Add item'));
+ var rows = element.all(by.repeater('item in items'));
+
+ expect(rows.count()).toBe(4);
+ expect(rows.get(0).getText()).toBe('Item 3');
+ expect(rows.get(1).getText()).toBe('Item 2');
+
+ button.click();
+
+ expect(rows.count()).toBe(5);
+ expect(rows.get(0).getText()).toBe('Item 4');
+ expect(rows.get(1).getText()).toBe('Item 3');
+ });
+
+ it('should add even class to even entries', function() {
+ var button = element(by.buttonText('Add item'));
+ var rows = element.all(by.repeater('item in items'));
+
+ expect(rows.get(0).getAttribute('class')).not.toMatch(/even/);
+ expect(rows.get(1).getAttribute('class')).toMatch(/even/);
+
+ button.click();
+
+ expect(rows.get(0).getAttribute('class')).not.toMatch(/even/);
+ expect(rows.get(1).getAttribute('class')).toMatch(/even/);
+ });
+
+
*/
var ngClassEvenDirective = classDirective('Even', 1);
@@ -26779,7 +27392,7 @@ var ngClassEvenDirective = classDirective('Even', 1);
* @restrict AC
*
* @description
- * The `ngCloak` directive is used to prevent the Angular html template from being briefly
+ * The `ngCloak` directive is used to prevent the AngularJS html template from being briefly
* displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
* directive to avoid the undesirable flicker effect caused by the html template display.
*
@@ -26798,7 +27411,7 @@ var ngClassEvenDirective = classDirective('Even', 1);
* ```
*
* When this css rule is loaded by the browser, all html elements (including their children) that
- * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
+ * are tagged with the `ngCloak` directive are hidden. When AngularJS encounters this directive
* during the compilation of the template it deletes the `ngCloak` element attribute, making
* the compiled element visible.
*
@@ -26870,7 +27483,7 @@ var ngCloakDirective = ngDirective({
* @example
* Here is a simple form for editing user contact information. Adding, removing, clearing, and
* greeting are methods declared on the controller (see source tab). These methods can
- * easily be called from the angular markup. Any changes to the data are automatically reflected
+ * easily be called from the AngularJS markup. Any changes to the data are automatically reflected
* in the View without the need for a manual update.
*
* Two different declaration styles are included below:
@@ -26880,7 +27493,7 @@ var ngCloakDirective = ngDirective({
* * one injects `$scope` into the controller:
* `ng-controller="SettingsController2"`
*
- * The second option is more common in the Angular community, and is generally used in boilerplates
+ * The second option is more common in the AngularJS community, and is generally used in boilerplates
* and in this guide. However, there are advantages to binding properties directly to the controller
* and avoiding scope.
*
@@ -27077,31 +27690,31 @@ var ngControllerDirective = [function() {
* @element ANY
* @description
*
- * Angular has some features that can conflict with certain restrictions that are applied when using
+ * AngularJS has some features that can conflict with certain restrictions that are applied when using
* [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) rules.
*
- * If you intend to implement CSP with these rules then you must tell Angular not to use these
+ * If you intend to implement CSP with these rules then you must tell AngularJS not to use these
* features.
*
* This is necessary when developing things like Google Chrome Extensions or Universal Windows Apps.
*
*
- * The following default rules in CSP affect Angular:
+ * The following default rules in CSP affect AngularJS:
*
* * The use of `eval()`, `Function(string)` and similar functions to dynamically create and execute
- * code from strings is forbidden. Angular makes use of this in the {@link $parse} service to
- * provide a 30% increase in the speed of evaluating Angular expressions. (This CSP rule can be
+ * code from strings is forbidden. AngularJS makes use of this in the {@link $parse} service to
+ * provide a 30% increase in the speed of evaluating AngularJS expressions. (This CSP rule can be
* disabled with the CSP keyword `unsafe-eval`, but it is generally not recommended as it would
* weaken the protections offered by CSP.)
*
* * The use of inline resources, such as inline `