angular-rails-engine 1.2.0.2 → 1.2.3.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.
@@ -1,14 +1,14 @@
1
1
  /*
2
- AngularJS v1.2.0
3
- (c) 2010-2012 Google, Inc. http://angularjs.org
2
+ AngularJS v1.2.3
3
+ (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  License: MIT
5
5
  */
6
- (function(m,g,n){'use strict';function h(a){var d={};a=a.split(",");var c;for(c=0;c<a.length;c++)d[a[c]]=!0;return d}function D(a,d){function c(a,b,c,f){b=g.lowercase(b);if(r[b])for(;e.last()&&s[e.last()];)k("",e.last());t[b]&&e.last()==b&&k("",b);(f=u[b]||!!f)||e.push(b);var l={};c.replace(E,function(a,b,d,c,e){l[b]=p(d||c||e||"")});d.start&&d.start(b,l,f)}function k(a,b){var c=0,k;if(b=g.lowercase(b))for(c=e.length-1;0<=c&&e[c]!=b;c--);if(0<=c){for(k=e.length-1;k>=c;k--)d.end&&d.end(e[k]);e.length=
7
- c}}var b,f,e=[],l=a;for(e.last=function(){return e[e.length-1]};a;){f=!0;if(e.last()&&v[e.last()])a=a.replace(RegExp("(.*)<\\s*\\/\\s*"+e.last()+"[^>]*>","i"),function(a,b){b=b.replace(F,"$1").replace(G,"$1");d.chars&&d.chars(p(b));return""}),k("",e.last());else{if(0===a.indexOf("\x3c!--"))b=a.indexOf("--",4),0<=b&&a.lastIndexOf("--\x3e",b)===b&&(d.comment&&d.comment(a.substring(4,b)),a=a.substring(b+3),f=!1);else if(w.test(a)){if(b=a.match(w))a=a.replace(b[0],""),f=!1}else if(H.test(a)){if(b=a.match(x))a=
8
- a.substring(b[0].length),b[0].replace(x,k),f=!1}else I.test(a)&&(b=a.match(y))&&(a=a.substring(b[0].length),b[0].replace(y,c),f=!1);f&&(b=a.indexOf("<"),f=0>b?a:a.substring(0,b),a=0>b?"":a.substring(b),d.chars&&d.chars(p(f)))}if(a==l)throw J("badparse",a);l=a}k()}function p(a){q.innerHTML=a.replace(/</g,"&lt;");return q.innerText||q.textContent||""}function z(a){return a.replace(/&/g,"&amp;").replace(K,function(a){return"&#"+a.charCodeAt(0)+";"}).replace(/</g,"&lt;").replace(/>/g,"&gt;")}function A(a){var d=
9
- !1,c=g.bind(a,a.push);return{start:function(a,b,f){a=g.lowercase(a);!d&&v[a]&&(d=a);d||!0!==B[a]||(c("<"),c(a),g.forEach(b,function(a,b){var d=g.lowercase(b);!0!==L[d]||!0===C[d]&&!a.match(M)||(c(" "),c(b),c('="'),c(z(a)),c('"'))}),c(f?"/>":">"))},end:function(a){a=g.lowercase(a);d||!0!==B[a]||(c("</"),c(a),c(">"));a==d&&(d=!1)},chars:function(a){d||c(z(a))}}}var J=g.$$minErr("$sanitize"),y=/^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/,x=/^<\s*\/\s*([\w:-]+)[^>]*>/,
10
- E=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,I=/^</,H=/^<\s*\//,F=/\x3c!--(.*?)--\x3e/g,w=/<!DOCTYPE([^>]*?)>/i,G=/<!\[CDATA\[(.*?)]]\x3e/g,M=/^((ftp|https?):\/\/|mailto:|tel:|#)/i,K=/([^\#-~| |!])/g,u=h("area,br,col,hr,img,wbr");m=h("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr");n=h("rp,rt");var t=g.extend({},n,m),r=g.extend({},m,h("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
- s=g.extend({},n,h("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")),v=h("script,style"),B=g.extend({},u,r,s,t),C=h("background,cite,href,longdesc,src,usemap"),L=g.extend({},C,h("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")),
12
- q=document.createElement("pre");g.module("ngSanitize",[]).value("$sanitize",function(a){var d=[];D(a,A(d));return d.join("")});g.module("ngSanitize").filter("linky",function(){var a=/((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>]/,d=/^mailto:/;return function(c,k){if(!c)return c;var b,f=c,e=[],l=A(e),h,m,n={};g.isDefined(k)&&(n.target=k);for(;b=f.match(a);)h=b[0],b[2]==b[3]&&(h="mailto:"+h),m=b.index,l.chars(f.substr(0,m)),n.href=h,l.start("a",n),l.chars(b[0].replace(d,"")),l.end("a"),
13
- f=f.substring(m+b[0].length);l.chars(f);return e.join("")}})})(window,window.angular);
6
+ (function(n,h,q){'use strict';function F(a){var e=[];t(e,h.noop).chars(a);return e.join("")}function k(a){var e={};a=a.split(",");var d;for(d=0;d<a.length;d++)e[a[d]]=!0;return e}function G(a,e){function d(a,b,d,g){b=h.lowercase(b);if(u[b])for(;f.last()&&v[f.last()];)c("",f.last());w[b]&&f.last()==b&&c("",b);(g=x[b]||!!g)||f.push(b);var l={};d.replace(H,function(a,b,e,c,m){l[b]=r(e||c||m||"")});e.start&&e.start(b,l,g)}function c(a,b){var c=0,d;if(b=h.lowercase(b))for(c=f.length-1;0<=c&&f[c]!=b;c--);
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=a;for(f.last=function(){return f[f.length-1]};a;){g=!0;if(f.last()&&y[f.last()])a=a.replace(RegExp("(.*)<\\s*\\/\\s*"+f.last()+"[^>]*>","i"),function(a,b){b=b.replace(I,"$1").replace(J,"$1");e.chars&&e.chars(r(b));return""}),c("",f.last());else{if(0===a.indexOf("\x3c!--"))b=a.indexOf("--",4),0<=b&&a.lastIndexOf("--\x3e",b)===b&&(e.comment&&e.comment(a.substring(4,b)),a=a.substring(b+3),g=!1);else if(z.test(a)){if(b=a.match(z))a=
8
+ a.replace(b[0],""),g=!1}else if(K.test(a)){if(b=a.match(A))a=a.substring(b[0].length),b[0].replace(A,c),g=!1}else L.test(a)&&(b=a.match(B))&&(a=a.substring(b[0].length),b[0].replace(B,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 M("badparse",a);l=a}c()}function r(a){if(!a)return"";a=/^(\s*)([\s\S]*?)(\s*)$/.exec(a);a[0]="";a[2]&&(s.innerHTML=a[2].replace(/</g,"&lt;"),a[2]=s.innerText||s.textContent);return a.join("")}function C(a){return a.replace(/&/g,
9
+ "&amp;").replace(N,function(a){return"&#"+a.charCodeAt(0)+";"}).replace(/</g,"&lt;").replace(/>/g,"&gt;")}function t(a,e){var d=!1,c=h.bind(a,a.push);return{start:function(a,g,f){a=h.lowercase(a);!d&&y[a]&&(d=a);d||!0!==D[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===E[g]&&!e(d,k)||(c(" "),c(f),c('="'),c(C(d)),c('"'))}),c(f?"/>":">"))},end:function(a){a=h.lowercase(a);d||!0!==D[a]||(c("</"),c(a),c(">"));a==d&&(d=!1)},chars:function(a){d||
10
+ c(C(a))}}}var M=h.$$minErr("$sanitize"),B=/^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/,A=/^<\s*\/\s*([\w:-]+)[^>]*>/,H=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,L=/^</,K=/^<\s*\//,I=/\x3c!--(.*?)--\x3e/g,z=/<!DOCTYPE([^>]*?)>/i,J=/<!\[CDATA\[(.*?)]]\x3e/g,N=/([^\#-~| |!])/g,x=k("area,br,col,hr,img,wbr");n=k("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr");q=k("rp,rt");var w=h.extend({},q,n),u=h.extend({},n,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
+ v=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")),y=k("script,style"),D=h.extend({},x,u,v,w),E=k("background,cite,href,longdesc,src,usemap"),O=h.extend({},E,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")),
12
+ s=document.createElement("pre");h.module("ngSanitize",[]).provider("$sanitize",function(){this.$get=["$$sanitizeUri",function(a){return function(e){var d=[];G(e,t(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(F(a))}function f(a,c){m.push("<a ");h.isDefined(b)&&(m.push('target="'),
13
+ 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=[],p,n;l=k.match(e);)p=l[0],l[2]==l[3]&&(p="mailto:"+p),n=l.index,g(k.substr(0,n)),f(p,l[0].replace(d,"")),k=k.substring(n+l[0].length);g(k);return a(m.join(""))}}])})(window,window.angular);
14
14
  //# sourceMappingURL=angular-sanitize.min.js.map
@@ -9790,8 +9790,8 @@ if ( typeof module === "object" && module && typeof module.exports === "object"
9790
9790
  })( window );
9791
9791
 
9792
9792
  /**
9793
- * @license AngularJS v1.2.0
9794
- * (c) 2010-2012 Google, Inc. http://angularjs.org
9793
+ * @license AngularJS v1.2.3
9794
+ * (c) 2010-2014 Google, Inc. http://angularjs.org
9795
9795
  * License: MIT
9796
9796
  */
9797
9797
  (function(window, document){
@@ -9832,11 +9832,11 @@ function minErr(module) {
9832
9832
  template = arguments[1],
9833
9833
  templateArgs = arguments,
9834
9834
  stringify = function (obj) {
9835
- if (isFunction(obj)) {
9835
+ if (typeof obj === 'function') {
9836
9836
  return obj.toString().replace(/ \{[\s\S]*$/, '');
9837
- } else if (isUndefined(obj)) {
9837
+ } else if (typeof obj === 'undefined') {
9838
9838
  return 'undefined';
9839
- } else if (!isString(obj)) {
9839
+ } else if (typeof obj !== 'string') {
9840
9840
  return JSON.stringify(obj);
9841
9841
  }
9842
9842
  return obj;
@@ -9848,11 +9848,11 @@ function minErr(module) {
9848
9848
 
9849
9849
  if (index + 2 < templateArgs.length) {
9850
9850
  arg = templateArgs[index + 2];
9851
- if (isFunction(arg)) {
9851
+ if (typeof arg === 'function') {
9852
9852
  return arg.toString().replace(/ ?\{[\s\S]*$/, '');
9853
- } else if (isUndefined(arg)) {
9853
+ } else if (typeof arg === 'undefined') {
9854
9854
  return 'undefined';
9855
- } else if (!isString(arg)) {
9855
+ } else if (typeof arg !== 'string') {
9856
9856
  return toJson(arg);
9857
9857
  }
9858
9858
  return arg;
@@ -9860,7 +9860,7 @@ function minErr(module) {
9860
9860
  return match;
9861
9861
  });
9862
9862
 
9863
- message = message + '\nhttp://errors.angularjs.org/' + version.full + '/' +
9863
+ message = message + '\nhttp://errors.angularjs.org/1.2.3/' +
9864
9864
  (module ? module + '/' : '') + code;
9865
9865
  for (i = 2; i < arguments.length; i++) {
9866
9866
  message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
@@ -9951,7 +9951,7 @@ function minErr(module) {
9951
9951
  -assertArgFn,
9952
9952
  -assertNotHasOwnProperty,
9953
9953
  -getter,
9954
- -getBlockElements
9954
+ -getBlockElements,
9955
9955
 
9956
9956
  */
9957
9957
 
@@ -10415,7 +10415,7 @@ var trim = (function() {
10415
10415
  // TODO: we should move this into IE/ES5 polyfill
10416
10416
  if (!String.prototype.trim) {
10417
10417
  return function(value) {
10418
- return isString(value) ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value;
10418
+ return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
10419
10419
  };
10420
10420
  }
10421
10421
  return function(value) {
@@ -10973,26 +10973,38 @@ function encodeUriQuery(val, pctEncodeSpaces) {
10973
10973
  *
10974
10974
  * @description
10975
10975
  *
10976
- * Use this directive to auto-bootstrap an application. Only
10977
- * one ngApp directive can be used per HTML document. The directive
10978
- * designates the root of the application and is typically placed
10979
- * at the root of the page.
10976
+ * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
10977
+ * designates the **root element** of the application and is typically placed near the root element
10978
+ * of the page - e.g. on the `<body>` or `<html>` tags.
10980
10979
  *
10981
- * The first ngApp found in the document will be auto-bootstrapped. To use multiple applications in
10982
- * an HTML document you must manually bootstrap them using {@link angular.bootstrap}.
10983
- * Applications cannot be nested.
10980
+ * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
10981
+ * found in the document will be used to define the root element to auto-bootstrap as an
10982
+ * application. To run multiple applications in an HTML document you must manually bootstrap them using
10983
+ * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
10984
10984
  *
10985
- * In the example below if the `ngApp` directive were not placed
10986
- * on the `html` element then the document would not be compiled
10987
- * and the `{{ 1+2 }}` would not be resolved to `3`.
10985
+ * You can specify an **AngularJS module** to be used as the root module for the application. This
10986
+ * module will be loaded into the {@link AUTO.$injector} when the application is bootstrapped and
10987
+ * should contain the application code needed or have dependencies on other modules that will
10988
+ * contain the code. See {@link angular.module} for more information.
10988
10989
  *
10989
- * `ngApp` is the easiest way to bootstrap an application.
10990
+ * In the example below if the `ngApp` directive were not placed on the `html` element then the
10991
+ * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
10992
+ * would not be resolved to `3`.
10990
10993
  *
10991
- <doc:example>
10992
- <doc:source>
10993
- I can add: 1 + 2 = {{ 1+2 }}
10994
- </doc:source>
10995
- </doc:example>
10994
+ * `ngApp` is the easiest, and most common, way to bootstrap an application.
10995
+ *
10996
+ <example module="ngAppDemo">
10997
+ <file name="index.html">
10998
+ <div ng-controller="ngAppDemoController">
10999
+ I can add: {{a}} + {{b}} = {{ a+b }}
11000
+ </file>
11001
+ <file name="script.js">
11002
+ angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
11003
+ $scope.a = 1;
11004
+ $scope.b = 2;
11005
+ });
11006
+ </file>
11007
+ </example>
10996
11008
  *
10997
11009
  */
10998
11010
  function angularInit(element, bootstrap) {
@@ -11221,12 +11233,18 @@ function getBlockElements(block) {
11221
11233
  function setupModuleLoader(window) {
11222
11234
 
11223
11235
  var $injectorMinErr = minErr('$injector');
11236
+ var ngMinErr = minErr('ng');
11224
11237
 
11225
11238
  function ensure(obj, name, factory) {
11226
11239
  return obj[name] || (obj[name] = factory());
11227
11240
  }
11228
11241
 
11229
- return ensure(ensure(window, 'angular', Object), 'module', function() {
11242
+ var angular = ensure(window, 'angular', Object);
11243
+
11244
+ // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
11245
+ angular.$$minErr = angular.$$minErr || minErr;
11246
+
11247
+ return ensure(angular, 'module', function() {
11230
11248
  /** @type {Object.<string, angular.Module>} */
11231
11249
  var modules = {};
11232
11250
 
@@ -11281,6 +11299,12 @@ function setupModuleLoader(window) {
11281
11299
  * @returns {module} new module with the {@link angular.Module} api.
11282
11300
  */
11283
11301
  return function module(name, requires, configFn) {
11302
+ var assertNotHasOwnProperty = function(name, context) {
11303
+ if (name === 'hasOwnProperty') {
11304
+ throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
11305
+ }
11306
+ };
11307
+
11284
11308
  assertNotHasOwnProperty(name, 'module');
11285
11309
  if (requires && modules.hasOwnProperty(name)) {
11286
11310
  modules[name] = null;
@@ -11570,6 +11594,7 @@ function setupModuleLoader(window) {
11570
11594
  $ParseProvider,
11571
11595
  $RootScopeProvider,
11572
11596
  $QProvider,
11597
+ $$SanitizeUriProvider,
11573
11598
  $SceProvider,
11574
11599
  $SceDelegateProvider,
11575
11600
  $SnifferProvider,
@@ -11593,11 +11618,11 @@ function setupModuleLoader(window) {
11593
11618
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
11594
11619
  */
11595
11620
  var version = {
11596
- full: '1.2.0', // all of these placeholder strings will be replaced by grunt's
11621
+ full: '1.2.3', // all of these placeholder strings will be replaced by grunt's
11597
11622
  major: 1, // package task
11598
- minor: "NG_VERSION_MINOR",
11599
- dot: 0,
11600
- codeName: 'timely-delivery'
11623
+ minor: 2,
11624
+ dot: 3,
11625
+ codeName: 'unicorn-zapper'
11601
11626
  };
11602
11627
 
11603
11628
 
@@ -11641,6 +11666,10 @@ function publishExternalAPI(angular){
11641
11666
 
11642
11667
  angularModule('ng', ['ngLocale'], ['$provide',
11643
11668
  function ngModule($provide) {
11669
+ // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
11670
+ $provide.provider({
11671
+ $$sanitizeUri: $$SanitizeUriProvider
11672
+ });
11644
11673
  $provide.provider('$compile', $CompileProvider).
11645
11674
  directive({
11646
11675
  a: htmlAnchorDirective,
@@ -13144,11 +13173,11 @@ function annotate(fn) {
13144
13173
  * @example
13145
13174
  * Here are some examples of creating value services.
13146
13175
  * <pre>
13147
- * $provide.constant('ADMIN_USER', 'admin');
13176
+ * $provide.value('ADMIN_USER', 'admin');
13148
13177
  *
13149
- * $provide.constant('RoleLookup', { admin: 0, writer: 1, reader: 2 });
13178
+ * $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
13150
13179
  *
13151
- * $provide.constant('halfOf', function(value) {
13180
+ * $provide.value('halfOf', function(value) {
13152
13181
  * return value / 2;
13153
13182
  * });
13154
13183
  * </pre>
@@ -13634,13 +13663,14 @@ var $AnimateProvider = ['$provide', function($provide) {
13634
13663
  * inserted into the DOM
13635
13664
  */
13636
13665
  enter : function(element, parent, after, done) {
13637
- var afterNode = after && after[after.length - 1];
13638
- var parentNode = parent && parent[0] || afterNode && afterNode.parentNode;
13639
- // IE does not like undefined so we have to pass null.
13640
- var afterNextSibling = (afterNode && afterNode.nextSibling) || null;
13641
- forEach(element, function(node) {
13642
- parentNode.insertBefore(node, afterNextSibling);
13643
- });
13666
+ if (after) {
13667
+ after.after(element);
13668
+ } else {
13669
+ if (!parent || !parent[0]) {
13670
+ parent = after.parent();
13671
+ }
13672
+ parent.append(element);
13673
+ }
13644
13674
  done && $timeout(done, 0, false);
13645
13675
  },
13646
13676
 
@@ -14488,8 +14518,9 @@ function $TemplateCacheProvider() {
14488
14518
  * When there are multiple directives defined on a single DOM element, sometimes it
14489
14519
  * is necessary to specify the order in which the directives are applied. The `priority` is used
14490
14520
  * to sort the directives before their `compile` functions get called. Priority is defined as a
14491
- * number. Directives with greater numerical `priority` are compiled first. The order of directives with
14492
- * the same priority is undefined. The default priority is `0`.
14521
+ * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
14522
+ * are also run in priority order, but post-link functions are run in reverse order. The order
14523
+ * of directives with the same priority is undefined. The default priority is `0`.
14493
14524
  *
14494
14525
  * #### `terminal`
14495
14526
  * If set to true then the current `priority` will be the last set of directives
@@ -14550,8 +14581,9 @@ function $TemplateCacheProvider() {
14550
14581
  * * `$scope` - Current scope associated with the element
14551
14582
  * * `$element` - Current element
14552
14583
  * * `$attrs` - Current attributes object for the element
14553
- * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
14554
- * `function(cloneLinkingFn)`.
14584
+ * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope.
14585
+ * The scope can be overridden by an optional first argument.
14586
+ * `function([scope], cloneLinkingFn)`.
14555
14587
  *
14556
14588
  *
14557
14589
  * #### `require`
@@ -14644,7 +14676,7 @@ function $TemplateCacheProvider() {
14644
14676
  * * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
14645
14677
  * between all directive compile functions.
14646
14678
  *
14647
- * * `transclude` - A transclude linking function: `function(scope, cloneLinkingFn)`.
14679
+ * * `transclude` - [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
14648
14680
  *
14649
14681
  * <div class="alert alert-warning">
14650
14682
  * **Note:** The template instance and the link instance may be different objects if the template has
@@ -14653,6 +14685,12 @@ function $TemplateCacheProvider() {
14653
14685
  * should be done in a linking function rather than in a compile function.
14654
14686
  * </div>
14655
14687
  *
14688
+ * <div class="alert alert-error">
14689
+ * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
14690
+ * e.g. does not know about the right outer scope. Please use the transclude function that is passed
14691
+ * to the link function instead.
14692
+ * </div>
14693
+
14656
14694
  * A compile function can have a return value which can be either a function or an object.
14657
14695
  *
14658
14696
  * * returning a (post-link) function - is equivalent to registering the linking function via the
@@ -14667,7 +14705,7 @@ function $TemplateCacheProvider() {
14667
14705
  * This property is used only if the `compile` property is not defined.
14668
14706
  *
14669
14707
  * <pre>
14670
- * function link(scope, iElement, iAttrs, controller) { ... }
14708
+ * function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
14671
14709
  * </pre>
14672
14710
  *
14673
14711
  * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
@@ -14688,6 +14726,10 @@ function $TemplateCacheProvider() {
14688
14726
  * element defines a controller. The controller is shared among all the directives, which allows
14689
14727
  * the directives to use the controllers as a communication channel.
14690
14728
  *
14729
+ * * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
14730
+ * The scope can be overridden by an optional first argument. This is the same as the `$transclude`
14731
+ * parameter of directive controllers.
14732
+ * `function([scope], cloneLinkingFn)`.
14691
14733
  *
14692
14734
  *
14693
14735
  * #### Pre-linking function
@@ -14854,14 +14896,12 @@ var $compileMinErr = minErr('$compile');
14854
14896
  *
14855
14897
  * @description
14856
14898
  */
14857
- $CompileProvider.$inject = ['$provide'];
14858
- function $CompileProvider($provide) {
14899
+ $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
14900
+ function $CompileProvider($provide, $$sanitizeUriProvider) {
14859
14901
  var hasDirectives = {},
14860
14902
  Suffix = 'Directive',
14861
14903
  COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
14862
- CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
14863
- aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
14864
- imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//;
14904
+ CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/;
14865
14905
 
14866
14906
  // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
14867
14907
  // The assumption is that future DOM event attribute names will begin with
@@ -14945,10 +14985,11 @@ function $CompileProvider($provide) {
14945
14985
  */
14946
14986
  this.aHrefSanitizationWhitelist = function(regexp) {
14947
14987
  if (isDefined(regexp)) {
14948
- aHrefSanitizationWhitelist = regexp;
14988
+ $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
14949
14989
  return this;
14990
+ } else {
14991
+ return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
14950
14992
  }
14951
- return aHrefSanitizationWhitelist;
14952
14993
  };
14953
14994
 
14954
14995
 
@@ -14975,18 +15016,18 @@ function $CompileProvider($provide) {
14975
15016
  */
14976
15017
  this.imgSrcSanitizationWhitelist = function(regexp) {
14977
15018
  if (isDefined(regexp)) {
14978
- imgSrcSanitizationWhitelist = regexp;
15019
+ $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
14979
15020
  return this;
15021
+ } else {
15022
+ return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
14980
15023
  }
14981
- return imgSrcSanitizationWhitelist;
14982
15024
  };
14983
15025
 
14984
-
14985
15026
  this.$get = [
14986
15027
  '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
14987
- '$controller', '$rootScope', '$document', '$sce', '$animate',
15028
+ '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
14988
15029
  function($injector, $interpolate, $exceptionHandler, $http, $templateCache, $parse,
14989
- $controller, $rootScope, $document, $sce, $animate) {
15030
+ $controller, $rootScope, $document, $sce, $animate, $$sanitizeUri) {
14990
15031
 
14991
15032
  var Attributes = function(element, attr) {
14992
15033
  this.$$element = element;
@@ -15033,6 +15074,24 @@ function $CompileProvider($provide) {
15033
15074
  }
15034
15075
  },
15035
15076
 
15077
+ /**
15078
+ * @ngdoc function
15079
+ * @name ng.$compile.directive.Attributes#$updateClass
15080
+ * @methodOf ng.$compile.directive.Attributes
15081
+ * @function
15082
+ *
15083
+ * @description
15084
+ * Adds and removes the appropriate CSS class values to the element based on the difference
15085
+ * between the new and old CSS class values (specified as newClasses and oldClasses).
15086
+ *
15087
+ * @param {string} newClasses The current CSS className value
15088
+ * @param {string} oldClasses The former CSS className value
15089
+ */
15090
+ $updateClass : function(newClasses, oldClasses) {
15091
+ this.$removeClass(tokenDifference(oldClasses, newClasses));
15092
+ this.$addClass(tokenDifference(newClasses, oldClasses));
15093
+ },
15094
+
15036
15095
  /**
15037
15096
  * Set a normalized attribute on the element in a way such that all directives
15038
15097
  * can share the attribute. This function properly handles boolean attributes.
@@ -15043,59 +15102,44 @@ function $CompileProvider($provide) {
15043
15102
  * @param {string=} attrName Optional none normalized name. Defaults to key.
15044
15103
  */
15045
15104
  $set: function(key, value, writeAttr, attrName) {
15046
- //special case for class attribute addition + removal
15047
- //so that class changes can tap into the animation
15048
- //hooks provided by the $animate service
15049
- if(key == 'class') {
15050
- value = value || '';
15051
- var current = this.$$element.attr('class') || '';
15052
- this.$removeClass(tokenDifference(current, value).join(' '));
15053
- this.$addClass(tokenDifference(value, current).join(' '));
15054
- } else {
15055
- var booleanKey = getBooleanAttrName(this.$$element[0], key),
15056
- normalizedVal,
15057
- nodeName;
15105
+ // TODO: decide whether or not to throw an error if "class"
15106
+ //is set through this function since it may cause $updateClass to
15107
+ //become unstable.
15058
15108
 
15059
- if (booleanKey) {
15060
- this.$$element.prop(key, value);
15061
- attrName = booleanKey;
15062
- }
15109
+ var booleanKey = getBooleanAttrName(this.$$element[0], key),
15110
+ normalizedVal,
15111
+ nodeName;
15063
15112
 
15064
- this[key] = value;
15113
+ if (booleanKey) {
15114
+ this.$$element.prop(key, value);
15115
+ attrName = booleanKey;
15116
+ }
15065
15117
 
15066
- // translate normalized key to actual key
15067
- if (attrName) {
15068
- this.$attr[key] = attrName;
15069
- } else {
15070
- attrName = this.$attr[key];
15071
- if (!attrName) {
15072
- this.$attr[key] = attrName = snake_case(key, '-');
15073
- }
15074
- }
15118
+ this[key] = value;
15075
15119
 
15076
- nodeName = nodeName_(this.$$element);
15077
-
15078
- // sanitize a[href] and img[src] values
15079
- if ((nodeName === 'A' && key === 'href') ||
15080
- (nodeName === 'IMG' && key === 'src')) {
15081
- // NOTE: urlResolve() doesn't support IE < 8 so we don't sanitize for that case.
15082
- if (!msie || msie >= 8 ) {
15083
- normalizedVal = urlResolve(value).href;
15084
- if (normalizedVal !== '') {
15085
- if ((key === 'href' && !normalizedVal.match(aHrefSanitizationWhitelist)) ||
15086
- (key === 'src' && !normalizedVal.match(imgSrcSanitizationWhitelist))) {
15087
- this[key] = value = 'unsafe:' + normalizedVal;
15088
- }
15089
- }
15090
- }
15120
+ // translate normalized key to actual key
15121
+ if (attrName) {
15122
+ this.$attr[key] = attrName;
15123
+ } else {
15124
+ attrName = this.$attr[key];
15125
+ if (!attrName) {
15126
+ this.$attr[key] = attrName = snake_case(key, '-');
15091
15127
  }
15128
+ }
15092
15129
 
15093
- if (writeAttr !== false) {
15094
- if (value === null || value === undefined) {
15095
- this.$$element.removeAttr(attrName);
15096
- } else {
15097
- this.$$element.attr(attrName, value);
15098
- }
15130
+ nodeName = nodeName_(this.$$element);
15131
+
15132
+ // sanitize a[href] and img[src] values
15133
+ if ((nodeName === 'A' && key === 'href') ||
15134
+ (nodeName === 'IMG' && key === 'src')) {
15135
+ this[key] = value = $$sanitizeUri(value, key === 'src');
15136
+ }
15137
+
15138
+ if (writeAttr !== false) {
15139
+ if (value === null || value === undefined) {
15140
+ this.$$element.removeAttr(attrName);
15141
+ } else {
15142
+ this.$$element.attr(attrName, value);
15099
15143
  }
15100
15144
  }
15101
15145
 
@@ -15108,22 +15152,6 @@ function $CompileProvider($provide) {
15108
15152
  $exceptionHandler(e);
15109
15153
  }
15110
15154
  });
15111
-
15112
- function tokenDifference(str1, str2) {
15113
- var values = [],
15114
- tokens1 = str1.split(/\s+/),
15115
- tokens2 = str2.split(/\s+/);
15116
-
15117
- outer:
15118
- for(var i=0;i<tokens1.length;i++) {
15119
- var token = tokens1[i];
15120
- for(var j=0;j<tokens2.length;j++) {
15121
- if(token == tokens2[j]) continue outer;
15122
- }
15123
- values.push(token);
15124
- }
15125
- return values;
15126
- }
15127
15155
  },
15128
15156
 
15129
15157
 
@@ -15193,7 +15221,7 @@ function $CompileProvider($provide) {
15193
15221
  var compositeLinkFn =
15194
15222
  compileNodes($compileNodes, transcludeFn, $compileNodes,
15195
15223
  maxPriority, ignoreDirective, previousCompileContext);
15196
- return function publicLinkFn(scope, cloneConnectFn){
15224
+ return function publicLinkFn(scope, cloneConnectFn, transcludeControllers){
15197
15225
  assertArg(scope, 'scope');
15198
15226
  // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
15199
15227
  // and sometimes changes the structure of the DOM.
@@ -15201,6 +15229,10 @@ function $CompileProvider($provide) {
15201
15229
  ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
15202
15230
  : $compileNodes;
15203
15231
 
15232
+ forEach(transcludeControllers, function(instance, name) {
15233
+ $linkNode.data('$' + name + 'Controller', instance);
15234
+ });
15235
+
15204
15236
  // Attach scope only to non-text nodes.
15205
15237
  for(var i = 0, ii = $linkNode.length; i<ii; i++) {
15206
15238
  var node = $linkNode[i];
@@ -15299,15 +15331,7 @@ function $CompileProvider($provide) {
15299
15331
  childTranscludeFn = nodeLinkFn.transclude;
15300
15332
  if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
15301
15333
  nodeLinkFn(childLinkFn, childScope, node, $rootElement,
15302
- (function(transcludeFn) {
15303
- return function(cloneFn) {
15304
- var transcludeScope = scope.$new();
15305
- transcludeScope.$$transcluded = true;
15306
-
15307
- return transcludeFn(transcludeScope, cloneFn).
15308
- on('$destroy', bind(transcludeScope, transcludeScope.$destroy));
15309
- };
15310
- })(childTranscludeFn || transcludeFn)
15334
+ createBoundTranscludeFn(scope, childTranscludeFn || transcludeFn)
15311
15335
  );
15312
15336
  } else {
15313
15337
  nodeLinkFn(childLinkFn, childScope, node, undefined, boundTranscludeFn);
@@ -15319,6 +15343,23 @@ function $CompileProvider($provide) {
15319
15343
  }
15320
15344
  }
15321
15345
 
15346
+ function createBoundTranscludeFn(scope, transcludeFn) {
15347
+ return function boundTranscludeFn(transcludedScope, cloneFn, controllers) {
15348
+ var scopeCreated = false;
15349
+
15350
+ if (!transcludedScope) {
15351
+ transcludedScope = scope.$new();
15352
+ transcludedScope.$$transcluded = true;
15353
+ scopeCreated = true;
15354
+ }
15355
+
15356
+ var clone = transcludeFn(transcludedScope, cloneFn, controllers);
15357
+ if (scopeCreated) {
15358
+ clone.on('$destroy', bind(transcludedScope, transcludedScope.$destroy));
15359
+ }
15360
+ return clone;
15361
+ };
15362
+ }
15322
15363
 
15323
15364
  /**
15324
15365
  * Looks for directives on the given node and adds them to the directive collection which is
@@ -15456,9 +15497,9 @@ function $CompileProvider($provide) {
15456
15497
  * @returns {Function}
15457
15498
  */
15458
15499
  function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
15459
- return function(scope, element, attrs, controllers) {
15500
+ return function(scope, element, attrs, controllers, transcludeFn) {
15460
15501
  element = groupScan(element[0], attrStart, attrEnd);
15461
- return linkFn(scope, element, attrs, controllers);
15502
+ return linkFn(scope, element, attrs, controllers, transcludeFn);
15462
15503
  };
15463
15504
  }
15464
15505
 
@@ -15495,7 +15536,9 @@ function $CompileProvider($provide) {
15495
15536
  controllerDirectives = previousCompileContext.controllerDirectives,
15496
15537
  newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
15497
15538
  templateDirective = previousCompileContext.templateDirective,
15498
- transcludeDirective = previousCompileContext.transcludeDirective,
15539
+ nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
15540
+ hasTranscludeDirective = false,
15541
+ hasElementTranscludeDirective = false,
15499
15542
  $compileNode = templateAttrs.$$element = jqLite(compileNode),
15500
15543
  directive,
15501
15544
  directiveName,
@@ -15546,15 +15589,18 @@ function $CompileProvider($provide) {
15546
15589
  }
15547
15590
 
15548
15591
  if (directiveValue = directive.transclude) {
15592
+ hasTranscludeDirective = true;
15593
+
15549
15594
  // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
15550
15595
  // This option should only be used by directives that know how to how to safely handle element transclusion,
15551
15596
  // where the transcluded nodes are added or replaced after linking.
15552
15597
  if (!directive.$$tlb) {
15553
- assertNoDuplicate('transclusion', transcludeDirective, directive, $compileNode);
15554
- transcludeDirective = directive;
15598
+ assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
15599
+ nonTlbTranscludeDirective = directive;
15555
15600
  }
15556
15601
 
15557
15602
  if (directiveValue == 'element') {
15603
+ hasElementTranscludeDirective = true;
15558
15604
  terminalPriority = directive.priority;
15559
15605
  $template = groupScan(compileNode, attrStart, attrEnd);
15560
15606
  $compileNode = templateAttrs.$$element =
@@ -15570,9 +15616,9 @@ function $CompileProvider($provide) {
15570
15616
  // - newIsolateScopeDirective or templateDirective - combining templates with
15571
15617
  // element transclusion doesn't make sense.
15572
15618
  //
15573
- // We need only transcludeDirective so that we prevent putting transclusion
15619
+ // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
15574
15620
  // on the same element more than once.
15575
- transcludeDirective: transcludeDirective
15621
+ nonTlbTranscludeDirective: nonTlbTranscludeDirective
15576
15622
  });
15577
15623
  } else {
15578
15624
  $template = jqLite(jqLiteClone(compileNode)).contents();
@@ -15641,7 +15687,7 @@ function $CompileProvider($provide) {
15641
15687
  controllerDirectives: controllerDirectives,
15642
15688
  newIsolateScopeDirective: newIsolateScopeDirective,
15643
15689
  templateDirective: templateDirective,
15644
- transcludeDirective: transcludeDirective
15690
+ nonTlbTranscludeDirective: nonTlbTranscludeDirective
15645
15691
  });
15646
15692
  ii = directives.length;
15647
15693
  } else if (directive.compile) {
@@ -15665,7 +15711,7 @@ function $CompileProvider($provide) {
15665
15711
  }
15666
15712
 
15667
15713
  nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
15668
- nodeLinkFn.transclude = transcludeDirective && childTranscludeFn;
15714
+ nodeLinkFn.transclude = hasTranscludeDirective && childTranscludeFn;
15669
15715
 
15670
15716
  // might be normal or delayed nodeLinkFn depending on if templateUrl is present
15671
15717
  return nodeLinkFn;
@@ -15692,7 +15738,7 @@ function $CompileProvider($provide) {
15692
15738
  }
15693
15739
 
15694
15740
 
15695
- function getControllers(require, $element) {
15741
+ function getControllers(require, $element, elementControllers) {
15696
15742
  var value, retrievalMethod = 'data', optional = false;
15697
15743
  if (isString(require)) {
15698
15744
  while((value = require.charAt(0)) == '^' || value == '?') {
@@ -15702,13 +15748,12 @@ function $CompileProvider($provide) {
15702
15748
  }
15703
15749
  optional = optional || value == '?';
15704
15750
  }
15751
+ value = null;
15705
15752
 
15706
- value = $element[retrievalMethod]('$' + require + 'Controller');
15707
-
15708
- if ($element[0].nodeType == 8 && $element[0].$$controller) { // Transclusion comment node
15709
- value = value || $element[0].$$controller;
15710
- $element[0].$$controller = null;
15753
+ if (elementControllers && retrievalMethod === 'data') {
15754
+ value = elementControllers[require];
15711
15755
  }
15756
+ value = value || $element[retrievalMethod]('$' + require + 'Controller');
15712
15757
 
15713
15758
  if (!value && !optional) {
15714
15759
  throw $compileMinErr('ctreq',
@@ -15719,7 +15764,7 @@ function $CompileProvider($provide) {
15719
15764
  } else if (isArray(require)) {
15720
15765
  value = [];
15721
15766
  forEach(require, function(require) {
15722
- value.push(getControllers(require, $element));
15767
+ value.push(getControllers(require, $element, elementControllers));
15723
15768
  });
15724
15769
  }
15725
15770
  return value;
@@ -15727,7 +15772,7 @@ function $CompileProvider($provide) {
15727
15772
 
15728
15773
 
15729
15774
  function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
15730
- var attrs, $element, i, ii, linkFn, controller, isolateScope;
15775
+ var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn;
15731
15776
 
15732
15777
  if (compileNode === linkNode) {
15733
15778
  attrs = templateAttrs;
@@ -15821,14 +15866,14 @@ function $CompileProvider($provide) {
15821
15866
  }
15822
15867
  });
15823
15868
  }
15824
-
15869
+ transcludeFn = boundTranscludeFn && controllersBoundTransclude;
15825
15870
  if (controllerDirectives) {
15826
15871
  forEach(controllerDirectives, function(directive) {
15827
15872
  var locals = {
15828
15873
  $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
15829
15874
  $element: $element,
15830
15875
  $attrs: attrs,
15831
- $transclude: boundTranscludeFn
15876
+ $transclude: transcludeFn
15832
15877
  }, controllerInstance;
15833
15878
 
15834
15879
  controller = directive.controller;
@@ -15837,16 +15882,16 @@ function $CompileProvider($provide) {
15837
15882
  }
15838
15883
 
15839
15884
  controllerInstance = $controller(controller, locals);
15840
-
15841
- // Directives with element transclusion and a controller need to attach controller
15842
- // to the comment node created by the compiler, but jQuery .data doesn't support
15843
- // attaching data to comment nodes so instead we set it directly on the element and
15844
- // remove it after we read it later.
15845
- if ($element[0].nodeType == 8) { // Transclusion comment node
15846
- $element[0].$$controller = controllerInstance;
15847
- } else {
15885
+ // For directives with element transclusion the element is a comment,
15886
+ // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
15887
+ // clean up (http://bugs.jquery.com/ticket/8335).
15888
+ // Instead, we save the controllers for the element in a local hash and attach to .data
15889
+ // later, once we have the actual element.
15890
+ elementControllers[directive.name] = controllerInstance;
15891
+ if (!hasElementTranscludeDirective) {
15848
15892
  $element.data('$' + directive.name + 'Controller', controllerInstance);
15849
15893
  }
15894
+
15850
15895
  if (directive.controllerAs) {
15851
15896
  locals.$scope[directive.controllerAs] = controllerInstance;
15852
15897
  }
@@ -15858,7 +15903,7 @@ function $CompileProvider($provide) {
15858
15903
  try {
15859
15904
  linkFn = preLinkFns[i];
15860
15905
  linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
15861
- linkFn.require && getControllers(linkFn.require, $element));
15906
+ linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn);
15862
15907
  } catch (e) {
15863
15908
  $exceptionHandler(e, startingTag($element));
15864
15909
  }
@@ -15878,11 +15923,28 @@ function $CompileProvider($provide) {
15878
15923
  try {
15879
15924
  linkFn = postLinkFns[i];
15880
15925
  linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
15881
- linkFn.require && getControllers(linkFn.require, $element));
15926
+ linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn);
15882
15927
  } catch (e) {
15883
15928
  $exceptionHandler(e, startingTag($element));
15884
15929
  }
15885
15930
  }
15931
+
15932
+ // This is the function that is injected as `$transclude`.
15933
+ function controllersBoundTransclude(scope, cloneAttachFn) {
15934
+ var transcludeControllers;
15935
+
15936
+ // no scope passed
15937
+ if (arguments.length < 2) {
15938
+ cloneAttachFn = scope;
15939
+ scope = undefined;
15940
+ }
15941
+
15942
+ if (hasElementTranscludeDirective) {
15943
+ transcludeControllers = elementControllers;
15944
+ }
15945
+
15946
+ return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers);
15947
+ }
15886
15948
  }
15887
15949
  }
15888
15950
 
@@ -15961,6 +16023,7 @@ function $CompileProvider($provide) {
15961
16023
  dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
15962
16024
  } else if (key == 'style') {
15963
16025
  $element.attr('style', $element.attr('style') + ';' + value);
16026
+ dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
15964
16027
  // `dst` will never contain hasOwnProperty as DOM parser won't let it.
15965
16028
  // You will get an "InvalidCharacterError: DOM Exception 5" error if you
15966
16029
  // have an attribute like "has-own-property" or "data-has-own-property", etc.
@@ -15991,7 +16054,7 @@ function $CompileProvider($provide) {
15991
16054
 
15992
16055
  $http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}).
15993
16056
  success(function(content) {
15994
- var compileNode, tempTemplateAttrs, $template;
16057
+ var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
15995
16058
 
15996
16059
  content = denormalizeTemplate(content);
15997
16060
 
@@ -16036,7 +16099,7 @@ function $CompileProvider($provide) {
16036
16099
  var scope = linkQueue.shift(),
16037
16100
  beforeTemplateLinkNode = linkQueue.shift(),
16038
16101
  linkRootElement = linkQueue.shift(),
16039
- controller = linkQueue.shift(),
16102
+ boundTranscludeFn = linkQueue.shift(),
16040
16103
  linkNode = $compileNode[0];
16041
16104
 
16042
16105
  if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
@@ -16044,9 +16107,13 @@ function $CompileProvider($provide) {
16044
16107
  linkNode = jqLiteClone(compileNode);
16045
16108
  replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
16046
16109
  }
16047
-
16110
+ if (afterTemplateNodeLinkFn.transclude) {
16111
+ childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude);
16112
+ } else {
16113
+ childBoundTranscludeFn = boundTranscludeFn;
16114
+ }
16048
16115
  afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
16049
- controller);
16116
+ childBoundTranscludeFn);
16050
16117
  }
16051
16118
  linkQueue = null;
16052
16119
  }).
@@ -16054,14 +16121,14 @@ function $CompileProvider($provide) {
16054
16121
  throw $compileMinErr('tpload', 'Failed to load template: {0}', config.url);
16055
16122
  });
16056
16123
 
16057
- return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, controller) {
16124
+ return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
16058
16125
  if (linkQueue) {
16059
16126
  linkQueue.push(scope);
16060
16127
  linkQueue.push(node);
16061
16128
  linkQueue.push(rootElement);
16062
- linkQueue.push(controller);
16129
+ linkQueue.push(boundTranscludeFn);
16063
16130
  } else {
16064
- afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, controller);
16131
+ afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, boundTranscludeFn);
16065
16132
  }
16066
16133
  };
16067
16134
  }
@@ -16106,10 +16173,15 @@ function $CompileProvider($provide) {
16106
16173
 
16107
16174
 
16108
16175
  function getTrustedContext(node, attrNormalizedName) {
16176
+ if (attrNormalizedName == "srcdoc") {
16177
+ return $sce.HTML;
16178
+ }
16179
+ var tag = nodeName_(node);
16109
16180
  // maction[xlink:href] can source SVG. It's not limited to <maction>.
16110
16181
  if (attrNormalizedName == "xlinkHref" ||
16111
- (nodeName_(node) != "IMG" && (attrNormalizedName == "src" ||
16112
- attrNormalizedName == "ngSrc"))) {
16182
+ (tag == "FORM" && attrNormalizedName == "action") ||
16183
+ (tag != "IMG" && (attrNormalizedName == "src" ||
16184
+ attrNormalizedName == "ngSrc"))) {
16113
16185
  return $sce.RESOURCE_URL;
16114
16186
  }
16115
16187
  }
@@ -16154,9 +16226,19 @@ function $CompileProvider($provide) {
16154
16226
  attr[name] = interpolateFn(scope);
16155
16227
  ($$observers[name] || ($$observers[name] = [])).$$inter = true;
16156
16228
  (attr.$$observers && attr.$$observers[name].$$scope || scope).
16157
- $watch(interpolateFn, function interpolateFnWatchAction(value) {
16158
- attr.$set(name, value);
16159
- });
16229
+ $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
16230
+ //special case for class attribute addition + removal
16231
+ //so that class changes can tap into the animation
16232
+ //hooks provided by the $animate service. Be sure to
16233
+ //skip animations when the first digest occurs (when
16234
+ //both the new and the old values are the same) since
16235
+ //the CSS classes are the non-interpolated values
16236
+ if(name === 'class' && newValue != oldValue) {
16237
+ attr.$updateClass(newValue, oldValue);
16238
+ } else {
16239
+ attr.$set(name, newValue);
16240
+ }
16241
+ });
16160
16242
  }
16161
16243
  };
16162
16244
  }
@@ -16297,6 +16379,22 @@ function directiveLinkingFn(
16297
16379
  /* function(Function) */ boundTranscludeFn
16298
16380
  ){}
16299
16381
 
16382
+ function tokenDifference(str1, str2) {
16383
+ var values = '',
16384
+ tokens1 = str1.split(/\s+/),
16385
+ tokens2 = str2.split(/\s+/);
16386
+
16387
+ outer:
16388
+ for(var i = 0; i < tokens1.length; i++) {
16389
+ var token = tokens1[i];
16390
+ for(var j = 0; j < tokens2.length; j++) {
16391
+ if(token == tokens2[j]) continue outer;
16392
+ }
16393
+ values += (values.length > 0 ? ' ' : '') + token;
16394
+ }
16395
+ return values;
16396
+ }
16397
+
16300
16398
  /**
16301
16399
  * @ngdoc object
16302
16400
  * @name ng.$controllerProvider
@@ -16766,9 +16864,11 @@ function $HttpProvider() {
16766
16864
  *
16767
16865
  * # Caching
16768
16866
  *
16769
- * To enable caching, set the configuration property `cache` to `true`. When the cache is
16770
- * enabled, `$http` stores the response from the server in local cache. Next time the
16771
- * response is served from the cache without sending a request to the server.
16867
+ * To enable caching, set the request configuration `cache` property to `true` (to use default
16868
+ * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
16869
+ * When the cache is enabled, `$http` stores the response from the server in the specified
16870
+ * cache. The next time the same request is made, the response is served from the cache without
16871
+ * sending a request to the server.
16772
16872
  *
16773
16873
  * Note that even if the response is served from cache, delivery of the data is asynchronous in
16774
16874
  * the same way that real requests are.
@@ -16777,9 +16877,13 @@ function $HttpProvider() {
16777
16877
  * cache, but the cache is not populated yet, only one request to the server will be made and
16778
16878
  * the remaining requests will be fulfilled using the response from the first request.
16779
16879
  *
16780
- * A custom default cache built with $cacheFactory can be provided in $http.defaults.cache.
16781
- * To skip it, set configuration property `cache` to `false`.
16880
+ * You can change the default cache to a new object (built with
16881
+ * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
16882
+ * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set
16883
+ * their `cache` property to `true` will now use this cache object.
16782
16884
  *
16885
+ * If you set the default cache to `false` then only requests that specify their own custom
16886
+ * cache object will be cached.
16783
16887
  *
16784
16888
  * # Interceptors
16785
16889
  *
@@ -17501,12 +17605,13 @@ var XHR = window.XMLHttpRequest || function() {
17501
17605
  */
17502
17606
  function $HttpBackendProvider() {
17503
17607
  this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
17504
- return createHttpBackend($browser, XHR, $browser.defer, $window.angular.callbacks,
17505
- $document[0], $window.location.protocol.replace(':', ''));
17608
+ return createHttpBackend($browser, XHR, $browser.defer, $window.angular.callbacks, $document[0]);
17506
17609
  }];
17507
17610
  }
17508
17611
 
17509
- function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument, locationProtocol) {
17612
+ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument) {
17613
+ var ABORTED = -1;
17614
+
17510
17615
  // TODO(vojta): fix the signature
17511
17616
  return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
17512
17617
  var status;
@@ -17542,13 +17647,19 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
17542
17647
  // always async
17543
17648
  xhr.onreadystatechange = function() {
17544
17649
  if (xhr.readyState == 4) {
17545
- var responseHeaders = xhr.getAllResponseHeaders();
17650
+ var responseHeaders = null,
17651
+ response = null;
17652
+
17653
+ if(status !== ABORTED) {
17654
+ responseHeaders = xhr.getAllResponseHeaders();
17655
+ response = xhr.responseType ? xhr.response : xhr.responseText;
17656
+ }
17546
17657
 
17547
17658
  // responseText is the old-school way of retrieving response (supported by IE8 & 9)
17548
17659
  // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
17549
17660
  completeRequest(callback,
17550
17661
  status || xhr.status,
17551
- (xhr.responseType ? xhr.response : xhr.responseText),
17662
+ response,
17552
17663
  responseHeaders);
17553
17664
  }
17554
17665
  };
@@ -17572,20 +17683,20 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
17572
17683
 
17573
17684
 
17574
17685
  function timeoutRequest() {
17575
- status = -1;
17686
+ status = ABORTED;
17576
17687
  jsonpDone && jsonpDone();
17577
17688
  xhr && xhr.abort();
17578
17689
  }
17579
17690
 
17580
17691
  function completeRequest(callback, status, response, headersString) {
17581
- var protocol = locationProtocol || urlResolve(url).protocol;
17692
+ var protocol = urlResolve(url).protocol;
17582
17693
 
17583
17694
  // cancel timeout and subsequent timeout promise resolution
17584
17695
  timeoutId && $browserDefer.cancel(timeoutId);
17585
17696
  jsonpDone = xhr = null;
17586
17697
 
17587
17698
  // fix status code for file protocol (it's always 0)
17588
- status = (protocol == 'file') ? (response ? 200 : 404) : status;
17699
+ status = (protocol == 'file' && status === 0) ? (response ? 200 : 404) : status;
17589
17700
 
17590
17701
  // normalize IE bug (http://bugs.jquery.com/ticket/1450)
17591
17702
  status = status == 1223 ? 204 : status;
@@ -17601,6 +17712,7 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
17601
17712
  // - adds and immediately removes script elements from the document
17602
17713
  var script = rawDocument.createElement('script'),
17603
17714
  doneWrapper = function() {
17715
+ script.onreadystatechange = script.onload = script.onerror = null;
17604
17716
  rawDocument.body.removeChild(script);
17605
17717
  if (done) done();
17606
17718
  };
@@ -17608,12 +17720,16 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
17608
17720
  script.type = 'text/javascript';
17609
17721
  script.src = url;
17610
17722
 
17611
- if (msie) {
17723
+ if (msie && msie <= 8) {
17612
17724
  script.onreadystatechange = function() {
17613
- if (/loaded|complete/.test(script.readyState)) doneWrapper();
17725
+ if (/loaded|complete/.test(script.readyState)) {
17726
+ doneWrapper();
17727
+ }
17614
17728
  };
17615
17729
  } else {
17616
- script.onload = script.onerror = doneWrapper;
17730
+ script.onload = script.onerror = function() {
17731
+ doneWrapper();
17732
+ };
17617
17733
  }
17618
17734
 
17619
17735
  rawDocument.body.appendChild(script);
@@ -18043,8 +18159,8 @@ function encodePath(path) {
18043
18159
  return segments.join('/');
18044
18160
  }
18045
18161
 
18046
- function parseAbsoluteUrl(absoluteUrl, locationObj) {
18047
- var parsedUrl = urlResolve(absoluteUrl);
18162
+ function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
18163
+ var parsedUrl = urlResolve(absoluteUrl, appBase);
18048
18164
 
18049
18165
  locationObj.$$protocol = parsedUrl.protocol;
18050
18166
  locationObj.$$host = parsedUrl.hostname;
@@ -18052,12 +18168,12 @@ function parseAbsoluteUrl(absoluteUrl, locationObj) {
18052
18168
  }
18053
18169
 
18054
18170
 
18055
- function parseAppUrl(relativeUrl, locationObj) {
18171
+ function parseAppUrl(relativeUrl, locationObj, appBase) {
18056
18172
  var prefixed = (relativeUrl.charAt(0) !== '/');
18057
18173
  if (prefixed) {
18058
18174
  relativeUrl = '/' + relativeUrl;
18059
18175
  }
18060
- var match = urlResolve(relativeUrl);
18176
+ var match = urlResolve(relativeUrl, appBase);
18061
18177
  locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
18062
18178
  match.pathname.substring(1) : match.pathname);
18063
18179
  locationObj.$$search = parseKeyValue(match.search);
@@ -18112,7 +18228,7 @@ function LocationHtml5Url(appBase, basePrefix) {
18112
18228
  this.$$html5 = true;
18113
18229
  basePrefix = basePrefix || '';
18114
18230
  var appBaseNoFile = stripFile(appBase);
18115
- parseAbsoluteUrl(appBase, this);
18231
+ parseAbsoluteUrl(appBase, this, appBase);
18116
18232
 
18117
18233
 
18118
18234
  /**
@@ -18127,7 +18243,7 @@ function LocationHtml5Url(appBase, basePrefix) {
18127
18243
  appBaseNoFile);
18128
18244
  }
18129
18245
 
18130
- parseAppUrl(pathUrl, this);
18246
+ parseAppUrl(pathUrl, this, appBase);
18131
18247
 
18132
18248
  if (!this.$$path) {
18133
18249
  this.$$path = '/';
@@ -18179,7 +18295,7 @@ function LocationHtml5Url(appBase, basePrefix) {
18179
18295
  function LocationHashbangUrl(appBase, hashPrefix) {
18180
18296
  var appBaseNoFile = stripFile(appBase);
18181
18297
 
18182
- parseAbsoluteUrl(appBase, this);
18298
+ parseAbsoluteUrl(appBase, this, appBase);
18183
18299
 
18184
18300
 
18185
18301
  /**
@@ -18199,8 +18315,48 @@ function LocationHashbangUrl(appBase, hashPrefix) {
18199
18315
  throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
18200
18316
  hashPrefix);
18201
18317
  }
18202
- parseAppUrl(withoutHashUrl, this);
18318
+ parseAppUrl(withoutHashUrl, this, appBase);
18319
+
18320
+ this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
18321
+
18203
18322
  this.$$compose();
18323
+
18324
+ /*
18325
+ * In Windows, on an anchor node on documents loaded from
18326
+ * the filesystem, the browser will return a pathname
18327
+ * prefixed with the drive name ('/C:/path') when a
18328
+ * pathname without a drive is set:
18329
+ * * a.setAttribute('href', '/foo')
18330
+ * * a.pathname === '/C:/foo' //true
18331
+ *
18332
+ * Inside of Angular, we're always using pathnames that
18333
+ * do not include drive names for routing.
18334
+ */
18335
+ function removeWindowsDriveName (path, url, base) {
18336
+ /*
18337
+ Matches paths for file protocol on windows,
18338
+ such as /C:/foo/bar, and captures only /foo/bar.
18339
+ */
18340
+ var windowsFilePathExp = /^\/?.*?:(\/.*)/;
18341
+
18342
+ var firstPathSegmentMatch;
18343
+
18344
+ //Get the relative path from the input URL.
18345
+ if (url.indexOf(base) === 0) {
18346
+ url = url.replace(base, '');
18347
+ }
18348
+
18349
+ /*
18350
+ * The input URL intentionally contains a
18351
+ * first path segment that ends with a colon.
18352
+ */
18353
+ if (windowsFilePathExp.exec(url)) {
18354
+ return path;
18355
+ }
18356
+
18357
+ firstPathSegmentMatch = windowsFilePathExp.exec(path);
18358
+ return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
18359
+ }
18204
18360
  };
18205
18361
 
18206
18362
  /**
@@ -18690,7 +18846,7 @@ function $LocationProvider(){
18690
18846
  *
18691
18847
  * The main purpose of this service is to simplify debugging and troubleshooting.
18692
18848
  *
18693
- * The default is not to log `debug` messages. You can use
18849
+ * The default is to log `debug` messages. You can use
18694
18850
  * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
18695
18851
  *
18696
18852
  * @example
@@ -18847,23 +19003,18 @@ var promiseWarning;
18847
19003
  // ------------------------------
18848
19004
  // Angular expressions are generally considered safe because these expressions only have direct
18849
19005
  // access to $scope and locals. However, one can obtain the ability to execute arbitrary JS code by
18850
- // obtaining a reference to native JS functions such as the Function constructor, the global Window
18851
- // or Document object. In addition, many powerful functions for use by JavaScript code are
18852
- // published on scope that shouldn't be available from within an Angular expression.
19006
+ // obtaining a reference to native JS functions such as the Function constructor.
18853
19007
  //
18854
19008
  // As an example, consider the following Angular expression:
18855
19009
  //
18856
19010
  // {}.toString.constructor(alert("evil JS code"))
18857
19011
  //
18858
19012
  // We want to prevent this type of access. For the sake of performance, during the lexing phase we
18859
- // disallow any "dotted" access to any member named "constructor" or to any member whose name begins
18860
- // or ends with an underscore. The latter allows one to exclude the private / JavaScript only API
18861
- // available on the scope and controllers from the context of an Angular expression.
19013
+ // disallow any "dotted" access to any member named "constructor".
18862
19014
  //
18863
- // For reflective calls (a[b]), we check that the value of the lookup is not the Function
18864
- // constructor, Window or DOM node while evaluating the expression, which is a stronger but more
18865
- // expensive test. Since reflective calls are expensive anyway, this is not such a big deal compared
18866
- // to static dereferencing.
19015
+ // For reflective calls (a[b]) we check that the value of the lookup is not the Function constructor
19016
+ // while evaluating the expression, which is a stronger but more expensive test. Since reflective
19017
+ // calls are expensive anyway, this is not such a big deal compared to static dereferencing.
18867
19018
  //
18868
19019
  // This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
18869
19020
  // against the expression language, but not to prevent exploits that were enabled by exposing
@@ -18877,20 +19028,12 @@ var promiseWarning;
18877
19028
  // In general, it is not possible to access a Window object from an angular expression unless a
18878
19029
  // window or some DOM object that has a reference to window is published onto a Scope.
18879
19030
 
18880
- function ensureSafeMemberName(name, fullExpression, allowConstructor) {
18881
- if (typeof name !== 'string' && toString.apply(name) !== "[object String]") {
18882
- return name;
18883
- }
18884
- if (name === "constructor" && !allowConstructor) {
19031
+ function ensureSafeMemberName(name, fullExpression) {
19032
+ if (name === "constructor") {
18885
19033
  throw $parseMinErr('isecfld',
18886
19034
  'Referencing "constructor" field in Angular expressions is disallowed! Expression: {0}',
18887
19035
  fullExpression);
18888
19036
  }
18889
- if (name.charAt(0) === '_' || name.charAt(name.length-1) === '_') {
18890
- throw $parseMinErr('isecprv',
18891
- 'Referencing private fields in Angular expressions is disallowed! Expression: {0}',
18892
- fullExpression);
18893
- }
18894
19037
  return name;
18895
19038
  }
18896
19039
 
@@ -19574,10 +19717,7 @@ Parser.prototype = {
19574
19717
 
19575
19718
  return extend(function(self, locals) {
19576
19719
  var o = obj(self, locals),
19577
- // In the getter, we will not block looking up "constructor" by name in order to support user defined
19578
- // constructors. However, if value looked up is the Function constructor, we will still block it in the
19579
- // ensureSafeObject call right after we look up o[i] (a few lines below.)
19580
- i = ensureSafeMemberName(indexFn(self, locals), parser.text, true /* allowConstructor */),
19720
+ i = indexFn(self, locals),
19581
19721
  v, p;
19582
19722
 
19583
19723
  if (!o) return undefined;
@@ -19593,7 +19733,7 @@ Parser.prototype = {
19593
19733
  return v;
19594
19734
  }, {
19595
19735
  assign: function(self, value, locals) {
19596
- var key = ensureSafeMemberName(indexFn(self, locals), parser.text);
19736
+ var key = indexFn(self, locals);
19597
19737
  // prevent overwriting of Function.constructor which would break ensureSafeObject check
19598
19738
  var safe = ensureSafeObject(obj(self, locals), parser.text);
19599
19739
  return safe[key] = value;
@@ -19872,7 +20012,7 @@ function getterFn(path, options, fullExp) {
19872
20012
  : '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' +
19873
20013
  (options.unwrapPromises
19874
20014
  ? 'if (s && s.then) {\n' +
19875
- ' pw("' + fullExp.replace(/\"/g, '\\"') + '");\n' +
20015
+ ' pw("' + fullExp.replace(/(["\r\n])/g, '\\$1') + '");\n' +
19876
20016
  ' if (!("$$v" in s)) {\n' +
19877
20017
  ' p=s;\n' +
19878
20018
  ' p.$$v = undefined;\n' +
@@ -20253,7 +20393,7 @@ function $ParseProvider() {
20253
20393
  * // Propagate promise resolution to 'then' functions using $apply().
20254
20394
  * $rootScope.$apply();
20255
20395
  * expect(resolvedValue).toEqual(123);
20256
- * });
20396
+ * }));
20257
20397
  * </pre>
20258
20398
  */
20259
20399
  function $QProvider() {
@@ -21643,6 +21783,79 @@ function $RootScopeProvider(){
21643
21783
  }];
21644
21784
  }
21645
21785
 
21786
+ /**
21787
+ * @description
21788
+ * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
21789
+ */
21790
+ function $$SanitizeUriProvider() {
21791
+ var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
21792
+ imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//;
21793
+
21794
+ /**
21795
+ * @description
21796
+ * Retrieves or overrides the default regular expression that is used for whitelisting of safe
21797
+ * urls during a[href] sanitization.
21798
+ *
21799
+ * The sanitization is a security measure aimed at prevent XSS attacks via html links.
21800
+ *
21801
+ * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
21802
+ * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
21803
+ * regular expression. If a match is found, the original url is written into the dom. Otherwise,
21804
+ * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
21805
+ *
21806
+ * @param {RegExp=} regexp New regexp to whitelist urls with.
21807
+ * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
21808
+ * chaining otherwise.
21809
+ */
21810
+ this.aHrefSanitizationWhitelist = function(regexp) {
21811
+ if (isDefined(regexp)) {
21812
+ aHrefSanitizationWhitelist = regexp;
21813
+ return this;
21814
+ }
21815
+ return aHrefSanitizationWhitelist;
21816
+ };
21817
+
21818
+
21819
+ /**
21820
+ * @description
21821
+ * Retrieves or overrides the default regular expression that is used for whitelisting of safe
21822
+ * urls during img[src] sanitization.
21823
+ *
21824
+ * The sanitization is a security measure aimed at prevent XSS attacks via html links.
21825
+ *
21826
+ * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
21827
+ * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
21828
+ * regular expression. If a match is found, the original url is written into the dom. Otherwise,
21829
+ * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
21830
+ *
21831
+ * @param {RegExp=} regexp New regexp to whitelist urls with.
21832
+ * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
21833
+ * chaining otherwise.
21834
+ */
21835
+ this.imgSrcSanitizationWhitelist = function(regexp) {
21836
+ if (isDefined(regexp)) {
21837
+ imgSrcSanitizationWhitelist = regexp;
21838
+ return this;
21839
+ }
21840
+ return imgSrcSanitizationWhitelist;
21841
+ };
21842
+
21843
+ this.$get = function() {
21844
+ return function sanitizeUri(uri, isImage) {
21845
+ var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
21846
+ var normalizedVal;
21847
+ // NOTE: urlResolve() doesn't support IE < 8 so we don't sanitize for that case.
21848
+ if (!msie || msie >= 8 ) {
21849
+ normalizedVal = urlResolve(uri).href;
21850
+ if (normalizedVal !== '' && !normalizedVal.match(regex)) {
21851
+ return 'unsafe:'+normalizedVal;
21852
+ }
21853
+ }
21854
+ return uri;
21855
+ };
21856
+ };
21857
+ }
21858
+
21646
21859
  var $sceMinErr = minErr('$sce');
21647
21860
 
21648
21861
  var SCE_CONTEXTS = {
@@ -21842,8 +22055,7 @@ function $SceDelegateProvider() {
21842
22055
  return resourceUrlBlacklist;
21843
22056
  };
21844
22057
 
21845
- this.$get = ['$log', '$document', '$injector', function(
21846
- $log, $document, $injector) {
22058
+ this.$get = ['$injector', function($injector) {
21847
22059
 
21848
22060
  var htmlSanitizer = function htmlSanitizer(html) {
21849
22061
  throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
@@ -22070,10 +22282,10 @@ function $SceDelegateProvider() {
22070
22282
  *
22071
22283
  * <pre class="prettyprint">
22072
22284
  * <input ng-model="userHtml">
22073
- * <div ng-bind-html="{{userHtml}}">
22285
+ * <div ng-bind-html="userHtml">
22074
22286
  * </pre>
22075
22287
  *
22076
- * Notice that `ng-bind-html` is bound to `{{userHtml}}` controlled by the user. With SCE
22288
+ * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user. With SCE
22077
22289
  * disabled, this application allows the user to render arbitrary HTML into the DIV.
22078
22290
  * In a more realistic example, one may be rendering user comments, blog articles, etc. via
22079
22291
  * bindings. (HTML is just one example of a context where rendering user controlled input creates
@@ -22374,18 +22586,15 @@ function $SceProvider() {
22374
22586
  * sce.js and sceSpecs.js would need to be aware of this detail.
22375
22587
  */
22376
22588
 
22377
- this.$get = ['$parse', '$document', '$sceDelegate', function(
22378
- $parse, $document, $sceDelegate) {
22589
+ this.$get = ['$parse', '$sniffer', '$sceDelegate', function(
22590
+ $parse, $sniffer, $sceDelegate) {
22379
22591
  // Prereq: Ensure that we're not running in IE8 quirks mode. In that mode, IE allows
22380
22592
  // the "expression(javascript expression)" syntax which is insecure.
22381
- if (enabled && msie) {
22382
- var documentMode = $document[0].documentMode;
22383
- if (documentMode !== undefined && documentMode < 8) {
22384
- throw $sceMinErr('iequirks',
22385
- 'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' +
22386
- 'mode. You can fix this by adding the text <!doctype html> to the top of your HTML ' +
22387
- 'document. See http://docs.angularjs.org/api/ng.$sce for more information.');
22388
- }
22593
+ if (enabled && $sniffer.msie && $sniffer.msieDocumentMode < 8) {
22594
+ throw $sceMinErr('iequirks',
22595
+ 'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' +
22596
+ 'mode. You can fix this by adding the text <!doctype html> to the top of your HTML ' +
22597
+ 'document. See http://docs.angularjs.org/api/ng.$sce for more information.');
22389
22598
  }
22390
22599
 
22391
22600
  var sce = copy(SCE_CONTEXTS);
@@ -22747,6 +22956,7 @@ function $SnifferProvider() {
22747
22956
  int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
22748
22957
  boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
22749
22958
  document = $document[0] || {},
22959
+ documentMode = document.documentMode,
22750
22960
  vendorPrefix,
22751
22961
  vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/,
22752
22962
  bodyStyle = document.body && document.body.style,
@@ -22791,7 +23001,7 @@ function $SnifferProvider() {
22791
23001
  // jshint +W018
22792
23002
  hashchange: 'onhashchange' in $window &&
22793
23003
  // IE8 compatible mode lies
22794
- (!document.documentMode || document.documentMode > 7),
23004
+ (!documentMode || documentMode > 7),
22795
23005
  hasEvent: function(event) {
22796
23006
  // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
22797
23007
  // it. In particular the event is not fired when backspace or delete key are pressed or
@@ -22809,7 +23019,8 @@ function $SnifferProvider() {
22809
23019
  vendorPrefix: vendorPrefix,
22810
23020
  transitions : transitions,
22811
23021
  animations : animations,
22812
- msie : msie
23022
+ msie : msie,
23023
+ msieDocumentMode: documentMode
22813
23024
  };
22814
23025
  }];
22815
23026
  }
@@ -22996,6 +23207,7 @@ function $TimeoutProvider() {
22996
23207
  var urlParsingNode = document.createElement("a");
22997
23208
  var originUrl = urlResolve(window.location.href, true);
22998
23209
 
23210
+
22999
23211
  /**
23000
23212
  *
23001
23213
  * Implementation Notes for non-IE browsers
@@ -23014,7 +23226,7 @@ var originUrl = urlResolve(window.location.href, true);
23014
23226
  * browsers. However, the parsed components will not be set if the URL assigned did not specify
23015
23227
  * them. (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.) We
23016
23228
  * work around that by performing the parsing in a 2nd step by taking a previously normalized
23017
- * URL (e.g. by assining to a.href) and assigning it a.href again. This correctly populates the
23229
+ * URL (e.g. by assigning to a.href) and assigning it a.href again. This correctly populates the
23018
23230
  * properties such as protocol, hostname, port, etc.
23019
23231
  *
23020
23232
  * IE7 does not normalize the URL when assigned to an anchor node. (Apparently, it does, if one
@@ -23048,8 +23260,9 @@ var originUrl = urlResolve(window.location.href, true);
23048
23260
  * | pathname | The pathname, beginning with "/"
23049
23261
  *
23050
23262
  */
23051
- function urlResolve(url) {
23263
+ function urlResolve(url, base) {
23052
23264
  var href = url;
23265
+
23053
23266
  if (msie) {
23054
23267
  // Normalize before parse. Refer Implementation Notes on why this is
23055
23268
  // done in two steps on IE.
@@ -23059,7 +23272,7 @@ function urlResolve(url) {
23059
23272
 
23060
23273
  urlParsingNode.setAttribute('href', href);
23061
23274
 
23062
- // $$urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
23275
+ // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
23063
23276
  return {
23064
23277
  href: urlParsingNode.href,
23065
23278
  protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
@@ -23068,12 +23281,12 @@ function urlResolve(url) {
23068
23281
  hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
23069
23282
  hostname: urlParsingNode.hostname,
23070
23283
  port: urlParsingNode.port,
23071
- pathname: urlParsingNode.pathname && urlParsingNode.pathname.charAt(0) === '/' ?
23072
- urlParsingNode.pathname : '/' + urlParsingNode.pathname
23284
+ pathname: (urlParsingNode.pathname.charAt(0) === '/')
23285
+ ? urlParsingNode.pathname
23286
+ : '/' + urlParsingNode.pathname
23073
23287
  };
23074
23288
  }
23075
23289
 
23076
-
23077
23290
  /**
23078
23291
  * Parse a request URL and determine whether this is a same-origin request as the application document.
23079
23292
  *
@@ -24382,8 +24595,11 @@ var htmlAnchorDirective = valueFn({
24382
24595
  *
24383
24596
  * The HTML specification does not require browsers to preserve the values of boolean attributes
24384
24597
  * such as disabled. (Their presence means true and their absence means false.)
24385
- * This prevents the Angular compiler from retrieving the binding expression.
24598
+ * If we put an Angular interpolation expression into such an attribute then the
24599
+ * binding information would be lost when the browser removes the attribute.
24386
24600
  * The `ngDisabled` directive solves this problem for the `disabled` attribute.
24601
+ * This complementary directive is not removed by the browser and so provides
24602
+ * a permanent reliable place to store the binding information.
24387
24603
  *
24388
24604
  * @example
24389
24605
  <doc:example>
@@ -24414,8 +24630,11 @@ var htmlAnchorDirective = valueFn({
24414
24630
  * @description
24415
24631
  * The HTML specification does not require browsers to preserve the values of boolean attributes
24416
24632
  * such as checked. (Their presence means true and their absence means false.)
24417
- * This prevents the Angular compiler from retrieving the binding expression.
24633
+ * If we put an Angular interpolation expression into such an attribute then the
24634
+ * binding information would be lost when the browser removes the attribute.
24418
24635
  * The `ngChecked` directive solves this problem for the `checked` attribute.
24636
+ * This complementary directive is not removed by the browser and so provides
24637
+ * a permanent reliable place to store the binding information.
24419
24638
  * @example
24420
24639
  <doc:example>
24421
24640
  <doc:source>
@@ -24445,8 +24664,12 @@ var htmlAnchorDirective = valueFn({
24445
24664
  * @description
24446
24665
  * The HTML specification does not require browsers to preserve the values of boolean attributes
24447
24666
  * such as readonly. (Their presence means true and their absence means false.)
24448
- * This prevents the Angular compiler from retrieving the binding expression.
24667
+ * If we put an Angular interpolation expression into such an attribute then the
24668
+ * binding information would be lost when the browser removes the attribute.
24449
24669
  * The `ngReadonly` directive solves this problem for the `readonly` attribute.
24670
+ * This complementary directive is not removed by the browser and so provides
24671
+ * a permanent reliable place to store the binding information.
24672
+
24450
24673
  * @example
24451
24674
  <doc:example>
24452
24675
  <doc:source>
@@ -24476,8 +24699,11 @@ var htmlAnchorDirective = valueFn({
24476
24699
  * @description
24477
24700
  * The HTML specification does not require browsers to preserve the values of boolean attributes
24478
24701
  * such as selected. (Their presence means true and their absence means false.)
24479
- * This prevents the Angular compiler from retrieving the binding expression.
24702
+ * If we put an Angular interpolation expression into such an attribute then the
24703
+ * binding information would be lost when the browser removes the attribute.
24480
24704
  * The `ngSelected` directive solves this problem for the `selected` atttribute.
24705
+ * This complementary directive is not removed by the browser and so provides
24706
+ * a permanent reliable place to store the binding information.
24481
24707
  * @example
24482
24708
  <doc:example>
24483
24709
  <doc:source>
@@ -24509,8 +24735,12 @@ var htmlAnchorDirective = valueFn({
24509
24735
  * @description
24510
24736
  * The HTML specification does not require browsers to preserve the values of boolean attributes
24511
24737
  * such as open. (Their presence means true and their absence means false.)
24512
- * This prevents the Angular compiler from retrieving the binding expression.
24738
+ * If we put an Angular interpolation expression into such an attribute then the
24739
+ * binding information would be lost when the browser removes the attribute.
24513
24740
  * The `ngOpen` directive solves this problem for the `open` attribute.
24741
+ * This complementary directive is not removed by the browser and so provides
24742
+ * a permanent reliable place to store the binding information.
24743
+
24514
24744
  *
24515
24745
  * @example
24516
24746
  <doc:example>
@@ -24603,7 +24833,7 @@ var nullFormCtrl = {
24603
24833
  * @property {Object} $error Is an object hash, containing references to all invalid controls or
24604
24834
  * forms, where:
24605
24835
  *
24606
- * - keys are validation tokens (error names) — such as `required`, `url` or `email`),
24836
+ * - keys are validation tokens (error names) — such as `required`, `url` or `email`,
24607
24837
  * - values are arrays of controls or forms that are invalid with given error.
24608
24838
  *
24609
24839
  * @description
@@ -25340,8 +25570,21 @@ var inputType = {
25340
25570
 
25341
25571
 
25342
25572
  function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
25573
+ // In composition mode, users are still inputing intermediate text buffer,
25574
+ // hold the listener until composition is done.
25575
+ // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
25576
+ var composing = false;
25577
+
25578
+ element.on('compositionstart', function() {
25579
+ composing = true;
25580
+ });
25581
+
25582
+ element.on('compositionend', function() {
25583
+ composing = false;
25584
+ });
25343
25585
 
25344
25586
  var listener = function() {
25587
+ if (composing) return;
25345
25588
  var value = element.val();
25346
25589
 
25347
25590
  // By default we will trim the value
@@ -25384,15 +25627,15 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
25384
25627
  deferListener();
25385
25628
  });
25386
25629
 
25387
- // if user paste into input using mouse, we need "change" event to catch it
25388
- element.on('change', listener);
25389
-
25390
25630
  // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
25391
25631
  if ($sniffer.hasEvent('paste')) {
25392
25632
  element.on('paste cut', deferListener);
25393
25633
  }
25394
25634
  }
25395
25635
 
25636
+ // if user paste into input using mouse on older browser
25637
+ // or form autocomplete on newer browser, we need "change" event to catch it
25638
+ element.on('change', listener);
25396
25639
 
25397
25640
  ctrl.$render = function() {
25398
25641
  element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
@@ -25788,6 +26031,11 @@ var VALID_CLASS = 'ng-valid',
25788
26031
  * }
25789
26032
  * ngModel.$formatters.push(formatter);
25790
26033
  * </pre>
26034
+ *
26035
+ * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
26036
+ * view value has changed. It is called with no arguments, and its return value is ignored.
26037
+ * This can be used in place of additional $watches against the model value.
26038
+ *
25791
26039
  * @property {Object} $error An object hash with all errors as keys.
25792
26040
  *
25793
26041
  * @property {boolean} $pristine True if user has not interacted with the control yet.
@@ -26051,14 +26299,19 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
26051
26299
  * @methodOf ng.directive:ngModel.NgModelController
26052
26300
  *
26053
26301
  * @description
26054
- * Read a value from view.
26302
+ * Update the view value.
26055
26303
  *
26056
- * This method should be called from within a DOM event handler.
26057
- * For example {@link ng.directive:input input} or
26304
+ * This method should be called when the view value changes, typically from within a DOM event handler.
26305
+ * For example {@link ng.directive:input input} and
26058
26306
  * {@link ng.directive:select select} directives call it.
26059
26307
  *
26060
- * It internally calls all `$parsers` (including validators) and updates the `$modelValue` and the actual model path.
26061
- * Lastly it calls all registered change listeners.
26308
+ * It will update the $viewValue, then pass this value through each of the functions in `$parsers`,
26309
+ * which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to
26310
+ * `$modelValue` and the **expression** specified in the `ng-model` attribute.
26311
+ *
26312
+ * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
26313
+ *
26314
+ * Note that calling this function does not trigger a `$digest`.
26062
26315
  *
26063
26316
  * @param {string} value Value from the view.
26064
26317
  */
@@ -26560,27 +26813,33 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
26560
26813
  * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
26561
26814
  *
26562
26815
  * @example
26563
- * Try it here: enter text in text box and watch the greeting change.
26564
- <doc:example module="ngBindHtmlExample" deps="angular-sanitize.js" >
26565
- <doc:source>
26566
- <script>
26567
- angular.module('ngBindHtmlExample', ['ngSanitize'])
26568
-
26569
- .controller('ngBindHtmlCtrl', ['$scope', function ngBindHtmlCtrl($scope) {
26570
- $scope.myHTML = 'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>';
26571
- }]);
26572
- </script>
26816
+ Try it here: enter text in text box and watch the greeting change.
26817
+
26818
+ <example module="ngBindHtmlExample" deps="angular-sanitize.js">
26819
+ <file name="index.html">
26573
26820
  <div ng-controller="ngBindHtmlCtrl">
26574
26821
  <p ng-bind-html="myHTML"></p>
26575
26822
  </div>
26576
- </doc:source>
26577
- <doc:scenario>
26823
+ </file>
26824
+
26825
+ <file name="script.js">
26826
+ angular.module('ngBindHtmlExample', ['ngSanitize'])
26827
+
26828
+ .controller('ngBindHtmlCtrl', ['$scope', function ngBindHtmlCtrl($scope) {
26829
+ $scope.myHTML =
26830
+ 'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>';
26831
+ }]);
26832
+ </file>
26833
+
26834
+ <file name="scenario.js">
26578
26835
  it('should check ng-bind-html', function() {
26579
26836
  expect(using('.doc-example-live').binding('myHTML')).
26580
- toBe('I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>');
26837
+ toBe(
26838
+ 'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>'
26839
+ );
26581
26840
  });
26582
- </doc:scenario>
26583
- </doc:example>
26841
+ </file>
26842
+ </example>
26584
26843
  */
26585
26844
  var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
26586
26845
  return function(scope, element, attr) {
@@ -26615,11 +26874,10 @@ function classDirective(name, selector) {
26615
26874
  // jshint bitwise: false
26616
26875
  var mod = $index & 1;
26617
26876
  if (mod !== old$index & 1) {
26618
- if (mod === selector) {
26619
- addClass(scope.$eval(attr[name]));
26620
- } else {
26621
- removeClass(scope.$eval(attr[name]));
26622
- }
26877
+ var classes = flattenClasses(scope.$eval(attr[name]));
26878
+ mod === selector ?
26879
+ attr.$addClass(classes) :
26880
+ attr.$removeClass(classes);
26623
26881
  }
26624
26882
  });
26625
26883
  }
@@ -26627,24 +26885,17 @@ function classDirective(name, selector) {
26627
26885
 
26628
26886
  function ngClassWatchAction(newVal) {
26629
26887
  if (selector === true || scope.$index % 2 === selector) {
26630
- if (oldVal && !equals(newVal,oldVal)) {
26631
- removeClass(oldVal);
26888
+ var newClasses = flattenClasses(newVal || '');
26889
+ if(!oldVal) {
26890
+ attr.$addClass(newClasses);
26891
+ } else if(!equals(newVal,oldVal)) {
26892
+ attr.$updateClass(newClasses, flattenClasses(oldVal));
26632
26893
  }
26633
- addClass(newVal);
26634
26894
  }
26635
26895
  oldVal = copy(newVal);
26636
26896
  }
26637
26897
 
26638
26898
 
26639
- function removeClass(classVal) {
26640
- attr.$removeClass(flattenClasses(classVal));
26641
- }
26642
-
26643
-
26644
- function addClass(classVal) {
26645
- attr.$addClass(flattenClasses(classVal));
26646
- }
26647
-
26648
26899
  function flattenClasses(classVal) {
26649
26900
  if(isArray(classVal)) {
26650
26901
  return classVal.join(' ');
@@ -26693,18 +26944,18 @@ function classDirective(name, selector) {
26693
26944
  * @example Example that demonstrates basic bindings via ngClass directive.
26694
26945
  <example>
26695
26946
  <file name="index.html">
26696
- <p ng-class="{strike: strike, bold: bold, red: red}">Map Syntax Example</p>
26697
- <input type="checkbox" ng-model="bold"> bold
26698
- <input type="checkbox" ng-model="strike"> strike
26699
- <input type="checkbox" ng-model="red"> red
26947
+ <p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
26948
+ <input type="checkbox" ng-model="deleted"> deleted (apply "strike" class)<br>
26949
+ <input type="checkbox" ng-model="important"> important (apply "bold" class)<br>
26950
+ <input type="checkbox" ng-model="error"> error (apply "red" class)
26700
26951
  <hr>
26701
26952
  <p ng-class="style">Using String Syntax</p>
26702
26953
  <input type="text" ng-model="style" placeholder="Type: bold strike red">
26703
26954
  <hr>
26704
26955
  <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
26705
- <input ng-model="style1" placeholder="Type: bold"><br>
26706
- <input ng-model="style2" placeholder="Type: strike"><br>
26707
- <input ng-model="style3" placeholder="Type: red"><br>
26956
+ <input ng-model="style1" placeholder="Type: bold, strike or red"><br>
26957
+ <input ng-model="style2" placeholder="Type: bold, strike or red"><br>
26958
+ <input ng-model="style3" placeholder="Type: bold, strike or red"><br>
26708
26959
  </file>
26709
26960
  <file name="style.css">
26710
26961
  .strike {
@@ -26723,10 +26974,10 @@ function classDirective(name, selector) {
26723
26974
  expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/bold/);
26724
26975
  expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/red/);
26725
26976
 
26726
- input('bold').check();
26977
+ input('important').check();
26727
26978
  expect(element('.doc-example-live p:first').prop('className')).toMatch(/bold/);
26728
26979
 
26729
- input('red').check();
26980
+ input('error').check();
26730
26981
  expect(element('.doc-example-live p:first').prop('className')).toMatch(/red/);
26731
26982
  });
26732
26983
 
@@ -27122,7 +27373,8 @@ var ngCloakDirective = ngDirective({
27122
27373
  var ngControllerDirective = [function() {
27123
27374
  return {
27124
27375
  scope: true,
27125
- controller: '@'
27376
+ controller: '@',
27377
+ priority: 500
27126
27378
  };
27127
27379
  }];
27128
27380
 
@@ -27572,7 +27824,7 @@ forEach(
27572
27824
  }
27573
27825
 
27574
27826
  /&#42;
27575
- The transition styles can also be placed on the CSS base class above
27827
+ The transition styles can also be placed on the CSS base class above
27576
27828
  &#42;/
27577
27829
  .animate-if.ng-enter, .animate-if.ng-leave {
27578
27830
  -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
@@ -27598,22 +27850,21 @@ var ngIfDirective = ['$animate', function($animate) {
27598
27850
  terminal: true,
27599
27851
  restrict: 'A',
27600
27852
  $$tlb: true,
27601
- compile: function (element, attr, transclude) {
27602
- return function ($scope, $element, $attr) {
27853
+ link: function ($scope, $element, $attr, ctrl, $transclude) {
27603
27854
  var block, childScope;
27604
27855
  $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
27605
27856
 
27606
27857
  if (toBoolean(value)) {
27607
-
27608
- childScope = $scope.$new();
27609
- transclude(childScope, function (clone) {
27610
- block = {
27611
- startNode: clone[0],
27612
- endNode: clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ')
27613
- };
27614
- $animate.enter(clone, $element.parent(), $element);
27615
- });
27616
-
27858
+ if (!childScope) {
27859
+ childScope = $scope.$new();
27860
+ $transclude(childScope, function (clone) {
27861
+ block = {
27862
+ startNode: clone[0],
27863
+ endNode: clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ')
27864
+ };
27865
+ $animate.enter(clone, $element.parent(), $element);
27866
+ });
27867
+ }
27617
27868
  } else {
27618
27869
 
27619
27870
  if (childScope) {
@@ -27627,7 +27878,6 @@ var ngIfDirective = ['$animate', function($animate) {
27627
27878
  }
27628
27879
  }
27629
27880
  });
27630
- };
27631
27881
  }
27632
27882
  };
27633
27883
  }];
@@ -27786,12 +28036,12 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
27786
28036
  priority: 400,
27787
28037
  terminal: true,
27788
28038
  transclude: 'element',
27789
- compile: function(element, attr, transclusion) {
28039
+ compile: function(element, attr) {
27790
28040
  var srcExp = attr.ngInclude || attr.src,
27791
28041
  onloadExp = attr.onload || '',
27792
28042
  autoScrollExp = attr.autoscroll;
27793
28043
 
27794
- return function(scope, $element) {
28044
+ return function(scope, $element, $attr, ctrl, $transclude) {
27795
28045
  var changeCounter = 0,
27796
28046
  currentScope,
27797
28047
  currentElement;
@@ -27820,18 +28070,23 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
27820
28070
  if (thisChangeId !== changeCounter) return;
27821
28071
  var newScope = scope.$new();
27822
28072
 
27823
- transclusion(newScope, function(clone) {
27824
- cleanupLastIncludeContent();
27825
-
27826
- currentScope = newScope;
27827
- currentElement = clone;
27828
-
27829
- currentElement.html(response);
27830
- $animate.enter(currentElement, null, $element, afterAnimation);
27831
- $compile(currentElement.contents())(currentScope);
27832
- currentScope.$emit('$includeContentLoaded');
27833
- scope.$eval(onloadExp);
27834
- });
28073
+ // Note: This will also link all children of ng-include that were contained in the original
28074
+ // html. If that content contains controllers, ... they could pollute/change the scope.
28075
+ // However, using ng-include on an element with additional content does not make sense...
28076
+ // Note: We can't remove them in the cloneAttchFn of $transclude as that
28077
+ // function is called before linking the content, which would apply child
28078
+ // directives to non existing elements.
28079
+ var clone = $transclude(newScope, noop);
28080
+ cleanupLastIncludeContent();
28081
+
28082
+ currentScope = newScope;
28083
+ currentElement = clone;
28084
+
28085
+ currentElement.html(response);
28086
+ $animate.enter(currentElement, null, $element, afterAnimation);
28087
+ $compile(currentElement.contents())(currentScope);
28088
+ currentScope.$emit('$includeContentLoaded');
28089
+ scope.$eval(onloadExp);
27835
28090
  }).error(function() {
27836
28091
  if (thisChangeId === changeCounter) cleanupLastIncludeContent();
27837
28092
  });
@@ -27986,7 +28241,7 @@ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
27986
28241
  * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
27987
28242
  * show "a dozen people are viewing".
27988
28243
  *
27989
- * You can use a set of closed braces(`{}`) as a placeholder for the number that you want substituted
28244
+ * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
27990
28245
  * into pluralized strings. In the previous example, Angular will replace `{}` with
27991
28246
  * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
27992
28247
  * for <span ng-non-bindable>{{numberExpression}}</span>.
@@ -28247,7 +28502,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
28247
28502
  * For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
28248
28503
  * `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
28249
28504
  * with the corresponding item in the array by identity. Moving the same object in array would move the DOM
28250
- * element in the same way ian the DOM.
28505
+ * element in the same way in the DOM.
28251
28506
  *
28252
28507
  * For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
28253
28508
  * case the object identity does not matter. Two objects are considered equivalent as long as their `id`
@@ -28349,8 +28604,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
28349
28604
  priority: 1000,
28350
28605
  terminal: true,
28351
28606
  $$tlb: true,
28352
- compile: function(element, attr, linker) {
28353
- return function($scope, $element, $attr){
28607
+ link: function($scope, $element, $attr, ctrl, $transclude){
28354
28608
  var expression = $attr.ngRepeat;
28355
28609
  var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),
28356
28610
  trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
@@ -28512,7 +28766,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
28512
28766
  // jshint bitwise: true
28513
28767
 
28514
28768
  if (!block.startNode) {
28515
- linker(childScope, function(clone) {
28769
+ $transclude(childScope, function(clone) {
28516
28770
  clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
28517
28771
  $animate.enter(clone, null, jqLite(previousNode));
28518
28772
  previousNode = clone;
@@ -28525,7 +28779,6 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
28525
28779
  }
28526
28780
  lastBlockMap = nextBlockMap;
28527
28781
  });
28528
- };
28529
28782
  }
28530
28783
  };
28531
28784
  }];
@@ -29034,10 +29287,10 @@ var ngSwitchWhenDirective = ngDirective({
29034
29287
  transclude: 'element',
29035
29288
  priority: 800,
29036
29289
  require: '^ngSwitch',
29037
- compile: function(element, attrs, transclude) {
29038
- return function(scope, element, attr, ctrl) {
29290
+ compile: function(element, attrs) {
29291
+ return function(scope, element, attr, ctrl, $transclude) {
29039
29292
  ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
29040
- ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: transclude, element: element });
29293
+ ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
29041
29294
  };
29042
29295
  }
29043
29296
  });
@@ -29046,12 +29299,10 @@ var ngSwitchDefaultDirective = ngDirective({
29046
29299
  transclude: 'element',
29047
29300
  priority: 800,
29048
29301
  require: '^ngSwitch',
29049
- compile: function(element, attrs, transclude) {
29050
- return function(scope, element, attr, ctrl) {
29051
- ctrl.cases['?'] = (ctrl.cases['?'] || []);
29052
- ctrl.cases['?'].push({ transclude: transclude, element: element });
29053
- };
29054
- }
29302
+ link: function(scope, element, attr, ctrl, $transclude) {
29303
+ ctrl.cases['?'] = (ctrl.cases['?'] || []);
29304
+ ctrl.cases['?'].push({ transclude: $transclude, element: element });
29305
+ }
29055
29306
  });
29056
29307
 
29057
29308
  /**
@@ -32032,5 +32283,5 @@ if (config.autotest) {
32032
32283
  })(window, document);
32033
32284
 
32034
32285
 
32035
- !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/* The styles below ensure that the CSS transition will ALWAYS\n * animate and close. A nasty bug occurs with CSS transitions where\n * when the active class isn\'t set, or if the active class doesn\'t\n * contain any styles to transition to, then, if ngAnimate is used,\n * it will appear as if the webpage is broken due to the forever hanging\n * animations. The clip (!ie) and zoom (ie) CSS properties are used\n * since they trigger a transition without making the browser\n * animate anything and they\'re both highly underused CSS properties */\n.ng-animate-start { clip:rect(0, auto, auto, 0); -ms-zoom:1.0001; }\n.ng-animate-active { clip:rect(-1px, auto, auto, 0); -ms-zoom:1; }\n</style>');
32286
+ !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/* The styles below ensure that the CSS transition will ALWAYS\n * animate and close. A nasty bug occurs with CSS transitions where\n * when the active class isn\'t set, or if the active class doesn\'t\n * contain any styles to transition to, then, if ngAnimate is used,\n * it will appear as if the webpage is broken due to the forever hanging\n * animations. The border-spacing (!ie) and zoom (ie) CSS properties are\n * used below since they trigger a transition without making the browser\n * animate anything and they\'re both highly underused CSS properties */\n.ng-animate-start { border-spacing:1px 1px; -ms-zoom:1.0001; }\n.ng-animate-active { border-spacing:0px 0px; -ms-zoom:1; }\n</style>');
32036
32287
  !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>');