angular-rails-engine 1.2.5.0 → 1.2.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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>');
|