angularjs-rails 1.4.8 → 1.5.0

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