angular-rails-engine 1.2.0.2 → 1.2.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @license AngularJS v1.2.0
3
- * (c) 2010-2012 Google, Inc. http://angularjs.org
2
+ * @license AngularJS v1.2.3
3
+ * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
6
6
  (function(window, angular, undefined) {'use strict';
@@ -1,6 +1,6 @@
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
6
  (function(y,v,z){'use strict';function t(g,a,b){q.directive(g,["$parse","$swipe",function(l,n){var r=75,h=0.3,d=30;return function(p,m,k){function e(e){if(!u)return!1;var c=Math.abs(e.y-u.y);e=(e.x-u.x)*a;return f&&c<r&&0<e&&e>d&&c/e<h}var c=l(k[g]),u,f;n.bind(m,{start:function(e,c){u=e;f=!0},cancel:function(e){f=!1},end:function(a,f){e(a)&&p.$apply(function(){m.triggerHandler(b);c(p,{$event:f})})}})}}])}var q=v.module("ngTouch",[]);q.factory("$swipe",[function(){function g(a){var b=a.touches&&a.touches.length?
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @license AngularJS v1.2.0
3
- * (c) 2010-2012 Google, Inc. http://angularjs.org
2
+ * @license AngularJS v1.2.3
3
+ * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
6
6
  (function(window, document, undefined) {'use strict';
@@ -40,11 +40,11 @@ function minErr(module) {
40
40
  template = arguments[1],
41
41
  templateArgs = arguments,
42
42
  stringify = function (obj) {
43
- if (isFunction(obj)) {
43
+ if (typeof obj === 'function') {
44
44
  return obj.toString().replace(/ \{[\s\S]*$/, '');
45
- } else if (isUndefined(obj)) {
45
+ } else if (typeof obj === 'undefined') {
46
46
  return 'undefined';
47
- } else if (!isString(obj)) {
47
+ } else if (typeof obj !== 'string') {
48
48
  return JSON.stringify(obj);
49
49
  }
50
50
  return obj;
@@ -56,11 +56,11 @@ function minErr(module) {
56
56
 
57
57
  if (index + 2 < templateArgs.length) {
58
58
  arg = templateArgs[index + 2];
59
- if (isFunction(arg)) {
59
+ if (typeof arg === 'function') {
60
60
  return arg.toString().replace(/ ?\{[\s\S]*$/, '');
61
- } else if (isUndefined(arg)) {
61
+ } else if (typeof arg === 'undefined') {
62
62
  return 'undefined';
63
- } else if (!isString(arg)) {
63
+ } else if (typeof arg !== 'string') {
64
64
  return toJson(arg);
65
65
  }
66
66
  return arg;
@@ -68,7 +68,7 @@ function minErr(module) {
68
68
  return match;
69
69
  });
70
70
 
71
- message = message + '\nhttp://errors.angularjs.org/' + version.full + '/' +
71
+ message = message + '\nhttp://errors.angularjs.org/1.2.3/' +
72
72
  (module ? module + '/' : '') + code;
73
73
  for (i = 2; i < arguments.length; i++) {
74
74
  message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
@@ -159,7 +159,7 @@ function minErr(module) {
159
159
  -assertArgFn,
160
160
  -assertNotHasOwnProperty,
161
161
  -getter,
162
- -getBlockElements
162
+ -getBlockElements,
163
163
 
164
164
  */
165
165
 
@@ -623,7 +623,7 @@ var trim = (function() {
623
623
  // TODO: we should move this into IE/ES5 polyfill
624
624
  if (!String.prototype.trim) {
625
625
  return function(value) {
626
- return isString(value) ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value;
626
+ return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
627
627
  };
628
628
  }
629
629
  return function(value) {
@@ -1181,26 +1181,38 @@ function encodeUriQuery(val, pctEncodeSpaces) {
1181
1181
  *
1182
1182
  * @description
1183
1183
  *
1184
- * Use this directive to auto-bootstrap an application. Only
1185
- * one ngApp directive can be used per HTML document. The directive
1186
- * designates the root of the application and is typically placed
1187
- * at the root of the page.
1188
- *
1189
- * The first ngApp found in the document will be auto-bootstrapped. To use multiple applications in
1190
- * an HTML document you must manually bootstrap them using {@link angular.bootstrap}.
1191
- * Applications cannot be nested.
1192
- *
1193
- * In the example below if the `ngApp` directive were not placed
1194
- * on the `html` element then the document would not be compiled
1195
- * and the `{{ 1+2 }}` would not be resolved to `3`.
1196
- *
1197
- * `ngApp` is the easiest way to bootstrap an application.
1198
- *
1199
- <doc:example>
1200
- <doc:source>
1201
- I can add: 1 + 2 = {{ 1+2 }}
1202
- </doc:source>
1203
- </doc:example>
1184
+ * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
1185
+ * designates the **root element** of the application and is typically placed near the root element
1186
+ * of the page - e.g. on the `<body>` or `<html>` tags.
1187
+ *
1188
+ * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
1189
+ * found in the document will be used to define the root element to auto-bootstrap as an
1190
+ * application. To run multiple applications in an HTML document you must manually bootstrap them using
1191
+ * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
1192
+ *
1193
+ * You can specify an **AngularJS module** to be used as the root module for the application. This
1194
+ * module will be loaded into the {@link AUTO.$injector} when the application is bootstrapped and
1195
+ * should contain the application code needed or have dependencies on other modules that will
1196
+ * contain the code. See {@link angular.module} for more information.
1197
+ *
1198
+ * In the example below if the `ngApp` directive were not placed on the `html` element then the
1199
+ * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
1200
+ * would not be resolved to `3`.
1201
+ *
1202
+ * `ngApp` is the easiest, and most common, way to bootstrap an application.
1203
+ *
1204
+ <example module="ngAppDemo">
1205
+ <file name="index.html">
1206
+ <div ng-controller="ngAppDemoController">
1207
+ I can add: {{a}} + {{b}} = {{ a+b }}
1208
+ </file>
1209
+ <file name="script.js">
1210
+ angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
1211
+ $scope.a = 1;
1212
+ $scope.b = 2;
1213
+ });
1214
+ </file>
1215
+ </example>
1204
1216
  *
1205
1217
  */
1206
1218
  function angularInit(element, bootstrap) {
@@ -1429,12 +1441,18 @@ function getBlockElements(block) {
1429
1441
  function setupModuleLoader(window) {
1430
1442
 
1431
1443
  var $injectorMinErr = minErr('$injector');
1444
+ var ngMinErr = minErr('ng');
1432
1445
 
1433
1446
  function ensure(obj, name, factory) {
1434
1447
  return obj[name] || (obj[name] = factory());
1435
1448
  }
1436
1449
 
1437
- return ensure(ensure(window, 'angular', Object), 'module', function() {
1450
+ var angular = ensure(window, 'angular', Object);
1451
+
1452
+ // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
1453
+ angular.$$minErr = angular.$$minErr || minErr;
1454
+
1455
+ return ensure(angular, 'module', function() {
1438
1456
  /** @type {Object.<string, angular.Module>} */
1439
1457
  var modules = {};
1440
1458
 
@@ -1489,6 +1507,12 @@ function setupModuleLoader(window) {
1489
1507
  * @returns {module} new module with the {@link angular.Module} api.
1490
1508
  */
1491
1509
  return function module(name, requires, configFn) {
1510
+ var assertNotHasOwnProperty = function(name, context) {
1511
+ if (name === 'hasOwnProperty') {
1512
+ throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
1513
+ }
1514
+ };
1515
+
1492
1516
  assertNotHasOwnProperty(name, 'module');
1493
1517
  if (requires && modules.hasOwnProperty(name)) {
1494
1518
  modules[name] = null;
@@ -1778,6 +1802,7 @@ function setupModuleLoader(window) {
1778
1802
  $ParseProvider,
1779
1803
  $RootScopeProvider,
1780
1804
  $QProvider,
1805
+ $$SanitizeUriProvider,
1781
1806
  $SceProvider,
1782
1807
  $SceDelegateProvider,
1783
1808
  $SnifferProvider,
@@ -1801,11 +1826,11 @@ function setupModuleLoader(window) {
1801
1826
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
1802
1827
  */
1803
1828
  var version = {
1804
- full: '1.2.0', // all of these placeholder strings will be replaced by grunt's
1829
+ full: '1.2.3', // all of these placeholder strings will be replaced by grunt's
1805
1830
  major: 1, // package task
1806
- minor: "NG_VERSION_MINOR",
1807
- dot: 0,
1808
- codeName: 'timely-delivery'
1831
+ minor: 2,
1832
+ dot: 3,
1833
+ codeName: 'unicorn-zapper'
1809
1834
  };
1810
1835
 
1811
1836
 
@@ -1849,6 +1874,10 @@ function publishExternalAPI(angular){
1849
1874
 
1850
1875
  angularModule('ng', ['ngLocale'], ['$provide',
1851
1876
  function ngModule($provide) {
1877
+ // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
1878
+ $provide.provider({
1879
+ $$sanitizeUri: $$SanitizeUriProvider
1880
+ });
1852
1881
  $provide.provider('$compile', $CompileProvider).
1853
1882
  directive({
1854
1883
  a: htmlAnchorDirective,
@@ -3352,11 +3381,11 @@ function annotate(fn) {
3352
3381
  * @example
3353
3382
  * Here are some examples of creating value services.
3354
3383
  * <pre>
3355
- * $provide.constant('ADMIN_USER', 'admin');
3384
+ * $provide.value('ADMIN_USER', 'admin');
3356
3385
  *
3357
- * $provide.constant('RoleLookup', { admin: 0, writer: 1, reader: 2 });
3386
+ * $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
3358
3387
  *
3359
- * $provide.constant('halfOf', function(value) {
3388
+ * $provide.value('halfOf', function(value) {
3360
3389
  * return value / 2;
3361
3390
  * });
3362
3391
  * </pre>
@@ -3842,13 +3871,14 @@ var $AnimateProvider = ['$provide', function($provide) {
3842
3871
  * inserted into the DOM
3843
3872
  */
3844
3873
  enter : function(element, parent, after, done) {
3845
- var afterNode = after && after[after.length - 1];
3846
- var parentNode = parent && parent[0] || afterNode && afterNode.parentNode;
3847
- // IE does not like undefined so we have to pass null.
3848
- var afterNextSibling = (afterNode && afterNode.nextSibling) || null;
3849
- forEach(element, function(node) {
3850
- parentNode.insertBefore(node, afterNextSibling);
3851
- });
3874
+ if (after) {
3875
+ after.after(element);
3876
+ } else {
3877
+ if (!parent || !parent[0]) {
3878
+ parent = after.parent();
3879
+ }
3880
+ parent.append(element);
3881
+ }
3852
3882
  done && $timeout(done, 0, false);
3853
3883
  },
3854
3884
 
@@ -4696,8 +4726,9 @@ function $TemplateCacheProvider() {
4696
4726
  * When there are multiple directives defined on a single DOM element, sometimes it
4697
4727
  * is necessary to specify the order in which the directives are applied. The `priority` is used
4698
4728
  * to sort the directives before their `compile` functions get called. Priority is defined as a
4699
- * number. Directives with greater numerical `priority` are compiled first. The order of directives with
4700
- * the same priority is undefined. The default priority is `0`.
4729
+ * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
4730
+ * are also run in priority order, but post-link functions are run in reverse order. The order
4731
+ * of directives with the same priority is undefined. The default priority is `0`.
4701
4732
  *
4702
4733
  * #### `terminal`
4703
4734
  * If set to true then the current `priority` will be the last set of directives
@@ -4758,8 +4789,9 @@ function $TemplateCacheProvider() {
4758
4789
  * * `$scope` - Current scope associated with the element
4759
4790
  * * `$element` - Current element
4760
4791
  * * `$attrs` - Current attributes object for the element
4761
- * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
4762
- * `function(cloneLinkingFn)`.
4792
+ * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope.
4793
+ * The scope can be overridden by an optional first argument.
4794
+ * `function([scope], cloneLinkingFn)`.
4763
4795
  *
4764
4796
  *
4765
4797
  * #### `require`
@@ -4852,7 +4884,7 @@ function $TemplateCacheProvider() {
4852
4884
  * * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
4853
4885
  * between all directive compile functions.
4854
4886
  *
4855
- * * `transclude` - A transclude linking function: `function(scope, cloneLinkingFn)`.
4887
+ * * `transclude` - [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
4856
4888
  *
4857
4889
  * <div class="alert alert-warning">
4858
4890
  * **Note:** The template instance and the link instance may be different objects if the template has
@@ -4861,6 +4893,12 @@ function $TemplateCacheProvider() {
4861
4893
  * should be done in a linking function rather than in a compile function.
4862
4894
  * </div>
4863
4895
  *
4896
+ * <div class="alert alert-error">
4897
+ * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
4898
+ * e.g. does not know about the right outer scope. Please use the transclude function that is passed
4899
+ * to the link function instead.
4900
+ * </div>
4901
+
4864
4902
  * A compile function can have a return value which can be either a function or an object.
4865
4903
  *
4866
4904
  * * returning a (post-link) function - is equivalent to registering the linking function via the
@@ -4875,7 +4913,7 @@ function $TemplateCacheProvider() {
4875
4913
  * This property is used only if the `compile` property is not defined.
4876
4914
  *
4877
4915
  * <pre>
4878
- * function link(scope, iElement, iAttrs, controller) { ... }
4916
+ * function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
4879
4917
  * </pre>
4880
4918
  *
4881
4919
  * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
@@ -4896,6 +4934,10 @@ function $TemplateCacheProvider() {
4896
4934
  * element defines a controller. The controller is shared among all the directives, which allows
4897
4935
  * the directives to use the controllers as a communication channel.
4898
4936
  *
4937
+ * * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
4938
+ * The scope can be overridden by an optional first argument. This is the same as the `$transclude`
4939
+ * parameter of directive controllers.
4940
+ * `function([scope], cloneLinkingFn)`.
4899
4941
  *
4900
4942
  *
4901
4943
  * #### Pre-linking function
@@ -5062,14 +5104,12 @@ var $compileMinErr = minErr('$compile');
5062
5104
  *
5063
5105
  * @description
5064
5106
  */
5065
- $CompileProvider.$inject = ['$provide'];
5066
- function $CompileProvider($provide) {
5107
+ $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
5108
+ function $CompileProvider($provide, $$sanitizeUriProvider) {
5067
5109
  var hasDirectives = {},
5068
5110
  Suffix = 'Directive',
5069
5111
  COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
5070
- CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
5071
- aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
5072
- imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//;
5112
+ CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/;
5073
5113
 
5074
5114
  // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
5075
5115
  // The assumption is that future DOM event attribute names will begin with
@@ -5153,10 +5193,11 @@ function $CompileProvider($provide) {
5153
5193
  */
5154
5194
  this.aHrefSanitizationWhitelist = function(regexp) {
5155
5195
  if (isDefined(regexp)) {
5156
- aHrefSanitizationWhitelist = regexp;
5196
+ $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
5157
5197
  return this;
5198
+ } else {
5199
+ return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
5158
5200
  }
5159
- return aHrefSanitizationWhitelist;
5160
5201
  };
5161
5202
 
5162
5203
 
@@ -5183,18 +5224,18 @@ function $CompileProvider($provide) {
5183
5224
  */
5184
5225
  this.imgSrcSanitizationWhitelist = function(regexp) {
5185
5226
  if (isDefined(regexp)) {
5186
- imgSrcSanitizationWhitelist = regexp;
5227
+ $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
5187
5228
  return this;
5229
+ } else {
5230
+ return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
5188
5231
  }
5189
- return imgSrcSanitizationWhitelist;
5190
5232
  };
5191
5233
 
5192
-
5193
5234
  this.$get = [
5194
5235
  '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
5195
- '$controller', '$rootScope', '$document', '$sce', '$animate',
5236
+ '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
5196
5237
  function($injector, $interpolate, $exceptionHandler, $http, $templateCache, $parse,
5197
- $controller, $rootScope, $document, $sce, $animate) {
5238
+ $controller, $rootScope, $document, $sce, $animate, $$sanitizeUri) {
5198
5239
 
5199
5240
  var Attributes = function(element, attr) {
5200
5241
  this.$$element = element;
@@ -5241,6 +5282,24 @@ function $CompileProvider($provide) {
5241
5282
  }
5242
5283
  },
5243
5284
 
5285
+ /**
5286
+ * @ngdoc function
5287
+ * @name ng.$compile.directive.Attributes#$updateClass
5288
+ * @methodOf ng.$compile.directive.Attributes
5289
+ * @function
5290
+ *
5291
+ * @description
5292
+ * Adds and removes the appropriate CSS class values to the element based on the difference
5293
+ * between the new and old CSS class values (specified as newClasses and oldClasses).
5294
+ *
5295
+ * @param {string} newClasses The current CSS className value
5296
+ * @param {string} oldClasses The former CSS className value
5297
+ */
5298
+ $updateClass : function(newClasses, oldClasses) {
5299
+ this.$removeClass(tokenDifference(oldClasses, newClasses));
5300
+ this.$addClass(tokenDifference(newClasses, oldClasses));
5301
+ },
5302
+
5244
5303
  /**
5245
5304
  * Set a normalized attribute on the element in a way such that all directives
5246
5305
  * can share the attribute. This function properly handles boolean attributes.
@@ -5251,59 +5310,44 @@ function $CompileProvider($provide) {
5251
5310
  * @param {string=} attrName Optional none normalized name. Defaults to key.
5252
5311
  */
5253
5312
  $set: function(key, value, writeAttr, attrName) {
5254
- //special case for class attribute addition + removal
5255
- //so that class changes can tap into the animation
5256
- //hooks provided by the $animate service
5257
- if(key == 'class') {
5258
- value = value || '';
5259
- var current = this.$$element.attr('class') || '';
5260
- this.$removeClass(tokenDifference(current, value).join(' '));
5261
- this.$addClass(tokenDifference(value, current).join(' '));
5262
- } else {
5263
- var booleanKey = getBooleanAttrName(this.$$element[0], key),
5264
- normalizedVal,
5265
- nodeName;
5313
+ // TODO: decide whether or not to throw an error if "class"
5314
+ //is set through this function since it may cause $updateClass to
5315
+ //become unstable.
5266
5316
 
5267
- if (booleanKey) {
5268
- this.$$element.prop(key, value);
5269
- attrName = booleanKey;
5270
- }
5317
+ var booleanKey = getBooleanAttrName(this.$$element[0], key),
5318
+ normalizedVal,
5319
+ nodeName;
5271
5320
 
5272
- this[key] = value;
5321
+ if (booleanKey) {
5322
+ this.$$element.prop(key, value);
5323
+ attrName = booleanKey;
5324
+ }
5273
5325
 
5274
- // translate normalized key to actual key
5275
- if (attrName) {
5276
- this.$attr[key] = attrName;
5277
- } else {
5278
- attrName = this.$attr[key];
5279
- if (!attrName) {
5280
- this.$attr[key] = attrName = snake_case(key, '-');
5281
- }
5282
- }
5326
+ this[key] = value;
5283
5327
 
5284
- nodeName = nodeName_(this.$$element);
5285
-
5286
- // sanitize a[href] and img[src] values
5287
- if ((nodeName === 'A' && key === 'href') ||
5288
- (nodeName === 'IMG' && key === 'src')) {
5289
- // NOTE: urlResolve() doesn't support IE < 8 so we don't sanitize for that case.
5290
- if (!msie || msie >= 8 ) {
5291
- normalizedVal = urlResolve(value).href;
5292
- if (normalizedVal !== '') {
5293
- if ((key === 'href' && !normalizedVal.match(aHrefSanitizationWhitelist)) ||
5294
- (key === 'src' && !normalizedVal.match(imgSrcSanitizationWhitelist))) {
5295
- this[key] = value = 'unsafe:' + normalizedVal;
5296
- }
5297
- }
5298
- }
5328
+ // translate normalized key to actual key
5329
+ if (attrName) {
5330
+ this.$attr[key] = attrName;
5331
+ } else {
5332
+ attrName = this.$attr[key];
5333
+ if (!attrName) {
5334
+ this.$attr[key] = attrName = snake_case(key, '-');
5299
5335
  }
5336
+ }
5300
5337
 
5301
- if (writeAttr !== false) {
5302
- if (value === null || value === undefined) {
5303
- this.$$element.removeAttr(attrName);
5304
- } else {
5305
- this.$$element.attr(attrName, value);
5306
- }
5338
+ nodeName = nodeName_(this.$$element);
5339
+
5340
+ // sanitize a[href] and img[src] values
5341
+ if ((nodeName === 'A' && key === 'href') ||
5342
+ (nodeName === 'IMG' && key === 'src')) {
5343
+ this[key] = value = $$sanitizeUri(value, key === 'src');
5344
+ }
5345
+
5346
+ if (writeAttr !== false) {
5347
+ if (value === null || value === undefined) {
5348
+ this.$$element.removeAttr(attrName);
5349
+ } else {
5350
+ this.$$element.attr(attrName, value);
5307
5351
  }
5308
5352
  }
5309
5353
 
@@ -5316,22 +5360,6 @@ function $CompileProvider($provide) {
5316
5360
  $exceptionHandler(e);
5317
5361
  }
5318
5362
  });
5319
-
5320
- function tokenDifference(str1, str2) {
5321
- var values = [],
5322
- tokens1 = str1.split(/\s+/),
5323
- tokens2 = str2.split(/\s+/);
5324
-
5325
- outer:
5326
- for(var i=0;i<tokens1.length;i++) {
5327
- var token = tokens1[i];
5328
- for(var j=0;j<tokens2.length;j++) {
5329
- if(token == tokens2[j]) continue outer;
5330
- }
5331
- values.push(token);
5332
- }
5333
- return values;
5334
- }
5335
5363
  },
5336
5364
 
5337
5365
 
@@ -5401,7 +5429,7 @@ function $CompileProvider($provide) {
5401
5429
  var compositeLinkFn =
5402
5430
  compileNodes($compileNodes, transcludeFn, $compileNodes,
5403
5431
  maxPriority, ignoreDirective, previousCompileContext);
5404
- return function publicLinkFn(scope, cloneConnectFn){
5432
+ return function publicLinkFn(scope, cloneConnectFn, transcludeControllers){
5405
5433
  assertArg(scope, 'scope');
5406
5434
  // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
5407
5435
  // and sometimes changes the structure of the DOM.
@@ -5409,6 +5437,10 @@ function $CompileProvider($provide) {
5409
5437
  ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
5410
5438
  : $compileNodes;
5411
5439
 
5440
+ forEach(transcludeControllers, function(instance, name) {
5441
+ $linkNode.data('$' + name + 'Controller', instance);
5442
+ });
5443
+
5412
5444
  // Attach scope only to non-text nodes.
5413
5445
  for(var i = 0, ii = $linkNode.length; i<ii; i++) {
5414
5446
  var node = $linkNode[i];
@@ -5507,15 +5539,7 @@ function $CompileProvider($provide) {
5507
5539
  childTranscludeFn = nodeLinkFn.transclude;
5508
5540
  if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
5509
5541
  nodeLinkFn(childLinkFn, childScope, node, $rootElement,
5510
- (function(transcludeFn) {
5511
- return function(cloneFn) {
5512
- var transcludeScope = scope.$new();
5513
- transcludeScope.$$transcluded = true;
5514
-
5515
- return transcludeFn(transcludeScope, cloneFn).
5516
- on('$destroy', bind(transcludeScope, transcludeScope.$destroy));
5517
- };
5518
- })(childTranscludeFn || transcludeFn)
5542
+ createBoundTranscludeFn(scope, childTranscludeFn || transcludeFn)
5519
5543
  );
5520
5544
  } else {
5521
5545
  nodeLinkFn(childLinkFn, childScope, node, undefined, boundTranscludeFn);
@@ -5527,6 +5551,23 @@ function $CompileProvider($provide) {
5527
5551
  }
5528
5552
  }
5529
5553
 
5554
+ function createBoundTranscludeFn(scope, transcludeFn) {
5555
+ return function boundTranscludeFn(transcludedScope, cloneFn, controllers) {
5556
+ var scopeCreated = false;
5557
+
5558
+ if (!transcludedScope) {
5559
+ transcludedScope = scope.$new();
5560
+ transcludedScope.$$transcluded = true;
5561
+ scopeCreated = true;
5562
+ }
5563
+
5564
+ var clone = transcludeFn(transcludedScope, cloneFn, controllers);
5565
+ if (scopeCreated) {
5566
+ clone.on('$destroy', bind(transcludedScope, transcludedScope.$destroy));
5567
+ }
5568
+ return clone;
5569
+ };
5570
+ }
5530
5571
 
5531
5572
  /**
5532
5573
  * Looks for directives on the given node and adds them to the directive collection which is
@@ -5664,9 +5705,9 @@ function $CompileProvider($provide) {
5664
5705
  * @returns {Function}
5665
5706
  */
5666
5707
  function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
5667
- return function(scope, element, attrs, controllers) {
5708
+ return function(scope, element, attrs, controllers, transcludeFn) {
5668
5709
  element = groupScan(element[0], attrStart, attrEnd);
5669
- return linkFn(scope, element, attrs, controllers);
5710
+ return linkFn(scope, element, attrs, controllers, transcludeFn);
5670
5711
  };
5671
5712
  }
5672
5713
 
@@ -5703,7 +5744,9 @@ function $CompileProvider($provide) {
5703
5744
  controllerDirectives = previousCompileContext.controllerDirectives,
5704
5745
  newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
5705
5746
  templateDirective = previousCompileContext.templateDirective,
5706
- transcludeDirective = previousCompileContext.transcludeDirective,
5747
+ nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
5748
+ hasTranscludeDirective = false,
5749
+ hasElementTranscludeDirective = false,
5707
5750
  $compileNode = templateAttrs.$$element = jqLite(compileNode),
5708
5751
  directive,
5709
5752
  directiveName,
@@ -5754,15 +5797,18 @@ function $CompileProvider($provide) {
5754
5797
  }
5755
5798
 
5756
5799
  if (directiveValue = directive.transclude) {
5800
+ hasTranscludeDirective = true;
5801
+
5757
5802
  // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
5758
5803
  // This option should only be used by directives that know how to how to safely handle element transclusion,
5759
5804
  // where the transcluded nodes are added or replaced after linking.
5760
5805
  if (!directive.$$tlb) {
5761
- assertNoDuplicate('transclusion', transcludeDirective, directive, $compileNode);
5762
- transcludeDirective = directive;
5806
+ assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
5807
+ nonTlbTranscludeDirective = directive;
5763
5808
  }
5764
5809
 
5765
5810
  if (directiveValue == 'element') {
5811
+ hasElementTranscludeDirective = true;
5766
5812
  terminalPriority = directive.priority;
5767
5813
  $template = groupScan(compileNode, attrStart, attrEnd);
5768
5814
  $compileNode = templateAttrs.$$element =
@@ -5778,9 +5824,9 @@ function $CompileProvider($provide) {
5778
5824
  // - newIsolateScopeDirective or templateDirective - combining templates with
5779
5825
  // element transclusion doesn't make sense.
5780
5826
  //
5781
- // We need only transcludeDirective so that we prevent putting transclusion
5827
+ // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
5782
5828
  // on the same element more than once.
5783
- transcludeDirective: transcludeDirective
5829
+ nonTlbTranscludeDirective: nonTlbTranscludeDirective
5784
5830
  });
5785
5831
  } else {
5786
5832
  $template = jqLite(jqLiteClone(compileNode)).contents();
@@ -5849,7 +5895,7 @@ function $CompileProvider($provide) {
5849
5895
  controllerDirectives: controllerDirectives,
5850
5896
  newIsolateScopeDirective: newIsolateScopeDirective,
5851
5897
  templateDirective: templateDirective,
5852
- transcludeDirective: transcludeDirective
5898
+ nonTlbTranscludeDirective: nonTlbTranscludeDirective
5853
5899
  });
5854
5900
  ii = directives.length;
5855
5901
  } else if (directive.compile) {
@@ -5873,7 +5919,7 @@ function $CompileProvider($provide) {
5873
5919
  }
5874
5920
 
5875
5921
  nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
5876
- nodeLinkFn.transclude = transcludeDirective && childTranscludeFn;
5922
+ nodeLinkFn.transclude = hasTranscludeDirective && childTranscludeFn;
5877
5923
 
5878
5924
  // might be normal or delayed nodeLinkFn depending on if templateUrl is present
5879
5925
  return nodeLinkFn;
@@ -5900,7 +5946,7 @@ function $CompileProvider($provide) {
5900
5946
  }
5901
5947
 
5902
5948
 
5903
- function getControllers(require, $element) {
5949
+ function getControllers(require, $element, elementControllers) {
5904
5950
  var value, retrievalMethod = 'data', optional = false;
5905
5951
  if (isString(require)) {
5906
5952
  while((value = require.charAt(0)) == '^' || value == '?') {
@@ -5910,13 +5956,12 @@ function $CompileProvider($provide) {
5910
5956
  }
5911
5957
  optional = optional || value == '?';
5912
5958
  }
5959
+ value = null;
5913
5960
 
5914
- value = $element[retrievalMethod]('$' + require + 'Controller');
5915
-
5916
- if ($element[0].nodeType == 8 && $element[0].$$controller) { // Transclusion comment node
5917
- value = value || $element[0].$$controller;
5918
- $element[0].$$controller = null;
5961
+ if (elementControllers && retrievalMethod === 'data') {
5962
+ value = elementControllers[require];
5919
5963
  }
5964
+ value = value || $element[retrievalMethod]('$' + require + 'Controller');
5920
5965
 
5921
5966
  if (!value && !optional) {
5922
5967
  throw $compileMinErr('ctreq',
@@ -5927,7 +5972,7 @@ function $CompileProvider($provide) {
5927
5972
  } else if (isArray(require)) {
5928
5973
  value = [];
5929
5974
  forEach(require, function(require) {
5930
- value.push(getControllers(require, $element));
5975
+ value.push(getControllers(require, $element, elementControllers));
5931
5976
  });
5932
5977
  }
5933
5978
  return value;
@@ -5935,7 +5980,7 @@ function $CompileProvider($provide) {
5935
5980
 
5936
5981
 
5937
5982
  function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
5938
- var attrs, $element, i, ii, linkFn, controller, isolateScope;
5983
+ var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn;
5939
5984
 
5940
5985
  if (compileNode === linkNode) {
5941
5986
  attrs = templateAttrs;
@@ -6029,14 +6074,14 @@ function $CompileProvider($provide) {
6029
6074
  }
6030
6075
  });
6031
6076
  }
6032
-
6077
+ transcludeFn = boundTranscludeFn && controllersBoundTransclude;
6033
6078
  if (controllerDirectives) {
6034
6079
  forEach(controllerDirectives, function(directive) {
6035
6080
  var locals = {
6036
6081
  $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
6037
6082
  $element: $element,
6038
6083
  $attrs: attrs,
6039
- $transclude: boundTranscludeFn
6084
+ $transclude: transcludeFn
6040
6085
  }, controllerInstance;
6041
6086
 
6042
6087
  controller = directive.controller;
@@ -6045,16 +6090,16 @@ function $CompileProvider($provide) {
6045
6090
  }
6046
6091
 
6047
6092
  controllerInstance = $controller(controller, locals);
6048
-
6049
- // Directives with element transclusion and a controller need to attach controller
6050
- // to the comment node created by the compiler, but jQuery .data doesn't support
6051
- // attaching data to comment nodes so instead we set it directly on the element and
6052
- // remove it after we read it later.
6053
- if ($element[0].nodeType == 8) { // Transclusion comment node
6054
- $element[0].$$controller = controllerInstance;
6055
- } else {
6093
+ // For directives with element transclusion the element is a comment,
6094
+ // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
6095
+ // clean up (http://bugs.jquery.com/ticket/8335).
6096
+ // Instead, we save the controllers for the element in a local hash and attach to .data
6097
+ // later, once we have the actual element.
6098
+ elementControllers[directive.name] = controllerInstance;
6099
+ if (!hasElementTranscludeDirective) {
6056
6100
  $element.data('$' + directive.name + 'Controller', controllerInstance);
6057
6101
  }
6102
+
6058
6103
  if (directive.controllerAs) {
6059
6104
  locals.$scope[directive.controllerAs] = controllerInstance;
6060
6105
  }
@@ -6066,7 +6111,7 @@ function $CompileProvider($provide) {
6066
6111
  try {
6067
6112
  linkFn = preLinkFns[i];
6068
6113
  linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
6069
- linkFn.require && getControllers(linkFn.require, $element));
6114
+ linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn);
6070
6115
  } catch (e) {
6071
6116
  $exceptionHandler(e, startingTag($element));
6072
6117
  }
@@ -6086,11 +6131,28 @@ function $CompileProvider($provide) {
6086
6131
  try {
6087
6132
  linkFn = postLinkFns[i];
6088
6133
  linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
6089
- linkFn.require && getControllers(linkFn.require, $element));
6134
+ linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn);
6090
6135
  } catch (e) {
6091
6136
  $exceptionHandler(e, startingTag($element));
6092
6137
  }
6093
6138
  }
6139
+
6140
+ // This is the function that is injected as `$transclude`.
6141
+ function controllersBoundTransclude(scope, cloneAttachFn) {
6142
+ var transcludeControllers;
6143
+
6144
+ // no scope passed
6145
+ if (arguments.length < 2) {
6146
+ cloneAttachFn = scope;
6147
+ scope = undefined;
6148
+ }
6149
+
6150
+ if (hasElementTranscludeDirective) {
6151
+ transcludeControllers = elementControllers;
6152
+ }
6153
+
6154
+ return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers);
6155
+ }
6094
6156
  }
6095
6157
  }
6096
6158
 
@@ -6169,6 +6231,7 @@ function $CompileProvider($provide) {
6169
6231
  dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
6170
6232
  } else if (key == 'style') {
6171
6233
  $element.attr('style', $element.attr('style') + ';' + value);
6234
+ dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
6172
6235
  // `dst` will never contain hasOwnProperty as DOM parser won't let it.
6173
6236
  // You will get an "InvalidCharacterError: DOM Exception 5" error if you
6174
6237
  // have an attribute like "has-own-property" or "data-has-own-property", etc.
@@ -6199,7 +6262,7 @@ function $CompileProvider($provide) {
6199
6262
 
6200
6263
  $http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}).
6201
6264
  success(function(content) {
6202
- var compileNode, tempTemplateAttrs, $template;
6265
+ var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
6203
6266
 
6204
6267
  content = denormalizeTemplate(content);
6205
6268
 
@@ -6244,7 +6307,7 @@ function $CompileProvider($provide) {
6244
6307
  var scope = linkQueue.shift(),
6245
6308
  beforeTemplateLinkNode = linkQueue.shift(),
6246
6309
  linkRootElement = linkQueue.shift(),
6247
- controller = linkQueue.shift(),
6310
+ boundTranscludeFn = linkQueue.shift(),
6248
6311
  linkNode = $compileNode[0];
6249
6312
 
6250
6313
  if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
@@ -6252,9 +6315,13 @@ function $CompileProvider($provide) {
6252
6315
  linkNode = jqLiteClone(compileNode);
6253
6316
  replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
6254
6317
  }
6255
-
6318
+ if (afterTemplateNodeLinkFn.transclude) {
6319
+ childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude);
6320
+ } else {
6321
+ childBoundTranscludeFn = boundTranscludeFn;
6322
+ }
6256
6323
  afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
6257
- controller);
6324
+ childBoundTranscludeFn);
6258
6325
  }
6259
6326
  linkQueue = null;
6260
6327
  }).
@@ -6262,14 +6329,14 @@ function $CompileProvider($provide) {
6262
6329
  throw $compileMinErr('tpload', 'Failed to load template: {0}', config.url);
6263
6330
  });
6264
6331
 
6265
- return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, controller) {
6332
+ return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
6266
6333
  if (linkQueue) {
6267
6334
  linkQueue.push(scope);
6268
6335
  linkQueue.push(node);
6269
6336
  linkQueue.push(rootElement);
6270
- linkQueue.push(controller);
6337
+ linkQueue.push(boundTranscludeFn);
6271
6338
  } else {
6272
- afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, controller);
6339
+ afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, boundTranscludeFn);
6273
6340
  }
6274
6341
  };
6275
6342
  }
@@ -6314,10 +6381,15 @@ function $CompileProvider($provide) {
6314
6381
 
6315
6382
 
6316
6383
  function getTrustedContext(node, attrNormalizedName) {
6384
+ if (attrNormalizedName == "srcdoc") {
6385
+ return $sce.HTML;
6386
+ }
6387
+ var tag = nodeName_(node);
6317
6388
  // maction[xlink:href] can source SVG. It's not limited to <maction>.
6318
6389
  if (attrNormalizedName == "xlinkHref" ||
6319
- (nodeName_(node) != "IMG" && (attrNormalizedName == "src" ||
6320
- attrNormalizedName == "ngSrc"))) {
6390
+ (tag == "FORM" && attrNormalizedName == "action") ||
6391
+ (tag != "IMG" && (attrNormalizedName == "src" ||
6392
+ attrNormalizedName == "ngSrc"))) {
6321
6393
  return $sce.RESOURCE_URL;
6322
6394
  }
6323
6395
  }
@@ -6362,9 +6434,19 @@ function $CompileProvider($provide) {
6362
6434
  attr[name] = interpolateFn(scope);
6363
6435
  ($$observers[name] || ($$observers[name] = [])).$$inter = true;
6364
6436
  (attr.$$observers && attr.$$observers[name].$$scope || scope).
6365
- $watch(interpolateFn, function interpolateFnWatchAction(value) {
6366
- attr.$set(name, value);
6367
- });
6437
+ $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
6438
+ //special case for class attribute addition + removal
6439
+ //so that class changes can tap into the animation
6440
+ //hooks provided by the $animate service. Be sure to
6441
+ //skip animations when the first digest occurs (when
6442
+ //both the new and the old values are the same) since
6443
+ //the CSS classes are the non-interpolated values
6444
+ if(name === 'class' && newValue != oldValue) {
6445
+ attr.$updateClass(newValue, oldValue);
6446
+ } else {
6447
+ attr.$set(name, newValue);
6448
+ }
6449
+ });
6368
6450
  }
6369
6451
  };
6370
6452
  }
@@ -6505,6 +6587,22 @@ function directiveLinkingFn(
6505
6587
  /* function(Function) */ boundTranscludeFn
6506
6588
  ){}
6507
6589
 
6590
+ function tokenDifference(str1, str2) {
6591
+ var values = '',
6592
+ tokens1 = str1.split(/\s+/),
6593
+ tokens2 = str2.split(/\s+/);
6594
+
6595
+ outer:
6596
+ for(var i = 0; i < tokens1.length; i++) {
6597
+ var token = tokens1[i];
6598
+ for(var j = 0; j < tokens2.length; j++) {
6599
+ if(token == tokens2[j]) continue outer;
6600
+ }
6601
+ values += (values.length > 0 ? ' ' : '') + token;
6602
+ }
6603
+ return values;
6604
+ }
6605
+
6508
6606
  /**
6509
6607
  * @ngdoc object
6510
6608
  * @name ng.$controllerProvider
@@ -6974,9 +7072,11 @@ function $HttpProvider() {
6974
7072
  *
6975
7073
  * # Caching
6976
7074
  *
6977
- * To enable caching, set the configuration property `cache` to `true`. When the cache is
6978
- * enabled, `$http` stores the response from the server in local cache. Next time the
6979
- * response is served from the cache without sending a request to the server.
7075
+ * To enable caching, set the request configuration `cache` property to `true` (to use default
7076
+ * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
7077
+ * When the cache is enabled, `$http` stores the response from the server in the specified
7078
+ * cache. The next time the same request is made, the response is served from the cache without
7079
+ * sending a request to the server.
6980
7080
  *
6981
7081
  * Note that even if the response is served from cache, delivery of the data is asynchronous in
6982
7082
  * the same way that real requests are.
@@ -6985,9 +7085,13 @@ function $HttpProvider() {
6985
7085
  * cache, but the cache is not populated yet, only one request to the server will be made and
6986
7086
  * the remaining requests will be fulfilled using the response from the first request.
6987
7087
  *
6988
- * A custom default cache built with $cacheFactory can be provided in $http.defaults.cache.
6989
- * To skip it, set configuration property `cache` to `false`.
7088
+ * You can change the default cache to a new object (built with
7089
+ * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
7090
+ * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set
7091
+ * their `cache` property to `true` will now use this cache object.
6990
7092
  *
7093
+ * If you set the default cache to `false` then only requests that specify their own custom
7094
+ * cache object will be cached.
6991
7095
  *
6992
7096
  * # Interceptors
6993
7097
  *
@@ -7709,12 +7813,13 @@ var XHR = window.XMLHttpRequest || function() {
7709
7813
  */
7710
7814
  function $HttpBackendProvider() {
7711
7815
  this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
7712
- return createHttpBackend($browser, XHR, $browser.defer, $window.angular.callbacks,
7713
- $document[0], $window.location.protocol.replace(':', ''));
7816
+ return createHttpBackend($browser, XHR, $browser.defer, $window.angular.callbacks, $document[0]);
7714
7817
  }];
7715
7818
  }
7716
7819
 
7717
- function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument, locationProtocol) {
7820
+ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument) {
7821
+ var ABORTED = -1;
7822
+
7718
7823
  // TODO(vojta): fix the signature
7719
7824
  return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
7720
7825
  var status;
@@ -7750,13 +7855,19 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
7750
7855
  // always async
7751
7856
  xhr.onreadystatechange = function() {
7752
7857
  if (xhr.readyState == 4) {
7753
- var responseHeaders = xhr.getAllResponseHeaders();
7858
+ var responseHeaders = null,
7859
+ response = null;
7860
+
7861
+ if(status !== ABORTED) {
7862
+ responseHeaders = xhr.getAllResponseHeaders();
7863
+ response = xhr.responseType ? xhr.response : xhr.responseText;
7864
+ }
7754
7865
 
7755
7866
  // responseText is the old-school way of retrieving response (supported by IE8 & 9)
7756
7867
  // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
7757
7868
  completeRequest(callback,
7758
7869
  status || xhr.status,
7759
- (xhr.responseType ? xhr.response : xhr.responseText),
7870
+ response,
7760
7871
  responseHeaders);
7761
7872
  }
7762
7873
  };
@@ -7780,20 +7891,20 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
7780
7891
 
7781
7892
 
7782
7893
  function timeoutRequest() {
7783
- status = -1;
7894
+ status = ABORTED;
7784
7895
  jsonpDone && jsonpDone();
7785
7896
  xhr && xhr.abort();
7786
7897
  }
7787
7898
 
7788
7899
  function completeRequest(callback, status, response, headersString) {
7789
- var protocol = locationProtocol || urlResolve(url).protocol;
7900
+ var protocol = urlResolve(url).protocol;
7790
7901
 
7791
7902
  // cancel timeout and subsequent timeout promise resolution
7792
7903
  timeoutId && $browserDefer.cancel(timeoutId);
7793
7904
  jsonpDone = xhr = null;
7794
7905
 
7795
7906
  // fix status code for file protocol (it's always 0)
7796
- status = (protocol == 'file') ? (response ? 200 : 404) : status;
7907
+ status = (protocol == 'file' && status === 0) ? (response ? 200 : 404) : status;
7797
7908
 
7798
7909
  // normalize IE bug (http://bugs.jquery.com/ticket/1450)
7799
7910
  status = status == 1223 ? 204 : status;
@@ -7809,6 +7920,7 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
7809
7920
  // - adds and immediately removes script elements from the document
7810
7921
  var script = rawDocument.createElement('script'),
7811
7922
  doneWrapper = function() {
7923
+ script.onreadystatechange = script.onload = script.onerror = null;
7812
7924
  rawDocument.body.removeChild(script);
7813
7925
  if (done) done();
7814
7926
  };
@@ -7816,12 +7928,16 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
7816
7928
  script.type = 'text/javascript';
7817
7929
  script.src = url;
7818
7930
 
7819
- if (msie) {
7931
+ if (msie && msie <= 8) {
7820
7932
  script.onreadystatechange = function() {
7821
- if (/loaded|complete/.test(script.readyState)) doneWrapper();
7933
+ if (/loaded|complete/.test(script.readyState)) {
7934
+ doneWrapper();
7935
+ }
7822
7936
  };
7823
7937
  } else {
7824
- script.onload = script.onerror = doneWrapper;
7938
+ script.onload = script.onerror = function() {
7939
+ doneWrapper();
7940
+ };
7825
7941
  }
7826
7942
 
7827
7943
  rawDocument.body.appendChild(script);
@@ -8251,8 +8367,8 @@ function encodePath(path) {
8251
8367
  return segments.join('/');
8252
8368
  }
8253
8369
 
8254
- function parseAbsoluteUrl(absoluteUrl, locationObj) {
8255
- var parsedUrl = urlResolve(absoluteUrl);
8370
+ function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
8371
+ var parsedUrl = urlResolve(absoluteUrl, appBase);
8256
8372
 
8257
8373
  locationObj.$$protocol = parsedUrl.protocol;
8258
8374
  locationObj.$$host = parsedUrl.hostname;
@@ -8260,12 +8376,12 @@ function parseAbsoluteUrl(absoluteUrl, locationObj) {
8260
8376
  }
8261
8377
 
8262
8378
 
8263
- function parseAppUrl(relativeUrl, locationObj) {
8379
+ function parseAppUrl(relativeUrl, locationObj, appBase) {
8264
8380
  var prefixed = (relativeUrl.charAt(0) !== '/');
8265
8381
  if (prefixed) {
8266
8382
  relativeUrl = '/' + relativeUrl;
8267
8383
  }
8268
- var match = urlResolve(relativeUrl);
8384
+ var match = urlResolve(relativeUrl, appBase);
8269
8385
  locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
8270
8386
  match.pathname.substring(1) : match.pathname);
8271
8387
  locationObj.$$search = parseKeyValue(match.search);
@@ -8320,7 +8436,7 @@ function LocationHtml5Url(appBase, basePrefix) {
8320
8436
  this.$$html5 = true;
8321
8437
  basePrefix = basePrefix || '';
8322
8438
  var appBaseNoFile = stripFile(appBase);
8323
- parseAbsoluteUrl(appBase, this);
8439
+ parseAbsoluteUrl(appBase, this, appBase);
8324
8440
 
8325
8441
 
8326
8442
  /**
@@ -8335,7 +8451,7 @@ function LocationHtml5Url(appBase, basePrefix) {
8335
8451
  appBaseNoFile);
8336
8452
  }
8337
8453
 
8338
- parseAppUrl(pathUrl, this);
8454
+ parseAppUrl(pathUrl, this, appBase);
8339
8455
 
8340
8456
  if (!this.$$path) {
8341
8457
  this.$$path = '/';
@@ -8387,7 +8503,7 @@ function LocationHtml5Url(appBase, basePrefix) {
8387
8503
  function LocationHashbangUrl(appBase, hashPrefix) {
8388
8504
  var appBaseNoFile = stripFile(appBase);
8389
8505
 
8390
- parseAbsoluteUrl(appBase, this);
8506
+ parseAbsoluteUrl(appBase, this, appBase);
8391
8507
 
8392
8508
 
8393
8509
  /**
@@ -8407,8 +8523,48 @@ function LocationHashbangUrl(appBase, hashPrefix) {
8407
8523
  throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
8408
8524
  hashPrefix);
8409
8525
  }
8410
- parseAppUrl(withoutHashUrl, this);
8526
+ parseAppUrl(withoutHashUrl, this, appBase);
8527
+
8528
+ this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
8529
+
8411
8530
  this.$$compose();
8531
+
8532
+ /*
8533
+ * In Windows, on an anchor node on documents loaded from
8534
+ * the filesystem, the browser will return a pathname
8535
+ * prefixed with the drive name ('/C:/path') when a
8536
+ * pathname without a drive is set:
8537
+ * * a.setAttribute('href', '/foo')
8538
+ * * a.pathname === '/C:/foo' //true
8539
+ *
8540
+ * Inside of Angular, we're always using pathnames that
8541
+ * do not include drive names for routing.
8542
+ */
8543
+ function removeWindowsDriveName (path, url, base) {
8544
+ /*
8545
+ Matches paths for file protocol on windows,
8546
+ such as /C:/foo/bar, and captures only /foo/bar.
8547
+ */
8548
+ var windowsFilePathExp = /^\/?.*?:(\/.*)/;
8549
+
8550
+ var firstPathSegmentMatch;
8551
+
8552
+ //Get the relative path from the input URL.
8553
+ if (url.indexOf(base) === 0) {
8554
+ url = url.replace(base, '');
8555
+ }
8556
+
8557
+ /*
8558
+ * The input URL intentionally contains a
8559
+ * first path segment that ends with a colon.
8560
+ */
8561
+ if (windowsFilePathExp.exec(url)) {
8562
+ return path;
8563
+ }
8564
+
8565
+ firstPathSegmentMatch = windowsFilePathExp.exec(path);
8566
+ return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
8567
+ }
8412
8568
  };
8413
8569
 
8414
8570
  /**
@@ -8898,7 +9054,7 @@ function $LocationProvider(){
8898
9054
  *
8899
9055
  * The main purpose of this service is to simplify debugging and troubleshooting.
8900
9056
  *
8901
- * The default is not to log `debug` messages. You can use
9057
+ * The default is to log `debug` messages. You can use
8902
9058
  * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
8903
9059
  *
8904
9060
  * @example
@@ -9055,23 +9211,18 @@ var promiseWarning;
9055
9211
  // ------------------------------
9056
9212
  // Angular expressions are generally considered safe because these expressions only have direct
9057
9213
  // access to $scope and locals. However, one can obtain the ability to execute arbitrary JS code by
9058
- // obtaining a reference to native JS functions such as the Function constructor, the global Window
9059
- // or Document object. In addition, many powerful functions for use by JavaScript code are
9060
- // published on scope that shouldn't be available from within an Angular expression.
9214
+ // obtaining a reference to native JS functions such as the Function constructor.
9061
9215
  //
9062
9216
  // As an example, consider the following Angular expression:
9063
9217
  //
9064
9218
  // {}.toString.constructor(alert("evil JS code"))
9065
9219
  //
9066
9220
  // We want to prevent this type of access. For the sake of performance, during the lexing phase we
9067
- // disallow any "dotted" access to any member named "constructor" or to any member whose name begins
9068
- // or ends with an underscore. The latter allows one to exclude the private / JavaScript only API
9069
- // available on the scope and controllers from the context of an Angular expression.
9221
+ // disallow any "dotted" access to any member named "constructor".
9070
9222
  //
9071
- // For reflective calls (a[b]), we check that the value of the lookup is not the Function
9072
- // constructor, Window or DOM node while evaluating the expression, which is a stronger but more
9073
- // expensive test. Since reflective calls are expensive anyway, this is not such a big deal compared
9074
- // to static dereferencing.
9223
+ // For reflective calls (a[b]) we check that the value of the lookup is not the Function constructor
9224
+ // while evaluating the expression, which is a stronger but more expensive test. Since reflective
9225
+ // calls are expensive anyway, this is not such a big deal compared to static dereferencing.
9075
9226
  //
9076
9227
  // This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
9077
9228
  // against the expression language, but not to prevent exploits that were enabled by exposing
@@ -9085,20 +9236,12 @@ var promiseWarning;
9085
9236
  // In general, it is not possible to access a Window object from an angular expression unless a
9086
9237
  // window or some DOM object that has a reference to window is published onto a Scope.
9087
9238
 
9088
- function ensureSafeMemberName(name, fullExpression, allowConstructor) {
9089
- if (typeof name !== 'string' && toString.apply(name) !== "[object String]") {
9090
- return name;
9091
- }
9092
- if (name === "constructor" && !allowConstructor) {
9239
+ function ensureSafeMemberName(name, fullExpression) {
9240
+ if (name === "constructor") {
9093
9241
  throw $parseMinErr('isecfld',
9094
9242
  'Referencing "constructor" field in Angular expressions is disallowed! Expression: {0}',
9095
9243
  fullExpression);
9096
9244
  }
9097
- if (name.charAt(0) === '_' || name.charAt(name.length-1) === '_') {
9098
- throw $parseMinErr('isecprv',
9099
- 'Referencing private fields in Angular expressions is disallowed! Expression: {0}',
9100
- fullExpression);
9101
- }
9102
9245
  return name;
9103
9246
  }
9104
9247
 
@@ -9782,10 +9925,7 @@ Parser.prototype = {
9782
9925
 
9783
9926
  return extend(function(self, locals) {
9784
9927
  var o = obj(self, locals),
9785
- // In the getter, we will not block looking up "constructor" by name in order to support user defined
9786
- // constructors. However, if value looked up is the Function constructor, we will still block it in the
9787
- // ensureSafeObject call right after we look up o[i] (a few lines below.)
9788
- i = ensureSafeMemberName(indexFn(self, locals), parser.text, true /* allowConstructor */),
9928
+ i = indexFn(self, locals),
9789
9929
  v, p;
9790
9930
 
9791
9931
  if (!o) return undefined;
@@ -9801,7 +9941,7 @@ Parser.prototype = {
9801
9941
  return v;
9802
9942
  }, {
9803
9943
  assign: function(self, value, locals) {
9804
- var key = ensureSafeMemberName(indexFn(self, locals), parser.text);
9944
+ var key = indexFn(self, locals);
9805
9945
  // prevent overwriting of Function.constructor which would break ensureSafeObject check
9806
9946
  var safe = ensureSafeObject(obj(self, locals), parser.text);
9807
9947
  return safe[key] = value;
@@ -10080,7 +10220,7 @@ function getterFn(path, options, fullExp) {
10080
10220
  : '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' +
10081
10221
  (options.unwrapPromises
10082
10222
  ? 'if (s && s.then) {\n' +
10083
- ' pw("' + fullExp.replace(/\"/g, '\\"') + '");\n' +
10223
+ ' pw("' + fullExp.replace(/(["\r\n])/g, '\\$1') + '");\n' +
10084
10224
  ' if (!("$$v" in s)) {\n' +
10085
10225
  ' p=s;\n' +
10086
10226
  ' p.$$v = undefined;\n' +
@@ -10461,7 +10601,7 @@ function $ParseProvider() {
10461
10601
  * // Propagate promise resolution to 'then' functions using $apply().
10462
10602
  * $rootScope.$apply();
10463
10603
  * expect(resolvedValue).toEqual(123);
10464
- * });
10604
+ * }));
10465
10605
  * </pre>
10466
10606
  */
10467
10607
  function $QProvider() {
@@ -11851,6 +11991,79 @@ function $RootScopeProvider(){
11851
11991
  }];
11852
11992
  }
11853
11993
 
11994
+ /**
11995
+ * @description
11996
+ * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
11997
+ */
11998
+ function $$SanitizeUriProvider() {
11999
+ var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
12000
+ imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//;
12001
+
12002
+ /**
12003
+ * @description
12004
+ * Retrieves or overrides the default regular expression that is used for whitelisting of safe
12005
+ * urls during a[href] sanitization.
12006
+ *
12007
+ * The sanitization is a security measure aimed at prevent XSS attacks via html links.
12008
+ *
12009
+ * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
12010
+ * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
12011
+ * regular expression. If a match is found, the original url is written into the dom. Otherwise,
12012
+ * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
12013
+ *
12014
+ * @param {RegExp=} regexp New regexp to whitelist urls with.
12015
+ * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
12016
+ * chaining otherwise.
12017
+ */
12018
+ this.aHrefSanitizationWhitelist = function(regexp) {
12019
+ if (isDefined(regexp)) {
12020
+ aHrefSanitizationWhitelist = regexp;
12021
+ return this;
12022
+ }
12023
+ return aHrefSanitizationWhitelist;
12024
+ };
12025
+
12026
+
12027
+ /**
12028
+ * @description
12029
+ * Retrieves or overrides the default regular expression that is used for whitelisting of safe
12030
+ * urls during img[src] sanitization.
12031
+ *
12032
+ * The sanitization is a security measure aimed at prevent XSS attacks via html links.
12033
+ *
12034
+ * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
12035
+ * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
12036
+ * regular expression. If a match is found, the original url is written into the dom. Otherwise,
12037
+ * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
12038
+ *
12039
+ * @param {RegExp=} regexp New regexp to whitelist urls with.
12040
+ * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
12041
+ * chaining otherwise.
12042
+ */
12043
+ this.imgSrcSanitizationWhitelist = function(regexp) {
12044
+ if (isDefined(regexp)) {
12045
+ imgSrcSanitizationWhitelist = regexp;
12046
+ return this;
12047
+ }
12048
+ return imgSrcSanitizationWhitelist;
12049
+ };
12050
+
12051
+ this.$get = function() {
12052
+ return function sanitizeUri(uri, isImage) {
12053
+ var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
12054
+ var normalizedVal;
12055
+ // NOTE: urlResolve() doesn't support IE < 8 so we don't sanitize for that case.
12056
+ if (!msie || msie >= 8 ) {
12057
+ normalizedVal = urlResolve(uri).href;
12058
+ if (normalizedVal !== '' && !normalizedVal.match(regex)) {
12059
+ return 'unsafe:'+normalizedVal;
12060
+ }
12061
+ }
12062
+ return uri;
12063
+ };
12064
+ };
12065
+ }
12066
+
11854
12067
  var $sceMinErr = minErr('$sce');
11855
12068
 
11856
12069
  var SCE_CONTEXTS = {
@@ -12050,8 +12263,7 @@ function $SceDelegateProvider() {
12050
12263
  return resourceUrlBlacklist;
12051
12264
  };
12052
12265
 
12053
- this.$get = ['$log', '$document', '$injector', function(
12054
- $log, $document, $injector) {
12266
+ this.$get = ['$injector', function($injector) {
12055
12267
 
12056
12268
  var htmlSanitizer = function htmlSanitizer(html) {
12057
12269
  throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
@@ -12278,10 +12490,10 @@ function $SceDelegateProvider() {
12278
12490
  *
12279
12491
  * <pre class="prettyprint">
12280
12492
  * <input ng-model="userHtml">
12281
- * <div ng-bind-html="{{userHtml}}">
12493
+ * <div ng-bind-html="userHtml">
12282
12494
  * </pre>
12283
12495
  *
12284
- * Notice that `ng-bind-html` is bound to `{{userHtml}}` controlled by the user. With SCE
12496
+ * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user. With SCE
12285
12497
  * disabled, this application allows the user to render arbitrary HTML into the DIV.
12286
12498
  * In a more realistic example, one may be rendering user comments, blog articles, etc. via
12287
12499
  * bindings. (HTML is just one example of a context where rendering user controlled input creates
@@ -12582,18 +12794,15 @@ function $SceProvider() {
12582
12794
  * sce.js and sceSpecs.js would need to be aware of this detail.
12583
12795
  */
12584
12796
 
12585
- this.$get = ['$parse', '$document', '$sceDelegate', function(
12586
- $parse, $document, $sceDelegate) {
12797
+ this.$get = ['$parse', '$sniffer', '$sceDelegate', function(
12798
+ $parse, $sniffer, $sceDelegate) {
12587
12799
  // Prereq: Ensure that we're not running in IE8 quirks mode. In that mode, IE allows
12588
12800
  // the "expression(javascript expression)" syntax which is insecure.
12589
- if (enabled && msie) {
12590
- var documentMode = $document[0].documentMode;
12591
- if (documentMode !== undefined && documentMode < 8) {
12592
- throw $sceMinErr('iequirks',
12593
- 'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' +
12594
- 'mode. You can fix this by adding the text <!doctype html> to the top of your HTML ' +
12595
- 'document. See http://docs.angularjs.org/api/ng.$sce for more information.');
12596
- }
12801
+ if (enabled && $sniffer.msie && $sniffer.msieDocumentMode < 8) {
12802
+ throw $sceMinErr('iequirks',
12803
+ 'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' +
12804
+ 'mode. You can fix this by adding the text <!doctype html> to the top of your HTML ' +
12805
+ 'document. See http://docs.angularjs.org/api/ng.$sce for more information.');
12597
12806
  }
12598
12807
 
12599
12808
  var sce = copy(SCE_CONTEXTS);
@@ -12955,6 +13164,7 @@ function $SnifferProvider() {
12955
13164
  int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
12956
13165
  boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
12957
13166
  document = $document[0] || {},
13167
+ documentMode = document.documentMode,
12958
13168
  vendorPrefix,
12959
13169
  vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/,
12960
13170
  bodyStyle = document.body && document.body.style,
@@ -12999,7 +13209,7 @@ function $SnifferProvider() {
12999
13209
  // jshint +W018
13000
13210
  hashchange: 'onhashchange' in $window &&
13001
13211
  // IE8 compatible mode lies
13002
- (!document.documentMode || document.documentMode > 7),
13212
+ (!documentMode || documentMode > 7),
13003
13213
  hasEvent: function(event) {
13004
13214
  // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
13005
13215
  // it. In particular the event is not fired when backspace or delete key are pressed or
@@ -13017,7 +13227,8 @@ function $SnifferProvider() {
13017
13227
  vendorPrefix: vendorPrefix,
13018
13228
  transitions : transitions,
13019
13229
  animations : animations,
13020
- msie : msie
13230
+ msie : msie,
13231
+ msieDocumentMode: documentMode
13021
13232
  };
13022
13233
  }];
13023
13234
  }
@@ -13204,6 +13415,7 @@ function $TimeoutProvider() {
13204
13415
  var urlParsingNode = document.createElement("a");
13205
13416
  var originUrl = urlResolve(window.location.href, true);
13206
13417
 
13418
+
13207
13419
  /**
13208
13420
  *
13209
13421
  * Implementation Notes for non-IE browsers
@@ -13222,7 +13434,7 @@ var originUrl = urlResolve(window.location.href, true);
13222
13434
  * browsers. However, the parsed components will not be set if the URL assigned did not specify
13223
13435
  * them. (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.) We
13224
13436
  * work around that by performing the parsing in a 2nd step by taking a previously normalized
13225
- * URL (e.g. by assining to a.href) and assigning it a.href again. This correctly populates the
13437
+ * URL (e.g. by assigning to a.href) and assigning it a.href again. This correctly populates the
13226
13438
  * properties such as protocol, hostname, port, etc.
13227
13439
  *
13228
13440
  * IE7 does not normalize the URL when assigned to an anchor node. (Apparently, it does, if one
@@ -13256,8 +13468,9 @@ var originUrl = urlResolve(window.location.href, true);
13256
13468
  * | pathname | The pathname, beginning with "/"
13257
13469
  *
13258
13470
  */
13259
- function urlResolve(url) {
13471
+ function urlResolve(url, base) {
13260
13472
  var href = url;
13473
+
13261
13474
  if (msie) {
13262
13475
  // Normalize before parse. Refer Implementation Notes on why this is
13263
13476
  // done in two steps on IE.
@@ -13267,7 +13480,7 @@ function urlResolve(url) {
13267
13480
 
13268
13481
  urlParsingNode.setAttribute('href', href);
13269
13482
 
13270
- // $$urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
13483
+ // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
13271
13484
  return {
13272
13485
  href: urlParsingNode.href,
13273
13486
  protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
@@ -13276,12 +13489,12 @@ function urlResolve(url) {
13276
13489
  hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
13277
13490
  hostname: urlParsingNode.hostname,
13278
13491
  port: urlParsingNode.port,
13279
- pathname: urlParsingNode.pathname && urlParsingNode.pathname.charAt(0) === '/' ?
13280
- urlParsingNode.pathname : '/' + urlParsingNode.pathname
13492
+ pathname: (urlParsingNode.pathname.charAt(0) === '/')
13493
+ ? urlParsingNode.pathname
13494
+ : '/' + urlParsingNode.pathname
13281
13495
  };
13282
13496
  }
13283
13497
 
13284
-
13285
13498
  /**
13286
13499
  * Parse a request URL and determine whether this is a same-origin request as the application document.
13287
13500
  *
@@ -14590,8 +14803,11 @@ var htmlAnchorDirective = valueFn({
14590
14803
  *
14591
14804
  * The HTML specification does not require browsers to preserve the values of boolean attributes
14592
14805
  * such as disabled. (Their presence means true and their absence means false.)
14593
- * This prevents the Angular compiler from retrieving the binding expression.
14806
+ * If we put an Angular interpolation expression into such an attribute then the
14807
+ * binding information would be lost when the browser removes the attribute.
14594
14808
  * The `ngDisabled` directive solves this problem for the `disabled` attribute.
14809
+ * This complementary directive is not removed by the browser and so provides
14810
+ * a permanent reliable place to store the binding information.
14595
14811
  *
14596
14812
  * @example
14597
14813
  <doc:example>
@@ -14622,8 +14838,11 @@ var htmlAnchorDirective = valueFn({
14622
14838
  * @description
14623
14839
  * The HTML specification does not require browsers to preserve the values of boolean attributes
14624
14840
  * such as checked. (Their presence means true and their absence means false.)
14625
- * This prevents the Angular compiler from retrieving the binding expression.
14841
+ * If we put an Angular interpolation expression into such an attribute then the
14842
+ * binding information would be lost when the browser removes the attribute.
14626
14843
  * The `ngChecked` directive solves this problem for the `checked` attribute.
14844
+ * This complementary directive is not removed by the browser and so provides
14845
+ * a permanent reliable place to store the binding information.
14627
14846
  * @example
14628
14847
  <doc:example>
14629
14848
  <doc:source>
@@ -14653,8 +14872,12 @@ var htmlAnchorDirective = valueFn({
14653
14872
  * @description
14654
14873
  * The HTML specification does not require browsers to preserve the values of boolean attributes
14655
14874
  * such as readonly. (Their presence means true and their absence means false.)
14656
- * This prevents the Angular compiler from retrieving the binding expression.
14875
+ * If we put an Angular interpolation expression into such an attribute then the
14876
+ * binding information would be lost when the browser removes the attribute.
14657
14877
  * The `ngReadonly` directive solves this problem for the `readonly` attribute.
14878
+ * This complementary directive is not removed by the browser and so provides
14879
+ * a permanent reliable place to store the binding information.
14880
+
14658
14881
  * @example
14659
14882
  <doc:example>
14660
14883
  <doc:source>
@@ -14684,8 +14907,11 @@ var htmlAnchorDirective = valueFn({
14684
14907
  * @description
14685
14908
  * The HTML specification does not require browsers to preserve the values of boolean attributes
14686
14909
  * such as selected. (Their presence means true and their absence means false.)
14687
- * This prevents the Angular compiler from retrieving the binding expression.
14910
+ * If we put an Angular interpolation expression into such an attribute then the
14911
+ * binding information would be lost when the browser removes the attribute.
14688
14912
  * The `ngSelected` directive solves this problem for the `selected` atttribute.
14913
+ * This complementary directive is not removed by the browser and so provides
14914
+ * a permanent reliable place to store the binding information.
14689
14915
  * @example
14690
14916
  <doc:example>
14691
14917
  <doc:source>
@@ -14717,8 +14943,12 @@ var htmlAnchorDirective = valueFn({
14717
14943
  * @description
14718
14944
  * The HTML specification does not require browsers to preserve the values of boolean attributes
14719
14945
  * such as open. (Their presence means true and their absence means false.)
14720
- * This prevents the Angular compiler from retrieving the binding expression.
14946
+ * If we put an Angular interpolation expression into such an attribute then the
14947
+ * binding information would be lost when the browser removes the attribute.
14721
14948
  * The `ngOpen` directive solves this problem for the `open` attribute.
14949
+ * This complementary directive is not removed by the browser and so provides
14950
+ * a permanent reliable place to store the binding information.
14951
+
14722
14952
  *
14723
14953
  * @example
14724
14954
  <doc:example>
@@ -14811,7 +15041,7 @@ var nullFormCtrl = {
14811
15041
  * @property {Object} $error Is an object hash, containing references to all invalid controls or
14812
15042
  * forms, where:
14813
15043
  *
14814
- * - keys are validation tokens (error names) — such as `required`, `url` or `email`),
15044
+ * - keys are validation tokens (error names) — such as `required`, `url` or `email`,
14815
15045
  * - values are arrays of controls or forms that are invalid with given error.
14816
15046
  *
14817
15047
  * @description
@@ -15548,8 +15778,21 @@ var inputType = {
15548
15778
 
15549
15779
 
15550
15780
  function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
15781
+ // In composition mode, users are still inputing intermediate text buffer,
15782
+ // hold the listener until composition is done.
15783
+ // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
15784
+ var composing = false;
15785
+
15786
+ element.on('compositionstart', function() {
15787
+ composing = true;
15788
+ });
15789
+
15790
+ element.on('compositionend', function() {
15791
+ composing = false;
15792
+ });
15551
15793
 
15552
15794
  var listener = function() {
15795
+ if (composing) return;
15553
15796
  var value = element.val();
15554
15797
 
15555
15798
  // By default we will trim the value
@@ -15592,15 +15835,15 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
15592
15835
  deferListener();
15593
15836
  });
15594
15837
 
15595
- // if user paste into input using mouse, we need "change" event to catch it
15596
- element.on('change', listener);
15597
-
15598
15838
  // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
15599
15839
  if ($sniffer.hasEvent('paste')) {
15600
15840
  element.on('paste cut', deferListener);
15601
15841
  }
15602
15842
  }
15603
15843
 
15844
+ // if user paste into input using mouse on older browser
15845
+ // or form autocomplete on newer browser, we need "change" event to catch it
15846
+ element.on('change', listener);
15604
15847
 
15605
15848
  ctrl.$render = function() {
15606
15849
  element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
@@ -15996,6 +16239,11 @@ var VALID_CLASS = 'ng-valid',
15996
16239
  * }
15997
16240
  * ngModel.$formatters.push(formatter);
15998
16241
  * </pre>
16242
+ *
16243
+ * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
16244
+ * view value has changed. It is called with no arguments, and its return value is ignored.
16245
+ * This can be used in place of additional $watches against the model value.
16246
+ *
15999
16247
  * @property {Object} $error An object hash with all errors as keys.
16000
16248
  *
16001
16249
  * @property {boolean} $pristine True if user has not interacted with the control yet.
@@ -16259,14 +16507,19 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
16259
16507
  * @methodOf ng.directive:ngModel.NgModelController
16260
16508
  *
16261
16509
  * @description
16262
- * Read a value from view.
16510
+ * Update the view value.
16263
16511
  *
16264
- * This method should be called from within a DOM event handler.
16265
- * For example {@link ng.directive:input input} or
16512
+ * This method should be called when the view value changes, typically from within a DOM event handler.
16513
+ * For example {@link ng.directive:input input} and
16266
16514
  * {@link ng.directive:select select} directives call it.
16267
16515
  *
16268
- * It internally calls all `$parsers` (including validators) and updates the `$modelValue` and the actual model path.
16269
- * Lastly it calls all registered change listeners.
16516
+ * It will update the $viewValue, then pass this value through each of the functions in `$parsers`,
16517
+ * which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to
16518
+ * `$modelValue` and the **expression** specified in the `ng-model` attribute.
16519
+ *
16520
+ * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
16521
+ *
16522
+ * Note that calling this function does not trigger a `$digest`.
16270
16523
  *
16271
16524
  * @param {string} value Value from the view.
16272
16525
  */
@@ -16768,27 +17021,33 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
16768
17021
  * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
16769
17022
  *
16770
17023
  * @example
16771
- * Try it here: enter text in text box and watch the greeting change.
16772
- <doc:example module="ngBindHtmlExample" deps="angular-sanitize.js" >
16773
- <doc:source>
16774
- <script>
16775
- angular.module('ngBindHtmlExample', ['ngSanitize'])
16776
-
16777
- .controller('ngBindHtmlCtrl', ['$scope', function ngBindHtmlCtrl($scope) {
16778
- $scope.myHTML = 'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>';
16779
- }]);
16780
- </script>
17024
+ Try it here: enter text in text box and watch the greeting change.
17025
+
17026
+ <example module="ngBindHtmlExample" deps="angular-sanitize.js">
17027
+ <file name="index.html">
16781
17028
  <div ng-controller="ngBindHtmlCtrl">
16782
17029
  <p ng-bind-html="myHTML"></p>
16783
17030
  </div>
16784
- </doc:source>
16785
- <doc:scenario>
17031
+ </file>
17032
+
17033
+ <file name="script.js">
17034
+ angular.module('ngBindHtmlExample', ['ngSanitize'])
17035
+
17036
+ .controller('ngBindHtmlCtrl', ['$scope', function ngBindHtmlCtrl($scope) {
17037
+ $scope.myHTML =
17038
+ 'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>';
17039
+ }]);
17040
+ </file>
17041
+
17042
+ <file name="scenario.js">
16786
17043
  it('should check ng-bind-html', function() {
16787
17044
  expect(using('.doc-example-live').binding('myHTML')).
16788
- toBe('I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>');
17045
+ toBe(
17046
+ 'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>'
17047
+ );
16789
17048
  });
16790
- </doc:scenario>
16791
- </doc:example>
17049
+ </file>
17050
+ </example>
16792
17051
  */
16793
17052
  var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
16794
17053
  return function(scope, element, attr) {
@@ -16823,11 +17082,10 @@ function classDirective(name, selector) {
16823
17082
  // jshint bitwise: false
16824
17083
  var mod = $index & 1;
16825
17084
  if (mod !== old$index & 1) {
16826
- if (mod === selector) {
16827
- addClass(scope.$eval(attr[name]));
16828
- } else {
16829
- removeClass(scope.$eval(attr[name]));
16830
- }
17085
+ var classes = flattenClasses(scope.$eval(attr[name]));
17086
+ mod === selector ?
17087
+ attr.$addClass(classes) :
17088
+ attr.$removeClass(classes);
16831
17089
  }
16832
17090
  });
16833
17091
  }
@@ -16835,24 +17093,17 @@ function classDirective(name, selector) {
16835
17093
 
16836
17094
  function ngClassWatchAction(newVal) {
16837
17095
  if (selector === true || scope.$index % 2 === selector) {
16838
- if (oldVal && !equals(newVal,oldVal)) {
16839
- removeClass(oldVal);
17096
+ var newClasses = flattenClasses(newVal || '');
17097
+ if(!oldVal) {
17098
+ attr.$addClass(newClasses);
17099
+ } else if(!equals(newVal,oldVal)) {
17100
+ attr.$updateClass(newClasses, flattenClasses(oldVal));
16840
17101
  }
16841
- addClass(newVal);
16842
17102
  }
16843
17103
  oldVal = copy(newVal);
16844
17104
  }
16845
17105
 
16846
17106
 
16847
- function removeClass(classVal) {
16848
- attr.$removeClass(flattenClasses(classVal));
16849
- }
16850
-
16851
-
16852
- function addClass(classVal) {
16853
- attr.$addClass(flattenClasses(classVal));
16854
- }
16855
-
16856
17107
  function flattenClasses(classVal) {
16857
17108
  if(isArray(classVal)) {
16858
17109
  return classVal.join(' ');
@@ -16901,18 +17152,18 @@ function classDirective(name, selector) {
16901
17152
  * @example Example that demonstrates basic bindings via ngClass directive.
16902
17153
  <example>
16903
17154
  <file name="index.html">
16904
- <p ng-class="{strike: strike, bold: bold, red: red}">Map Syntax Example</p>
16905
- <input type="checkbox" ng-model="bold"> bold
16906
- <input type="checkbox" ng-model="strike"> strike
16907
- <input type="checkbox" ng-model="red"> red
17155
+ <p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
17156
+ <input type="checkbox" ng-model="deleted"> deleted (apply "strike" class)<br>
17157
+ <input type="checkbox" ng-model="important"> important (apply "bold" class)<br>
17158
+ <input type="checkbox" ng-model="error"> error (apply "red" class)
16908
17159
  <hr>
16909
17160
  <p ng-class="style">Using String Syntax</p>
16910
17161
  <input type="text" ng-model="style" placeholder="Type: bold strike red">
16911
17162
  <hr>
16912
17163
  <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
16913
- <input ng-model="style1" placeholder="Type: bold"><br>
16914
- <input ng-model="style2" placeholder="Type: strike"><br>
16915
- <input ng-model="style3" placeholder="Type: red"><br>
17164
+ <input ng-model="style1" placeholder="Type: bold, strike or red"><br>
17165
+ <input ng-model="style2" placeholder="Type: bold, strike or red"><br>
17166
+ <input ng-model="style3" placeholder="Type: bold, strike or red"><br>
16916
17167
  </file>
16917
17168
  <file name="style.css">
16918
17169
  .strike {
@@ -16931,10 +17182,10 @@ function classDirective(name, selector) {
16931
17182
  expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/bold/);
16932
17183
  expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/red/);
16933
17184
 
16934
- input('bold').check();
17185
+ input('important').check();
16935
17186
  expect(element('.doc-example-live p:first').prop('className')).toMatch(/bold/);
16936
17187
 
16937
- input('red').check();
17188
+ input('error').check();
16938
17189
  expect(element('.doc-example-live p:first').prop('className')).toMatch(/red/);
16939
17190
  });
16940
17191
 
@@ -17330,7 +17581,8 @@ var ngCloakDirective = ngDirective({
17330
17581
  var ngControllerDirective = [function() {
17331
17582
  return {
17332
17583
  scope: true,
17333
- controller: '@'
17584
+ controller: '@',
17585
+ priority: 500
17334
17586
  };
17335
17587
  }];
17336
17588
 
@@ -17780,7 +18032,7 @@ forEach(
17780
18032
  }
17781
18033
 
17782
18034
  /&#42;
17783
- The transition styles can also be placed on the CSS base class above
18035
+ The transition styles can also be placed on the CSS base class above
17784
18036
  &#42;/
17785
18037
  .animate-if.ng-enter, .animate-if.ng-leave {
17786
18038
  -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
@@ -17806,22 +18058,21 @@ var ngIfDirective = ['$animate', function($animate) {
17806
18058
  terminal: true,
17807
18059
  restrict: 'A',
17808
18060
  $$tlb: true,
17809
- compile: function (element, attr, transclude) {
17810
- return function ($scope, $element, $attr) {
18061
+ link: function ($scope, $element, $attr, ctrl, $transclude) {
17811
18062
  var block, childScope;
17812
18063
  $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
17813
18064
 
17814
18065
  if (toBoolean(value)) {
17815
-
17816
- childScope = $scope.$new();
17817
- transclude(childScope, function (clone) {
17818
- block = {
17819
- startNode: clone[0],
17820
- endNode: clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ')
17821
- };
17822
- $animate.enter(clone, $element.parent(), $element);
17823
- });
17824
-
18066
+ if (!childScope) {
18067
+ childScope = $scope.$new();
18068
+ $transclude(childScope, function (clone) {
18069
+ block = {
18070
+ startNode: clone[0],
18071
+ endNode: clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ')
18072
+ };
18073
+ $animate.enter(clone, $element.parent(), $element);
18074
+ });
18075
+ }
17825
18076
  } else {
17826
18077
 
17827
18078
  if (childScope) {
@@ -17835,7 +18086,6 @@ var ngIfDirective = ['$animate', function($animate) {
17835
18086
  }
17836
18087
  }
17837
18088
  });
17838
- };
17839
18089
  }
17840
18090
  };
17841
18091
  }];
@@ -17994,12 +18244,12 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
17994
18244
  priority: 400,
17995
18245
  terminal: true,
17996
18246
  transclude: 'element',
17997
- compile: function(element, attr, transclusion) {
18247
+ compile: function(element, attr) {
17998
18248
  var srcExp = attr.ngInclude || attr.src,
17999
18249
  onloadExp = attr.onload || '',
18000
18250
  autoScrollExp = attr.autoscroll;
18001
18251
 
18002
- return function(scope, $element) {
18252
+ return function(scope, $element, $attr, ctrl, $transclude) {
18003
18253
  var changeCounter = 0,
18004
18254
  currentScope,
18005
18255
  currentElement;
@@ -18028,18 +18278,23 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
18028
18278
  if (thisChangeId !== changeCounter) return;
18029
18279
  var newScope = scope.$new();
18030
18280
 
18031
- transclusion(newScope, function(clone) {
18032
- cleanupLastIncludeContent();
18033
-
18034
- currentScope = newScope;
18035
- currentElement = clone;
18036
-
18037
- currentElement.html(response);
18038
- $animate.enter(currentElement, null, $element, afterAnimation);
18039
- $compile(currentElement.contents())(currentScope);
18040
- currentScope.$emit('$includeContentLoaded');
18041
- scope.$eval(onloadExp);
18042
- });
18281
+ // Note: This will also link all children of ng-include that were contained in the original
18282
+ // html. If that content contains controllers, ... they could pollute/change the scope.
18283
+ // However, using ng-include on an element with additional content does not make sense...
18284
+ // Note: We can't remove them in the cloneAttchFn of $transclude as that
18285
+ // function is called before linking the content, which would apply child
18286
+ // directives to non existing elements.
18287
+ var clone = $transclude(newScope, noop);
18288
+ cleanupLastIncludeContent();
18289
+
18290
+ currentScope = newScope;
18291
+ currentElement = clone;
18292
+
18293
+ currentElement.html(response);
18294
+ $animate.enter(currentElement, null, $element, afterAnimation);
18295
+ $compile(currentElement.contents())(currentScope);
18296
+ currentScope.$emit('$includeContentLoaded');
18297
+ scope.$eval(onloadExp);
18043
18298
  }).error(function() {
18044
18299
  if (thisChangeId === changeCounter) cleanupLastIncludeContent();
18045
18300
  });
@@ -18194,7 +18449,7 @@ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
18194
18449
  * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
18195
18450
  * show "a dozen people are viewing".
18196
18451
  *
18197
- * You can use a set of closed braces(`{}`) as a placeholder for the number that you want substituted
18452
+ * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
18198
18453
  * into pluralized strings. In the previous example, Angular will replace `{}` with
18199
18454
  * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
18200
18455
  * for <span ng-non-bindable>{{numberExpression}}</span>.
@@ -18455,7 +18710,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
18455
18710
  * For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
18456
18711
  * `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
18457
18712
  * with the corresponding item in the array by identity. Moving the same object in array would move the DOM
18458
- * element in the same way ian the DOM.
18713
+ * element in the same way in the DOM.
18459
18714
  *
18460
18715
  * For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
18461
18716
  * case the object identity does not matter. Two objects are considered equivalent as long as their `id`
@@ -18557,8 +18812,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
18557
18812
  priority: 1000,
18558
18813
  terminal: true,
18559
18814
  $$tlb: true,
18560
- compile: function(element, attr, linker) {
18561
- return function($scope, $element, $attr){
18815
+ link: function($scope, $element, $attr, ctrl, $transclude){
18562
18816
  var expression = $attr.ngRepeat;
18563
18817
  var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),
18564
18818
  trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
@@ -18720,7 +18974,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
18720
18974
  // jshint bitwise: true
18721
18975
 
18722
18976
  if (!block.startNode) {
18723
- linker(childScope, function(clone) {
18977
+ $transclude(childScope, function(clone) {
18724
18978
  clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
18725
18979
  $animate.enter(clone, null, jqLite(previousNode));
18726
18980
  previousNode = clone;
@@ -18733,7 +18987,6 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
18733
18987
  }
18734
18988
  lastBlockMap = nextBlockMap;
18735
18989
  });
18736
- };
18737
18990
  }
18738
18991
  };
18739
18992
  }];
@@ -19242,10 +19495,10 @@ var ngSwitchWhenDirective = ngDirective({
19242
19495
  transclude: 'element',
19243
19496
  priority: 800,
19244
19497
  require: '^ngSwitch',
19245
- compile: function(element, attrs, transclude) {
19246
- return function(scope, element, attr, ctrl) {
19498
+ compile: function(element, attrs) {
19499
+ return function(scope, element, attr, ctrl, $transclude) {
19247
19500
  ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
19248
- ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: transclude, element: element });
19501
+ ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
19249
19502
  };
19250
19503
  }
19251
19504
  });
@@ -19254,12 +19507,10 @@ var ngSwitchDefaultDirective = ngDirective({
19254
19507
  transclude: 'element',
19255
19508
  priority: 800,
19256
19509
  require: '^ngSwitch',
19257
- compile: function(element, attrs, transclude) {
19258
- return function(scope, element, attr, ctrl) {
19259
- ctrl.cases['?'] = (ctrl.cases['?'] || []);
19260
- ctrl.cases['?'].push({ transclude: transclude, element: element });
19261
- };
19262
- }
19510
+ link: function(scope, element, attr, ctrl, $transclude) {
19511
+ ctrl.cases['?'] = (ctrl.cases['?'] || []);
19512
+ ctrl.cases['?'].push({ transclude: $transclude, element: element });
19513
+ }
19263
19514
  });
19264
19515
 
19265
19516
  /**
@@ -20028,4 +20279,4 @@ var styleDirective = valueFn({
20028
20279
 
20029
20280
  })(window, document);
20030
20281
 
20031
- !angular.$$csp() && angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}.ng-animate-start{clip:rect(0,auto,auto,0);-ms-zoom:1.0001;}.ng-animate-active{clip:rect(-1px,auto,auto,0);-ms-zoom:1;}</style>');
20282
+ !angular.$$csp() && angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}.ng-animate-start{border-spacing:1px 1px;-ms-zoom:1.0001;}.ng-animate-active{border-spacing:0px 0px;-ms-zoom:1;}</style>');