angularjs-rails 1.4.8 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,10 +1,13 @@
1
1
  /**
2
- * @license AngularJS v1.4.8
3
- * (c) 2010-2015 Google, Inc. http://angularjs.org
2
+ * @license AngularJS v1.5.0
3
+ * (c) 2010-2016 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
6
6
  (function(window, angular, undefined) {'use strict';
7
7
 
8
+ /* global ngTouchClickDirectiveFactory: false,
9
+ */
10
+
8
11
  /**
9
12
  * @ngdoc module
10
13
  * @name ngTouch
@@ -27,10 +30,108 @@
27
30
  /* global -ngTouch */
28
31
  var ngTouch = angular.module('ngTouch', []);
29
32
 
33
+ ngTouch.provider('$touch', $TouchProvider);
34
+
30
35
  function nodeName_(element) {
31
36
  return angular.lowercase(element.nodeName || (element[0] && element[0].nodeName));
32
37
  }
33
38
 
39
+ /**
40
+ * @ngdoc provider
41
+ * @name $touchProvider
42
+ *
43
+ * @description
44
+ * The `$touchProvider` allows enabling / disabling {@link ngTouch.ngClick ngTouch's ngClick directive}.
45
+ */
46
+ $TouchProvider.$inject = ['$provide', '$compileProvider'];
47
+ function $TouchProvider($provide, $compileProvider) {
48
+
49
+ /**
50
+ * @ngdoc method
51
+ * @name $touchProvider#ngClickOverrideEnabled
52
+ *
53
+ * @param {boolean=} enabled update the ngClickOverrideEnabled state if provided, otherwise just return the
54
+ * current ngClickOverrideEnabled state
55
+ * @returns {*} current value if used as getter or itself (chaining) if used as setter
56
+ *
57
+ * @kind function
58
+ *
59
+ * @description
60
+ * Call this method to enable/disable {@link ngTouch.ngClick ngTouch's ngClick directive}. If enabled,
61
+ * the default ngClick directive will be replaced by a version that eliminates the 300ms delay for
62
+ * click events on browser for touch-devices.
63
+ *
64
+ * The default is `false`.
65
+ *
66
+ */
67
+ var ngClickOverrideEnabled = false;
68
+ var ngClickDirectiveAdded = false;
69
+ this.ngClickOverrideEnabled = function(enabled) {
70
+ if (angular.isDefined(enabled)) {
71
+
72
+ if (enabled && !ngClickDirectiveAdded) {
73
+ ngClickDirectiveAdded = true;
74
+
75
+ // Use this to identify the correct directive in the delegate
76
+ ngTouchClickDirectiveFactory.$$moduleName = 'ngTouch';
77
+ $compileProvider.directive('ngClick', ngTouchClickDirectiveFactory);
78
+
79
+ $provide.decorator('ngClickDirective', ['$delegate', function($delegate) {
80
+ if (ngClickOverrideEnabled) {
81
+ // drop the default ngClick directive
82
+ $delegate.shift();
83
+ } else {
84
+ // drop the ngTouch ngClick directive if the override has been re-disabled (because
85
+ // we cannot de-register added directives)
86
+ var i = $delegate.length - 1;
87
+ while (i >= 0) {
88
+ if ($delegate[i].$$moduleName === 'ngTouch') {
89
+ $delegate.splice(i, 1);
90
+ break;
91
+ }
92
+ i--;
93
+ }
94
+ }
95
+
96
+ return $delegate;
97
+ }]);
98
+ }
99
+
100
+ ngClickOverrideEnabled = enabled;
101
+ return this;
102
+ }
103
+
104
+ return ngClickOverrideEnabled;
105
+ };
106
+
107
+ /**
108
+ * @ngdoc service
109
+ * @name $touch
110
+ * @kind object
111
+ *
112
+ * @description
113
+ * Provides the {@link ngTouch.$touch#ngClickOverrideEnabled `ngClickOverrideEnabled`} method.
114
+ *
115
+ */
116
+ this.$get = function() {
117
+ return {
118
+ /**
119
+ * @ngdoc method
120
+ * @name $touch#ngClickOverrideEnabled
121
+ *
122
+ * @returns {*} current value of `ngClickOverrideEnabled` set in the {@link ngTouch.$touchProvider $touchProvider},
123
+ * i.e. if {@link ngTouch.ngClick ngTouch's ngClick} directive is enabled.
124
+ *
125
+ * @kind function
126
+ */
127
+ ngClickOverrideEnabled: function() {
128
+ return ngClickOverrideEnabled;
129
+ }
130
+ };
131
+ };
132
+
133
+ }
134
+
34
135
  /* global ngTouch: false */
35
136
 
36
137
  /**
@@ -43,8 +144,7 @@ function nodeName_(element) {
43
144
  *
44
145
  * Requires the {@link ngTouch `ngTouch`} module to be installed.
45
146
  *
46
- * `$swipe` is used by the `ngSwipeLeft` and `ngSwipeRight` directives in `ngTouch`, and by
47
- * `ngCarousel` in a separate component.
147
+ * `$swipe` is used by the `ngSwipeLeft` and `ngSwipeRight` directives in `ngTouch`.
48
148
  *
49
149
  * # Usage
50
150
  * The `$swipe` service is an object with a single method: `bind`. `bind` takes an element
@@ -203,8 +303,17 @@ ngTouch.factory('$swipe', [function() {
203
303
  /**
204
304
  * @ngdoc directive
205
305
  * @name ngClick
306
+ * @deprecated
206
307
  *
207
308
  * @description
309
+ * <div class="alert alert-danger">
310
+ * **DEPRECATION NOTICE**: Beginning with Angular 1.5, this directive is deprecated and by default **disabled**.
311
+ * The directive will receive no further support and might be removed from future releases.
312
+ * If you need the directive, you can enable it with the {@link ngTouch.$touchProvider $touchProvider#ngClickOverrideEnabled}
313
+ * function. We also recommend that you migrate to [FastClick](https://github.com/ftlabs/fastclick).
314
+ * To learn more about the 300ms delay, this [Telerik article](http://developer.telerik.com/featured/300-ms-click-delay-ios-8/)
315
+ * gives a good overview.
316
+ * </div>
208
317
  * A more powerful replacement for the default ngClick designed to be used on touchscreen
209
318
  * devices. Most mobile browsers wait about 300ms after a tap-and-release before sending
210
319
  * the click event. This version handles them immediately, and then prevents the
@@ -236,15 +345,7 @@ ngTouch.factory('$swipe', [function() {
236
345
  </example>
237
346
  */
238
347
 
239
- ngTouch.config(['$provide', function($provide) {
240
- $provide.decorator('ngClickDirective', ['$delegate', function($delegate) {
241
- // drop the default ngClick directive
242
- $delegate.shift();
243
- return $delegate;
244
- }]);
245
- }]);
246
-
247
- ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
348
+ var ngTouchClickDirectiveFactory = ['$parse', '$timeout', '$rootElement',
248
349
  function($parse, $timeout, $rootElement) {
249
350
  var TAP_DURATION = 750; // Shorter than 750ms is a tap, longer is a taphold or drag.
250
351
  var MOVE_TOLERANCE = 12; // 12px seems to work in most mobile browsers.
@@ -488,7 +589,7 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
488
589
  });
489
590
 
490
591
  };
491
- }]);
592
+ }];
492
593
 
493
594
  /* global ngTouch: false */
