angular-rails-engine 1.2.5.0 → 1.2.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/README.md +1 -1
- data/app/assets/javascripts/angular/angular-animate.js +461 -195
- data/app/assets/javascripts/angular/angular-animate.min.js +23 -18
- data/app/assets/javascripts/angular/angular-cookies.js +1 -1
- data/app/assets/javascripts/angular/angular-cookies.min.js +2 -1
- data/app/assets/javascripts/angular/angular-loader.js +2 -2
- data/app/assets/javascripts/angular/angular-loader.min.js +3 -2
- data/app/assets/javascripts/angular/angular-mocks.js +54 -34
- data/app/assets/javascripts/angular/angular-resource.js +36 -5
- data/app/assets/javascripts/angular/angular-resource.min.js +9 -8
- data/app/assets/javascripts/angular/angular-route.js +25 -15
- data/app/assets/javascripts/angular/angular-route.min.js +10 -9
- data/app/assets/javascripts/angular/angular-sanitize.js +35 -32
- data/app/assets/javascripts/angular/angular-sanitize.min.js +3 -2
- data/app/assets/javascripts/angular/angular-scenario.js +1472 -966
- data/app/assets/javascripts/angular/angular-touch.js +1 -1
- data/app/assets/javascripts/angular/angular-touch.min.js +2 -1
- data/app/assets/javascripts/angular/angular.js +1470 -965
- data/app/assets/javascripts/angular/angular.min.js +200 -196
- data/app/assets/stylesheets/angular/angular-csp.css +18 -0
- data/gem-public_cert.pem +11 -10
- data/lib/angular-rails-engine.rb +1 -1
- data/lib/angular-rails-engine/version.rb +1 -1
- metadata +14 -13
- metadata.gz.sig +0 -0
- data/app/assets/stylesheets/angular-csp.css +0 -24
@@ -1,13 +1,14 @@
|
|
1
1
|
/*
|
2
|
-
AngularJS v1.2.
|
2
|
+
AngularJS v1.2.13
|
3
3
|
(c) 2010-2014 Google, Inc. http://angularjs.org
|
4
4
|
License: MIT
|
5
5
|
*/
|
6
|
-
(function(h,e,A){'use strict';function u(w,q,k){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(a,c,b,f,n){function y(){l&&(l.$destroy(),l=null);g&&(k.leave(g),g=null)}function v(){var b=w.current&&w.current.locals;if(b&&b.$template){var b=a.$new(),f=w.current;g=n(b,function(d){k.enter(d,null,g||c,function(){!e.isDefined(t)||t&&!a.$eval(t)||q()});y()});l=f.scope=b;l.$emit("$viewContentLoaded");l.$eval(h)}else y()}var l,g,t=b.autoscroll,h=b.onload||"";
|
7
|
-
v);v()}}}function z(e,h,k){return{restrict:"ECA",priority:-400,link:function(a,c){var b=k.current,f=b.locals;c.html(f.$template);var n=e(c.contents());b.controller&&(f.$scope=a,f=h(b.controller,f),b.controllerAs&&(a[b.controllerAs]=f),c.data("$ngControllerController",f),c.children().data("$ngControllerController",f));n(a)}}}h=e.module("ngRoute",["ng"]).provider("$route",function(){function h(a,c){return e.extend(new (e.extend(function(){},{prototype:a})),c)}function q(a,
|
8
|
-
f={originalPath:a,regexp:a},h=f.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)([
|
9
|
-
q(b,c))}return this};this.otherwise=function(a){this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache","$sce",function(a,c,b,f,n,q,v,l){function g(){var d=t(),m=r.current;if(d&&m&&d.$$route===m.$$route&&e.equals(d.pathParams,m.pathParams)&&!d.reloadOnSearch&&!x)m.params=d.params,e.copy(m.params,b),a.$broadcast("$routeUpdate",m);else if(d||m)x=!1,a.$broadcast("$routeChangeStart",d,m),(r.current=
|
10
|
-
c.path(u(d.redirectTo,d.params)).search(d.params).replace():c.url(d.redirectTo(d.pathParams,c.path(),c.search())).replace()),f.when(d).then(function(){if(d){var a=e.extend({},d.resolve),c,b;e.forEach(a,function(d,c){a[c]=e.isString(d)?n.get(d):n.invoke(d)});e.isDefined(c=d.template)?e.isFunction(c)&&(c=c(d.params)):e.isDefined(b=d.templateUrl)&&(e.isFunction(b)&&(b=b(d.params)),b=l.getTrustedResourceUrl(b),e.isDefined(b)&&(d.loadedTemplateUrl=b,c=q.get(b,
|
11
|
-
e.isDefined(c)&&(a.$template=c);return f.all(a)}}).then(function(c){d==r.current&&(d&&(d.locals=c,e.copy(d.params,b)),a.$broadcast("$routeChangeSuccess",d,m))},function(c){d==r.current&&a.$broadcast("$routeChangeError",d,m,c)})}function t(){var a,b;e.forEach(k,function(f,k){var p;if(p=!b){var s=c.path();p=f.keys;var l={};if(f.regexp)if(s=f.regexp.exec(s)){for(var g=1,q=s.length;g<q;++g){var n=p[g-1],r="string"==typeof s[g]?decodeURIComponent(s[g]):s[g];
|
12
|
-
p=a=p}p&&(b=h(f,{params:e.extend({},c.search(),a),pathParams:a}),b.$$route=f)});return b||k[null]&&h(k[null],{params:{},pathParams:{}})}function u(a,c){var b=[];e.forEach((a||"").split(":"),function(a,d){if(0===d)b.push(a);else{var e=a.match(/(\w+)(.*)/),f=e[1];b.push(c[f]);b.push(e[2]||"");delete c[f]}});return b.join("")}var x=!1,r={routes:k,reload:function(){x=!0;a.$evalAsync(g)}};a.$on("$locationChangeSuccess",g);return r}]});h.provider("$routeParams",
|
13
|
-
h.directive("ngView",u);h.directive("ngView",z);u.$inject=["$route","$anchorScroll","$animate"];z.$inject=["$compile","$controller","$route"]})(window,window.angular);
|
6
|
+
(function(h,e,A){'use strict';function u(w,q,k){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(a,c,b,f,n){function y(){l&&(l.$destroy(),l=null);g&&(k.leave(g),g=null)}function v(){var b=w.current&&w.current.locals;if(e.isDefined(b&&b.$template)){var b=a.$new(),f=w.current;g=n(b,function(d){k.enter(d,null,g||c,function(){!e.isDefined(t)||t&&!a.$eval(t)||q()});y()});l=f.scope=b;l.$emit("$viewContentLoaded");l.$eval(h)}else y()}var l,g,t=b.autoscroll,h=b.onload||"";
|
7
|
+
a.$on("$routeChangeSuccess",v);v()}}}function z(e,h,k){return{restrict:"ECA",priority:-400,link:function(a,c){var b=k.current,f=b.locals;c.html(f.$template);var n=e(c.contents());b.controller&&(f.$scope=a,f=h(b.controller,f),b.controllerAs&&(a[b.controllerAs]=f),c.data("$ngControllerController",f),c.children().data("$ngControllerController",f));n(a)}}}h=e.module("ngRoute",["ng"]).provider("$route",function(){function h(a,c){return e.extend(new (e.extend(function(){},{prototype:a})),c)}function q(a,
|
8
|
+
e){var b=e.caseInsensitiveMatch,f={originalPath:a,regexp:a},h=f.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)([\?\*])?/g,function(a,e,b,c){a="?"===c?c:null;c="*"===c?c:null;h.push({name:b,optional:!!a});e=e||"";return""+(a?"":e)+"(?:"+(a?e:"")+(c&&"(.+?)"||"([^/]+)")+(a||"")+")"+(a||"")}).replace(/([\/$\*])/g,"\\$1");f.regexp=RegExp("^"+a+"$",b?"i":"");return f}var k={};this.when=function(a,c){k[a]=e.extend({reloadOnSearch:!0},c,a&&q(a,c));if(a){var b="/"==a[a.length-1]?a.substr(0,a.length-
|
9
|
+
1):a+"/";k[b]=e.extend({redirectTo:a},q(b,c))}return this};this.otherwise=function(a){this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache","$sce",function(a,c,b,f,n,q,v,l){function g(){var d=t(),m=r.current;if(d&&m&&d.$$route===m.$$route&&e.equals(d.pathParams,m.pathParams)&&!d.reloadOnSearch&&!x)m.params=d.params,e.copy(m.params,b),a.$broadcast("$routeUpdate",m);else if(d||m)x=!1,a.$broadcast("$routeChangeStart",d,m),(r.current=
|
10
|
+
d)&&d.redirectTo&&(e.isString(d.redirectTo)?c.path(u(d.redirectTo,d.params)).search(d.params).replace():c.url(d.redirectTo(d.pathParams,c.path(),c.search())).replace()),f.when(d).then(function(){if(d){var a=e.extend({},d.resolve),c,b;e.forEach(a,function(d,c){a[c]=e.isString(d)?n.get(d):n.invoke(d)});e.isDefined(c=d.template)?e.isFunction(c)&&(c=c(d.params)):e.isDefined(b=d.templateUrl)&&(e.isFunction(b)&&(b=b(d.params)),b=l.getTrustedResourceUrl(b),e.isDefined(b)&&(d.loadedTemplateUrl=b,c=q.get(b,
|
11
|
+
{cache:v}).then(function(a){return a.data})));e.isDefined(c)&&(a.$template=c);return f.all(a)}}).then(function(c){d==r.current&&(d&&(d.locals=c,e.copy(d.params,b)),a.$broadcast("$routeChangeSuccess",d,m))},function(c){d==r.current&&a.$broadcast("$routeChangeError",d,m,c)})}function t(){var a,b;e.forEach(k,function(f,k){var p;if(p=!b){var s=c.path();p=f.keys;var l={};if(f.regexp)if(s=f.regexp.exec(s)){for(var g=1,q=s.length;g<q;++g){var n=p[g-1],r="string"==typeof s[g]?decodeURIComponent(s[g]):s[g];
|
12
|
+
n&&r&&(l[n.name]=r)}p=l}else p=null;else p=null;p=a=p}p&&(b=h(f,{params:e.extend({},c.search(),a),pathParams:a}),b.$$route=f)});return b||k[null]&&h(k[null],{params:{},pathParams:{}})}function u(a,c){var b=[];e.forEach((a||"").split(":"),function(a,d){if(0===d)b.push(a);else{var e=a.match(/(\w+)(.*)/),f=e[1];b.push(c[f]);b.push(e[2]||"");delete c[f]}});return b.join("")}var x=!1,r={routes:k,reload:function(){x=!0;a.$evalAsync(g)}};a.$on("$locationChangeSuccess",g);return r}]});h.provider("$routeParams",
|
13
|
+
function(){this.$get=function(){return{}}});h.directive("ngView",u);h.directive("ngView",z);u.$inject=["$route","$anchorScroll","$animate"];z.$inject=["$compile","$controller","$route"]})(window,window.angular);
|
14
|
+
//# sourceMappingURL=angular-route.min.js.map
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.2.
|
2
|
+
* @license AngularJS v1.2.13
|
3
3
|
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -104,35 +104,37 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize');
|
|
104
104
|
</table>
|
105
105
|
</div>
|
106
106
|
</doc:source>
|
107
|
-
<doc:
|
107
|
+
<doc:protractor>
|
108
108
|
it('should sanitize the html snippet by default', function() {
|
109
|
-
expect(
|
109
|
+
expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()).
|
110
110
|
toBe('<p>an html\n<em>click here</em>\nsnippet</p>');
|
111
111
|
});
|
112
112
|
|
113
113
|
it('should inline raw snippet if bound to a trusted value', function() {
|
114
|
-
expect(
|
114
|
+
expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).
|
115
115
|
toBe("<p style=\"color:blue\">an html\n" +
|
116
116
|
"<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
|
117
117
|
"snippet</p>");
|
118
118
|
});
|
119
119
|
|
120
120
|
it('should escape snippet without any filter', function() {
|
121
|
-
expect(
|
121
|
+
expect(element(by.css('#bind-default div')).getInnerHtml()).
|
122
122
|
toBe("<p style=\"color:blue\">an html\n" +
|
123
123
|
"<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
|
124
124
|
"snippet</p>");
|
125
125
|
});
|
126
126
|
|
127
127
|
it('should update', function() {
|
128
|
-
|
129
|
-
|
130
|
-
expect(
|
128
|
+
element(by.model('snippet')).clear();
|
129
|
+
element(by.model('snippet')).sendKeys('new <b onclick="alert(1)">text</b>');
|
130
|
+
expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()).
|
131
|
+
toBe('new <b>text</b>');
|
132
|
+
expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).toBe(
|
131
133
|
'new <b onclick="alert(1)">text</b>');
|
132
|
-
expect(
|
134
|
+
expect(element(by.css('#bind-default div')).getInnerHtml()).toBe(
|
133
135
|
"new <b onclick=\"alert(1)\">text</b>");
|
134
136
|
});
|
135
|
-
</doc:
|
137
|
+
</doc:protractor>
|
136
138
|
</doc:example>
|
137
139
|
*/
|
138
140
|
function $SanitizeProvider() {
|
@@ -211,7 +213,7 @@ var validAttrs = angular.extend({}, uriAttrs, makeMap(
|
|
211
213
|
'abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,'+
|
212
214
|
'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,'+
|
213
215
|
'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,'+
|
214
|
-
'scope,scrolling,shape,span,start,summary,target,title,type,'+
|
216
|
+
'scope,scrolling,shape,size,span,start,summary,target,title,type,'+
|
215
217
|
'valign,value,vspace,width'));
|
216
218
|
|
217
219
|
function makeMap(str) {
|
@@ -537,37 +539,38 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
|
|
537
539
|
</tr>
|
538
540
|
</table>
|
539
541
|
</doc:source>
|
540
|
-
<doc:
|
542
|
+
<doc:protractor>
|
541
543
|
it('should linkify the snippet with urls', function() {
|
542
|
-
expect(
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
'<a href="mailto:another@somewhere.org">another@somewhere.org</a>, ' +
|
547
|
-
'and one more: <a href="ftp://127.0.0.1/">ftp://127.0.0.1/</a>.');
|
544
|
+
expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
|
545
|
+
toBe('Pretty text with some links: http://angularjs.org/, us@somewhere.org, ' +
|
546
|
+
'another@somewhere.org, and one more: ftp://127.0.0.1/.');
|
547
|
+
expect(element.all(by.css('#linky-filter a')).count()).toEqual(4);
|
548
548
|
});
|
549
549
|
|
550
|
-
it
|
551
|
-
expect(
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
"another@somewhere.org,\n" +
|
556
|
-
"and one more: ftp://127.0.0.1/.");
|
550
|
+
it('should not linkify snippet without the linky filter', function() {
|
551
|
+
expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()).
|
552
|
+
toBe('Pretty text with some links: http://angularjs.org/, mailto:us@somewhere.org, ' +
|
553
|
+
'another@somewhere.org, and one more: ftp://127.0.0.1/.');
|
554
|
+
expect(element.all(by.css('#escaped-html a')).count()).toEqual(0);
|
557
555
|
});
|
558
556
|
|
559
557
|
it('should update', function() {
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
558
|
+
element(by.model('snippet')).clear();
|
559
|
+
element(by.model('snippet')).sendKeys('new http://link.');
|
560
|
+
expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
|
561
|
+
toBe('new http://link.');
|
562
|
+
expect(element.all(by.css('#linky-filter a')).count()).toEqual(1);
|
563
|
+
expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText())
|
564
|
+
.toBe('new http://link.');
|
564
565
|
});
|
565
566
|
|
566
567
|
it('should work with the target property', function() {
|
567
|
-
expect(
|
568
|
-
|
568
|
+
expect(element(by.id('linky-target')).
|
569
|
+
element(by.binding("snippetWithTarget | linky:'_blank'")).getText()).
|
570
|
+
toBe('http://angularjs.org/');
|
571
|
+
expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank');
|
569
572
|
});
|
570
|
-
</doc:
|
573
|
+
</doc:protractor>
|
571
574
|
</doc:example>
|
572
575
|
*/
|
573
576
|
angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/*
|
2
|
-
AngularJS v1.2.
|
2
|
+
AngularJS v1.2.13
|
3
3
|
(c) 2010-2014 Google, Inc. http://angularjs.org
|
4
4
|
License: MIT
|
5
5
|
*/
|
@@ -8,6 +8,7 @@ if(0<=c){for(d=f.length-1;d>=c;d--)e.end&&e.end(f[d]);f.length=c}}var b,g,f=[],l
|
|
8
8
|
a.replace(b[0],""),g=!1}else if(J.test(a)){if(b=a.match(z))a=a.substring(b[0].length),b[0].replace(z,c),g=!1}else K.test(a)&&(b=a.match(A))&&(a=a.substring(b[0].length),b[0].replace(A,d),g=!1);g&&(b=a.indexOf("<"),g=0>b?a:a.substring(0,b),a=0>b?"":a.substring(b),e.chars&&e.chars(r(g)))}if(a==l)throw L("badparse",a);l=a}c()}function r(a){if(!a)return"";var e=M.exec(a);a=e[1];var d=e[3];if(e=e[2])n.innerHTML=e.replace(/</g,"<"),e="textContent"in n?n.textContent:n.innerText;return a+e+d}function B(a){return a.replace(/&/g,
|
9
9
|
"&").replace(N,function(a){return"&#"+a.charCodeAt(0)+";"}).replace(/</g,"<").replace(/>/g,">")}function s(a,e){var d=!1,c=h.bind(a,a.push);return{start:function(a,g,f){a=h.lowercase(a);!d&&x[a]&&(d=a);d||!0!==C[a]||(c("<"),c(a),h.forEach(g,function(d,f){var g=h.lowercase(f),k="img"===a&&"src"===g||"background"===g;!0!==O[g]||!0===D[g]&&!e(d,k)||(c(" "),c(f),c('="'),c(B(d)),c('"'))}),c(f?"/>":">"))},end:function(a){a=h.lowercase(a);d||!0!==C[a]||(c("</"),c(a),c(">"));a==d&&(d=!1)},chars:function(a){d||
|
10
10
|
c(B(a))}}}var L=h.$$minErr("$sanitize"),A=/^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/,z=/^<\s*\/\s*([\w:-]+)[^>]*>/,G=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,K=/^</,J=/^<\s*\//,H=/\x3c!--(.*?)--\x3e/g,y=/<!DOCTYPE([^>]*?)>/i,I=/<!\[CDATA\[(.*?)]]\x3e/g,N=/([^\#-~| |!])/g,w=k("area,br,col,hr,img,wbr");p=k("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr");q=k("rp,rt");var v=h.extend({},q,p),t=h.extend({},p,k("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,script,section,table,ul")),
|
11
|
-
u=h.extend({},q,k("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")),x=k("script,style"),C=h.extend({},w,t,u,v),D=k("background,cite,href,longdesc,src,usemap"),O=h.extend({},D,k("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,span,start,summary,target,title,type,valign,value,vspace,width")),
|
11
|
+
u=h.extend({},q,k("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")),x=k("script,style"),C=h.extend({},w,t,u,v),D=k("background,cite,href,longdesc,src,usemap"),O=h.extend({},D,k("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,target,title,type,valign,value,vspace,width")),
|
12
12
|
n=document.createElement("pre"),M=/^(\s*)([\s\S]*?)(\s*)$/;h.module("ngSanitize",[]).provider("$sanitize",function(){this.$get=["$$sanitizeUri",function(a){return function(e){var d=[];F(e,s(d,function(c,b){return!/^unsafe/.test(a(c,b))}));return d.join("")}}]});h.module("ngSanitize").filter("linky",["$sanitize",function(a){var e=/((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>]/,d=/^mailto:/;return function(c,b){function g(a){a&&m.push(E(a))}function f(a,c){m.push("<a ");h.isDefined(b)&&
|
13
13
|
(m.push('target="'),m.push(b),m.push('" '));m.push('href="');m.push(a);m.push('">');g(c);m.push("</a>")}if(!c)return c;for(var l,k=c,m=[],n,p;l=k.match(e);)n=l[0],l[2]==l[3]&&(n="mailto:"+n),p=l.index,g(k.substr(0,p)),f(n,l[0].replace(d,"")),k=k.substring(p+l[0].length);g(k);return a(m.join(""))}}])})(window,window.angular);
|
14
|
+
//# sourceMappingURL=angular-sanitize.min.js.map
|
@@ -9790,7 +9790,7 @@ if ( typeof module === "object" && module && typeof module.exports === "object"
|
|
9790
9790
|
})( window );
|
9791
9791
|
|
9792
9792
|
/**
|
9793
|
-
* @license AngularJS v1.2.
|
9793
|
+
* @license AngularJS v1.2.13
|
9794
9794
|
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
9795
9795
|
* License: MIT
|
9796
9796
|
*/
|
@@ -9860,7 +9860,7 @@ function minErr(module) {
|
|
9860
9860
|
return match;
|
9861
9861
|
});
|
9862
9862
|
|
9863
|
-
message = message + '\nhttp://errors.angularjs.org/1.2.
|
9863
|
+
message = message + '\nhttp://errors.angularjs.org/1.2.13/' +
|
9864
9864
|
(module ? module + '/' : '') + code;
|
9865
9865
|
for (i = 2; i < arguments.length; i++) {
|
9866
9866
|
message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
|
@@ -9952,6 +9952,7 @@ function minErr(module) {
|
|
9952
9952
|
-assertNotHasOwnProperty,
|
9953
9953
|
-getter,
|
9954
9954
|
-getBlockElements,
|
9955
|
+
-hasOwnProperty,
|
9955
9956
|
|
9956
9957
|
*/
|
9957
9958
|
|
@@ -9967,7 +9968,7 @@ function minErr(module) {
|
|
9967
9968
|
* @returns {string} Lowercased string.
|
9968
9969
|
*/
|
9969
9970
|
var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
|
9970
|
-
|
9971
|
+
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
9971
9972
|
|
9972
9973
|
/**
|
9973
9974
|
* @ngdoc function
|
@@ -10063,7 +10064,8 @@ function isArrayLike(obj) {
|
|
10063
10064
|
* is the value of an object property or an array element and `key` is the object property key or
|
10064
10065
|
* array element index. Specifying a `context` for the function is optional.
|
10065
10066
|
*
|
10066
|
-
*
|
10067
|
+
* It is worth noting that `.forEach` does not iterate over inherited properties because it filters
|
10068
|
+
* using the `hasOwnProperty` method.
|
10067
10069
|
*
|
10068
10070
|
<pre>
|
10069
10071
|
var values = {name: 'misko', gender: 'male'};
|
@@ -10071,7 +10073,7 @@ function isArrayLike(obj) {
|
|
10071
10073
|
angular.forEach(values, function(value, key){
|
10072
10074
|
this.push(key + ': ' + value);
|
10073
10075
|
}, log);
|
10074
|
-
expect(log).toEqual(['name: misko', 'gender:male']);
|
10076
|
+
expect(log).toEqual(['name: misko', 'gender: male']);
|
10075
10077
|
</pre>
|
10076
10078
|
*
|
10077
10079
|
* @param {Object|Array} obj Object to iterate over.
|
@@ -10084,7 +10086,9 @@ function forEach(obj, iterator, context) {
|
|
10084
10086
|
if (obj) {
|
10085
10087
|
if (isFunction(obj)){
|
10086
10088
|
for (key in obj) {
|
10087
|
-
|
10089
|
+
// Need to check if hasOwnProperty exists,
|
10090
|
+
// as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
|
10091
|
+
if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
|
10088
10092
|
iterator.call(context, obj[key], key);
|
10089
10093
|
}
|
10090
10094
|
}
|
@@ -10640,7 +10644,7 @@ function shallowCopy(src, dst) {
|
|
10640
10644
|
for(var key in src) {
|
10641
10645
|
// shallowCopy is only ever called by $compile nodeLinkFn, which has control over src
|
10642
10646
|
// so we don't need to worry about using our custom hasOwnProperty here
|
10643
|
-
if (src.hasOwnProperty(key) && key.
|
10647
|
+
if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
|
10644
10648
|
dst[key] = src[key];
|
10645
10649
|
}
|
10646
10650
|
}
|
@@ -10828,7 +10832,9 @@ function fromJson(json) {
|
|
10828
10832
|
|
10829
10833
|
|
10830
10834
|
function toBoolean(value) {
|
10831
|
-
if (
|
10835
|
+
if (typeof value === 'function') {
|
10836
|
+
value = true;
|
10837
|
+
} else if (value && value.length !== 0) {
|
10832
10838
|
var v = lowercase("" + value);
|
10833
10839
|
value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
|
10834
10840
|
} else {
|
@@ -10997,6 +11003,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
|
|
10997
11003
|
<file name="index.html">
|
10998
11004
|
<div ng-controller="ngAppDemoController">
|
10999
11005
|
I can add: {{a}} + {{b}} = {{ a+b }}
|
11006
|
+
</div>
|
11000
11007
|
</file>
|
11001
11008
|
<file name="script.js">
|
11002
11009
|
angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
|
@@ -11621,11 +11628,11 @@ function setupModuleLoader(window) {
|
|
11621
11628
|
* - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
|
11622
11629
|
*/
|
11623
11630
|
var version = {
|
11624
|
-
full: '1.2.
|
11631
|
+
full: '1.2.13', // all of these placeholder strings will be replaced by grunt's
|
11625
11632
|
major: 1, // package task
|
11626
11633
|
minor: 2,
|
11627
|
-
dot:
|
11628
|
-
codeName: '
|
11634
|
+
dot: 13,
|
11635
|
+
codeName: 'romantic-transclusion'
|
11629
11636
|
};
|
11630
11637
|
|
11631
11638
|
|
@@ -11787,7 +11794,7 @@ function publishExternalAPI(angular){
|
|
11787
11794
|
* - [`after()`](http://api.jquery.com/after/)
|
11788
11795
|
* - [`append()`](http://api.jquery.com/append/)
|
11789
11796
|
* - [`attr()`](http://api.jquery.com/attr/)
|
11790
|
-
* - [`bind()`](http://api.jquery.com/
|
11797
|
+
* - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
|
11791
11798
|
* - [`children()`](http://api.jquery.com/children/) - Does not support selectors
|
11792
11799
|
* - [`clone()`](http://api.jquery.com/clone/)
|
11793
11800
|
* - [`contents()`](http://api.jquery.com/contents/)
|
@@ -11801,6 +11808,7 @@ function publishExternalAPI(angular){
|
|
11801
11808
|
* - [`next()`](http://api.jquery.com/next/) - Does not support selectors
|
11802
11809
|
* - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
|
11803
11810
|
* - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
|
11811
|
+
* - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
|
11804
11812
|
* - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
|
11805
11813
|
* - [`prepend()`](http://api.jquery.com/prepend/)
|
11806
11814
|
* - [`prop()`](http://api.jquery.com/prop/)
|
@@ -11813,7 +11821,7 @@ function publishExternalAPI(angular){
|
|
11813
11821
|
* - [`text()`](http://api.jquery.com/text/)
|
11814
11822
|
* - [`toggleClass()`](http://api.jquery.com/toggleClass/)
|
11815
11823
|
* - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
|
11816
|
-
* - [`unbind()`](http://api.jquery.com/
|
11824
|
+
* - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces
|
11817
11825
|
* - [`val()`](http://api.jquery.com/val/)
|
11818
11826
|
* - [`wrap()`](http://api.jquery.com/wrap/)
|
11819
11827
|
*
|
@@ -11853,6 +11861,14 @@ var jqCache = JQLite.cache = {},
|
|
11853
11861
|
? function(element, type, fn) {element.removeEventListener(type, fn, false); }
|
11854
11862
|
: function(element, type, fn) {element.detachEvent('on' + type, fn); });
|
11855
11863
|
|
11864
|
+
/*
|
11865
|
+
* !!! This is an undocumented "private" function !!!
|
11866
|
+
*/
|
11867
|
+
var jqData = JQLite._data = function(node) {
|
11868
|
+
//jQuery always returns an object on cache miss
|
11869
|
+
return this.cache[node[this.expando]] || {};
|
11870
|
+
};
|
11871
|
+
|
11856
11872
|
function jqNextId() { return ++jqId; }
|
11857
11873
|
|
11858
11874
|
|
@@ -11921,6 +11937,9 @@ function JQLite(element) {
|
|
11921
11937
|
if (element instanceof JQLite) {
|
11922
11938
|
return element;
|
11923
11939
|
}
|
11940
|
+
if (isString(element)) {
|
11941
|
+
element = trim(element);
|
11942
|
+
}
|
11924
11943
|
if (!(this instanceof JQLite)) {
|
11925
11944
|
if (isString(element) && element.charAt(0) != '<') {
|
11926
11945
|
throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
|
@@ -12392,7 +12411,10 @@ function createEventHandler(element, events) {
|
|
12392
12411
|
return event.defaultPrevented || event.returnValue === false;
|
12393
12412
|
};
|
12394
12413
|
|
12395
|
-
|
12414
|
+
// Copy event handlers in case event handlers array is modified during execution.
|
12415
|
+
var eventHandlersCopy = shallowCopy(events[type || event.type] || []);
|
12416
|
+
|
12417
|
+
forEach(eventHandlersCopy, function(fn) {
|
12396
12418
|
fn.call(element, event);
|
12397
12419
|
});
|
12398
12420
|
|
@@ -12488,6 +12510,19 @@ forEach({
|
|
12488
12510
|
|
12489
12511
|
off: jqLiteOff,
|
12490
12512
|
|
12513
|
+
one: function(element, type, fn) {
|
12514
|
+
element = jqLite(element);
|
12515
|
+
|
12516
|
+
//add the listener twice so that when it is called
|
12517
|
+
//you can remove the original function and still be
|
12518
|
+
//able to call element.off(ev, fn) normally
|
12519
|
+
element.on(type, function onFn() {
|
12520
|
+
element.off(type, fn);
|
12521
|
+
element.off(type, onFn);
|
12522
|
+
});
|
12523
|
+
element.on(type, fn);
|
12524
|
+
},
|
12525
|
+
|
12491
12526
|
replaceWith: function(element, replaceNode) {
|
12492
12527
|
var index, parent = element.parentNode;
|
12493
12528
|
jqLiteDealoc(element);
|
@@ -13050,11 +13085,9 @@ function annotate(fn) {
|
|
13050
13085
|
* @param {(Object|function())} provider If the provider is:
|
13051
13086
|
*
|
13052
13087
|
* - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
|
13053
|
-
*
|
13054
|
-
*
|
13055
|
-
*
|
13056
|
-
* {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as
|
13057
|
-
* `object`.
|
13088
|
+
* {@link AUTO.$injector#invoke $injector.invoke()} when an instance needs to be created.
|
13089
|
+
* - `Constructor`: a new instance of the provider will be created using
|
13090
|
+
* {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as `object`.
|
13058
13091
|
*
|
13059
13092
|
* @returns {Object} registered provider instance
|
13060
13093
|
|
@@ -13170,7 +13203,7 @@ function annotate(fn) {
|
|
13170
13203
|
* constructor function that will be used to instantiate the service instance.
|
13171
13204
|
*
|
13172
13205
|
* You should use {@link AUTO.$provide#methods_service $provide.service(class)} if you define your service
|
13173
|
-
* as a type/class.
|
13206
|
+
* as a type/class.
|
13174
13207
|
*
|
13175
13208
|
* @param {string} name The name of the instance.
|
13176
13209
|
* @param {Function} constructor A class (constructor function) that will be instantiated.
|
@@ -13178,20 +13211,24 @@ function annotate(fn) {
|
|
13178
13211
|
*
|
13179
13212
|
* @example
|
13180
13213
|
* Here is an example of registering a service using
|
13181
|
-
* {@link AUTO.$provide#methods_service $provide.service(class)}
|
13214
|
+
* {@link AUTO.$provide#methods_service $provide.service(class)}.
|
13182
13215
|
* <pre>
|
13183
|
-
*
|
13184
|
-
*
|
13185
|
-
*
|
13186
|
-
*
|
13187
|
-
*
|
13188
|
-
*
|
13216
|
+
* var Ping = function($http) {
|
13217
|
+
* this.$http = $http;
|
13218
|
+
* };
|
13219
|
+
*
|
13220
|
+
* Ping.$inject = ['$http'];
|
13221
|
+
*
|
13222
|
+
* Ping.prototype.send = function() {
|
13223
|
+
* return this.$http.get('/ping');
|
13224
|
+
* };
|
13225
|
+
* $provide.service('ping', Ping);
|
13189
13226
|
* </pre>
|
13190
13227
|
* You would then inject and use this service like this:
|
13191
13228
|
* <pre>
|
13192
|
-
* someModule.controller
|
13193
|
-
* ping.send()
|
13194
|
-
* ]
|
13229
|
+
* someModule.controller('Ctrl', ['ping', function(ping) {
|
13230
|
+
* ping.send();
|
13231
|
+
* }]);
|
13195
13232
|
* </pre>
|
13196
13233
|
*/
|
13197
13234
|
|
@@ -13283,7 +13320,7 @@ function annotate(fn) {
|
|
13283
13320
|
* Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
|
13284
13321
|
* calls to {@link ng.$log#error $log.warn()}.
|
13285
13322
|
* <pre>
|
13286
|
-
* $
|
13323
|
+
* $provide.decorator('$log', ['$delegate', function($delegate) {
|
13287
13324
|
* $delegate.warn = $delegate.error;
|
13288
13325
|
* return $delegate;
|
13289
13326
|
* }]);
|
@@ -13436,6 +13473,11 @@ function createInjector(modulesToLoad) {
|
|
13436
13473
|
path.unshift(serviceName);
|
13437
13474
|
cache[serviceName] = INSTANTIATING;
|
13438
13475
|
return cache[serviceName] = factory(serviceName);
|
13476
|
+
} catch (err) {
|
13477
|
+
if (cache[serviceName] === INSTANTIATING) {
|
13478
|
+
delete cache[serviceName];
|
13479
|
+
}
|
13480
|
+
throw err;
|
13439
13481
|
} finally {
|
13440
13482
|
path.shift();
|
13441
13483
|
}
|
@@ -13656,6 +13698,28 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
13656
13698
|
$provide.factory(key, factory);
|
13657
13699
|
};
|
13658
13700
|
|
13701
|
+
/**
|
13702
|
+
* @ngdoc function
|
13703
|
+
* @name ng.$animateProvider#classNameFilter
|
13704
|
+
* @methodOf ng.$animateProvider
|
13705
|
+
*
|
13706
|
+
* @description
|
13707
|
+
* Sets and/or returns the CSS class regular expression that is checked when performing
|
13708
|
+
* an animation. Upon bootstrap the classNameFilter value is not set at all and will
|
13709
|
+
* therefore enable $animate to attempt to perform an animation on any element.
|
13710
|
+
* When setting the classNameFilter value, animations will only be performed on elements
|
13711
|
+
* that successfully match the filter expression. This in turn can boost performance
|
13712
|
+
* for low-powered devices as well as applications containing a lot of structural operations.
|
13713
|
+
* @param {RegExp=} expression The className expression which will be checked against all animations
|
13714
|
+
* @return {RegExp} The current CSS className expression value. If null then there is no expression value
|
13715
|
+
*/
|
13716
|
+
this.classNameFilter = function(expression) {
|
13717
|
+
if(arguments.length === 1) {
|
13718
|
+
this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
|
13719
|
+
}
|
13720
|
+
return this.$$classNameFilter;
|
13721
|
+
};
|
13722
|
+
|
13659
13723
|
this.$get = ['$timeout', function($timeout) {
|
13660
13724
|
|
13661
13725
|
/**
|
@@ -13795,6 +13859,29 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
13795
13859
|
done && $timeout(done, 0, false);
|
13796
13860
|
},
|
13797
13861
|
|
13862
|
+
/**
|
13863
|
+
*
|
13864
|
+
* @ngdoc function
|
13865
|
+
* @name ng.$animate#setClass
|
13866
|
+
* @methodOf ng.$animate
|
13867
|
+
* @function
|
13868
|
+
* @description Adds and/or removes the given CSS classes to and from the element.
|
13869
|
+
* Once complete, the done() callback will be fired (if provided).
|
13870
|
+
* @param {jQuery/jqLite element} element the element which will it's CSS classes changed
|
13871
|
+
* removed from it
|
13872
|
+
* @param {string} add the CSS classes which will be added to the element
|
13873
|
+
* @param {string} remove the CSS class which will be removed from the element
|
13874
|
+
* @param {function=} done the callback function (if provided) that will be fired after the
|
13875
|
+
* CSS classes have been set on the element
|
13876
|
+
*/
|
13877
|
+
setClass : function(element, add, remove, done) {
|
13878
|
+
forEach(element, function (element) {
|
13879
|
+
jqLiteAddClass(element, add);
|
13880
|
+
jqLiteRemoveClass(element, remove);
|
13881
|
+
});
|
13882
|
+
done && $timeout(done, 0, false);
|
13883
|
+
},
|
13884
|
+
|
13798
13885
|
enabled : noop
|
13799
13886
|
};
|
13800
13887
|
}];
|
@@ -13948,8 +14035,9 @@ function Browser(window, document, $log, $sniffer) {
|
|
13948
14035
|
* @param {boolean=} replace Should new url replace current history record ?
|
13949
14036
|
*/
|
13950
14037
|
self.url = function(url, replace) {
|
13951
|
-
// Android Browser BFCache causes location reference to become stale.
|
14038
|
+
// Android Browser BFCache causes location, history reference to become stale.
|
13952
14039
|
if (location !== window.location) location = window.location;
|
14040
|
+
if (history !== window.history) history = window.history;
|
13953
14041
|
|
13954
14042
|
// setter
|
13955
14043
|
if (url) {
|
@@ -14001,7 +14089,7 @@ function Browser(window, document, $log, $sniffer) {
|
|
14001
14089
|
* @description
|
14002
14090
|
* Register callback function that will be called, when url changes.
|
14003
14091
|
*
|
14004
|
-
* It's only called when the url is changed
|
14092
|
+
* It's only called when the url is changed from outside of angular:
|
14005
14093
|
* - user types different url into address bar
|
14006
14094
|
* - user clicks on history (forward/back) button
|
14007
14095
|
* - user clicks on a link
|
@@ -14043,7 +14131,7 @@ function Browser(window, document, $log, $sniffer) {
|
|
14043
14131
|
/**
|
14044
14132
|
* @name ng.$browser#baseHref
|
14045
14133
|
* @methodOf ng.$browser
|
14046
|
-
*
|
14134
|
+
*
|
14047
14135
|
* @description
|
14048
14136
|
* Returns current <base href>
|
14049
14137
|
* (always relative - without domain)
|
@@ -14052,7 +14140,7 @@ function Browser(window, document, $log, $sniffer) {
|
|
14052
14140
|
*/
|
14053
14141
|
self.baseHref = function() {
|
14054
14142
|
var href = baseElement.attr('href');
|
14055
|
-
return href ? href.replace(/^https
|
14143
|
+
return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
|
14056
14144
|
};
|
14057
14145
|
|
14058
14146
|
//////////////////////////////////////////////////////////////
|
@@ -14074,13 +14162,13 @@ function Browser(window, document, $log, $sniffer) {
|
|
14074
14162
|
* It is not meant to be used directly, use the $cookie service instead.
|
14075
14163
|
*
|
14076
14164
|
* The return values vary depending on the arguments that the method was called with as follows:
|
14077
|
-
*
|
14165
|
+
*
|
14078
14166
|
* - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify
|
14079
14167
|
* it
|
14080
14168
|
* - cookies(name, value) -> set name to value, if value is undefined delete the cookie
|
14081
14169
|
* - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that
|
14082
14170
|
* way)
|
14083
|
-
*
|
14171
|
+
*
|
14084
14172
|
* @returns {Object} Hash of all cookies (if called without any parameter)
|
14085
14173
|
*/
|
14086
14174
|
self.cookies = function(name, value) {
|
@@ -14458,7 +14546,7 @@ function $TemplateCacheProvider() {
|
|
14458
14546
|
* @function
|
14459
14547
|
*
|
14460
14548
|
* @description
|
14461
|
-
* Compiles
|
14549
|
+
* Compiles an HTML string or DOM into a template and produces a template function, which
|
14462
14550
|
* can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
|
14463
14551
|
*
|
14464
14552
|
* The compilation is a process of walking the DOM tree and matching DOM elements to
|
@@ -14858,13 +14946,17 @@ function $TemplateCacheProvider() {
|
|
14858
14946
|
<div compile="html"></div>
|
14859
14947
|
</div>
|
14860
14948
|
</doc:source>
|
14861
|
-
<doc:
|
14949
|
+
<doc:protractor>
|
14862
14950
|
it('should auto compile', function() {
|
14863
|
-
|
14864
|
-
|
14865
|
-
|
14951
|
+
var textarea = $('textarea');
|
14952
|
+
var output = $('div[compile]');
|
14953
|
+
// The initial state reads 'Hello Angular'.
|
14954
|
+
expect(output.getText()).toBe('Hello Angular');
|
14955
|
+
textarea.clear();
|
14956
|
+
textarea.sendKeys('{{name}}!');
|
14957
|
+
expect(output.getText()).toBe('Angular!');
|
14866
14958
|
});
|
14867
|
-
</doc:
|
14959
|
+
</doc:protractor>
|
14868
14960
|
</doc:example>
|
14869
14961
|
|
14870
14962
|
*
|
@@ -14903,14 +14995,14 @@ function $TemplateCacheProvider() {
|
|
14903
14995
|
* example would not point to the clone, but rather to the original template that was cloned. In
|
14904
14996
|
* this case, you can access the clone via the cloneAttachFn:
|
14905
14997
|
* <pre>
|
14906
|
-
* var
|
14998
|
+
* var templateElement = angular.element('<p>{{total}}</p>'),
|
14907
14999
|
* scope = ....;
|
14908
15000
|
*
|
14909
|
-
* var clonedElement = $compile(
|
15001
|
+
* var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
|
14910
15002
|
* //attach the clone to DOM document at the right place
|
14911
15003
|
* });
|
14912
15004
|
*
|
14913
|
-
* //now we have reference to the cloned DOM via `
|
15005
|
+
* //now we have reference to the cloned DOM via `clonedElement`
|
14914
15006
|
* </pre>
|
14915
15007
|
*
|
14916
15008
|
*
|
@@ -14932,7 +15024,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
14932
15024
|
var hasDirectives = {},
|
14933
15025
|
Suffix = 'Directive',
|
14934
15026
|
COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
|
14935
|
-
CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)
|
15027
|
+
CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
|
15028
|
+
TABLE_CONTENT_REGEXP = /^<\s*(tr|th|td|tbody)(\s+[^>]*)?>/i;
|
14936
15029
|
|
14937
15030
|
// Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
|
14938
15031
|
// The assumption is that future DOM event attribute names will begin with
|
@@ -15119,8 +15212,16 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15119
15212
|
* @param {string} oldClasses The former CSS className value
|
15120
15213
|
*/
|
15121
15214
|
$updateClass : function(newClasses, oldClasses) {
|
15122
|
-
|
15123
|
-
|
15215
|
+
var toAdd = tokenDifference(newClasses, oldClasses);
|
15216
|
+
var toRemove = tokenDifference(oldClasses, newClasses);
|
15217
|
+
|
15218
|
+
if(toAdd.length === 0) {
|
15219
|
+
$animate.removeClass(this.$$element, toRemove);
|
15220
|
+
} else if(toRemove.length === 0) {
|
15221
|
+
$animate.addClass(this.$$element, toAdd);
|
15222
|
+
} else {
|
15223
|
+
$animate.setClass(this.$$element, toAdd, toRemove);
|
15224
|
+
}
|
15124
15225
|
},
|
15125
15226
|
|
15126
15227
|
/**
|
@@ -15252,6 +15353,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15252
15353
|
var compositeLinkFn =
|
15253
15354
|
compileNodes($compileNodes, transcludeFn, $compileNodes,
|
15254
15355
|
maxPriority, ignoreDirective, previousCompileContext);
|
15356
|
+
safeAddClass($compileNodes, 'ng-scope');
|
15255
15357
|
return function publicLinkFn(scope, cloneConnectFn, transcludeControllers){
|
15256
15358
|
assertArg(scope, 'scope');
|
15257
15359
|
// important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
|
@@ -15266,12 +15368,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15266
15368
|
|
15267
15369
|
// Attach scope only to non-text nodes.
|
15268
15370
|
for(var i = 0, ii = $linkNode.length; i<ii; i++) {
|
15269
|
-
var node = $linkNode[i]
|
15270
|
-
|
15371
|
+
var node = $linkNode[i],
|
15372
|
+
nodeType = node.nodeType;
|
15373
|
+
if (nodeType === 1 /* element */ || nodeType === 9 /* document */) {
|
15271
15374
|
$linkNode.eq(i).data('$scope', scope);
|
15272
15375
|
}
|
15273
15376
|
}
|
15274
|
-
|
15377
|
+
|
15275
15378
|
if (cloneConnectFn) cloneConnectFn($linkNode, scope);
|
15276
15379
|
if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode);
|
15277
15380
|
return $linkNode;
|
@@ -15299,15 +15402,15 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15299
15402
|
* @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
|
15300
15403
|
* the rootElement must be set the jqLite collection of the compile root. This is
|
15301
15404
|
* needed so that the jqLite collection items can be replaced with widgets.
|
15302
|
-
* @param {number=}
|
15405
|
+
* @param {number=} maxPriority Max directive priority.
|
15303
15406
|
* @returns {?function} A composite linking function of all of the matched directives or null.
|
15304
15407
|
*/
|
15305
15408
|
function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
|
15306
15409
|
previousCompileContext) {
|
15307
15410
|
var linkFns = [],
|
15308
|
-
|
15411
|
+
attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound;
|
15309
15412
|
|
15310
|
-
for(var i = 0; i < nodeList.length; i++) {
|
15413
|
+
for (var i = 0; i < nodeList.length; i++) {
|
15311
15414
|
attrs = new Attributes();
|
15312
15415
|
|
15313
15416
|
// we must always refer to nodeList[i] since the nodes can be replaced underneath us.
|
@@ -15319,16 +15422,19 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15319
15422
|
null, [], [], previousCompileContext)
|
15320
15423
|
: null;
|
15321
15424
|
|
15425
|
+
if (nodeLinkFn && nodeLinkFn.scope) {
|
15426
|
+
safeAddClass(jqLite(nodeList[i]), 'ng-scope');
|
15427
|
+
}
|
15428
|
+
|
15322
15429
|
childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
|
15323
|
-
!nodeList[i].childNodes ||
|
15324
|
-
!
|
15430
|
+
!(childNodes = nodeList[i].childNodes) ||
|
15431
|
+
!childNodes.length)
|
15325
15432
|
? null
|
15326
|
-
: compileNodes(
|
15433
|
+
: compileNodes(childNodes,
|
15327
15434
|
nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
|
15328
15435
|
|
15329
|
-
linkFns.push(nodeLinkFn);
|
15330
|
-
|
15331
|
-
linkFnFound = (linkFnFound || nodeLinkFn || childLinkFn);
|
15436
|
+
linkFns.push(nodeLinkFn, childLinkFn);
|
15437
|
+
linkFnFound = linkFnFound || nodeLinkFn || childLinkFn;
|
15332
15438
|
//use the previous context only for the first element in the virtual group
|
15333
15439
|
previousCompileContext = null;
|
15334
15440
|
}
|
@@ -15340,9 +15446,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15340
15446
|
var nodeLinkFn, childLinkFn, node, $node, childScope, childTranscludeFn, i, ii, n;
|
15341
15447
|
|
15342
15448
|
// copy nodeList so that linking doesn't break due to live list updates.
|
15343
|
-
var
|
15344
|
-
|
15345
|
-
|
15449
|
+
var nodeListLength = nodeList.length,
|
15450
|
+
stableNodeList = new Array(nodeListLength);
|
15451
|
+
for (i = 0; i < nodeListLength; i++) {
|
15452
|
+
stableNodeList[i] = nodeList[i];
|
15346
15453
|
}
|
15347
15454
|
|
15348
15455
|
for(i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
|
@@ -15355,7 +15462,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15355
15462
|
if (nodeLinkFn.scope) {
|
15356
15463
|
childScope = scope.$new();
|
15357
15464
|
$node.data('$scope', childScope);
|
15358
|
-
safeAddClass($node, 'ng-scope');
|
15359
15465
|
} else {
|
15360
15466
|
childScope = scope;
|
15361
15467
|
}
|
@@ -15438,9 +15544,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15438
15544
|
|
15439
15545
|
nName = directiveNormalize(name.toLowerCase());
|
15440
15546
|
attrsMap[nName] = name;
|
15441
|
-
attrs[nName] = value = trim(
|
15442
|
-
? decodeURIComponent(node.getAttribute(name, 2))
|
15443
|
-
: attr.value);
|
15547
|
+
attrs[nName] = value = trim(attr.value);
|
15444
15548
|
if (getBooleanAttrName(node, nName)) {
|
15445
15549
|
attrs[nName] = true; // presence means true
|
15446
15550
|
}
|
@@ -15569,7 +15673,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15569
15673
|
templateDirective = previousCompileContext.templateDirective,
|
15570
15674
|
nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
|
15571
15675
|
hasTranscludeDirective = false,
|
15572
|
-
hasElementTranscludeDirective =
|
15676
|
+
hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
|
15573
15677
|
$compileNode = templateAttrs.$$element = jqLite(compileNode),
|
15574
15678
|
directive,
|
15575
15679
|
directiveName,
|
@@ -15623,7 +15727,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15623
15727
|
hasTranscludeDirective = true;
|
15624
15728
|
|
15625
15729
|
// Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
|
15626
|
-
// This option should only be used by directives that know how to
|
15730
|
+
// This option should only be used by directives that know how to safely handle element transclusion,
|
15627
15731
|
// where the transcluded nodes are added or replaced after linking.
|
15628
15732
|
if (!directive.$$tlb) {
|
15629
15733
|
assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
|
@@ -15670,9 +15774,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15670
15774
|
|
15671
15775
|
if (directive.replace) {
|
15672
15776
|
replaceDirective = directive;
|
15673
|
-
$template =
|
15674
|
-
trim(directiveValue) +
|
15675
|
-
'</div>').contents();
|
15777
|
+
$template = directiveTemplateContents(directiveValue);
|
15676
15778
|
compileNode = $template[0];
|
15677
15779
|
|
15678
15780
|
if ($template.length != 1 || compileNode.nodeType !== 1) {
|
@@ -15743,6 +15845,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15743
15845
|
|
15744
15846
|
nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
|
15745
15847
|
nodeLinkFn.transclude = hasTranscludeDirective && childTranscludeFn;
|
15848
|
+
previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
|
15746
15849
|
|
15747
15850
|
// might be normal or delayed nodeLinkFn depending on if templateUrl is present
|
15748
15851
|
return nodeLinkFn;
|
@@ -16070,6 +16173,28 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
16070
16173
|
}
|
16071
16174
|
|
16072
16175
|
|
16176
|
+
function directiveTemplateContents(template) {
|
16177
|
+
var type;
|
16178
|
+
template = trim(template);
|
16179
|
+
if ((type = TABLE_CONTENT_REGEXP.exec(template))) {
|
16180
|
+
type = type[1].toLowerCase();
|
16181
|
+
var table = jqLite('<table>' + template + '</table>'),
|
16182
|
+
tbody = table.children('tbody'),
|
16183
|
+
leaf = /(td|th)/.test(type) && table.find('tr');
|
16184
|
+
if (tbody.length && type !== 'tbody') {
|
16185
|
+
table = tbody;
|
16186
|
+
}
|
16187
|
+
if (leaf && leaf.length) {
|
16188
|
+
table = leaf;
|
16189
|
+
}
|
16190
|
+
return table.contents();
|
16191
|
+
}
|
16192
|
+
return jqLite('<div>' +
|
16193
|
+
template +
|
16194
|
+
'</div>').contents();
|
16195
|
+
}
|
16196
|
+
|
16197
|
+
|
16073
16198
|
function compileTemplateUrl(directives, $compileNode, tAttrs,
|
16074
16199
|
$rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
|
16075
16200
|
var linkQueue = [],
|
@@ -16094,7 +16219,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
16094
16219
|
content = denormalizeTemplate(content);
|
16095
16220
|
|
16096
16221
|
if (origAsyncDirective.replace) {
|
16097
|
-
$template =
|
16222
|
+
$template = directiveTemplateContents(content);
|
16098
16223
|
compileNode = $template[0];
|
16099
16224
|
|
16100
16225
|
if ($template.length != 1 || compileNode.nodeType !== 1) {
|
@@ -16138,9 +16263,18 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
16138
16263
|
linkNode = $compileNode[0];
|
16139
16264
|
|
16140
16265
|
if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
|
16141
|
-
|
16142
|
-
|
16266
|
+
var oldClasses = beforeTemplateLinkNode.className;
|
16267
|
+
|
16268
|
+
if (!(previousCompileContext.hasElementTranscludeDirective &&
|
16269
|
+
origAsyncDirective.replace)) {
|
16270
|
+
// it was cloned therefore we have to clone as well.
|
16271
|
+
linkNode = jqLiteClone(compileNode);
|
16272
|
+
}
|
16273
|
+
|
16143
16274
|
replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
|
16275
|
+
|
16276
|
+
// Copy in CSS classes from original node
|
16277
|
+
safeAddClass(jqLite(linkNode), oldClasses);
|
16144
16278
|
}
|
16145
16279
|
if (afterTemplateNodeLinkFn.transclude) {
|
16146
16280
|
childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude);
|
@@ -16388,7 +16522,7 @@ function directiveNormalize(name) {
|
|
16388
16522
|
*
|
16389
16523
|
*
|
16390
16524
|
* @param {string} name Normalized element attribute name of the property to modify. The name is
|
16391
|
-
*
|
16525
|
+
* reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
|
16392
16526
|
* property to the original name.
|
16393
16527
|
* @param {string} value Value to set the attribute to. The value can be an interpolated string.
|
16394
16528
|
*/
|
@@ -16526,8 +16660,7 @@ function $ControllerProvider() {
|
|
16526
16660
|
* @requires $window
|
16527
16661
|
*
|
16528
16662
|
* @description
|
16529
|
-
* A {@link angular.element jQuery
|
16530
|
-
* element.
|
16663
|
+
* A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
|
16531
16664
|
*/
|
16532
16665
|
function $DocumentProvider(){
|
16533
16666
|
this.$get = ['$window', function(window){
|
@@ -16686,9 +16819,9 @@ function $HttpProvider() {
|
|
16686
16819
|
common: {
|
16687
16820
|
'Accept': 'application/json, text/plain, */*'
|
16688
16821
|
},
|
16689
|
-
post: CONTENT_TYPE_APPLICATION_JSON,
|
16690
|
-
put: CONTENT_TYPE_APPLICATION_JSON,
|
16691
|
-
patch: CONTENT_TYPE_APPLICATION_JSON
|
16822
|
+
post: copy(CONTENT_TYPE_APPLICATION_JSON),
|
16823
|
+
put: copy(CONTENT_TYPE_APPLICATION_JSON),
|
16824
|
+
patch: copy(CONTENT_TYPE_APPLICATION_JSON)
|
16692
16825
|
},
|
16693
16826
|
|
16694
16827
|
xsrfCookieName: 'XSRF-TOKEN',
|
@@ -16797,32 +16930,15 @@ function $HttpProvider() {
|
|
16797
16930
|
* will result in the success callback being called. Note that if the response is a redirect,
|
16798
16931
|
* XMLHttpRequest will transparently follow it, meaning that the error callback will not be
|
16799
16932
|
* called for such responses.
|
16800
|
-
*
|
16801
|
-
* # Calling $http from outside AngularJS
|
16802
|
-
* The `$http` service will not actually send the request until the next `$digest()` is
|
16803
|
-
* executed. Normally this is not an issue, since almost all the time your call to `$http` will
|
16804
|
-
* be from within a `$apply()` block.
|
16805
|
-
* If you are calling `$http` from outside Angular, then you should wrap it in a call to
|
16806
|
-
* `$apply` to cause a $digest to occur and also to handle errors in the block correctly.
|
16807
|
-
*
|
16808
|
-
* ```
|
16809
|
-
* $scope.$apply(function() {
|
16810
|
-
* $http(...);
|
16811
|
-
* });
|
16812
|
-
* ```
|
16813
16933
|
*
|
16814
16934
|
* # Writing Unit Tests that use $http
|
16815
|
-
* When unit testing
|
16816
|
-
*
|
16817
|
-
*
|
16818
|
-
* code that calls the `$http()` method inside a $apply block as explained in the previous
|
16819
|
-
* section.
|
16935
|
+
* When unit testing (using {@link api/ngMock ngMock}), it is necessary to call
|
16936
|
+
* {@link api/ngMock.$httpBackend#methods_flush $httpBackend.flush()} to flush each pending
|
16937
|
+
* request using trained responses.
|
16820
16938
|
*
|
16821
16939
|
* ```
|
16822
16940
|
* $httpBackend.expectGET(...);
|
16823
|
-
* $
|
16824
|
-
* $http.get(...);
|
16825
|
-
* });
|
16941
|
+
* $http.get(...);
|
16826
16942
|
* $httpBackend.flush();
|
16827
16943
|
* ```
|
16828
16944
|
*
|
@@ -16866,7 +16982,15 @@ function $HttpProvider() {
|
|
16866
16982
|
* `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }.
|
16867
16983
|
*
|
16868
16984
|
* The defaults can also be set at runtime via the `$http.defaults` object in the same
|
16869
|
-
* fashion.
|
16985
|
+
* fashion. For example:
|
16986
|
+
*
|
16987
|
+
* ```
|
16988
|
+
* module.run(function($http) {
|
16989
|
+
* $http.defaults.headers.common.Authentication = 'Basic YmVlcDpib29w'
|
16990
|
+
* });
|
16991
|
+
* ```
|
16992
|
+
*
|
16993
|
+
* In addition, you can supply a `headers` property in the config object passed when
|
16870
16994
|
* calling `$http(config)`, which overrides the defaults without changing them globally.
|
16871
16995
|
*
|
16872
16996
|
*
|
@@ -16890,7 +17014,9 @@ function $HttpProvider() {
|
|
16890
17014
|
* properties. These properties are by default an array of transform functions, which allows you
|
16891
17015
|
* to `push` or `unshift` a new transformation function into the transformation chain. You can
|
16892
17016
|
* also decide to completely override any default transformations by assigning your
|
16893
|
-
* transformation functions to these properties directly without the array wrapper.
|
17017
|
+
* transformation functions to these properties directly without the array wrapper. These defaults
|
17018
|
+
* are again available on the $http factory at run-time, which may be useful if you have run-time
|
17019
|
+
* services you wish to be involved in your transformations.
|
16894
17020
|
*
|
16895
17021
|
* Similarly, to locally override the request/response transforms, augment the
|
16896
17022
|
* `transformRequest` and/or `transformResponse` properties of the configuration object passed
|
@@ -16984,19 +17110,20 @@ function $HttpProvider() {
|
|
16984
17110
|
* return responseOrNewPromise
|
16985
17111
|
* }
|
16986
17112
|
* return $q.reject(rejection);
|
16987
|
-
* }
|
16988
|
-
* }
|
17113
|
+
* }
|
17114
|
+
* };
|
16989
17115
|
* });
|
16990
17116
|
*
|
16991
17117
|
* $httpProvider.interceptors.push('myHttpInterceptor');
|
16992
17118
|
*
|
16993
17119
|
*
|
16994
|
-
* // register the interceptor via an anonymous factory
|
17120
|
+
* // alternatively, register the interceptor via an anonymous factory
|
16995
17121
|
* $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
|
16996
17122
|
* return {
|
16997
17123
|
* 'request': function(config) {
|
16998
17124
|
* // same as above
|
16999
17125
|
* },
|
17126
|
+
*
|
17000
17127
|
* 'response': function(response) {
|
17001
17128
|
* // same as above
|
17002
17129
|
* }
|
@@ -17103,7 +17230,8 @@ function $HttpProvider() {
|
|
17103
17230
|
* for added security.
|
17104
17231
|
*
|
17105
17232
|
* The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
|
17106
|
-
* properties of either $httpProvider.defaults,
|
17233
|
+
* properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
|
17234
|
+
* or the per-request config object.
|
17107
17235
|
*
|
17108
17236
|
*
|
17109
17237
|
* @param {object} config Object describing the request to be made and how it should be
|
@@ -17167,14 +17295,14 @@ function $HttpProvider() {
|
|
17167
17295
|
<option>JSONP</option>
|
17168
17296
|
</select>
|
17169
17297
|
<input type="text" ng-model="url" size="80"/>
|
17170
|
-
<button ng-click="fetch()">fetch</button><br>
|
17171
|
-
<button ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
|
17172
|
-
<button
|
17298
|
+
<button id="fetchbtn" ng-click="fetch()">fetch</button><br>
|
17299
|
+
<button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
|
17300
|
+
<button id="samplejsonpbtn"
|
17173
17301
|
ng-click="updateModel('JSONP',
|
17174
17302
|
'http://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
|
17175
17303
|
Sample JSONP
|
17176
17304
|
</button>
|
17177
|
-
<button
|
17305
|
+
<button id="invalidjsonpbtn"
|
17178
17306
|
ng-click="updateModel('JSONP', 'http://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
|
17179
17307
|
Invalid JSONP
|
17180
17308
|
</button>
|
@@ -17211,27 +17339,34 @@ function $HttpProvider() {
|
|
17211
17339
|
<file name="http-hello.html">
|
17212
17340
|
Hello, $http!
|
17213
17341
|
</file>
|
17214
|
-
<file name="
|
17342
|
+
<file name="protractorTest.js">
|
17343
|
+
var status = element(by.binding('status'));
|
17344
|
+
var data = element(by.binding('data'));
|
17345
|
+
var fetchBtn = element(by.id('fetchbtn'));
|
17346
|
+
var sampleGetBtn = element(by.id('samplegetbtn'));
|
17347
|
+
var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
|
17348
|
+
var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
|
17349
|
+
|
17215
17350
|
it('should make an xhr GET request', function() {
|
17216
|
-
|
17217
|
-
|
17218
|
-
expect(
|
17219
|
-
expect(
|
17351
|
+
sampleGetBtn.click();
|
17352
|
+
fetchBtn.click();
|
17353
|
+
expect(status.getText()).toMatch('200');
|
17354
|
+
expect(data.getText()).toMatch(/Hello, \$http!/)
|
17220
17355
|
});
|
17221
17356
|
|
17222
17357
|
it('should make a JSONP request to angularjs.org', function() {
|
17223
|
-
|
17224
|
-
|
17225
|
-
expect(
|
17226
|
-
expect(
|
17358
|
+
sampleJsonpBtn.click();
|
17359
|
+
fetchBtn.click();
|
17360
|
+
expect(status.getText()).toMatch('200');
|
17361
|
+
expect(data.getText()).toMatch(/Super Hero!/);
|
17227
17362
|
});
|
17228
17363
|
|
17229
17364
|
it('should make JSONP request to invalid URL and invoke the error handler',
|
17230
17365
|
function() {
|
17231
|
-
|
17232
|
-
|
17233
|
-
expect(
|
17234
|
-
expect(
|
17366
|
+
invalidJsonpBtn.click();
|
17367
|
+
fetchBtn.click();
|
17368
|
+
expect(status.getText()).toMatch('0');
|
17369
|
+
expect(data.getText()).toMatch('Request failed');
|
17235
17370
|
});
|
17236
17371
|
</file>
|
17237
17372
|
</example>
|
@@ -17612,14 +17747,19 @@ function $HttpProvider() {
|
|
17612
17747
|
}];
|
17613
17748
|
}
|
17614
17749
|
|
17615
|
-
|
17616
|
-
|
17617
|
-
|
17618
|
-
|
17619
|
-
|
17620
|
-
|
17621
|
-
|
17750
|
+
function createXhr(method) {
|
17751
|
+
//if IE and the method is not RFC2616 compliant, or if XMLHttpRequest
|
17752
|
+
//is not available, try getting an ActiveXObject. Otherwise, use XMLHttpRequest
|
17753
|
+
//if it is available
|
17754
|
+
if (msie <= 8 && (!method.match(/^(get|post|head|put|delete|options)$/i) ||
|
17755
|
+
!window.XMLHttpRequest)) {
|
17756
|
+
return new window.ActiveXObject("Microsoft.XMLHTTP");
|
17757
|
+
} else if (window.XMLHttpRequest) {
|
17758
|
+
return new window.XMLHttpRequest();
|
17759
|
+
}
|
17622
17760
|
|
17761
|
+
throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest.");
|
17762
|
+
}
|
17623
17763
|
|
17624
17764
|
/**
|
17625
17765
|
* @ngdoc object
|
@@ -17640,11 +17780,11 @@ var XHR = window.XMLHttpRequest || function() {
|
|
17640
17780
|
*/
|
17641
17781
|
function $HttpBackendProvider() {
|
17642
17782
|
this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
|
17643
|
-
return createHttpBackend($browser,
|
17783
|
+
return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]);
|
17644
17784
|
}];
|
17645
17785
|
}
|
17646
17786
|
|
17647
|
-
function createHttpBackend($browser,
|
17787
|
+
function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
|
17648
17788
|
var ABORTED = -1;
|
17649
17789
|
|
17650
17790
|
// TODO(vojta): fix the signature
|
@@ -17666,10 +17806,12 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument)
|
|
17666
17806
|
} else {
|
17667
17807
|
completeRequest(callback, status || -2);
|
17668
17808
|
}
|
17669
|
-
|
17809
|
+
callbacks[callbackId] = angular.noop;
|
17670
17810
|
});
|
17671
17811
|
} else {
|
17672
|
-
|
17812
|
+
|
17813
|
+
var xhr = createXhr(method);
|
17814
|
+
|
17673
17815
|
xhr.open(method, url, true);
|
17674
17816
|
forEach(headers, function(value, key) {
|
17675
17817
|
if (isDefined(value)) {
|
@@ -17681,17 +17823,25 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument)
|
|
17681
17823
|
// response is in the cache. the promise api will ensure that to the app code the api is
|
17682
17824
|
// always async
|
17683
17825
|
xhr.onreadystatechange = function() {
|
17684
|
-
|
17826
|
+
// onreadystatechange might get called multiple times with readyState === 4 on mobile webkit caused by
|
17827
|
+
// xhrs that are resolved while the app is in the background (see #5426).
|
17828
|
+
// since calling completeRequest sets the `xhr` variable to null, we just check if it's not null before
|
17829
|
+
// continuing
|
17830
|
+
//
|
17831
|
+
// we can't set xhr.onreadystatechange to undefined or delete it because that breaks IE8 (method=PATCH) and
|
17832
|
+
// Safari respectively.
|
17833
|
+
if (xhr && xhr.readyState == 4) {
|
17685
17834
|
var responseHeaders = null,
|
17686
17835
|
response = null;
|
17687
17836
|
|
17688
17837
|
if(status !== ABORTED) {
|
17689
17838
|
responseHeaders = xhr.getAllResponseHeaders();
|
17690
|
-
|
17839
|
+
|
17840
|
+
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
|
17841
|
+
// response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
|
17842
|
+
response = ('response' in xhr) ? xhr.response : xhr.responseText;
|
17691
17843
|
}
|
17692
17844
|
|
17693
|
-
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
|
17694
|
-
// response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
|
17695
17845
|
completeRequest(callback,
|
17696
17846
|
status || xhr.status,
|
17697
17847
|
response,
|
@@ -17704,7 +17854,20 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument)
|
|
17704
17854
|
}
|
17705
17855
|
|
17706
17856
|
if (responseType) {
|
17707
|
-
|
17857
|
+
try {
|
17858
|
+
xhr.responseType = responseType;
|
17859
|
+
} catch (e) {
|
17860
|
+
// WebKit added support for the json responseType value on 09/03/2013
|
17861
|
+
// https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
|
17862
|
+
// known to throw when setting the value "json" as the response type. Other older
|
17863
|
+
// browsers implementing the responseType
|
17864
|
+
//
|
17865
|
+
// The json response type can be ignored if not supported, because JSON payloads are
|
17866
|
+
// parsed on the client-side regardless.
|
17867
|
+
if (responseType !== 'json') {
|
17868
|
+
throw e;
|
17869
|
+
}
|
17870
|
+
}
|
17708
17871
|
}
|
17709
17872
|
|
17710
17873
|
xhr.send(post || null);
|
@@ -17724,14 +17887,14 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument)
|
|
17724
17887
|
}
|
17725
17888
|
|
17726
17889
|
function completeRequest(callback, status, response, headersString) {
|
17727
|
-
var protocol = urlResolve(url).protocol;
|
17728
|
-
|
17729
17890
|
// cancel timeout and subsequent timeout promise resolution
|
17730
17891
|
timeoutId && $browserDefer.cancel(timeoutId);
|
17731
17892
|
jsonpDone = xhr = null;
|
17732
17893
|
|
17733
|
-
// fix status code
|
17734
|
-
|
17894
|
+
// fix status code when it is 0 (0 status is undocumented).
|
17895
|
+
// Occurs when accessing file resources.
|
17896
|
+
// On Android 4.1 stock browser it occurs while retrieving files from application cache.
|
17897
|
+
status = (status === 0) ? (response ? 200 : 404) : status;
|
17735
17898
|
|
17736
17899
|
// normalize IE bug (http://bugs.jquery.com/ticket/1450)
|
17737
17900
|
status = status == 1223 ? 204 : status;
|
@@ -17803,11 +17966,11 @@ var $interpolateMinErr = minErr('$interpolate');
|
|
17803
17966
|
//demo.label//
|
17804
17967
|
</div>
|
17805
17968
|
</doc:source>
|
17806
|
-
<doc:
|
17807
|
-
|
17808
|
-
|
17809
|
-
|
17810
|
-
</doc:
|
17969
|
+
<doc:protractor>
|
17970
|
+
it('should interpolate binding with custom symbols', function() {
|
17971
|
+
expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
|
17972
|
+
});
|
17973
|
+
</doc:protractor>
|
17811
17974
|
</doc:example>
|
17812
17975
|
*/
|
17813
17976
|
function $InterpolateProvider() {
|
@@ -17999,7 +18162,7 @@ function $InterpolateProvider() {
|
|
17999
18162
|
* @description
|
18000
18163
|
* Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
|
18001
18164
|
*
|
18002
|
-
* Use {@link ng.$interpolateProvider#
|
18165
|
+
* Use {@link ng.$interpolateProvider#methods_endSymbol $interpolateProvider#endSymbol} to change
|
18003
18166
|
* the symbol.
|
18004
18167
|
*
|
18005
18168
|
* @returns {string} start symbol.
|
@@ -18036,6 +18199,14 @@ function $IntervalProvider() {
|
|
18036
18199
|
* move forward by `millis` milliseconds and trigger any functions scheduled to run in that
|
18037
18200
|
* time.
|
18038
18201
|
*
|
18202
|
+
* <div class="alert alert-warning">
|
18203
|
+
* **Note**: Intervals created by this service must be explicitly destroyed when you are finished
|
18204
|
+
* with them. In particular they are not automatically destroyed when a controller's scope or a
|
18205
|
+
* directive's element are destroyed.
|
18206
|
+
* You should take this into consideration and make sure to always cancel the interval at the
|
18207
|
+
* appropriate moment. See the example below for more details on how and when to do this.
|
18208
|
+
* </div>
|
18209
|
+
*
|
18039
18210
|
* @param {function()} fn A function that should be called repeatedly.
|
18040
18211
|
* @param {number} delay Number of milliseconds between each function call.
|
18041
18212
|
* @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
|
@@ -18043,6 +18214,95 @@ function $IntervalProvider() {
|
|
18043
18214
|
* @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
|
18044
18215
|
* will invoke `fn` within the {@link ng.$rootScope.Scope#methods_$apply $apply} block.
|
18045
18216
|
* @returns {promise} A promise which will be notified on each iteration.
|
18217
|
+
*
|
18218
|
+
* @example
|
18219
|
+
<doc:example module="time">
|
18220
|
+
<doc:source>
|
18221
|
+
<script>
|
18222
|
+
function Ctrl2($scope,$interval) {
|
18223
|
+
$scope.format = 'M/d/yy h:mm:ss a';
|
18224
|
+
$scope.blood_1 = 100;
|
18225
|
+
$scope.blood_2 = 120;
|
18226
|
+
|
18227
|
+
var stop;
|
18228
|
+
$scope.fight = function() {
|
18229
|
+
// Don't start a new fight if we are already fighting
|
18230
|
+
if ( angular.isDefined(stop) ) return;
|
18231
|
+
|
18232
|
+
stop = $interval(function() {
|
18233
|
+
if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
|
18234
|
+
$scope.blood_1 = $scope.blood_1 - 3;
|
18235
|
+
$scope.blood_2 = $scope.blood_2 - 4;
|
18236
|
+
} else {
|
18237
|
+
$scope.stopFight();
|
18238
|
+
}
|
18239
|
+
}, 100);
|
18240
|
+
};
|
18241
|
+
|
18242
|
+
$scope.stopFight = function() {
|
18243
|
+
if (angular.isDefined(stop)) {
|
18244
|
+
$interval.cancel(stop);
|
18245
|
+
stop = undefined;
|
18246
|
+
}
|
18247
|
+
};
|
18248
|
+
|
18249
|
+
$scope.resetFight = function() {
|
18250
|
+
$scope.blood_1 = 100;
|
18251
|
+
$scope.blood_2 = 120;
|
18252
|
+
}
|
18253
|
+
|
18254
|
+
$scope.$on('$destroy', function() {
|
18255
|
+
// Make sure that the interval is destroyed too
|
18256
|
+
$scope.stopFight();
|
18257
|
+
});
|
18258
|
+
}
|
18259
|
+
|
18260
|
+
angular.module('time', [])
|
18261
|
+
// Register the 'myCurrentTime' directive factory method.
|
18262
|
+
// We inject $interval and dateFilter service since the factory method is DI.
|
18263
|
+
.directive('myCurrentTime', function($interval, dateFilter) {
|
18264
|
+
// return the directive link function. (compile function not needed)
|
18265
|
+
return function(scope, element, attrs) {
|
18266
|
+
var format, // date format
|
18267
|
+
stopTime; // so that we can cancel the time updates
|
18268
|
+
|
18269
|
+
// used to update the UI
|
18270
|
+
function updateTime() {
|
18271
|
+
element.text(dateFilter(new Date(), format));
|
18272
|
+
}
|
18273
|
+
|
18274
|
+
// watch the expression, and update the UI on change.
|
18275
|
+
scope.$watch(attrs.myCurrentTime, function(value) {
|
18276
|
+
format = value;
|
18277
|
+
updateTime();
|
18278
|
+
});
|
18279
|
+
|
18280
|
+
stopTime = $interval(updateTime, 1000);
|
18281
|
+
|
18282
|
+
// listen on DOM destroy (removal) event, and cancel the next UI update
|
18283
|
+
// to prevent updating time ofter the DOM element was removed.
|
18284
|
+
element.bind('$destroy', function() {
|
18285
|
+
$interval.cancel(stopTime);
|
18286
|
+
});
|
18287
|
+
}
|
18288
|
+
});
|
18289
|
+
</script>
|
18290
|
+
|
18291
|
+
<div>
|
18292
|
+
<div ng-controller="Ctrl2">
|
18293
|
+
Date format: <input ng-model="format"> <hr/>
|
18294
|
+
Current time is: <span my-current-time="format"></span>
|
18295
|
+
<hr/>
|
18296
|
+
Blood 1 : <font color='red'>{{blood_1}}</font>
|
18297
|
+
Blood 2 : <font color='red'>{{blood_2}}</font>
|
18298
|
+
<button type="button" data-ng-click="fight()">Fight</button>
|
18299
|
+
<button type="button" data-ng-click="stopFight()">StopFight</button>
|
18300
|
+
<button type="button" data-ng-click="resetFight()">resetFight</button>
|
18301
|
+
</div>
|
18302
|
+
</div>
|
18303
|
+
|
18304
|
+
</doc:source>
|
18305
|
+
</doc:example>
|
18046
18306
|
*/
|
18047
18307
|
function interval(fn, delay, count, invokeApply) {
|
18048
18308
|
var setInterval = $window.setInterval,
|
@@ -18051,8 +18311,8 @@ function $IntervalProvider() {
|
|
18051
18311
|
promise = deferred.promise,
|
18052
18312
|
iteration = 0,
|
18053
18313
|
skipApply = (isDefined(invokeApply) && !invokeApply);
|
18054
|
-
|
18055
|
-
count = isDefined(count) ? count : 0
|
18314
|
+
|
18315
|
+
count = isDefined(count) ? count : 0;
|
18056
18316
|
|
18057
18317
|
promise.then(null, null, fn);
|
18058
18318
|
|
@@ -18746,9 +19006,9 @@ function $LocationProvider(){
|
|
18746
19006
|
* @eventType broadcast on root scope
|
18747
19007
|
* @description
|
18748
19008
|
* Broadcasted before a URL will change. This change can be prevented by calling
|
18749
|
-
* `preventDefault` method of the event. See {@link ng.$rootScope.Scope
|
19009
|
+
* `preventDefault` method of the event. See {@link ng.$rootScope.Scope#methods_$on} for more
|
18750
19010
|
* details about event object. Upon successful change
|
18751
|
-
* {@link ng.$location
|
19011
|
+
* {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
|
18752
19012
|
*
|
18753
19013
|
* @param {Object} angularEvent Synthetic event object.
|
18754
19014
|
* @param {string} newUrl New URL
|
@@ -18801,6 +19061,13 @@ function $LocationProvider(){
|
|
18801
19061
|
}
|
18802
19062
|
|
18803
19063
|
var absHref = elm.prop('href');
|
19064
|
+
|
19065
|
+
if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
|
19066
|
+
// SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
|
19067
|
+
// an animation.
|
19068
|
+
absHref = urlResolve(absHref.animVal).href;
|
19069
|
+
}
|
19070
|
+
|
18804
19071
|
var rewrittenUrl = $location.$$rewrite(absHref);
|
18805
19072
|
|
18806
19073
|
if (absHref && !elm.attr('target') && rewrittenUrl && !event.isDefaultPrevented()) {
|
@@ -18824,16 +19091,17 @@ function $LocationProvider(){
|
|
18824
19091
|
// update $location when $browser url changes
|
18825
19092
|
$browser.onUrlChange(function(newUrl) {
|
18826
19093
|
if ($location.absUrl() != newUrl) {
|
18827
|
-
if ($rootScope.$broadcast('$locationChangeStart', newUrl,
|
18828
|
-
$location.absUrl()).defaultPrevented) {
|
18829
|
-
$browser.url($location.absUrl());
|
18830
|
-
return;
|
18831
|
-
}
|
18832
19094
|
$rootScope.$evalAsync(function() {
|
18833
19095
|
var oldUrl = $location.absUrl();
|
18834
19096
|
|
18835
19097
|
$location.$$parse(newUrl);
|
18836
|
-
|
19098
|
+
if ($rootScope.$broadcast('$locationChangeStart', newUrl,
|
19099
|
+
oldUrl).defaultPrevented) {
|
19100
|
+
$location.$$parse(oldUrl);
|
19101
|
+
$browser.url(oldUrl);
|
19102
|
+
} else {
|
19103
|
+
afterLocationChange(oldUrl);
|
19104
|
+
}
|
18837
19105
|
});
|
18838
19106
|
if (!$rootScope.$$phase) $rootScope.$digest();
|
18839
19107
|
}
|
@@ -18921,7 +19189,7 @@ function $LogProvider(){
|
|
18921
19189
|
* @name ng.$logProvider#debugEnabled
|
18922
19190
|
* @methodOf ng.$logProvider
|
18923
19191
|
* @description
|
18924
|
-
* @param {
|
19192
|
+
* @param {boolean=} flag enable or disable debug level messages
|
18925
19193
|
* @returns {*} current value if used as getter or itself (chaining) if used as setter
|
18926
19194
|
*/
|
18927
19195
|
this.debugEnabled = function(flag) {
|
@@ -19009,9 +19277,16 @@ function $LogProvider(){
|
|
19009
19277
|
|
19010
19278
|
function consoleLog(type) {
|
19011
19279
|
var console = $window.console || {},
|
19012
|
-
logFn = console[type] || console.log || noop
|
19280
|
+
logFn = console[type] || console.log || noop,
|
19281
|
+
hasApply = false;
|
19282
|
+
|
19283
|
+
// Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
|
19284
|
+
// The reason behind this is that console.log has type "object" in IE8...
|
19285
|
+
try {
|
19286
|
+
hasApply = !! logFn.apply;
|
19287
|
+
} catch (e) {}
|
19013
19288
|
|
19014
|
-
if (
|
19289
|
+
if (hasApply) {
|
19015
19290
|
return function() {
|
19016
19291
|
var args = [];
|
19017
19292
|
forEach(arguments, function(arg) {
|
@@ -19737,7 +20012,7 @@ Parser.prototype = {
|
|
19737
20012
|
var getter = getterFn(field, this.options, this.text);
|
19738
20013
|
|
19739
20014
|
return extend(function(scope, locals, self) {
|
19740
|
-
return getter(self || object(scope, locals)
|
20015
|
+
return getter(self || object(scope, locals));
|
19741
20016
|
}, {
|
19742
20017
|
assign: function(scope, value, locals) {
|
19743
20018
|
return setter(object(scope, locals), field, value, parser.text, parser.options);
|
@@ -19921,19 +20196,23 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
|
19921
20196
|
? function cspSafeGetter(scope, locals) {
|
19922
20197
|
var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
|
19923
20198
|
|
19924
|
-
if (pathVal
|
20199
|
+
if (pathVal == null) return pathVal;
|
19925
20200
|
pathVal = pathVal[key0];
|
19926
20201
|
|
19927
|
-
if (!key1
|
20202
|
+
if (!key1) return pathVal;
|
20203
|
+
if (pathVal == null) return undefined;
|
19928
20204
|
pathVal = pathVal[key1];
|
19929
20205
|
|
19930
|
-
if (!key2
|
20206
|
+
if (!key2) return pathVal;
|
20207
|
+
if (pathVal == null) return undefined;
|
19931
20208
|
pathVal = pathVal[key2];
|
19932
20209
|
|
19933
|
-
if (!key3
|
20210
|
+
if (!key3) return pathVal;
|
20211
|
+
if (pathVal == null) return undefined;
|
19934
20212
|
pathVal = pathVal[key3];
|
19935
20213
|
|
19936
|
-
if (!key4
|
20214
|
+
if (!key4) return pathVal;
|
20215
|
+
if (pathVal == null) return undefined;
|
19937
20216
|
pathVal = pathVal[key4];
|
19938
20217
|
|
19939
20218
|
return pathVal;
|
@@ -19942,7 +20221,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
|
19942
20221
|
var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
|
19943
20222
|
promise;
|
19944
20223
|
|
19945
|
-
if (pathVal
|
20224
|
+
if (pathVal == null) return pathVal;
|
19946
20225
|
|
19947
20226
|
pathVal = pathVal[key0];
|
19948
20227
|
if (pathVal && pathVal.then) {
|
@@ -19954,8 +20233,9 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
|
19954
20233
|
}
|
19955
20234
|
pathVal = pathVal.$$v;
|
19956
20235
|
}
|
19957
|
-
if (!key1 || pathVal === null || pathVal === undefined) return pathVal;
|
19958
20236
|
|
20237
|
+
if (!key1) return pathVal;
|
20238
|
+
if (pathVal == null) return undefined;
|
19959
20239
|
pathVal = pathVal[key1];
|
19960
20240
|
if (pathVal && pathVal.then) {
|
19961
20241
|
promiseWarning(fullExp);
|
@@ -19966,8 +20246,9 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
|
19966
20246
|
}
|
19967
20247
|
pathVal = pathVal.$$v;
|
19968
20248
|
}
|
19969
|
-
if (!key2 || pathVal === null || pathVal === undefined) return pathVal;
|
19970
20249
|
|
20250
|
+
if (!key2) return pathVal;
|
20251
|
+
if (pathVal == null) return undefined;
|
19971
20252
|
pathVal = pathVal[key2];
|
19972
20253
|
if (pathVal && pathVal.then) {
|
19973
20254
|
promiseWarning(fullExp);
|
@@ -19978,8 +20259,9 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
|
19978
20259
|
}
|
19979
20260
|
pathVal = pathVal.$$v;
|
19980
20261
|
}
|
19981
|
-
if (!key3 || pathVal === null || pathVal === undefined) return pathVal;
|
19982
20262
|
|
20263
|
+
if (!key3) return pathVal;
|
20264
|
+
if (pathVal == null) return undefined;
|
19983
20265
|
pathVal = pathVal[key3];
|
19984
20266
|
if (pathVal && pathVal.then) {
|
19985
20267
|
promiseWarning(fullExp);
|
@@ -19990,8 +20272,9 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
|
19990
20272
|
}
|
19991
20273
|
pathVal = pathVal.$$v;
|
19992
20274
|
}
|
19993
|
-
if (!key4 || pathVal === null || pathVal === undefined) return pathVal;
|
19994
20275
|
|
20276
|
+
if (!key4) return pathVal;
|
20277
|
+
if (pathVal == null) return undefined;
|
19995
20278
|
pathVal = pathVal[key4];
|
19996
20279
|
if (pathVal && pathVal.then) {
|
19997
20280
|
promiseWarning(fullExp);
|
@@ -20006,6 +20289,26 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
|
20006
20289
|
};
|
20007
20290
|
}
|
20008
20291
|
|
20292
|
+
function simpleGetterFn1(key0, fullExp) {
|
20293
|
+
ensureSafeMemberName(key0, fullExp);
|
20294
|
+
|
20295
|
+
return function simpleGetterFn1(scope, locals) {
|
20296
|
+
if (scope == null) return undefined;
|
20297
|
+
return ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
|
20298
|
+
};
|
20299
|
+
}
|
20300
|
+
|
20301
|
+
function simpleGetterFn2(key0, key1, fullExp) {
|
20302
|
+
ensureSafeMemberName(key0, fullExp);
|
20303
|
+
ensureSafeMemberName(key1, fullExp);
|
20304
|
+
|
20305
|
+
return function simpleGetterFn2(scope, locals) {
|
20306
|
+
if (scope == null) return undefined;
|
20307
|
+
scope = ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
|
20308
|
+
return scope == null ? undefined : scope[key1];
|
20309
|
+
};
|
20310
|
+
}
|
20311
|
+
|
20009
20312
|
function getterFn(path, options, fullExp) {
|
20010
20313
|
// Check whether the cache has this getter already.
|
20011
20314
|
// We can use hasOwnProperty directly on the cache because we ensure,
|
@@ -20018,7 +20321,13 @@ function getterFn(path, options, fullExp) {
|
|
20018
20321
|
pathKeysLength = pathKeys.length,
|
20019
20322
|
fn;
|
20020
20323
|
|
20021
|
-
|
20324
|
+
// When we have only 1 or 2 tokens, use optimized special case closures.
|
20325
|
+
// http://jsperf.com/angularjs-parse-getter/6
|
20326
|
+
if (!options.unwrapPromises && pathKeysLength === 1) {
|
20327
|
+
fn = simpleGetterFn1(pathKeys[0], fullExp);
|
20328
|
+
} else if (!options.unwrapPromises && pathKeysLength === 2) {
|
20329
|
+
fn = simpleGetterFn2(pathKeys[0], pathKeys[1], fullExp);
|
20330
|
+
} else if (options.csp) {
|
20022
20331
|
if (pathKeysLength < 6) {
|
20023
20332
|
fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
|
20024
20333
|
options);
|
@@ -20036,11 +20345,10 @@ function getterFn(path, options, fullExp) {
|
|
20036
20345
|
};
|
20037
20346
|
}
|
20038
20347
|
} else {
|
20039
|
-
var code = 'var
|
20348
|
+
var code = 'var p;\n';
|
20040
20349
|
forEach(pathKeys, function(key, index) {
|
20041
20350
|
ensureSafeMemberName(key, fullExp);
|
20042
|
-
code += 'if(s
|
20043
|
-
'l=s;\n' +
|
20351
|
+
code += 'if(s == null) return undefined;\n' +
|
20044
20352
|
's='+ (index
|
20045
20353
|
// we simply dereference 's' on any .dot notation
|
20046
20354
|
? 's'
|
@@ -20063,10 +20371,10 @@ function getterFn(path, options, fullExp) {
|
|
20063
20371
|
/* jshint -W054 */
|
20064
20372
|
var evaledFnGetter = new Function('s', 'k', 'pw', code); // s=scope, k=locals, pw=promiseWarning
|
20065
20373
|
/* jshint +W054 */
|
20066
|
-
evaledFnGetter.toString =
|
20067
|
-
fn = function(scope, locals) {
|
20374
|
+
evaledFnGetter.toString = valueFn(code);
|
20375
|
+
fn = options.unwrapPromises ? function(scope, locals) {
|
20068
20376
|
return evaledFnGetter(scope, locals, promiseWarning);
|
20069
|
-
};
|
20377
|
+
} : evaledFnGetter;
|
20070
20378
|
}
|
20071
20379
|
|
20072
20380
|
// Only cache the value if it's not going to mess up the cache object
|
@@ -20280,9 +20588,9 @@ function $ParseProvider() {
|
|
20280
20588
|
* asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
|
20281
20589
|
*
|
20282
20590
|
* <pre>
|
20283
|
-
* // for the purpose of this example let's assume that variables `$q` and `
|
20284
|
-
* // available in the current lexical scope (they could have been injected or passed in).
|
20285
|
-
*
|
20591
|
+
* // for the purpose of this example let's assume that variables `$q`, `scope` and `okToGreet`
|
20592
|
+
* // are available in the current lexical scope (they could have been injected or passed in).
|
20593
|
+
*
|
20286
20594
|
* function asyncGreet(name) {
|
20287
20595
|
* var deferred = $q.defer();
|
20288
20596
|
*
|
@@ -20337,7 +20645,7 @@ function $ParseProvider() {
|
|
20337
20645
|
* constructed via `$q.reject`, the promise will be rejected instead.
|
20338
20646
|
* - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
|
20339
20647
|
* resolving it with a rejection constructed via `$q.reject`.
|
20340
|
-
* - `notify(value)` - provides updates on the status of the
|
20648
|
+
* - `notify(value)` - provides updates on the status of the promise's execution. This may be called
|
20341
20649
|
* multiple times before the promise is either resolved or rejected.
|
20342
20650
|
*
|
20343
20651
|
* **Properties**
|
@@ -20487,7 +20795,7 @@ function qFactory(nextTick, exceptionHandler) {
|
|
20487
20795
|
|
20488
20796
|
|
20489
20797
|
reject: function(reason) {
|
20490
|
-
deferred.resolve(
|
20798
|
+
deferred.resolve(createInternalRejectedPromise(reason));
|
20491
20799
|
},
|
20492
20800
|
|
20493
20801
|
|
@@ -20644,6 +20952,12 @@ function qFactory(nextTick, exceptionHandler) {
|
|
20644
20952
|
* @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
|
20645
20953
|
*/
|
20646
20954
|
var reject = function(reason) {
|
20955
|
+
var result = defer();
|
20956
|
+
result.reject(reason);
|
20957
|
+
return result.promise;
|
20958
|
+
};
|
20959
|
+
|
20960
|
+
var createInternalRejectedPromise = function(reason) {
|
20647
20961
|
return {
|
20648
20962
|
then: function(callback, errback) {
|
20649
20963
|
var result = defer();
|
@@ -20911,6 +21225,7 @@ function $RootScopeProvider(){
|
|
20911
21225
|
this.$$asyncQueue = [];
|
20912
21226
|
this.$$postDigestQueue = [];
|
20913
21227
|
this.$$listeners = {};
|
21228
|
+
this.$$listenerCount = {};
|
20914
21229
|
this.$$isolateBindings = {};
|
20915
21230
|
}
|
20916
21231
|
|
@@ -20963,13 +21278,14 @@ function $RootScopeProvider(){
|
|
20963
21278
|
} else {
|
20964
21279
|
ChildScope = function() {}; // should be anonymous; This is so that when the minifier munges
|
20965
21280
|
// the name it does not become random set of chars. This will then show up as class
|
20966
|
-
// name in the
|
21281
|
+
// name in the web inspector.
|
20967
21282
|
ChildScope.prototype = this;
|
20968
21283
|
child = new ChildScope();
|
20969
21284
|
child.$id = nextUid();
|
20970
21285
|
}
|
20971
21286
|
child['this'] = child;
|
20972
21287
|
child.$$listeners = {};
|
21288
|
+
child.$$listenerCount = {};
|
20973
21289
|
child.$parent = this;
|
20974
21290
|
child.$$watchers = child.$$nextSibling = child.$$childHead = child.$$childTail = null;
|
20975
21291
|
child.$$prevSibling = this.$$childTail;
|
@@ -21063,7 +21379,7 @@ function $RootScopeProvider(){
|
|
21063
21379
|
// No digest has been run so the counter will be zero
|
21064
21380
|
expect(scope.foodCounter).toEqual(0);
|
21065
21381
|
|
21066
|
-
// Run the digest but since food has not changed
|
21382
|
+
// Run the digest but since food has not changed count will still be zero
|
21067
21383
|
scope.$digest();
|
21068
21384
|
expect(scope.foodCounter).toEqual(0);
|
21069
21385
|
|
@@ -21129,6 +21445,7 @@ function $RootScopeProvider(){
|
|
21129
21445
|
|
21130
21446
|
return function() {
|
21131
21447
|
arrayRemove(array, watcher);
|
21448
|
+
lastDirtyWatch = null;
|
21132
21449
|
};
|
21133
21450
|
},
|
21134
21451
|
|
@@ -21407,7 +21724,7 @@ function $RootScopeProvider(){
|
|
21407
21724
|
|
21408
21725
|
// `break traverseScopesLoop;` takes us to here
|
21409
21726
|
|
21410
|
-
if(dirty && !(ttl--)) {
|
21727
|
+
if((dirty || asyncQueue.length) && !(ttl--)) {
|
21411
21728
|
clearPhase();
|
21412
21729
|
throw $rootScopeMinErr('infdig',
|
21413
21730
|
'{0} $digest() iterations reached. Aborting!\n' +
|
@@ -21474,6 +21791,8 @@ function $RootScopeProvider(){
|
|
21474
21791
|
this.$$destroyed = true;
|
21475
21792
|
if (this === $rootScope) return;
|
21476
21793
|
|
21794
|
+
forEach(this.$$listenerCount, bind(null, decrementListenerCount, this));
|
21795
|
+
|
21477
21796
|
if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
|
21478
21797
|
if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
|
21479
21798
|
if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
|
@@ -21663,8 +21982,18 @@ function $RootScopeProvider(){
|
|
21663
21982
|
}
|
21664
21983
|
namedListeners.push(listener);
|
21665
21984
|
|
21985
|
+
var current = this;
|
21986
|
+
do {
|
21987
|
+
if (!current.$$listenerCount[name]) {
|
21988
|
+
current.$$listenerCount[name] = 0;
|
21989
|
+
}
|
21990
|
+
current.$$listenerCount[name]++;
|
21991
|
+
} while ((current = current.$parent));
|
21992
|
+
|
21993
|
+
var self = this;
|
21666
21994
|
return function() {
|
21667
21995
|
namedListeners[indexOf(namedListeners, listener)] = null;
|
21996
|
+
decrementListenerCount(self, 1, name);
|
21668
21997
|
};
|
21669
21998
|
},
|
21670
21999
|
|
@@ -21689,7 +22018,7 @@ function $RootScopeProvider(){
|
|
21689
22018
|
* onto the {@link ng.$exceptionHandler $exceptionHandler} service.
|
21690
22019
|
*
|
21691
22020
|
* @param {string} name Event name to emit.
|
21692
|
-
* @param {...*} args Optional
|
22021
|
+
* @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
|
21693
22022
|
* @return {Object} Event object (see {@link ng.$rootScope.Scope#methods_$on}).
|
21694
22023
|
*/
|
21695
22024
|
$emit: function(name, args) {
|
@@ -21757,7 +22086,7 @@ function $RootScopeProvider(){
|
|
21757
22086
|
* onto the {@link ng.$exceptionHandler $exceptionHandler} service.
|
21758
22087
|
*
|
21759
22088
|
* @param {string} name Event name to broadcast.
|
21760
|
-
* @param {...*} args Optional
|
22089
|
+
* @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
|
21761
22090
|
* @return {Object} Event object, see {@link ng.$rootScope.Scope#methods_$on}
|
21762
22091
|
*/
|
21763
22092
|
$broadcast: function(name, args) {
|
@@ -21776,8 +22105,7 @@ function $RootScopeProvider(){
|
|
21776
22105
|
listeners, i, length;
|
21777
22106
|
|
21778
22107
|
//down while you can, then up and next sibling or up and next sibling until back at root
|
21779
|
-
|
21780
|
-
current = next;
|
22108
|
+
while ((current = next)) {
|
21781
22109
|
event.currentScope = current;
|
21782
22110
|
listeners = current.$$listeners[name] || [];
|
21783
22111
|
for (i=0, length = listeners.length; i<length; i++) {
|
@@ -21799,12 +22127,14 @@ function $RootScopeProvider(){
|
|
21799
22127
|
// Insanity Warning: scope depth-first traversal
|
21800
22128
|
// yes, this code is a bit crazy, but it works and we have tests to prove it!
|
21801
22129
|
// this piece should be kept in sync with the traversal in $digest
|
21802
|
-
|
22130
|
+
// (though it differs due to having the extra check for $$listenerCount)
|
22131
|
+
if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
|
22132
|
+
(current !== target && current.$$nextSibling)))) {
|
21803
22133
|
while(current !== target && !(next = current.$$nextSibling)) {
|
21804
22134
|
current = current.$parent;
|
21805
22135
|
}
|
21806
22136
|
}
|
21807
|
-
}
|
22137
|
+
}
|
21808
22138
|
|
21809
22139
|
return event;
|
21810
22140
|
}
|
@@ -21833,6 +22163,16 @@ function $RootScopeProvider(){
|
|
21833
22163
|
return fn;
|
21834
22164
|
}
|
21835
22165
|
|
22166
|
+
function decrementListenerCount(current, count, name) {
|
22167
|
+
do {
|
22168
|
+
current.$$listenerCount[name] -= count;
|
22169
|
+
|
22170
|
+
if (current.$$listenerCount[name] === 0) {
|
22171
|
+
delete current.$$listenerCount[name];
|
22172
|
+
}
|
22173
|
+
} while ((current = current.$parent));
|
22174
|
+
}
|
22175
|
+
|
21836
22176
|
/**
|
21837
22177
|
* function used as an initial value for watchers.
|
21838
22178
|
* because it's unique we can easily tell it apart from other values
|
@@ -22189,7 +22529,7 @@ function $SceDelegateProvider() {
|
|
22189
22529
|
*
|
22190
22530
|
* @description
|
22191
22531
|
* Returns an object that is trusted by angular for use in specified strict
|
22192
|
-
* contextual escaping contexts (such as ng-
|
22532
|
+
* contextual escaping contexts (such as ng-bind-html, ng-include, any src
|
22193
22533
|
* attribute interpolation, any dom event binding attribute interpolation
|
22194
22534
|
* such as for onclick, etc.) that uses the provided value.
|
22195
22535
|
* See {@link ng.$sce $sce} for enabling strict contextual escaping.
|
@@ -22235,7 +22575,7 @@ function $SceDelegateProvider() {
|
|
22235
22575
|
*
|
22236
22576
|
* @param {*} value The result of a prior {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}
|
22237
22577
|
* call or anything else.
|
22238
|
-
* @returns {*} The value
|
22578
|
+
* @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#methods_trustAs
|
22239
22579
|
* `$sceDelegate.trustAs`} if `value` is the result of such a call. Otherwise, returns
|
22240
22580
|
* `value` unchanged.
|
22241
22581
|
*/
|
@@ -22416,8 +22756,8 @@ function $SceDelegateProvider() {
|
|
22416
22756
|
* It's important to remember that SCE only applies to interpolation expressions.
|
22417
22757
|
*
|
22418
22758
|
* If your expressions are constant literals, they're automatically trusted and you don't need to
|
22419
|
-
* call `$sce.trustAs` on them
|
22420
|
-
* `<div ng-
|
22759
|
+
* call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
|
22760
|
+
* `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
|
22421
22761
|
*
|
22422
22762
|
* Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
|
22423
22763
|
* through {@link ng.$sce#methods_getTrusted $sce.getTrusted}. SCE doesn't play a role here.
|
@@ -22477,7 +22817,7 @@ function $SceDelegateProvider() {
|
|
22477
22817
|
* matched against the **entire** *normalized / absolute URL* of the resource being tested
|
22478
22818
|
* (even when the RegExp did not have the `^` and `$` codes.) In addition, any flags
|
22479
22819
|
* present on the RegExp (such as multiline, global, ignoreCase) are ignored.
|
22480
|
-
* - If you are generating your
|
22820
|
+
* - If you are generating your JavaScript from some other templating engine (not
|
22481
22821
|
* recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
|
22482
22822
|
* remember to escape your regular expression (and be aware that you might need more than
|
22483
22823
|
* one level of escaping depending on your templating engine and the way you interpolated
|
@@ -22494,7 +22834,7 @@ function $SceDelegateProvider() {
|
|
22494
22834
|
* ## Show me an example using SCE.
|
22495
22835
|
*
|
22496
22836
|
* @example
|
22497
|
-
<example module="mySceApp">
|
22837
|
+
<example module="mySceApp" deps="angular-sanitize.js">
|
22498
22838
|
<file name="index.html">
|
22499
22839
|
<div ng-controller="myAppController as myCtrl">
|
22500
22840
|
<i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
|
@@ -22538,13 +22878,15 @@ function $SceDelegateProvider() {
|
|
22538
22878
|
]
|
22539
22879
|
</file>
|
22540
22880
|
|
22541
|
-
<file name="
|
22881
|
+
<file name="protractorTest.js">
|
22542
22882
|
describe('SCE doc demo', function() {
|
22543
22883
|
it('should sanitize untrusted values', function() {
|
22544
|
-
expect(element('.htmlComment').
|
22884
|
+
expect(element(by.css('.htmlComment')).getInnerHtml())
|
22885
|
+
.toBe('<span>Is <i>anyone</i> reading this?</span>');
|
22545
22886
|
});
|
22887
|
+
|
22546
22888
|
it('should NOT sanitize explicitly trusted values', function() {
|
22547
|
-
expect(element('
|
22889
|
+
expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
|
22548
22890
|
'<span onmouseover="this.textContent="Explicitly trusted HTML bypasses ' +
|
22549
22891
|
'sanitization."">Hover over this text.</span>');
|
22550
22892
|
});
|
@@ -22719,8 +23061,8 @@ function $SceProvider() {
|
|
22719
23061
|
*
|
22720
23062
|
* @description
|
22721
23063
|
* Delegates to {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}. As such,
|
22722
|
-
* returns an
|
22723
|
-
* escaping contexts (such as ng-
|
23064
|
+
* returns an object that is trusted by angular for use in specified strict contextual
|
23065
|
+
* escaping contexts (such as ng-bind-html, ng-include, any src attribute
|
22724
23066
|
* interpolation, any dom event binding attribute interpolation such as for onclick, etc.)
|
22725
23067
|
* that uses the provided value. See * {@link ng.$sce $sce} for enabling strict contextual
|
22726
23068
|
* escaping.
|
@@ -23051,7 +23393,7 @@ function $SnifferProvider() {
|
|
23051
23393
|
// http://code.google.com/p/android/issues/detail?id=17471
|
23052
23394
|
// https://github.com/angular/angular.js/issues/904
|
23053
23395
|
|
23054
|
-
// older
|
23396
|
+
// older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
|
23055
23397
|
// so let's not use the history API also
|
23056
23398
|
// We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
|
23057
23399
|
// jshint -W018
|
@@ -23077,6 +23419,7 @@ function $SnifferProvider() {
|
|
23077
23419
|
vendorPrefix: vendorPrefix,
|
23078
23420
|
transitions : transitions,
|
23079
23421
|
animations : animations,
|
23422
|
+
android: android,
|
23080
23423
|
msie : msie,
|
23081
23424
|
msieDocumentMode: documentMode
|
23082
23425
|
};
|
@@ -23114,113 +23457,26 @@ function $TimeoutProvider() {
|
|
23114
23457
|
* @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
|
23115
23458
|
* promise will be resolved with is the return value of the `fn` function.
|
23116
23459
|
*
|
23117
|
-
|
23118
|
-
|
23119
|
-
|
23120
|
-
|
23121
|
-
|
23122
|
-
|
23123
|
-
$scope.blood_1 = 100;
|
23124
|
-
$scope.blood_2 = 120;
|
23125
|
-
|
23126
|
-
var stop;
|
23127
|
-
$scope.fight = function() {
|
23128
|
-
stop = $timeout(function() {
|
23129
|
-
if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
|
23130
|
-
$scope.blood_1 = $scope.blood_1 - 3;
|
23131
|
-
$scope.blood_2 = $scope.blood_2 - 4;
|
23132
|
-
$scope.fight();
|
23133
|
-
} else {
|
23134
|
-
$timeout.cancel(stop);
|
23135
|
-
}
|
23136
|
-
}, 100);
|
23137
|
-
};
|
23460
|
+
*/
|
23461
|
+
function timeout(fn, delay, invokeApply) {
|
23462
|
+
var deferred = $q.defer(),
|
23463
|
+
promise = deferred.promise,
|
23464
|
+
skipApply = (isDefined(invokeApply) && !invokeApply),
|
23465
|
+
timeoutId;
|
23138
23466
|
|
23139
|
-
|
23140
|
-
|
23141
|
-
|
23467
|
+
timeoutId = $browser.defer(function() {
|
23468
|
+
try {
|
23469
|
+
deferred.resolve(fn());
|
23470
|
+
} catch(e) {
|
23471
|
+
deferred.reject(e);
|
23472
|
+
$exceptionHandler(e);
|
23473
|
+
}
|
23474
|
+
finally {
|
23475
|
+
delete deferreds[promise.$$timeoutId];
|
23476
|
+
}
|
23142
23477
|
|
23143
|
-
|
23144
|
-
|
23145
|
-
$scope.blood_2 = 120;
|
23146
|
-
}
|
23147
|
-
}
|
23148
|
-
|
23149
|
-
angular.module('time', [])
|
23150
|
-
// Register the 'myCurrentTime' directive factory method.
|
23151
|
-
// We inject $timeout and dateFilter service since the factory method is DI.
|
23152
|
-
.directive('myCurrentTime', function($timeout, dateFilter) {
|
23153
|
-
// return the directive link function. (compile function not needed)
|
23154
|
-
return function(scope, element, attrs) {
|
23155
|
-
var format, // date format
|
23156
|
-
timeoutId; // timeoutId, so that we can cancel the time updates
|
23157
|
-
|
23158
|
-
// used to update the UI
|
23159
|
-
function updateTime() {
|
23160
|
-
element.text(dateFilter(new Date(), format));
|
23161
|
-
}
|
23162
|
-
|
23163
|
-
// watch the expression, and update the UI on change.
|
23164
|
-
scope.$watch(attrs.myCurrentTime, function(value) {
|
23165
|
-
format = value;
|
23166
|
-
updateTime();
|
23167
|
-
});
|
23168
|
-
|
23169
|
-
// schedule update in one second
|
23170
|
-
function updateLater() {
|
23171
|
-
// save the timeoutId for canceling
|
23172
|
-
timeoutId = $timeout(function() {
|
23173
|
-
updateTime(); // update DOM
|
23174
|
-
updateLater(); // schedule another update
|
23175
|
-
}, 1000);
|
23176
|
-
}
|
23177
|
-
|
23178
|
-
// listen on DOM destroy (removal) event, and cancel the next UI update
|
23179
|
-
// to prevent updating time ofter the DOM element was removed.
|
23180
|
-
element.bind('$destroy', function() {
|
23181
|
-
$timeout.cancel(timeoutId);
|
23182
|
-
});
|
23183
|
-
|
23184
|
-
updateLater(); // kick off the UI update process.
|
23185
|
-
}
|
23186
|
-
});
|
23187
|
-
</script>
|
23188
|
-
|
23189
|
-
<div>
|
23190
|
-
<div ng-controller="Ctrl2">
|
23191
|
-
Date format: <input ng-model="format"> <hr/>
|
23192
|
-
Current time is: <span my-current-time="format"></span>
|
23193
|
-
<hr/>
|
23194
|
-
Blood 1 : <font color='red'>{{blood_1}}</font>
|
23195
|
-
Blood 2 : <font color='red'>{{blood_2}}</font>
|
23196
|
-
<button type="button" data-ng-click="fight()">Fight</button>
|
23197
|
-
<button type="button" data-ng-click="stopFight()">StopFight</button>
|
23198
|
-
<button type="button" data-ng-click="resetFight()">resetFight</button>
|
23199
|
-
</div>
|
23200
|
-
</div>
|
23201
|
-
|
23202
|
-
</doc:source>
|
23203
|
-
</doc:example>
|
23204
|
-
*/
|
23205
|
-
function timeout(fn, delay, invokeApply) {
|
23206
|
-
var deferred = $q.defer(),
|
23207
|
-
promise = deferred.promise,
|
23208
|
-
skipApply = (isDefined(invokeApply) && !invokeApply),
|
23209
|
-
timeoutId;
|
23210
|
-
|
23211
|
-
timeoutId = $browser.defer(function() {
|
23212
|
-
try {
|
23213
|
-
deferred.resolve(fn());
|
23214
|
-
} catch(e) {
|
23215
|
-
deferred.reject(e);
|
23216
|
-
$exceptionHandler(e);
|
23217
|
-
}
|
23218
|
-
finally {
|
23219
|
-
delete deferreds[promise.$$timeoutId];
|
23220
|
-
}
|
23221
|
-
|
23222
|
-
if (!skipApply) $rootScope.$apply();
|
23223
|
-
}, delay);
|
23478
|
+
if (!skipApply) $rootScope.$apply();
|
23479
|
+
}, delay);
|
23224
23480
|
|
23225
23481
|
promise.$$timeoutId = timeoutId;
|
23226
23482
|
deferreds[timeoutId] = deferred;
|
@@ -23389,13 +23645,13 @@ function urlIsSameOrigin(requestUrl) {
|
|
23389
23645
|
<button ng-click="doGreeting(greeting)">ALERT</button>
|
23390
23646
|
</div>
|
23391
23647
|
</doc:source>
|
23392
|
-
<doc:
|
23648
|
+
<doc:protractor>
|
23393
23649
|
it('should display the greeting in the input box', function() {
|
23394
|
-
|
23650
|
+
element(by.model('greeting')).sendKeys('Hello, E2E Tests');
|
23395
23651
|
// If we click the button it will block the test runner
|
23396
23652
|
// element(':button').click();
|
23397
23653
|
});
|
23398
|
-
</doc:
|
23654
|
+
</doc:protractor>
|
23399
23655
|
</doc:example>
|
23400
23656
|
*/
|
23401
23657
|
function $WindowProvider(){
|
@@ -23548,8 +23804,8 @@ function $FilterProvider($provide) {
|
|
23548
23804
|
*
|
23549
23805
|
* Can be one of:
|
23550
23806
|
*
|
23551
|
-
* - `string`:
|
23552
|
-
*
|
23807
|
+
* - `string`: The string is evaluated as an expression and the resulting value is used for substring match against
|
23808
|
+
* the contents of the `array`. All strings or objects with string properties in `array` that contain this string
|
23553
23809
|
* will be returned. The predicate can be negated by prefixing the string with `!`.
|
23554
23810
|
*
|
23555
23811
|
* - `Object`: A pattern object can be used to filter specific properties on objects contained
|
@@ -23559,21 +23815,21 @@ function $FilterProvider($provide) {
|
|
23559
23815
|
* property of the object. That's equivalent to the simple substring match with a `string`
|
23560
23816
|
* as described above.
|
23561
23817
|
*
|
23562
|
-
* - `function`: A predicate function can be used to write arbitrary filters. The function is
|
23818
|
+
* - `function(value)`: A predicate function can be used to write arbitrary filters. The function is
|
23563
23819
|
* called for each element of `array`. The final result is an array of those elements that
|
23564
23820
|
* the predicate returned true for.
|
23565
23821
|
*
|
23566
|
-
* @param {function(
|
23822
|
+
* @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
|
23567
23823
|
* determining if the expected value (from the filter expression) and actual value (from
|
23568
23824
|
* the object in the array) should be considered a match.
|
23569
23825
|
*
|
23570
23826
|
* Can be one of:
|
23571
23827
|
*
|
23572
|
-
* - `function(
|
23828
|
+
* - `function(actual, expected)`:
|
23573
23829
|
* The function will be given the object value and the predicate value to compare and
|
23574
23830
|
* should return true if the item should be included in filtered result.
|
23575
23831
|
*
|
23576
|
-
* - `true`: A shorthand for `function(
|
23832
|
+
* - `true`: A shorthand for `function(actual, expected) { return angular.equals(expected, actual)}`.
|
23577
23833
|
* this is essentially strict comparison of expected and actual.
|
23578
23834
|
*
|
23579
23835
|
* - `false|undefined`: A short hand for a function which will look for a substring match in case
|
@@ -23604,35 +23860,47 @@ function $FilterProvider($provide) {
|
|
23604
23860
|
Equality <input type="checkbox" ng-model="strict"><br>
|
23605
23861
|
<table id="searchObjResults">
|
23606
23862
|
<tr><th>Name</th><th>Phone</th></tr>
|
23607
|
-
<tr ng-repeat="
|
23608
|
-
<td>{{
|
23609
|
-
<td>{{
|
23863
|
+
<tr ng-repeat="friendObj in friends | filter:search:strict">
|
23864
|
+
<td>{{friendObj.name}}</td>
|
23865
|
+
<td>{{friendObj.phone}}</td>
|
23610
23866
|
</tr>
|
23611
23867
|
</table>
|
23612
23868
|
</doc:source>
|
23613
|
-
<doc:
|
23614
|
-
|
23615
|
-
|
23616
|
-
|
23617
|
-
|
23869
|
+
<doc:protractor>
|
23870
|
+
var expectFriendNames = function(expectedNames, key) {
|
23871
|
+
element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
|
23872
|
+
arr.forEach(function(wd, i) {
|
23873
|
+
expect(wd.getText()).toMatch(expectedNames[i]);
|
23874
|
+
});
|
23875
|
+
});
|
23876
|
+
};
|
23618
23877
|
|
23619
|
-
|
23620
|
-
|
23621
|
-
|
23878
|
+
it('should search across all fields when filtering with a string', function() {
|
23879
|
+
var searchText = element(by.model('searchText'));
|
23880
|
+
searchText.clear();
|
23881
|
+
searchText.sendKeys('m');
|
23882
|
+
expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
|
23883
|
+
|
23884
|
+
searchText.clear();
|
23885
|
+
searchText.sendKeys('76');
|
23886
|
+
expectFriendNames(['John', 'Julie'], 'friend');
|
23622
23887
|
});
|
23623
23888
|
|
23624
23889
|
it('should search in specific fields when filtering with a predicate object', function() {
|
23625
|
-
|
23626
|
-
|
23627
|
-
|
23890
|
+
var searchAny = element(by.model('search.$'));
|
23891
|
+
searchAny.clear();
|
23892
|
+
searchAny.sendKeys('i');
|
23893
|
+
expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
|
23628
23894
|
});
|
23629
23895
|
it('should use a equal comparison when comparator is true', function() {
|
23630
|
-
|
23631
|
-
|
23632
|
-
|
23633
|
-
|
23896
|
+
var searchName = element(by.model('search.name'));
|
23897
|
+
var strict = element(by.model('strict'));
|
23898
|
+
searchName.clear();
|
23899
|
+
searchName.sendKeys('Julie');
|
23900
|
+
strict.click();
|
23901
|
+
expectFriendNames(['Julie'], 'friendObj');
|
23634
23902
|
});
|
23635
|
-
</doc:
|
23903
|
+
</doc:protractor>
|
23636
23904
|
</doc:example>
|
23637
23905
|
*/
|
23638
23906
|
function filterFilter() {
|
@@ -23658,6 +23926,15 @@ function filterFilter() {
|
|
23658
23926
|
};
|
23659
23927
|
} else {
|
23660
23928
|
comparator = function(obj, text) {
|
23929
|
+
if (obj && text && typeof obj === 'object' && typeof text === 'object') {
|
23930
|
+
for (var objKey in obj) {
|
23931
|
+
if (objKey.charAt(0) !== '$' && hasOwnProperty.call(obj, objKey) &&
|
23932
|
+
comparator(obj[objKey], text[objKey])) {
|
23933
|
+
return true;
|
23934
|
+
}
|
23935
|
+
}
|
23936
|
+
return false;
|
23937
|
+
}
|
23661
23938
|
text = (''+text).toLowerCase();
|
23662
23939
|
return (''+obj).toLowerCase().indexOf(text) > -1;
|
23663
23940
|
};
|
@@ -23707,23 +23984,12 @@ function filterFilter() {
|
|
23707
23984
|
case "object":
|
23708
23985
|
// jshint +W086
|
23709
23986
|
for (var key in expression) {
|
23710
|
-
|
23711
|
-
(
|
23712
|
-
|
23713
|
-
|
23714
|
-
|
23715
|
-
|
23716
|
-
});
|
23717
|
-
})();
|
23718
|
-
} else {
|
23719
|
-
(function() {
|
23720
|
-
if (typeof(expression[key]) == 'undefined') { return; }
|
23721
|
-
var path = key;
|
23722
|
-
predicates.push(function(value) {
|
23723
|
-
return search(getter(value,path), expression[path]);
|
23724
|
-
});
|
23725
|
-
})();
|
23726
|
-
}
|
23987
|
+
(function(path) {
|
23988
|
+
if (typeof expression[path] == 'undefined') return;
|
23989
|
+
predicates.push(function(value) {
|
23990
|
+
return search(path == '$' ? value : (value && value[path]), expression[path]);
|
23991
|
+
});
|
23992
|
+
})(key);
|
23727
23993
|
}
|
23728
23994
|
break;
|
23729
23995
|
case 'function':
|
@@ -23767,21 +24033,27 @@ function filterFilter() {
|
|
23767
24033
|
</script>
|
23768
24034
|
<div ng-controller="Ctrl">
|
23769
24035
|
<input type="number" ng-model="amount"> <br>
|
23770
|
-
default currency symbol ($): {{amount | currency}}
|
23771
|
-
custom currency identifier (USD$): {{amount | currency:"USD$"}}
|
24036
|
+
default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
|
24037
|
+
custom currency identifier (USD$): <span>{{amount | currency:"USD$"}}</span>
|
23772
24038
|
</div>
|
23773
24039
|
</doc:source>
|
23774
|
-
<doc:
|
24040
|
+
<doc:protractor>
|
23775
24041
|
it('should init with 1234.56', function() {
|
23776
|
-
expect(
|
23777
|
-
expect(binding('amount | currency:"USD$"')).toBe('USD$1,234.56');
|
24042
|
+
expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
|
24043
|
+
expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('USD$1,234.56');
|
23778
24044
|
});
|
23779
24045
|
it('should update', function() {
|
23780
|
-
|
23781
|
-
|
23782
|
-
|
24046
|
+
if (browser.params.browser == 'safari') {
|
24047
|
+
// Safari does not understand the minus key. See
|
24048
|
+
// https://github.com/angular/protractor/issues/481
|
24049
|
+
return;
|
24050
|
+
}
|
24051
|
+
element(by.model('amount')).clear();
|
24052
|
+
element(by.model('amount')).sendKeys('-1234');
|
24053
|
+
expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)');
|
24054
|
+
expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('(USD$1,234.00)');
|
23783
24055
|
});
|
23784
|
-
</doc:
|
24056
|
+
</doc:protractor>
|
23785
24057
|
</doc:example>
|
23786
24058
|
*/
|
23787
24059
|
currencyFilter.$inject = ['$locale'];
|
@@ -23820,25 +24092,26 @@ function currencyFilter($locale) {
|
|
23820
24092
|
</script>
|
23821
24093
|
<div ng-controller="Ctrl">
|
23822
24094
|
Enter number: <input ng-model='val'><br>
|
23823
|
-
Default formatting: {{val | number}}
|
23824
|
-
No fractions: {{val | number:0}}
|
23825
|
-
Negative number: {{-val | number:4}}
|
24095
|
+
Default formatting: <span id='number-default'>{{val | number}}</span><br>
|
24096
|
+
No fractions: <span>{{val | number:0}}</span><br>
|
24097
|
+
Negative number: <span>{{-val | number:4}}</span>
|
23826
24098
|
</div>
|
23827
24099
|
</doc:source>
|
23828
|
-
<doc:
|
24100
|
+
<doc:protractor>
|
23829
24101
|
it('should format numbers', function() {
|
23830
|
-
expect(
|
23831
|
-
expect(binding('val | number:0')).toBe('1,235');
|
23832
|
-
expect(binding('-val | number:4')).toBe('-1,234.5679');
|
24102
|
+
expect(element(by.id('number-default')).getText()).toBe('1,234.568');
|
24103
|
+
expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
|
24104
|
+
expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
|
23833
24105
|
});
|
23834
24106
|
|
23835
24107
|
it('should update', function() {
|
23836
|
-
|
23837
|
-
|
23838
|
-
expect(
|
23839
|
-
expect(binding('
|
23840
|
-
|
23841
|
-
|
24108
|
+
element(by.model('val')).clear();
|
24109
|
+
element(by.model('val')).sendKeys('3374.333');
|
24110
|
+
expect(element(by.id('number-default')).getText()).toBe('3,374.333');
|
24111
|
+
expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
|
24112
|
+
expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
|
24113
|
+
});
|
24114
|
+
</doc:protractor>
|
23842
24115
|
</doc:example>
|
23843
24116
|
*/
|
23844
24117
|
|
@@ -24068,22 +24341,22 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
|
|
24068
24341
|
<doc:example>
|
24069
24342
|
<doc:source>
|
24070
24343
|
<span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
|
24071
|
-
{{1288323623006 | date:'medium'}}
|
24344
|
+
<span>{{1288323623006 | date:'medium'}}</span><br>
|
24072
24345
|
<span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
|
24073
|
-
{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}
|
24346
|
+
<span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
|
24074
24347
|
<span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
|
24075
|
-
{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}
|
24348
|
+
<span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
|
24076
24349
|
</doc:source>
|
24077
|
-
<doc:
|
24350
|
+
<doc:protractor>
|
24078
24351
|
it('should format date', function() {
|
24079
|
-
expect(binding("1288323623006 | date:'medium'")).
|
24352
|
+
expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
|
24080
24353
|
toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
|
24081
|
-
expect(binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).
|
24354
|
+
expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
|
24082
24355
|
toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
|
24083
|
-
expect(binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).
|
24356
|
+
expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
|
24084
24357
|
toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
|
24085
24358
|
});
|
24086
|
-
</doc:
|
24359
|
+
</doc:protractor>
|
24087
24360
|
</doc:example>
|
24088
24361
|
*/
|
24089
24362
|
dateFilter.$inject = ['$locale'];
|
@@ -24182,11 +24455,11 @@ function dateFilter($locale) {
|
|
24182
24455
|
<doc:source>
|
24183
24456
|
<pre>{{ {'name':'value'} | json }}</pre>
|
24184
24457
|
</doc:source>
|
24185
|
-
<doc:
|
24458
|
+
<doc:protractor>
|
24186
24459
|
it('should jsonify filtered objects', function() {
|
24187
|
-
expect(binding("{'name':'value'}")).toMatch(/\{\n "name": ?"value"\n}/);
|
24460
|
+
expect(element(by.binding("{'name':'value'}")).getText()).toMatch(/\{\n "name": ?"value"\n}/);
|
24188
24461
|
});
|
24189
|
-
</doc:
|
24462
|
+
</doc:protractor>
|
24190
24463
|
</doc:example>
|
24191
24464
|
*
|
24192
24465
|
*/
|
@@ -24254,28 +24527,37 @@ var uppercaseFilter = valueFn(uppercase);
|
|
24254
24527
|
<p>Output letters: {{ letters | limitTo:letterLimit }}</p>
|
24255
24528
|
</div>
|
24256
24529
|
</doc:source>
|
24257
|
-
<doc:
|
24530
|
+
<doc:protractor>
|
24531
|
+
var numLimitInput = element(by.model('numLimit'));
|
24532
|
+
var letterLimitInput = element(by.model('letterLimit'));
|
24533
|
+
var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
|
24534
|
+
var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
|
24535
|
+
|
24258
24536
|
it('should limit the number array to first three items', function() {
|
24259
|
-
expect(
|
24260
|
-
expect(
|
24261
|
-
expect(
|
24262
|
-
expect(
|
24537
|
+
expect(numLimitInput.getAttribute('value')).toBe('3');
|
24538
|
+
expect(letterLimitInput.getAttribute('value')).toBe('3');
|
24539
|
+
expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
|
24540
|
+
expect(limitedLetters.getText()).toEqual('Output letters: abc');
|
24263
24541
|
});
|
24264
24542
|
|
24265
24543
|
it('should update the output when -3 is entered', function() {
|
24266
|
-
|
24267
|
-
|
24268
|
-
|
24269
|
-
|
24544
|
+
numLimitInput.clear();
|
24545
|
+
numLimitInput.sendKeys('-3');
|
24546
|
+
letterLimitInput.clear();
|
24547
|
+
letterLimitInput.sendKeys('-3');
|
24548
|
+
expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
|
24549
|
+
expect(limitedLetters.getText()).toEqual('Output letters: ghi');
|
24270
24550
|
});
|
24271
24551
|
|
24272
24552
|
it('should not exceed the maximum size of input array', function() {
|
24273
|
-
|
24274
|
-
|
24275
|
-
|
24276
|
-
|
24553
|
+
numLimitInput.clear();
|
24554
|
+
numLimitInput.sendKeys('100');
|
24555
|
+
letterLimitInput.clear();
|
24556
|
+
letterLimitInput.sendKeys('100');
|
24557
|
+
expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
|
24558
|
+
expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
|
24277
24559
|
});
|
24278
|
-
</doc:
|
24560
|
+
</doc:protractor>
|
24279
24561
|
</doc:example>
|
24280
24562
|
*/
|
24281
24563
|
function limitToFilter(){
|
@@ -24376,29 +24658,6 @@ function limitToFilter(){
|
|
24376
24658
|
</table>
|
24377
24659
|
</div>
|
24378
24660
|
</doc:source>
|
24379
|
-
<doc:scenario>
|
24380
|
-
it('should be reverse ordered by aged', function() {
|
24381
|
-
expect(binding('predicate')).toBe('-age');
|
24382
|
-
expect(repeater('table.friend', 'friend in friends').column('friend.age')).
|
24383
|
-
toEqual(['35', '29', '21', '19', '10']);
|
24384
|
-
expect(repeater('table.friend', 'friend in friends').column('friend.name')).
|
24385
|
-
toEqual(['Adam', 'Julie', 'Mike', 'Mary', 'John']);
|
24386
|
-
});
|
24387
|
-
|
24388
|
-
it('should reorder the table when user selects different predicate', function() {
|
24389
|
-
element('.doc-example-live a:contains("Name")').click();
|
24390
|
-
expect(repeater('table.friend', 'friend in friends').column('friend.name')).
|
24391
|
-
toEqual(['Adam', 'John', 'Julie', 'Mary', 'Mike']);
|
24392
|
-
expect(repeater('table.friend', 'friend in friends').column('friend.age')).
|
24393
|
-
toEqual(['35', '10', '29', '19', '21']);
|
24394
|
-
|
24395
|
-
element('.doc-example-live a:contains("Phone")').click();
|
24396
|
-
expect(repeater('table.friend', 'friend in friends').column('friend.phone')).
|
24397
|
-
toEqual(['555-9876', '555-8765', '555-5678', '555-4321', '555-1212']);
|
24398
|
-
expect(repeater('table.friend', 'friend in friends').column('friend.name')).
|
24399
|
-
toEqual(['Mary', 'Julie', 'Adam', 'Mike', 'John']);
|
24400
|
-
});
|
24401
|
-
</doc:scenario>
|
24402
24661
|
</doc:example>
|
24403
24662
|
*/
|
24404
24663
|
orderByFilter.$inject = ['$parse'];
|
@@ -24495,11 +24754,14 @@ var htmlAnchorDirective = valueFn({
|
|
24495
24754
|
element.append(document.createComment('IE fix'));
|
24496
24755
|
}
|
24497
24756
|
|
24498
|
-
if (!attr.href && !attr.name) {
|
24757
|
+
if (!attr.href && !attr.xlinkHref && !attr.name) {
|
24499
24758
|
return function(scope, element) {
|
24759
|
+
// SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
|
24760
|
+
var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
|
24761
|
+
'xlink:href' : 'href';
|
24500
24762
|
element.on('click', function(event){
|
24501
24763
|
// if we have no href url, then don't navigate anywhere.
|
24502
|
-
if (!element.attr(
|
24764
|
+
if (!element.attr(href)) {
|
24503
24765
|
event.preventDefault();
|
24504
24766
|
}
|
24505
24767
|
});
|
@@ -24512,6 +24774,7 @@ var htmlAnchorDirective = valueFn({
|
|
24512
24774
|
* @ngdoc directive
|
24513
24775
|
* @name ng.directive:ngHref
|
24514
24776
|
* @restrict A
|
24777
|
+
* @priority 99
|
24515
24778
|
*
|
24516
24779
|
* @description
|
24517
24780
|
* Using Angular markup like `{{hash}}` in an href attribute will
|
@@ -24548,46 +24811,55 @@ var htmlAnchorDirective = valueFn({
|
|
24548
24811
|
<a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
|
24549
24812
|
<a id="link-6" ng-href="{{value}}">link</a> (link, change location)
|
24550
24813
|
</doc:source>
|
24551
|
-
<doc:
|
24814
|
+
<doc:protractor>
|
24552
24815
|
it('should execute ng-click but not reload when href without value', function() {
|
24553
|
-
element('
|
24554
|
-
expect(
|
24555
|
-
expect(element('
|
24816
|
+
element(by.id('link-1')).click();
|
24817
|
+
expect(element(by.model('value')).getAttribute('value')).toEqual('1');
|
24818
|
+
expect(element(by.id('link-1')).getAttribute('href')).toBe('');
|
24556
24819
|
});
|
24557
24820
|
|
24558
24821
|
it('should execute ng-click but not reload when href empty string', function() {
|
24559
|
-
element('
|
24560
|
-
expect(
|
24561
|
-
expect(element('
|
24822
|
+
element(by.id('link-2')).click();
|
24823
|
+
expect(element(by.model('value')).getAttribute('value')).toEqual('2');
|
24824
|
+
expect(element(by.id('link-2')).getAttribute('href')).toBe('');
|
24562
24825
|
});
|
24563
24826
|
|
24564
24827
|
it('should execute ng-click and change url when ng-href specified', function() {
|
24565
|
-
expect(element('
|
24828
|
+
expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
|
24829
|
+
|
24830
|
+
element(by.id('link-3')).click();
|
24566
24831
|
|
24567
|
-
|
24568
|
-
|
24832
|
+
// At this point, we navigate away from an Angular page, so we need
|
24833
|
+
// to use browser.driver to get the base webdriver.
|
24834
|
+
|
24835
|
+
browser.wait(function() {
|
24836
|
+
return browser.driver.getCurrentUrl().then(function(url) {
|
24837
|
+
return url.match(/\/123$/);
|
24838
|
+
});
|
24839
|
+
}, 1000, 'page should navigate to /123');
|
24569
24840
|
});
|
24570
24841
|
|
24571
24842
|
it('should execute ng-click but not reload when href empty string and name specified', function() {
|
24572
|
-
element('
|
24573
|
-
expect(
|
24574
|
-
expect(element('
|
24843
|
+
element(by.id('link-4')).click();
|
24844
|
+
expect(element(by.model('value')).getAttribute('value')).toEqual('4');
|
24845
|
+
expect(element(by.id('link-4')).getAttribute('href')).toBe('');
|
24575
24846
|
});
|
24576
24847
|
|
24577
24848
|
it('should execute ng-click but not reload when no href but name specified', function() {
|
24578
|
-
element('
|
24579
|
-
expect(
|
24580
|
-
expect(element('
|
24849
|
+
element(by.id('link-5')).click();
|
24850
|
+
expect(element(by.model('value')).getAttribute('value')).toEqual('5');
|
24851
|
+
expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
|
24581
24852
|
});
|
24582
24853
|
|
24583
24854
|
it('should only change url when only ng-href', function() {
|
24584
|
-
|
24585
|
-
|
24855
|
+
element(by.model('value')).clear();
|
24856
|
+
element(by.model('value')).sendKeys('6');
|
24857
|
+
expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
|
24586
24858
|
|
24587
|
-
element('
|
24588
|
-
expect(browser
|
24859
|
+
element(by.id('link-6')).click();
|
24860
|
+
expect(browser.getCurrentUrl()).toMatch(/\/6$/);
|
24589
24861
|
});
|
24590
|
-
</doc:
|
24862
|
+
</doc:protractor>
|
24591
24863
|
</doc:example>
|
24592
24864
|
*/
|
24593
24865
|
|
@@ -24595,6 +24867,7 @@ var htmlAnchorDirective = valueFn({
|
|
24595
24867
|
* @ngdoc directive
|
24596
24868
|
* @name ng.directive:ngSrc
|
24597
24869
|
* @restrict A
|
24870
|
+
* @priority 99
|
24598
24871
|
*
|
24599
24872
|
* @description
|
24600
24873
|
* Using Angular markup like `{{hash}}` in a `src` attribute doesn't
|
@@ -24620,6 +24893,7 @@ var htmlAnchorDirective = valueFn({
|
|
24620
24893
|
* @ngdoc directive
|
24621
24894
|
* @name ng.directive:ngSrcset
|
24622
24895
|
* @restrict A
|
24896
|
+
* @priority 99
|
24623
24897
|
*
|
24624
24898
|
* @description
|
24625
24899
|
* Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
|
@@ -24645,6 +24919,7 @@ var htmlAnchorDirective = valueFn({
|
|
24645
24919
|
* @ngdoc directive
|
24646
24920
|
* @name ng.directive:ngDisabled
|
24647
24921
|
* @restrict A
|
24922
|
+
* @priority 100
|
24648
24923
|
*
|
24649
24924
|
* @description
|
24650
24925
|
*
|
@@ -24669,13 +24944,13 @@ var htmlAnchorDirective = valueFn({
|
|
24669
24944
|
Click me to toggle: <input type="checkbox" ng-model="checked"><br/>
|
24670
24945
|
<button ng-model="button" ng-disabled="checked">Button</button>
|
24671
24946
|
</doc:source>
|
24672
|
-
<doc:
|
24947
|
+
<doc:protractor>
|
24673
24948
|
it('should toggle button', function() {
|
24674
|
-
expect(element('.doc-example-live
|
24675
|
-
|
24676
|
-
expect(element('.doc-example-live
|
24949
|
+
expect(element(by.css('.doc-example-live button')).getAttribute('disabled')).toBeFalsy();
|
24950
|
+
element(by.model('checked')).click();
|
24951
|
+
expect(element(by.css('.doc-example-live button')).getAttribute('disabled')).toBeTruthy();
|
24677
24952
|
});
|
24678
|
-
</doc:
|
24953
|
+
</doc:protractor>
|
24679
24954
|
</doc:example>
|
24680
24955
|
*
|
24681
24956
|
* @element INPUT
|
@@ -24688,6 +24963,7 @@ var htmlAnchorDirective = valueFn({
|
|
24688
24963
|
* @ngdoc directive
|
24689
24964
|
* @name ng.directive:ngChecked
|
24690
24965
|
* @restrict A
|
24966
|
+
* @priority 100
|
24691
24967
|
*
|
24692
24968
|
* @description
|
24693
24969
|
* The HTML specification does not require browsers to preserve the values of boolean attributes
|
@@ -24703,13 +24979,13 @@ var htmlAnchorDirective = valueFn({
|
|
24703
24979
|
Check me to check both: <input type="checkbox" ng-model="master"><br/>
|
24704
24980
|
<input id="checkSlave" type="checkbox" ng-checked="master">
|
24705
24981
|
</doc:source>
|
24706
|
-
<doc:
|
24982
|
+
<doc:protractor>
|
24707
24983
|
it('should check both checkBoxes', function() {
|
24708
|
-
expect(element('
|
24709
|
-
|
24710
|
-
expect(element('
|
24984
|
+
expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
|
24985
|
+
element(by.model('master')).click();
|
24986
|
+
expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
|
24711
24987
|
});
|
24712
|
-
</doc:
|
24988
|
+
</doc:protractor>
|
24713
24989
|
</doc:example>
|
24714
24990
|
*
|
24715
24991
|
* @element INPUT
|
@@ -24722,6 +24998,7 @@ var htmlAnchorDirective = valueFn({
|
|
24722
24998
|
* @ngdoc directive
|
24723
24999
|
* @name ng.directive:ngReadonly
|
24724
25000
|
* @restrict A
|
25001
|
+
* @priority 100
|
24725
25002
|
*
|
24726
25003
|
* @description
|
24727
25004
|
* The HTML specification does not require browsers to preserve the values of boolean attributes
|
@@ -24731,20 +25008,19 @@ var htmlAnchorDirective = valueFn({
|
|
24731
25008
|
* The `ngReadonly` directive solves this problem for the `readonly` attribute.
|
24732
25009
|
* This complementary directive is not removed by the browser and so provides
|
24733
25010
|
* a permanent reliable place to store the binding information.
|
24734
|
-
|
24735
25011
|
* @example
|
24736
25012
|
<doc:example>
|
24737
25013
|
<doc:source>
|
24738
25014
|
Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
|
24739
25015
|
<input type="text" ng-readonly="checked" value="I'm Angular"/>
|
24740
25016
|
</doc:source>
|
24741
|
-
<doc:
|
25017
|
+
<doc:protractor>
|
24742
25018
|
it('should toggle readonly attr', function() {
|
24743
|
-
expect(element('.doc-example-live
|
24744
|
-
|
24745
|
-
expect(element('.doc-example-live
|
25019
|
+
expect(element(by.css('.doc-example-live [type="text"]')).getAttribute('readonly')).toBeFalsy();
|
25020
|
+
element(by.model('checked')).click();
|
25021
|
+
expect(element(by.css('.doc-example-live [type="text"]')).getAttribute('readonly')).toBeTruthy();
|
24746
25022
|
});
|
24747
|
-
</doc:
|
25023
|
+
</doc:protractor>
|
24748
25024
|
</doc:example>
|
24749
25025
|
*
|
24750
25026
|
* @element INPUT
|
@@ -24757,6 +25033,7 @@ var htmlAnchorDirective = valueFn({
|
|
24757
25033
|
* @ngdoc directive
|
24758
25034
|
* @name ng.directive:ngSelected
|
24759
25035
|
* @restrict A
|
25036
|
+
* @priority 100
|
24760
25037
|
*
|
24761
25038
|
* @description
|
24762
25039
|
* The HTML specification does not require browsers to preserve the values of boolean attributes
|
@@ -24766,6 +25043,7 @@ var htmlAnchorDirective = valueFn({
|
|
24766
25043
|
* The `ngSelected` directive solves this problem for the `selected` atttribute.
|
24767
25044
|
* This complementary directive is not removed by the browser and so provides
|
24768
25045
|
* a permanent reliable place to store the binding information.
|
25046
|
+
*
|
24769
25047
|
* @example
|
24770
25048
|
<doc:example>
|
24771
25049
|
<doc:source>
|
@@ -24775,13 +25053,13 @@ var htmlAnchorDirective = valueFn({
|
|
24775
25053
|
<option id="greet" ng-selected="selected">Greetings!</option>
|
24776
25054
|
</select>
|
24777
25055
|
</doc:source>
|
24778
|
-
<doc:
|
25056
|
+
<doc:protractor>
|
24779
25057
|
it('should select Greetings!', function() {
|
24780
|
-
expect(element('
|
24781
|
-
|
24782
|
-
expect(element('
|
25058
|
+
expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
|
25059
|
+
element(by.model('selected')).click();
|
25060
|
+
expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
|
24783
25061
|
});
|
24784
|
-
</doc:
|
25062
|
+
</doc:protractor>
|
24785
25063
|
</doc:example>
|
24786
25064
|
*
|
24787
25065
|
* @element OPTION
|
@@ -24793,6 +25071,7 @@ var htmlAnchorDirective = valueFn({
|
|
24793
25071
|
* @ngdoc directive
|
24794
25072
|
* @name ng.directive:ngOpen
|
24795
25073
|
* @restrict A
|
25074
|
+
* @priority 100
|
24796
25075
|
*
|
24797
25076
|
* @description
|
24798
25077
|
* The HTML specification does not require browsers to preserve the values of boolean attributes
|
@@ -24802,8 +25081,6 @@ var htmlAnchorDirective = valueFn({
|
|
24802
25081
|
* The `ngOpen` directive solves this problem for the `open` attribute.
|
24803
25082
|
* This complementary directive is not removed by the browser and so provides
|
24804
25083
|
* a permanent reliable place to store the binding information.
|
24805
|
-
|
24806
|
-
*
|
24807
25084
|
* @example
|
24808
25085
|
<doc:example>
|
24809
25086
|
<doc:source>
|
@@ -24812,13 +25089,13 @@ var htmlAnchorDirective = valueFn({
|
|
24812
25089
|
<summary>Show/Hide me</summary>
|
24813
25090
|
</details>
|
24814
25091
|
</doc:source>
|
24815
|
-
<doc:
|
25092
|
+
<doc:protractor>
|
24816
25093
|
it('should toggle open', function() {
|
24817
|
-
expect(element('
|
24818
|
-
|
24819
|
-
expect(element('
|
25094
|
+
expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
|
25095
|
+
element(by.model('open')).click();
|
25096
|
+
expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
|
24820
25097
|
});
|
24821
|
-
</doc:
|
25098
|
+
</doc:protractor>
|
24822
25099
|
</doc:example>
|
24823
25100
|
*
|
24824
25101
|
* @element DETAILS
|
@@ -24838,12 +25115,10 @@ forEach(BOOLEAN_ATTR, function(propName, attrName) {
|
|
24838
25115
|
ngAttributeAliasDirectives[normalized] = function() {
|
24839
25116
|
return {
|
24840
25117
|
priority: 100,
|
24841
|
-
|
24842
|
-
|
24843
|
-
|
24844
|
-
|
24845
|
-
});
|
24846
|
-
};
|
25118
|
+
link: function(scope, element, attr) {
|
25119
|
+
scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
|
25120
|
+
attr.$set(attrName, !!value);
|
25121
|
+
});
|
24847
25122
|
}
|
24848
25123
|
};
|
24849
25124
|
};
|
@@ -25123,10 +25398,10 @@ function FormController(element, attrs) {
|
|
25123
25398
|
*
|
25124
25399
|
*
|
25125
25400
|
* # CSS classes
|
25126
|
-
* - `ng-valid`
|
25127
|
-
* - `ng-invalid`
|
25128
|
-
* - `ng-pristine`
|
25129
|
-
* - `ng-dirty`
|
25401
|
+
* - `ng-valid` is set if the form is valid.
|
25402
|
+
* - `ng-invalid` is set if the form is invalid.
|
25403
|
+
* - `ng-pristine` is set if the form is pristine.
|
25404
|
+
* - `ng-dirty` is set if the form is dirty.
|
25130
25405
|
*
|
25131
25406
|
*
|
25132
25407
|
* # Submitting a form and preventing the default action
|
@@ -25179,18 +25454,27 @@ function FormController(element, attrs) {
|
|
25179
25454
|
<tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
|
25180
25455
|
</form>
|
25181
25456
|
</doc:source>
|
25182
|
-
<doc:
|
25457
|
+
<doc:protractor>
|
25183
25458
|
it('should initialize to model', function() {
|
25184
|
-
|
25185
|
-
|
25459
|
+
var userType = element(by.binding('userType'));
|
25460
|
+
var valid = element(by.binding('myForm.input.$valid'));
|
25461
|
+
|
25462
|
+
expect(userType.getText()).toContain('guest');
|
25463
|
+
expect(valid.getText()).toContain('true');
|
25186
25464
|
});
|
25187
25465
|
|
25188
25466
|
it('should be invalid if empty', function() {
|
25189
|
-
|
25190
|
-
|
25191
|
-
|
25467
|
+
var userType = element(by.binding('userType'));
|
25468
|
+
var valid = element(by.binding('myForm.input.$valid'));
|
25469
|
+
var userInput = element(by.model('userType'));
|
25470
|
+
|
25471
|
+
userInput.clear();
|
25472
|
+
userInput.sendKeys('');
|
25473
|
+
|
25474
|
+
expect(userType.getText()).toEqual('userType =');
|
25475
|
+
expect(valid.getText()).toContain('false');
|
25192
25476
|
});
|
25193
|
-
</doc:
|
25477
|
+
</doc:protractor>
|
25194
25478
|
</doc:example>
|
25195
25479
|
*/
|
25196
25480
|
var formDirectiveFactory = function(isNgForm) {
|
@@ -25262,7 +25546,7 @@ var ngFormDirective = formDirectiveFactory(true);
|
|
25262
25546
|
*/
|
25263
25547
|
|
25264
25548
|
var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
|
25265
|
-
var EMAIL_REGEXP = /^[
|
25549
|
+
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*$/i;
|
25266
25550
|
var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
|
25267
25551
|
|
25268
25552
|
var inputType = {
|
@@ -25315,29 +25599,31 @@ var inputType = {
|
|
25315
25599
|
<tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
|
25316
25600
|
</form>
|
25317
25601
|
</doc:source>
|
25318
|
-
<doc:
|
25602
|
+
<doc:protractor>
|
25603
|
+
var text = element(by.binding('text'));
|
25604
|
+
var valid = element(by.binding('myForm.input.$valid'));
|
25605
|
+
var input = element(by.model('text'));
|
25606
|
+
|
25319
25607
|
it('should initialize to model', function() {
|
25320
|
-
expect(
|
25321
|
-
expect(
|
25608
|
+
expect(text.getText()).toContain('guest');
|
25609
|
+
expect(valid.getText()).toContain('true');
|
25322
25610
|
});
|
25323
25611
|
|
25324
25612
|
it('should be invalid if empty', function() {
|
25325
|
-
input
|
25326
|
-
|
25327
|
-
|
25613
|
+
input.clear();
|
25614
|
+
input.sendKeys('');
|
25615
|
+
|
25616
|
+
expect(text.getText()).toEqual('text =');
|
25617
|
+
expect(valid.getText()).toContain('false');
|
25328
25618
|
});
|
25329
25619
|
|
25330
25620
|
it('should be invalid if multi word', function() {
|
25331
|
-
input
|
25332
|
-
|
25333
|
-
});
|
25621
|
+
input.clear();
|
25622
|
+
input.sendKeys('hello world');
|
25334
25623
|
|
25335
|
-
|
25336
|
-
input('text').enter('untrimmed ');
|
25337
|
-
expect(binding('text')).toEqual('untrimmed ');
|
25338
|
-
expect(binding('myForm.input.$valid')).toEqual('true');
|
25624
|
+
expect(valid.getText()).toContain('false');
|
25339
25625
|
});
|
25340
|
-
</doc:
|
25626
|
+
</doc:protractor>
|
25341
25627
|
</doc:example>
|
25342
25628
|
*/
|
25343
25629
|
'text': textInputType,
|
@@ -25391,24 +25677,30 @@ var inputType = {
|
|
25391
25677
|
<tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
|
25392
25678
|
</form>
|
25393
25679
|
</doc:source>
|
25394
|
-
<doc:
|
25680
|
+
<doc:protractor>
|
25681
|
+
var value = element(by.binding('value'));
|
25682
|
+
var valid = element(by.binding('myForm.input.$valid'));
|
25683
|
+
var input = element(by.model('value'));
|
25684
|
+
|
25395
25685
|
it('should initialize to model', function() {
|
25396
|
-
|
25397
|
-
|
25686
|
+
expect(value.getText()).toContain('12');
|
25687
|
+
expect(valid.getText()).toContain('true');
|
25398
25688
|
});
|
25399
25689
|
|
25400
25690
|
it('should be invalid if empty', function() {
|
25401
|
-
|
25402
|
-
|
25403
|
-
|
25691
|
+
input.clear();
|
25692
|
+
input.sendKeys('');
|
25693
|
+
expect(value.getText()).toEqual('value =');
|
25694
|
+
expect(valid.getText()).toContain('false');
|
25404
25695
|
});
|
25405
25696
|
|
25406
25697
|
it('should be invalid if over max', function() {
|
25407
|
-
|
25408
|
-
|
25409
|
-
|
25698
|
+
input.clear();
|
25699
|
+
input.sendKeys('123');
|
25700
|
+
expect(value.getText()).toEqual('value =');
|
25701
|
+
expect(valid.getText()).toContain('false');
|
25410
25702
|
});
|
25411
|
-
</doc:
|
25703
|
+
</doc:protractor>
|
25412
25704
|
</doc:example>
|
25413
25705
|
*/
|
25414
25706
|
'number': numberInputType,
|
@@ -25460,23 +25752,31 @@ var inputType = {
|
|
25460
25752
|
<tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
|
25461
25753
|
</form>
|
25462
25754
|
</doc:source>
|
25463
|
-
<doc:
|
25755
|
+
<doc:protractor>
|
25756
|
+
var text = element(by.binding('text'));
|
25757
|
+
var valid = element(by.binding('myForm.input.$valid'));
|
25758
|
+
var input = element(by.model('text'));
|
25759
|
+
|
25464
25760
|
it('should initialize to model', function() {
|
25465
|
-
expect(
|
25466
|
-
expect(
|
25761
|
+
expect(text.getText()).toContain('http://google.com');
|
25762
|
+
expect(valid.getText()).toContain('true');
|
25467
25763
|
});
|
25468
25764
|
|
25469
25765
|
it('should be invalid if empty', function() {
|
25470
|
-
input
|
25471
|
-
|
25472
|
-
|
25766
|
+
input.clear();
|
25767
|
+
input.sendKeys('');
|
25768
|
+
|
25769
|
+
expect(text.getText()).toEqual('text =');
|
25770
|
+
expect(valid.getText()).toContain('false');
|
25473
25771
|
});
|
25474
25772
|
|
25475
25773
|
it('should be invalid if not url', function() {
|
25476
|
-
input
|
25477
|
-
|
25774
|
+
input.clear();
|
25775
|
+
input.sendKeys('box');
|
25776
|
+
|
25777
|
+
expect(valid.getText()).toContain('false');
|
25478
25778
|
});
|
25479
|
-
</doc:
|
25779
|
+
</doc:protractor>
|
25480
25780
|
</doc:example>
|
25481
25781
|
*/
|
25482
25782
|
'url': urlInputType,
|
@@ -25528,23 +25828,30 @@ var inputType = {
|
|
25528
25828
|
<tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
|
25529
25829
|
</form>
|
25530
25830
|
</doc:source>
|
25531
|
-
<doc:
|
25831
|
+
<doc:protractor>
|
25832
|
+
var text = element(by.binding('text'));
|
25833
|
+
var valid = element(by.binding('myForm.input.$valid'));
|
25834
|
+
var input = element(by.model('text'));
|
25835
|
+
|
25532
25836
|
it('should initialize to model', function() {
|
25533
|
-
expect(
|
25534
|
-
expect(
|
25837
|
+
expect(text.getText()).toContain('me@example.com');
|
25838
|
+
expect(valid.getText()).toContain('true');
|
25535
25839
|
});
|
25536
25840
|
|
25537
25841
|
it('should be invalid if empty', function() {
|
25538
|
-
input
|
25539
|
-
|
25540
|
-
expect(
|
25842
|
+
input.clear();
|
25843
|
+
input.sendKeys('');
|
25844
|
+
expect(text.getText()).toEqual('text =');
|
25845
|
+
expect(valid.getText()).toContain('false');
|
25541
25846
|
});
|
25542
25847
|
|
25543
25848
|
it('should be invalid if not email', function() {
|
25544
|
-
input
|
25545
|
-
|
25849
|
+
input.clear();
|
25850
|
+
input.sendKeys('xxx');
|
25851
|
+
|
25852
|
+
expect(valid.getText()).toContain('false');
|
25546
25853
|
});
|
25547
|
-
</doc:
|
25854
|
+
</doc:protractor>
|
25548
25855
|
</doc:example>
|
25549
25856
|
*/
|
25550
25857
|
'email': emailInputType,
|
@@ -25562,6 +25869,8 @@ var inputType = {
|
|
25562
25869
|
* @param {string=} name Property name of the form under which the control is published.
|
25563
25870
|
* @param {string=} ngChange Angular expression to be executed when input changes due to user
|
25564
25871
|
* interaction with the input element.
|
25872
|
+
* @param {string} ngValue Angular expression which sets the value to which the expression should
|
25873
|
+
* be set when selected.
|
25565
25874
|
*
|
25566
25875
|
* @example
|
25567
25876
|
<doc:example>
|
@@ -25569,23 +25878,31 @@ var inputType = {
|
|
25569
25878
|
<script>
|
25570
25879
|
function Ctrl($scope) {
|
25571
25880
|
$scope.color = 'blue';
|
25881
|
+
$scope.specialValue = {
|
25882
|
+
"id": "12345",
|
25883
|
+
"value": "green"
|
25884
|
+
};
|
25572
25885
|
}
|
25573
25886
|
</script>
|
25574
25887
|
<form name="myForm" ng-controller="Ctrl">
|
25575
25888
|
<input type="radio" ng-model="color" value="red"> Red <br/>
|
25576
|
-
<input type="radio" ng-model="color" value="
|
25889
|
+
<input type="radio" ng-model="color" ng-value="specialValue"> Green <br/>
|
25577
25890
|
<input type="radio" ng-model="color" value="blue"> Blue <br/>
|
25578
|
-
<tt>color = {{color}}</tt><br/>
|
25891
|
+
<tt>color = {{color | json}}</tt><br/>
|
25579
25892
|
</form>
|
25893
|
+
Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
|
25580
25894
|
</doc:source>
|
25581
|
-
<doc:
|
25895
|
+
<doc:protractor>
|
25582
25896
|
it('should change state', function() {
|
25583
|
-
|
25897
|
+
var color = element(by.binding('color'));
|
25584
25898
|
|
25585
|
-
|
25586
|
-
|
25899
|
+
expect(color.getText()).toContain('blue');
|
25900
|
+
|
25901
|
+
element.all(by.model('color')).get(0).click();
|
25902
|
+
|
25903
|
+
expect(color.getText()).toContain('red');
|
25587
25904
|
});
|
25588
|
-
</doc:
|
25905
|
+
</doc:protractor>
|
25589
25906
|
</doc:example>
|
25590
25907
|
*/
|
25591
25908
|
'radio': radioInputType,
|
@@ -25622,17 +25939,21 @@ var inputType = {
|
|
25622
25939
|
<tt>value2 = {{value2}}</tt><br/>
|
25623
25940
|
</form>
|
25624
25941
|
</doc:source>
|
25625
|
-
<doc:
|
25942
|
+
<doc:protractor>
|
25626
25943
|
it('should change state', function() {
|
25627
|
-
|
25628
|
-
|
25944
|
+
var value1 = element(by.binding('value1'));
|
25945
|
+
var value2 = element(by.binding('value2'));
|
25629
25946
|
|
25630
|
-
|
25631
|
-
|
25632
|
-
|
25633
|
-
|
25947
|
+
expect(value1.getText()).toContain('true');
|
25948
|
+
expect(value2.getText()).toContain('YES');
|
25949
|
+
|
25950
|
+
element(by.model('value1')).click();
|
25951
|
+
element(by.model('value2')).click();
|
25952
|
+
|
25953
|
+
expect(value1.getText()).toContain('false');
|
25954
|
+
expect(value2.getText()).toContain('NO');
|
25634
25955
|
});
|
25635
|
-
</doc:
|
25956
|
+
</doc:protractor>
|
25636
25957
|
</doc:example>
|
25637
25958
|
*/
|
25638
25959
|
'checkbox': checkboxInputType,
|
@@ -25640,23 +25961,33 @@ var inputType = {
|
|
25640
25961
|
'hidden': noop,
|
25641
25962
|
'button': noop,
|
25642
25963
|
'submit': noop,
|
25643
|
-
'reset': noop
|
25964
|
+
'reset': noop,
|
25965
|
+
'file': noop
|
25644
25966
|
};
|
25645
25967
|
|
25968
|
+
// A helper function to call $setValidity and return the value / undefined,
|
25969
|
+
// a pattern that is repeated a lot in the input validation logic.
|
25970
|
+
function validate(ctrl, validatorName, validity, value){
|
25971
|
+
ctrl.$setValidity(validatorName, validity);
|
25972
|
+
return validity ? value : undefined;
|
25973
|
+
}
|
25646
25974
|
|
25647
25975
|
function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
25648
25976
|
// In composition mode, users are still inputing intermediate text buffer,
|
25649
25977
|
// hold the listener until composition is done.
|
25650
25978
|
// More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
|
25651
|
-
|
25979
|
+
if (!$sniffer.android) {
|
25980
|
+
var composing = false;
|
25652
25981
|
|
25653
|
-
|
25654
|
-
|
25655
|
-
|
25982
|
+
element.on('compositionstart', function(data) {
|
25983
|
+
composing = true;
|
25984
|
+
});
|
25656
25985
|
|
25657
|
-
|
25658
|
-
|
25659
|
-
|
25986
|
+
element.on('compositionend', function() {
|
25987
|
+
composing = false;
|
25988
|
+
listener();
|
25989
|
+
});
|
25990
|
+
}
|
25660
25991
|
|
25661
25992
|
var listener = function() {
|
25662
25993
|
if (composing) return;
|
@@ -25670,9 +26001,13 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
25670
26001
|
}
|
25671
26002
|
|
25672
26003
|
if (ctrl.$viewValue !== value) {
|
25673
|
-
scope
|
26004
|
+
if (scope.$$phase) {
|
25674
26005
|
ctrl.$setViewValue(value);
|
25675
|
-
}
|
26006
|
+
} else {
|
26007
|
+
scope.$apply(function() {
|
26008
|
+
ctrl.$setViewValue(value);
|
26009
|
+
});
|
26010
|
+
}
|
25676
26011
|
}
|
25677
26012
|
};
|
25678
26013
|
|
@@ -25721,22 +26056,15 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
25721
26056
|
patternValidator,
|
25722
26057
|
match;
|
25723
26058
|
|
25724
|
-
var validate = function(regexp, value) {
|
25725
|
-
if (ctrl.$isEmpty(value) || regexp.test(value)) {
|
25726
|
-
ctrl.$setValidity('pattern', true);
|
25727
|
-
return value;
|
25728
|
-
} else {
|
25729
|
-
ctrl.$setValidity('pattern', false);
|
25730
|
-
return undefined;
|
25731
|
-
}
|
25732
|
-
};
|
25733
|
-
|
25734
26059
|
if (pattern) {
|
26060
|
+
var validateRegex = function(regexp, value) {
|
26061
|
+
return validate(ctrl, 'pattern', ctrl.$isEmpty(value) || regexp.test(value), value);
|
26062
|
+
};
|
25735
26063
|
match = pattern.match(/^\/(.*)\/([gim]*)$/);
|
25736
26064
|
if (match) {
|
25737
26065
|
pattern = new RegExp(match[1], match[2]);
|
25738
26066
|
patternValidator = function(value) {
|
25739
|
-
return
|
26067
|
+
return validateRegex(pattern, value);
|
25740
26068
|
};
|
25741
26069
|
} else {
|
25742
26070
|
patternValidator = function(value) {
|
@@ -25747,7 +26075,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
25747
26075
|
'Expected {0} to be a RegExp but was {1}. Element: {2}', pattern,
|
25748
26076
|
patternObj, startingTag(element));
|
25749
26077
|
}
|
25750
|
-
return
|
26078
|
+
return validateRegex(patternObj, value);
|
25751
26079
|
};
|
25752
26080
|
}
|
25753
26081
|
|
@@ -25759,13 +26087,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
25759
26087
|
if (attr.ngMinlength) {
|
25760
26088
|
var minlength = int(attr.ngMinlength);
|
25761
26089
|
var minLengthValidator = function(value) {
|
25762
|
-
|
25763
|
-
ctrl.$setValidity('minlength', false);
|
25764
|
-
return undefined;
|
25765
|
-
} else {
|
25766
|
-
ctrl.$setValidity('minlength', true);
|
25767
|
-
return value;
|
25768
|
-
}
|
26090
|
+
return validate(ctrl, 'minlength', ctrl.$isEmpty(value) || value.length >= minlength, value);
|
25769
26091
|
};
|
25770
26092
|
|
25771
26093
|
ctrl.$parsers.push(minLengthValidator);
|
@@ -25776,13 +26098,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
25776
26098
|
if (attr.ngMaxlength) {
|
25777
26099
|
var maxlength = int(attr.ngMaxlength);
|
25778
26100
|
var maxLengthValidator = function(value) {
|
25779
|
-
|
25780
|
-
ctrl.$setValidity('maxlength', false);
|
25781
|
-
return undefined;
|
25782
|
-
} else {
|
25783
|
-
ctrl.$setValidity('maxlength', true);
|
25784
|
-
return value;
|
25785
|
-
}
|
26101
|
+
return validate(ctrl, 'maxlength', ctrl.$isEmpty(value) || value.length <= maxlength, value);
|
25786
26102
|
};
|
25787
26103
|
|
25788
26104
|
ctrl.$parsers.push(maxLengthValidator);
|
@@ -25811,13 +26127,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
25811
26127
|
if (attr.min) {
|
25812
26128
|
var minValidator = function(value) {
|
25813
26129
|
var min = parseFloat(attr.min);
|
25814
|
-
|
25815
|
-
ctrl.$setValidity('min', false);
|
25816
|
-
return undefined;
|
25817
|
-
} else {
|
25818
|
-
ctrl.$setValidity('min', true);
|
25819
|
-
return value;
|
25820
|
-
}
|
26130
|
+
return validate(ctrl, 'min', ctrl.$isEmpty(value) || value >= min, value);
|
25821
26131
|
};
|
25822
26132
|
|
25823
26133
|
ctrl.$parsers.push(minValidator);
|
@@ -25827,13 +26137,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
25827
26137
|
if (attr.max) {
|
25828
26138
|
var maxValidator = function(value) {
|
25829
26139
|
var max = parseFloat(attr.max);
|
25830
|
-
|
25831
|
-
ctrl.$setValidity('max', false);
|
25832
|
-
return undefined;
|
25833
|
-
} else {
|
25834
|
-
ctrl.$setValidity('max', true);
|
25835
|
-
return value;
|
25836
|
-
}
|
26140
|
+
return validate(ctrl, 'max', ctrl.$isEmpty(value) || value <= max, value);
|
25837
26141
|
};
|
25838
26142
|
|
25839
26143
|
ctrl.$parsers.push(maxValidator);
|
@@ -25841,14 +26145,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
25841
26145
|
}
|
25842
26146
|
|
25843
26147
|
ctrl.$formatters.push(function(value) {
|
25844
|
-
|
25845
|
-
if (ctrl.$isEmpty(value) || isNumber(value)) {
|
25846
|
-
ctrl.$setValidity('number', true);
|
25847
|
-
return value;
|
25848
|
-
} else {
|
25849
|
-
ctrl.$setValidity('number', false);
|
25850
|
-
return undefined;
|
25851
|
-
}
|
26148
|
+
return validate(ctrl, 'number', ctrl.$isEmpty(value) || isNumber(value), value);
|
25852
26149
|
});
|
25853
26150
|
}
|
25854
26151
|
|
@@ -25856,13 +26153,7 @@ function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
25856
26153
|
textInputType(scope, element, attr, ctrl, $sniffer, $browser);
|
25857
26154
|
|
25858
26155
|
var urlValidator = function(value) {
|
25859
|
-
|
25860
|
-
ctrl.$setValidity('url', true);
|
25861
|
-
return value;
|
25862
|
-
} else {
|
25863
|
-
ctrl.$setValidity('url', false);
|
25864
|
-
return undefined;
|
25865
|
-
}
|
26156
|
+
return validate(ctrl, 'url', ctrl.$isEmpty(value) || URL_REGEXP.test(value), value);
|
25866
26157
|
};
|
25867
26158
|
|
25868
26159
|
ctrl.$formatters.push(urlValidator);
|
@@ -25873,13 +26164,7 @@ function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
25873
26164
|
textInputType(scope, element, attr, ctrl, $sniffer, $browser);
|
25874
26165
|
|
25875
26166
|
var emailValidator = function(value) {
|
25876
|
-
|
25877
|
-
ctrl.$setValidity('email', true);
|
25878
|
-
return value;
|
25879
|
-
} else {
|
25880
|
-
ctrl.$setValidity('email', false);
|
25881
|
-
return undefined;
|
25882
|
-
}
|
26167
|
+
return validate(ctrl, 'email', ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value), value);
|
25883
26168
|
};
|
25884
26169
|
|
25885
26170
|
ctrl.$formatters.push(emailValidator);
|
@@ -26023,44 +26308,59 @@ function checkboxInputType(scope, element, attr, ctrl) {
|
|
26023
26308
|
<tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
|
26024
26309
|
</div>
|
26025
26310
|
</doc:source>
|
26026
|
-
<doc:
|
26311
|
+
<doc:protractor>
|
26312
|
+
var user = element(by.binding('{{user}}'));
|
26313
|
+
var userNameValid = element(by.binding('myForm.userName.$valid'));
|
26314
|
+
var lastNameValid = element(by.binding('myForm.lastName.$valid'));
|
26315
|
+
var lastNameError = element(by.binding('myForm.lastName.$error'));
|
26316
|
+
var formValid = element(by.binding('myForm.$valid'));
|
26317
|
+
var userNameInput = element(by.model('user.name'));
|
26318
|
+
var userLastInput = element(by.model('user.last'));
|
26319
|
+
|
26027
26320
|
it('should initialize to model', function() {
|
26028
|
-
expect(
|
26029
|
-
expect(
|
26030
|
-
expect(
|
26321
|
+
expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
|
26322
|
+
expect(userNameValid.getText()).toContain('true');
|
26323
|
+
expect(formValid.getText()).toContain('true');
|
26031
26324
|
});
|
26032
26325
|
|
26033
26326
|
it('should be invalid if empty when required', function() {
|
26034
|
-
|
26035
|
-
|
26036
|
-
|
26037
|
-
expect(
|
26327
|
+
userNameInput.clear();
|
26328
|
+
userNameInput.sendKeys('');
|
26329
|
+
|
26330
|
+
expect(user.getText()).toContain('{"last":"visitor"}');
|
26331
|
+
expect(userNameValid.getText()).toContain('false');
|
26332
|
+
expect(formValid.getText()).toContain('false');
|
26038
26333
|
});
|
26039
26334
|
|
26040
26335
|
it('should be valid if empty when min length is set', function() {
|
26041
|
-
|
26042
|
-
|
26043
|
-
|
26044
|
-
expect(
|
26336
|
+
userLastInput.clear();
|
26337
|
+
userLastInput.sendKeys('');
|
26338
|
+
|
26339
|
+
expect(user.getText()).toContain('{"name":"guest","last":""}');
|
26340
|
+
expect(lastNameValid.getText()).toContain('true');
|
26341
|
+
expect(formValid.getText()).toContain('true');
|
26045
26342
|
});
|
26046
26343
|
|
26047
26344
|
it('should be invalid if less than required min length', function() {
|
26048
|
-
|
26049
|
-
|
26050
|
-
|
26051
|
-
expect(
|
26052
|
-
expect(
|
26345
|
+
userLastInput.clear();
|
26346
|
+
userLastInput.sendKeys('xx');
|
26347
|
+
|
26348
|
+
expect(user.getText()).toContain('{"name":"guest"}');
|
26349
|
+
expect(lastNameValid.getText()).toContain('false');
|
26350
|
+
expect(lastNameError.getText()).toContain('minlength');
|
26351
|
+
expect(formValid.getText()).toContain('false');
|
26053
26352
|
});
|
26054
26353
|
|
26055
26354
|
it('should be invalid if longer than max length', function() {
|
26056
|
-
|
26057
|
-
|
26058
|
-
|
26059
|
-
expect(
|
26060
|
-
expect(
|
26061
|
-
expect(
|
26355
|
+
userLastInput.clear();
|
26356
|
+
userLastInput.sendKeys('some ridiculously long name');
|
26357
|
+
|
26358
|
+
expect(user.getText()).toContain('{"name":"guest"}');
|
26359
|
+
expect(lastNameValid.getText()).toContain('false');
|
26360
|
+
expect(lastNameError.getText()).toContain('maxlength');
|
26361
|
+
expect(formValid.getText()).toContain('false');
|
26062
26362
|
});
|
26063
|
-
</doc:
|
26363
|
+
</doc:protractor>
|
26064
26364
|
</doc:example>
|
26065
26365
|
*/
|
26066
26366
|
var inputDirective = ['$browser', '$sniffer', function($browser, $sniffer) {
|
@@ -26192,14 +26492,23 @@ var VALID_CLASS = 'ng-valid',
|
|
26192
26492
|
<textarea ng-model="userContent"></textarea>
|
26193
26493
|
</form>
|
26194
26494
|
</file>
|
26195
|
-
<file name="
|
26495
|
+
<file name="protractorTest.js">
|
26196
26496
|
it('should data-bind and become invalid', function() {
|
26197
|
-
|
26497
|
+
if (browser.params.browser = 'safari') {
|
26498
|
+
// SafariDriver can't handle contenteditable.
|
26499
|
+
return;
|
26500
|
+
};
|
26501
|
+
var contentEditable = element(by.css('.doc-example-live [contenteditable]'));
|
26502
|
+
|
26503
|
+
expect(contentEditable.getText()).toEqual('Change me!');
|
26504
|
+
|
26505
|
+
// Firefox driver doesn't trigger the proper events on 'clear', so do this hack
|
26506
|
+
contentEditable.click();
|
26507
|
+
contentEditable.sendKeys(protractor.Key.chord(protractor.Key.COMMAND, "a"));
|
26508
|
+
contentEditable.sendKeys(protractor.Key.BACK_SPACE);
|
26198
26509
|
|
26199
|
-
expect(contentEditable.
|
26200
|
-
|
26201
|
-
expect(contentEditable.text()).toEqual('');
|
26202
|
-
expect(contentEditable.prop('className')).toMatch(/ng-invalid-required/);
|
26510
|
+
expect(contentEditable.getText()).toEqual('');
|
26511
|
+
expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
|
26203
26512
|
});
|
26204
26513
|
</file>
|
26205
26514
|
* </example>
|
@@ -26252,6 +26561,9 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
26252
26561
|
* You can override this for input directives whose concept of being empty is different to the
|
26253
26562
|
* default. The `checkboxInputType` directive does this because in its case a value of `false`
|
26254
26563
|
* implies empty.
|
26564
|
+
*
|
26565
|
+
* @param {*} value Reference to check.
|
26566
|
+
* @returns {boolean} True if `value` is empty.
|
26255
26567
|
*/
|
26256
26568
|
this.$isEmpty = function(value) {
|
26257
26569
|
return isUndefined(value) || value === '' || value === null || value !== value;
|
@@ -26479,7 +26791,10 @@ var ngModelDirective = function() {
|
|
26479
26791
|
* @name ng.directive:ngChange
|
26480
26792
|
*
|
26481
26793
|
* @description
|
26482
|
-
* Evaluate given expression when user changes the input.
|
26794
|
+
* Evaluate the given expression when the user changes the input.
|
26795
|
+
* The expression is evaluated immediately, unlike the JavaScript onchange event
|
26796
|
+
* which only triggers at the end of a change (usually, when the user leaves the
|
26797
|
+
* form element or presses the return key).
|
26483
26798
|
* The expression is not evaluated when the value change is coming from the model.
|
26484
26799
|
*
|
26485
26800
|
* Note, this directive requires `ngModel` to be present.
|
@@ -26503,24 +26818,30 @@ var ngModelDirective = function() {
|
|
26503
26818
|
* <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
|
26504
26819
|
* <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
|
26505
26820
|
* <label for="ng-change-example2">Confirmed</label><br />
|
26506
|
-
* debug = {{confirmed}}
|
26507
|
-
* counter = {{counter}}
|
26821
|
+
* <tt>debug = {{confirmed}}</tt><br/>
|
26822
|
+
* <tt>counter = {{counter}}</tt><br/>
|
26508
26823
|
* </div>
|
26509
26824
|
* </doc:source>
|
26510
|
-
* <doc:
|
26825
|
+
* <doc:protractor>
|
26826
|
+
* var counter = element(by.binding('counter'));
|
26827
|
+
* var debug = element(by.binding('confirmed'));
|
26828
|
+
*
|
26511
26829
|
* it('should evaluate the expression if changing from view', function() {
|
26512
|
-
* expect(
|
26513
|
-
*
|
26514
|
-
*
|
26515
|
-
*
|
26830
|
+
* expect(counter.getText()).toContain('0');
|
26831
|
+
*
|
26832
|
+
* element(by.id('ng-change-example1')).click();
|
26833
|
+
*
|
26834
|
+
* expect(counter.getText()).toContain('1');
|
26835
|
+
* expect(debug.getText()).toContain('true');
|
26516
26836
|
* });
|
26517
26837
|
*
|
26518
26838
|
* it('should not evaluate the expression if changing from model', function() {
|
26519
|
-
* element('
|
26520
|
-
|
26521
|
-
* expect(
|
26839
|
+
* element(by.id('ng-change-example2')).click();
|
26840
|
+
|
26841
|
+
* expect(counter.getText()).toContain('0');
|
26842
|
+
* expect(debug.getText()).toContain('true');
|
26522
26843
|
* });
|
26523
|
-
* </doc:
|
26844
|
+
* </doc:protractor>
|
26524
26845
|
* </doc:example>
|
26525
26846
|
*/
|
26526
26847
|
var ngChangeDirective = valueFn({
|
@@ -26593,20 +26914,26 @@ var requiredDirective = function() {
|
|
26593
26914
|
<tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
|
26594
26915
|
</form>
|
26595
26916
|
</doc:source>
|
26596
|
-
<doc:
|
26917
|
+
<doc:protractor>
|
26918
|
+
var listInput = element(by.model('names'));
|
26919
|
+
var names = element(by.binding('{{names}}'));
|
26920
|
+
var valid = element(by.binding('myForm.namesInput.$valid'));
|
26921
|
+
var error = element(by.css('span.error'));
|
26922
|
+
|
26597
26923
|
it('should initialize to model', function() {
|
26598
|
-
expect(
|
26599
|
-
expect(
|
26600
|
-
expect(
|
26924
|
+
expect(names.getText()).toContain('["igor","misko","vojta"]');
|
26925
|
+
expect(valid.getText()).toContain('true');
|
26926
|
+
expect(error.getCssValue('display')).toBe('none');
|
26601
26927
|
});
|
26602
26928
|
|
26603
26929
|
it('should be invalid if empty', function() {
|
26604
|
-
|
26605
|
-
|
26606
|
-
|
26607
|
-
expect(
|
26608
|
-
|
26609
|
-
|
26930
|
+
listInput.clear();
|
26931
|
+
listInput.sendKeys('');
|
26932
|
+
|
26933
|
+
expect(names.getText()).toContain('');
|
26934
|
+
expect(valid.getText()).toContain('false');
|
26935
|
+
expect(error.getCssValue('display')).not.toBe('none'); });
|
26936
|
+
</doc:protractor>
|
26610
26937
|
</doc:example>
|
26611
26938
|
*/
|
26612
26939
|
var ngListDirective = function() {
|
@@ -26688,15 +27015,17 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
|
|
26688
27015
|
<div>You chose {{my.favorite}}</div>
|
26689
27016
|
</form>
|
26690
27017
|
</doc:source>
|
26691
|
-
<doc:
|
27018
|
+
<doc:protractor>
|
27019
|
+
var favorite = element(by.binding('my.favorite'));
|
27020
|
+
|
26692
27021
|
it('should initialize to model', function() {
|
26693
|
-
expect(
|
27022
|
+
expect(favorite.getText()).toContain('unicorns');
|
26694
27023
|
});
|
26695
27024
|
it('should bind the values to the inputs', function() {
|
26696
|
-
|
26697
|
-
expect(
|
27025
|
+
element.all(by.model('my.favorite')).get(0).click();
|
27026
|
+
expect(favorite.getText()).toContain('pizza');
|
26698
27027
|
});
|
26699
|
-
</doc:
|
27028
|
+
</doc:protractor>
|
26700
27029
|
</doc:example>
|
26701
27030
|
*/
|
26702
27031
|
var ngValueDirective = function() {
|
@@ -26756,13 +27085,17 @@ var ngValueDirective = function() {
|
|
26756
27085
|
Hello <span ng-bind="name"></span>!
|
26757
27086
|
</div>
|
26758
27087
|
</doc:source>
|
26759
|
-
<doc:
|
27088
|
+
<doc:protractor>
|
26760
27089
|
it('should check ng-bind', function() {
|
26761
|
-
|
26762
|
-
|
26763
|
-
|
27090
|
+
var exampleContainer = $('.doc-example-live');
|
27091
|
+
var nameInput = element(by.model('name'));
|
27092
|
+
|
27093
|
+
expect(exampleContainer.findElement(by.binding('name')).getText()).toBe('Whirled');
|
27094
|
+
nameInput.clear();
|
27095
|
+
nameInput.sendKeys('world');
|
27096
|
+
expect(exampleContainer.findElement(by.binding('name')).getText()).toBe('world');
|
26764
27097
|
});
|
26765
|
-
</doc:
|
27098
|
+
</doc:protractor>
|
26766
27099
|
</doc:example>
|
26767
27100
|
*/
|
26768
27101
|
var ngBindDirective = ngDirective(function(scope, element, attr) {
|
@@ -26808,20 +27141,22 @@ var ngBindDirective = ngDirective(function(scope, element, attr) {
|
|
26808
27141
|
<pre ng-bind-template="{{salutation}} {{name}}!"></pre>
|
26809
27142
|
</div>
|
26810
27143
|
</doc:source>
|
26811
|
-
<doc:
|
27144
|
+
<doc:protractor>
|
26812
27145
|
it('should check ng-bind', function() {
|
26813
|
-
|
26814
|
-
|
26815
|
-
|
26816
|
-
|
26817
|
-
|
26818
|
-
|
26819
|
-
|
26820
|
-
|
26821
|
-
|
26822
|
-
|
27146
|
+
var salutationElem = element(by.binding('salutation'));
|
27147
|
+
var salutationInput = element(by.model('salutation'));
|
27148
|
+
var nameInput = element(by.model('name'));
|
27149
|
+
|
27150
|
+
expect(salutationElem.getText()).toBe('Hello World!');
|
27151
|
+
|
27152
|
+
salutationInput.clear();
|
27153
|
+
salutationInput.sendKeys('Greetings');
|
27154
|
+
nameInput.clear();
|
27155
|
+
nameInput.sendKeys('user');
|
27156
|
+
|
27157
|
+
expect(salutationElem.getText()).toBe('Greetings user!');
|
26823
27158
|
});
|
26824
|
-
</doc:
|
27159
|
+
</doc:protractor>
|
26825
27160
|
</doc:example>
|
26826
27161
|
*/
|
26827
27162
|
var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
|
@@ -26874,12 +27209,10 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
|
|
26874
27209
|
}]);
|
26875
27210
|
</file>
|
26876
27211
|
|
26877
|
-
<file name="
|
27212
|
+
<file name="protractorTest.js">
|
26878
27213
|
it('should check ng-bind-html', function() {
|
26879
|
-
expect(
|
26880
|
-
|
26881
|
-
'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>'
|
26882
|
-
);
|
27214
|
+
expect(element(by.binding('myHTML')).getText()).toBe(
|
27215
|
+
'I am an HTMLstring with links! and other stuff');
|
26883
27216
|
});
|
26884
27217
|
</file>
|
26885
27218
|
</example>
|
@@ -27011,31 +27344,34 @@ function classDirective(name, selector) {
|
|
27011
27344
|
color: red;
|
27012
27345
|
}
|
27013
27346
|
</file>
|
27014
|
-
<file name="
|
27347
|
+
<file name="protractorTest.js">
|
27348
|
+
var ps = element.all(by.css('.doc-example-live p'));
|
27349
|
+
|
27015
27350
|
it('should let you toggle the class', function() {
|
27016
27351
|
|
27017
|
-
expect(
|
27018
|
-
expect(
|
27352
|
+
expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
|
27353
|
+
expect(ps.first().getAttribute('class')).not.toMatch(/red/);
|
27019
27354
|
|
27020
|
-
|
27021
|
-
expect(
|
27355
|
+
element(by.model('important')).click();
|
27356
|
+
expect(ps.first().getAttribute('class')).toMatch(/bold/);
|
27022
27357
|
|
27023
|
-
|
27024
|
-
expect(
|
27358
|
+
element(by.model('error')).click();
|
27359
|
+
expect(ps.first().getAttribute('class')).toMatch(/red/);
|
27025
27360
|
});
|
27026
27361
|
|
27027
27362
|
it('should let you toggle string example', function() {
|
27028
|
-
expect(
|
27029
|
-
|
27030
|
-
|
27363
|
+
expect(ps.get(1).getAttribute('class')).toBe('');
|
27364
|
+
element(by.model('style')).clear();
|
27365
|
+
element(by.model('style')).sendKeys('red');
|
27366
|
+
expect(ps.get(1).getAttribute('class')).toBe('red');
|
27031
27367
|
});
|
27032
27368
|
|
27033
27369
|
it('array example should have 3 classes', function() {
|
27034
|
-
expect(
|
27035
|
-
|
27036
|
-
|
27037
|
-
|
27038
|
-
expect(
|
27370
|
+
expect(ps.last().getAttribute('class')).toBe('');
|
27371
|
+
element(by.model('style1')).sendKeys('bold');
|
27372
|
+
element(by.model('style2')).sendKeys('strike');
|
27373
|
+
element(by.model('style3')).sendKeys('red');
|
27374
|
+
expect(ps.last().getAttribute('class')).toBe('bold strike red');
|
27039
27375
|
});
|
27040
27376
|
</file>
|
27041
27377
|
</example>
|
@@ -27046,8 +27382,8 @@ function classDirective(name, selector) {
|
|
27046
27382
|
|
27047
27383
|
<example animations="true">
|
27048
27384
|
<file name="index.html">
|
27049
|
-
<input type="button" value="set" ng-click="myVar='my-class'">
|
27050
|
-
<input type="button" value="clear" ng-click="myVar=''">
|
27385
|
+
<input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
|
27386
|
+
<input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
|
27051
27387
|
<br>
|
27052
27388
|
<span class="base-class" ng-class="myVar">Sample Text</span>
|
27053
27389
|
</file>
|
@@ -27062,19 +27398,19 @@ function classDirective(name, selector) {
|
|
27062
27398
|
font-size:3em;
|
27063
27399
|
}
|
27064
27400
|
</file>
|
27065
|
-
<file name="
|
27401
|
+
<file name="protractorTest.js">
|
27066
27402
|
it('should check ng-class', function() {
|
27067
|
-
expect(element('.
|
27403
|
+
expect(element(by.css('.base-class')).getAttribute('class')).not.
|
27068
27404
|
toMatch(/my-class/);
|
27069
27405
|
|
27070
|
-
|
27406
|
+
element(by.id('setbtn')).click();
|
27071
27407
|
|
27072
|
-
expect(element('.
|
27408
|
+
expect(element(by.css('.base-class')).getAttribute('class')).
|
27073
27409
|
toMatch(/my-class/);
|
27074
27410
|
|
27075
|
-
|
27411
|
+
element(by.id('clearbtn')).click();
|
27076
27412
|
|
27077
|
-
expect(element('.
|
27413
|
+
expect(element(by.css('.base-class')).getAttribute('class')).not.
|
27078
27414
|
toMatch(/my-class/);
|
27079
27415
|
});
|
27080
27416
|
</file>
|
@@ -27126,11 +27462,11 @@ var ngClassDirective = classDirective('', true);
|
|
27126
27462
|
color: blue;
|
27127
27463
|
}
|
27128
27464
|
</file>
|
27129
|
-
<file name="
|
27465
|
+
<file name="protractorTest.js">
|
27130
27466
|
it('should check ng-class-odd and ng-class-even', function() {
|
27131
|
-
expect(element('
|
27467
|
+
expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
|
27132
27468
|
toMatch(/odd/);
|
27133
|
-
expect(element('
|
27469
|
+
expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
|
27134
27470
|
toMatch(/even/);
|
27135
27471
|
});
|
27136
27472
|
</file>
|
@@ -27174,11 +27510,11 @@ var ngClassOddDirective = classDirective('Odd', 0);
|
|
27174
27510
|
color: blue;
|
27175
27511
|
}
|
27176
27512
|
</file>
|
27177
|
-
<file name="
|
27513
|
+
<file name="protractorTest.js">
|
27178
27514
|
it('should check ng-class-odd and ng-class-even', function() {
|
27179
|
-
expect(element('
|
27515
|
+
expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
|
27180
27516
|
toMatch(/odd/);
|
27181
|
-
expect(element('
|
27517
|
+
expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
|
27182
27518
|
toMatch(/even/);
|
27183
27519
|
});
|
27184
27520
|
</file>
|
@@ -27221,7 +27557,7 @@ var ngClassEvenDirective = classDirective('Even', 1);
|
|
27221
27557
|
*
|
27222
27558
|
* Legacy browsers, like IE7, do not provide attribute selector support (added in CSS 2.1) so they
|
27223
27559
|
* cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
|
27224
|
-
* class `
|
27560
|
+
* class `ng-cloak` in addition to the `ngCloak` directive as shown in the example below.
|
27225
27561
|
*
|
27226
27562
|
* @element ANY
|
27227
27563
|
*
|
@@ -27231,14 +27567,14 @@ var ngClassEvenDirective = classDirective('Even', 1);
|
|
27231
27567
|
<div id="template1" ng-cloak>{{ 'hello' }}</div>
|
27232
27568
|
<div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>
|
27233
27569
|
</doc:source>
|
27234
|
-
<doc:
|
27570
|
+
<doc:protractor>
|
27235
27571
|
it('should remove the template directive and css class', function() {
|
27236
|
-
expect(
|
27237
|
-
|
27238
|
-
expect(
|
27239
|
-
|
27572
|
+
expect($('.doc-example-live #template1').getAttribute('ng-cloak')).
|
27573
|
+
toBeNull();
|
27574
|
+
expect($('.doc-example-live #template2').getAttribute('ng-cloak')).
|
27575
|
+
toBeNull();
|
27240
27576
|
});
|
27241
|
-
</doc:
|
27577
|
+
</doc:protractor>
|
27242
27578
|
</doc:example>
|
27243
27579
|
*
|
27244
27580
|
*/
|
@@ -27331,22 +27667,36 @@ var ngCloakDirective = ngDirective({
|
|
27331
27667
|
</ul>
|
27332
27668
|
</div>
|
27333
27669
|
</doc:source>
|
27334
|
-
<doc:
|
27670
|
+
<doc:protractor>
|
27335
27671
|
it('should check controller as', function() {
|
27336
|
-
|
27337
|
-
|
27338
|
-
|
27339
|
-
|
27340
|
-
|
27341
|
-
|
27342
|
-
|
27343
|
-
|
27344
|
-
|
27345
|
-
|
27346
|
-
expect(
|
27347
|
-
|
27672
|
+
var container = element(by.id('ctrl-as-exmpl'));
|
27673
|
+
|
27674
|
+
expect(container.findElement(by.model('settings.name'))
|
27675
|
+
.getAttribute('value')).toBe('John Smith');
|
27676
|
+
|
27677
|
+
var firstRepeat =
|
27678
|
+
container.findElement(by.repeater('contact in settings.contacts').row(0));
|
27679
|
+
var secondRepeat =
|
27680
|
+
container.findElement(by.repeater('contact in settings.contacts').row(1));
|
27681
|
+
|
27682
|
+
expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
|
27683
|
+
.toBe('408 555 1212');
|
27684
|
+
expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
|
27685
|
+
.toBe('john.smith@example.org');
|
27686
|
+
|
27687
|
+
firstRepeat.findElement(by.linkText('clear')).click()
|
27688
|
+
|
27689
|
+
expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
|
27690
|
+
.toBe('');
|
27691
|
+
|
27692
|
+
container.findElement(by.linkText('add')).click();
|
27693
|
+
|
27694
|
+
expect(container.findElement(by.repeater('contact in settings.contacts').row(2))
|
27695
|
+
.findElement(by.model('contact.value'))
|
27696
|
+
.getAttribute('value'))
|
27697
|
+
.toBe('yourname@example.org');
|
27348
27698
|
});
|
27349
|
-
</doc:
|
27699
|
+
</doc:protractor>
|
27350
27700
|
</doc:example>
|
27351
27701
|
<doc:example>
|
27352
27702
|
<doc:source>
|
@@ -27394,22 +27744,36 @@ var ngCloakDirective = ngDirective({
|
|
27394
27744
|
</ul>
|
27395
27745
|
</div>
|
27396
27746
|
</doc:source>
|
27397
|
-
<doc:
|
27747
|
+
<doc:protractor>
|
27398
27748
|
it('should check controller', function() {
|
27399
|
-
|
27400
|
-
|
27401
|
-
|
27402
|
-
|
27403
|
-
|
27404
|
-
|
27405
|
-
|
27406
|
-
|
27407
|
-
|
27408
|
-
|
27409
|
-
expect(
|
27410
|
-
|
27749
|
+
var container = element(by.id('ctrl-exmpl'));
|
27750
|
+
|
27751
|
+
expect(container.findElement(by.model('name'))
|
27752
|
+
.getAttribute('value')).toBe('John Smith');
|
27753
|
+
|
27754
|
+
var firstRepeat =
|
27755
|
+
container.findElement(by.repeater('contact in contacts').row(0));
|
27756
|
+
var secondRepeat =
|
27757
|
+
container.findElement(by.repeater('contact in contacts').row(1));
|
27758
|
+
|
27759
|
+
expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
|
27760
|
+
.toBe('408 555 1212');
|
27761
|
+
expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
|
27762
|
+
.toBe('john.smith@example.org');
|
27763
|
+
|
27764
|
+
firstRepeat.findElement(by.linkText('clear')).click()
|
27765
|
+
|
27766
|
+
expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
|
27767
|
+
.toBe('');
|
27768
|
+
|
27769
|
+
container.findElement(by.linkText('add')).click();
|
27770
|
+
|
27771
|
+
expect(container.findElement(by.repeater('contact in contacts').row(2))
|
27772
|
+
.findElement(by.model('contact.value'))
|
27773
|
+
.getAttribute('value'))
|
27774
|
+
.toBe('yourname@example.org');
|
27411
27775
|
});
|
27412
|
-
</doc:
|
27776
|
+
</doc:protractor>
|
27413
27777
|
</doc:example>
|
27414
27778
|
|
27415
27779
|
*/
|
@@ -27472,6 +27836,7 @@ var ngControllerDirective = [function() {
|
|
27472
27836
|
* an element is clicked.
|
27473
27837
|
*
|
27474
27838
|
* @element ANY
|
27839
|
+
* @priority 0
|
27475
27840
|
* @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
|
27476
27841
|
* click. (Event object is available as `$event`)
|
27477
27842
|
*
|
@@ -27483,13 +27848,13 @@ var ngControllerDirective = [function() {
|
|
27483
27848
|
</button>
|
27484
27849
|
count: {{count}}
|
27485
27850
|
</doc:source>
|
27486
|
-
<doc:
|
27851
|
+
<doc:protractor>
|
27487
27852
|
it('should check ng-click', function() {
|
27488
|
-
expect(binding('count')).
|
27489
|
-
element('.doc-example-live
|
27490
|
-
expect(binding('count')).
|
27853
|
+
expect(element(by.binding('count')).getText()).toMatch('0');
|
27854
|
+
element(by.css('.doc-example-live button')).click();
|
27855
|
+
expect(element(by.binding('count')).getText()).toMatch('1');
|
27491
27856
|
});
|
27492
|
-
</doc:
|
27857
|
+
</doc:protractor>
|
27493
27858
|
</doc:example>
|
27494
27859
|
*/
|
27495
27860
|
/*
|
@@ -27528,11 +27893,19 @@ forEach(
|
|
27528
27893
|
* The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
|
27529
27894
|
*
|
27530
27895
|
* @element ANY
|
27896
|
+
* @priority 0
|
27531
27897
|
* @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
|
27532
27898
|
* a dblclick. (The Event object is available as `$event`)
|
27533
27899
|
*
|
27534
27900
|
* @example
|
27535
|
-
|
27901
|
+
<doc:example>
|
27902
|
+
<doc:source>
|
27903
|
+
<button ng-dblclick="count = count + 1" ng-init="count=0">
|
27904
|
+
Increment (on double click)
|
27905
|
+
</button>
|
27906
|
+
count: {{count}}
|
27907
|
+
</doc:source>
|
27908
|
+
</doc:example>
|
27536
27909
|
*/
|
27537
27910
|
|
27538
27911
|
|
@@ -27544,11 +27917,19 @@ forEach(
|
|
27544
27917
|
* The ngMousedown directive allows you to specify custom behavior on mousedown event.
|
27545
27918
|
*
|
27546
27919
|
* @element ANY
|
27920
|
+
* @priority 0
|
27547
27921
|
* @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
|
27548
27922
|
* mousedown. (Event object is available as `$event`)
|
27549
27923
|
*
|
27550
27924
|
* @example
|
27551
|
-
|
27925
|
+
<doc:example>
|
27926
|
+
<doc:source>
|
27927
|
+
<button ng-mousedown="count = count + 1" ng-init="count=0">
|
27928
|
+
Increment (on mouse down)
|
27929
|
+
</button>
|
27930
|
+
count: {{count}}
|
27931
|
+
</doc:source>
|
27932
|
+
</doc:example>
|
27552
27933
|
*/
|
27553
27934
|
|
27554
27935
|
|
@@ -27560,11 +27941,19 @@ forEach(
|
|
27560
27941
|
* Specify custom behavior on mouseup event.
|
27561
27942
|
*
|
27562
27943
|
* @element ANY
|
27944
|
+
* @priority 0
|
27563
27945
|
* @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
|
27564
27946
|
* mouseup. (Event object is available as `$event`)
|
27565
27947
|
*
|
27566
27948
|
* @example
|
27567
|
-
|
27949
|
+
<doc:example>
|
27950
|
+
<doc:source>
|
27951
|
+
<button ng-mouseup="count = count + 1" ng-init="count=0">
|
27952
|
+
Increment (on mouse up)
|
27953
|
+
</button>
|
27954
|
+
count: {{count}}
|
27955
|
+
</doc:source>
|
27956
|
+
</doc:example>
|
27568
27957
|
*/
|
27569
27958
|
|
27570
27959
|
/**
|
@@ -27575,11 +27964,19 @@ forEach(
|
|
27575
27964
|
* Specify custom behavior on mouseover event.
|
27576
27965
|
*
|
27577
27966
|
* @element ANY
|
27967
|
+
* @priority 0
|
27578
27968
|
* @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
|
27579
27969
|
* mouseover. (Event object is available as `$event`)
|
27580
27970
|
*
|
27581
27971
|
* @example
|
27582
|
-
|
27972
|
+
<doc:example>
|
27973
|
+
<doc:source>
|
27974
|
+
<button ng-mouseover="count = count + 1" ng-init="count=0">
|
27975
|
+
Increment (when mouse is over)
|
27976
|
+
</button>
|
27977
|
+
count: {{count}}
|
27978
|
+
</doc:source>
|
27979
|
+
</doc:example>
|
27583
27980
|
*/
|
27584
27981
|
|
27585
27982
|
|
@@ -27591,11 +27988,19 @@ forEach(
|
|
27591
27988
|
* Specify custom behavior on mouseenter event.
|
27592
27989
|
*
|
27593
27990
|
* @element ANY
|
27991
|
+
* @priority 0
|
27594
27992
|
* @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
|
27595
27993
|
* mouseenter. (Event object is available as `$event`)
|
27596
27994
|
*
|
27597
27995
|
* @example
|
27598
|
-
|
27996
|
+
<doc:example>
|
27997
|
+
<doc:source>
|
27998
|
+
<button ng-mouseenter="count = count + 1" ng-init="count=0">
|
27999
|
+
Increment (when mouse enters)
|
28000
|
+
</button>
|
28001
|
+
count: {{count}}
|
28002
|
+
</doc:source>
|
28003
|
+
</doc:example>
|
27599
28004
|
*/
|
27600
28005
|
|
27601
28006
|
|
@@ -27607,11 +28012,19 @@ forEach(
|
|
27607
28012
|
* Specify custom behavior on mouseleave event.
|
27608
28013
|
*
|
27609
28014
|
* @element ANY
|
28015
|
+
* @priority 0
|
27610
28016
|
* @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
|
27611
28017
|
* mouseleave. (Event object is available as `$event`)
|
27612
28018
|
*
|
27613
28019
|
* @example
|
27614
|
-
|
28020
|
+
<doc:example>
|
28021
|
+
<doc:source>
|
28022
|
+
<button ng-mouseleave="count = count + 1" ng-init="count=0">
|
28023
|
+
Increment (when mouse leaves)
|
28024
|
+
</button>
|
28025
|
+
count: {{count}}
|
28026
|
+
</doc:source>
|
28027
|
+
</doc:example>
|
27615
28028
|
*/
|
27616
28029
|
|
27617
28030
|
|
@@ -27623,11 +28036,19 @@ forEach(
|
|
27623
28036
|
* Specify custom behavior on mousemove event.
|
27624
28037
|
*
|
27625
28038
|
* @element ANY
|
28039
|
+
* @priority 0
|
27626
28040
|
* @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
|
27627
28041
|
* mousemove. (Event object is available as `$event`)
|
27628
28042
|
*
|
27629
28043
|
* @example
|
27630
|
-
|
28044
|
+
<doc:example>
|
28045
|
+
<doc:source>
|
28046
|
+
<button ng-mousemove="count = count + 1" ng-init="count=0">
|
28047
|
+
Increment (when mouse moves)
|
28048
|
+
</button>
|
28049
|
+
count: {{count}}
|
28050
|
+
</doc:source>
|
28051
|
+
</doc:example>
|
27631
28052
|
*/
|
27632
28053
|
|
27633
28054
|
|
@@ -27639,11 +28060,17 @@ forEach(
|
|
27639
28060
|
* Specify custom behavior on keydown event.
|
27640
28061
|
*
|
27641
28062
|
* @element ANY
|
28063
|
+
* @priority 0
|
27642
28064
|
* @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
|
27643
28065
|
* keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
|
27644
28066
|
*
|
27645
28067
|
* @example
|
27646
|
-
|
28068
|
+
<doc:example>
|
28069
|
+
<doc:source>
|
28070
|
+
<input ng-keydown="count = count + 1" ng-init="count=0">
|
28071
|
+
key down count: {{count}}
|
28072
|
+
</doc:source>
|
28073
|
+
</doc:example>
|
27647
28074
|
*/
|
27648
28075
|
|
27649
28076
|
|
@@ -27655,11 +28082,17 @@ forEach(
|
|
27655
28082
|
* Specify custom behavior on keyup event.
|
27656
28083
|
*
|
27657
28084
|
* @element ANY
|
28085
|
+
* @priority 0
|
27658
28086
|
* @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
|
27659
28087
|
* keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
|
27660
28088
|
*
|
27661
28089
|
* @example
|
27662
|
-
|
28090
|
+
<doc:example>
|
28091
|
+
<doc:source>
|
28092
|
+
<input ng-keyup="count = count + 1" ng-init="count=0">
|
28093
|
+
key up count: {{count}}
|
28094
|
+
</doc:source>
|
28095
|
+
</doc:example>
|
27663
28096
|
*/
|
27664
28097
|
|
27665
28098
|
|
@@ -27675,7 +28108,12 @@ forEach(
|
|
27675
28108
|
* keypress. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
|
27676
28109
|
*
|
27677
28110
|
* @example
|
27678
|
-
|
28111
|
+
<doc:example>
|
28112
|
+
<doc:source>
|
28113
|
+
<input ng-keypress="count = count + 1" ng-init="count=0">
|
28114
|
+
key press count: {{count}}
|
28115
|
+
</doc:source>
|
28116
|
+
</doc:example>
|
27679
28117
|
*/
|
27680
28118
|
|
27681
28119
|
|
@@ -27687,10 +28125,11 @@ forEach(
|
|
27687
28125
|
* Enables binding angular expressions to onsubmit events.
|
27688
28126
|
*
|
27689
28127
|
* Additionally it prevents the default action (which for form means sending the request to the
|
27690
|
-
* server and reloading the current page)
|
27691
|
-
*
|
28128
|
+
* server and reloading the current page), but only if the form does not contain `action`,
|
28129
|
+
* `data-action`, or `x-action` attributes.
|
27692
28130
|
*
|
27693
28131
|
* @element form
|
28132
|
+
* @priority 0
|
27694
28133
|
* @param {expression} ngSubmit {@link guide/expression Expression} to eval. (Event object is available as `$event`)
|
27695
28134
|
*
|
27696
28135
|
* @example
|
@@ -27715,20 +28154,20 @@ forEach(
|
|
27715
28154
|
<pre>list={{list}}</pre>
|
27716
28155
|
</form>
|
27717
28156
|
</doc:source>
|
27718
|
-
<doc:
|
28157
|
+
<doc:protractor>
|
27719
28158
|
it('should check ng-submit', function() {
|
27720
|
-
expect(binding('list')).toBe('[]');
|
27721
|
-
element('.doc-example-live #submit').click();
|
27722
|
-
expect(binding('list')).
|
27723
|
-
expect(input('text').
|
28159
|
+
expect(element(by.binding('list')).getText()).toBe('list=[]');
|
28160
|
+
element(by.css('.doc-example-live #submit')).click();
|
28161
|
+
expect(element(by.binding('list')).getText()).toContain('hello');
|
28162
|
+
expect(element(by.input('text')).getAttribute('value')).toBe('');
|
27724
28163
|
});
|
27725
28164
|
it('should ignore empty strings', function() {
|
27726
|
-
expect(binding('list')).toBe('[]');
|
27727
|
-
element('.doc-example-live #submit').click();
|
27728
|
-
element('.doc-example-live #submit').click();
|
27729
|
-
expect(binding('list')).
|
27730
|
-
|
27731
|
-
</doc:
|
28165
|
+
expect(element(by.binding('list')).getText()).toBe('list=[]');
|
28166
|
+
element(by.css('.doc-example-live #submit')).click();
|
28167
|
+
element(by.css('.doc-example-live #submit')).click();
|
28168
|
+
expect(element(by.binding('list')).getText()).toContain('hello');
|
28169
|
+
});
|
28170
|
+
</doc:protractor>
|
27732
28171
|
</doc:example>
|
27733
28172
|
*/
|
27734
28173
|
|
@@ -27740,6 +28179,7 @@ forEach(
|
|
27740
28179
|
* Specify custom behavior on focus event.
|
27741
28180
|
*
|
27742
28181
|
* @element window, input, select, textarea, a
|
28182
|
+
* @priority 0
|
27743
28183
|
* @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
|
27744
28184
|
* focus. (Event object is available as `$event`)
|
27745
28185
|
*
|
@@ -27755,6 +28195,7 @@ forEach(
|
|
27755
28195
|
* Specify custom behavior on blur event.
|
27756
28196
|
*
|
27757
28197
|
* @element window, input, select, textarea, a
|
28198
|
+
* @priority 0
|
27758
28199
|
* @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
|
27759
28200
|
* blur. (Event object is available as `$event`)
|
27760
28201
|
*
|
@@ -27770,11 +28211,17 @@ forEach(
|
|
27770
28211
|
* Specify custom behavior on copy event.
|
27771
28212
|
*
|
27772
28213
|
* @element window, input, select, textarea, a
|
28214
|
+
* @priority 0
|
27773
28215
|
* @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
|
27774
28216
|
* copy. (Event object is available as `$event`)
|
27775
28217
|
*
|
27776
28218
|
* @example
|
27777
|
-
|
28219
|
+
<doc:example>
|
28220
|
+
<doc:source>
|
28221
|
+
<input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
|
28222
|
+
copied: {{copied}}
|
28223
|
+
</doc:source>
|
28224
|
+
</doc:example>
|
27778
28225
|
*/
|
27779
28226
|
|
27780
28227
|
/**
|
@@ -27785,11 +28232,17 @@ forEach(
|
|
27785
28232
|
* Specify custom behavior on cut event.
|
27786
28233
|
*
|
27787
28234
|
* @element window, input, select, textarea, a
|
28235
|
+
* @priority 0
|
27788
28236
|
* @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
|
27789
28237
|
* cut. (Event object is available as `$event`)
|
27790
28238
|
*
|
27791
28239
|
* @example
|
27792
|
-
|
28240
|
+
<doc:example>
|
28241
|
+
<doc:source>
|
28242
|
+
<input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
|
28243
|
+
cut: {{cut}}
|
28244
|
+
</doc:source>
|
28245
|
+
</doc:example>
|
27793
28246
|
*/
|
27794
28247
|
|
27795
28248
|
/**
|
@@ -27800,11 +28253,17 @@ forEach(
|
|
27800
28253
|
* Specify custom behavior on paste event.
|
27801
28254
|
*
|
27802
28255
|
* @element window, input, select, textarea, a
|
28256
|
+
* @priority 0
|
27803
28257
|
* @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
|
27804
28258
|
* paste. (Event object is available as `$event`)
|
27805
28259
|
*
|
27806
28260
|
* @example
|
27807
|
-
|
28261
|
+
<doc:example>
|
28262
|
+
<doc:source>
|
28263
|
+
<input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
|
28264
|
+
pasted: {{paste}}
|
28265
|
+
</doc:source>
|
28266
|
+
</doc:example>
|
27808
28267
|
*/
|
27809
28268
|
|
27810
28269
|
/**
|
@@ -27866,9 +28325,6 @@ forEach(
|
|
27866
28325
|
padding:10px;
|
27867
28326
|
}
|
27868
28327
|
|
27869
|
-
/*
|
27870
|
-
The transition styles can also be placed on the CSS base class above
|
27871
|
-
*/
|
27872
28328
|
.animate-if.ng-enter, .animate-if.ng-leave {
|
27873
28329
|
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
27874
28330
|
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
@@ -28038,19 +28494,33 @@ var ngIfDirective = ['$animate', function($animate) {
|
|
28038
28494
|
top:50px;
|
28039
28495
|
}
|
28040
28496
|
</file>
|
28041
|
-
<file name="
|
28497
|
+
<file name="protractorTest.js">
|
28498
|
+
var templateSelect = element(by.model('template'));
|
28499
|
+
var includeElem = element(by.css('.doc-example-live [ng-include]'));
|
28500
|
+
|
28042
28501
|
it('should load template1.html', function() {
|
28043
|
-
|
28044
|
-
toMatch(/Content of template1.html/);
|
28502
|
+
expect(includeElem.getText()).toMatch(/Content of template1.html/);
|
28045
28503
|
});
|
28504
|
+
|
28046
28505
|
it('should load template2.html', function() {
|
28047
|
-
|
28048
|
-
|
28049
|
-
|
28506
|
+
if (browser.params.browser == 'firefox') {
|
28507
|
+
// Firefox can't handle using selects
|
28508
|
+
// See https://github.com/angular/protractor/issues/480
|
28509
|
+
return;
|
28510
|
+
}
|
28511
|
+
templateSelect.click();
|
28512
|
+
templateSelect.element.all(by.css('option')).get(2).click();
|
28513
|
+
expect(includeElem.getText()).toMatch(/Content of template2.html/);
|
28050
28514
|
});
|
28515
|
+
|
28051
28516
|
it('should change to blank', function() {
|
28052
|
-
|
28053
|
-
|
28517
|
+
if (browser.params.browser == 'firefox') {
|
28518
|
+
// Firefox can't handle using selects
|
28519
|
+
return;
|
28520
|
+
}
|
28521
|
+
templateSelect.click();
|
28522
|
+
templateSelect.element.all(by.css('option')).get(0).click();
|
28523
|
+
expect(includeElem.isPresent()).toBe(false);
|
28054
28524
|
});
|
28055
28525
|
</file>
|
28056
28526
|
</example>
|
@@ -28176,11 +28646,18 @@ var ngIncludeFillContentDirective = ['$compile',
|
|
28176
28646
|
* current scope.
|
28177
28647
|
*
|
28178
28648
|
* <div class="alert alert-error">
|
28179
|
-
* The only appropriate use of `ngInit` for aliasing special properties of
|
28649
|
+
* The only appropriate use of `ngInit` is for aliasing special properties of
|
28180
28650
|
* {@link api/ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
|
28181
28651
|
* should use {@link guide/controller controllers} rather than `ngInit`
|
28182
28652
|
* to initialize values on a scope.
|
28183
28653
|
* </div>
|
28654
|
+
* <div class="alert alert-warning">
|
28655
|
+
* **Note**: If you have assignment in `ngInit` along with {@link api/ng.$filter `$filter`}, make
|
28656
|
+
* sure you have parenthesis for correct precedence:
|
28657
|
+
* <pre class="prettyprint">
|
28658
|
+
* <div ng-init="test1 = (data | orderBy:'name')"></div>
|
28659
|
+
* </pre>
|
28660
|
+
* </div>
|
28184
28661
|
*
|
28185
28662
|
* @priority 450
|
28186
28663
|
*
|
@@ -28203,15 +28680,15 @@ var ngIncludeFillContentDirective = ['$compile',
|
|
28203
28680
|
</div>
|
28204
28681
|
</div>
|
28205
28682
|
</doc:source>
|
28206
|
-
<doc:
|
28683
|
+
<doc:protractor>
|
28207
28684
|
it('should alias index positions', function() {
|
28208
|
-
|
28209
|
-
|
28210
|
-
|
28211
|
-
|
28212
|
-
|
28685
|
+
var elements = element.all(by.css('.example-init'));
|
28686
|
+
expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
|
28687
|
+
expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
|
28688
|
+
expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
|
28689
|
+
expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
|
28213
28690
|
});
|
28214
|
-
</doc:
|
28691
|
+
</doc:protractor>
|
28215
28692
|
</doc:example>
|
28216
28693
|
*/
|
28217
28694
|
var ngInitDirective = ngDirective({
|
@@ -28249,13 +28726,12 @@ var ngInitDirective = ngDirective({
|
|
28249
28726
|
<div>Normal: {{1 + 2}}</div>
|
28250
28727
|
<div ng-non-bindable>Ignored: {{1 + 2}}</div>
|
28251
28728
|
</doc:source>
|
28252
|
-
<doc:
|
28729
|
+
<doc:protractor>
|
28253
28730
|
it('should check ng-non-bindable', function() {
|
28254
|
-
expect(
|
28255
|
-
expect(
|
28256
|
-
toMatch(/1 \+ 2/);
|
28731
|
+
expect(element(by.binding('1 + 2')).getText()).toContain('3');
|
28732
|
+
expect(element.all(by.css('.doc-example-live div')).last().getText()).toMatch(/1 \+ 2/);
|
28257
28733
|
});
|
28258
|
-
</doc:
|
28734
|
+
</doc:protractor>
|
28259
28735
|
</doc:example>
|
28260
28736
|
*/
|
28261
28737
|
var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
|
@@ -28383,49 +28859,53 @@ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
|
|
28383
28859
|
</ng-pluralize>
|
28384
28860
|
</div>
|
28385
28861
|
</doc:source>
|
28386
|
-
<doc:
|
28862
|
+
<doc:protractor>
|
28387
28863
|
it('should show correct pluralized string', function() {
|
28388
|
-
|
28389
|
-
|
28390
|
-
|
28391
|
-
|
28392
|
-
|
28393
|
-
|
28394
|
-
|
28395
|
-
|
28396
|
-
|
28397
|
-
|
28398
|
-
|
28399
|
-
|
28400
|
-
|
28401
|
-
|
28402
|
-
|
28403
|
-
toBe('Igor and Misko are viewing.');
|
28404
|
-
|
28405
|
-
using('.doc-example-live').input('personCount').enter('3');
|
28406
|
-
expect(element('.doc-example-live ng-pluralize:first').text()).
|
28407
|
-
toBe('3 people are viewing.');
|
28408
|
-
expect(element('.doc-example-live ng-pluralize:last').text()).
|
28409
|
-
toBe('Igor, Misko and one other person are viewing.');
|
28410
|
-
|
28411
|
-
using('.doc-example-live').input('personCount').enter('4');
|
28412
|
-
expect(element('.doc-example-live ng-pluralize:first').text()).
|
28413
|
-
toBe('4 people are viewing.');
|
28414
|
-
expect(element('.doc-example-live ng-pluralize:last').text()).
|
28415
|
-
toBe('Igor, Misko and 2 other people are viewing.');
|
28416
|
-
});
|
28864
|
+
var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
|
28865
|
+
var withOffset = element.all(by.css('ng-pluralize')).get(1);
|
28866
|
+
var countInput = element(by.model('personCount'));
|
28867
|
+
|
28868
|
+
expect(withoutOffset.getText()).toEqual('1 person is viewing.');
|
28869
|
+
expect(withOffset.getText()).toEqual('Igor is viewing.');
|
28870
|
+
|
28871
|
+
countInput.clear();
|
28872
|
+
countInput.sendKeys('0');
|
28873
|
+
|
28874
|
+
expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
|
28875
|
+
expect(withOffset.getText()).toEqual('Nobody is viewing.');
|
28876
|
+
|
28877
|
+
countInput.clear();
|
28878
|
+
countInput.sendKeys('2');
|
28417
28879
|
|
28418
|
-
|
28419
|
-
|
28420
|
-
expect(element('.doc-example-live ng-pluralize:last').text()).
|
28421
|
-
toBe('Igor, Misko and 2 other people are viewing.');
|
28880
|
+
expect(withoutOffset.getText()).toEqual('2 people are viewing.');
|
28881
|
+
expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
|
28422
28882
|
|
28423
|
-
|
28424
|
-
|
28425
|
-
|
28426
|
-
|
28883
|
+
countInput.clear();
|
28884
|
+
countInput.sendKeys('3');
|
28885
|
+
|
28886
|
+
expect(withoutOffset.getText()).toEqual('3 people are viewing.');
|
28887
|
+
expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
|
28888
|
+
|
28889
|
+
countInput.clear();
|
28890
|
+
countInput.sendKeys('4');
|
28891
|
+
|
28892
|
+
expect(withoutOffset.getText()).toEqual('4 people are viewing.');
|
28893
|
+
expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
|
28427
28894
|
});
|
28428
|
-
|
28895
|
+
it('should show data-bound names', function() {
|
28896
|
+
var withOffset = element.all(by.css('ng-pluralize')).get(1);
|
28897
|
+
var personCount = element(by.model('personCount'));
|
28898
|
+
var person1 = element(by.model('person1'));
|
28899
|
+
var person2 = element(by.model('person2'));
|
28900
|
+
personCount.clear();
|
28901
|
+
personCount.sendKeys('4');
|
28902
|
+
person1.clear();
|
28903
|
+
person1.sendKeys('Di');
|
28904
|
+
person2.clear();
|
28905
|
+
person2.sendKeys('Vojta');
|
28906
|
+
expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
|
28907
|
+
});
|
28908
|
+
</doc:protractor>
|
28429
28909
|
</doc:example>
|
28430
28910
|
*/
|
28431
28911
|
var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
|
@@ -28492,6 +28972,8 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
|
|
28492
28972
|
* | `$even` | {@type boolean} | true if the iterator position `$index` is even (otherwise false). |
|
28493
28973
|
* | `$odd` | {@type boolean} | true if the iterator position `$index` is odd (otherwise false). |
|
28494
28974
|
*
|
28975
|
+
* Creating aliases for these properties is possible with {@link api/ng.directive:ngInit `ngInit`}.
|
28976
|
+
* This may be useful when, for instance, nesting ngRepeats.
|
28495
28977
|
*
|
28496
28978
|
* # Special repeat start and end points
|
28497
28979
|
* To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
|
@@ -28642,25 +29124,27 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
|
|
28642
29124
|
max-height:40px;
|
28643
29125
|
}
|
28644
29126
|
</file>
|
28645
|
-
<file name="
|
28646
|
-
|
28647
|
-
|
28648
|
-
|
28649
|
-
|
28650
|
-
|
28651
|
-
|
28652
|
-
|
28653
|
-
|
29127
|
+
<file name="protractorTest.js">
|
29128
|
+
var friends = element(by.css('.doc-example-live'))
|
29129
|
+
.element.all(by.repeater('friend in friends'));
|
29130
|
+
|
29131
|
+
it('should render initial data set', function() {
|
29132
|
+
expect(friends.count()).toBe(10);
|
29133
|
+
expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
|
29134
|
+
expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
|
29135
|
+
expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
|
29136
|
+
expect(element(by.binding('friends.length')).getText())
|
29137
|
+
.toMatch("I have 10 friends. They are:");
|
29138
|
+
});
|
28654
29139
|
|
28655
29140
|
it('should update repeater when filter predicate changes', function() {
|
28656
|
-
|
28657
|
-
expect(r.count()).toBe(10);
|
29141
|
+
expect(friends.count()).toBe(10);
|
28658
29142
|
|
28659
|
-
|
29143
|
+
element(by.css('.doc-example-live')).element(by.model('q')).sendKeys('ma');
|
28660
29144
|
|
28661
|
-
expect(
|
28662
|
-
expect(
|
28663
|
-
expect(
|
29145
|
+
expect(friends.count()).toBe(2);
|
29146
|
+
expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
|
29147
|
+
expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
|
28664
29148
|
});
|
28665
29149
|
</file>
|
28666
29150
|
</example>
|
@@ -28675,7 +29159,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
|
28675
29159
|
$$tlb: true,
|
28676
29160
|
link: function($scope, $element, $attr, ctrl, $transclude){
|
28677
29161
|
var expression = $attr.ngRepeat;
|
28678
|
-
var match = expression.match(/^\s*(
|
29162
|
+
var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),
|
28679
29163
|
trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
|
28680
29164
|
lhs, rhs, valueIdentifier, keyIdentifier,
|
28681
29165
|
hashFnLocals = {$id: hashKey};
|
@@ -28687,7 +29171,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
|
28687
29171
|
|
28688
29172
|
lhs = match[1];
|
28689
29173
|
rhs = match[2];
|
28690
|
-
trackByExp = match[
|
29174
|
+
trackByExp = match[3];
|
28691
29175
|
|
28692
29176
|
if (trackByExp) {
|
28693
29177
|
trackByExpGetter = $parse(trackByExp);
|
@@ -28914,6 +29398,11 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
|
28914
29398
|
*
|
28915
29399
|
* Just remember to include the important flag so the CSS override will function.
|
28916
29400
|
*
|
29401
|
+
* <div class="alert alert-warning">
|
29402
|
+
* **Note:** Here is a list of values that ngShow will consider as a falsy value (case insensitive):<br />
|
29403
|
+
* "f" / "0" / "false" / "no" / "n" / "[]"
|
29404
|
+
* </div>
|
29405
|
+
*
|
28917
29406
|
* ## A note about animations with ngShow
|
28918
29407
|
*
|
28919
29408
|
* Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
|
@@ -28989,16 +29478,19 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
|
28989
29478
|
background:white;
|
28990
29479
|
}
|
28991
29480
|
</file>
|
28992
|
-
<file name="
|
28993
|
-
|
28994
|
-
|
28995
|
-
expect(element('.doc-example-live span:last:visible').count()).toEqual(1);
|
29481
|
+
<file name="protractorTest.js">
|
29482
|
+
var thumbsUp = element(by.css('.doc-example-live span.icon-thumbs-up'));
|
29483
|
+
var thumbsDown = element(by.css('.doc-example-live span.icon-thumbs-down'));
|
28996
29484
|
|
28997
|
-
|
29485
|
+
it('should check ng-show / ng-hide', function() {
|
29486
|
+
expect(thumbsUp.isDisplayed()).toBeFalsy();
|
29487
|
+
expect(thumbsDown.isDisplayed()).toBeTruthy();
|
28998
29488
|
|
28999
|
-
|
29000
|
-
|
29001
|
-
|
29489
|
+
element(by.model('checked')).click();
|
29490
|
+
|
29491
|
+
expect(thumbsUp.isDisplayed()).toBeTruthy();
|
29492
|
+
expect(thumbsDown.isDisplayed()).toBeFalsy();
|
29493
|
+
});
|
29002
29494
|
</file>
|
29003
29495
|
</example>
|
29004
29496
|
*/
|
@@ -29062,6 +29554,11 @@ var ngShowDirective = ['$animate', function($animate) {
|
|
29062
29554
|
* </pre>
|
29063
29555
|
*
|
29064
29556
|
* Just remember to include the important flag so the CSS override will function.
|
29557
|
+
*
|
29558
|
+
* <div class="alert alert-warning">
|
29559
|
+
* **Note:** Here is a list of values that ngHide will consider as a falsy value (case insensitive):<br />
|
29560
|
+
* "f" / "0" / "false" / "no" / "n" / "[]"
|
29561
|
+
* </div>
|
29065
29562
|
*
|
29066
29563
|
* ## A note about animations with ngHide
|
29067
29564
|
*
|
@@ -29138,16 +29635,19 @@ var ngShowDirective = ['$animate', function($animate) {
|
|
29138
29635
|
background:white;
|
29139
29636
|
}
|
29140
29637
|
</file>
|
29141
|
-
<file name="
|
29142
|
-
|
29143
|
-
|
29144
|
-
expect(element('.doc-example-live .check-element:last:visible').count()).toEqual(1);
|
29638
|
+
<file name="protractorTest.js">
|
29639
|
+
var thumbsUp = element(by.css('.doc-example-live span.icon-thumbs-up'));
|
29640
|
+
var thumbsDown = element(by.css('.doc-example-live span.icon-thumbs-down'));
|
29145
29641
|
|
29146
|
-
|
29642
|
+
it('should check ng-show / ng-hide', function() {
|
29643
|
+
expect(thumbsUp.isDisplayed()).toBeFalsy();
|
29644
|
+
expect(thumbsDown.isDisplayed()).toBeTruthy();
|
29147
29645
|
|
29148
|
-
|
29149
|
-
|
29150
|
-
|
29646
|
+
element(by.model('checked')).click();
|
29647
|
+
|
29648
|
+
expect(thumbsUp.isDisplayed()).toBeTruthy();
|
29649
|
+
expect(thumbsDown.isDisplayed()).toBeFalsy();
|
29650
|
+
});
|
29151
29651
|
</file>
|
29152
29652
|
</example>
|
29153
29653
|
*/
|
@@ -29186,13 +29686,15 @@ var ngHideDirective = ['$animate', function($animate) {
|
|
29186
29686
|
color: black;
|
29187
29687
|
}
|
29188
29688
|
</file>
|
29189
|
-
<file name="
|
29689
|
+
<file name="protractorTest.js">
|
29690
|
+
var colorSpan = element(by.css('.doc-example-live span'));
|
29691
|
+
|
29190
29692
|
it('should check ng-style', function() {
|
29191
|
-
expect(
|
29192
|
-
element('.doc-example-live
|
29193
|
-
expect(
|
29194
|
-
element('.doc-example-live
|
29195
|
-
expect(
|
29693
|
+
expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
|
29694
|
+
element(by.css('.doc-example-live input[value=set]')).click();
|
29695
|
+
expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
|
29696
|
+
element(by.css('.doc-example-live input[value=clear]')).click();
|
29697
|
+
expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
|
29196
29698
|
});
|
29197
29699
|
</file>
|
29198
29700
|
</example>
|
@@ -29217,7 +29719,7 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
|
|
29217
29719
|
* as specified in the template.
|
29218
29720
|
*
|
29219
29721
|
* The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
|
29220
|
-
* from the template cache), `ngSwitch` simply
|
29722
|
+
* from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
|
29221
29723
|
* matches the value obtained from the evaluated expression. In other words, you define a container element
|
29222
29724
|
* (where you place the directive), place an expression on the **`on="..."` attribute**
|
29223
29725
|
* (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
|
@@ -29313,17 +29815,20 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
|
|
29313
29815
|
top:0;
|
29314
29816
|
}
|
29315
29817
|
</file>
|
29316
|
-
<file name="
|
29818
|
+
<file name="protractorTest.js">
|
29819
|
+
var switchElem = element(by.css('.doc-example-live [ng-switch]'));
|
29820
|
+
var select = element(by.model('selection'));
|
29821
|
+
|
29317
29822
|
it('should start in settings', function() {
|
29318
|
-
expect(
|
29823
|
+
expect(switchElem.getText()).toMatch(/Settings Div/);
|
29319
29824
|
});
|
29320
29825
|
it('should change to home', function() {
|
29321
|
-
select('
|
29322
|
-
expect(
|
29826
|
+
select.element.all(by.css('option')).get(1).click();
|
29827
|
+
expect(switchElem.getText()).toMatch(/Home Span/);
|
29323
29828
|
});
|
29324
29829
|
it('should select default', function() {
|
29325
|
-
select('
|
29326
|
-
expect(
|
29830
|
+
select.element.all(by.css('option')).get(2).click();
|
29831
|
+
expect(switchElem.getText()).toMatch(/default/);
|
29327
29832
|
});
|
29328
29833
|
</file>
|
29329
29834
|
</example>
|
@@ -29374,11 +29879,9 @@ var ngSwitchWhenDirective = ngDirective({
|
|
29374
29879
|
transclude: 'element',
|
29375
29880
|
priority: 800,
|
29376
29881
|
require: '^ngSwitch',
|
29377
|
-
|
29378
|
-
|
29379
|
-
|
29380
|
-
ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
|
29381
|
-
};
|
29882
|
+
link: function(scope, element, attrs, ctrl, $transclude) {
|
29883
|
+
ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
|
29884
|
+
ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
|
29382
29885
|
}
|
29383
29886
|
});
|
29384
29887
|
|
@@ -29432,35 +29935,32 @@ var ngSwitchDefaultDirective = ngDirective({
|
|
29432
29935
|
<pane title="{{title}}">{{text}}</pane>
|
29433
29936
|
</div>
|
29434
29937
|
</doc:source>
|
29435
|
-
<doc:
|
29938
|
+
<doc:protractor>
|
29436
29939
|
it('should have transcluded', function() {
|
29437
|
-
|
29438
|
-
|
29439
|
-
|
29440
|
-
|
29940
|
+
var titleElement = element(by.model('title'));
|
29941
|
+
titleElement.clear();
|
29942
|
+
titleElement.sendKeys('TITLE');
|
29943
|
+
var textElement = element(by.model('text'));
|
29944
|
+
textElement.clear();
|
29945
|
+
textElement.sendKeys('TEXT');
|
29946
|
+
expect(element(by.binding('title')).getText()).toEqual('TITLE');
|
29947
|
+
expect(element(by.binding('text')).getText()).toEqual('TEXT');
|
29441
29948
|
});
|
29442
|
-
</doc:
|
29949
|
+
</doc:protractor>
|
29443
29950
|
</doc:example>
|
29444
29951
|
*
|
29445
29952
|
*/
|
29446
29953
|
var ngTranscludeDirective = ngDirective({
|
29447
|
-
|
29954
|
+
link: function($scope, $element, $attrs, controller, $transclude) {
|
29448
29955
|
if (!$transclude) {
|
29449
29956
|
throw minErr('ngTransclude')('orphan',
|
29450
|
-
|
29451
|
-
|
29452
|
-
|
29453
|
-
|
29957
|
+
'Illegal use of ngTransclude directive in the template! ' +
|
29958
|
+
'No parent directive that requires a transclusion found. ' +
|
29959
|
+
'Element: {0}',
|
29960
|
+
startingTag($element));
|
29454
29961
|
}
|
29455
|
-
|
29456
|
-
|
29457
|
-
// the parent element even when the transclusion replaces the current element. (we can't use priority here because
|
29458
|
-
// that applies only to compile fns and not controllers
|
29459
|
-
this.$transclude = $transclude;
|
29460
|
-
}],
|
29461
|
-
|
29462
|
-
link: function($scope, $element, $attrs, controller) {
|
29463
|
-
controller.$transclude(function(clone) {
|
29962
|
+
|
29963
|
+
$transclude(function(clone) {
|
29464
29964
|
$element.empty();
|
29465
29965
|
$element.append(clone);
|
29466
29966
|
});
|
@@ -29473,10 +29973,14 @@ var ngTranscludeDirective = ngDirective({
|
|
29473
29973
|
* @restrict E
|
29474
29974
|
*
|
29475
29975
|
* @description
|
29476
|
-
* Load content of a script
|
29477
|
-
* template can be used by
|
29976
|
+
* Load the content of a `<script>` element into {@link api/ng.$templateCache `$templateCache`}, so that the
|
29977
|
+
* template can be used by {@link api/ng.directive:ngInclude `ngInclude`},
|
29978
|
+
* {@link api/ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
|
29979
|
+
* `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
|
29980
|
+
* assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
|
29478
29981
|
*
|
29479
|
-
* @param {'text/ng-template'} type
|
29982
|
+
* @param {'text/ng-template'} type Must be set to `'text/ng-template'`.
|
29983
|
+
* @param {string} id Cache name of the template.
|
29480
29984
|
*
|
29481
29985
|
* @example
|
29482
29986
|
<doc:example>
|
@@ -29488,12 +29992,12 @@ var ngTranscludeDirective = ngDirective({
|
|
29488
29992
|
<a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
|
29489
29993
|
<div id="tpl-content" ng-include src="currentTpl"></div>
|
29490
29994
|
</doc:source>
|
29491
|
-
<doc:
|
29995
|
+
<doc:protractor>
|
29492
29996
|
it('should load template defined inside script tag', function() {
|
29493
|
-
element('#tpl-link').click();
|
29494
|
-
expect(element('#tpl-content').
|
29997
|
+
element(by.css('#tpl-link')).click();
|
29998
|
+
expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
|
29495
29999
|
});
|
29496
|
-
</doc:
|
30000
|
+
</doc:protractor>
|
29497
30001
|
</doc:example>
|
29498
30002
|
*/
|
29499
30003
|
var scriptDirective = ['$templateCache', function($templateCache) {
|
@@ -29531,14 +30035,21 @@ var ngOptionsMinErr = minErr('ngOptions');
|
|
29531
30035
|
* represented by the selected option will be bound to the model identified by the `ngModel`
|
29532
30036
|
* directive.
|
29533
30037
|
*
|
30038
|
+
* <div class="alert alert-warning">
|
30039
|
+
* **Note:** `ngModel` compares by reference, not value. This is important when binding to an
|
30040
|
+
* array of objects. See an example {@link http://jsfiddle.net/qWzTb/ in this jsfiddle}.
|
30041
|
+
* </div>
|
30042
|
+
*
|
29534
30043
|
* Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
|
29535
30044
|
* be nested into the `<select>` element. This element will then represent the `null` or "not selected"
|
29536
30045
|
* option. See example below for demonstration.
|
29537
30046
|
*
|
29538
|
-
*
|
30047
|
+
* <div class="alert alert-warning">
|
30048
|
+
* **Note:** `ngOptions` provides an iterator facility for the `<option>` element which should be used instead
|
29539
30049
|
* of {@link ng.directive:ngRepeat ngRepeat} when you want the
|
29540
30050
|
* `select` model to be bound to a non-string value. This is because an option element can only
|
29541
30051
|
* be bound to string values at present.
|
30052
|
+
* </div>
|
29542
30053
|
*
|
29543
30054
|
* @param {string} ngModel Assignable angular expression to data-bind to.
|
29544
30055
|
* @param {string=} name Property name of the form under which the control is published.
|
@@ -29625,23 +30136,25 @@ var ngOptionsMinErr = minErr('ngOptions');
|
|
29625
30136
|
</div>
|
29626
30137
|
</div>
|
29627
30138
|
</doc:source>
|
29628
|
-
<doc:
|
30139
|
+
<doc:protractor>
|
29629
30140
|
it('should check ng-options', function() {
|
29630
|
-
expect(binding('{selected_color:color}')).toMatch('red');
|
29631
|
-
select('color').
|
29632
|
-
|
29633
|
-
|
29634
|
-
|
30141
|
+
expect(element(by.binding('{selected_color:color}')).getText()).toMatch('red');
|
30142
|
+
element.all(by.select('color')).first().click();
|
30143
|
+
element.all(by.css('select[ng-model="color"] option')).first().click();
|
30144
|
+
expect(element(by.binding('{selected_color:color}')).getText()).toMatch('black');
|
30145
|
+
element(by.css('.nullable select[ng-model="color"]')).click();
|
30146
|
+
element.all(by.css('.nullable select[ng-model="color"] option')).first().click();
|
30147
|
+
expect(element(by.binding('{selected_color:color}')).getText()).toMatch('null');
|
29635
30148
|
});
|
29636
|
-
</doc:
|
30149
|
+
</doc:protractor>
|
29637
30150
|
</doc:example>
|
29638
30151
|
*/
|
29639
30152
|
|
29640
30153
|
var ngOptionsDirective = valueFn({ terminal: true });
|
29641
30154
|
// jshint maxlen: false
|
29642
30155
|
var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
29643
|
-
//
|
29644
|
-
var NG_OPTIONS_REGEXP = /^\s*(
|
30156
|
+
//000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
|
30157
|
+
var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/,
|
29645
30158
|
nullModelCtrl = {$setViewValue: noop};
|
29646
30159
|
// jshint maxlen: 100
|
29647
30160
|
|
@@ -29733,18 +30246,10 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
29733
30246
|
selectCtrl.init(ngModelCtrl, nullOption, unknownOption);
|
29734
30247
|
|
29735
30248
|
// required validator
|
29736
|
-
if (multiple
|
29737
|
-
|
29738
|
-
|
29739
|
-
return value;
|
30249
|
+
if (multiple) {
|
30250
|
+
ngModelCtrl.$isEmpty = function(value) {
|
30251
|
+
return !value || value.length === 0;
|
29740
30252
|
};
|
29741
|
-
|
29742
|
-
ngModelCtrl.$parsers.push(requiredValidator);
|
29743
|
-
ngModelCtrl.$formatters.unshift(requiredValidator);
|
29744
|
-
|
29745
|
-
attr.$observe('required', function() {
|
29746
|
-
requiredValidator(ngModelCtrl.$viewValue);
|
29747
|
-
});
|
29748
30253
|
}
|
29749
30254
|
|
29750
30255
|
if (optionsExp) setupAsOptions(scope, element, ngModelCtrl);
|
@@ -29950,7 +30455,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
29950
30455
|
|
29951
30456
|
// We now build up the list of options we need (we merge later)
|
29952
30457
|
for (index = 0; length = keys.length, index < length; index++) {
|
29953
|
-
|
30458
|
+
|
29954
30459
|
key = index;
|
29955
30460
|
if (keyName) {
|
29956
30461
|
key = keys[index];
|
@@ -30384,7 +30889,8 @@ function callerFile(offset) {
|
|
30384
30889
|
* To work around this we instead use our own handler that fires a real event.
|
30385
30890
|
*/
|
30386
30891
|
(function(fn){
|
30387
|
-
|
30892
|
+
// We need a handle to the original trigger function for input tests.
|
30893
|
+
var parentTrigger = fn._originalTrigger = fn.trigger;
|
30388
30894
|
fn.trigger = function(type) {
|
30389
30895
|
if (/(click|change|keydown|blur|input|mousedown|mouseup)/.test(type)) {
|
30390
30896
|
var processDefaults = [];
|
@@ -32370,5 +32876,5 @@ if (config.autotest) {
|
|
32370
32876
|
})(window, document);
|
32371
32877
|
|
32372
32878
|
|
32373
|
-
!angular.$$csp() && angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";\n\n[ng\\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],\n.ng-cloak, .x-ng-cloak,\n.ng-hide {\n display: none !important;\n}\n\nng\\:form {\n display: block;\n}\n\n
|
32879
|
+
!angular.$$csp() && angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";\n\n[ng\\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],\n.ng-cloak, .x-ng-cloak,\n.ng-hide {\n display: none !important;\n}\n\nng\\:form {\n display: block;\n}\n\n.ng-animate-block-transitions {\n transition:0s all!important;\n -webkit-transition:0s all!important;\n}\n</style>');
|
32374
32880
|
!angular.$$csp() && angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";\n/* CSS Document */\n\n/** Structure */\nbody {\n font-family: Arial, sans-serif;\n margin: 0;\n font-size: 14px;\n}\n\n#system-error {\n font-size: 1.5em;\n text-align: center;\n}\n\n#json, #xml {\n display: none;\n}\n\n#header {\n position: fixed;\n width: 100%;\n}\n\n#specs {\n padding-top: 50px;\n}\n\n#header .angular {\n font-family: Courier New, monospace;\n font-weight: bold;\n}\n\n#header h1 {\n font-weight: normal;\n float: left;\n font-size: 30px;\n line-height: 30px;\n margin: 0;\n padding: 10px 10px;\n height: 30px;\n}\n\n#application h2,\n#specs h2 {\n margin: 0;\n padding: 0.5em;\n font-size: 1.1em;\n}\n\n#status-legend {\n margin-top: 10px;\n margin-right: 10px;\n}\n\n#header,\n#application,\n.test-info,\n.test-actions li {\n overflow: hidden;\n}\n\n#application {\n margin: 10px;\n}\n\n#application iframe {\n width: 100%;\n height: 758px;\n}\n\n#application .popout {\n float: right;\n}\n\n#application iframe {\n border: none;\n}\n\n.tests li,\n.test-actions li,\n.test-it li,\n.test-it ol,\n.status-display {\n list-style-type: none;\n}\n\n.tests,\n.test-it ol,\n.status-display {\n margin: 0;\n padding: 0;\n}\n\n.test-info {\n margin-left: 1em;\n margin-top: 0.5em;\n border-radius: 8px 0 0 8px;\n -webkit-border-radius: 8px 0 0 8px;\n -moz-border-radius: 8px 0 0 8px;\n cursor: pointer;\n}\n\n.test-info:hover .test-name {\n text-decoration: underline;\n}\n\n.test-info .closed:before {\n content: \'\\25b8\\00A0\';\n}\n\n.test-info .open:before {\n content: \'\\25be\\00A0\';\n font-weight: bold;\n}\n\n.test-it ol {\n margin-left: 2.5em;\n}\n\n.status-display,\n.status-display li {\n float: right;\n}\n\n.status-display li {\n padding: 5px 10px;\n}\n\n.timer-result,\n.test-title {\n display: inline-block;\n margin: 0;\n padding: 4px;\n}\n\n.test-actions .test-title,\n.test-actions .test-result {\n display: table-cell;\n padding-left: 0.5em;\n padding-right: 0.5em;\n}\n\n.test-actions {\n display: table;\n}\n\n.test-actions li {\n display: table-row;\n}\n\n.timer-result {\n width: 4em;\n padding: 0 10px;\n text-align: right;\n font-family: monospace;\n}\n\n.test-it pre,\n.test-actions pre {\n clear: left;\n color: black;\n margin-left: 6em;\n}\n\n.test-describe {\n padding-bottom: 0.5em;\n}\n\n.test-describe .test-describe {\n margin: 5px 5px 10px 2em;\n}\n\n.test-actions .status-pending .test-title:before {\n content: \'\\00bb\\00A0\';\n}\n\n.scrollpane {\n max-height: 20em;\n overflow: auto;\n}\n\n/** Colors */\n\n#header {\n background-color: #F2C200;\n}\n\n#specs h2 {\n border-top: 2px solid #BABAD1;\n}\n\n#specs h2,\n#application h2 {\n background-color: #efefef;\n}\n\n#application {\n border: 1px solid #BABAD1;\n}\n\n.test-describe .test-describe {\n border-left: 1px solid #BABAD1;\n border-right: 1px solid #BABAD1;\n border-bottom: 1px solid #BABAD1;\n}\n\n.status-display {\n border: 1px solid #777;\n}\n\n.status-display .status-pending,\n.status-pending .test-info {\n background-color: #F9EEBC;\n}\n\n.status-display .status-success,\n.status-success .test-info {\n background-color: #B1D7A1;\n}\n\n.status-display .status-failure,\n.status-failure .test-info {\n background-color: #FF8286;\n}\n\n.status-display .status-error,\n.status-error .test-info {\n background-color: black;\n color: white;\n}\n\n.test-actions .status-success .test-title {\n color: #30B30A;\n}\n\n.test-actions .status-failure .test-title {\n color: #DF0000;\n}\n\n.test-actions .status-error .test-title {\n color: black;\n}\n\n.test-actions .timer-result {\n color: #888;\n}\n</style>');
|