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,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>');