494
595
 
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @license AngularJS v1.4.8
3
- * (c) 2010-2015 Google, Inc. http://angularjs.org
2
+ * @license AngularJS v1.5.0
3
+ * (c) 2010-2016 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
6
6
  (function(window, document, undefined) {'use strict';
@@ -57,7 +57,7 @@ function minErr(module, ErrorConstructor) {
57
57
  return match;
58
58
  });
59
59
 
60
- message += '\nhttp://errors.angularjs.org/1.4.8/' +
60
+ message += '\nhttp://errors.angularjs.org/1.5.0/' +
61
61
  (module ? module + '/' : '') + code;
62
62
 
63
63
  for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
@@ -188,29 +188,9 @@ var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
188
188
  // This is used so that it's possible for internal tests to create mock ValidityStates.
189
189
  var VALIDITY_STATE_PROPERTY = 'validity';
190
190
 
191
- /**
192
- * @ngdoc function
193
- * @name angular.lowercase
194
- * @module ng
195
- * @kind function
196
- *
197
- * @description Converts the specified string to lowercase.
198
- * @param {string} string String to be converted to lowercase.
199
- * @returns {string} Lowercased string.
200
- */
201
- var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
202
191
  var hasOwnProperty = Object.prototype.hasOwnProperty;
203
192
 
204
- /**
205
- * @ngdoc function
206
- * @name angular.uppercase
207
- * @module ng
208
- * @kind function
209
- *
210
- * @description Converts the specified string to uppercase.
211
- * @param {string} string String to be converted to uppercase.
212
- * @returns {string} Uppercased string.
213
- */
193
+ var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
214
194
  var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
215
195
 
216
196
 
@@ -230,7 +210,7 @@ var manualUppercase = function(s) {
230
210
 
231
211
  // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
232
212
  // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
233
- // with correct but slower alternatives.
213
+ // with correct but slower alternatives. See https://github.com/angular/angular.js/issues/11387
234
214
  if ('i' !== 'I'.toLowerCase()) {
235
215
  lowercase = manualLowercase;
236
216
  uppercase = manualUppercase;
@@ -273,7 +253,7 @@ function isArrayLike(obj) {
273
253
 
274
254
  // arrays, strings and jQuery/jqLite objects are array like
275
255
  // * jqLite is either the jQuery or jqLite constructor function
276
- // * we have to check the existance of jqLite first as this method is called
256
+ // * we have to check the existence of jqLite first as this method is called
277
257
  // via the forEach method when constructing the jqLite object in the first place
278
258
  if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;
279
259
 
@@ -284,7 +264,8 @@ function isArrayLike(obj) {
284
264
  // NodeList objects (with `item` method) and
285
265
  // other objects with suitable length characteristics are array-like
286
266
  return isNumber(length) &&
287
- (length >= 0 && (length - 1) in obj || typeof obj.item == 'function');
267
+ (length >= 0 && ((length - 1) in obj || obj instanceof Array) || typeof obj.item == 'function');
268
+
288
269
  }
289
270
 
290
271
  /**
@@ -381,7 +362,7 @@ function forEachSorted(obj, iterator, context) {
381
362
  * @returns {function(*, string)}
382
363
  */
383
364
  function reverseParams(iteratorFn) {
384
- return function(value, key) { iteratorFn(key, value); };
365
+ return function(value, key) {iteratorFn(key, value);};
385
366
  }
386
367
 
387
368
  /**
@@ -752,6 +733,10 @@ function isTypedArray(value) {
752
733
  return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
753
734
  }
754
735
 
736
+ function isArrayBuffer(obj) {
737
+ return toString.call(obj) === '[object ArrayBuffer]';
738
+ }
739
+
755
740
 
756
741
  var trim = function(value) {
757
742
  return isString(value) ? value.trim() : value;
@@ -789,7 +774,7 @@ function isElement(node) {
789
774
  * @returns {object} in the form of {key1:true, key2:true, ...}
790
775
  */
791
776
  function makeMap(str) {
792
- var obj = {}, items = str.split(","), i;
777
+ var obj = {}, items = str.split(','), i;
793
778
  for (i = 0; i < items.length; i++) {
794
779
  obj[items[i]] = true;
795
780
  }
@@ -876,7 +861,7 @@ function copy(source, destination) {
876
861
  var stackDest = [];
877
862
 
878
863
  if (destination) {
879
- if (isTypedArray(destination)) {
864
+ if (isTypedArray(destination) || isArrayBuffer(destination)) {
880
865
  throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated.");
881
866
  }
882
867
  if (source === destination) {
@@ -950,22 +935,10 @@ function copy(source, destination) {
950
935
  }
951
936
 
952
937
  var needsRecurse = false;
953
- var destination;
938
+ var destination = copyType(source);
954
939
 
955
- if (isArray(source)) {
956
- destination = [];
957
- needsRecurse = true;
958
- } else if (isTypedArray(source)) {
959
- destination = new source.constructor(source);
960
- } else if (isDate(source)) {
961
- destination = new Date(source.getTime());
962
- } else if (isRegExp(source)) {
963
- destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
964
- destination.lastIndex = source.lastIndex;
965
- } else if (isFunction(source.cloneNode)) {
966
- destination = source.cloneNode(true);
967
- } else {
968
- destination = Object.create(getPrototypeOf(source));
940
+ if (destination === undefined) {
941
+ destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
969
942
  needsRecurse = true;
970
943
  }
971
944
 
@@ -976,6 +949,45 @@ function copy(source, destination) {
976
949
  ? copyRecurse(source, destination)
977
950
  : destination;
978
951
  }
952
+
953
+ function copyType(source) {
954
+ switch (toString.call(source)) {
955
+ case '[object Int8Array]':
956
+ case '[object Int16Array]':
957
+ case '[object Int32Array]':
958
+ case '[object Float32Array]':
959
+ case '[object Float64Array]':
960
+ case '[object Uint8Array]':
961
+ case '[object Uint8ClampedArray]':
962
+ case '[object Uint16Array]':
963
+ case '[object Uint32Array]':
964
+ return new source.constructor(copyElement(source.buffer));
965
+
966
+ case '[object ArrayBuffer]':
967
+ //Support: IE10
968
+ if (!source.slice) {
969
+ var copied = new ArrayBuffer(source.byteLength);
970
+ new Uint8Array(copied).set(new Uint8Array(source));
971
+ return copied;
972
+ }
973
+ return source.slice(0);
974
+
975
+ case '[object Boolean]':
976
+ case '[object Number]':
977
+ case '[object String]':
978
+ case '[object Date]':
979
+ return new source.constructor(source.valueOf());
980
+
981
+ case '[object RegExp]':
982
+ var re = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
983
+ re.lastIndex = source.lastIndex;
984
+ return re;
985
+ }
986
+
987
+ if (isFunction(source.cloneNode)) {
988
+ return source.cloneNode(true);
989
+ }
990
+ }
979
991
  }
980
992
 
981
993
  /**
@@ -1038,38 +1050,37 @@ function equals(o1, o2) {
1038
1050
  if (o1 === null || o2 === null) return false;
1039
1051
  if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
1040
1052
  var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
1041
- if (t1 == t2) {
1042
- if (t1 == 'object') {
1043
- if (isArray(o1)) {
1044
- if (!isArray(o2)) return false;
1045
- if ((length = o1.length) == o2.length) {
1046
- for (key = 0; key < length; key++) {
1047
- if (!equals(o1[key], o2[key])) return false;
1048
- }
1049
- return true;
1050
- }
1051
- } else if (isDate(o1)) {
1052
- if (!isDate(o2)) return false;
1053
- return equals(o1.getTime(), o2.getTime());
1054
- } else if (isRegExp(o1)) {
1055
- return isRegExp(o2) ? o1.toString() == o2.toString() : false;
1056
- } else {
1057
- if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
1058
- isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
1059
- keySet = createMap();
1060
- for (key in o1) {
1061
- if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
1053
+ if (t1 == t2 && t1 == 'object') {
1054
+ if (isArray(o1)) {
1055
+ if (!isArray(o2)) return false;
1056
+ if ((length = o1.length) == o2.length) {
1057
+ for (key = 0; key < length; key++) {
1062
1058
  if (!equals(o1[key], o2[key])) return false;
1063
- keySet[key] = true;
1064
- }
1065
- for (key in o2) {
1066
- if (!(key in keySet) &&
1067
- key.charAt(0) !== '$' &&
1068
- isDefined(o2[key]) &&
1069
- !isFunction(o2[key])) return false;
1070
1059
  }
1071
1060
  return true;
1072
1061
  }
1062
+ } else if (isDate(o1)) {
1063
+ if (!isDate(o2)) return false;
1064
+ return equals(o1.getTime(), o2.getTime());
1065
+ } else if (isRegExp(o1)) {
1066
+ if (!isRegExp(o2)) return false;
1067
+ return o1.toString() == o2.toString();
1068
+ } else {
1069
+ if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
1070
+ isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
1071
+ keySet = createMap();
1072
+ for (key in o1) {
1073
+ if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
1074
+ if (!equals(o1[key], o2[key])) return false;
1075
+ keySet[key] = true;
1076
+ }
1077
+ for (key in o2) {
1078
+ if (!(key in keySet) &&
1079
+ key.charAt(0) !== '$' &&
1080
+ isDefined(o2[key]) &&
1081
+ !isFunction(o2[key])) return false;
1082
+ }
1083
+ return true;
1073
1084
  }
1074
1085
  }
1075
1086
  return false;
@@ -1246,7 +1257,7 @@ function toJsonReplacer(key, value) {
1246
1257
  * @returns {string|undefined} JSON-ified string representing `obj`.
1247
1258
  */
1248
1259
  function toJson(obj, pretty) {
1249
- if (typeof obj === 'undefined') return undefined;
1260
+ if (isUndefined(obj)) return undefined;
1250
1261
  if (!isNumber(pretty)) {
1251
1262
  pretty = pretty ? 2 : null;
1252
1263
  }
@@ -1273,7 +1284,10 @@ function fromJson(json) {
1273
1284
  }
1274
1285
 
1275
1286
 
1287
+ var ALL_COLONS = /:/g;
1276
1288
  function timezoneToOffset(timezone, fallback) {
1289
+ // IE/Edge do not "understand" colon (`:`) in timezone
1290
+ timezone = timezone.replace(ALL_COLONS, '');
1277
1291
  var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
1278
1292
  return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
1279
1293
  }
@@ -1288,8 +1302,9 @@ function addDateMinutes(date, minutes) {
1288
1302
 
1289
1303
  function convertTimezoneToLocal(date, timezone, reverse) {
1290
1304
  reverse = reverse ? -1 : 1;
1291
- var timezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
1292
- return addDateMinutes(date, reverse * (timezoneOffset - date.getTimezoneOffset()));
1305
+ var dateTimezoneOffset = date.getTimezoneOffset();
1306
+ var timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
1307
+ return addDateMinutes(date, reverse * (timezoneOffset - dateTimezoneOffset));
1293
1308
  }
1294
1309
 
1295
1310
 
@@ -1308,7 +1323,7 @@ function startingTag(element) {
1308
1323
  return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
1309
1324
  elemHtml.
1310
1325
  match(/^(<[^>]+>)/)[1].
1311
- replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
1326
+ replace(/^<([\w\-]+)/, function(match, nodeName) {return '<' + lowercase(nodeName);});
1312
1327
  } catch (e) {
1313
1328
  return lowercase(elemHtml);
1314
1329
  }
@@ -1751,7 +1766,6 @@ function snake_case(name, separator) {
1751
1766
  }
1752
1767
 
1753
1768
  var bindJQueryFired = false;
1754
- var skipDestroyOnNextJQueryCleanData;
1755
1769
  function bindJQuery() {
1756
1770
  var originalCleanData;
1757
1771
 
@@ -1785,15 +1799,11 @@ function bindJQuery() {
1785
1799
  originalCleanData = jQuery.cleanData;
1786
1800
  jQuery.cleanData = function(elems) {
1787
1801
  var events;
1788
- if (!skipDestroyOnNextJQueryCleanData) {
1789
- for (var i = 0, elem; (elem = elems[i]) != null; i++) {
1790
- events = jQuery._data(elem, "events");
1791
- if (events && events.$destroy) {
1792
- jQuery(elem).triggerHandler('$destroy');
1793
- }
1802
+ for (var i = 0, elem; (elem = elems[i]) != null; i++) {
1803
+ events = jQuery._data(elem, "events");
1804
+ if (events && events.$destroy) {
1805
+ jQuery(elem).triggerHandler('$destroy');
1794
1806
  }
1795
- } else {
1796
- skipDestroyOnNextJQueryCleanData = false;
1797
1807
  }
1798
1808
  originalCleanData(elems);
1799
1809
  };
@@ -1987,7 +1997,7 @@ function setupModuleLoader(window) {
1987
1997
  * unspecified then the module is being retrieved for further configuration.
1988
1998
  * @param {Function=} configFn Optional configuration function for the module. Same as
1989
1999
  * {@link angular.Module#config Module#config()}.
1990
- * @returns {module} new module with the {@link angular.Module} api.
2000
+ * @returns {angular.Module} new module with the {@link angular.Module} api.
1991
2001
  */
1992
2002
  return function module(name, requires, configFn) {
1993
2003
  var assertNotHasOwnProperty = function(name, context) {
@@ -2193,6 +2203,19 @@ function setupModuleLoader(window) {
2193
2203
  */
2194
2204
  directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
2195
2205
 
2206
+ /**
2207
+ * @ngdoc method
2208
+ * @name angular.Module#component
2209
+ * @module ng
2210
+ * @param {string} name Name of the component in camel-case (i.e. myComp which will match as my-comp)
2211
+ * @param {Object} options Component definition object (a simplified
2212
+ * {@link ng.$compile#directive-definition-object directive definition object})
2213
+ *
2214
+ * @description
2215
+ * See {@link ng.$compileProvider#component $compileProvider.component()}.
2216
+ */
2217
+ component: invokeLaterAndSetModuleName('$compileProvider', 'component'),
2218
+
2196
2219
  /**
2197
2220
  * @ngdoc method
2198
2221
  * @name angular.Module#config
@@ -2344,11 +2367,14 @@ function toDebugString(obj) {
2344
2367
  $AnchorScrollProvider,
2345
2368
  $AnimateProvider,
2346
2369
  $CoreAnimateCssProvider,
2370
+ $$CoreAnimateJsProvider,
2347
2371
  $$CoreAnimateQueueProvider,
2348
- $$CoreAnimateRunnerProvider,
2372
+ $$AnimateRunnerFactoryProvider,
2373
+ $$AnimateAsyncRunFactoryProvider,
2349
2374
  $BrowserProvider,
2350
2375
  $CacheFactoryProvider,
2351
2376
  $ControllerProvider,
2377
+ $DateProvider,
2352
2378
  $DocumentProvider,
2353
2379
  $ExceptionHandlerProvider,
2354
2380
  $FilterProvider,
@@ -2398,11 +2424,11 @@ function toDebugString(obj) {
2398
2424
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
2399
2425
  */
2400
2426
  var version = {
2401
- full: '1.4.8', // all of these placeholder strings will be replaced by grunt's
2427
+ full: '1.5.0', // all of these placeholder strings will be replaced by grunt's
2402
2428
  major: 1, // package task
2403
- minor: 4,
2404
- dot: 8,
2405
- codeName: 'ice-manipulation'
2429
+ minor: 5,
2430
+ dot: 0,
2431
+ codeName: 'ennoblement-facilitation'
2406
2432
  };
2407
2433
 
2408
2434
 
@@ -2504,8 +2530,10 @@ function publishExternalAPI(angular) {
2504
2530
  $anchorScroll: $AnchorScrollProvider,
2505
2531
  $animate: $AnimateProvider,
2506
2532
  $animateCss: $CoreAnimateCssProvider,
2533
+ $$animateJs: $$CoreAnimateJsProvider,
2507
2534
  $$animateQueue: $$CoreAnimateQueueProvider,
2508
- $$AnimateRunner: $$CoreAnimateRunnerProvider,
2535
+ $$AnimateRunner: $$AnimateRunnerFactoryProvider,
2536
+ $$animateAsyncRun: $$AnimateAsyncRunFactoryProvider,
2509
2537
  $browser: $BrowserProvider,
2510
2538
  $cacheFactory: $CacheFactoryProvider,
2511
2539
  $controller: $ControllerProvider,
@@ -2576,16 +2604,22 @@ function publishExternalAPI(angular) {
2576
2604
  *
2577
2605
  * If jQuery is available, `angular.element` is an alias for the
2578
2606
  * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
2579
- * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
2607
+ * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or **jqLite**.
2580
2608
  *
2581
- * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
2582
- * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
2583
- * commonly needed functionality with the goal of having a very small footprint.</div>
2609
+ * jqLite is a tiny, API-compatible subset of jQuery that allows
2610
+ * Angular to manipulate the DOM in a cross-browser compatible way. jqLite implements only the most
2611
+ * commonly needed functionality with the goal of having a very small footprint.
2584
2612
  *
2585
- * To use `jQuery`, simply ensure it is loaded before the `angular.js` file.
2613
+ * To use `jQuery`, simply ensure it is loaded before the `angular.js` file. You can also use the
2614
+ * {@link ngJq `ngJq`} directive to specify that jqlite should be used over jQuery, or to use a
2615
+ * specific version of jQuery if multiple versions exist on the page.
2586
2616
  *
2587
- * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
2588
- * jqLite; they are never raw DOM references.</div>
2617
+ * <div class="alert alert-info">**Note:** All element references in Angular are always wrapped with jQuery or
2618
+ * jqLite (such as the element argument in a directive's compile / link function). They are never raw DOM references.</div>
2619
+ *
2620
+ * <div class="alert alert-warning">**Note:** Keep in mind that this function will not find elements
2621
+ * by tag name / CSS selector. For lookups by tag name, try instead `angular.element(document).find(...)`
2622
+ * or `$document.find()`, or use the standard DOM APIs, e.g. `document.querySelectorAll()`.</div>
2589
2623
  *
2590
2624
  * ## Angular's jqLite
2591
2625
  * jqLite provides only the following jQuery methods:
@@ -2598,7 +2632,8 @@ function publishExternalAPI(angular) {
2598
2632
  * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
2599
2633
  * - [`clone()`](http://api.jquery.com/clone/)
2600
2634
  * - [`contents()`](http://api.jquery.com/contents/)
2601
- * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`. As a setter, does not convert numbers to strings or append 'px'.
2635
+ * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`.
2636
+ * As a setter, does not convert numbers to strings or append 'px', and also does not have automatic property prefixing.
2602
2637
  * - [`data()`](http://api.jquery.com/data/)
2603
2638
  * - [`detach()`](http://api.jquery.com/detach/)
2604
2639
  * - [`empty()`](http://api.jquery.com/empty/)
@@ -2732,6 +2767,12 @@ function jqLiteHasData(node) {
2732
2767
  return false;
2733
2768
  }
2734
2769
 
2770
+ function jqLiteCleanData(nodes) {
2771
+ for (var i = 0, ii = nodes.length; i < ii; i++) {
2772
+ jqLiteRemoveData(nodes[i]);
2773
+ }
2774
+ }
2775
+
2735
2776
  function jqLiteBuildFragment(html, context) {
2736
2777
  var tmp, tag, wrap,
2737
2778
  fragment = context.createDocumentFragment(),
@@ -2784,6 +2825,16 @@ function jqLiteParseHTML(html, context) {
2784
2825
  return [];
2785
2826
  }
2786
2827
 
2828
+ function jqLiteWrapNode(node, wrapper) {
2829
+ var parent = node.parentNode;
2830
+
2831
+ if (parent) {
2832
+ parent.replaceChild(wrapper, node);
2833
+ }
2834
+
2835
+ wrapper.appendChild(node);
2836
+ }
2837
+
2787
2838
 
2788
2839
  // IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
2789
2840
  var jqLiteContains = Node.prototype.contains || function(arg) {
@@ -3034,7 +3085,7 @@ function jqLiteRemove(element, keepData) {
3034
3085
  function jqLiteDocumentLoaded(action, win) {
3035
3086
  win = win || window;
3036
3087
  if (win.document.readyState === 'complete') {
3037
- // Force the action to be run async for consistent behaviour
3088
+ // Force the action to be run async for consistent behavior
3038
3089
  // from the action's point of view
3039
3090
  // i.e. it will definitely not be in a $apply
3040
3091
  win.setTimeout(action);
@@ -3120,7 +3171,8 @@ function getAliasedAttrName(name) {
3120
3171
  forEach({
3121
3172
  data: jqLiteData,
3122
3173
  removeData: jqLiteRemoveData,
3123
- hasData: jqLiteHasData
3174
+ hasData: jqLiteHasData,
3175
+ cleanData: jqLiteCleanData
3124
3176
  }, function(fn, name) {
3125
3177
  JQLite[name] = fn;
3126
3178
  });
@@ -3475,12 +3527,7 @@ forEach({
3475
3527
  },
3476
3528
 
3477
3529
  wrap: function(element, wrapNode) {
3478
- wrapNode = jqLite(wrapNode).eq(0).clone()[0];
3479
- var parent = element.parentNode;
3480
- if (parent) {
3481
- parent.replaceChild(wrapNode, element);
3482
- }
3483
- wrapNode.appendChild(element);
3530
+ jqLiteWrapNode(element, jqLite(wrapNode).eq(0).clone()[0]);
3484
3531
  },
3485
3532
 
3486
3533
  remove: jqLiteRemove,
@@ -3758,17 +3805,23 @@ var $$HashMapProvider = [function() {
3758
3805
  * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
3759
3806
  */
3760
3807
 
3808
+ var ARROW_ARG = /^([^\(]+?)=>/;
3761
3809
  var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m;
3762
3810
  var FN_ARG_SPLIT = /,/;
3763
3811
  var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
3764
3812
  var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
3765
3813
  var $injectorMinErr = minErr('$injector');
3766
3814
 
3815
+ function extractArgs(fn) {
3816
+ var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
3817
+ args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS);
3818
+ return args;
3819
+ }
3820
+
3767
3821
  function anonFn(fn) {
3768
3822
  // For anonymous functions, showing at the very least the function signature can help in
3769
3823
  // debugging.
3770
- var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
3771
- args = fnText.match(FN_ARGS);
3824
+ var args = extractArgs(fn);
3772
3825
  if (args) {
3773
3826
  return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
3774
3827
  }
@@ -3777,7 +3830,6 @@ function anonFn(fn) {
3777
3830
 
3778
3831
  function annotate(fn, strictDi, name) {
3779
3832
  var $inject,
3780
- fnText,
3781
3833
  argDecl,
3782
3834
  last;
3783
3835
 
@@ -3792,8 +3844,7 @@ function annotate(fn, strictDi, name) {
3792
3844
  throw $injectorMinErr('strictdi',
3793
3845
  '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
3794
3846
  }
3795
- fnText = fn.toString().replace(STRIP_COMMENTS, '');
3796
- argDecl = fnText.match(FN_ARGS);
3847
+ argDecl = extractArgs(fn);
3797
3848
  forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
3798
3849
  arg.replace(FN_ARG, function(all, underscore, name) {
3799
3850
  $inject.push(name);
@@ -4183,8 +4234,20 @@ function annotate(fn, strictDi, name) {
4183
4234
  *
4184
4235
  * Register a **service constructor**, which will be invoked with `new` to create the service
4185
4236
  * instance.
4186
- * This is short for registering a service where its provider's `$get` property is the service
4187
- * constructor function that will be used to instantiate the service instance.
4237
+ * This is short for registering a service where its provider's `$get` property is a factory
4238
+ * function that returns an instance instantiated by the injector from the service constructor
4239
+ * function.
4240
+ *
4241
+ * Internally it looks a bit like this:
4242
+ *
4243
+ * ```
4244
+ * {
4245
+ * $get: function() {
4246
+ * return $injector.instantiate(constructor);
4247
+ * }
4248
+ * }
4249
+ * ```
4250
+ *
4188
4251
  *
4189
4252
  * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
4190
4253
  * as a type/class.
@@ -4285,7 +4348,7 @@ function annotate(fn, strictDi, name) {
4285
4348
  * @description
4286
4349
  *
4287
4350
  * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
4288
- * intercepts the creation of a service, allowing it to override or modify the behaviour of the
4351
+ * intercepts the creation of a service, allowing it to override or modify the behavior of the
4289
4352
  * service. The object returned by the decorator may be the original service, or a new service
4290
4353
  * object which replaces or wraps and delegates to the original service.
4291
4354
  *
@@ -4334,14 +4397,19 @@ function createInjector(modulesToLoad, strictDi) {
4334
4397
  throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
4335
4398
  })),
4336
4399
  instanceCache = {},
4337
- instanceInjector = (instanceCache.$injector =
4400
+ protoInstanceInjector =
4338
4401
  createInternalInjector(instanceCache, function(serviceName, caller) {
4339
4402
  var provider = providerInjector.get(serviceName + providerSuffix, caller);
4340
- return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
4341
- }));
4342
-
4403
+ return instanceInjector.invoke(
4404
+ provider.$get, provider, undefined, serviceName);
4405
+ }),
4406
+ instanceInjector = protoInstanceInjector;
4343
4407
 
4344
- forEach(loadModules(modulesToLoad), function(fn) { if (fn) instanceInjector.invoke(fn); });
4408
+ providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) };
4409
+ var runBlocks = loadModules(modulesToLoad);
4410
+ instanceInjector = protoInstanceInjector.get('$injector');
4411
+ instanceInjector.strictDi = strictDi;
4412
+ forEach(runBlocks, function(fn) { if (fn) instanceInjector.invoke(fn); });
4345
4413
 
4346
4414
  return instanceInjector;
4347
4415
 
@@ -4491,48 +4559,67 @@ function createInjector(modulesToLoad, strictDi) {
4491
4559
  }
4492
4560
  }
4493
4561
 
4494
- function invoke(fn, self, locals, serviceName) {
4495
- if (typeof locals === 'string') {
4496
- serviceName = locals;
4497
- locals = null;
4498
- }
4499
4562
 
4563
+ function injectionArgs(fn, locals, serviceName) {
4500
4564
  var args = [],
4501
- $inject = createInjector.$$annotate(fn, strictDi, serviceName),
4502
- length, i,
4503
- key;
4565
+ $inject = createInjector.$$annotate(fn, strictDi, serviceName);
4504
4566
 
4505
- for (i = 0, length = $inject.length; i < length; i++) {
4506
- key = $inject[i];
4567
+ for (var i = 0, length = $inject.length; i < length; i++) {
4568
+ var key = $inject[i];
4507
4569
  if (typeof key !== 'string') {
4508
4570
  throw $injectorMinErr('itkn',
4509
4571
  'Incorrect injection token! Expected service name as string, got {0}', key);
4510
4572
  }
4511
- args.push(
4512
- locals && locals.hasOwnProperty(key)
4513
- ? locals[key]
4514
- : getService(key, serviceName)
4515
- );
4573
+ args.push(locals && locals.hasOwnProperty(key) ? locals[key] :
4574
+ getService(key, serviceName));
4575
+ }
4576
+ return args;
4577
+ }
4578
+
4579
+ function isClass(func) {
4580
+ // IE 9-11 do not support classes and IE9 leaks with the code below.
4581
+ if (msie <= 11) {
4582
+ return false;
4516
4583
  }
4584
+ // Workaround for MS Edge.
4585
+ // Check https://connect.microsoft.com/IE/Feedback/Details/2211653
4586
+ return typeof func === 'function'
4587
+ && /^(?:class\s|constructor\()/.test(Function.prototype.toString.call(func));
4588
+ }
4589
+
4590
+ function invoke(fn, self, locals, serviceName) {
4591
+ if (typeof locals === 'string') {
4592
+ serviceName = locals;
4593
+ locals = null;
4594
+ }
4595
+
4596
+ var args = injectionArgs(fn, locals, serviceName);
4517
4597
  if (isArray(fn)) {
4518
- fn = fn[length];
4598
+ fn = fn[fn.length - 1];
4519
4599
  }
4520
4600
 
4521
- // http://jsperf.com/angularjs-invoke-apply-vs-switch
4522
- // #5388
4523
- return fn.apply(self, args);
4601
+ if (!isClass(fn)) {
4602
+ // http://jsperf.com/angularjs-invoke-apply-vs-switch
4603
+ // #5388
4604
+ return fn.apply(self, args);
4605
+ } else {
4606
+ args.unshift(null);
4607
+ return new (Function.prototype.bind.apply(fn, args))();
4608
+ }
4524
4609
  }
4525
4610
 
4611
+
4526
4612
  function instantiate(Type, locals, serviceName) {
4527
4613
  // Check if Type is annotated and use just the given function at n-1 as parameter
4528
4614
  // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
4529
- // Object creation: http://jsperf.com/create-constructor/2
4530
- var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null);
4531
- var returnedValue = invoke(Type, instance, locals, serviceName);
4532
-
4533
- return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
4615
+ var ctor = (isArray(Type) ? Type[Type.length - 1] : Type);
4616
+ var args = injectionArgs(Type, locals, serviceName);
4617
+ // Empty object at position 0 is ignored for invocation with `new`, but required.
4618
+ args.unshift(null);
4619
+ return new (Function.prototype.bind.apply(ctor, args))();
4534
4620
  }
4535
4621
 
4622
+
4536
4623
  return {
4537
4624
  invoke: invoke,
4538
4625
  instantiate: instantiate,
@@ -4871,27 +4958,8 @@ function prepareAnimateOptions(options) {
4871
4958
  : {};
4872
4959
  }
4873
4960
 
4874
- var $$CoreAnimateRunnerProvider = function() {
4875
- this.$get = ['$q', '$$rAF', function($q, $$rAF) {
4876
- function AnimateRunner() {}
4877
- AnimateRunner.all = noop;
4878
- AnimateRunner.chain = noop;
4879
- AnimateRunner.prototype = {
4880
- end: noop,
4881
- cancel: noop,
4882
- resume: noop,
4883
- pause: noop,
4884
- complete: noop,
4885
- then: function(pass, fail) {
4886
- return $q(function(resolve) {
4887
- $$rAF(function() {
4888
- resolve();
4889
- });
4890
- }).then(pass, fail);
4891
- }
4892
- };
4893
- return AnimateRunner;
4894
- }];
4961
+ var $$CoreAnimateJsProvider = function() {
4962
+ this.$get = function() {};
4895
4963
  };
4896
4964
 
4897
4965
  // this is prefixed with Core since it conflicts with
@@ -4919,7 +4987,12 @@ var $$CoreAnimateQueueProvider = function() {
4919
4987
  addRemoveClassesPostDigest(element, options.addClass, options.removeClass);
4920
4988
  }
4921
4989
 
4922
- return new $$AnimateRunner(); // jshint ignore:line
4990
+ var runner = new $$AnimateRunner(); // jshint ignore:line
4991
+
4992
+ // since there are no animations to run the runner needs to be
4993
+ // notified that the animation call is complete.
4994
+ runner.complete();
4995
+ return runner;
4923
4996
  }
4924
4997
  };
4925
4998
 
@@ -5161,8 +5234,8 @@ var $AnimateProvider = ['$provide', function($provide) {
5161
5234
  * // remove all the animation event listeners listening for `enter` on the given element and its children
5162
5235
  * $animate.off('enter', container);
5163
5236
  *
5164
- * // remove the event listener function provided by `listenerFn` that is set
5165
- * // to listen for `enter` on the given `element` as well as its children
5237
+ * // remove the event listener function provided by `callback` that is set
5238
+ * // to listen for `enter` on the given `container` as well as its children
5166
5239
  * $animate.off('enter', container, callback);
5167
5240
  * ```
5168
5241
  *
@@ -5384,17 +5457,30 @@ var $AnimateProvider = ['$provide', function($provide) {
5384
5457
  * @kind function
5385
5458
  *
5386
5459
  * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.
5387
- * If any detected CSS transition, keyframe or JavaScript matches the provided className value then the animation will take
5388
- * on the provided styles. For example, if a transition animation is set for the given className then the provided from and
5389
- * to styles will be applied alongside the given transition. If a JavaScript animation is detected then the provided styles
5390
- * will be given in as function paramters into the `animate` method (or as apart of the `options` parameter).
5460
+ * If any detected CSS transition, keyframe or JavaScript matches the provided className value, then the animation will take
5461
+ * on the provided styles. For example, if a transition animation is set for the given classNamem, then the provided `from` and
5462
+ * `to` styles will be applied alongside the given transition. If the CSS style provided in `from` does not have a corresponding
5463
+ * style in `to`, the style in `from` is applied immediately, and no animation is run.
5464
+ * If a JavaScript animation is detected then the provided styles will be given in as function parameters into the `animate`
5465
+ * method (or as part of the `options` parameter):
5466
+ *
5467
+ * ```js
5468
+ * ngModule.animation('.my-inline-animation', function() {
5469
+ * return {
5470
+ * animate : function(element, from, to, done, options) {
5471
+ * //animation
5472
+ * done();
5473
+ * }
5474
+ * }
5475
+ * });
5476
+ * ```
5391
5477
  *
5392
5478
  * @param {DOMElement} element the element which the CSS styles will be applied to
5393
5479
  * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation.
5394
5480
  * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.
5395
5481
  * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
5396
5482
  * this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
5397
- * (Note that if no animation is detected then this value will not be appplied to the element.)
5483
+ * (Note that if no animation is detected then this value will not be applied to the element.)
5398
5484
  * @param {object=} options an optional collection of options/styles that will be applied to the element
5399
5485
  *
5400
5486
  * @return {Promise} the animation callback promise
@@ -5412,6 +5498,190 @@ var $AnimateProvider = ['$provide', function($provide) {
5412
5498
  }];
5413
5499
  }];
5414
5500
 
5501
+ var $$AnimateAsyncRunFactoryProvider = function() {
5502
+ this.$get = ['$$rAF', function($$rAF) {
5503
+ var waitQueue = [];
5504
+
5505
+ function waitForTick(fn) {
5506
+ waitQueue.push(fn);
5507
+ if (waitQueue.length > 1) return;
5508
+ $$rAF(function() {
5509
+ for (var i = 0; i < waitQueue.length; i++) {
5510
+ waitQueue[i]();
5511
+ }
5512
+ waitQueue = [];
5513
+ });
5514
+ }
5515
+
5516
+ return function() {
5517
+ var passed = false;
5518
+ waitForTick(function() {
5519
+ passed = true;
5520
+ });
5521
+ return function(callback) {
5522
+ passed ? callback() : waitForTick(callback);
5523
+ };
5524
+ };
5525
+ }];
5526
+ };
5527
+
5528
+ var $$AnimateRunnerFactoryProvider = function() {
5529
+ this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$document', '$timeout',
5530
+ function($q, $sniffer, $$animateAsyncRun, $document, $timeout) {
5531
+
5532
+ var INITIAL_STATE = 0;
5533
+ var DONE_PENDING_STATE = 1;
5534
+ var DONE_COMPLETE_STATE = 2;
5535
+
5536
+ AnimateRunner.chain = function(chain, callback) {
5537
+ var index = 0;
5538
+
5539
+ next();
5540
+ function next() {
5541
+ if (index === chain.length) {
5542
+ callback(true);
5543
+ return;
5544
+ }
5545
+
5546
+ chain[index](function(response) {
5547
+ if (response === false) {
5548
+ callback(false);
5549
+ return;
5550
+ }
5551
+ index++;
5552
+ next();
5553
+ });
5554
+ }
5555
+ };
5556
+
5557
+ AnimateRunner.all = function(runners, callback) {
5558
+ var count = 0;
5559
+ var status = true;
5560
+ forEach(runners, function(runner) {
5561
+ runner.done(onProgress);
5562
+ });
5563
+
5564
+ function onProgress(response) {
5565
+ status = status && response;
5566
+ if (++count === runners.length) {
5567
+ callback(status);
5568
+ }
5569
+ }
5570
+ };
5571
+
5572
+ function AnimateRunner(host) {
5573
+ this.setHost(host);
5574
+
5575
+ var rafTick = $$animateAsyncRun();
5576
+ var timeoutTick = function(fn) {
5577
+ $timeout(fn, 0, false);
5578
+ };
5579
+
5580
+ this._doneCallbacks = [];
5581
+ this._tick = function(fn) {
5582
+ var doc = $document[0];
5583
+
5584
+ // the document may not be ready or attached
5585
+ // to the module for some internal tests
5586
+ if (doc && doc.hidden) {
5587
+ timeoutTick(fn);
5588
+ } else {
5589
+ rafTick(fn);
5590
+ }
5591
+ };
5592
+ this._state = 0;
5593
+ }
5594
+
5595
+ AnimateRunner.prototype = {
5596
+ setHost: function(host) {
5597
+ this.host = host || {};
5598
+ },
5599
+
5600
+ done: function(fn) {
5601
+ if (this._state === DONE_COMPLETE_STATE) {
5602
+ fn();
5603
+ } else {
5604
+ this._doneCallbacks.push(fn);
5605
+ }
5606
+ },
5607
+
5608
+ progress: noop,
5609
+
5610
+ getPromise: function() {
5611
+ if (!this.promise) {
5612
+ var self = this;
5613
+ this.promise = $q(function(resolve, reject) {
5614
+ self.done(function(status) {
5615
+ status === false ? reject() : resolve();
5616
+ });
5617
+ });
5618
+ }
5619
+ return this.promise;
5620
+ },
5621
+
5622
+ then: function(resolveHandler, rejectHandler) {
5623
+ return this.getPromise().then(resolveHandler, rejectHandler);
5624
+ },
5625
+
5626
+ 'catch': function(handler) {
5627
+ return this.getPromise()['catch'](handler);
5628
+ },
5629
+
5630
+ 'finally': function(handler) {
5631
+ return this.getPromise()['finally'](handler);
5632
+ },
5633
+
5634
+ pause: function() {
5635
+ if (this.host.pause) {
5636
+ this.host.pause();
5637
+ }
5638
+ },
5639
+
5640
+ resume: function() {
5641
+ if (this.host.resume) {
5642
+ this.host.resume();
5643
+ }
5644
+ },
5645
+
5646
+ end: function() {
5647
+ if (this.host.end) {
5648
+ this.host.end();
5649
+ }
5650
+ this._resolve(true);
5651
+ },
5652
+
5653
+ cancel: function() {
5654
+ if (this.host.cancel) {
5655
+ this.host.cancel();
5656
+ }
5657
+ this._resolve(false);
5658
+ },
5659
+
5660
+ complete: function(response) {
5661
+ var self = this;
5662
+ if (self._state === INITIAL_STATE) {
5663
+ self._state = DONE_PENDING_STATE;
5664
+ self._tick(function() {
5665
+ self._resolve(response);
5666
+ });
5667
+ }
5668
+ },
5669
+
5670
+ _resolve: function(response) {
5671
+ if (this._state !== DONE_COMPLETE_STATE) {
5672
+ forEach(this._doneCallbacks, function(fn) {
5673
+ fn(response);
5674
+ });
5675
+ this._doneCallbacks.length = 0;
5676
+ this._state = DONE_COMPLETE_STATE;
5677
+ }
5678
+ }
5679
+ };
5680
+
5681
+ return AnimateRunner;
5682
+ }];
5683
+ };
5684
+
5415
5685
  /**
5416
5686
  * @ngdoc service
5417
5687
  * @name $animateCss
@@ -5424,37 +5694,18 @@ var $AnimateProvider = ['$provide', function($provide) {
5424
5694
  * Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}.
5425
5695
  */
5426
5696
  var $CoreAnimateCssProvider = function() {
5427
- this.$get = ['$$rAF', '$q', function($$rAF, $q) {
5697
+ this.$get = ['$$rAF', '$q', '$$AnimateRunner', function($$rAF, $q, $$AnimateRunner) {
5428
5698
 
5429
- var RAFPromise = function() {};
5430
- RAFPromise.prototype = {
5431
- done: function(cancel) {
5432
- this.defer && this.defer[cancel === true ? 'reject' : 'resolve']();
5433
- },
5434
- end: function() {
5435
- this.done();
5436
- },
5437
- cancel: function() {
5438
- this.done(true);
5439
- },
5440
- getPromise: function() {
5441
- if (!this.defer) {
5442
- this.defer = $q.defer();
5443
- }
5444
- return this.defer.promise;
5445
- },
5446
- then: function(f1,f2) {
5447
- return this.getPromise().then(f1,f2);
5448
- },
5449
- 'catch': function(f1) {
5450
- return this.getPromise()['catch'](f1);
5451
- },
5452
- 'finally': function(f1) {
5453
- return this.getPromise()['finally'](f1);
5699
+ return function(element, initialOptions) {
5700
+ // all of the animation functions should create
5701
+ // a copy of the options data, however, if a
5702
+ // parent service has already created a copy then
5703
+ // we should stick to using that
5704
+ var options = initialOptions || {};
5705
+ if (!options.$$prepared) {
5706
+ options = copy(options);
5454
5707
  }
5455
- };
5456
5708
 
5457
- return function(element, options) {
5458
5709
  // there is no point in applying the styles since
5459
5710
  // there is no animation that goes on at all in
5460
5711
  // this version of $animateCss.
@@ -5467,7 +5718,8 @@ var $CoreAnimateCssProvider = function() {
5467
5718
  options.from = null;
5468
5719
  }
5469
5720
 
5470
- var closed, runner = new RAFPromise();
5721
+ /* jshint newcap: false */
5722
+ var closed, runner = new $$AnimateRunner();
5471
5723
  return {
5472
5724
  start: run,
5473
5725
  end: run
@@ -5475,16 +5727,16 @@ var $CoreAnimateCssProvider = function() {
5475
5727
 
5476
5728
  function run() {
5477
5729
  $$rAF(function() {
5478
- close();
5730
+ applyAnimationContents();
5479
5731
  if (!closed) {
5480
- runner.done();
5732
+ runner.complete();
5481
5733
  }
5482
5734
  closed = true;
5483
5735
  });
5484
5736
  return runner;
5485
5737
  }
5486
5738
 
5487
- function close() {
5739
+ function applyAnimationContents() {
5488
5740
  if (options.addClass) {
5489
5741
  element.addClass(options.addClass);
5490
5742
  options.addClass = null;
@@ -6392,7 +6644,7 @@ function $TemplateCacheProvider() {
6392
6644
  * When this property is set to true, the HTML compiler will collect DOM nodes between
6393
6645
  * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
6394
6646
  * together as the directive elements. It is recommended that this feature be used on directives
6395
- * which are not strictly behavioural (such as {@link ngClick}), and which
6647
+ * which are not strictly behavioral (such as {@link ngClick}), and which
6396
6648
  * do not manipulate or replace child nodes (such as {@link ngInclude}).
6397
6649
  *
6398
6650
  * #### `priority`
@@ -6430,35 +6682,62 @@ function $TemplateCacheProvider() {
6430
6682
  * is bound to the parent scope, via matching attributes on the directive's element:
6431
6683
  *
6432
6684
  * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
6433
- * always a string since DOM attributes are strings. If no `attr` name is specified then the
6434
- * attribute name is assumed to be the same as the local name.
6435
- * Given `<widget my-attr="hello {{name}}">` and widget definition
6436
- * of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
6437
- * the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
6438
- * `localName` property on the widget scope. The `name` is read from the parent scope (not
6439
- * component scope).
6440
- *
6441
- * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
6442
- * parent scope property of name defined via the value of the `attr` attribute. If no `attr`
6443
- * name is specified then the attribute name is assumed to be the same as the local name.
6444
- * Given `<widget my-attr="parentModel">` and widget definition of
6445
- * `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
6685
+ * always a string since DOM attributes are strings. If no `attr` name is specified then the
6686
+ * attribute name is assumed to be the same as the local name. Given `<my-component
6687
+ * my-attr="hello {{name}}">` and the isolate scope definition `scope: { localName:'@myAttr' }`,
6688
+ * the directive's scope property `localName` will reflect the interpolated value of `hello
6689
+ * {{name}}`. As the `name` attribute changes so will the `localName` property on the directive's
6690
+ * scope. The `name` is read from the parent scope (not the directive's scope).
6691
+ *
6692
+ * * `=` or `=attr` - set up a bidirectional binding between a local scope property and an expression
6693
+ * passed via the attribute `attr`. The expression is evaluated in the context of the parent scope.
6694
+ * If no `attr` name is specified then the attribute name is assumed to be the same as the local
6695
+ * name. Given `<my-component my-attr="parentModel">` and the isolate scope definition `scope: {
6696
+ * localModel: '=myAttr' }`, the property `localModel` on the directive's scope will reflect the
6697
+ * value of `parentModel` on the parent scope. Changes to `parentModel` will be reflected in
6698
+ * `localModel` and vice versa. Optional attributes should be marked as such with a question mark:
6699
+ * `=?` or `=?attr`. If the binding expression is non-assignable, or if the attribute isn't
6700
+ * optional and doesn't exist, an exception ({@link error/$compile/nonassign `$compile:nonassign`})
6701
+ * will be thrown upon discovering changes to the local value, since it will be impossible to sync
6702
+ * them back to the parent scope. By default, the {@link ng.$rootScope.Scope#$watch `$watch`}
6703
+ * method is used for tracking changes, and the equality check is based on object identity.
6704
+ * However, if an object literal or an array literal is passed as the binding expression, the
6705
+ * equality check is done by value (using the {@link angular.equals} function). It's also possible
6706
+ * to watch the evaluated value shallowly with {@link ng.$rootScope.Scope#$watchCollection
6707
+ * `$watchCollection`}: use `=*` or `=*attr` (`=*?` or `=*?attr` if the attribute is optional).
6708
+ *
6709
+ * * `<` or `<attr` - set up a one-way (one-directional) binding between a local scope property and an
6710
+ * expression passed via the attribute `attr`. The expression is evaluated in the context of the
6711
+ * parent scope. If no `attr` name is specified then the attribute name is assumed to be the same as the
6712
+ * local name. You can also make the binding optional by adding `?`: `<?` or `<?attr`.
6713
+ *
6714
+ * For example, given `<my-component my-attr="parentModel">` and directive definition of
6715
+ * `scope: { localModel:'<myAttr' }`, then the isolated scope property `localModel` will reflect the
6446
6716
  * value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
6447
- * in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
6448
- * scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
6449
- * can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional. If
6450
- * you want to shallow watch for changes (i.e. $watchCollection instead of $watch) you can use
6451
- * `=*` or `=*attr` (`=*?` or `=*?attr` if the property is optional).
6452
- *
6453
- * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
6454
- * If no `attr` name is specified then the attribute name is assumed to be the same as the
6455
- * local name. Given `<widget my-attr="count = count + value">` and widget definition of
6456
- * `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
6457
- * a function wrapper for the `count = count + value` expression. Often it's desirable to
6458
- * pass data from the isolated scope via an expression to the parent scope, this can be
6459
- * done by passing a map of local variable names and values into the expression wrapper fn.
6460
- * For example, if the expression is `increment(amount)` then we can specify the amount value
6461
- * by calling the `localFn` as `localFn({amount: 22})`.
6717
+ * in `localModel`, but changes in `localModel` will not reflect in `parentModel`. There are however
6718
+ * two caveats:
6719
+ * 1. one-way binding does not copy the value from the parent to the isolate scope, it simply
6720
+ * sets the same value. That means if your bound value is an object, changes to its properties
6721
+ * in the isolated scope will be reflected in the parent scope (because both reference the same object).
6722
+ * 2. one-way binding watches changes to the **identity** of the parent value. That means the
6723
+ * {@link ng.$rootScope.Scope#$watch `$watch`} on the parent value only fires if the reference
6724
+ * to the value has changed. In most cases, this should not be of concern, but can be important
6725
+ * to know if you one-way bind to an object, and then replace that object in the isolated scope.
6726
+ * If you now change a property of the object in your parent scope, the change will not be
6727
+ * propagated to the isolated scope, because the identity of the object on the parent scope
6728
+ * has not changed. Instead you must assign a new object.
6729
+ *
6730
+ * One-way binding is useful if you do not plan to propagate changes to your isolated scope bindings
6731
+ * back to the parent. However, it does not make this completely impossible.
6732
+ *
6733
+ * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope. If
6734
+ * no `attr` name is specified then the attribute name is assumed to be the same as the local name.
6735
+ * Given `<my-component my-attr="count = count + value">` and the isolate scope definition `scope: {
6736
+ * localFn:'&myAttr' }`, the isolate scope property `localFn` will point to a function wrapper for
6737
+ * the `count = count + value` expression. Often it's desirable to pass data from the isolated scope
6738
+ * via an expression to the parent scope. This can be done by passing a map of local variable names
6739
+ * and values into the expression wrapper fn. For example, if the expression is `increment(amount)`
6740
+ * then we can specify the amount value by calling the `localFn` as `localFn({amount: 22})`.
6462
6741
  *
6463
6742
  * In general it's possible to apply more than one directive to one element, but there might be limitations
6464
6743
  * depending on the type of scope required by the directives. The following points will help explain these limitations.
@@ -6476,9 +6755,32 @@ function $TemplateCacheProvider() {
6476
6755
  *
6477
6756
  *
6478
6757
  * #### `bindToController`
6479
- * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController: true` will
6480
- * allow a component to have its properties bound to the controller, rather than to scope. When the controller
6481
- * is instantiated, the initial values of the isolate scope bindings are already available.
6758
+ * This property is used to bind scope properties directly to the controller. It can be either
6759
+ * `true` or an object hash with the same format as the `scope` property. Additionally, a controller
6760
+ * alias must be set, either by using `controllerAs: 'myAlias'` or by specifying the alias in the controller
6761
+ * definition: `controller: 'myCtrl as myAlias'`.
6762
+ *
6763
+ * When an isolate scope is used for a directive (see above), `bindToController: true` will
6764
+ * allow a component to have its properties bound to the controller, rather than to scope.
6765
+ *
6766
+ * After the controller is instantiated, the initial values of the isolate scope bindings will be bound to the controller
6767
+ * properties. You can access these bindings once they have been initialized by providing a controller method called
6768
+ * `$onInit`, which is called after all the controllers on an element have been constructed and had their bindings
6769
+ * initialized.
6770
+ *
6771
+ * <div class="alert alert-warning">
6772
+ * **Deprecation warning:** although bindings for non-ES6 class controllers are currently
6773
+ * bound to `this` before the controller constructor is called, this use is now deprecated. Please place initialization
6774
+ * code that relies upon bindings inside a `$onInit` method on the controller, instead.
6775
+ * </div>
6776
+ *
6777
+ * It is also possible to set `bindToController` to an object hash with the same format as the `scope` property.
6778
+ * This will set up the scope bindings to the controller directly. Note that `scope` can still be used
6779
+ * to define which kind of scope is created. By default, no scope is created. Use `scope: {}` to create an isolate
6780
+ * scope (useful for component directives).
6781
+ *
6782
+ * If both `bindToController` and `scope` are defined and have object hashes, `bindToController` overrides `scope`.
6783
+ *
6482
6784
  *
6483
6785
  * #### `controller`
6484
6786
  * Controller constructor function. The controller is instantiated before the
@@ -6490,10 +6792,10 @@ function $TemplateCacheProvider() {
6490
6792
  * * `$element` - Current element
6491
6793
  * * `$attrs` - Current attributes object for the element
6492
6794
  * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
6493
- * `function([scope], cloneLinkingFn, futureParentElement)`.
6494
- * * `scope`: optional argument to override the scope.
6495
- * * `cloneLinkingFn`: optional argument to create clones of the original transcluded content.
6496
- * * `futureParentElement`:
6795
+ * `function([scope], cloneLinkingFn, futureParentElement, slotName)`:
6796
+ * * `scope`: (optional) override the scope.
6797
+ * * `cloneLinkingFn`: (optional) argument to create clones of the original transcluded content.
6798
+ * * `futureParentElement` (optional):
6497
6799
  * * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
6498
6800
  * * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
6499
6801
  * * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
@@ -6501,14 +6803,34 @@ function $TemplateCacheProvider() {
6501
6803
  * as those elements need to created and cloned in a special way when they are defined outside their
6502
6804
  * usual containers (e.g. like `<svg>`).
6503
6805
  * * See also the `directive.templateNamespace` property.
6806
+ * * `slotName`: (optional) the name of the slot to transclude. If falsy (e.g. `null`, `undefined` or `''`)
6807
+ * then the default translusion is provided.
6808
+ * The `$transclude` function also has a method on it, `$transclude.isSlotFilled(slotName)`, which returns
6809
+ * `true` if the specified slot contains content (i.e. one or more DOM nodes).
6504
6810
  *
6811
+ * The controller can provide the following methods that act as life-cycle hooks:
6812
+ * * `$onInit` - Called on each controller after all the controllers on an element have been constructed and
6813
+ * had their bindings initialized (and before the pre &amp; post linking functions for the directives on
6814
+ * this element). This is a good place to put initialization code for your controller.
6505
6815
  *
6506
6816
  * #### `require`
6507
6817
  * Require another directive and inject its controller as the fourth argument to the linking function. The
6508
- * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
6509
- * injected argument will be an array in corresponding order. If no such directive can be
6510
- * found, or if the directive does not have a controller, then an error is raised (unless no link function
6511
- * is specified, in which case error checking is skipped). The name can be prefixed with:
6818
+ * `require` property can be a string, an array or an object:
6819
+ * * a **string** containing the name of the directive to pass to the linking function
6820
+ * * an **array** containing the names of directives to pass to the linking function. The argument passed to the
6821
+ * linking function will be an array of controllers in the same order as the names in the `require` property
6822
+ * * an **object** whose property values are the names of the directives to pass to the linking function. The argument
6823
+ * passed to the linking function will also be an object with matching keys, whose values will hold the corresponding
6824
+ * controllers.
6825
+ *
6826
+ * If the `require` property is an object and `bindToController` is truthy, then the required controllers are
6827
+ * bound to the controller using the keys of the `require` property. This binding occurs after all the controllers
6828
+ * have been constructed but before `$onInit` is called.
6829
+ * See the {@link $compileProvider#component} helper for an example of how this can be used.
6830
+ *
6831
+ * If no such required directive(s) can be found, or if the directive does not have a controller, then an error is
6832
+ * raised (unless no link function is specified and the required controllers are not being bound to the directive
6833
+ * controller, in which case error checking is skipped). The name can be prefixed with:
6512
6834
  *
6513
6835
  * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
6514
6836
  * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
@@ -6601,14 +6923,6 @@ function $TemplateCacheProvider() {
6601
6923
  * The contents are compiled and provided to the directive as a **transclusion function**. See the
6602
6924
  * {@link $compile#transclusion Transclusion} section below.
6603
6925
  *
6604
- * There are two kinds of transclusion depending upon whether you want to transclude just the contents of the
6605
- * directive's element or the entire element:
6606
- *
6607
- * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
6608
- * * `'element'` - transclude the whole of the directive's element including any directives on this
6609
- * element that defined at a lower priority than this directive. When used, the `template`
6610
- * property is ignored.
6611
- *
6612
6926
  *
6613
6927
  * #### `compile`
6614
6928
  *
@@ -6636,7 +6950,7 @@ function $TemplateCacheProvider() {
6636
6950
 
6637
6951
  * <div class="alert alert-warning">
6638
6952
  * **Note:** The compile function cannot handle directives that recursively use themselves in their
6639
- * own templates or compile functions. Compiling these directives results in an infinite loop and a
6953
+ * own templates or compile functions. Compiling these directives results in an infinite loop and
6640
6954
  * stack overflow errors.
6641
6955
  *
6642
6956
  * This can be avoided by manually using $compile in the postLink function to imperatively compile
@@ -6738,6 +7052,34 @@ function $TemplateCacheProvider() {
6738
7052
  * Testing Transclusion Directives}.
6739
7053
  * </div>
6740
7054
  *
7055
+ * There are three kinds of transclusion depending upon whether you want to transclude just the contents of the
7056
+ * directive's element, the entire element or multiple parts of the element contents:
7057
+ *
7058
+ * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
7059
+ * * `'element'` - transclude the whole of the directive's element including any directives on this
7060
+ * element that defined at a lower priority than this directive. When used, the `template`
7061
+ * property is ignored.
7062
+ * * **`{...}` (an object hash):** - map elements of the content onto transclusion "slots" in the template.
7063
+ *
7064
+ * **Mult-slot transclusion** is declared by providing an object for the `transclude` property.
7065
+ *
7066
+ * This object is a map where the keys are the name of the slot to fill and the value is an element selector
7067
+ * used to match the HTML to the slot. The element selector should be in normalized form (e.g. `myElement`)
7068
+ * and will match the standard element variants (e.g. `my-element`, `my:element`, `data-my-element`, etc).
7069
+ *
7070
+ * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
7071
+ *
7072
+ * If the element selector is prefixed with a `?` then that slot is optional.
7073
+ *
7074
+ * For example, the transclude object `{ slotA: '?myCustomElement' }` maps `<my-custom-element>` elements to
7075
+ * the `slotA` slot, which can be accessed via the `$transclude` function or via the {@link ngTransclude} directive.
7076
+ *
7077
+ * Slots that are not marked as optional (`?`) will trigger a compile time error if there are no matching elements
7078
+ * in the transclude content. If you wish to know if an optional slot was filled with content, then you can call
7079
+ * `$transclude.isSlotFilled(slotName)` on the transclude function passed to the directive's link function and
7080
+ * injectable into the directive's controller.
7081
+ *
7082
+ *
6741
7083
  * #### Transclusion Functions
6742
7084
  *
6743
7085
  * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
@@ -6758,7 +7100,7 @@ function $TemplateCacheProvider() {
6758
7100
  * content and the `scope` is the newly created transclusion scope, to which the clone is bound.
6759
7101
  *
6760
7102
  * <div class="alert alert-info">
6761
- * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a translude function
7103
+ * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a transclude function
6762
7104
  * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
6763
7105
  * </div>
6764
7106
  *
@@ -6790,7 +7132,7 @@ function $TemplateCacheProvider() {
6790
7132
  * </div>
6791
7133
  *
6792
7134
  * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
6793
- * automatically destroy their transluded clones as necessary so you do not need to worry about this if
7135
+ * automatically destroy their transcluded clones as necessary so you do not need to worry about this if
6794
7136
  * you are simply using {@link ngTransclude} to inject the transclusion into your directive.
6795
7137
  *
6796
7138
  *
@@ -6815,19 +7157,19 @@ function $TemplateCacheProvider() {
6815
7157
  *
6816
7158
  * The `$parent` scope hierarchy will look like this:
6817
7159
  *
6818
- * ```
6819
- * - $rootScope
6820
- * - isolate
6821
- * - transclusion
6822
- * ```
7160
+ ```
7161
+ - $rootScope
7162
+ - isolate
7163
+ - transclusion
7164
+ ```
6823
7165
  *
6824
7166
  * but the scopes will inherit prototypically from different scopes to their `$parent`.
6825
7167
  *
6826
- * ```
6827
- * - $rootScope
6828
- * - transclusion
6829
- * - isolate
6830
- * ```
7168
+ ```
7169
+ - $rootScope
7170
+ - transclusion
7171
+ - isolate
7172
+ ```
6831
7173
  *
6832
7174
  *
6833
7175
  * ### Attributes
@@ -6835,10 +7177,9 @@ function $TemplateCacheProvider() {
6835
7177
  * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
6836
7178
  * `link()` or `compile()` functions. It has a variety of uses.
6837
7179
  *
6838
- * accessing *Normalized attribute names:*
6839
- * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
6840
- * the attributes object allows for normalized access to
6841
- * the attributes.
7180
+ * * *Accessing normalized attribute names:* Directives like 'ngBind' can be expressed in many ways:
7181
+ * 'ng:bind', `data-ng-bind`, or 'x-ng-bind'. The attributes object allows for normalized access
7182
+ * to the attributes.
6842
7183
  *
6843
7184
  * * *Directive inter-communication:* All directives share the same instance of the attributes
6844
7185
  * object which allows the directives to use the attributes object as inter directive
@@ -6959,8 +7300,15 @@ function $TemplateCacheProvider() {
6959
7300
  * directives; if given, it will be passed through to the link functions of
6960
7301
  * directives found in `element` during compilation.
6961
7302
  * * `transcludeControllers` - an object hash with keys that map controller names
6962
- * to controller instances; if given, it will make the controllers
6963
- * available to directives.
7303
+ * to a hash with the key `instance`, which maps to the controller instance;
7304
+ * if given, it will make the controllers available to directives on the compileNode:
7305
+ * ```
7306
+ * {
7307
+ * parent: {
7308
+ * instance: parentControllerInstance
7309
+ * }
7310
+ * }
7311
+ * ```
6964
7312
  * * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
6965
7313
  * the cloned elements; only needed for transcludes that are allowed to contain non html
6966
7314
  * elements (e.g. SVG elements). See also the directive.controller property.
@@ -7021,7 +7369,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7021
7369
  var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
7022
7370
 
7023
7371
  function parseIsolateBindings(scope, directiveName, isController) {
7024
- var LOCAL_REGEXP = /^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/;
7372
+ var LOCAL_REGEXP = /^\s*([@&<]|=(\*?))(\??)\s*(\w*)\s*$/;
7025
7373
 
7026
7374
  var bindings = {};
7027
7375
 
@@ -7108,8 +7456,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7108
7456
  * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
7109
7457
  * will match as <code>ng-bind</code>), or an object map of directives where the keys are the
7110
7458
  * names and the values are the factories.
7111
- * @param {Function|Array} directiveFactory An injectable directive factory function. See
7112
- * {@link guide/directive} for more info.
7459
+ * @param {Function|Array} directiveFactory An injectable directive factory function. See the
7460
+ * {@link guide/directive directive guide} and the {@link $compile compile API} for more info.
7113
7461
  * @returns {ng.$compileProvider} Self for chaining.
7114
7462
  */
7115
7463
  this.directive = function registerDirective(name, directiveFactory) {
@@ -7156,6 +7504,128 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7156
7504
  return this;
7157
7505
  };
7158
7506
 
7507
+ /**
7508
+ * @ngdoc method
7509
+ * @name $compileProvider#component
7510
+ * @module ng
7511
+ * @param {string} name Name of the component in camelCase (i.e. `myComp` which will match `<my-comp>`)
7512
+ * @param {Object} options Component definition object (a simplified
7513
+ * {@link ng.$compile#directive-definition-object directive definition object}),
7514
+ * with the following properties (all optional):
7515
+ *
7516
+ * - `controller` – `{(string|function()=}` – controller constructor function that should be
7517
+ * associated with newly created scope or the name of a {@link ng.$compile#-controller-
7518
+ * registered controller} if passed as a string. An empty `noop` function by default.
7519
+ * - `controllerAs` – `{string=}` – identifier name for to reference the controller in the component's scope.
7520
+ * If present, the controller will be published to scope under the `controllerAs` name.
7521
+ * If not present, this will default to be `$ctrl`.
7522
+ * - `template` – `{string=|function()=}` – html template as a string or a function that
7523
+ * returns an html template as a string which should be used as the contents of this component.
7524
+ * Empty string by default.
7525
+ *
7526
+ * If `template` is a function, then it is {@link auto.$injector#invoke injected} with
7527
+ * the following locals:
7528
+ *
7529
+ * - `$element` - Current element
7530
+ * - `$attrs` - Current attributes object for the element
7531
+ *
7532
+ * - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
7533
+ * template that should be used as the contents of this component.
7534
+ *
7535
+ * If `templateUrl` is a function, then it is {@link auto.$injector#invoke injected} with
7536
+ * the following locals:
7537
+ *
7538
+ * - `$element` - Current element
7539
+ * - `$attrs` - Current attributes object for the element
7540
+ *
7541
+ * - `bindings` – `{object=}` – defines bindings between DOM attributes and component properties.
7542
+ * Component properties are always bound to the component controller and not to the scope.
7543
+ * See {@link ng.$compile#-bindtocontroller- `bindToController`}.
7544
+ * - `transclude` – `{boolean=}` – whether {@link $compile#transclusion content transclusion} is enabled.
7545
+ * Disabled by default.
7546
+ * - `$...` – `{function()=}` – additional annotations to provide to the directive factory function.
7547
+ *
7548
+ * @returns {ng.$compileProvider} the compile provider itself, for chaining of function calls.
7549
+ * @description
7550
+ * Register a **component definition** with the compiler. This is a shorthand for registering a special
7551
+ * type of directive, which represents a self-contained UI component in your application. Such components
7552
+ * are always isolated (i.e. `scope: {}`) and are always restricted to elements (i.e. `restrict: 'E'`).
7553
+ *
7554
+ * Component definitions are very simple and do not require as much configuration as defining general
7555
+ * directives. Component definitions usually consist only of a template and a controller backing it.
7556
+ *
7557
+ * In order to make the definition easier, components enforce best practices like use of `controllerAs`,
7558
+ * `bindToController`. They always have **isolate scope** and are restricted to elements.
7559
+ *
7560
+ * Here are a few examples of how you would usually define components:
7561
+ *
7562
+ * ```js
7563
+ * var myMod = angular.module(...);
7564
+ * myMod.component('myComp', {
7565
+ * template: '<div>My name is {{$ctrl.name}}</div>',
7566
+ * controller: function() {
7567
+ * this.name = 'shahar';
7568
+ * }
7569
+ * });
7570
+ *
7571
+ * myMod.component('myComp', {
7572
+ * template: '<div>My name is {{$ctrl.name}}</div>',
7573
+ * bindings: {name: '@'}
7574
+ * });
7575
+ *
7576
+ * myMod.component('myComp', {
7577
+ * templateUrl: 'views/my-comp.html',
7578
+ * controller: 'MyCtrl as ctrl',
7579
+ * bindings: {name: '@'}
7580
+ * });
7581
+ *
7582
+ * ```
7583
+ * For more examples, and an in-depth guide, see the {@link guide/component component guide}.
7584
+ *
7585
+ * <br />
7586
+ * See also {@link ng.$compileProvider#directive $compileProvider.directive()}.
7587
+ */
7588
+ this.component = function registerComponent(name, options) {
7589
+ var controller = options.controller || function() {};
7590
+
7591
+ function factory($injector) {
7592
+ function makeInjectable(fn) {
7593
+ if (isFunction(fn) || isArray(fn)) {
7594
+ return function(tElement, tAttrs) {
7595
+ return $injector.invoke(fn, this, {$element: tElement, $attrs: tAttrs});
7596
+ };
7597
+ } else {
7598
+ return fn;
7599
+ }
7600
+ }
7601
+
7602
+ var template = (!options.template && !options.templateUrl ? '' : options.template);
7603
+ return {
7604
+ controller: controller,
7605
+ controllerAs: identifierForController(options.controller) || options.controllerAs || '$ctrl',
7606
+ template: makeInjectable(template),
7607
+ templateUrl: makeInjectable(options.templateUrl),
7608
+ transclude: options.transclude,
7609
+ scope: {},
7610
+ bindToController: options.bindings || {},
7611
+ restrict: 'E',
7612
+ require: options.require
7613
+ };
7614
+ }
7615
+
7616
+ // Copy any annotation properties (starting with $) over to the factory function
7617
+ // These could be used by libraries such as the new component router
7618
+ forEach(options, function(val, key) {
7619
+ if (key.charAt(0) === '$') {
7620
+ factory[key] = val;
7621
+ }
7622
+ });
7623
+
7624
+ factory.$inject = ['$injector'];
7625
+
7626
+ return this.directive(name, factory);
7627
+ };
7628
+
7159
7629
 
7160
7630
  /**
7161
7631
  * @ngdoc method
@@ -7249,10 +7719,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7249
7719
 
7250
7720
  this.$get = [
7251
7721
  '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
7252
- '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
7722
+ '$controller', '$rootScope', '$sce', '$animate', '$$sanitizeUri',
7253
7723
  function($injector, $interpolate, $exceptionHandler, $templateRequest, $parse,
7254
- $controller, $rootScope, $document, $sce, $animate, $$sanitizeUri) {
7724
+ $controller, $rootScope, $sce, $animate, $$sanitizeUri) {
7255
7725
 
7726
+ var SIMPLE_ATTR_NAME = /^\w/;
7727
+ var specialAttrHolder = document.createElement('div');
7256
7728
  var Attributes = function(element, attributesToCopy) {
7257
7729
  if (attributesToCopy) {
7258
7730
  var keys = Object.keys(attributesToCopy);
@@ -7388,7 +7860,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7388
7860
 
7389
7861
  nodeName = nodeName_(this.$$element);
7390
7862
 
7391
- if ((nodeName === 'a' && key === 'href') ||
7863
+ if ((nodeName === 'a' && (key === 'href' || key === 'xlinkHref')) ||
7392
7864
  (nodeName === 'img' && key === 'src')) {
7393
7865
  // sanitize a[href] and img[src] values
7394
7866
  this[key] = value = $$sanitizeUri(value, key === 'src');
@@ -7432,7 +7904,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7432
7904
  if (value === null || isUndefined(value)) {
7433
7905
  this.$$element.removeAttr(attrName);
7434
7906
  } else {
7435
- this.$$element.attr(attrName, value);
7907
+ if (SIMPLE_ATTR_NAME.test(attrName)) {
7908
+ this.$$element.attr(attrName, value);
7909
+ } else {
7910
+ setSpecialAttr(this.$$element[0], attrName, value);
7911
+ }
7436
7912
  }
7437
7913
  }
7438
7914
 
@@ -7463,7 +7939,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7463
7939
  * @param {string} key Normalized key. (ie ngAttribute) .
7464
7940
  * @param {function(interpolatedValue)} fn Function that will be called whenever
7465
7941
  the interpolated value of the attribute changes.
7466
- * See the {@link guide/directive#text-and-attribute-bindings Directives} guide for more info.
7942
+ * See the {@link guide/interpolation#how-text-and-attribute-bindings-work Interpolation
7943
+ * guide} for more info.
7467
7944
  * @returns {function()} Returns a deregistration function for this observer.
7468
7945
  */
7469
7946
  $observe: function(key, fn) {
@@ -7485,6 +7962,18 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7485
7962
  }
7486
7963
  };
7487
7964
 
7965
+ function setSpecialAttr(element, attrName, value) {
7966
+ // Attributes names that do not start with letters (such as `(click)`) cannot be set using `setAttribute`
7967
+ // so we have to jump through some hoops to get such an attribute
7968
+ // https://github.com/angular/angular.js/pull/13318
7969
+ specialAttrHolder.innerHTML = "<span " + attrName + ">";
7970
+ var attributes = specialAttrHolder.firstChild.attributes;
7971
+ var attribute = attributes[0];
7972
+ // We have to remove the attribute from its container element before we can add it to the destination element
7973
+ attributes.removeNamedItem(attribute.name);
7974
+ attribute.value = value;
7975
+ element.attributes.setNamedItem(attribute);
7976
+ }
7488
7977
 
7489
7978
  function safeAddClass($element, className) {
7490
7979
  try {
@@ -7498,7 +7987,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7498
7987
 
7499
7988
  var startSymbol = $interpolate.startSymbol(),
7500
7989
  endSymbol = $interpolate.endSymbol(),
7501
- denormalizeTemplate = (startSymbol == '{{' || endSymbol == '}}')
7990
+ denormalizeTemplate = (startSymbol == '{{' && endSymbol == '}}')
7502
7991
  ? identity
7503
7992
  : function denormalizeTemplate(template) {
7504
7993
  return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
@@ -7542,13 +8031,19 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7542
8031
  // modify it.
7543
8032
  $compileNodes = jqLite($compileNodes);
7544
8033
  }
8034
+
8035
+ var NOT_EMPTY = /\S+/;
8036
+
7545
8037
  // We can not compile top level text elements since text nodes can be merged and we will
7546
8038
  // not be able to attach scope data to them, so we will wrap them in <span>
7547
- forEach($compileNodes, function(node, index) {
7548
- if (node.nodeType == NODE_TYPE_TEXT && node.nodeValue.match(/\S+/) /* non-empty */ ) {
7549
- $compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
8039
+ for (var i = 0, len = $compileNodes.length; i < len; i++) {
8040
+ var domNode = $compileNodes[i];
8041
+
8042
+ if (domNode.nodeType === NODE_TYPE_TEXT && domNode.nodeValue.match(NOT_EMPTY) /* non-empty */) {
8043
+ jqLiteWrapNode(domNode, $compileNodes[i] = document.createElement('span'));
7550
8044
  }
7551
- });
8045
+ }
8046
+
7552
8047
  var compositeLinkFn =
7553
8048
  compileNodes($compileNodes, transcludeFn, $compileNodes,
7554
8049
  maxPriority, ignoreDirective, previousCompileContext);
@@ -7619,7 +8114,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7619
8114
  if (!node) {
7620
8115
  return 'html';
7621
8116
  } else {
7622
- return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg' : 'html';
8117
+ return nodeName_(node) !== 'foreignobject' && toString.call(node).match(/SVG/) ? 'svg' : 'html';
7623
8118
  }
7624
8119
  }
7625
8120
 
@@ -7753,6 +8248,17 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7753
8248
  });
7754
8249
  };
7755
8250
 
8251
+ // We need to attach the transclusion slots onto the `boundTranscludeFn`
8252
+ // so that they are available inside the `controllersBoundTransclude` function
8253
+ var boundSlots = boundTranscludeFn.$$slots = createMap();
8254
+ for (var slotName in transcludeFn.$$slots) {
8255
+ if (transcludeFn.$$slots[slotName]) {
8256
+ boundSlots[slotName] = createBoundTranscludeFn(scope, transcludeFn.$$slots[slotName], previousBoundTranscludeFn);
8257
+ } else {
8258
+ boundSlots[slotName] = null;
8259
+ }
8260
+ }
8261
+
7756
8262
  return boundTranscludeFn;
7757
8263
  }
7758
8264
 
@@ -7911,6 +8417,37 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7911
8417
  };
7912
8418
  }
7913
8419
 
8420
+ /**
8421
+ * A function generator that is used to support both eager and lazy compilation
8422
+ * linking function.
8423
+ * @param eager
8424
+ * @param $compileNodes
8425
+ * @param transcludeFn
8426
+ * @param maxPriority
8427
+ * @param ignoreDirective
8428
+ * @param previousCompileContext
8429
+ * @returns {Function}
8430
+ */
8431
+ function compilationGenerator(eager, $compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext) {
8432
+ if (eager) {
8433
+ return compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
8434
+ }
8435
+
8436
+ var compiled;
8437
+
8438
+ return function() {
8439
+ if (!compiled) {
8440
+ compiled = compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
8441
+
8442
+ // Null out all of these references in order to make them eligible for garbage collection
8443
+ // since this is a potentially long lived closure
8444
+ $compileNodes = transcludeFn = previousCompileContext = null;
8445
+ }
8446
+
8447
+ return compiled.apply(this, arguments);
8448
+ };
8449
+ }
8450
+
7914
8451
  /**
7915
8452
  * Once the directives have been collected, their compile functions are executed. This method
7916
8453
  * is responsible for inlining directive templates as well as terminating the application
@@ -7955,6 +8492,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7955
8492
  replaceDirective = originalReplaceDirective,
7956
8493
  childTranscludeFn = transcludeFn,
7957
8494
  linkFn,
8495
+ didScanForMultipleTransclusion = false,
8496
+ mightHaveMultipleTransclusionError = false,
7958
8497
  directiveValue;
7959
8498
 
7960
8499
  // executes all directives on the current element
@@ -7997,6 +8536,27 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7997
8536
 
7998
8537
  directiveName = directive.name;
7999
8538
 
8539
+ // If we encounter a condition that can result in transclusion on the directive,
8540
+ // then scan ahead in the remaining directives for others that may cause a multiple
8541
+ // transclusion error to be thrown during the compilation process. If a matching directive
8542
+ // is found, then we know that when we encounter a transcluded directive, we need to eagerly
8543
+ // compile the `transclude` function rather than doing it lazily in order to throw
8544
+ // exceptions at the correct time
8545
+ if (!didScanForMultipleTransclusion && ((directive.replace && (directive.templateUrl || directive.template))
8546
+ || (directive.transclude && !directive.$$tlb))) {
8547
+ var candidateDirective;
8548
+
8549
+ for (var scanningIndex = i + 1; candidateDirective = directives[scanningIndex++];) {
8550
+ if ((candidateDirective.transclude && !candidateDirective.$$tlb)
8551
+ || (candidateDirective.replace && (candidateDirective.templateUrl || candidateDirective.template))) {
8552
+ mightHaveMultipleTransclusionError = true;
8553
+ break;
8554
+ }
8555
+ }
8556
+
8557
+ didScanForMultipleTransclusion = true;
8558
+ }
8559
+
8000
8560
  if (!directive.templateUrl && directive.controller) {
8001
8561
  directiveValue = directive.controller;
8002
8562
  controllerDirectives = controllerDirectives || createMap();
@@ -8026,7 +8586,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8026
8586
  compileNode = $compileNode[0];
8027
8587
  replaceWith(jqCollection, sliceArgs($template), compileNode);
8028
8588
 
8029
- childTranscludeFn = compile($template, transcludeFn, terminalPriority,
8589
+ childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, terminalPriority,
8030
8590
  replaceDirective && replaceDirective.name, {
8031
8591
  // Don't pass in:
8032
8592
  // - controllerDirectives - otherwise we'll create duplicates controllers
@@ -8038,10 +8598,69 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8038
8598
  nonTlbTranscludeDirective: nonTlbTranscludeDirective
8039
8599
  });
8040
8600
  } else {
8601
+
8602
+ var slots = createMap();
8603
+
8041
8604
  $template = jqLite(jqLiteClone(compileNode)).contents();
8605
+
8606
+ if (isObject(directiveValue)) {
8607
+
8608
+ // We have transclusion slots,
8609
+ // collect them up, compile them and store their transclusion functions
8610
+ $template = [];
8611
+
8612
+ var slotMap = createMap();
8613
+ var filledSlots = createMap();
8614
+
8615
+ // Parse the element selectors
8616
+ forEach(directiveValue, function(elementSelector, slotName) {
8617
+ // If an element selector starts with a ? then it is optional
8618
+ var optional = (elementSelector.charAt(0) === '?');
8619
+ elementSelector = optional ? elementSelector.substring(1) : elementSelector;
8620
+
8621
+ slotMap[elementSelector] = slotName;
8622
+
8623
+ // We explicitly assign `null` since this implies that a slot was defined but not filled.
8624
+ // Later when calling boundTransclusion functions with a slot name we only error if the
8625
+ // slot is `undefined`
8626
+ slots[slotName] = null;
8627
+
8628
+ // filledSlots contains `true` for all slots that are either optional or have been
8629
+ // filled. This is used to check that we have not missed any required slots
8630
+ filledSlots[slotName] = optional;
8631
+ });
8632
+
8633
+ // Add the matching elements into their slot
8634
+ forEach($compileNode.contents(), function(node) {
8635
+ var slotName = slotMap[directiveNormalize(nodeName_(node))];
8636
+ if (slotName) {
8637
+ filledSlots[slotName] = true;
8638
+ slots[slotName] = slots[slotName] || [];
8639
+ slots[slotName].push(node);
8640
+ } else {
8641
+ $template.push(node);
8642
+ }
8643
+ });
8644
+
8645
+ // Check for required slots that were not filled
8646
+ forEach(filledSlots, function(filled, slotName) {
8647
+ if (!filled) {
8648
+ throw $compileMinErr('reqslot', 'Required transclusion slot `{0}` was not filled.', slotName);
8649
+ }
8650
+ });
8651
+
8652
+ for (var slotName in slots) {
8653
+ if (slots[slotName]) {
8654
+ // Only define a transclusion function if the slot was filled
8655
+ slots[slotName] = compilationGenerator(mightHaveMultipleTransclusionError, slots[slotName], transcludeFn);
8656
+ }
8657
+ }
8658
+ }
8659
+
8042
8660
  $compileNode.empty(); // clear contents
8043
- childTranscludeFn = compile($template, transcludeFn, undefined,
8661
+ childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, undefined,
8044
8662
  undefined, { needsNewScope: directive.$$isolateScope || directive.$$newScope});
8663
+ childTranscludeFn.$$slots = slots;
8045
8664
  }
8046
8665
  }
8047
8666
 
@@ -8204,6 +8823,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8204
8823
  for (var i = 0, ii = require.length; i < ii; i++) {
8205
8824
  value[i] = getControllers(directiveName, require[i], $element, elementControllers);
8206
8825
  }
8826
+ } else if (isObject(require)) {
8827
+ value = {};
8828
+ forEach(require, function(controller, property) {
8829
+ value[property] = getControllers(directiveName, controller, $element, elementControllers);
8830
+ });
8207
8831
  }
8208
8832
 
8209
8833
  return value || null;
@@ -8241,7 +8865,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8241
8865
  }
8242
8866
 
8243
8867
  function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
8244
- var linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
8868
+ var i, ii, linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
8245
8869
  attrs, removeScopeBindingWatches, removeControllerBindingWatches;
8246
8870
 
8247
8871
  if (compileNode === linkNode) {
@@ -8264,6 +8888,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8264
8888
  // is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
8265
8889
  transcludeFn = controllersBoundTransclude;
8266
8890
  transcludeFn.$$boundTransclude = boundTranscludeFn;
8891
+ // expose the slots on the `$transclude` function
8892
+ transcludeFn.isSlotFilled = function(slotName) {
8893
+ return !!boundTranscludeFn.$$slots[slotName];
8894
+ };
8267
8895
  }
8268
8896
 
8269
8897
  if (controllerDirectives) {
@@ -8308,6 +8936,21 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8308
8936
  }
8309
8937
  }
8310
8938
 
8939
+ // Bind the required controllers to the controller, if `require` is an object and `bindToController` is truthy
8940
+ forEach(controllerDirectives, function(controllerDirective, name) {
8941
+ var require = controllerDirective.require;
8942
+ if (controllerDirective.bindToController && !isArray(require) && isObject(require)) {
8943
+ extend(elementControllers[name].instance, getControllers(name, require, $element, elementControllers));
8944
+ }
8945
+ });
8946
+
8947
+ // Trigger the `$onInit` method on all controllers that have one
8948
+ forEach(elementControllers, function(controller) {
8949
+ if (isFunction(controller.instance.$onInit)) {
8950
+ controller.instance.$onInit();
8951
+ }
8952
+ });
8953
+
8311
8954
  // PRELINKING
8312
8955
  for (i = 0, ii = preLinkFns.length; i < ii; i++) {
8313
8956
  linkFn = preLinkFns[i];
@@ -8343,11 +8986,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8343
8986
 
8344
8987
  // This is the function that is injected as `$transclude`.
8345
8988
  // Note: all arguments are optional!
8346
- function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement) {
8989
+ function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement, slotName) {
8347
8990
  var transcludeControllers;
8348
-
8349
8991
  // No scope passed in:
8350
8992
  if (!isScope(scope)) {
8993
+ slotName = futureParentElement;
8351
8994
  futureParentElement = cloneAttachFn;
8352
8995
  cloneAttachFn = scope;
8353
8996
  scope = undefined;
@@ -8359,7 +9002,23 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8359
9002
  if (!futureParentElement) {
8360
9003
  futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
8361
9004
  }
8362
- return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
9005
+ if (slotName) {
9006
+ // slotTranscludeFn can be one of three things:
9007
+ // * a transclude function - a filled slot
9008
+ // * `null` - an optional slot that was not filled
9009
+ // * `undefined` - a slot that was not declared (i.e. invalid)
9010
+ var slotTranscludeFn = boundTranscludeFn.$$slots[slotName];
9011
+ if (slotTranscludeFn) {
9012
+ return slotTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
9013
+ } else if (isUndefined(slotTranscludeFn)) {
9014
+ throw $compileMinErr('noslot',
9015
+ 'No parent directive that requires a transclusion with slot name "{0}". ' +
9016
+ 'Element: {1}',
9017
+ slotName, startingTag($element));
9018
+ }
9019
+ } else {
9020
+ return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
9021
+ }
8363
9022
  }
8364
9023
  }
8365
9024
  }
@@ -8791,9 +9450,14 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8791
9450
  parent.replaceChild(newNode, firstElementToRemove);
8792
9451
  }
8793
9452
 
8794
- // TODO(perf): what's this document fragment for? is it needed? can we at least reuse it?
9453
+ // Append all the `elementsToRemove` to a fragment. This will...
9454
+ // - remove them from the DOM
9455
+ // - allow them to still be traversed with .nextSibling
9456
+ // - allow a single fragment.qSA to fetch all elements being removed
8795
9457
  var fragment = document.createDocumentFragment();
8796
- fragment.appendChild(firstElementToRemove);
9458
+ for (i = 0; i < removeCount; i++) {
9459
+ fragment.appendChild(elementsToRemove[i]);
9460
+ }
8797
9461
 
8798
9462
  if (jqLite.hasData(firstElementToRemove)) {
8799
9463
  // Copy over user data (that includes Angular's $scope etc.). Don't copy private
@@ -8801,31 +9465,18 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8801
9465
  // event listeners (which is the main use of private data) wouldn't work anyway.
8802
9466
  jqLite.data(newNode, jqLite.data(firstElementToRemove));
8803
9467
 
8804
- // Remove data of the replaced element. We cannot just call .remove()
8805
- // on the element it since that would deallocate scope that is needed
8806
- // for the new node. Instead, remove the data "manually".
8807
- if (!jQuery) {
8808
- delete jqLite.cache[firstElementToRemove[jqLite.expando]];
8809
- } else {
8810
- // jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after
8811
- // the replaced element. The cleanData version monkey-patched by Angular would cause
8812
- // the scope to be trashed and we do need the very same scope to work with the new
8813
- // element. However, we cannot just cache the non-patched version and use it here as
8814
- // that would break if another library patches the method after Angular does (one
8815
- // example is jQuery UI). Instead, set a flag indicating scope destroying should be
8816
- // skipped this one time.
8817
- skipDestroyOnNextJQueryCleanData = true;
8818
- jQuery.cleanData([firstElementToRemove]);
8819
- }
9468
+ // Remove $destroy event listeners from `firstElementToRemove`
9469
+ jqLite(firstElementToRemove).off('$destroy');
8820
9470
  }
8821
9471
 
8822
- for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
8823
- var element = elementsToRemove[k];
8824
- jqLite(element).remove(); // must do this way to clean up expando
8825
- fragment.appendChild(element);
8826
- delete elementsToRemove[k];
8827
- }
9472
+ // Cleanup any data/listeners on the elements and children.
9473
+ // This includes invoking the $destroy event on any elements with listeners.
9474
+ jqLite.cleanData(fragment.querySelectorAll('*'));
8828
9475
 
9476
+ // Update the jqLite collection to only contain the `newNode`
9477
+ for (i = 1; i < removeCount; i++) {
9478
+ delete elementsToRemove[i];
9479
+ }
8829
9480
  elementsToRemove[0] = newNode;
8830
9481
  elementsToRemove.length = 1;
8831
9482
  }
@@ -8854,7 +9505,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8854
9505
  optional = definition.optional,
8855
9506
  mode = definition.mode, // @, =, or &
8856
9507
  lastValue,
8857
- parentGet, parentSet, compare;
9508
+ parentGet, parentSet, compare, removeWatch;
8858
9509
 
8859
9510
  switch (mode) {
8860
9511
 
@@ -8868,10 +9519,15 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8868
9519
  }
8869
9520
  });
8870
9521
  attrs.$$observers[attrName].$$scope = scope;
8871
- if (isString(attrs[attrName])) {
9522
+ lastValue = attrs[attrName];
9523
+ if (isString(lastValue)) {
8872
9524
  // If the attribute has been provided then we trigger an interpolation to ensure
8873
9525
  // the value is there for use in the link fn
8874
- destination[scopeName] = $interpolate(attrs[attrName])(scope);
9526
+ destination[scopeName] = $interpolate(lastValue)(scope);
9527
+ } else if (isBoolean(lastValue)) {
9528
+ // If the attributes is one of the BOOLEAN_ATTR then Angular will have converted
9529
+ // the value to boolean rather than a string, so we special case this situation
9530
+ destination[scopeName] = lastValue;
8875
9531
  }
8876
9532
  break;
8877
9533
 
@@ -8892,8 +9548,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8892
9548
  // reset the change, or we will throw this exception on every $digest
8893
9549
  lastValue = destination[scopeName] = parentGet(scope);
8894
9550
  throw $compileMinErr('nonassign',
8895
- "Expression '{0}' used with directive '{1}' is non-assignable!",
8896
- attrs[attrName], directive.name);
9551
+ "Expression '{0}' in attribute '{1}' used with directive '{2}' is non-assignable!",
9552
+ attrs[attrName], attrName, directive.name);
8897
9553
  };
8898
9554
  lastValue = destination[scopeName] = parentGet(scope);
8899
9555
  var parentValueWatch = function parentValueWatch(parentValue) {
@@ -8910,7 +9566,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8910
9566
  return lastValue = parentValue;
8911
9567
  };
8912
9568
  parentValueWatch.$stateful = true;
8913
- var removeWatch;
8914
9569
  if (definition.collection) {
8915
9570
  removeWatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
8916
9571
  } else {
@@ -8919,6 +9574,24 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8919
9574
  removeWatchCollection.push(removeWatch);
8920
9575
  break;
8921
9576
 
9577
+ case '<':
9578
+ if (!hasOwnProperty.call(attrs, attrName)) {
9579
+ if (optional) break;
9580
+ attrs[attrName] = void 0;
9581
+ }
9582
+ if (optional && !attrs[attrName]) break;
9583
+
9584
+ parentGet = $parse(attrs[attrName]);
9585
+
9586
+ destination[scopeName] = parentGet(scope);
9587
+
9588
+ removeWatch = scope.$watch(parentGet, function parentValueWatchAction(newParentValue) {
9589
+ destination[scopeName] = newParentValue;
9590
+ }, parentGet.literal);
9591
+
9592
+ removeWatchCollection.push(removeWatch);
9593
+ break;
9594
+
8922
9595
  case '&':
8923
9596
  // Don't assign Object.prototype method to scope
8924
9597
  parentGet = attrs.hasOwnProperty(attrName) ? $parse(attrs[attrName]) : noop;
@@ -9047,7 +9720,7 @@ function removeComments(jqNodes) {
9047
9720
  var $controllerMinErr = minErr('$controller');
9048
9721
 
9049
9722
 
9050
- var CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
9723
+ var CNTRL_REG = /^(\S+)(\s+as\s+([\w$]+))?$/;
9051
9724
  function identifierForController(controller, ident) {
9052
9725
  if (ident && isString(ident)) return ident;
9053
9726
  if (isString(controller)) {
@@ -9838,7 +10511,7 @@ function $HttpProvider() {
9838
10511
  *
9839
10512
  * ```
9840
10513
  * module.run(function($http) {
9841
- * $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
10514
+ * $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w';
9842
10515
  * });
9843
10516
  * ```
9844
10517
  *
@@ -10066,13 +10739,13 @@ function $HttpProvider() {
10066
10739
  *
10067
10740
  * ### Cross Site Request Forgery (XSRF) Protection
10068
10741
  *
10069
- * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which
10070
- * an unauthorized site can gain your user's private data. Angular provides a mechanism
10071
- * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
10072
- * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
10073
- * JavaScript that runs on your domain could read the cookie, your server can be assured that
10074
- * the XHR came from JavaScript running on your domain. The header will not be set for
10075
- * cross-domain requests.
10742
+ * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is an attack technique by
10743
+ * which the attacker can trick an authenticated user into unknowingly executing actions on your
10744
+ * website. Angular provides a mechanism to counter XSRF. When performing XHR requests, the
10745
+ * $http service reads a token from a cookie (by default, `XSRF-TOKEN`) and sets it as an HTTP
10746
+ * header (`X-XSRF-TOKEN`). Since only JavaScript that runs on your domain could read the
10747
+ * cookie, your server can be assured that the XHR came from JavaScript running on your domain.
10748
+ * The header will not be set for cross-domain requests.
10076
10749
  *
10077
10750
  * To take advantage of this, your server needs to set a token in a JavaScript readable session
10078
10751
  * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
@@ -10231,10 +10904,14 @@ function $HttpProvider() {
10231
10904
  */
10232
10905
  function $http(requestConfig) {
10233
10906
 
10234
- if (!angular.isObject(requestConfig)) {
10907
+ if (!isObject(requestConfig)) {
10235
10908
  throw minErr('$http')('badreq', 'Http request configuration must be an object. Received: {0}', requestConfig);
10236
10909
  }
10237
10910
 
10911
+ if (!isString(requestConfig.url)) {
10912
+ throw minErr('$http')('badreq', 'Http request configuration url must be a string. Received: {0}', requestConfig.url);
10913
+ }
10914
+
10238
10915
  var config = extend({
10239
10916
  method: 'get',
10240
10917
  transformRequest: defaults.transformRequest,
@@ -10347,7 +11024,7 @@ function $HttpProvider() {
10347
11024
 
10348
11025
  defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
10349
11026
 
10350
- // using for-in instead of forEach to avoid unecessary iteration after header has been found
11027
+ // using for-in instead of forEach to avoid unnecessary iteration after header has been found
10351
11028
  defaultHeadersIteration:
10352
11029
  for (defHeaderName in defHeaders) {
10353
11030
  lowercaseDefHeaderName = lowercase(defHeaderName);
@@ -10846,8 +11523,16 @@ $interpolateMinErr.interr = function(text, err) {
10846
11523
  *
10847
11524
  * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
10848
11525
  *
11526
+ * <div class="alert alert-danger">
11527
+ * This feature is sometimes used to mix different markup languages, e.g. to wrap an Angular
11528
+ * template within a Python Jinja template (or any other template language). Mixing templating
11529
+ * languages is **very dangerous**. The embedding template language will not safely escape Angular
11530
+ * expressions, so any user-controlled values in the template will cause Cross Site Scripting (XSS)
11531
+ * security bugs!
11532
+ * </div>
11533
+ *
10849
11534
  * @example
10850
- <example module="customInterpolationApp">
11535
+ <example name="custom-interpolation-markup" module="customInterpolationApp">
10851
11536
  <file name="index.html">
10852
11537
  <script>
10853
11538
  var customInterpolationApp = angular.module('customInterpolationApp', []);
@@ -10862,7 +11547,7 @@ $interpolateMinErr.interr = function(text, err) {
10862
11547
  this.label = "This binding is brought you by // interpolation symbols.";
10863
11548
  });
10864
11549
  </script>
10865
- <div ng-app="App" ng-controller="DemoController as demo">
11550
+ <div ng-controller="DemoController as demo">
10866
11551
  //demo.label//
10867
11552
  </div>
10868
11553
  </file>
@@ -10946,6 +11631,15 @@ function $InterpolateProvider() {
10946
11631
  return value;
10947
11632
  }
10948
11633
 
11634
+ //TODO: this is the same as the constantWatchDelegate in parse.js
11635
+ function constantWatchDelegate(scope, listener, objectEquality, constantInterp) {
11636
+ var unwatch;
11637
+ return unwatch = scope.$watch(function constantInterpolateWatch(scope) {
11638
+ unwatch();
11639
+ return constantInterp(scope);
11640
+ }, listener, objectEquality);
11641
+ }
11642
+
10949
11643
  /**
10950
11644
  * @ngdoc service
10951
11645
  * @name $interpolate
@@ -11041,6 +11735,19 @@ function $InterpolateProvider() {
11041
11735
  * - `context`: evaluation context for all expressions embedded in the interpolated text
11042
11736
  */
11043
11737
  function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
11738
+ // Provide a quick exit and simplified result function for text with no interpolation
11739
+ if (!text.length || text.indexOf(startSymbol) === -1) {
11740
+ var constantInterp;
11741
+ if (!mustHaveExpression) {
11742
+ var unescapedText = unescapeText(text);
11743
+ constantInterp = valueFn(unescapedText);
11744
+ constantInterp.exp = text;
11745
+ constantInterp.expressions = [];
11746
+ constantInterp.$$watchDelegate = constantWatchDelegate;
11747
+ }
11748
+ return constantInterp;
11749
+ }
11750
+
11044
11751
  allOrNothing = !!allOrNothing;
11045
11752
  var startIndex,
11046
11753
  endIndex,
@@ -11177,8 +11884,8 @@ function $InterpolateProvider() {
11177
11884
  }
11178
11885
 
11179
11886
  function $IntervalProvider() {
11180
- this.$get = ['$rootScope', '$window', '$q', '$$q',
11181
- function($rootScope, $window, $q, $$q) {
11887
+ this.$get = ['$rootScope', '$window', '$q', '$$q', '$browser',
11888
+ function($rootScope, $window, $q, $$q, $browser) {
11182
11889
  var intervals = {};
11183
11890
 
11184
11891
 
@@ -11319,11 +12026,12 @@ function $IntervalProvider() {
11319
12026
 
11320
12027
  count = isDefined(count) ? count : 0;
11321
12028
 
11322
- promise.then(null, null, (!hasParams) ? fn : function() {
11323
- fn.apply(null, args);
11324
- });
11325
-
11326
12029
  promise.$$intervalId = setInterval(function tick() {
12030
+ if (skipApply) {
12031
+ $browser.defer(callback);
12032
+ } else {
12033
+ $rootScope.$evalAsync(callback);
12034
+ }
11327
12035
  deferred.notify(iteration++);
11328
12036
 
11329
12037
  if (count > 0 && iteration >= count) {
@@ -11339,6 +12047,14 @@ function $IntervalProvider() {
11339
12047
  intervals[promise.$$intervalId] = deferred;
11340
12048
 
11341
12049
  return promise;
12050
+
12051
+ function callback() {
12052
+ if (!hasParams) {
12053
+ fn(iteration);
12054
+ } else {
12055
+ fn.apply(null, args);
12056
+ }
12057
+ }
11342
12058
  }
11343
12059
 
11344
12060
 
@@ -12578,23 +13294,22 @@ function ensureSafeMemberName(name, fullExpression) {
12578
13294
  return name;
12579
13295
  }
12580
13296
 
12581
- function getStringValue(name, fullExpression) {
12582
- // From the JavaScript docs:
13297
+ function getStringValue(name) {
12583
13298
  // Property names must be strings. This means that non-string objects cannot be used
12584
13299
  // as keys in an object. Any non-string object, including a number, is typecasted
12585
13300
  // into a string via the toString method.
13301
+ // -- MDN, https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Property_accessors#Property_names
12586
13302
  //
12587
- // So, to ensure that we are checking the same `name` that JavaScript would use,
12588
- // we cast it to a string, if possible.
12589
- // Doing `name + ''` can cause a repl error if the result to `toString` is not a string,
12590
- // this is, this will handle objects that misbehave.
12591
- name = name + '';
12592
- if (!isString(name)) {
12593
- throw $parseMinErr('iseccst',
12594
- 'Cannot convert object to primitive value! '
12595
- + 'Expression: {0}', fullExpression);
12596
- }
12597
- return name;
13303
+ // So, to ensure that we are checking the same `name` that JavaScript would use, we cast it
13304
+ // to a string. It's not always possible. If `name` is an object and its `toString` method is
13305
+ // 'broken' (doesn't return a string, isn't a function, etc.), an error will be thrown:
13306
+ //
13307
+ // TypeError: Cannot convert object to primitive value
13308
+ //
13309
+ // For performance reasons, we don't catch this error here and allow it to propagate up the call
13310
+ // stack. Note that you'll get the same error in JavaScript if you try to access a property using
13311
+ // such a 'broken' object as a key.
13312
+ return name + '';
12598
13313
  }
12599
13314
 
12600
13315
  function ensureSafeObject(obj, fullExpression) {
@@ -12855,6 +13570,7 @@ AST.ArrayExpression = 'ArrayExpression';
12855
13570
  AST.Property = 'Property';
12856
13571
  AST.ObjectExpression = 'ObjectExpression';
12857
13572
  AST.ThisExpression = 'ThisExpression';
13573
+ AST.LocalsExpression = 'LocalsExpression';
12858
13574
 
12859
13575
  // Internal use only
12860
13576
  AST.NGValueParameter = 'NGValueParameter';
@@ -13155,7 +13871,8 @@ AST.prototype = {
13155
13871
  'false': { type: AST.Literal, value: false },
13156
13872
  'null': { type: AST.Literal, value: null },
13157
13873
  'undefined': {type: AST.Literal, value: undefined },
13158
- 'this': {type: AST.ThisExpression }
13874
+ 'this': {type: AST.ThisExpression },
13875
+ '$locals': {type: AST.LocalsExpression }
13159
13876
  }
13160
13877
  };
13161
13878
 
@@ -13275,6 +13992,10 @@ function findConstantAndWatchExpressions(ast, $filter) {
13275
13992
  ast.constant = false;
13276
13993
  ast.toWatch = [];
13277
13994
  break;
13995
+ case AST.LocalsExpression:
13996
+ ast.constant = false;
13997
+ ast.toWatch = [];
13998
+ break;
13278
13999
  }
13279
14000
  }
13280
14001
 
@@ -13518,6 +14239,9 @@ ASTCompiler.prototype = {
13518
14239
  intoId = intoId || this.nextId();
13519
14240
  self.recurse(ast.object, left, undefined, function() {
13520
14241
  self.if_(self.notNull(left), function() {
14242
+ if (create && create !== 1) {
14243
+ self.addEnsureSafeAssignContext(left);
14244
+ }
13521
14245
  if (ast.computed) {
13522
14246
  right = self.nextId();
13523
14247
  self.recurse(ast.property, right);
@@ -13599,7 +14323,7 @@ ASTCompiler.prototype = {
13599
14323
  right = this.nextId();
13600
14324
  left = {};
13601
14325
  if (!isAssignable(ast.left)) {
13602
- throw $parseMinErr('lval', 'Trying to assing a value to a non l-value');
14326
+ throw $parseMinErr('lval', 'Trying to assign a value to a non l-value');
13603
14327
  }
13604
14328
  this.recurse(ast.left, undefined, left, function() {
13605
14329
  self.if_(self.notNull(left.context), function() {
@@ -13641,6 +14365,10 @@ ASTCompiler.prototype = {
13641
14365
  this.assign(intoId, 's');
13642
14366
  recursionFn('s');
13643
14367
  break;
14368
+ case AST.LocalsExpression:
14369
+ this.assign(intoId, 'l');
14370
+ recursionFn('l');
14371
+ break;
13644
14372
  case AST.NGValueParameter:
13645
14373
  this.assign(intoId, 'v');
13646
14374
  recursionFn('v');
@@ -13748,7 +14476,7 @@ ASTCompiler.prototype = {
13748
14476
  },
13749
14477
 
13750
14478
  getStringValue: function(item) {
13751
- this.assign(item, 'getStringValue(' + item + ',text)');
14479
+ this.assign(item, 'getStringValue(' + item + ')');
13752
14480
  },
13753
14481
 
13754
14482
  ensureSafeAssignContext: function(item) {
@@ -13968,6 +14696,10 @@ ASTInterpreter.prototype = {
13968
14696
  return function(scope) {
13969
14697
  return context ? {value: scope} : scope;
13970
14698
  };
14699
+ case AST.LocalsExpression:
14700
+ return function(scope, locals) {
14701
+ return context ? {value: locals} : locals;
14702
+ };
13971
14703
  case AST.NGValueParameter:
13972
14704
  return function(scope, locals, assign, inputs) {
13973
14705
  return context ? {value: assign} : assign;
@@ -14132,8 +14864,11 @@ ASTInterpreter.prototype = {
14132
14864
  rhs = right(scope, locals, assign, inputs);
14133
14865
  rhs = getStringValue(rhs);
14134
14866
  ensureSafeMemberName(rhs, expression);
14135
- if (create && create !== 1 && lhs && !(lhs[rhs])) {
14136
- lhs[rhs] = {};
14867
+ if (create && create !== 1) {
14868
+ ensureSafeAssignContext(lhs);
14869
+ if (lhs && !(lhs[rhs])) {
14870
+ lhs[rhs] = {};
14871
+ }
14137
14872
  }
14138
14873
  value = lhs[rhs];
14139
14874
  ensureSafeObject(value, expression);
@@ -14148,8 +14883,11 @@ ASTInterpreter.prototype = {
14148
14883
  nonComputedMember: function(left, right, expensiveChecks, context, create, expression) {
14149
14884
  return function(scope, locals, assign, inputs) {
14150
14885
  var lhs = left(scope, locals, assign, inputs);
14151
- if (create && create !== 1 && lhs && !(lhs[right])) {
14152
- lhs[right] = {};
14886
+ if (create && create !== 1) {
14887
+ ensureSafeAssignContext(lhs);
14888
+ if (lhs && !(lhs[right])) {
14889
+ lhs[right] = {};
14890
+ }
14153
14891
  }
14154
14892
  var value = lhs != null ? lhs[right] : undefined;
14155
14893
  if (expensiveChecks || isPossiblyDangerousMemberName(right)) {
@@ -14190,9 +14928,6 @@ Parser.prototype = {
14190
14928
  }
14191
14929
  };
14192
14930
 
14193
- var getterFnCacheDefault = createMap();
14194
- var getterFnCacheExpensive = createMap();
14195
-
14196
14931
  function isPossiblyDangerousMemberName(name) {
14197
14932
  return name == 'constructor';
14198
14933
  }
@@ -14268,10 +15003,19 @@ function $ParseProvider() {
14268
15003
  csp: noUnsafeEval,
14269
15004
  expensiveChecks: true
14270
15005
  };
15006
+ var runningChecksEnabled = false;
15007
+
15008
+ $parse.$$runningExpensiveChecks = function() {
15009
+ return runningChecksEnabled;
15010
+ };
15011
+
15012
+ return $parse;
14271
15013
 
14272
- return function $parse(exp, interceptorFn, expensiveChecks) {
15014
+ function $parse(exp, interceptorFn, expensiveChecks) {
14273
15015
  var parsedExpression, oneTime, cacheKey;
14274
15016
 
15017
+ expensiveChecks = expensiveChecks || runningChecksEnabled;
15018
+
14275
15019
  switch (typeof exp) {
14276
15020
  case 'string':
14277
15021
  exp = exp.trim();
@@ -14297,6 +15041,9 @@ function $ParseProvider() {
14297
15041
  } else if (parsedExpression.inputs) {
14298
15042
  parsedExpression.$$watchDelegate = inputsWatchDelegate;
14299
15043
  }
15044
+ if (expensiveChecks) {
15045
+ parsedExpression = expensiveChecksInterceptor(parsedExpression);
15046
+ }
14300
15047
  cache[cacheKey] = parsedExpression;
14301
15048
  }
14302
15049
  return addInterceptor(parsedExpression, interceptorFn);
@@ -14305,9 +15052,33 @@ function $ParseProvider() {
14305
15052
  return addInterceptor(exp, interceptorFn);
14306
15053
 
14307
15054
  default:
14308
- return noop;
15055
+ return addInterceptor(noop, interceptorFn);
14309
15056
  }
14310
- };
15057
+ }
15058
+
15059
+ function expensiveChecksInterceptor(fn) {
15060
+ if (!fn) return fn;
15061
+ expensiveCheckFn.$$watchDelegate = fn.$$watchDelegate;
15062
+ expensiveCheckFn.assign = expensiveChecksInterceptor(fn.assign);
15063
+ expensiveCheckFn.constant = fn.constant;
15064
+ expensiveCheckFn.literal = fn.literal;
15065
+ for (var i = 0; fn.inputs && i < fn.inputs.length; ++i) {
15066
+ fn.inputs[i] = expensiveChecksInterceptor(fn.inputs[i]);
15067
+ }
15068
+ expensiveCheckFn.inputs = fn.inputs;
15069
+
15070
+ return expensiveCheckFn;
15071
+
15072
+ function expensiveCheckFn(scope, locals, assign, inputs) {
15073
+ var expensiveCheckOldValue = runningChecksEnabled;
15074
+ runningChecksEnabled = true;
15075
+ try {
15076
+ return fn(scope, locals, assign, inputs);
15077
+ } finally {
15078
+ runningChecksEnabled = expensiveCheckOldValue;
15079
+ }
15080
+ }
15081
+ }
14311
15082
 
14312
15083
  function expressionInputDirtyCheck(newValue, oldValueOfValue) {
14313
15084
 
@@ -14424,13 +15195,9 @@ function $ParseProvider() {
14424
15195
  function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
14425
15196
  var unwatch;
14426
15197
  return unwatch = scope.$watch(function constantWatch(scope) {
14427
- return parsedExpression(scope);
14428
- }, function constantListener(value, old, scope) {
14429
- if (isFunction(listener)) {
14430
- listener.apply(this, arguments);
14431
- }
14432
15198
  unwatch();
14433
- }, objectEquality);
15199
+ return parsedExpression(scope);
15200
+ }, listener, objectEquality);
14434
15201
  }
14435
15202
 
14436
15203
  function addInterceptor(parsedExpression, interceptorFn) {
@@ -14523,7 +15290,7 @@ function $ParseProvider() {
14523
15290
  *
14524
15291
  * Note: progress/notify callbacks are not currently supported via the ES6-style interface.
14525
15292
  *
14526
- * Note: unlike ES6 behaviour, an exception thrown in the constructor function will NOT implicitly reject the promise.
15293
+ * Note: unlike ES6 behavior, an exception thrown in the constructor function will NOT implicitly reject the promise.
14527
15294
  *
14528
15295
  * However, the more traditional CommonJS-style usage is still available, and documented below.
14529
15296
  *
@@ -14713,18 +15480,6 @@ function $$QProvider() {
14713
15480
  */
14714
15481
  function qFactory(nextTick, exceptionHandler) {
14715
15482
  var $qMinErr = minErr('$q', TypeError);
14716
- function callOnce(self, resolveFn, rejectFn) {
14717
- var called = false;
14718
- function wrap(fn) {
14719
- return function(value) {
14720
- if (called) return;
14721
- called = true;
14722
- fn.call(self, value);
14723
- };
14724
- }
14725
-
14726
- return [wrap(resolveFn), wrap(rejectFn)];
14727
- }
14728
15483
 
14729
15484
  /**
14730
15485
  * @ngdoc method
@@ -14737,7 +15492,12 @@ function qFactory(nextTick, exceptionHandler) {
14737
15492
  * @returns {Deferred} Returns a new instance of deferred.
14738
15493
  */
14739
15494
  var defer = function() {
14740
- return new Deferred();
15495
+ var d = new Deferred();
15496
+ //Necessary to support unbound execution :/
15497
+ d.resolve = simpleBind(d, d.resolve);
15498
+ d.reject = simpleBind(d, d.reject);
15499
+ d.notify = simpleBind(d, d.notify);
15500
+ return d;
14741
15501
  };
14742
15502
 
14743
15503
  function Promise() {
@@ -14810,10 +15570,6 @@ function qFactory(nextTick, exceptionHandler) {
14810
15570
 
14811
15571
  function Deferred() {
14812
15572
  this.promise = new Promise();
14813
- //Necessary to support unbound execution :/
14814
- this.resolve = simpleBind(this, this.resolve);
14815
- this.reject = simpleBind(this, this.reject);
14816
- this.notify = simpleBind(this, this.notify);
14817
15573
  }
14818
15574
 
14819
15575
  extend(Deferred.prototype, {
@@ -14831,23 +15587,34 @@ function qFactory(nextTick, exceptionHandler) {
14831
15587
  },
14832
15588
 
14833
15589
  $$resolve: function(val) {
14834
- var then, fns;
14835
-
14836
- fns = callOnce(this, this.$$resolve, this.$$reject);
15590
+ var then;
15591
+ var that = this;
15592
+ var done = false;
14837
15593
  try {
14838
15594
  if ((isObject(val) || isFunction(val))) then = val && val.then;
14839
15595
  if (isFunction(then)) {
14840
15596
  this.promise.$$state.status = -1;
14841
- then.call(val, fns[0], fns[1], this.notify);
15597
+ then.call(val, resolvePromise, rejectPromise, simpleBind(this, this.notify));
14842
15598
  } else {
14843
15599
  this.promise.$$state.value = val;
14844
15600
  this.promise.$$state.status = 1;
14845
15601
  scheduleProcessQueue(this.promise.$$state);
14846
15602
  }
14847
15603
  } catch (e) {
14848
- fns[1](e);
15604
+ rejectPromise(e);
14849
15605
  exceptionHandler(e);
14850
15606
  }
15607
+
15608
+ function resolvePromise(val) {
15609
+ if (done) return;
15610
+ done = true;
15611
+ that.$$resolve(val);
15612
+ }
15613
+ function rejectPromise(val) {
15614
+ if (done) return;
15615
+ done = true;
15616
+ that.$$reject(val);
15617
+ }
14851
15618
  },
14852
15619
 
14853
15620
  reject: function(reason) {
@@ -15036,11 +15803,6 @@ function qFactory(nextTick, exceptionHandler) {
15036
15803
  throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
15037
15804
  }
15038
15805
 
15039
- if (!(this instanceof Q)) {
15040
- // More useful when $Q is the Promise itself.
15041
- return new Q(resolver);
15042
- }
15043
-
15044
15806
  var deferred = new Deferred();
15045
15807
 
15046
15808
  function resolveFn(value) {
@@ -15056,6 +15818,10 @@ function qFactory(nextTick, exceptionHandler) {
15056
15818
  return deferred.promise;
15057
15819
  };
15058
15820
 
15821
+ // Let's make the instanceof operator work for promises, so that
15822
+ // `new $q(fn) instanceof $q` would evaluate to true.
15823
+ $Q.prototype = Promise.prototype;
15824
+
15059
15825
  $Q.defer = defer;
15060
15826
  $Q.reject = reject;
15061
15827
  $Q.when = when;
@@ -15189,8 +15955,8 @@ function $RootScopeProvider() {
15189
15955
  return ChildScope;
15190
15956
  }
15191
15957
 
15192
- this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
15193
- function($injector, $exceptionHandler, $parse, $browser) {
15958
+ this.$get = ['$exceptionHandler', '$parse', '$browser',
15959
+ function($exceptionHandler, $parse, $browser) {
15194
15960
 
15195
15961
  function destroyChildScope($event) {
15196
15962
  $event.currentScope.$$destroyed = true;
@@ -15474,7 +16240,7 @@ function $RootScopeProvider() {
15474
16240
  * - `newVal` contains the current value of the `watchExpression`
15475
16241
  * - `oldVal` contains the previous value of the `watchExpression`
15476
16242
  * - `scope` refers to the current scope
15477
- * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
16243
+ * @param {boolean=} [objectEquality=false] Compare for object equality using {@link angular.equals} instead of
15478
16244
  * comparing for reference equality.
15479
16245
  * @returns {function()} Returns a deregistration function for this listener.
15480
16246
  */
@@ -15839,7 +16605,7 @@ function $RootScopeProvider() {
15839
16605
  *
15840
16606
  */
15841
16607
  $digest: function() {
15842
- var watch, value, last,
16608
+ var watch, value, last, fn, get,
15843
16609
  watchers,
15844
16610
  length,
15845
16611
  dirty, ttl = TTL,
@@ -15885,7 +16651,8 @@ function $RootScopeProvider() {
15885
16651
  // Most common watches are on primitives, in which case we can short
15886
16652
  // circuit it with === operator, only when === fails do we use .equals
15887
16653
  if (watch) {
15888
- if ((value = watch.get(current)) !== (last = watch.last) &&
16654
+ get = watch.get;
16655
+ if ((value = get(current)) !== (last = watch.last) &&
15889
16656
  !(watch.eq
15890
16657
  ? equals(value, last)
15891
16658
  : (typeof value === 'number' && typeof last === 'number'
@@ -15893,7 +16660,8 @@ function $RootScopeProvider() {
15893
16660
  dirty = true;
15894
16661
  lastDirtyWatch = watch;
15895
16662
  watch.last = watch.eq ? copy(value, null) : value;
15896
- watch.fn(value, ((last === initWatchVal) ? value : last), current);
16663
+ fn = watch.fn;
16664
+ fn(value, ((last === initWatchVal) ? value : last), current);
15897
16665
  if (ttl < 5) {
15898
16666
  logIdx = 4 - ttl;
15899
16667
  if (!watchLog[logIdx]) watchLog[logIdx] = [];
@@ -16093,7 +16861,7 @@ function $RootScopeProvider() {
16093
16861
  });
16094
16862
  }
16095
16863
 
16096
- asyncQueue.push({scope: this, expression: expr, locals: locals});
16864
+ asyncQueue.push({scope: this, expression: $parse(expr), locals: locals});
16097
16865
  },
16098
16866
 
16099
16867
  $$postDigest: function(fn) {
@@ -16185,6 +16953,7 @@ function $RootScopeProvider() {
16185
16953
  $applyAsync: function(expr) {
16186
16954
  var scope = this;
16187
16955
  expr && applyAsyncQueue.push($applyAsyncExpression);
16956
+ expr = $parse(expr);
16188
16957
  scheduleApplyAsync();
16189
16958
 
16190
16959
  function $applyAsyncExpression() {
@@ -16459,6 +17228,21 @@ function $RootScopeProvider() {
16459
17228
  }];
16460
17229
  }
16461
17230
 
17231
+ /**
17232
+ * @ngdoc service
17233
+ * @name $rootElement
17234
+ *
17235
+ * @description
17236
+ * The root element of Angular application. This is either the element where {@link
17237
+ * ng.directive:ngApp ngApp} was declared or the element passed into
17238
+ * {@link angular.bootstrap}. The element represents the root element of application. It is also the
17239
+ * location where the application's {@link auto.$injector $injector} service gets
17240
+ * published, and can be retrieved using `$rootElement.injector()`.
17241
+ */
17242
+
17243
+
17244
+ // the implementation is in angular.bootstrap
17245
+
16462
17246
  /**
16463
17247
  * @description
16464
17248
  * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
@@ -16673,13 +17457,15 @@ function $SceDelegateProvider() {
16673
17457
  * @kind function
16674
17458
  *
16675
17459
  * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
16676
- * provided. This must be an array or null. A snapshot of this array is used so further
16677
- * changes to the array are ignored.
17460
+ * provided. This must be an array or null. A snapshot of this array is used so further
17461
+ * changes to the array are ignored.
16678
17462
  *
16679
- * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
16680
- * allowed in this array.
17463
+ * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
17464
+ * allowed in this array.
16681
17465
  *
16682
- * Note: **an empty whitelist array will block all URLs**!
17466
+ * <div class="alert alert-warning">
17467
+ * **Note:** an empty whitelist array will block all URLs!
17468
+ * </div>
16683
17469
  *
16684
17470
  * @return {Array} the currently set whitelist array.
16685
17471
  *
@@ -16702,17 +17488,17 @@ function $SceDelegateProvider() {
16702
17488
  * @kind function
16703
17489
  *
16704
17490
  * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
16705
- * provided. This must be an array or null. A snapshot of this array is used so further
16706
- * changes to the array are ignored.
17491
+ * provided. This must be an array or null. A snapshot of this array is used so further
17492
+ * changes to the array are ignored.
16707
17493
  *
16708
- * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
16709
- * allowed in this array.
17494
+ * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
17495
+ * allowed in this array.
16710
17496
  *
16711
- * The typical usage for the blacklist is to **block
16712
- * [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
16713
- * these would otherwise be trusted but actually return content from the redirected domain.
17497
+ * The typical usage for the blacklist is to **block
17498
+ * [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
17499
+ * these would otherwise be trusted but actually return content from the redirected domain.
16714
17500
  *
16715
- * Finally, **the blacklist overrides the whitelist** and has the final say.
17501
+ * Finally, **the blacklist overrides the whitelist** and has the final say.
16716
17502
  *
16717
17503
  * @return {Array} the currently set blacklist array.
16718
17504
  *
@@ -16871,6 +17657,11 @@ function $SceDelegateProvider() {
16871
17657
  * returns the originally supplied value if the queried context type is a supertype of the
16872
17658
  * created type. If this condition isn't satisfied, throws an exception.
16873
17659
  *
17660
+ * <div class="alert alert-danger">
17661
+ * Disabling auto-escaping is extremely dangerous, it usually creates a Cross Site Scripting
17662
+ * (XSS) vulnerability in your application.
17663
+ * </div>
17664
+ *
16874
17665
  * @param {string} type The kind of context in which this value is to be used.
16875
17666
  * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
16876
17667
  * `$sceDelegate.trustAs`} call.
@@ -17678,26 +18469,63 @@ function $SnifferProvider() {
17678
18469
  var $compileMinErr = minErr('$compile');
17679
18470
 
17680
18471
  /**
17681
- * @ngdoc service
17682
- * @name $templateRequest
17683
- *
18472
+ * @ngdoc provider
18473
+ * @name $templateRequestProvider
17684
18474
  * @description
17685
- * The `$templateRequest` service runs security checks then downloads the provided template using
17686
- * `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
17687
- * fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
17688
- * exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
17689
- * contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
17690
- * when `tpl` is of type string and `$templateCache` has the matching entry.
17691
- *
17692
- * @param {string|TrustedResourceUrl} tpl The HTTP request template URL
17693
- * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
18475
+ * Used to configure the options passed to the {@link $http} service when making a template request.
17694
18476
  *
17695
- * @return {Promise} a promise for the HTTP response data of the given URL.
17696
- *
17697
- * @property {number} totalPendingRequests total amount of pending template requests being downloaded.
18477
+ * For example, it can be used for specifying the "Accept" header that is sent to the server, when
18478
+ * requesting a template.
17698
18479
  */
17699
18480
  function $TemplateRequestProvider() {
18481
+
18482
+ var httpOptions;
18483
+
18484
+ /**
18485
+ * @ngdoc method
18486
+ * @name $templateRequestProvider#httpOptions
18487
+ * @description
18488
+ * The options to be passed to the {@link $http} service when making the request.
18489
+ * You can use this to override options such as the "Accept" header for template requests.
18490
+ *
18491
+ * The {@link $templateRequest} will set the `cache` and the `transformResponse` properties of the
18492
+ * options if not overridden here.
18493
+ *
18494
+ * @param {string=} value new value for the {@link $http} options.
18495
+ * @returns {string|self} Returns the {@link $http} options when used as getter and self if used as setter.
18496
+ */
18497
+ this.httpOptions = function(val) {
18498
+ if (val) {
18499
+ httpOptions = val;
18500
+ return this;
18501
+ }
18502
+ return httpOptions;
18503
+ };
18504
+
18505
+ /**
18506
+ * @ngdoc service
18507
+ * @name $templateRequest
18508
+ *
18509
+ * @description
18510
+ * The `$templateRequest` service runs security checks then downloads the provided template using
18511
+ * `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
18512
+ * fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
18513
+ * exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
18514
+ * contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
18515
+ * when `tpl` is of type string and `$templateCache` has the matching entry.
18516
+ *
18517
+ * If you want to pass custom options to the `$http` service, such as setting the Accept header you
18518
+ * can configure this via {@link $templateRequestProvider#httpOptions}.
18519
+ *
18520
+ * @param {string|TrustedResourceUrl} tpl The HTTP request template URL
18521
+ * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
18522
+ *
18523
+ * @return {Promise} a promise for the HTTP response data of the given URL.
18524
+ *
18525
+ * @property {number} totalPendingRequests total amount of pending template requests being downloaded.
18526
+ */
17700
18527
  this.$get = ['$templateCache', '$http', '$q', '$sce', function($templateCache, $http, $q, $sce) {
18528
+
17701
18529
  function handleRequestFn(tpl, ignoreRequestError) {
17702
18530
  handleRequestFn.totalPendingRequests++;
17703
18531
 
@@ -17720,12 +18548,10 @@ function $TemplateRequestProvider() {
17720
18548
  transformResponse = null;
17721
18549
  }
17722
18550
 
17723
- var httpOptions = {
17724
- cache: $templateCache,
17725
- transformResponse: transformResponse
17726
- };
17727
-
17728
- return $http.get(tpl, httpOptions)
18551
+ return $http.get(tpl, extend({
18552
+ cache: $templateCache,
18553
+ transformResponse: transformResponse
18554
+ }, httpOptions))
17729
18555
  ['finally'](function() {
17730
18556
  handleRequestFn.totalPendingRequests--;
17731
18557
  })
@@ -17896,8 +18722,8 @@ function $TimeoutProvider() {
17896
18722
  * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
17897
18723
  * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
17898
18724
  * @param {...*=} Pass additional parameters to the executed function.
17899
- * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
17900
- * promise will be resolved with is the return value of the `fn` function.
18725
+ * @returns {Promise} Promise that will be resolved when the timeout is reached. The promise
18726
+ * will be resolved with the return value of the `fn` function.
17901
18727
  *
17902
18728
  */
17903
18729
  function timeout(fn, delay, invokeApply) {
@@ -18573,6 +19399,10 @@ function getTypeForFilter(val) {
18573
19399
  return (val === null) ? 'null' : typeof val;
18574
19400
  }
18575
19401
 
19402
+ var MAX_DIGITS = 22;
19403
+ var DECIMAL_SEP = '.';
19404
+ var ZERO_CHAR = '0';
19405
+
18576
19406
  /**
18577
19407
  * @ngdoc filter
18578
19408
  * @name currency
@@ -18662,7 +19492,7 @@ function currencyFilter($locale) {
18662
19492
  * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
18663
19493
  * If this is not provided then the fraction size is computed from the current locale's number
18664
19494
  * formatting pattern. In the case of the default locale, it will be 3.
18665
- * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
19495
+ * @returns {string} Number rounded to fractionSize and places a “,” after each third digit.
18666
19496
  *
18667
19497
  * @example
18668
19498
  <example module="numberFilterExample">
@@ -18697,8 +19527,6 @@ function currencyFilter($locale) {
18697
19527
  </file>
18698
19528
  </example>
18699
19529
  */
18700
-
18701
-
18702
19530
  numberFilter.$inject = ['$locale'];
18703
19531
  function numberFilter($locale) {
18704
19532
  var formats = $locale.NUMBER_FORMATS;
@@ -18712,93 +19540,194 @@ function numberFilter($locale) {
18712
19540
  };
18713
19541
  }
18714
19542
 
18715
- var DECIMAL_SEP = '.';
18716
- function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
18717
- if (isObject(number)) return '';
19543
+ /**
19544
+ * Parse a number (as a string) into three components that can be used
19545
+ * for formatting the number.
19546
+ *
19547
+ * (Significant bits of this parse algorithm came from https://github.com/MikeMcl/big.js/)
19548
+ *
19549
+ * @param {string} numStr The number to parse
19550
+ * @return {object} An object describing this number, containing the following keys:
19551
+ * - d : an array of digits containing leading zeros as necessary
19552
+ * - i : the number of the digits in `d` that are to the left of the decimal point
19553
+ * - e : the exponent for numbers that would need more than `MAX_DIGITS` digits in `d`
19554
+ *
19555
+ */
19556
+ function parse(numStr) {
19557
+ var exponent = 0, digits, numberOfIntegerDigits;
19558
+ var i, j, zeros;
18718
19559
 
18719
- var isNegative = number < 0;
18720
- number = Math.abs(number);
19560
+ // Decimal point?
19561
+ if ((numberOfIntegerDigits = numStr.indexOf(DECIMAL_SEP)) > -1) {
19562
+ numStr = numStr.replace(DECIMAL_SEP, '');
19563
+ }
18721
19564
 
18722
- var isInfinity = number === Infinity;
18723
- if (!isInfinity && !isFinite(number)) return '';
19565
+ // Exponential form?
19566
+ if ((i = numStr.search(/e/i)) > 0) {
19567
+ // Work out the exponent.
19568
+ if (numberOfIntegerDigits < 0) numberOfIntegerDigits = i;
19569
+ numberOfIntegerDigits += +numStr.slice(i + 1);
19570
+ numStr = numStr.substring(0, i);
19571
+ } else if (numberOfIntegerDigits < 0) {
19572
+ // There was no decimal point or exponent so it is an integer.
19573
+ numberOfIntegerDigits = numStr.length;
19574
+ }
18724
19575
 
18725
- var numStr = number + '',
18726
- formatedText = '',
18727
- hasExponent = false,
18728
- parts = [];
19576
+ // Count the number of leading zeros.
19577
+ for (i = 0; numStr.charAt(i) == ZERO_CHAR; i++);
18729
19578
 
18730
- if (isInfinity) formatedText = '\u221e';
19579
+ if (i == (zeros = numStr.length)) {
19580
+ // The digits are all zero.
19581
+ digits = [0];
19582
+ numberOfIntegerDigits = 1;
19583
+ } else {
19584
+ // Count the number of trailing zeros
19585
+ zeros--;
19586
+ while (numStr.charAt(zeros) == ZERO_CHAR) zeros--;
18731
19587
 
18732
- if (!isInfinity && numStr.indexOf('e') !== -1) {
18733
- var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
18734
- if (match && match[2] == '-' && match[3] > fractionSize + 1) {
18735
- number = 0;
18736
- } else {
18737
- formatedText = numStr;
18738
- hasExponent = true;
19588
+ // Trailing zeros are insignificant so ignore them
19589
+ numberOfIntegerDigits -= i;
19590
+ digits = [];
19591
+ // Convert string to array of digits without leading/trailing zeros.
19592
+ for (j = 0; i <= zeros; i++, j++) {
19593
+ digits[j] = +numStr.charAt(i);
18739
19594
  }
18740
19595
  }
18741
19596
 
18742
- if (!isInfinity && !hasExponent) {
18743
- var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
19597
+ // If the number overflows the maximum allowed digits then use an exponent.
19598
+ if (numberOfIntegerDigits > MAX_DIGITS) {
19599
+ digits = digits.splice(0, MAX_DIGITS - 1);
19600
+ exponent = numberOfIntegerDigits - 1;
19601
+ numberOfIntegerDigits = 1;
19602
+ }
18744
19603
 
18745
- // determine fractionSize if it is not specified
18746
- if (isUndefined(fractionSize)) {
18747
- fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
19604
+ return { d: digits, e: exponent, i: numberOfIntegerDigits };
19605
+ }
19606
+
19607
+ /**
19608
+ * Round the parsed number to the specified number of decimal places
19609
+ * This function changed the parsedNumber in-place
19610
+ */
19611
+ function roundNumber(parsedNumber, fractionSize, minFrac, maxFrac) {
19612
+ var digits = parsedNumber.d;
19613
+ var fractionLen = digits.length - parsedNumber.i;
19614
+
19615
+ // determine fractionSize if it is not specified; `+fractionSize` converts it to a number
19616
+ fractionSize = (isUndefined(fractionSize)) ? Math.min(Math.max(minFrac, fractionLen), maxFrac) : +fractionSize;
19617
+
19618
+ // The index of the digit to where rounding is to occur
19619
+ var roundAt = fractionSize + parsedNumber.i;
19620
+ var digit = digits[roundAt];
19621
+
19622
+ if (roundAt > 0) {
19623
+ digits.splice(roundAt);
19624
+ } else {
19625
+ // We rounded to zero so reset the parsedNumber
19626
+ parsedNumber.i = 1;
19627
+ digits.length = roundAt = fractionSize + 1;
19628
+ for (var i=0; i < roundAt; i++) digits[i] = 0;
18748
19629
  }
18749
19630
 
18750
- // safely round numbers in JS without hitting imprecisions of floating-point arithmetics
18751
- // inspired by:
18752
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
18753
- number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
19631
+ if (digit >= 5) digits[roundAt - 1]++;
18754
19632
 
18755
- var fraction = ('' + number).split(DECIMAL_SEP);
18756
- var whole = fraction[0];
18757
- fraction = fraction[1] || '';
19633
+ // Pad out with zeros to get the required fraction length
19634
+ for (; fractionLen < fractionSize; fractionLen++) digits.push(0);
18758
19635
 
18759
- var i, pos = 0,
18760
- lgroup = pattern.lgSize,
18761
- group = pattern.gSize;
18762
19636
 
18763
- if (whole.length >= (lgroup + group)) {
18764
- pos = whole.length - lgroup;
18765
- for (i = 0; i < pos; i++) {
18766
- if ((pos - i) % group === 0 && i !== 0) {
18767
- formatedText += groupSep;
18768
- }
18769
- formatedText += whole.charAt(i);
18770
- }
19637
+ // Do any carrying, e.g. a digit was rounded up to 10
19638
+ var carry = digits.reduceRight(function(carry, d, i, digits) {
19639
+ d = d + carry;
19640
+ digits[i] = d % 10;
19641
+ return Math.floor(d / 10);
19642
+ }, 0);
19643
+ if (carry) {
19644
+ digits.unshift(carry);
19645
+ parsedNumber.i++;
18771
19646
  }
19647
+ }
18772
19648
 
18773
- for (i = pos; i < whole.length; i++) {
18774
- if ((whole.length - i) % lgroup === 0 && i !== 0) {
18775
- formatedText += groupSep;
18776
- }
18777
- formatedText += whole.charAt(i);
19649
+ /**
19650
+ * Format a number into a string
19651
+ * @param {number} number The number to format
19652
+ * @param {{
19653
+ * minFrac, // the minimum number of digits required in the fraction part of the number
19654
+ * maxFrac, // the maximum number of digits required in the fraction part of the number
19655
+ * gSize, // number of digits in each group of separated digits
19656
+ * lgSize, // number of digits in the last group of digits before the decimal separator
19657
+ * negPre, // the string to go in front of a negative number (e.g. `-` or `(`))
19658
+ * posPre, // the string to go in front of a positive number
19659
+ * negSuf, // the string to go after a negative number (e.g. `)`)
19660
+ * posSuf // the string to go after a positive number
19661
+ * }} pattern
19662
+ * @param {string} groupSep The string to separate groups of number (e.g. `,`)
19663
+ * @param {string} decimalSep The string to act as the decimal separator (e.g. `.`)
19664
+ * @param {[type]} fractionSize The size of the fractional part of the number
19665
+ * @return {string} The number formatted as a string
19666
+ */
19667
+ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
19668
+
19669
+ if (!(isString(number) || isNumber(number)) || isNaN(number)) return '';
19670
+
19671
+ var isInfinity = !isFinite(number);
19672
+ var isZero = false;
19673
+ var numStr = Math.abs(number) + '',
19674
+ formattedText = '',
19675
+ parsedNumber;
19676
+
19677
+ if (isInfinity) {
19678
+ formattedText = '\u221e';
19679
+ } else {
19680
+ parsedNumber = parse(numStr);
19681
+
19682
+ roundNumber(parsedNumber, fractionSize, pattern.minFrac, pattern.maxFrac);
19683
+
19684
+ var digits = parsedNumber.d;
19685
+ var integerLen = parsedNumber.i;
19686
+ var exponent = parsedNumber.e;
19687
+ var decimals = [];
19688
+ isZero = digits.reduce(function(isZero, d) { return isZero && !d; }, true);
19689
+
19690
+ // pad zeros for small numbers
19691
+ while (integerLen < 0) {
19692
+ digits.unshift(0);
19693
+ integerLen++;
18778
19694
  }
18779
19695
 
18780
- // format fraction part.
18781
- while (fraction.length < fractionSize) {
18782
- fraction += '0';
19696
+ // extract decimals digits
19697
+ if (integerLen > 0) {
19698
+ decimals = digits.splice(integerLen);
19699
+ } else {
19700
+ decimals = digits;
19701
+ digits = [0];
18783
19702
  }
18784
19703
 
18785
- if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
18786
- } else {
18787
- if (fractionSize > 0 && number < 1) {
18788
- formatedText = number.toFixed(fractionSize);
18789
- number = parseFloat(formatedText);
18790
- formatedText = formatedText.replace(DECIMAL_SEP, decimalSep);
19704
+ // format the integer digits with grouping separators
19705
+ var groups = [];
19706
+ if (digits.length > pattern.lgSize) {
19707
+ groups.unshift(digits.splice(-pattern.lgSize).join(''));
18791
19708
  }
18792
- }
19709
+ while (digits.length > pattern.gSize) {
19710
+ groups.unshift(digits.splice(-pattern.gSize).join(''));
19711
+ }
19712
+ if (digits.length) {
19713
+ groups.unshift(digits.join(''));
19714
+ }
19715
+ formattedText = groups.join(groupSep);
18793
19716
 
18794
- if (number === 0) {
18795
- isNegative = false;
18796
- }
19717
+ // append the decimal digits
19718
+ if (decimals.length) {
19719
+ formattedText += decimalSep + decimals.join('');
19720
+ }
18797
19721
 
18798
- parts.push(isNegative ? pattern.negPre : pattern.posPre,
18799
- formatedText,
18800
- isNegative ? pattern.negSuf : pattern.posSuf);
18801
- return parts.join('');
19722
+ if (exponent) {
19723
+ formattedText += 'e+' + exponent;
19724
+ }
19725
+ }
19726
+ if (number < 0 && !isZero) {
19727
+ return pattern.negPre + formattedText + pattern.negSuf;
19728
+ } else {
19729
+ return pattern.posPre + formattedText + pattern.posSuf;
19730
+ }
18802
19731
  }
18803
19732
 
18804
19733
  function padNumber(num, digits, trim) {
@@ -18808,7 +19737,7 @@ function padNumber(num, digits, trim) {
18808
19737
  num = -num;
18809
19738
  }
18810
19739
  num = '' + num;
18811
- while (num.length < digits) num = '0' + num;
19740
+ while (num.length < digits) num = ZERO_CHAR + num;
18812
19741
  if (trim) {
18813
19742
  num = num.substr(num.length - digits);
18814
19743
  }
@@ -19077,13 +20006,13 @@ function dateFilter($locale) {
19077
20006
 
19078
20007
  var dateTimezoneOffset = date.getTimezoneOffset();
19079
20008
  if (timezone) {
19080
- dateTimezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
20009
+ dateTimezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
19081
20010
  date = convertTimezoneToLocal(date, timezone, true);
19082
20011
  }
19083
20012
  forEach(parts, function(value) {
19084
20013
  fn = DATE_FORMATS[value];
19085
20014
  text += fn ? fn(date, $locale.DATETIME_FORMATS, dateTimezoneOffset)
19086
- : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
20015
+ : value === "''" ? "'" : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
19087
20016
  });
19088
20017
 
19089
20018
  return text;
@@ -19287,8 +20216,9 @@ function limitToFilter() {
19287
20216
  * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
19288
20217
  * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
19289
20218
  * as expected, make sure they are actually being saved as numbers and not strings.
20219
+ * Array-like values (e.g. NodeLists, jQuery objects, TypedArrays, Strings, etc) are also supported.
19290
20220
  *
19291
- * @param {Array} array The array to sort.
20221
+ * @param {Array} array The array (or array-like object) to sort.
19292
20222
  * @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
19293
20223
  * used by the comparator to determine the order of elements.
19294
20224
  *
@@ -19319,17 +20249,6 @@ function limitToFilter() {
19319
20249
  * `reverse` is not set, which means it defaults to `false`.
19320
20250
  <example module="orderByExample">
19321
20251
  <file name="index.html">
19322
- <script>
19323
- angular.module('orderByExample', [])
19324
- .controller('ExampleController', ['$scope', function($scope) {
19325
- $scope.friends =
19326
- [{name:'John', phone:'555-1212', age:10},
19327
- {name:'Mary', phone:'555-9876', age:19},
19328
- {name:'Mike', phone:'555-4321', age:21},
19329
- {name:'Adam', phone:'555-5678', age:35},
19330
- {name:'Julie', phone:'555-8765', age:29}];
19331
- }]);
19332
- </script>
19333
20252
  <div ng-controller="ExampleController">
19334
20253
  <table class="friend">
19335
20254
  <tr>
@@ -19345,6 +20264,17 @@ function limitToFilter() {
19345
20264
  </table>
19346
20265
  </div>
19347
20266
  </file>
20267
+ <file name="script.js">
20268
+ angular.module('orderByExample', [])
20269
+ .controller('ExampleController', ['$scope', function($scope) {
20270
+ $scope.friends =
20271
+ [{name:'John', phone:'555-1212', age:10},
20272
+ {name:'Mary', phone:'555-9876', age:19},
20273
+ {name:'Mike', phone:'555-4321', age:21},
20274
+ {name:'Adam', phone:'555-5678', age:35},
20275
+ {name:'Julie', phone:'555-8765', age:29}];
20276
+ }]);
20277
+ </file>
19348
20278
  </example>
19349
20279
  *
19350
20280
  * The predicate and reverse parameters can be controlled dynamically through scope properties,
@@ -19352,49 +20282,24 @@ function limitToFilter() {
19352
20282
  * @example
19353
20283
  <example module="orderByExample">
19354
20284
  <file name="index.html">
19355
- <script>
19356
- angular.module('orderByExample', [])
19357
- .controller('ExampleController', ['$scope', function($scope) {
19358
- $scope.friends =
19359
- [{name:'John', phone:'555-1212', age:10},
19360
- {name:'Mary', phone:'555-9876', age:19},
19361
- {name:'Mike', phone:'555-4321', age:21},
19362
- {name:'Adam', phone:'555-5678', age:35},
19363
- {name:'Julie', phone:'555-8765', age:29}];
19364
- $scope.predicate = 'age';
19365
- $scope.reverse = true;
19366
- $scope.order = function(predicate) {
19367
- $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
19368
- $scope.predicate = predicate;
19369
- };
19370
- }]);
19371
- </script>
19372
- <style type="text/css">
19373
- .sortorder:after {
19374
- content: '\25b2';
19375
- }
19376
- .sortorder.reverse:after {
19377
- content: '\25bc';
19378
- }
19379
- </style>
19380
20285
  <div ng-controller="ExampleController">
19381
20286
  <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
19382
20287
  <hr/>
19383
- [ <a href="" ng-click="predicate=''">unsorted</a> ]
20288
+ <button ng-click="predicate=''">Set to unsorted</button>
19384
20289
  <table class="friend">
19385
20290
  <tr>
19386
- <th>
19387
- <a href="" ng-click="order('name')">Name</a>
19388
- <span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
19389
- </th>
19390
- <th>
19391
- <a href="" ng-click="order('phone')">Phone Number</a>
19392
- <span class="sortorder" ng-show="predicate === 'phone'" ng-class="{reverse:reverse}"></span>
19393
- </th>
19394
- <th>
19395
- <a href="" ng-click="order('age')">Age</a>
19396
- <span class="sortorder" ng-show="predicate === 'age'" ng-class="{reverse:reverse}"></span>
19397
- </th>
20291
+ <th>
20292
+ <button ng-click="order('name')">Name</button>
20293
+ <span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
20294
+ </th>
20295
+ <th>
20296
+ <button ng-click="order('phone')">Phone Number</button>
20297
+ <span class="sortorder" ng-show="predicate === 'phone'" ng-class="{reverse:reverse}"></span>
20298
+ </th>
20299
+ <th>
20300
+ <button ng-click="order('age')">Age</button>
20301
+ <span class="sortorder" ng-show="predicate === 'age'" ng-class="{reverse:reverse}"></span>
20302
+ </th>
19398
20303
  </tr>
19399
20304
  <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
19400
20305
  <td>{{friend.name}}</td>
@@ -19404,6 +20309,31 @@ function limitToFilter() {
19404
20309
  </table>
19405
20310
  </div>
19406
20311
  </file>
20312
+ <file name="script.js">
20313
+ angular.module('orderByExample', [])
20314
+ .controller('ExampleController', ['$scope', function($scope) {
20315
+ $scope.friends =
20316
+ [{name:'John', phone:'555-1212', age:10},
20317
+ {name:'Mary', phone:'555-9876', age:19},
20318
+ {name:'Mike', phone:'555-4321', age:21},
20319
+ {name:'Adam', phone:'555-5678', age:35},
20320
+ {name:'Julie', phone:'555-8765', age:29}];
20321
+ $scope.predicate = 'age';
20322
+ $scope.reverse = true;
20323
+ $scope.order = function(predicate) {
20324
+ $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
20325
+ $scope.predicate = predicate;
20326
+ };
20327
+ }]);
20328
+ </file>
20329
+ <file name="style.css">
20330
+ .sortorder:after {
20331
+ content: '\25b2';
20332
+ }
20333
+ .sortorder.reverse:after {
20334
+ content: '\25bc';
20335
+ }
20336
+ </file>
19407
20337
  </example>
19408
20338
  *
19409
20339
  * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
@@ -19415,21 +20345,30 @@ function limitToFilter() {
19415
20345
  * @example
19416
20346
  <example module="orderByExample">
19417
20347
  <file name="index.html">
19418
- <div ng-controller="ExampleController">
19419
- <table class="friend">
19420
- <tr>
19421
- <th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
19422
- (<a href="" ng-click="order('-name',false)">^</a>)</th>
19423
- <th><a href="" ng-click="reverse=!reverse;order('phone', reverse)">Phone Number</a></th>
19424
- <th><a href="" ng-click="reverse=!reverse;order('age',reverse)">Age</a></th>
19425
- </tr>
19426
- <tr ng-repeat="friend in friends">
19427
- <td>{{friend.name}}</td>
19428
- <td>{{friend.phone}}</td>
19429
- <td>{{friend.age}}</td>
19430
- </tr>
19431
- </table>
19432
- </div>
20348
+ <div ng-controller="ExampleController">
20349
+ <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
20350
+ <table class="friend">
20351
+ <tr>
20352
+ <th>
20353
+ <button ng-click="order('name')">Name</button>
20354
+ <span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
20355
+ </th>
20356
+ <th>
20357
+ <button ng-click="order('phone')">Phone Number</button>
20358
+ <span class="sortorder" ng-show="predicate === 'phone'" ng-class="{reverse:reverse}"></span>
20359
+ </th>
20360
+ <th>
20361
+ <button ng-click="order('age')">Age</button>
20362
+ <span class="sortorder" ng-show="predicate === 'age'" ng-class="{reverse:reverse}"></span>
20363
+ </th>
20364
+ </tr>
20365
+ <tr ng-repeat="friend in friends">
20366
+ <td>{{friend.name}}</td>
20367
+ <td>{{friend.phone}}</td>
20368
+ <td>{{friend.age}}</td>
20369
+ </tr>
20370
+ </table>
20371
+ </div>
19433
20372
  </file>
19434
20373
 
19435
20374
  <file name="script.js">
@@ -19443,19 +20382,33 @@ function limitToFilter() {
19443
20382
  { name: 'Adam', phone: '555-5678', age: 35 },
19444
20383
  { name: 'Julie', phone: '555-8765', age: 29 }
19445
20384
  ];
19446
- $scope.order = function(predicate, reverse) {
19447
- $scope.friends = orderBy($scope.friends, predicate, reverse);
20385
+ $scope.order = function(predicate) {
20386
+ $scope.predicate = predicate;
20387
+ $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
20388
+ $scope.friends = orderBy($scope.friends, predicate, $scope.reverse);
19448
20389
  };
19449
- $scope.order('-age',false);
20390
+ $scope.order('age', true);
19450
20391
  }]);
19451
20392
  </file>
20393
+
20394
+ <file name="style.css">
20395
+ .sortorder:after {
20396
+ content: '\25b2';
20397
+ }
20398
+ .sortorder.reverse:after {
20399
+ content: '\25bc';
20400
+ }
20401
+ </file>
19452
20402
  </example>
19453
20403
  */
19454
20404
  orderByFilter.$inject = ['$parse'];
19455
20405
  function orderByFilter($parse) {
19456
20406
  return function(array, sortPredicate, reverseOrder) {
19457
20407
 
19458
- if (!(isArrayLike(array))) return array;
20408
+ if (array == null) return array;
20409
+ if (!isArrayLike(array)) {
20410
+ throw minErr('orderBy')('notarray', 'Expected array but received: {0}', array);
20411
+ }
19459
20412
 
19460
20413
  if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }
19461
20414
  if (sortPredicate.length === 0) { sortPredicate = ['+']; }
@@ -19778,20 +20731,7 @@ var htmlAnchorDirective = valueFn({
19778
20731
  * {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
19779
20732
  *
19780
20733
  * A special directive is necessary because we cannot use interpolation inside the `disabled`
19781
- * attribute. The following example would make the button enabled on Chrome/Firefox
19782
- * but not on older IEs:
19783
- *
19784
- * ```html
19785
- * <!-- See below for an example of ng-disabled being used correctly -->
19786
- * <div ng-init="isDisabled = false">
19787
- * <button disabled="{{isDisabled}}">Disabled</button>
19788
- * </div>
19789
- * ```
19790
- *
19791
- * This is because the HTML specification does not require browsers to preserve the values of
19792
- * boolean attributes such as `disabled` (Their presence means true and their absence means false.)
19793
- * If we put an Angular interpolation expression into such an attribute then the
19794
- * binding information would be lost when the browser removes the attribute.
20734
+ * attribute. See the {@link guide/interpolation interpolation guide} for more info.
19795
20735
  *
19796
20736
  * @example
19797
20737
  <example>
@@ -19826,15 +20766,9 @@ var htmlAnchorDirective = valueFn({
19826
20766
  * Note that this directive should not be used together with {@link ngModel `ngModel`},
19827
20767
  * as this can lead to unexpected behavior.
19828
20768
  *
19829
- * ### Why do we need `ngChecked`?
20769
+ * A special directive is necessary because we cannot use interpolation inside the `checked`
20770
+ * attribute. See the {@link guide/interpolation interpolation guide} for more info.
19830
20771
  *
19831
- * The HTML specification does not require browsers to preserve the values of boolean attributes
19832
- * such as checked. (Their presence means true and their absence means false.)
19833
- * If we put an Angular interpolation expression into such an attribute then the
19834
- * binding information would be lost when the browser removes the attribute.
19835
- * The `ngChecked` directive solves this problem for the `checked` attribute.
19836
- * This complementary directive is not removed by the browser and so provides
19837
- * a permanent reliable place to store the binding information.
19838
20772
  * @example
19839
20773
  <example>
19840
20774
  <file name="index.html">
@@ -19863,13 +20797,12 @@ var htmlAnchorDirective = valueFn({
19863
20797
  * @priority 100
19864
20798
  *
19865
20799
  * @description
19866
- * The HTML specification does not require browsers to preserve the values of boolean attributes
19867
- * such as readonly. (Their presence means true and their absence means false.)
19868
- * If we put an Angular interpolation expression into such an attribute then the
19869
- * binding information would be lost when the browser removes the attribute.
19870
- * The `ngReadonly` directive solves this problem for the `readonly` attribute.
19871
- * This complementary directive is not removed by the browser and so provides
19872
- * a permanent reliable place to store the binding information.
20800
+ *
20801
+ * Sets the `readOnly` attribute on the element, if the expression inside `ngReadonly` is truthy.
20802
+ *
20803
+ * A special directive is necessary because we cannot use interpolation inside the `readOnly`
20804
+ * attribute. See the {@link guide/interpolation interpolation guide} for more info.
20805
+ *
19873
20806
  * @example
19874
20807
  <example>
19875
20808
  <file name="index.html">
@@ -19898,13 +20831,11 @@ var htmlAnchorDirective = valueFn({
19898
20831
  * @priority 100
19899
20832
  *
19900
20833
  * @description
19901
- * The HTML specification does not require browsers to preserve the values of boolean attributes
19902
- * such as selected. (Their presence means true and their absence means false.)
19903
- * If we put an Angular interpolation expression into such an attribute then the
19904
- * binding information would be lost when the browser removes the attribute.
19905
- * The `ngSelected` directive solves this problem for the `selected` attribute.
19906
- * This complementary directive is not removed by the browser and so provides
19907
- * a permanent reliable place to store the binding information.
20834
+ *
20835
+ * Sets the `selected` attribute on the element, if the expression inside `ngSelected` is truthy.
20836
+ *
20837
+ * A special directive is necessary because we cannot use interpolation inside the `selected`
20838
+ * attribute. See the {@link guide/interpolation interpolation guide} for more info.
19908
20839
  *
19909
20840
  * @example
19910
20841
  <example>
@@ -19936,13 +20867,12 @@ var htmlAnchorDirective = valueFn({
19936
20867
  * @priority 100
19937
20868
  *
19938
20869
  * @description
19939
- * The HTML specification does not require browsers to preserve the values of boolean attributes
19940
- * such as open. (Their presence means true and their absence means false.)
19941
- * If we put an Angular interpolation expression into such an attribute then the
19942
- * binding information would be lost when the browser removes the attribute.
19943
- * The `ngOpen` directive solves this problem for the `open` attribute.
19944
- * This complementary directive is not removed by the browser and so provides
19945
- * a permanent reliable place to store the binding information.
20870
+ *
20871
+ * Sets the `open` attribute on the element, if the expression inside `ngOpen` is truthy.
20872
+ *
20873
+ * A special directive is necessary because we cannot use interpolation inside the `open`
20874
+ * attribute. See the {@link guide/interpolation interpolation guide} for more info.
20875
+ *
19946
20876
  * @example
19947
20877
  <example>
19948
20878
  <file name="index.html">
@@ -20188,7 +21118,7 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
20188
21118
  *
20189
21119
  * However, if the method is used programmatically, for example by adding dynamically created controls,
20190
21120
  * or controls that have been previously removed without destroying their corresponding DOM element,
20191
- * it's the developers responsiblity to make sure the current state propagates to the parent form.
21121
+ * it's the developers responsibility to make sure the current state propagates to the parent form.
20192
21122
  *
20193
21123
  * For example, if an input control is added that is already `$dirty` and has `$error` properties,
20194
21124
  * calling `$setDirty()` and `$validate()` afterwards will propagate the state to the parent form.
@@ -20398,13 +21328,9 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
20398
21328
  *
20399
21329
  * In Angular, forms can be nested. This means that the outer form is valid when all of the child
20400
21330
  * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
20401
- * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
20402
- * `<form>` but can be nested. This allows you to have nested forms, which is very useful when
20403
- * using Angular validation directives in forms that are dynamically generated using the
20404
- * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
20405
- * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
20406
- * `ngForm` directive and nest these in an outer `form` element.
20407
- *
21331
+ * Angular provides the {@link ng.directive:ngForm `ngForm`} directive, which behaves identically to
21332
+ * `form` but can be nested. Nested forms can be useful, for example, if the validity of a sub-group
21333
+ * of controls needs to be determined.
20408
21334
  *
20409
21335
  * # CSS classes
20410
21336
  * - `ng-valid` is set if the form is valid.
@@ -20625,7 +21551,18 @@ var ngFormDirective = formDirectiveFactory(true);
20625
21551
  // Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
20626
21552
  var ISO_DATE_REGEXP = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/;
20627
21553
  // See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987)
20628
- var URL_REGEXP = /^[A-Za-z][A-Za-z\d.+-]*:\/*(?:\w+(?::\w+)?@)?[^\s/]+(?::\d+)?(?:\/[\w#!:.?+=&%@\-/]*)?$/;
21554
+ // Note: We are being more lenient, because browsers are too.
21555
+ // 1. Scheme
21556
+ // 2. Slashes
21557
+ // 3. Username
21558
+ // 4. Password
21559
+ // 5. Hostname
21560
+ // 6. Port
21561
+ // 7. Path
21562
+ // 8. Query
21563
+ // 9. Fragment
21564
+ // 1111111111111111 222 333333 44444 555555555555555555555555 666 77777777 8888888 999
21565
+ var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+\])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
20629
21566
  var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
20630
21567
  var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
20631
21568
  var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
@@ -20658,8 +21595,8 @@ var inputType = {
20658
21595
  * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
20659
21596
  * that contains the regular expression body that will be converted to a regular expression
20660
21597
  * as in the ngPattern directive.
20661
- * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
20662
- * a RegExp found by evaluating the Angular expression given in the attribute value.
21598
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
21599
+ * does not match a RegExp found by evaluating the Angular expression given in the attribute value.
20663
21600
  * If the expression evaluates to a RegExp object, then this is used directly.
20664
21601
  * If the expression evaluates to a string, then it will be converted to a RegExp
20665
21602
  * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
@@ -20946,7 +21883,7 @@ var inputType = {
20946
21883
  *
20947
21884
  * @description
20948
21885
  * Input with time validation and transformation. In browsers that do not yet support
20949
- * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
21886
+ * the HTML5 time input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
20950
21887
  * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
20951
21888
  * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
20952
21889
  *
@@ -21293,8 +22230,8 @@ var inputType = {
21293
22230
  * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
21294
22231
  * that contains the regular expression body that will be converted to a regular expression
21295
22232
  * as in the ngPattern directive.
21296
- * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
21297
- * a RegExp found by evaluating the Angular expression given in the attribute value.
22233
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
22234
+ * does not match a RegExp found by evaluating the Angular expression given in the attribute value.
21298
22235
  * If the expression evaluates to a RegExp object, then this is used directly.
21299
22236
  * If the expression evaluates to a string, then it will be converted to a RegExp
21300
22237
  * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
@@ -21391,8 +22328,8 @@ var inputType = {
21391
22328
  * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
21392
22329
  * that contains the regular expression body that will be converted to a regular expression
21393
22330
  * as in the ngPattern directive.
21394
- * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
21395
- * a RegExp found by evaluating the Angular expression given in the attribute value.
22331
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
22332
+ * does not match a RegExp found by evaluating the Angular expression given in the attribute value.
21396
22333
  * If the expression evaluates to a RegExp object, then this is used directly.
21397
22334
  * If the expression evaluates to a string, then it will be converted to a RegExp
21398
22335
  * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
@@ -21490,8 +22427,8 @@ var inputType = {
21490
22427
  * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
21491
22428
  * that contains the regular expression body that will be converted to a regular expression
21492
22429
  * as in the ngPattern directive.
21493
- * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
21494
- * a RegExp found by evaluating the Angular expression given in the attribute value.
22430
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
22431
+ * does not match a RegExp found by evaluating the Angular expression given in the attribute value.
21495
22432
  * If the expression evaluates to a RegExp object, then this is used directly.
21496
22433
  * If the expression evaluates to a string, then it will be converted to a RegExp
21497
22434
  * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
@@ -21951,11 +22888,7 @@ function badInputChecker(scope, element, attr, ctrl) {
21951
22888
  if (nativeValidation) {
21952
22889
  ctrl.$parsers.push(function(value) {
21953
22890
  var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
21954
- // Detect bug in FF35 for input[email] (https://bugzilla.mozilla.org/show_bug.cgi?id=1064430):
21955
- // - also sets validity.badInput (should only be validity.typeMismatch).
21956
- // - see http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-mail-state-(type=email)
21957
- // - can ignore this case as we can still read out the erroneous email...
21958
- return validity.badInput && !validity.typeMismatch ? undefined : value;
22891
+ return validity.badInput || validity.typeMismatch ? undefined : value;
21959
22892
  });
21960
22893
  }
21961
22894
  }
@@ -22127,8 +23060,8 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt
22127
23060
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
22128
23061
  * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
22129
23062
  * length.
22130
- * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
22131
- * a RegExp found by evaluating the Angular expression given in the attribute value.
23063
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
23064
+ * does not match a RegExp found by evaluating the Angular expression given in the attribute value.
22132
23065
  * If the expression evaluates to a RegExp object, then this is used directly.
22133
23066
  * If the expression evaluates to a string, then it will be converted to a RegExp
22134
23067
  * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
@@ -22166,8 +23099,8 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt
22166
23099
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
22167
23100
  * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
22168
23101
  * length.
22169
- * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
22170
- * a RegExp found by evaluating the Angular expression given in the attribute value.
23102
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
23103
+ * value does not match a RegExp found by evaluating the Angular expression given in the attribute value.
22171
23104
  * If the expression evaluates to a RegExp object, then this is used directly.
22172
23105
  * If the expression evaluates to a string, then it will be converted to a RegExp
22173
23106
  * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
@@ -23393,7 +24326,7 @@ var ngControllerDirective = [function() {
23393
24326
  *
23394
24327
  * * no-inline-style: this stops Angular from injecting CSS styles into the DOM
23395
24328
  *
23396
- * * no-unsafe-eval: this stops Angular from optimising $parse with unsafe eval of strings
24329
+ * * no-unsafe-eval: this stops Angular from optimizing $parse with unsafe eval of strings
23397
24330
  *
23398
24331
  * You can use these values in the following combinations:
23399
24332
  *
@@ -23410,7 +24343,7 @@ var ngControllerDirective = [function() {
23410
24343
  * inline styles. E.g. `<body ng-csp="no-unsafe-eval">`.
23411
24344
  *
23412
24345
  * * Specifying only `no-inline-style` tells Angular that we must not inject styles, but that we can
23413
- * run eval - no automcatic check for unsafe eval will occur. E.g. `<body ng-csp="no-inline-style">`
24346
+ * run eval - no automatic check for unsafe eval will occur. E.g. `<body ng-csp="no-inline-style">`
23414
24347
  *
23415
24348
  * * Specifying both `no-unsafe-eval` and `no-inline-style` tells Angular that we must not inject
23416
24349
  * styles nor use eval, which is the same as an empty: ng-csp.
@@ -24389,6 +25322,8 @@ var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
24389
25322
  //set the 2nd param to true to ignore the template request error so that the inner
24390
25323
  //contents and scope can be cleaned up.
24391
25324
  $templateRequest(src, true).then(function(response) {
25325
+ if (scope.$$destroyed) return;
25326
+
24392
25327
  if (thisChangeId !== changeCounter) return;
24393
25328
  var newScope = scope.$new();
24394
25329
  ctrl.template = response;
@@ -24410,6 +25345,8 @@ var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
24410
25345
  currentScope.$emit('$includeContentLoaded', src);
24411
25346
  scope.$eval(onloadExp);
24412
25347
  }, function() {
25348
+ if (scope.$$destroyed) return;
25349
+
24413
25350
  if (thisChangeId === changeCounter) {
24414
25351
  cleanupLastIncludeContent();
24415
25352
  scope.$emit('$includeContentError', src);
@@ -24438,7 +25375,7 @@ var ngIncludeFillContentDirective = ['$compile',
24438
25375
  priority: -400,
24439
25376
  require: 'ngInclude',
24440
25377
  link: function(scope, $element, $attr, ctrl) {
24441
- if (/SVG/.test($element[0].toString())) {
25378
+ if (toString.call($element[0]).match(/SVG/)) {
24442
25379
  // WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
24443
25380
  // support innerHTML, so detect this here and try to generate the contents
24444
25381
  // specially.
@@ -24667,7 +25604,9 @@ var VALID_CLASS = 'ng-valid',
24667
25604
  DIRTY_CLASS = 'ng-dirty',
24668
25605
  UNTOUCHED_CLASS = 'ng-untouched',
24669
25606
  TOUCHED_CLASS = 'ng-touched',
24670
- PENDING_CLASS = 'ng-pending';
25607
+ PENDING_CLASS = 'ng-pending',
25608
+ EMPTY_CLASS = 'ng-empty',
25609
+ NOT_EMPTY_CLASS = 'ng-not-empty';
24671
25610
 
24672
25611
  var ngModelMinErr = minErr('ngModel');
24673
25612
 
@@ -24971,6 +25910,17 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
24971
25910
  return isUndefined(value) || value === '' || value === null || value !== value;
24972
25911
  };
24973
25912
 
25913
+ this.$$updateEmptyClasses = function(value) {
25914
+ if (ctrl.$isEmpty(value)) {
25915
+ $animate.removeClass($element, NOT_EMPTY_CLASS);
25916
+ $animate.addClass($element, EMPTY_CLASS);
25917
+ } else {
25918
+ $animate.removeClass($element, EMPTY_CLASS);
25919
+ $animate.addClass($element, NOT_EMPTY_CLASS);
25920
+ }
25921
+ };
25922
+
25923
+
24974
25924
  var currentValidationRunId = 0;
24975
25925
 
24976
25926
  /**
@@ -25088,11 +26038,14 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
25088
26038
  * which may be caused by a pending debounced event or because the input is waiting for a some
25089
26039
  * future event.
25090
26040
  *
25091
- * If you have an input that uses `ng-model-options` to set up debounced events or events such
25092
- * as blur you can have a situation where there is a period when the `$viewValue`
25093
- * is out of synch with the ngModel's `$modelValue`.
26041
+ * If you have an input that uses `ng-model-options` to set up debounced updates or updates that
26042
+ * depend on special events such as blur, you can have a situation where there is a period when
26043
+ * the `$viewValue` is out of sync with the ngModel's `$modelValue`.
26044
+ *
26045
+ * In this case, you can use `$rollbackViewValue()` to manually cancel the debounced / future update
26046
+ * and reset the input to the last committed view value.
25094
26047
  *
25095
- * In this case, you can run into difficulties if you try to update the ngModel's `$modelValue`
26048
+ * It is also possible that you run into difficulties if you try to update the ngModel's `$modelValue`
25096
26049
  * programmatically before these debounced/future events have resolved/occurred, because Angular's
25097
26050
  * dirty checking mechanism is not able to tell whether the model has actually changed or not.
25098
26051
  *
@@ -25105,39 +26058,63 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
25105
26058
  * angular.module('cancel-update-example', [])
25106
26059
  *
25107
26060
  * .controller('CancelUpdateController', ['$scope', function($scope) {
25108
- * $scope.resetWithCancel = function(e) {
25109
- * if (e.keyCode == 27) {
25110
- * $scope.myForm.myInput1.$rollbackViewValue();
25111
- * $scope.myValue = '';
25112
- * }
25113
- * };
25114
- * $scope.resetWithoutCancel = function(e) {
26061
+ * $scope.model = {};
26062
+ *
26063
+ * $scope.setEmpty = function(e, value, rollback) {
25115
26064
  * if (e.keyCode == 27) {
25116
- * $scope.myValue = '';
26065
+ * e.preventDefault();
26066
+ * if (rollback) {
26067
+ * $scope.myForm[value].$rollbackViewValue();
26068
+ * }
26069
+ * $scope.model[value] = '';
25117
26070
  * }
25118
26071
  * };
25119
26072
  * }]);
25120
26073
  * </file>
25121
26074
  * <file name="index.html">
25122
26075
  * <div ng-controller="CancelUpdateController">
25123
- * <p>Try typing something in each input. See that the model only updates when you
25124
- * blur off the input.
25125
- * </p>
25126
- * <p>Now see what happens if you start typing then press the Escape key</p>
26076
+ * <p>Both of these inputs are only updated if they are blurred. Hitting escape should
26077
+ * empty them. Follow these steps and observe the difference:</p>
26078
+ * <ol>
26079
+ * <li>Type something in the input. You will see that the model is not yet updated</li>
26080
+ * <li>Press the Escape key.
26081
+ * <ol>
26082
+ * <li> In the first example, nothing happens, because the model is already '', and no
26083
+ * update is detected. If you blur the input, the model will be set to the current view.
26084
+ * </li>
26085
+ * <li> In the second example, the pending update is cancelled, and the input is set back
26086
+ * to the last committed view value (''). Blurring the input does nothing.
26087
+ * </li>
26088
+ * </ol>
26089
+ * </li>
26090
+ * </ol>
25127
26091
  *
25128
26092
  * <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
25129
- * <p id="inputDescription1">With $rollbackViewValue()</p>
25130
- * <input name="myInput1" aria-describedby="inputDescription1" ng-model="myValue"
25131
- * ng-keydown="resetWithCancel($event)"><br/>
25132
- * myValue: "{{ myValue }}"
25133
- *
25134
- * <p id="inputDescription2">Without $rollbackViewValue()</p>
25135
- * <input name="myInput2" aria-describedby="inputDescription2" ng-model="myValue"
25136
- * ng-keydown="resetWithoutCancel($event)"><br/>
25137
- * myValue: "{{ myValue }}"
26093
+ * <div>
26094
+ * <p id="inputDescription1">Without $rollbackViewValue():</p>
26095
+ * <input name="value1" aria-describedby="inputDescription1" ng-model="model.value1"
26096
+ * ng-keydown="setEmpty($event, 'value1')">
26097
+ * value1: "{{ model.value1 }}"
26098
+ * </div>
26099
+ *
26100
+ * <div>
26101
+ * <p id="inputDescription2">With $rollbackViewValue():</p>
26102
+ * <input name="value2" aria-describedby="inputDescription2" ng-model="model.value2"
26103
+ * ng-keydown="setEmpty($event, 'value2', true)">
26104
+ * value2: "{{ model.value2 }}"
26105
+ * </div>
25138
26106
  * </form>
25139
26107
  * </div>
25140
26108
  * </file>
26109
+ <file name="style.css">
26110
+ div {
26111
+ display: table-cell;
26112
+ }
26113
+ div:nth-child(1) {
26114
+ padding-right: 30px;
26115
+ }
26116
+
26117
+ </file>
25141
26118
  * </example>
25142
26119
  */
25143
26120
  this.$rollbackViewValue = function() {
@@ -25251,7 +26228,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
25251
26228
  forEach(ctrl.$asyncValidators, function(validator, name) {
25252
26229
  var promise = validator(modelValue, viewValue);
25253
26230
  if (!isPromiseLike(promise)) {
25254
- throw ngModelMinErr("$asyncValidators",
26231
+ throw ngModelMinErr('nopromise',
25255
26232
  "Expected asynchronous validator to return a promise but got '{0}' instead.", promise);
25256
26233
  }
25257
26234
  setValidity(name, undefined);
@@ -25307,6 +26284,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
25307
26284
  if (ctrl.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !ctrl.$$hasNativeValidators)) {
25308
26285
  return;
25309
26286
  }
26287
+ ctrl.$$updateEmptyClasses(viewValue);
25310
26288
  ctrl.$$lastCommittedViewValue = viewValue;
25311
26289
 
25312
26290
  // change to dirty
@@ -25405,7 +26383,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
25405
26383
  * However, custom controls might also pass objects to this method. In this case, we should make
25406
26384
  * a copy of the object before passing it to `$setViewValue`. This is because `ngModel` does not
25407
26385
  * perform a deep watch of objects, it only looks for a change of identity. If you only change
25408
- * the property of the object then ngModel will not realise that the object has changed and
26386
+ * the property of the object then ngModel will not realize that the object has changed and
25409
26387
  * will not invoke the `$parsers` and `$validators` pipelines. For this reason, you should
25410
26388
  * not change properties of the copy once it has been passed to `$setViewValue`.
25411
26389
  * Otherwise you may cause the model value on the scope to change incorrectly.
@@ -25489,6 +26467,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
25489
26467
  viewValue = formatters[idx](viewValue);
25490
26468
  }
25491
26469
  if (ctrl.$viewValue !== viewValue) {
26470
+ ctrl.$$updateEmptyClasses(viewValue);
25492
26471
  ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
25493
26472
  ctrl.$render();
25494
26473
 
@@ -25519,7 +26498,8 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
25519
26498
  * require.
25520
26499
  * - Providing validation behavior (i.e. required, number, email, url).
25521
26500
  * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
25522
- * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`, `ng-untouched`) including animations.
26501
+ * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`,
26502
+ * `ng-untouched`, `ng-empty`, `ng-not-empty`) including animations.
25523
26503
  * - Registering the control with its parent {@link ng.directive:form form}.
25524
26504
  *
25525
26505
  * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
@@ -25547,6 +26527,22 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
25547
26527
  * - {@link ng.directive:select select}
25548
26528
  * - {@link ng.directive:textarea textarea}
25549
26529
  *
26530
+ * # Complex Models (objects or collections)
26531
+ *
26532
+ * By default, `ngModel` watches the model by reference, not value. This is important to know when
26533
+ * binding inputs to models that are objects (e.g. `Date`) or collections (e.g. arrays). If only properties of the
26534
+ * object or collection change, `ngModel` will not be notified and so the input will not be re-rendered.
26535
+ *
26536
+ * The model must be assigned an entirely new object or collection before a re-rendering will occur.
26537
+ *
26538
+ * Some directives have options that will cause them to use a custom `$watchCollection` on the model expression
26539
+ * - for example, `ngOptions` will do so when a `track by` clause is included in the comprehension expression or
26540
+ * if the select is given the `multiple` attribute.
26541
+ *
26542
+ * The `$watchCollection()` method only does a shallow comparison, meaning that changing properties deeper than the
26543
+ * first level of the object (or only changing the properties of an item in the collection if it's an array) will still
26544
+ * not trigger a re-rendering of the model.
26545
+ *
25550
26546
  * # CSS classes
25551
26547
  * The following CSS classes are added and removed on the associated input/select/textarea element
25552
26548
  * depending on the validity of the model.
@@ -25560,13 +26556,16 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
25560
26556
  * - `ng-touched`: the control has been blurred
25561
26557
  * - `ng-untouched`: the control hasn't been blurred
25562
26558
  * - `ng-pending`: any `$asyncValidators` are unfulfilled
26559
+ * - `ng-empty`: the view does not contain a value or the value is deemed "empty", as defined
26560
+ * by the {@link ngModel.NgModelController#$isEmpty} method
26561
+ * - `ng-not-empty`: the view contains a non-empty value
25563
26562
  *
25564
26563
  * Keep in mind that ngAnimate can detect each of these classes when added and removed.
25565
26564
  *
25566
26565
  * ## Animation Hooks
25567
26566
  *
25568
26567
  * Animations within models are triggered when any of the associated CSS classes are added and removed
25569
- * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
26568
+ * on the input element which is attached to the model. These classes include: `.ng-pristine`, `.ng-dirty`,
25570
26569
  * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
25571
26570
  * The animations that are triggered within ngModel are similar to how they work in ngClass and
25572
26571
  * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
@@ -26459,14 +27458,10 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
26459
27458
  var optionTemplate = document.createElement('option'),
26460
27459
  optGroupTemplate = document.createElement('optgroup');
26461
27460
 
26462
-
26463
27461
  function ngOptionsPostLink(scope, selectElement, attr, ctrls) {
26464
27462
 
26465
- // if ngModel is not defined, we don't need to do anything
26466
- var ngModelCtrl = ctrls[1];
26467
- if (!ngModelCtrl) return;
26468
-
26469
27463
  var selectCtrl = ctrls[0];
27464
+ var ngModelCtrl = ctrls[1];
26470
27465
  var multiple = attr.multiple;
26471
27466
 
26472
27467
  // The emptyOption allows the application developer to provide their own custom "empty"
@@ -26697,7 +27692,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
26697
27692
  (current === emptyOption_ ||
26698
27693
  current === unknownOption_ ||
26699
27694
  current.nodeType === NODE_TYPE_COMMENT ||
26700
- current.value === '')) {
27695
+ (nodeName_(current) === 'option' && current.value === ''))) {
26701
27696
  current = current.nextSibling;
26702
27697
  }
26703
27698
  }
@@ -26726,7 +27721,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
26726
27721
  var groupElement;
26727
27722
  var optionElement;
26728
27723
 
26729
- if (option.group) {
27724
+ if (isDefined(option.group)) {
26730
27725
 
26731
27726
  // This option is to live in a group
26732
27727
  // See if we have already created this group
@@ -26787,7 +27782,8 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
26787
27782
  // Check to see if the value has changed due to the update to the options
26788
27783
  if (!ngModelCtrl.$isEmpty(previousValue)) {
26789
27784
  var nextValue = selectCtrl.readValue();
26790
- if (ngOptions.trackBy ? !equals(previousValue, nextValue) : previousValue !== nextValue) {
27785
+ var isNotPrimitive = ngOptions.trackBy || multiple;
27786
+ if (isNotPrimitive ? !equals(previousValue, nextValue) : previousValue !== nextValue) {
26791
27787
  ngModelCtrl.$setViewValue(nextValue);
26792
27788
  ngModelCtrl.$render();
26793
27789
  }
@@ -26799,7 +27795,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
26799
27795
  return {
26800
27796
  restrict: 'A',
26801
27797
  terminal: true,
26802
- require: ['select', '?ngModel'],
27798
+ require: ['select', 'ngModel'],
26803
27799
  link: {
26804
27800
  pre: function ngOptionsPreLink(scope, selectElement, attr, ctrls) {
26805
27801
  // Deactivate the SelectController.register method to prevent
@@ -27027,7 +28023,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
27027
28023
  }
27028
28024
 
27029
28025
  // If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
27030
- // In JS `NaN !== NaN`, so we have to exlicitly check.
28026
+ // In JS `NaN !== NaN`, so we have to explicitly check.
27031
28027
  if ((count !== lastCount) && !(countIsNaN && isNumber(lastCount) && isNaN(lastCount))) {
27032
28028
  watchRemover();
27033
28029
  var whenExpFn = whensExpFns[count];
@@ -27144,7 +28140,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
27144
28140
  * by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`
27145
28141
  * will not have to rebuild the DOM elements for items it has already rendered, even if the
27146
28142
  * JavaScript objects in the collection have been substituted for new ones. For large collections,
27147
- * this signifincantly improves rendering performance. If you don't have a unique identifier,
28143
+ * this significantly improves rendering performance. If you don't have a unique identifier,
27148
28144
  * `track by $index` can also provide a performance boost.
27149
28145
  * </div>
27150
28146
  * ```html
@@ -27221,6 +28217,8 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
27221
28217
  *
27222
28218
  * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
27223
28219
  *
28220
+ * See the example below for defining CSS animations with ngRepeat.
28221
+ *
27224
28222
  * @element ANY
27225
28223
  * @scope
27226
28224
  * @priority 1000
@@ -27273,22 +28271,11 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
27273
28271
  * For example: `item in items | filter : x | orderBy : order | limitTo : limit as results` .
27274
28272
  *
27275
28273
  * @example
27276
- * This example initializes the scope to a list of names and
27277
- * then uses `ngRepeat` to display every person:
27278
- <example module="ngAnimate" deps="angular-animate.js" animations="true">
28274
+ * This example uses `ngRepeat` to display a list of people. A filter is used to restrict the displayed
28275
+ * results by name. New (entering) and removed (leaving) items are animated.
28276
+ <example module="ngRepeat" name="ngRepeat" deps="angular-animate.js" animations="true">
27279
28277
  <file name="index.html">
27280
- <div ng-init="friends = [
27281
- {name:'John', age:25, gender:'boy'},
27282
- {name:'Jessie', age:30, gender:'girl'},
27283
- {name:'Johanna', age:28, gender:'girl'},
27284
- {name:'Joy', age:15, gender:'girl'},
27285
- {name:'Mary', age:28, gender:'girl'},
27286
- {name:'Peter', age:95, gender:'boy'},
27287
- {name:'Sebastian', age:50, gender:'boy'},
27288
- {name:'Erika', age:27, gender:'girl'},
27289
- {name:'Patrick', age:40, gender:'boy'},
27290
- {name:'Samantha', age:60, gender:'girl'}
27291
- ]">
28278
+ <div ng-controller="repeatController">
27292
28279
  I have {{friends.length}} friends. They are:
27293
28280
  <input type="search" ng-model="q" placeholder="filter friends..." aria-label="filter friends" />
27294
28281
  <ul class="example-animate-container">
@@ -27301,6 +28288,22 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
27301
28288
  </ul>
27302
28289
  </div>
27303
28290
  </file>
28291
+ <file name="script.js">
28292
+ angular.module('ngRepeat', ['ngAnimate']).controller('repeatController', function($scope) {
28293
+ $scope.friends = [
28294
+ {name:'John', age:25, gender:'boy'},
28295
+ {name:'Jessie', age:30, gender:'girl'},
28296
+ {name:'Johanna', age:28, gender:'girl'},
28297
+ {name:'Joy', age:15, gender:'girl'},
28298
+ {name:'Mary', age:28, gender:'girl'},
28299
+ {name:'Peter', age:95, gender:'boy'},
28300
+ {name:'Sebastian', age:50, gender:'boy'},
28301
+ {name:'Erika', age:27, gender:'girl'},
28302
+ {name:'Patrick', age:40, gender:'boy'},
28303
+ {name:'Samantha', age:60, gender:'girl'}
28304
+ ];
28305
+ });
28306
+ </file>
27304
28307
  <file name="animations.css">
27305
28308
  .example-animate-container {
27306
28309
  background:white;
@@ -27311,7 +28314,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
27311
28314
  }
27312
28315
 
27313
28316
  .animate-repeat {
27314
- line-height:40px;
28317
+ line-height:30px;
27315
28318
  list-style:none;
27316
28319
  box-sizing:border-box;
27317
28320
  }
@@ -27333,7 +28336,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
27333
28336
  .animate-repeat.ng-move.ng-move-active,
27334
28337
  .animate-repeat.ng-enter.ng-enter-active {
27335
28338
  opacity:1;
27336
- max-height:40px;
28339
+ max-height:30px;
27337
28340
  }
27338
28341
  </file>
27339
28342
  <file name="protractor.js" type="protractor">
@@ -28190,67 +29193,186 @@ var ngSwitchDefaultDirective = ngDirective({
28190
29193
  * @description
28191
29194
  * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
28192
29195
  *
28193
- * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
29196
+ * You can specify that you want to insert a named transclusion slot, instead of the default slot, by providing the slot name
29197
+ * as the value of the `ng-transclude` or `ng-transclude-slot` attribute.
29198
+ *
29199
+ * If the transcluded content is not empty (i.e. contains one or more DOM nodes, including whitespace text nodes), any existing
29200
+ * content of this element will be removed before the transcluded content is inserted.
29201
+ * If the transcluded content is empty, the existing content is left intact. This lets you provide fallback content in the case
29202
+ * that no transcluded content is provided.
28194
29203
  *
28195
29204
  * @element ANY
28196
29205
  *
29206
+ * @param {string} ngTransclude|ngTranscludeSlot the name of the slot to insert at this point. If this is not provided, is empty
29207
+ * or its value is the same as the name of the attribute then the default slot is used.
29208
+ *
28197
29209
  * @example
28198
- <example module="transcludeExample">
28199
- <file name="index.html">
28200
- <script>
28201
- angular.module('transcludeExample', [])
28202
- .directive('pane', function(){
28203
- return {
28204
- restrict: 'E',
28205
- transclude: true,
28206
- scope: { title:'@' },
28207
- template: '<div style="border: 1px solid black;">' +
28208
- '<div style="background-color: gray">{{title}}</div>' +
28209
- '<ng-transclude></ng-transclude>' +
28210
- '</div>'
28211
- };
28212
- })
28213
- .controller('ExampleController', ['$scope', function($scope) {
28214
- $scope.title = 'Lorem Ipsum';
28215
- $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
28216
- }]);
28217
- </script>
28218
- <div ng-controller="ExampleController">
28219
- <input ng-model="title" aria-label="title"> <br/>
28220
- <textarea ng-model="text" aria-label="text"></textarea> <br/>
28221
- <pane title="{{title}}">{{text}}</pane>
28222
- </div>
28223
- </file>
28224
- <file name="protractor.js" type="protractor">
28225
- it('should have transcluded', function() {
28226
- var titleElement = element(by.model('title'));
28227
- titleElement.clear();
28228
- titleElement.sendKeys('TITLE');
28229
- var textElement = element(by.model('text'));
28230
- textElement.clear();
28231
- textElement.sendKeys('TEXT');
28232
- expect(element(by.binding('title')).getText()).toEqual('TITLE');
28233
- expect(element(by.binding('text')).getText()).toEqual('TEXT');
28234
- });
28235
- </file>
28236
- </example>
29210
+ * ### Basic transclusion
29211
+ * This example demonstrates basic transclusion of content into a component directive.
29212
+ * <example name="simpleTranscludeExample" module="transcludeExample">
29213
+ * <file name="index.html">
29214
+ * <script>
29215
+ * angular.module('transcludeExample', [])
29216
+ * .directive('pane', function(){
29217
+ * return {
29218
+ * restrict: 'E',
29219
+ * transclude: true,
29220
+ * scope: { title:'@' },
29221
+ * template: '<div style="border: 1px solid black;">' +
29222
+ * '<div style="background-color: gray">{{title}}</div>' +
29223
+ * '<ng-transclude></ng-transclude>' +
29224
+ * '</div>'
29225
+ * };
29226
+ * })
29227
+ * .controller('ExampleController', ['$scope', function($scope) {
29228
+ * $scope.title = 'Lorem Ipsum';
29229
+ * $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
29230
+ * }]);
29231
+ * </script>
29232
+ * <div ng-controller="ExampleController">
29233
+ * <input ng-model="title" aria-label="title"> <br/>
29234
+ * <textarea ng-model="text" aria-label="text"></textarea> <br/>
29235
+ * <pane title="{{title}}">{{text}}</pane>
29236
+ * </div>
29237
+ * </file>
29238
+ * <file name="protractor.js" type="protractor">
29239
+ * it('should have transcluded', function() {
29240
+ * var titleElement = element(by.model('title'));
29241
+ * titleElement.clear();
29242
+ * titleElement.sendKeys('TITLE');
29243
+ * var textElement = element(by.model('text'));
29244
+ * textElement.clear();
29245
+ * textElement.sendKeys('TEXT');
29246
+ * expect(element(by.binding('title')).getText()).toEqual('TITLE');
29247
+ * expect(element(by.binding('text')).getText()).toEqual('TEXT');
29248
+ * });
29249
+ * </file>
29250
+ * </example>
29251
+ *
29252
+ * @example
29253
+ * ### Transclude fallback content
29254
+ * This example shows how to use `NgTransclude` with fallback content, that
29255
+ * is displayed if no transcluded content is provided.
29256
+ *
29257
+ * <example module="transcludeFallbackContentExample">
29258
+ * <file name="index.html">
29259
+ * <script>
29260
+ * angular.module('transcludeFallbackContentExample', [])
29261
+ * .directive('myButton', function(){
29262
+ * return {
29263
+ * restrict: 'E',
29264
+ * transclude: true,
29265
+ * scope: true,
29266
+ * template: '<button style="cursor: pointer;">' +
29267
+ * '<ng-transclude>' +
29268
+ * '<b style="color: red;">Button1</b>' +
29269
+ * '</ng-transclude>' +
29270
+ * '</button>'
29271
+ * };
29272
+ * });
29273
+ * </script>
29274
+ * <!-- fallback button content -->
29275
+ * <my-button id="fallback"></my-button>
29276
+ * <!-- modified button content -->
29277
+ * <my-button id="modified">
29278
+ * <i style="color: green;">Button2</i>
29279
+ * </my-button>
29280
+ * </file>
29281
+ * <file name="protractor.js" type="protractor">
29282
+ * it('should have different transclude element content', function() {
29283
+ * expect(element(by.id('fallback')).getText()).toBe('Button1');
29284
+ * expect(element(by.id('modified')).getText()).toBe('Button2');
29285
+ * });
29286
+ * </file>
29287
+ * </example>
28237
29288
  *
29289
+ * @example
29290
+ * ### Multi-slot transclusion
29291
+ * This example demonstrates using multi-slot transclusion in a component directive.
29292
+ * <example name="multiSlotTranscludeExample" module="multiSlotTranscludeExample">
29293
+ * <file name="index.html">
29294
+ * <style>
29295
+ * .title, .footer {
29296
+ * background-color: gray
29297
+ * }
29298
+ * </style>
29299
+ * <div ng-controller="ExampleController">
29300
+ * <input ng-model="title" aria-label="title"> <br/>
29301
+ * <textarea ng-model="text" aria-label="text"></textarea> <br/>
29302
+ * <pane>
29303
+ * <pane-title><a ng-href="{{link}}">{{title}}</a></pane-title>
29304
+ * <pane-body><p>{{text}}</p></pane-body>
29305
+ * </pane>
29306
+ * </div>
29307
+ * </file>
29308
+ * <file name="app.js">
29309
+ * angular.module('multiSlotTranscludeExample', [])
29310
+ * .directive('pane', function(){
29311
+ * return {
29312
+ * restrict: 'E',
29313
+ * transclude: {
29314
+ * 'title': '?paneTitle',
29315
+ * 'body': 'paneBody',
29316
+ * 'footer': '?paneFooter'
29317
+ * },
29318
+ * template: '<div style="border: 1px solid black;">' +
29319
+ * '<div class="title" ng-transclude="title">Fallback Title</div>' +
29320
+ * '<div ng-transclude="body"></div>' +
29321
+ * '<div class="footer" ng-transclude="footer">Fallback Footer</div>' +
29322
+ * '</div>'
29323
+ * };
29324
+ * })
29325
+ * .controller('ExampleController', ['$scope', function($scope) {
29326
+ * $scope.title = 'Lorem Ipsum';
29327
+ * $scope.link = "https://google.com";
29328
+ * $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
29329
+ * }]);
29330
+ * </file>
29331
+ * <file name="protractor.js" type="protractor">
29332
+ * it('should have transcluded the title and the body', function() {
29333
+ * var titleElement = element(by.model('title'));
29334
+ * titleElement.clear();
29335
+ * titleElement.sendKeys('TITLE');
29336
+ * var textElement = element(by.model('text'));
29337
+ * textElement.clear();
29338
+ * textElement.sendKeys('TEXT');
29339
+ * expect(element(by.css('.title')).getText()).toEqual('TITLE');
29340
+ * expect(element(by.binding('text')).getText()).toEqual('TEXT');
29341
+ * expect(element(by.css('.footer')).getText()).toEqual('Fallback Footer');
29342
+ * });
29343
+ * </file>
29344
+ * </example>
28238
29345
  */
29346
+ var ngTranscludeMinErr = minErr('ngTransclude');
28239
29347
  var ngTranscludeDirective = ngDirective({
28240
29348
  restrict: 'EAC',
28241
29349
  link: function($scope, $element, $attrs, controller, $transclude) {
29350
+
29351
+ if ($attrs.ngTransclude === $attrs.$attr.ngTransclude) {
29352
+ // If the attribute is of the form: `ng-transclude="ng-transclude"`
29353
+ // then treat it like the default
29354
+ $attrs.ngTransclude = '';
29355
+ }
29356
+
29357
+ function ngTranscludeCloneAttachFn(clone) {
29358
+ if (clone.length) {
29359
+ $element.empty();
29360
+ $element.append(clone);
29361
+ }
29362
+ }
29363
+
28242
29364
  if (!$transclude) {
28243
- throw minErr('ngTransclude')('orphan',
29365
+ throw ngTranscludeMinErr('orphan',
28244
29366
  'Illegal use of ngTransclude directive in the template! ' +
28245
29367
  'No parent directive that requires a transclusion found. ' +
28246
29368
  'Element: {0}',
28247
29369
  startingTag($element));
28248
29370
  }
28249
29371
 
28250
- $transclude(function(clone) {
28251
- $element.empty();
28252
- $element.append(clone);
28253
- });
29372
+ // If there is no slot name defined or the slot name is not optional
29373
+ // then transclude the slot
29374
+ var slotName = $attrs.ngTransclude || $attrs.ngTranscludeSlot;
29375
+ $transclude(ngTranscludeCloneAttachFn, null, slotName);
28254
29376
  }
28255
29377
  });
28256
29378
 
@@ -28382,6 +29504,9 @@ var SelectController =
28382
29504
 
28383
29505
  // Tell the select control that an option, with the given value, has been added
28384
29506
  self.addOption = function(value, element) {
29507
+ // Skip comment nodes, as they only pollute the `optionsMap`
29508
+ if (element[0].nodeType === NODE_TYPE_COMMENT) return;
29509
+
28385
29510
  assertNotHasOwnProperty(value, '"option value"');
28386
29511
  if (value === '') {
28387
29512
  self.emptyOption = element;
@@ -28456,7 +29581,7 @@ var SelectController =
28456
29581
  *
28457
29582
  * The `select` directive is used together with {@link ngModel `ngModel`} to provide data-binding
28458
29583
  * between the scope and the `<select>` control (including setting default values).
28459
- * Ìt also handles dynamic `<option>` elements, which can be added using the {@link ngRepeat `ngRepeat}` or
29584
+ * It also handles dynamic `<option>` elements, which can be added using the {@link ngRepeat `ngRepeat}` or
28460
29585
  * {@link ngOptions `ngOptions`} directives.
28461
29586
  *
28462
29587
  * When an item in the `<select>` menu is selected, the value of the selected option will be bound
@@ -28466,7 +29591,7 @@ var SelectController =
28466
29591
  *
28467
29592
  * <div class="alert alert-warning">
28468
29593
  * Note that the value of a `select` directive used without `ngOptions` is always a string.
28469
- * When the model needs to be bound to a non-string value, you must either explictly convert it
29594
+ * When the model needs to be bound to a non-string value, you must either explicitly convert it
28470
29595
  * using a directive (see example below) or use `ngOptions` to specify the set of options.
28471
29596
  * This is because an option element can only be bound to string values at present.
28472
29597
  * </div>
@@ -28658,7 +29783,8 @@ var selectDirective = function() {
28658
29783
  controller: SelectController,
28659
29784
  priority: 1,
28660
29785
  link: {
28661
- pre: selectPreLink
29786
+ pre: selectPreLink,
29787
+ post: selectPostLink
28662
29788
  }
28663
29789
  };
28664
29790
 
@@ -28672,13 +29798,6 @@ var selectDirective = function() {
28672
29798
 
28673
29799
  selectCtrl.ngModelCtrl = ngModelCtrl;
28674
29800
 
28675
- // We delegate rendering to the `writeValue` method, which can be changed
28676
- // if the select can have multiple selected values or if the options are being
28677
- // generated by `ngOptions`
28678
- ngModelCtrl.$render = function() {
28679
- selectCtrl.writeValue(ngModelCtrl.$viewValue);
28680
- };
28681
-
28682
29801
  // When the selected item(s) changes we delegate getting the value of the select control
28683
29802
  // to the `readValue` method, which can be changed if the select can have multiple
28684
29803
  // selected values or if the options are being generated by `ngOptions`
@@ -28732,6 +29851,23 @@ var selectDirective = function() {
28732
29851
 
28733
29852
  }
28734
29853
  }
29854
+
29855
+ function selectPostLink(scope, element, attrs, ctrls) {
29856
+ // if ngModel is not defined, we don't need to do anything
29857
+ var ngModelCtrl = ctrls[1];
29858
+ if (!ngModelCtrl) return;
29859
+
29860
+ var selectCtrl = ctrls[0];
29861
+
29862
+ // We delegate rendering to the `writeValue` method, which can be changed
29863
+ // if the select can have multiple selected values or if the options are being
29864
+ // generated by `ngOptions`.
29865
+ // This must be done in the postLink fn to prevent $render to be called before
29866
+ // all nodes have been linked correctly.
29867
+ ngModelCtrl.$render = function() {
29868
+ selectCtrl.writeValue(ngModelCtrl.$viewValue);
29869
+ };
29870
+ }
28735
29871
  };
28736
29872
 
28737
29873
 
@@ -28743,7 +29879,6 @@ var optionDirective = ['$interpolate', function($interpolate) {
28743
29879
  restrict: 'E',
28744
29880
  priority: 100,
28745
29881
  compile: function(element, attr) {
28746
-
28747
29882
  if (isDefined(attr.value)) {
28748
29883
  // If the value attribute is defined, check if it contains an interpolation
28749
29884
  var interpolateValueFn = $interpolate(attr.value, true);
@@ -28757,7 +29892,6 @@ var optionDirective = ['$interpolate', function($interpolate) {
28757
29892
  }
28758
29893
 
28759
29894
  return function(scope, element, attr) {
28760
-
28761
29895
  // This is an optimization over using ^^ since we don't want to have to search
28762
29896
  // all the way to the root of the DOM for every single option element
28763
29897
  var selectCtrlName = '$selectController',
@@ -28778,6 +29912,64 @@ var styleDirective = valueFn({
28778
29912
  terminal: false
28779
29913
  });
28780
29914
 
29915
+ /**
29916
+ * @ngdoc directive
29917
+ * @name ngRequired
29918
+ *
29919
+ * @description
29920
+ *
29921
+ * ngRequired adds the required {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
29922
+ * It is most often used for {@link input `input`} and {@link select `select`} controls, but can also be
29923
+ * applied to custom controls.
29924
+ *
29925
+ * The directive sets the `required` attribute on the element if the Angular expression inside
29926
+ * `ngRequired` evaluates to true. A special directive for setting `required` is necessary because we
29927
+ * cannot use interpolation inside `required`. See the {@link guide/interpolation interpolation guide}
29928
+ * for more info.
29929
+ *
29930
+ * The validator will set the `required` error key to true if the `required` attribute is set and
29931
+ * calling {@link ngModel.NgModelController#$isEmpty `NgModelController.$isEmpty`} with the
29932
+ * {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`} returns `true`. For example, the
29933
+ * `$isEmpty()` implementation for `input[text]` checks the length of the `$viewValue`. When developing
29934
+ * custom controls, `$isEmpty()` can be overwritten to account for a $viewValue that is not string-based.
29935
+ *
29936
+ * @example
29937
+ * <example name="ngRequiredDirective" module="ngRequiredExample">
29938
+ * <file name="index.html">
29939
+ * <script>
29940
+ * angular.module('ngRequiredExample', [])
29941
+ * .controller('ExampleController', ['$scope', function($scope) {
29942
+ * $scope.required = true;
29943
+ * }]);
29944
+ * </script>
29945
+ * <div ng-controller="ExampleController">
29946
+ * <form name="form">
29947
+ * <label for="required">Toggle required: </label>
29948
+ * <input type="checkbox" ng-model="required" id="required" />
29949
+ * <br>
29950
+ * <label for="input">This input must be filled if `required` is true: </label>
29951
+ * <input type="text" ng-model="model" id="input" name="input" ng-required="required" /><br>
29952
+ * <hr>
29953
+ * required error set? = <code>{{form.input.$error.required}}</code><br>
29954
+ * model = <code>{{model}}</code>
29955
+ * </form>
29956
+ * </div>
29957
+ * </file>
29958
+ * <file name="protractor.js" type="protractor">
29959
+ var required = element(by.binding('form.input.$error.required'));
29960
+ var model = element(by.binding('model'));
29961
+ var input = element(by.id('input'));
29962
+
29963
+ it('should set the required error', function() {
29964
+ expect(required.getText()).toContain('true');
29965
+
29966
+ input.sendKeys('123');
29967
+ expect(required.getText()).not.toContain('true');
29968
+ expect(model.getText()).toContain('123');
29969
+ });
29970
+ * </file>
29971
+ * </example>
29972
+ */
28781
29973
  var requiredDirective = function() {
28782
29974
  return {
28783
29975
  restrict: 'A',
@@ -28797,7 +29989,81 @@ var requiredDirective = function() {
28797
29989
  };
28798
29990
  };
28799
29991
 
29992
+ /**
29993
+ * @ngdoc directive
29994
+ * @name ngPattern
29995
+ *
29996
+ * @description
29997
+ *
29998
+ * ngPattern adds the pattern {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
29999
+ * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
30000
+ *
30001
+ * The validator sets the `pattern` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
30002
+ * does not match a RegExp which is obtained by evaluating the Angular expression given in the
30003
+ * `ngPattern` attribute value:
30004
+ * * If the expression evaluates to a RegExp object, then this is used directly.
30005
+ * * If the expression evaluates to a string, then it will be converted to a RegExp after wrapping it
30006
+ * in `^` and `$` characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
30007
+ *
30008
+ * <div class="alert alert-info">
30009
+ * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
30010
+ * start at the index of the last search's match, thus not taking the whole input value into
30011
+ * account.
30012
+ * </div>
30013
+ *
30014
+ * <div class="alert alert-info">
30015
+ * **Note:** This directive is also added when the plain `pattern` attribute is used, with two
30016
+ * differences:
30017
+ * <ol>
30018
+ * <li>
30019
+ * `ngPattern` does not set the `pattern` attribute and therefore HTML5 constraint validation is
30020
+ * not available.
30021
+ * </li>
30022
+ * <li>
30023
+ * The `ngPattern` attribute must be an expression, while the `pattern` value must be
30024
+ * interpolated.
30025
+ * </li>
30026
+ * </ol>
30027
+ * </div>
30028
+ *
30029
+ * @example
30030
+ * <example name="ngPatternDirective" module="ngPatternExample">
30031
+ * <file name="index.html">
30032
+ * <script>
30033
+ * angular.module('ngPatternExample', [])
30034
+ * .controller('ExampleController', ['$scope', function($scope) {
30035
+ * $scope.regex = '\\d+';
30036
+ * }]);
30037
+ * </script>
30038
+ * <div ng-controller="ExampleController">
30039
+ * <form name="form">
30040
+ * <label for="regex">Set a pattern (regex string): </label>
30041
+ * <input type="text" ng-model="regex" id="regex" />
30042
+ * <br>
30043
+ * <label for="input">This input is restricted by the current pattern: </label>
30044
+ * <input type="text" ng-model="model" id="input" name="input" ng-pattern="regex" /><br>
30045
+ * <hr>
30046
+ * input valid? = <code>{{form.input.$valid}}</code><br>
30047
+ * model = <code>{{model}}</code>
30048
+ * </form>
30049
+ * </div>
30050
+ * </file>
30051
+ * <file name="protractor.js" type="protractor">
30052
+ var model = element(by.binding('model'));
30053
+ var input = element(by.id('input'));
30054
+
30055
+ it('should validate the input with the default pattern', function() {
30056
+ input.sendKeys('aaa');
30057
+ expect(model.getText()).not.toContain('aaa');
28800
30058
 
30059
+ input.clear().then(function() {
30060
+ input.sendKeys('123');
30061
+ expect(model.getText()).toContain('123');
30062
+ });
30063
+ });
30064
+ * </file>
30065
+ * </example>
30066
+ */
28801
30067
  var patternDirective = function() {
28802
30068
  return {
28803
30069
  restrict: 'A',
@@ -28829,7 +30095,72 @@ var patternDirective = function() {
28829
30095
  };
28830
30096
  };
28831
30097
 
30098
+ /**
30099
+ * @ngdoc directive
30100
+ * @name ngMaxlength
30101
+ *
30102
+ * @description
30103
+ *
30104
+ * ngMaxlength adds the maxlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
30105
+ * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
30106
+ *
30107
+ * The validator sets the `maxlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
30108
+ * is longer than the integer obtained by evaluating the Angular expression given in the
30109
+ * `ngMaxlength` attribute value.
30110
+ *
30111
+ * <div class="alert alert-info">
30112
+ * **Note:** This directive is also added when the plain `maxlength` attribute is used, with two
30113
+ * differences:
30114
+ * <ol>
30115
+ * <li>
30116
+ * `ngMaxlength` does not set the `maxlength` attribute and therefore HTML5 constraint
30117
+ * validation is not available.
30118
+ * </li>
30119
+ * <li>
30120
+ * The `ngMaxlength` attribute must be an expression, while the `maxlength` value must be
30121
+ * interpolated.
30122
+ * </li>
30123
+ * </ol>
30124
+ * </div>
30125
+ *
30126
+ * @example
30127
+ * <example name="ngMaxlengthDirective" module="ngMaxlengthExample">
30128
+ * <file name="index.html">
30129
+ * <script>
30130
+ * angular.module('ngMaxlengthExample', [])
30131
+ * .controller('ExampleController', ['$scope', function($scope) {
30132
+ * $scope.maxlength = 5;
30133
+ * }]);
30134
+ * </script>
30135
+ * <div ng-controller="ExampleController">
30136
+ * <form name="form">
30137
+ * <label for="maxlength">Set a maxlength: </label>
30138
+ * <input type="number" ng-model="maxlength" id="maxlength" />
30139
+ * <br>
30140
+ * <label for="input">This input is restricted by the current maxlength: </label>
30141
+ * <input type="text" ng-model="model" id="input" name="input" ng-maxlength="maxlength" /><br>
30142
+ * <hr>
30143
+ * input valid? = <code>{{form.input.$valid}}</code><br>
30144
+ * model = <code>{{model}}</code>
30145
+ * </form>
30146
+ * </div>
30147
+ * </file>
30148
+ * <file name="protractor.js" type="protractor">
30149
+ var model = element(by.binding('model'));
30150
+ var input = element(by.id('input'));
30151
+
30152
+ it('should validate the input with the default maxlength', function() {
30153
+ input.sendKeys('abcdef');
30154
+ expect(model.getText()).not.toContain('abcdef');
28832
30155
 
30156
+ input.clear().then(function() {
30157
+ input.sendKeys('abcde');
30158
+ expect(model.getText()).toContain('abcde');
30159
+ });
30160
+ });
30161
+ * </file>
30162
+ * </example>
30163
+ */
28833
30164
  var maxlengthDirective = function() {
28834
30165
  return {
28835
30166
  restrict: 'A',
@@ -28850,6 +30181,70 @@ var maxlengthDirective = function() {
28850
30181
  };
28851
30182
  };
28852
30183
 
30184
+ /**
30185
+ * @ngdoc directive
30186
+ * @name ngMinlength
30187
+ *
30188
+ * @description
30189
+ *
30190
+ * ngMinlength adds the minlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
30191
+ * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
30192
+ *
30193
+ * The validator sets the `minlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
30194
+ * is shorter than the integer obtained by evaluating the Angular expression given in the
30195
+ * `ngMinlength` attribute value.
30196
+ *
30197
+ * <div class="alert alert-info">
30198
+ * **Note:** This directive is also added when the plain `minlength` attribute is used, with two
30199
+ * differences:
30200
+ * <ol>
30201
+ * <li>
30202
+ * `ngMinlength` does not set the `minlength` attribute and therefore HTML5 constraint
30203
+ * validation is not available.
30204
+ * </li>
30205
+ * <li>
30206
+ * The `ngMinlength` value must be an expression, while the `minlength` value must be
30207
+ * interpolated.
30208
+ * </li>
30209
+ * </ol>
30210
+ * </div>
30211
+ *
30212
+ * @example
30213
+ * <example name="ngMinlengthDirective" module="ngMinlengthExample">
30214
+ * <file name="index.html">
30215
+ * <script>
30216
+ * angular.module('ngMinlengthExample', [])
30217
+ * .controller('ExampleController', ['$scope', function($scope) {
30218
+ * $scope.minlength = 3;
30219
+ * }]);
30220
+ * </script>
30221
+ * <div ng-controller="ExampleController">
30222
+ * <form name="form">
30223
+ * <label for="minlength">Set a minlength: </label>
30224
+ * <input type="number" ng-model="minlength" id="minlength" />
30225
+ * <br>
30226
+ * <label for="input">This input is restricted by the current minlength: </label>
30227
+ * <input type="text" ng-model="model" id="input" name="input" ng-minlength="minlength" /><br>
30228
+ * <hr>
30229
+ * input valid? = <code>{{form.input.$valid}}</code><br>
30230
+ * model = <code>{{model}}</code>
30231
+ * </form>
30232
+ * </div>
30233
+ * </file>
30234
+ * <file name="protractor.js" type="protractor">
30235
+ var model = element(by.binding('model'));
30236
+ var input = element(by.id('input'));
30237
+
30238
+ it('should validate the input with the default minlength', function() {
30239
+ input.sendKeys('ab');
30240
+ expect(model.getText()).not.toContain('ab');
30241
+
30242
+ input.sendKeys('abc');
30243
+ expect(model.getText()).toContain('abc');
30244
+ });
30245
+ * </file>
30246
+ * </example>
30247
+ */
28853
30248
  var minlengthDirective = function() {
28854
30249
  return {
28855
30250
  restrict: 'A',
@@ -28962,6 +30357,20 @@ $provide.value("$locale", {
28962
30357
  "Nov",
28963
30358
  "Dec"
28964
30359
  ],
30360
+ "STANDALONEMONTH": [
30361
+ "January",
30362
+ "February",
30363
+ "March",
30364
+ "April",
30365
+ "May",
30366
+ "June",
30367
+ "July",
30368
+ "August",
30369
+ "September",
30370
+ "October",
30371
+ "November",
30372
+ "December"
30373
+ ],
28965
30374
  "WEEKENDRANGE": [
28966
30375
  5,
28967
30376
  6
@@ -29005,6 +30414,7 @@ $provide.value("$locale", {
29005
30414
  ]
29006
30415
  },
29007
30416
  "id": "en-us",
30417
+ "localeID": "en_US",
29008
30418
  "pluralCat": function(n, opt_precision) { var i = n | 0; var vf = getVF(n, opt_precision); if (i == 1 && vf.v == 0) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
29009
30419
  });
29010
30420
  }]);