angularjs-rails 1.4.4 → 1.4.7

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,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.4.4
2
+ * @license AngularJS v1.4.7
3
3
  * (c) 2010-2015 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -9190,7 +9190,7 @@ return jQuery;
9190
9190
  }));
9191
9191
 
9192
9192
  /**
9193
- * @license AngularJS v1.4.4
9193
+ * @license AngularJS v1.4.7
9194
9194
  * (c) 2010-2015 Google, Inc. http://angularjs.org
9195
9195
  * License: MIT
9196
9196
  */
@@ -9249,7 +9249,7 @@ function minErr(module, ErrorConstructor) {
9249
9249
  return match;
9250
9250
  });
9251
9251
 
9252
- message += '\nhttp://errors.angularjs.org/1.4.4/' +
9252
+ message += '\nhttp://errors.angularjs.org/1.4.7/' +
9253
9253
  (module ? module + '/' : '') + code;
9254
9254
 
9255
9255
  for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
@@ -10086,6 +10086,8 @@ function copy(source, destination, stackSource, stackDest) {
10086
10086
  } else if (isRegExp(source)) {
10087
10087
  destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
10088
10088
  destination.lastIndex = source.lastIndex;
10089
+ } else if (isFunction(source.cloneNode)) {
10090
+ destination = source.cloneNode(true);
10089
10091
  } else {
10090
10092
  var emptyObject = Object.create(getPrototypeOf(source));
10091
10093
  return copy(source, emptyObject, stackSource, stackDest);
@@ -10236,7 +10238,7 @@ function equals(o1, o2) {
10236
10238
  for (key in o2) {
10237
10239
  if (!(key in keySet) &&
10238
10240
  key.charAt(0) !== '$' &&
10239
- o2[key] !== undefined &&
10241
+ isDefined(o2[key]) &&
10240
10242
  !isFunction(o2[key])) return false;
10241
10243
  }
10242
10244
  return true;
@@ -10932,10 +10934,9 @@ function bindJQuery() {
10932
10934
 
10933
10935
  // bind to jQuery if present;
10934
10936
  var jqName = jq();
10935
- jQuery = window.jQuery; // use default jQuery.
10936
- if (isDefined(jqName)) { // `ngJq` present
10937
- jQuery = jqName === null ? undefined : window[jqName]; // if empty; use jqLite. if not empty, use jQuery specified by `ngJq`.
10938
- }
10937
+ jQuery = isUndefined(jqName) ? window.jQuery : // use jQuery (if present)
10938
+ !jqName ? undefined : // use jqLite
10939
+ window[jqName]; // use jQuery specified by `ngJq`
10939
10940
 
10940
10941
  // Use jQuery if it exists with proper functionality, otherwise default to us.
10941
10942
  // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
@@ -11040,22 +11041,24 @@ function getter(obj, path, bindFnToScope) {
11040
11041
  /**
11041
11042
  * Return the DOM siblings between the first and last node in the given array.
11042
11043
  * @param {Array} array like object
11043
- * @returns {jqLite} jqLite collection containing the nodes
11044
+ * @returns {Array} the inputted object or a jqLite collection containing the nodes
11044
11045
  */
11045
11046
  function getBlockNodes(nodes) {
11046
- // TODO(perf): just check if all items in `nodes` are siblings and if they are return the original
11047
- // collection, otherwise update the original collection.
11047
+ // TODO(perf): update `nodes` instead of creating a new object?
11048
11048
  var node = nodes[0];
11049
11049
  var endNode = nodes[nodes.length - 1];
11050
- var blockNodes = [node];
11050
+ var blockNodes;
11051
11051
 
11052
- do {
11053
- node = node.nextSibling;
11054
- if (!node) break;
11055
- blockNodes.push(node);
11056
- } while (node !== endNode);
11052
+ for (var i = 1; node !== endNode && (node = node.nextSibling); i++) {
11053
+ if (blockNodes || nodes[i] !== node) {
11054
+ if (!blockNodes) {
11055
+ blockNodes = jqLite(slice.call(nodes, 0, i));
11056
+ }
11057
+ blockNodes.push(node);
11058
+ }
11059
+ }
11057
11060
 
11058
- return jqLite(blockNodes);
11061
+ return blockNodes || nodes;
11059
11062
  }
11060
11063
 
11061
11064
 
@@ -11439,7 +11442,7 @@ function serializeObject(obj) {
11439
11442
  val = toJsonReplacer(key, val);
11440
11443
  if (isObject(val)) {
11441
11444
 
11442
- if (seen.indexOf(val) >= 0) return '<<already seen>>';
11445
+ if (seen.indexOf(val) >= 0) return '...';
11443
11446
 
11444
11447
  seen.push(val);
11445
11448
  }
@@ -11450,7 +11453,7 @@ function serializeObject(obj) {
11450
11453
  function toDebugString(obj) {
11451
11454
  if (typeof obj === 'function') {
11452
11455
  return obj.toString().replace(/ \{[\s\S]*$/, '');
11453
- } else if (typeof obj === 'undefined') {
11456
+ } else if (isUndefined(obj)) {
11454
11457
  return 'undefined';
11455
11458
  } else if (typeof obj !== 'string') {
11456
11459
  return serializeObject(obj);
@@ -11530,6 +11533,7 @@ function toDebugString(obj) {
11530
11533
  $HttpParamSerializerProvider,
11531
11534
  $HttpParamSerializerJQLikeProvider,
11532
11535
  $HttpBackendProvider,
11536
+ $xhrFactoryProvider,
11533
11537
  $LocationProvider,
11534
11538
  $LogProvider,
11535
11539
  $ParseProvider,
@@ -11556,8 +11560,9 @@ function toDebugString(obj) {
11556
11560
  * @name angular.version
11557
11561
  * @module ng
11558
11562
  * @description
11559
- * An object that contains information about the current AngularJS version. This object has the
11560
- * following properties:
11563
+ * An object that contains information about the current AngularJS version.
11564
+ *
11565
+ * This object has the following properties:
11561
11566
  *
11562
11567
  * - `full` – `{string}` – Full version string, such as "0.9.18".
11563
11568
  * - `major` – `{number}` – Major version number, such as "0".
@@ -11566,11 +11571,11 @@ function toDebugString(obj) {
11566
11571
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
11567
11572
  */
11568
11573
  var version = {
11569
- full: '1.4.4', // all of these placeholder strings will be replaced by grunt's
11574
+ full: '1.4.7', // all of these placeholder strings will be replaced by grunt's
11570
11575
  major: 1, // package task
11571
11576
  minor: 4,
11572
- dot: 4,
11573
- codeName: 'pylon-requirement'
11577
+ dot: 7,
11578
+ codeName: 'dark-luminescence'
11574
11579
  };
11575
11580
 
11576
11581
 
@@ -11687,6 +11692,7 @@ function publishExternalAPI(angular) {
11687
11692
  $httpParamSerializer: $HttpParamSerializerProvider,
11688
11693
  $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,
11689
11694
  $httpBackend: $HttpBackendProvider,
11695
+ $xhrFactory: $xhrFactoryProvider,
11690
11696
  $location: $LocationProvider,
11691
11697
  $log: $LogProvider,
11692
11698
  $parse: $ParseProvider,
@@ -11775,7 +11781,7 @@ function publishExternalAPI(angular) {
11775
11781
  * - [`html()`](http://api.jquery.com/html/)
11776
11782
  * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
11777
11783
  * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
11778
- * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
11784
+ * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces, selectors or event object as parameter
11779
11785
  * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
11780
11786
  * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
11781
11787
  * - [`prepend()`](http://api.jquery.com/prepend/)
@@ -11789,7 +11795,7 @@ function publishExternalAPI(angular) {
11789
11795
  * - [`text()`](http://api.jquery.com/text/)
11790
11796
  * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
11791
11797
  * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
11792
- * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces
11798
+ * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces or event object as parameter
11793
11799
  * - [`val()`](http://api.jquery.com/val/)
11794
11800
  * - [`wrap()`](http://api.jquery.com/wrap/)
11795
11801
  *
@@ -11861,10 +11867,10 @@ function camelCase(name) {
11861
11867
  replace(MOZ_HACK_REGEXP, 'Moz$1');
11862
11868
  }
11863
11869
 
11864
- var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;
11870
+ var SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/;
11865
11871
  var HTML_REGEXP = /<|&#?\w+;/;
11866
- var TAG_NAME_REGEXP = /<([\w:]+)/;
11867
- var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi;
11872
+ var TAG_NAME_REGEXP = /<([\w:-]+)/;
11873
+ var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi;
11868
11874
 
11869
11875
  var wrapMap = {
11870
11876
  'option': [1, '<select multiple="multiple">', '</select>'],
@@ -12160,7 +12166,7 @@ function jqLiteInheritedData(element, name, value) {
12160
12166
 
12161
12167
  while (element) {
12162
12168
  for (var i = 0, ii = names.length; i < ii; i++) {
12163
- if ((value = jqLite.data(element, names[i])) !== undefined) return value;
12169
+ if (isDefined(value = jqLite.data(element, names[i]))) return value;
12164
12170
  }
12165
12171
 
12166
12172
  // If dealing with a document fragment node with a host element, and no parent, use the host
@@ -12266,9 +12272,8 @@ function getBooleanAttrName(element, name) {
12266
12272
  return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
12267
12273
  }
12268
12274
 
12269
- function getAliasedAttrName(element, name) {
12270
- var nodeName = element.nodeName;
12271
- return (nodeName === 'INPUT' || nodeName === 'TEXTAREA') && ALIASED_ATTR[name];
12275
+ function getAliasedAttrName(name) {
12276
+ return ALIASED_ATTR[name];
12272
12277
  }
12273
12278
 
12274
12279
  forEach({
@@ -12405,7 +12410,7 @@ forEach({
12405
12410
  // in a way that survives minification.
12406
12411
  // jqLiteEmpty takes no arguments but is a setter.
12407
12412
  if (fn !== jqLiteEmpty &&
12408
- (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) {
12413
+ (isUndefined((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2))) {
12409
12414
  if (isObject(arg1)) {
12410
12415
 
12411
12416
  // we are a write, but the object properties are the key/values
@@ -12426,7 +12431,7 @@ forEach({
12426
12431
  // TODO: do we still need this?
12427
12432
  var value = fn.$dv;
12428
12433
  // Only if we have $dv do we iterate over all, otherwise it is just the first element.
12429
- var jj = (value === undefined) ? Math.min(nodeCount, 1) : nodeCount;
12434
+ var jj = (isUndefined(value)) ? Math.min(nodeCount, 1) : nodeCount;
12430
12435
  for (var j = 0; j < jj; j++) {
12431
12436
  var nodeValue = fn(this[j], arg1, arg2);
12432
12437
  value = value ? value + nodeValue : nodeValue;
@@ -14065,61 +14070,66 @@ var $$CoreAnimateQueueProvider = function() {
14065
14070
  }
14066
14071
  };
14067
14072
 
14068
- function addRemoveClassesPostDigest(element, add, remove) {
14069
- var classVal, data = postDigestQueue.get(element);
14070
14073
 
14071
- if (!data) {
14072
- postDigestQueue.put(element, data = {});
14073
- postDigestElements.push(element);
14074
+ function updateData(data, classes, value) {
14075
+ var changed = false;
14076
+ if (classes) {
14077
+ classes = isString(classes) ? classes.split(' ') :
14078
+ isArray(classes) ? classes : [];
14079
+ forEach(classes, function(className) {
14080
+ if (className) {
14081
+ changed = true;
14082
+ data[className] = value;
14083
+ }
14084
+ });
14074
14085
  }
14075
-
14076
- var updateData = function(classes, value) {
14077
- var changed = false;
14078
- if (classes) {
14079
- classes = isString(classes) ? classes.split(' ') :
14080
- isArray(classes) ? classes : [];
14081
- forEach(classes, function(className) {
14082
- if (className) {
14083
- changed = true;
14084
- data[className] = value;
14086
+ return changed;
14087
+ }
14088
+
14089
+ function handleCSSClassChanges() {
14090
+ forEach(postDigestElements, function(element) {
14091
+ var data = postDigestQueue.get(element);
14092
+ if (data) {
14093
+ var existing = splitClasses(element.attr('class'));
14094
+ var toAdd = '';
14095
+ var toRemove = '';
14096
+ forEach(data, function(status, className) {
14097
+ var hasClass = !!existing[className];
14098
+ if (status !== hasClass) {
14099
+ if (status) {
14100
+ toAdd += (toAdd.length ? ' ' : '') + className;
14101
+ } else {
14102
+ toRemove += (toRemove.length ? ' ' : '') + className;
14103
+ }
14085
14104
  }
14086
14105
  });
14106
+
14107
+ forEach(element, function(elm) {
14108
+ toAdd && jqLiteAddClass(elm, toAdd);
14109
+ toRemove && jqLiteRemoveClass(elm, toRemove);
14110
+ });
14111
+ postDigestQueue.remove(element);
14087
14112
  }
14088
- return changed;
14089
- };
14113
+ });
14114
+ postDigestElements.length = 0;
14115
+ }
14090
14116
 
14091
- var classesAdded = updateData(add, true);
14092
- var classesRemoved = updateData(remove, false);
14093
- if ((!classesAdded && !classesRemoved) || postDigestElements.length > 1) return;
14094
-
14095
- $rootScope.$$postDigest(function() {
14096
- forEach(postDigestElements, function(element) {
14097
- var data = postDigestQueue.get(element);
14098
- if (data) {
14099
- var existing = splitClasses(element.attr('class'));
14100
- var toAdd = '';
14101
- var toRemove = '';
14102
- forEach(data, function(status, className) {
14103
- var hasClass = !!existing[className];
14104
- if (status !== hasClass) {
14105
- if (status) {
14106
- toAdd += (toAdd.length ? ' ' : '') + className;
14107
- } else {
14108
- toRemove += (toRemove.length ? ' ' : '') + className;
14109
- }
14110
- }
14111
- });
14112
14117
 
14113
- forEach(element, function(elm) {
14114
- toAdd && jqLiteAddClass(elm, toAdd);
14115
- toRemove && jqLiteRemoveClass(elm, toRemove);
14116
- });
14117
- postDigestQueue.remove(element);
14118
- }
14119
- });
14118
+ function addRemoveClassesPostDigest(element, add, remove) {
14119
+ var data = postDigestQueue.get(element) || {};
14120
14120
 
14121
- postDigestElements.length = 0;
14122
- });
14121
+ var classesAdded = updateData(data, add, true);
14122
+ var classesRemoved = updateData(data, remove, false);
14123
+
14124
+ if (classesAdded || classesRemoved) {
14125
+
14126
+ postDigestQueue.put(element, data);
14127
+ postDigestElements.push(element);
14128
+
14129
+ if (postDigestElements.length === 1) {
14130
+ $rootScope.$$postDigest(handleCSSClassChanges);
14131
+ }
14132
+ }
14123
14133
  }
14124
14134
  }];
14125
14135
  };
@@ -14584,14 +14594,21 @@ var $CoreAnimateCssProvider = function() {
14584
14594
  return this.getPromise().then(f1,f2);
14585
14595
  },
14586
14596
  'catch': function(f1) {
14587
- return this.getPromise().catch(f1);
14597
+ return this.getPromise()['catch'](f1);
14588
14598
  },
14589
14599
  'finally': function(f1) {
14590
- return this.getPromise().finally(f1);
14600
+ return this.getPromise()['finally'](f1);
14591
14601
  }
14592
14602
  };
14593
14603
 
14594
14604
  return function(element, options) {
14605
+ // there is no point in applying the styles since
14606
+ // there is no animation that goes on at all in
14607
+ // this version of $animateCss.
14608
+ if (options.cleanupStyles) {
14609
+ options.from = options.to = null;
14610
+ }
14611
+
14595
14612
  if (options.from) {
14596
14613
  element.css(options.from);
14597
14614
  options.from = null;
@@ -14720,7 +14737,7 @@ function Browser(window, document, $log, $sniffer) {
14720
14737
  var cachedState, lastHistoryState,
14721
14738
  lastBrowserUrl = location.href,
14722
14739
  baseElement = document.find('base'),
14723
- reloadLocation = null;
14740
+ pendingLocation = null;
14724
14741
 
14725
14742
  cacheState();
14726
14743
  lastHistoryState = cachedState;
@@ -14780,8 +14797,8 @@ function Browser(window, document, $log, $sniffer) {
14780
14797
  // Do the assignment again so that those two variables are referentially identical.
14781
14798
  lastHistoryState = cachedState;
14782
14799
  } else {
14783
- if (!sameBase || reloadLocation) {
14784
- reloadLocation = url;
14800
+ if (!sameBase || pendingLocation) {
14801
+ pendingLocation = url;
14785
14802
  }
14786
14803
  if (replace) {
14787
14804
  location.replace(url);
@@ -14790,14 +14807,18 @@ function Browser(window, document, $log, $sniffer) {
14790
14807
  } else {
14791
14808
  location.hash = getHash(url);
14792
14809
  }
14810
+ if (location.href !== url) {
14811
+ pendingLocation = url;
14812
+ }
14793
14813
  }
14794
14814
  return self;
14795
14815
  // getter
14796
14816
  } else {
14797
- // - reloadLocation is needed as browsers don't allow to read out
14798
- // the new location.href if a reload happened.
14817
+ // - pendingLocation is needed as browsers don't allow to read out
14818
+ // the new location.href if a reload happened or if there is a bug like in iOS 9 (see
14819
+ // https://openradar.appspot.com/22186109).
14799
14820
  // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
14800
- return reloadLocation || location.href.replace(/%27/g,"'");
14821
+ return pendingLocation || location.href.replace(/%27/g,"'");
14801
14822
  }
14802
14823
  };
14803
14824
 
@@ -14819,6 +14840,7 @@ function Browser(window, document, $log, $sniffer) {
14819
14840
  urlChangeInit = false;
14820
14841
 
14821
14842
  function cacheStateAndFireUrlChange() {
14843
+ pendingLocation = null;
14822
14844
  cacheState();
14823
14845
  fireUrlChange();
14824
14846
  }
@@ -15054,10 +15076,10 @@ function $BrowserProvider() {
15054
15076
  $scope.keys = [];
15055
15077
  $scope.cache = $cacheFactory('cacheId');
15056
15078
  $scope.put = function(key, value) {
15057
- if ($scope.cache.get(key) === undefined) {
15079
+ if (angular.isUndefined($scope.cache.get(key))) {
15058
15080
  $scope.keys.push(key);
15059
15081
  }
15060
- $scope.cache.put(key, value === undefined ? null : value);
15082
+ $scope.cache.put(key, angular.isUndefined(value) ? null : value);
15061
15083
  };
15062
15084
  }]);
15063
15085
  </file>
@@ -15533,18 +15555,24 @@ function $TemplateCacheProvider() {
15533
15555
  * and other directives used in the directive's template will also be excluded from execution.
15534
15556
  *
15535
15557
  * #### `scope`
15536
- * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the
15537
- * same element request a new scope, only one new scope is created. The new scope rule does not
15538
- * apply for the root of the template since the root of the template always gets a new scope.
15558
+ * The scope property can be `true`, an object or a falsy value:
15559
+ *
15560
+ * * **falsy:** No scope will be created for the directive. The directive will use its parent's scope.
15561
+ *
15562
+ * * **`true`:** A new child scope that prototypically inherits from its parent will be created for
15563
+ * the directive's element. If multiple directives on the same element request a new scope,
15564
+ * only one new scope is created. The new scope rule does not apply for the root of the template
15565
+ * since the root of the template always gets a new scope.
15539
15566
  *
15540
- * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from
15541
- * normal scope in that it does not prototypically inherit from the parent scope. This is useful
15542
- * when creating reusable components, which should not accidentally read or modify data in the
15543
- * parent scope.
15567
+ * * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's element. The
15568
+ * 'isolate' scope differs from normal scope in that it does not prototypically inherit from its parent
15569
+ * scope. This is useful when creating reusable components, which should not accidentally read or modify
15570
+ * data in the parent scope.
15544
15571
  *
15545
- * The 'isolate' scope takes an object hash which defines a set of local scope properties
15546
- * derived from the parent scope. These local properties are useful for aliasing values for
15547
- * templates. Locals definition is a hash of local scope property to its source:
15572
+ * The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the
15573
+ * directive's element. These local properties are useful for aliasing values for templates. The keys in
15574
+ * the object hash map to the name of the property on the isolate scope; the values define how the property
15575
+ * is bound to the parent scope, via matching attributes on the directive's element:
15548
15576
  *
15549
15577
  * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
15550
15578
  * always a string since DOM attributes are strings. If no `attr` name is specified then the
@@ -15577,6 +15605,20 @@ function $TemplateCacheProvider() {
15577
15605
  * For example, if the expression is `increment(amount)` then we can specify the amount value
15578
15606
  * by calling the `localFn` as `localFn({amount: 22})`.
15579
15607
  *
15608
+ * In general it's possible to apply more than one directive to one element, but there might be limitations
15609
+ * depending on the type of scope required by the directives. The following points will help explain these limitations.
15610
+ * For simplicity only two directives are taken into account, but it is also applicable for several directives:
15611
+ *
15612
+ * * **no scope** + **no scope** => Two directives which don't require their own scope will use their parent's scope
15613
+ * * **child scope** + **no scope** => Both directives will share one single child scope
15614
+ * * **child scope** + **child scope** => Both directives will share one single child scope
15615
+ * * **isolated scope** + **no scope** => The isolated directive will use it's own created isolated scope. The other directive will use
15616
+ * its parent's scope
15617
+ * * **isolated scope** + **child scope** => **Won't work!** Only one scope can be related to one element. Therefore these directives cannot
15618
+ * be applied to the same element.
15619
+ * * **isolated scope** + **isolated scope** => **Won't work!** Only one scope can be related to one element. Therefore these directives
15620
+ * cannot be applied to the same element.
15621
+ *
15580
15622
  *
15581
15623
  * #### `bindToController`
15582
15624
  * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController: true` will
@@ -15585,7 +15627,7 @@ function $TemplateCacheProvider() {
15585
15627
  *
15586
15628
  * #### `controller`
15587
15629
  * Controller constructor function. The controller is instantiated before the
15588
- * pre-linking phase and it is shared with other directives (see
15630
+ * pre-linking phase and can be accessed by other directives (see
15589
15631
  * `require` attribute). This allows the directives to communicate with each other and augment
15590
15632
  * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
15591
15633
  *
@@ -15625,9 +15667,10 @@ function $TemplateCacheProvider() {
15625
15667
  *
15626
15668
  * #### `controllerAs`
15627
15669
  * Identifier name for a reference to the controller in the directive's scope.
15628
- * This allows the controller to be referenced from the directive template. The directive
15629
- * needs to define a scope for this configuration to be used. Useful in the case when
15630
- * directive is used as component.
15670
+ * This allows the controller to be referenced from the directive template. This is especially
15671
+ * useful when a directive is used as component, i.e. with an `isolate` scope. It's also possible
15672
+ * to use it in a directive without an `isolate` / `new` scope, but you need to be aware that the
15673
+ * `controllerAs` reference might overwrite a property that already exists on the parent scope.
15631
15674
  *
15632
15675
  *
15633
15676
  * #### `restrict`
@@ -16464,7 +16507,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16464
16507
 
16465
16508
  var node = this.$$element[0],
16466
16509
  booleanKey = getBooleanAttrName(node, key),
16467
- aliasedKey = getAliasedAttrName(node, key),
16510
+ aliasedKey = getAliasedAttrName(key),
16468
16511
  observer = key,
16469
16512
  nodeName;
16470
16513
 
@@ -16531,7 +16574,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16531
16574
  }
16532
16575
 
16533
16576
  if (writeAttr !== false) {
16534
- if (value === null || value === undefined) {
16577
+ if (value === null || isUndefined(value)) {
16535
16578
  this.$$element.removeAttr(attrName);
16536
16579
  } else {
16537
16580
  this.$$element.attr(attrName, value);
@@ -17497,7 +17540,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
17497
17540
  i = 0, ii = directives.length; i < ii; i++) {
17498
17541
  try {
17499
17542
  directive = directives[i];
17500
- if ((maxPriority === undefined || maxPriority > directive.priority) &&
17543
+ if ((isUndefined(maxPriority) || maxPriority > directive.priority) &&
17501
17544
  directive.restrict.indexOf(location) != -1) {
17502
17545
  if (startAttrName) {
17503
17546
  directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
@@ -17793,7 +17836,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
17793
17836
  compile: function() {
17794
17837
  return {
17795
17838
  pre: function attrInterpolatePreLinkFn(scope, element, attr) {
17796
- var $$observers = (attr.$$observers || (attr.$$observers = {}));
17839
+ var $$observers = (attr.$$observers || (attr.$$observers = createMap()));
17797
17840
 
17798
17841
  if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
17799
17842
  throw $compileMinErr('nodomevents',
@@ -18845,28 +18888,18 @@ function $HttpProvider() {
18845
18888
  *
18846
18889
  *
18847
18890
  * ## General usage
18848
- * The `$http` service is a function which takes a single argument — a configuration object —
18891
+ * The `$http` service is a function which takes a single argument — a {@link $http#usage configuration object}
18849
18892
  * that is used to generate an HTTP request and returns a {@link ng.$q promise}.
18850
18893
  *
18851
18894
  * ```js
18852
- * // Simple GET request example :
18853
- * $http.get('/someUrl').
18854
- * then(function(response) {
18855
- * // this callback will be called asynchronously
18856
- * // when the response is available
18857
- * }, function(response) {
18858
- * // called asynchronously if an error occurs
18859
- * // or server returns response with an error status.
18860
- * });
18861
- * ```
18862
- *
18863
- * ```js
18864
- * // Simple POST request example (passing data) :
18865
- * $http.post('/someUrl', {msg:'hello word!'}).
18866
- * then(function(response) {
18895
+ * // Simple GET request example:
18896
+ * $http({
18897
+ * method: 'GET',
18898
+ * url: '/someUrl'
18899
+ * }).then(function successCallback(response) {
18867
18900
  * // this callback will be called asynchronously
18868
18901
  * // when the response is available
18869
- * }, function(response) {
18902
+ * }, function errorCallback(response) {
18870
18903
  * // called asynchronously if an error occurs
18871
18904
  * // or server returns response with an error status.
18872
18905
  * });
@@ -18886,25 +18919,16 @@ function $HttpProvider() {
18886
18919
  * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
18887
18920
  * called for such responses.
18888
18921
  *
18889
- * ## Writing Unit Tests that use $http
18890
- * When unit testing (using {@link ngMock ngMock}), it is necessary to call
18891
- * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
18892
- * request using trained responses.
18893
- *
18894
- * ```
18895
- * $httpBackend.expectGET(...);
18896
- * $http.get(...);
18897
- * $httpBackend.flush();
18898
- * ```
18899
18922
  *
18900
18923
  * ## Shortcut methods
18901
18924
  *
18902
18925
  * Shortcut methods are also available. All shortcut methods require passing in the URL, and
18903
- * request data must be passed in for POST/PUT requests.
18926
+ * request data must be passed in for POST/PUT requests. An optional config can be passed as the
18927
+ * last argument.
18904
18928
  *
18905
18929
  * ```js
18906
- * $http.get('/someUrl').then(successCallback);
18907
- * $http.post('/someUrl', data).then(successCallback);
18930
+ * $http.get('/someUrl', config).then(successCallback, errorCallback);
18931
+ * $http.post('/someUrl', data, config).then(successCallback, errorCallback);
18908
18932
  * ```
18909
18933
  *
18910
18934
  * Complete list of shortcut methods:
@@ -18918,6 +18942,17 @@ function $HttpProvider() {
18918
18942
  * - {@link ng.$http#patch $http.patch}
18919
18943
  *
18920
18944
  *
18945
+ * ## Writing Unit Tests that use $http
18946
+ * When unit testing (using {@link ngMock ngMock}), it is necessary to call
18947
+ * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
18948
+ * request using trained responses.
18949
+ *
18950
+ * ```
18951
+ * $httpBackend.expectGET(...);
18952
+ * $http.get(...);
18953
+ * $httpBackend.flush();
18954
+ * ```
18955
+ *
18921
18956
  * ## Deprecation Notice
18922
18957
  * <div class="alert alert-danger">
18923
18958
  * The `$http` legacy promise methods `success` and `error` have been deprecated.
@@ -19075,7 +19110,7 @@ function $HttpProvider() {
19075
19110
  *
19076
19111
  * There are two kinds of interceptors (and two kinds of rejection interceptors):
19077
19112
  *
19078
- * * `request`: interceptors get called with a http `config` object. The function is free to
19113
+ * * `request`: interceptors get called with a http {@link $http#usage config} object. The function is free to
19079
19114
  * modify the `config` object or create a new one. The function needs to return the `config`
19080
19115
  * object directly, or a promise containing the `config` or a new `config` object.
19081
19116
  * * `requestError`: interceptor gets called when a previous interceptor threw an error or
@@ -19709,8 +19744,8 @@ function $HttpProvider() {
19709
19744
  * Resolves the raw $http promise.
19710
19745
  */
19711
19746
  function resolvePromise(response, status, headers, statusText) {
19712
- // normalize internal statuses to 0
19713
- status = Math.max(status, 0);
19747
+ //status: HTTP response status code, 0, -1 (aborted by timeout / promise)
19748
+ status = status >= -1 ? status : 0;
19714
19749
 
19715
19750
  (isSuccess(status) ? deferred.resolve : deferred.reject)({
19716
19751
  data: response,
@@ -19741,8 +19776,33 @@ function $HttpProvider() {
19741
19776
  }];
19742
19777
  }
19743
19778
 
19744
- function createXhr() {
19745
- return new window.XMLHttpRequest();
19779
+ /**
19780
+ * @ngdoc service
19781
+ * @name $xhrFactory
19782
+ *
19783
+ * @description
19784
+ * Factory function used to create XMLHttpRequest objects.
19785
+ *
19786
+ * Replace or decorate this service to create your own custom XMLHttpRequest objects.
19787
+ *
19788
+ * ```
19789
+ * angular.module('myApp', [])
19790
+ * .factory('$xhrFactory', function() {
19791
+ * return function createXhr(method, url) {
19792
+ * return new window.XMLHttpRequest({mozSystem: true});
19793
+ * };
19794
+ * });
19795
+ * ```
19796
+ *
19797
+ * @param {string} method HTTP method of the request (GET, POST, PUT, ..)
19798
+ * @param {string} url URL of the request.
19799
+ */
19800
+ function $xhrFactoryProvider() {
19801
+ this.$get = function() {
19802
+ return function createXhr() {
19803
+ return new window.XMLHttpRequest();
19804
+ };
19805
+ };
19746
19806
  }
19747
19807
 
19748
19808
  /**
@@ -19750,6 +19810,7 @@ function createXhr() {
19750
19810
  * @name $httpBackend
19751
19811
  * @requires $window
19752
19812
  * @requires $document
19813
+ * @requires $xhrFactory
19753
19814
  *
19754
19815
  * @description
19755
19816
  * HTTP backend used by the {@link ng.$http service} that delegates to
@@ -19762,8 +19823,8 @@ function createXhr() {
19762
19823
  * $httpBackend} which can be trained with responses.
19763
19824
  */
19764
19825
  function $HttpBackendProvider() {
19765
- this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
19766
- return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]);
19826
+ this.$get = ['$browser', '$window', '$document', '$xhrFactory', function($browser, $window, $document, $xhrFactory) {
19827
+ return createHttpBackend($browser, $xhrFactory, $browser.defer, $window.angular.callbacks, $document[0]);
19767
19828
  }];
19768
19829
  }
19769
19830
 
@@ -19787,7 +19848,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
19787
19848
  });
19788
19849
  } else {
19789
19850
 
19790
- var xhr = createXhr();
19851
+ var xhr = createXhr(method, url);
19791
19852
 
19792
19853
  xhr.open(method, url, true);
19793
19854
  forEach(headers, function(value, key) {
@@ -19850,7 +19911,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
19850
19911
  }
19851
19912
  }
19852
19913
 
19853
- xhr.send(post);
19914
+ xhr.send(isUndefined(post) ? null : post);
19854
19915
  }
19855
19916
 
19856
19917
  if (timeout > 0) {
@@ -19867,7 +19928,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
19867
19928
 
19868
19929
  function completeRequest(callback, status, response, headersString, statusText) {
19869
19930
  // cancel timeout and subsequent timeout promise resolution
19870
- if (timeoutId !== undefined) {
19931
+ if (isDefined(timeoutId)) {
19871
19932
  $browserDefer.cancel(timeoutId);
19872
19933
  }
19873
19934
  jsonpDone = xhr = null;
@@ -20053,7 +20114,7 @@ function $InterpolateProvider() {
20053
20114
  * ```js
20054
20115
  * var $interpolate = ...; // injected
20055
20116
  * var exp = $interpolate('Hello {{name | uppercase}}!');
20056
- * expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
20117
+ * expect(exp({name:'Angular'})).toEqual('Hello ANGULAR!');
20057
20118
  * ```
20058
20119
  *
20059
20120
  * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is
@@ -20606,14 +20667,14 @@ function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) {
20606
20667
  var appUrl, prevAppUrl;
20607
20668
  var rewrittenUrl;
20608
20669
 
20609
- if ((appUrl = beginsWith(appBase, url)) !== undefined) {
20670
+ if (isDefined(appUrl = beginsWith(appBase, url))) {
20610
20671
  prevAppUrl = appUrl;
20611
- if ((appUrl = beginsWith(basePrefix, appUrl)) !== undefined) {
20672
+ if (isDefined(appUrl = beginsWith(basePrefix, appUrl))) {
20612
20673
  rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
20613
20674
  } else {
20614
20675
  rewrittenUrl = appBase + prevAppUrl;
20615
20676
  }
20616
- } else if ((appUrl = beginsWith(appBaseNoFile, url)) !== undefined) {
20677
+ } else if (isDefined(appUrl = beginsWith(appBaseNoFile, url))) {
20617
20678
  rewrittenUrl = appBaseNoFile + appUrl;
20618
20679
  } else if (appBaseNoFile == url + '/') {
20619
20680
  rewrittenUrl = appBaseNoFile;
@@ -21666,6 +21727,25 @@ function ensureSafeMemberName(name, fullExpression) {
21666
21727
  return name;
21667
21728
  }
21668
21729
 
21730
+ function getStringValue(name, fullExpression) {
21731
+ // From the JavaScript docs:
21732
+ // Property names must be strings. This means that non-string objects cannot be used
21733
+ // as keys in an object. Any non-string object, including a number, is typecasted
21734
+ // into a string via the toString method.
21735
+ //
21736
+ // So, to ensure that we are checking the same `name` that JavaScript would use,
21737
+ // we cast it to a string, if possible.
21738
+ // Doing `name + ''` can cause a repl error if the result to `toString` is not a string,
21739
+ // this is, this will handle objects that misbehave.
21740
+ name = name + '';
21741
+ if (!isString(name)) {
21742
+ throw $parseMinErr('iseccst',
21743
+ 'Cannot convert object to primitive value! '
21744
+ + 'Expression: {0}', fullExpression);
21745
+ }
21746
+ return name;
21747
+ }
21748
+
21669
21749
  function ensureSafeObject(obj, fullExpression) {
21670
21750
  // nifty check if obj is Function that is fast and works across iframes and other contexts
21671
21751
  if (obj) {
@@ -21711,6 +21791,16 @@ function ensureSafeFunction(obj, fullExpression) {
21711
21791
  }
21712
21792
  }
21713
21793
 
21794
+ function ensureSafeAssignContext(obj, fullExpression) {
21795
+ if (obj) {
21796
+ if (obj === (0).constructor || obj === (false).constructor || obj === ''.constructor ||
21797
+ obj === {}.constructor || obj === [].constructor || obj === Function.constructor) {
21798
+ throw $parseMinErr('isecaf',
21799
+ 'Assigning to a constructor is disallowed! Expression: {0}', fullExpression);
21800
+ }
21801
+ }
21802
+ }
21803
+
21714
21804
  var OPERATORS = createMap();
21715
21805
  forEach('+ - * / % === !== == != < > <= >= && || ! = |'.split(' '), function(operator) { OPERATORS[operator] = true; });
21716
21806
  var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
@@ -22392,6 +22482,7 @@ ASTCompiler.prototype = {
22392
22482
  this.state.computing = 'assign';
22393
22483
  var result = this.nextId();
22394
22484
  this.recurse(assignable, result);
22485
+ this.return_(result);
22395
22486
  extra = 'fn.assign=' + this.generateFunction('assign', 's,v,l');
22396
22487
  }
22397
22488
  var toWatch = getInputs(ast.body);
@@ -22424,6 +22515,8 @@ ASTCompiler.prototype = {
22424
22515
  'ensureSafeMemberName',
22425
22516
  'ensureSafeObject',
22426
22517
  'ensureSafeFunction',
22518
+ 'getStringValue',
22519
+ 'ensureSafeAssignContext',
22427
22520
  'ifDefined',
22428
22521
  'plus',
22429
22522
  'text',
@@ -22432,6 +22525,8 @@ ASTCompiler.prototype = {
22432
22525
  ensureSafeMemberName,
22433
22526
  ensureSafeObject,
22434
22527
  ensureSafeFunction,
22528
+ getStringValue,
22529
+ ensureSafeAssignContext,
22435
22530
  ifDefined,
22436
22531
  plusFn,
22437
22532
  expression);
@@ -22575,6 +22670,7 @@ ASTCompiler.prototype = {
22575
22670
  if (ast.computed) {
22576
22671
  right = self.nextId();
22577
22672
  self.recurse(ast.property, right);
22673
+ self.getStringValue(right);
22578
22674
  self.addEnsureSafeMemberName(right);
22579
22675
  if (create && create !== 1) {
22580
22676
  self.if_(self.not(self.computedMember(left, right)), self.lazyAssign(self.computedMember(left, right), '{}'));
@@ -22658,6 +22754,7 @@ ASTCompiler.prototype = {
22658
22754
  self.if_(self.notNull(left.context), function() {
22659
22755
  self.recurse(ast.right, right);
22660
22756
  self.addEnsureSafeObject(self.member(left.context, left.name, left.computed));
22757
+ self.addEnsureSafeAssignContext(left.context);
22661
22758
  expression = self.member(left.context, left.name, left.computed) + ast.operator + right;
22662
22759
  self.assign(intoId, expression);
22663
22760
  recursionFn(intoId || expression);
@@ -22783,6 +22880,10 @@ ASTCompiler.prototype = {
22783
22880
  this.current().body.push(this.ensureSafeFunction(item), ';');
22784
22881
  },
22785
22882
 
22883
+ addEnsureSafeAssignContext: function(item) {
22884
+ this.current().body.push(this.ensureSafeAssignContext(item), ';');
22885
+ },
22886
+
22786
22887
  ensureSafeObject: function(item) {
22787
22888
  return 'ensureSafeObject(' + item + ',text)';
22788
22889
  },
@@ -22795,6 +22896,14 @@ ASTCompiler.prototype = {
22795
22896
  return 'ensureSafeFunction(' + item + ',text)';
22796
22897
  },
22797
22898
 
22899
+ getStringValue: function(item) {
22900
+ this.assign(item, 'getStringValue(' + item + ',text)');
22901
+ },
22902
+
22903
+ ensureSafeAssignContext: function(item) {
22904
+ return 'ensureSafeAssignContext(' + item + ',text)';
22905
+ },
22906
+
22798
22907
  lazyRecurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
22799
22908
  var self = this;
22800
22909
  return function() {
@@ -22972,6 +23081,7 @@ ASTInterpreter.prototype = {
22972
23081
  var lhs = left(scope, locals, assign, inputs);
22973
23082
  var rhs = right(scope, locals, assign, inputs);
22974
23083
  ensureSafeObject(lhs.value, self.expression);
23084
+ ensureSafeAssignContext(lhs.context);
22975
23085
  lhs.context[lhs.name] = rhs;
22976
23086
  return context ? {value: rhs} : rhs;
22977
23087
  };
@@ -23169,6 +23279,7 @@ ASTInterpreter.prototype = {
23169
23279
  var value;
23170
23280
  if (lhs != null) {
23171
23281
  rhs = right(scope, locals, assign, inputs);
23282
+ rhs = getStringValue(rhs);
23172
23283
  ensureSafeMemberName(rhs, expression);
23173
23284
  if (create && create !== 1 && lhs && !(lhs[rhs])) {
23174
23285
  lhs[rhs] = {};
@@ -24109,7 +24220,7 @@ function $$RAFProvider() { //rAF
24109
24220
  $window.webkitCancelRequestAnimationFrame;
24110
24221
 
24111
24222
  var rafSupported = !!requestAnimationFrame;
24112
- var rafFn = rafSupported
24223
+ var raf = rafSupported
24113
24224
  ? function(fn) {
24114
24225
  var id = requestAnimationFrame(fn);
24115
24226
  return function() {
@@ -24123,47 +24234,9 @@ function $$RAFProvider() { //rAF
24123
24234
  };
24124
24235
  };
24125
24236
 
24126
- queueFn.supported = rafSupported;
24127
-
24128
- var cancelLastRAF;
24129
- var taskCount = 0;
24130
- var taskQueue = [];
24131
- return queueFn;
24132
-
24133
- function flush() {
24134
- for (var i = 0; i < taskQueue.length; i++) {
24135
- var task = taskQueue[i];
24136
- if (task) {
24137
- taskQueue[i] = null;
24138
- task();
24139
- }
24140
- }
24141
- taskCount = taskQueue.length = 0;
24142
- }
24143
-
24144
- function queueFn(asyncFn) {
24145
- var index = taskQueue.length;
24237
+ raf.supported = rafSupported;
24146
24238
 
24147
- taskCount++;
24148
- taskQueue.push(asyncFn);
24149
-
24150
- if (index === 0) {
24151
- cancelLastRAF = rafFn(flush);
24152
- }
24153
-
24154
- return function cancelQueueFn() {
24155
- if (index >= 0) {
24156
- taskQueue[index] = null;
24157
- index = null;
24158
-
24159
- if (--taskCount === 0 && cancelLastRAF) {
24160
- cancelLastRAF();
24161
- cancelLastRAF = null;
24162
- taskQueue.length = 0;
24163
- }
24164
- }
24165
- };
24166
- }
24239
+ return raf;
24167
24240
  }];
24168
24241
  }
24169
24242
 
@@ -24420,10 +24493,10 @@ function $RootScopeProvider() {
24420
24493
  * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
24421
24494
  *
24422
24495
  * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
24423
- * $digest()} and should return the value that will be watched. (Since
24424
- * {@link ng.$rootScope.Scope#$digest $digest()} reruns when it detects changes the
24425
- * `watchExpression` can execute multiple times per
24426
- * {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
24496
+ * $digest()} and should return the value that will be watched. (`watchExpression` should not change
24497
+ * its value when executed multiple times with the same input because it may be executed multiple
24498
+ * times by {@link ng.$rootScope.Scope#$digest $digest()}. That is, `watchExpression` should be
24499
+ * [idempotent](http://en.wikipedia.org/wiki/Idempotence).
24427
24500
  * - The `listener` is called only when the value from the current `watchExpression` and the
24428
24501
  * previous call to `watchExpression` are not equal (with the exception of the initial run,
24429
24502
  * see below). Inequality is determined according to reference inequality,
@@ -24772,7 +24845,7 @@ function $RootScopeProvider() {
24772
24845
  // copy the items to oldValue and look for changes.
24773
24846
  newLength = 0;
24774
24847
  for (key in newValue) {
24775
- if (newValue.hasOwnProperty(key)) {
24848
+ if (hasOwnProperty.call(newValue, key)) {
24776
24849
  newLength++;
24777
24850
  newItem = newValue[key];
24778
24851
  oldItem = oldValue[key];
@@ -24794,7 +24867,7 @@ function $RootScopeProvider() {
24794
24867
  // we used to have more keys, need to find them and destroy them.
24795
24868
  changeDetected++;
24796
24869
  for (key in oldValue) {
24797
- if (!newValue.hasOwnProperty(key)) {
24870
+ if (!hasOwnProperty.call(newValue, key)) {
24798
24871
  oldLength--;
24799
24872
  delete oldValue[key];
24800
24873
  }
@@ -25879,7 +25952,7 @@ function $SceDelegateProvider() {
25879
25952
  'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
25880
25953
  type, trustedValue);
25881
25954
  }
25882
- if (trustedValue === null || trustedValue === undefined || trustedValue === '') {
25955
+ if (trustedValue === null || isUndefined(trustedValue) || trustedValue === '') {
25883
25956
  return trustedValue;
25884
25957
  }
25885
25958
  // All the current contexts in SCE_CONTEXTS happen to be strings. In order to avoid trusting
@@ -25934,7 +26007,7 @@ function $SceDelegateProvider() {
25934
26007
  * `$sceDelegate.trustAs`} if valid in this context. Otherwise, throws an exception.
25935
26008
  */
25936
26009
  function getTrusted(type, maybeTrusted) {
25937
- if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') {
26010
+ if (maybeTrusted === null || isUndefined(maybeTrusted) || maybeTrusted === '') {
25938
26011
  return maybeTrusted;
25939
26012
  }
25940
26013
  var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
@@ -27195,7 +27268,7 @@ function $$CookieReader($document) {
27195
27268
  // the first value that is seen for a cookie is the most
27196
27269
  // specific one. values for the same cookie name that
27197
27270
  // follow are for less specific paths.
27198
- if (lastCookies[name] === undefined) {
27271
+ if (isUndefined(lastCookies[name])) {
27199
27272
  lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
27200
27273
  }
27201
27274
  }
@@ -27843,6 +27916,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
27843
27916
  if (fractionSize > 0 && number < 1) {
27844
27917
  formatedText = number.toFixed(fractionSize);
27845
27918
  number = parseFloat(formatedText);
27919
+ formatedText = formatedText.replace(DECIMAL_SEP, decimalSep);
27846
27920
  }
27847
27921
  }
27848
27922
 
@@ -29141,6 +29215,7 @@ function nullFormRenameControl(control, name) {
29141
29215
  * @property {boolean} $dirty True if user has already interacted with the form.
29142
29216
  * @property {boolean} $valid True if all of the containing forms and controls are valid.
29143
29217
  * @property {boolean} $invalid True if at least one containing control or form is invalid.
29218
+ * @property {boolean} $pending True if at least one containing control or form is pending.
29144
29219
  * @property {boolean} $submitted True if user has submitted the form even if its invalid.
29145
29220
  *
29146
29221
  * @property {Object} $error Is an object hash, containing references to controls or
@@ -29180,8 +29255,6 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
29180
29255
  var form = this,
29181
29256
  controls = [];
29182
29257
 
29183
- var parentForm = form.$$parentForm = element.parent().controller('form') || nullFormCtrl;
29184
-
29185
29258
  // init state
29186
29259
  form.$error = {};
29187
29260
  form.$$success = {};
@@ -29192,8 +29265,7 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
29192
29265
  form.$valid = true;
29193
29266
  form.$invalid = false;
29194
29267
  form.$submitted = false;
29195
-
29196
- parentForm.$addControl(form);
29268
+ form.$$parentForm = nullFormCtrl;
29197
29269
 
29198
29270
  /**
29199
29271
  * @ngdoc method
@@ -29232,11 +29304,23 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
29232
29304
  /**
29233
29305
  * @ngdoc method
29234
29306
  * @name form.FormController#$addControl
29307
+ * @param {object} control control object, either a {@link form.FormController} or an
29308
+ * {@link ngModel.NgModelController}
29235
29309
  *
29236
29310
  * @description
29237
- * Register a control with the form.
29311
+ * Register a control with the form. Input elements using ngModelController do this automatically
29312
+ * when they are linked.
29238
29313
  *
29239
- * Input elements using ngModelController do this automatically when they are linked.
29314
+ * Note that the current state of the control will not be reflected on the new parent form. This
29315
+ * is not an issue with normal use, as freshly compiled and linked controls are in a `$pristine`
29316
+ * state.
29317
+ *
29318
+ * However, if the method is used programmatically, for example by adding dynamically created controls,
29319
+ * or controls that have been previously removed without destroying their corresponding DOM element,
29320
+ * it's the developers responsiblity to make sure the current state propagates to the parent form.
29321
+ *
29322
+ * For example, if an input control is added that is already `$dirty` and has `$error` properties,
29323
+ * calling `$setDirty()` and `$validate()` afterwards will propagate the state to the parent form.
29240
29324
  */
29241
29325
  form.$addControl = function(control) {
29242
29326
  // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
@@ -29247,6 +29331,8 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
29247
29331
  if (control.$name) {
29248
29332
  form[control.$name] = control;
29249
29333
  }
29334
+
29335
+ control.$$parentForm = form;
29250
29336
  };
29251
29337
 
29252
29338
  // Private API: rename a form control
@@ -29263,11 +29349,18 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
29263
29349
  /**
29264
29350
  * @ngdoc method
29265
29351
  * @name form.FormController#$removeControl
29352
+ * @param {object} control control object, either a {@link form.FormController} or an
29353
+ * {@link ngModel.NgModelController}
29266
29354
  *
29267
29355
  * @description
29268
29356
  * Deregister a control from the form.
29269
29357
  *
29270
29358
  * Input elements using ngModelController do this automatically when they are destroyed.
29359
+ *
29360
+ * Note that only the removed control's validation state (`$errors`etc.) will be removed from the
29361
+ * form. `$dirty`, `$submitted` states will not be changed, because the expected behavior can be
29362
+ * different from case to case. For example, removing the only `$dirty` control from a form may or
29363
+ * may not mean that the form is still `$dirty`.
29271
29364
  */
29272
29365
  form.$removeControl = function(control) {
29273
29366
  if (control.$name && form[control.$name] === control) {
@@ -29284,6 +29377,7 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
29284
29377
  });
29285
29378
 
29286
29379
  arrayRemove(controls, control);
29380
+ control.$$parentForm = nullFormCtrl;
29287
29381
  };
29288
29382
 
29289
29383
 
@@ -29320,7 +29414,6 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
29320
29414
  delete object[property];
29321
29415
  }
29322
29416
  },
29323
- parentForm: parentForm,
29324
29417
  $animate: $animate
29325
29418
  });
29326
29419
 
@@ -29339,7 +29432,7 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
29339
29432
  $animate.addClass(element, DIRTY_CLASS);
29340
29433
  form.$dirty = true;
29341
29434
  form.$pristine = false;
29342
- parentForm.$setDirty();
29435
+ form.$$parentForm.$setDirty();
29343
29436
  };
29344
29437
 
29345
29438
  /**
@@ -29395,7 +29488,7 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
29395
29488
  form.$setSubmitted = function() {
29396
29489
  $animate.addClass(element, SUBMITTED_CLASS);
29397
29490
  form.$submitted = true;
29398
- parentForm.$setSubmitted();
29491
+ form.$$parentForm.$setSubmitted();
29399
29492
  };
29400
29493
  }
29401
29494
 
@@ -29445,6 +29538,7 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
29445
29538
  * # CSS classes
29446
29539
  * - `ng-valid` is set if the form is valid.
29447
29540
  * - `ng-invalid` is set if the form is invalid.
29541
+ * - `ng-pending` is set if the form is pending.
29448
29542
  * - `ng-pristine` is set if the form is pristine.
29449
29543
  * - `ng-dirty` is set if the form is dirty.
29450
29544
  * - `ng-submitted` is set if the form was submitted.
@@ -29520,7 +29614,6 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
29520
29614
  </script>
29521
29615
  <style>
29522
29616
  .my-form {
29523
- -webkit-transition:all linear 0.5s;
29524
29617
  transition:all linear 0.5s;
29525
29618
  background: transparent;
29526
29619
  }
@@ -29569,6 +29662,7 @@ var formDirectiveFactory = function(isNgForm) {
29569
29662
  var formDirective = {
29570
29663
  name: 'form',
29571
29664
  restrict: isNgForm ? 'EAC' : 'E',
29665
+ require: ['form', '^^?form'], //first is the form's own ctrl, second is an optional parent form
29572
29666
  controller: FormController,
29573
29667
  compile: function ngFormCompile(formElement, attr) {
29574
29668
  // Setup initial state of the control
@@ -29577,7 +29671,9 @@ var formDirectiveFactory = function(isNgForm) {
29577
29671
  var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false);
29578
29672
 
29579
29673
  return {
29580
- pre: function ngFormPreLink(scope, formElement, attr, controller) {
29674
+ pre: function ngFormPreLink(scope, formElement, attr, ctrls) {
29675
+ var controller = ctrls[0];
29676
+
29581
29677
  // if `action` attr is not present on the form, prevent the default action (submission)
29582
29678
  if (!('action' in attr)) {
29583
29679
  // we can't use jq events because if a form is destroyed during submission the default
@@ -29606,7 +29702,9 @@ var formDirectiveFactory = function(isNgForm) {
29606
29702
  });
29607
29703
  }
29608
29704
 
29609
- var parentFormCtrl = controller.$$parentForm;
29705
+ var parentFormCtrl = ctrls[1] || controller.$$parentForm;
29706
+ parentFormCtrl.$addControl(controller);
29707
+
29610
29708
  var setter = nameAttr ? getSetter(controller.$name) : noop;
29611
29709
 
29612
29710
  if (nameAttr) {
@@ -29614,13 +29712,13 @@ var formDirectiveFactory = function(isNgForm) {
29614
29712
  attr.$observe(nameAttr, function(newValue) {
29615
29713
  if (controller.$name === newValue) return;
29616
29714
  setter(scope, undefined);
29617
- parentFormCtrl.$$renameControl(controller, newValue);
29715
+ controller.$$parentForm.$$renameControl(controller, newValue);
29618
29716
  setter = getSetter(controller.$name);
29619
29717
  setter(scope, controller);
29620
29718
  });
29621
29719
  }
29622
29720
  formElement.on('$destroy', function() {
29623
- parentFormCtrl.$removeControl(controller);
29721
+ controller.$$parentForm.$removeControl(controller);
29624
29722
  setter(scope, undefined);
29625
29723
  extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
29626
29724
  });
@@ -29782,9 +29880,17 @@ var inputType = {
29782
29880
  * @param {string} ngModel Assignable angular expression to data-bind to.
29783
29881
  * @param {string=} name Property name of the form under which the control is published.
29784
29882
  * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
29785
- * valid ISO date string (yyyy-MM-dd).
29883
+ * valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
29884
+ * (e.g. `min="{{minDate | date:'yyyy-MM-dd'}}"`). Note that `min` will also add native HTML5
29885
+ * constraint validation.
29786
29886
  * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
29787
- * a valid ISO date string (yyyy-MM-dd).
29887
+ * a valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
29888
+ * (e.g. `max="{{maxDate | date:'yyyy-MM-dd'}}"`). Note that `max` will also add native HTML5
29889
+ * constraint validation.
29890
+ * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO date string
29891
+ * the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
29892
+ * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO date string
29893
+ * the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
29788
29894
  * @param {string=} required Sets `required` validation error key if the value is not entered.
29789
29895
  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
29790
29896
  * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
@@ -29876,10 +29982,18 @@ var inputType = {
29876
29982
  *
29877
29983
  * @param {string} ngModel Assignable angular expression to data-bind to.
29878
29984
  * @param {string=} name Property name of the form under which the control is published.
29879
- * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
29880
- * valid ISO datetime format (yyyy-MM-ddTHH:mm:ss).
29881
- * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
29882
- * a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss).
29985
+ * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
29986
+ * This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
29987
+ * inside this attribute (e.g. `min="{{minDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
29988
+ * Note that `min` will also add native HTML5 constraint validation.
29989
+ * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
29990
+ * This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
29991
+ * inside this attribute (e.g. `max="{{maxDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
29992
+ * Note that `max` will also add native HTML5 constraint validation.
29993
+ * @param {(date|string)=} ngMin Sets the `min` validation error key to the Date / ISO datetime string
29994
+ * the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
29995
+ * @param {(date|string)=} ngMax Sets the `max` validation error key to the Date / ISO datetime string
29996
+ * the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
29883
29997
  * @param {string=} required Sets `required` validation error key if the value is not entered.
29884
29998
  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
29885
29999
  * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
@@ -29972,10 +30086,18 @@ var inputType = {
29972
30086
  *
29973
30087
  * @param {string} ngModel Assignable angular expression to data-bind to.
29974
30088
  * @param {string=} name Property name of the form under which the control is published.
29975
- * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
29976
- * valid ISO time format (HH:mm:ss).
29977
- * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be a
29978
- * valid ISO time format (HH:mm:ss).
30089
+ * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
30090
+ * This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
30091
+ * attribute (e.g. `min="{{minTime | date:'HH:mm:ss'}}"`). Note that `min` will also add
30092
+ * native HTML5 constraint validation.
30093
+ * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
30094
+ * This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
30095
+ * attribute (e.g. `max="{{maxTime | date:'HH:mm:ss'}}"`). Note that `max` will also add
30096
+ * native HTML5 constraint validation.
30097
+ * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO time string the
30098
+ * `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
30099
+ * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO time string the
30100
+ * `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
29979
30101
  * @param {string=} required Sets `required` validation error key if the value is not entered.
29980
30102
  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
29981
30103
  * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
@@ -30067,10 +30189,18 @@ var inputType = {
30067
30189
  *
30068
30190
  * @param {string} ngModel Assignable angular expression to data-bind to.
30069
30191
  * @param {string=} name Property name of the form under which the control is published.
30070
- * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
30071
- * valid ISO week format (yyyy-W##).
30072
- * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
30073
- * a valid ISO week format (yyyy-W##).
30192
+ * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
30193
+ * This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
30194
+ * attribute (e.g. `min="{{minWeek | date:'yyyy-Www'}}"`). Note that `min` will also add
30195
+ * native HTML5 constraint validation.
30196
+ * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
30197
+ * This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
30198
+ * attribute (e.g. `max="{{maxWeek | date:'yyyy-Www'}}"`). Note that `max` will also add
30199
+ * native HTML5 constraint validation.
30200
+ * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
30201
+ * the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
30202
+ * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
30203
+ * the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
30074
30204
  * @param {string=} required Sets `required` validation error key if the value is not entered.
30075
30205
  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
30076
30206
  * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
@@ -30164,10 +30294,19 @@ var inputType = {
30164
30294
  *
30165
30295
  * @param {string} ngModel Assignable angular expression to data-bind to.
30166
30296
  * @param {string=} name Property name of the form under which the control is published.
30167
- * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be
30168
- * a valid ISO month format (yyyy-MM).
30169
- * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must
30170
- * be a valid ISO month format (yyyy-MM).
30297
+ * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
30298
+ * This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
30299
+ * attribute (e.g. `min="{{minMonth | date:'yyyy-MM'}}"`). Note that `min` will also add
30300
+ * native HTML5 constraint validation.
30301
+ * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
30302
+ * This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
30303
+ * attribute (e.g. `max="{{maxMonth | date:'yyyy-MM'}}"`). Note that `max` will also add
30304
+ * native HTML5 constraint validation.
30305
+ * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
30306
+ * the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
30307
+ * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
30308
+ * the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
30309
+
30171
30310
  * @param {string=} required Sets `required` validation error key if the value is not entered.
30172
30311
  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
30173
30312
  * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
@@ -30929,7 +31068,7 @@ function createDateInputType(type, regexp, parseDate, format) {
30929
31068
  }
30930
31069
 
30931
31070
  function parseObservedDateValue(val) {
30932
- return isDefined(val) ? (isDate(val) ? val : parseDate(val)) : undefined;
31071
+ return isDefined(val) && !isDate(val) ? parseDate(val) || undefined : val;
30933
31072
  }
30934
31073
  };
30935
31074
  }
@@ -31424,7 +31563,7 @@ var ngBindDirective = ['$compile', function($compile) {
31424
31563
  $compile.$$addBindingInfo(element, attr.ngBind);
31425
31564
  element = element[0];
31426
31565
  scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
31427
- element.textContent = value === undefined ? '' : value;
31566
+ element.textContent = isUndefined(value) ? '' : value;
31428
31567
  });
31429
31568
  };
31430
31569
  }
@@ -31492,7 +31631,7 @@ var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate
31492
31631
  $compile.$$addBindingInfo(element, interpolateFn.expressions);
31493
31632
  element = element[0];
31494
31633
  attr.$observe('ngBindTemplate', function(value) {
31495
- element.textContent = value === undefined ? '' : value;
31634
+ element.textContent = isUndefined(value) ? '' : value;
31496
31635
  });
31497
31636
  };
31498
31637
  }
@@ -31909,7 +32048,6 @@ function classDirective(name, selector) {
31909
32048
  </file>
31910
32049
  <file name="style.css">
31911
32050
  .base-class {
31912
- -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
31913
32051
  transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
31914
32052
  }
31915
32053
 
@@ -33084,7 +33222,6 @@ forEach(
33084
33222
  }
33085
33223
 
33086
33224
  .animate-if.ng-enter, .animate-if.ng-leave {
33087
- -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
33088
33225
  transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
33089
33226
  }
33090
33227
 
@@ -33233,7 +33370,6 @@ var ngIfDirective = ['$animate', function($animate) {
33233
33370
  }
33234
33371
 
33235
33372
  .slide-animate.ng-enter, .slide-animate.ng-leave {
33236
- -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
33237
33373
  transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
33238
33374
 
33239
33375
  position:absolute;
@@ -33452,16 +33588,18 @@ var ngIncludeFillContentDirective = ['$compile',
33452
33588
  * current scope.
33453
33589
  *
33454
33590
  * <div class="alert alert-danger">
33455
- * The only appropriate use of `ngInit` is for aliasing special properties of
33456
- * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
33457
- * should use {@link guide/controller controllers} rather than `ngInit`
33458
- * to initialize values on a scope.
33591
+ * This directive can be abused to add unnecessary amounts of logic into your templates.
33592
+ * There are only a few appropriate uses of `ngInit`, such as for aliasing special properties of
33593
+ * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below; and for injecting data via
33594
+ * server side scripting. Besides these few cases, you should use {@link guide/controller controllers}
33595
+ * rather than `ngInit` to initialize values on a scope.
33459
33596
  * </div>
33597
+ *
33460
33598
  * <div class="alert alert-warning">
33461
- * **Note**: If you have assignment in `ngInit` along with {@link ng.$filter `$filter`}, make
33462
- * sure you have parenthesis for correct precedence:
33599
+ * **Note**: If you have assignment in `ngInit` along with a {@link ng.$filter `filter`}, make
33600
+ * sure you have parentheses to ensure correct operator precedence:
33463
33601
  * <pre class="prettyprint">
33464
- * `<div ng-init="test1 = (data | orderBy:'name')"></div>`
33602
+ * `<div ng-init="test1 = ($index | toString)"></div>`
33465
33603
  * </pre>
33466
33604
  * </div>
33467
33605
  *
@@ -33574,7 +33712,7 @@ var ngInitDirective = ngDirective({
33574
33712
  * </file>
33575
33713
  * </example>
33576
33714
  *
33577
- * ### Example - splitting on whitespace
33715
+ * ### Example - splitting on newline
33578
33716
  * <example name="ngList-directive-newlines">
33579
33717
  * <file name="index.html">
33580
33718
  * <textarea ng-model="list" ng-list="&#10;" ng-trim="false"></textarea>
@@ -33659,7 +33797,9 @@ var ngModelMinErr = minErr('ngModel');
33659
33797
  * @ngdoc type
33660
33798
  * @name ngModel.NgModelController
33661
33799
  *
33662
- * @property {string} $viewValue Actual string value in the view.
33800
+ * @property {*} $viewValue The actual value from the control's view. For `input` elements, this is a
33801
+ * String. See {@link ngModel.NgModelController#$setViewValue} for information about when the $viewValue
33802
+ * is set.
33663
33803
  * @property {*} $modelValue The value in the model that the control is bound to.
33664
33804
  * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
33665
33805
  the control reads value from the DOM. The functions are called in array order, each passing
@@ -33873,7 +34013,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
33873
34013
  this.$$success = {}; // keep valid keys here
33874
34014
  this.$pending = undefined; // keep pending keys here
33875
34015
  this.$name = $interpolate($attr.name || '', false)($scope);
33876
-
34016
+ this.$$parentForm = nullFormCtrl;
33877
34017
 
33878
34018
  var parsedNgModel = $parse($attr.ngModel),
33879
34019
  parsedNgModelAssign = parsedNgModel.assign,
@@ -33953,8 +34093,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
33953
34093
  return isUndefined(value) || value === '' || value === null || value !== value;
33954
34094
  };
33955
34095
 
33956
- var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
33957
- currentValidationRunId = 0;
34096
+ var currentValidationRunId = 0;
33958
34097
 
33959
34098
  /**
33960
34099
  * @ngdoc method
@@ -33987,7 +34126,6 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
33987
34126
  unset: function(object, property) {
33988
34127
  delete object[property];
33989
34128
  },
33990
- parentForm: parentForm,
33991
34129
  $animate: $animate
33992
34130
  });
33993
34131
 
@@ -34025,7 +34163,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
34025
34163
  ctrl.$pristine = false;
34026
34164
  $animate.removeClass($element, PRISTINE_CLASS);
34027
34165
  $animate.addClass($element, DIRTY_CLASS);
34028
- parentForm.$setDirty();
34166
+ ctrl.$$parentForm.$setDirty();
34029
34167
  };
34030
34168
 
34031
34169
  /**
@@ -34195,7 +34333,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
34195
34333
 
34196
34334
  function processParseErrors() {
34197
34335
  var errorKey = ctrl.$$parserName || 'parse';
34198
- if (parserValid === undefined) {
34336
+ if (isUndefined(parserValid)) {
34199
34337
  setValidity(errorKey, null);
34200
34338
  } else {
34201
34339
  if (!parserValid) {
@@ -34365,37 +34503,47 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
34365
34503
  * @description
34366
34504
  * Update the view value.
34367
34505
  *
34368
- * This method should be called when an input directive want to change the view value; typically,
34369
- * this is done from within a DOM event handler.
34370
- *
34371
- * For example {@link ng.directive:input input} calls it when the value of the input changes and
34372
- * {@link ng.directive:select select} calls it when an option is selected.
34373
- *
34374
- * If the new `value` is an object (rather than a string or a number), we should make a copy of the
34375
- * object before passing it to `$setViewValue`. This is because `ngModel` does not perform a deep
34376
- * watch of objects, it only looks for a change of identity. If you only change the property of
34377
- * the object then ngModel will not realise that the object has changed and will not invoke the
34378
- * `$parsers` and `$validators` pipelines.
34379
- *
34380
- * For this reason, you should not change properties of the copy once it has been passed to
34381
- * `$setViewValue`. Otherwise you may cause the model value on the scope to change incorrectly.
34506
+ * This method should be called when a control wants to change the view value; typically,
34507
+ * this is done from within a DOM event handler. For example, the {@link ng.directive:input input}
34508
+ * directive calls it when the value of the input changes and {@link ng.directive:select select}
34509
+ * calls it when an option is selected.
34382
34510
  *
34383
- * When this method is called, the new `value` will be staged for committing through the `$parsers`
34511
+ * When `$setViewValue` is called, the new `value` will be staged for committing through the `$parsers`
34384
34512
  * and `$validators` pipelines. If there are no special {@link ngModelOptions} specified then the staged
34385
34513
  * value sent directly for processing, finally to be applied to `$modelValue` and then the
34386
- * **expression** specified in the `ng-model` attribute.
34387
- *
34388
- * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
34514
+ * **expression** specified in the `ng-model` attribute. Lastly, all the registered change listeners,
34515
+ * in the `$viewChangeListeners` list, are called.
34389
34516
  *
34390
34517
  * In case the {@link ng.directive:ngModelOptions ngModelOptions} directive is used with `updateOn`
34391
34518
  * and the `default` trigger is not listed, all those actions will remain pending until one of the
34392
34519
  * `updateOn` events is triggered on the DOM element.
34393
34520
  * All these actions will be debounced if the {@link ng.directive:ngModelOptions ngModelOptions}
34394
34521
  * directive is used with a custom debounce for this particular event.
34522
+ * Note that a `$digest` is only triggered once the `updateOn` events are fired, or if `debounce`
34523
+ * is specified, once the timer runs out.
34524
+ *
34525
+ * When used with standard inputs, the view value will always be a string (which is in some cases
34526
+ * parsed into another type, such as a `Date` object for `input[date]`.)
34527
+ * However, custom controls might also pass objects to this method. In this case, we should make
34528
+ * a copy of the object before passing it to `$setViewValue`. This is because `ngModel` does not
34529
+ * perform a deep watch of objects, it only looks for a change of identity. If you only change
34530
+ * the property of the object then ngModel will not realise that the object has changed and
34531
+ * will not invoke the `$parsers` and `$validators` pipelines. For this reason, you should
34532
+ * not change properties of the copy once it has been passed to `$setViewValue`.
34533
+ * Otherwise you may cause the model value on the scope to change incorrectly.
34534
+ *
34535
+ * <div class="alert alert-info">
34536
+ * In any case, the value passed to the method should always reflect the current value
34537
+ * of the control. For example, if you are calling `$setViewValue` for an input element,
34538
+ * you should pass the input DOM value. Otherwise, the control and the scope model become
34539
+ * out of sync. It's also important to note that `$setViewValue` does not call `$render` or change
34540
+ * the control's DOM value in any way. If we want to change the control's DOM value
34541
+ * programmatically, we should update the `ngModel` scope expression. Its new value will be
34542
+ * picked up by the model controller, which will run it through the `$formatters`, `$render` it
34543
+ * to update the DOM, and finally call `$validate` on it.
34544
+ * </div>
34395
34545
  *
34396
- * Note that calling this function does not trigger a `$digest`.
34397
- *
34398
- * @param {string} value Value from the view.
34546
+ * @param {*} value value from the view.
34399
34547
  * @param {string} trigger Event that triggered the update.
34400
34548
  */
34401
34549
  this.$setViewValue = function(value, trigger) {
@@ -34572,7 +34720,6 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
34572
34720
  </script>
34573
34721
  <style>
34574
34722
  .my-input {
34575
- -webkit-transition:all linear 0.5s;
34576
34723
  transition:all linear 0.5s;
34577
34724
  background: transparent;
34578
34725
  }
@@ -34659,7 +34806,7 @@ var ngModelDirective = ['$rootScope', function($rootScope) {
34659
34806
  return {
34660
34807
  pre: function ngModelPreLink(scope, element, attr, ctrls) {
34661
34808
  var modelCtrl = ctrls[0],
34662
- formCtrl = ctrls[1] || nullFormCtrl;
34809
+ formCtrl = ctrls[1] || modelCtrl.$$parentForm;
34663
34810
 
34664
34811
  modelCtrl.$$setOptions(ctrls[2] && ctrls[2].$options);
34665
34812
 
@@ -34668,12 +34815,12 @@ var ngModelDirective = ['$rootScope', function($rootScope) {
34668
34815
 
34669
34816
  attr.$observe('name', function(newValue) {
34670
34817
  if (modelCtrl.$name !== newValue) {
34671
- formCtrl.$$renameControl(modelCtrl, newValue);
34818
+ modelCtrl.$$parentForm.$$renameControl(modelCtrl, newValue);
34672
34819
  }
34673
34820
  });
34674
34821
 
34675
34822
  scope.$on('$destroy', function() {
34676
- formCtrl.$removeControl(modelCtrl);
34823
+ modelCtrl.$$parentForm.$removeControl(modelCtrl);
34677
34824
  });
34678
34825
  },
34679
34826
  post: function ngModelPostLink(scope, element, attr, ctrls) {
@@ -34868,7 +35015,7 @@ var ngModelOptionsDirective = function() {
34868
35015
  var that = this;
34869
35016
  this.$options = copy($scope.$eval($attrs.ngModelOptions));
34870
35017
  // Allow adding/overriding bound events
34871
- if (this.$options.updateOn !== undefined) {
35018
+ if (isDefined(this.$options.updateOn)) {
34872
35019
  this.$options.updateOnDefault = false;
34873
35020
  // extract "default" pseudo-event from list of events that can trigger a model update
34874
35021
  this.$options.updateOn = trim(this.$options.updateOn.replace(DEFAULT_REGEXP, function() {
@@ -34891,7 +35038,6 @@ function addSetValidityMethod(context) {
34891
35038
  classCache = {},
34892
35039
  set = context.set,
34893
35040
  unset = context.unset,
34894
- parentForm = context.parentForm,
34895
35041
  $animate = context.$animate;
34896
35042
 
34897
35043
  classCache[INVALID_CLASS] = !(classCache[VALID_CLASS] = $element.hasClass(VALID_CLASS));
@@ -34899,7 +35045,7 @@ function addSetValidityMethod(context) {
34899
35045
  ctrl.$setValidity = setValidity;
34900
35046
 
34901
35047
  function setValidity(validationErrorKey, state, controller) {
34902
- if (state === undefined) {
35048
+ if (isUndefined(state)) {
34903
35049
  createAndSet('$pending', validationErrorKey, controller);
34904
35050
  } else {
34905
35051
  unsetAndCleanup('$pending', validationErrorKey, controller);
@@ -34943,7 +35089,7 @@ function addSetValidityMethod(context) {
34943
35089
  }
34944
35090
 
34945
35091
  toggleValidationCss(validationErrorKey, combinedState);
34946
- parentForm.$setValidity(validationErrorKey, combinedState, ctrl);
35092
+ ctrl.$$parentForm.$setValidity(validationErrorKey, combinedState, ctrl);
34947
35093
  }
34948
35094
 
34949
35095
  function createAndSet(name, value, controller) {
@@ -35604,11 +35750,16 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
35604
35750
  function updateOptionElement(option, element) {
35605
35751
  option.element = element;
35606
35752
  element.disabled = option.disabled;
35607
- if (option.value !== element.value) element.value = option.selectValue;
35753
+ // NOTE: The label must be set before the value, otherwise IE10/11/EDGE create unresponsive
35754
+ // selects in certain circumstances when multiple selects are next to each other and display
35755
+ // the option list in listbox style, i.e. the select is [multiple], or specifies a [size].
35756
+ // See https://github.com/angular/angular.js/issues/11314 for more info.
35757
+ // This is unfortunately untestable with unit / e2e tests
35608
35758
  if (option.label !== element.label) {
35609
35759
  element.label = option.label;
35610
35760
  element.textContent = option.label;
35611
35761
  }
35762
+ if (option.value !== element.value) element.value = option.selectValue;
35612
35763
  }
35613
35764
 
35614
35765
  function addOrReuseElement(parent, current, type, templateElement) {
@@ -35649,7 +35800,10 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
35649
35800
  if (emptyOption_ || unknownOption_) {
35650
35801
  while (current &&
35651
35802
  (current === emptyOption_ ||
35652
- current === unknownOption_)) {
35803
+ current === unknownOption_ ||
35804
+ emptyOption_ && emptyOption_.nodeType === NODE_TYPE_COMMENT)) {
35805
+ // Empty options might have directives that transclude
35806
+ // and insert comments (e.g. ngIf)
35653
35807
  current = current.nextSibling;
35654
35808
  }
35655
35809
  }
@@ -36011,8 +36165,10 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
36011
36165
  * | `$even` | {@type boolean} | true if the iterator position `$index` is even (otherwise false). |
36012
36166
  * | `$odd` | {@type boolean} | true if the iterator position `$index` is odd (otherwise false). |
36013
36167
  *
36014
- * Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
36015
- * This may be useful when, for instance, nesting ngRepeats.
36168
+ * <div class="alert alert-info">
36169
+ * Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
36170
+ * This may be useful when, for instance, nesting ngRepeats.
36171
+ * </div>
36016
36172
  *
36017
36173
  *
36018
36174
  * # Iterating over object properties
@@ -36246,7 +36402,6 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
36246
36402
  .animate-repeat.ng-move,
36247
36403
  .animate-repeat.ng-enter,
36248
36404
  .animate-repeat.ng-leave {
36249
- -webkit-transition:all linear 0.5s;
36250
36405
  transition:all linear 0.5s;
36251
36406
  }
36252
36407
 
@@ -36418,7 +36573,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
36418
36573
  // if object, extract keys, in enumeration order, unsorted
36419
36574
  collectionKeys = [];
36420
36575
  for (var itemKey in collection) {
36421
- if (collection.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
36576
+ if (hasOwnProperty.call(collection, itemKey) && itemKey.charAt(0) !== '$') {
36422
36577
  collectionKeys.push(itemKey);
36423
36578
  }
36424
36579
  }
@@ -36643,9 +36798,7 @@ var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
36643
36798
  background: white;
36644
36799
  }
36645
36800
 
36646
- .animate-show.ng-hide-add.ng-hide-add-active,
36647
- .animate-show.ng-hide-remove.ng-hide-remove-active {
36648
- -webkit-transition: all linear 0.5s;
36801
+ .animate-show.ng-hide-add, .animate-show.ng-hide-remove {
36649
36802
  transition: all linear 0.5s;
36650
36803
  }
36651
36804
 
@@ -36802,7 +36955,6 @@ var ngShowDirective = ['$animate', function($animate) {
36802
36955
  </file>
36803
36956
  <file name="animations.css">
36804
36957
  .animate-hide {
36805
- -webkit-transition: all linear 0.5s;
36806
36958
  transition: all linear 0.5s;
36807
36959
  line-height: 20px;
36808
36960
  opacity: 1;
@@ -37001,7 +37153,6 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
37001
37153
  }
37002
37154
 
37003
37155
  .animate-switch.ng-animate {
37004
- -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
37005
37156
  transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
37006
37157
 
37007
37158
  position:absolute;
@@ -37342,31 +37493,162 @@ var SelectController =
37342
37493
  * @description
37343
37494
  * HTML `SELECT` element with angular data-binding.
37344
37495
  *
37345
- * In many cases, `ngRepeat` can be used on `<option>` elements instead of {@link ng.directive:ngOptions
37346
- * ngOptions} to achieve a similar result. However, `ngOptions` provides some benefits such as reducing
37347
- * memory and increasing speed by not creating a new scope for each repeated instance, as well as providing
37348
- * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
37349
- * comprehension expression.
37496
+ * The `select` directive is used together with {@link ngModel `ngModel`} to provide data-binding
37497
+ * between the scope and the `<select>` control (including setting default values).
37498
+ * Ìt also handles dynamic `<option>` elements, which can be added using the {@link ngRepeat `ngRepeat}` or
37499
+ * {@link ngOptions `ngOptions`} directives.
37350
37500
  *
37351
- * When an item in the `<select>` menu is selected, the array element or object property
37352
- * represented by the selected option will be bound to the model identified by the `ngModel`
37353
- * directive.
37501
+ * When an item in the `<select>` menu is selected, the value of the selected option will be bound
37502
+ * to the model identified by the `ngModel` directive. With static or repeated options, this is
37503
+ * the content of the `value` attribute or the textContent of the `<option>`, if the value attribute is missing.
37504
+ * If you want dynamic value attributes, you can use interpolation inside the value attribute.
37354
37505
  *
37355
- * If the viewValue contains a value that doesn't match any of the options then the control
37356
- * will automatically add an "unknown" option, which it then removes when this is resolved.
37506
+ * <div class="alert alert-warning">
37507
+ * Note that the value of a `select` directive used without `ngOptions` is always a string.
37508
+ * When the model needs to be bound to a non-string value, you must either explictly convert it
37509
+ * using a directive (see example below) or use `ngOptions` to specify the set of options.
37510
+ * This is because an option element can only be bound to string values at present.
37511
+ * </div>
37512
+ *
37513
+ * If the viewValue of `ngModel` does not match any of the options, then the control
37514
+ * will automatically add an "unknown" option, which it then removes when the mismatch is resolved.
37357
37515
  *
37358
37516
  * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
37359
37517
  * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
37360
37518
  * option. See example below for demonstration.
37361
37519
  *
37362
37520
  * <div class="alert alert-info">
37363
- * The value of a `select` directive used without `ngOptions` is always a string.
37364
- * When the model needs to be bound to a non-string value, you must either explictly convert it
37365
- * using a directive (see example below) or use `ngOptions` to specify the set of options.
37366
- * This is because an option element can only be bound to string values at present.
37521
+ * In many cases, `ngRepeat` can be used on `<option>` elements instead of {@link ng.directive:ngOptions
37522
+ * ngOptions} to achieve a similar result. However, `ngOptions` provides some benefits, such as
37523
+ * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
37524
+ * comprehension expression, and additionally in reducing memory and increasing speed by not creating
37525
+ * a new scope for each repeated instance.
37526
+ * </div>
37527
+ *
37528
+ *
37529
+ * @param {string} ngModel Assignable angular expression to data-bind to.
37530
+ * @param {string=} name Property name of the form under which the control is published.
37531
+ * @param {string=} required Sets `required` validation error key if the value is not entered.
37532
+ * @param {string=} ngRequired Adds required attribute and required validation constraint to
37533
+ * the element when the ngRequired expression evaluates to true. Use ngRequired instead of required
37534
+ * when you want to data-bind to the required attribute.
37535
+ * @param {string=} ngChange Angular expression to be executed when selected option(s) changes due to user
37536
+ * interaction with the select element.
37537
+ * @param {string=} ngOptions sets the options that the select is populated with and defines what is
37538
+ * set on the model on selection. See {@link ngOptions `ngOptions`}.
37539
+ *
37540
+ * @example
37541
+ * ### Simple `select` elements with static options
37542
+ *
37543
+ * <example name="static-select" module="staticSelect">
37544
+ * <file name="index.html">
37545
+ * <div ng-controller="ExampleController">
37546
+ * <form name="myForm">
37547
+ * <label for="singleSelect"> Single select: </label><br>
37548
+ * <select name="singleSelect" ng-model="data.singleSelect">
37549
+ * <option value="option-1">Option 1</option>
37550
+ * <option value="option-2">Option 2</option>
37551
+ * </select><br>
37552
+ *
37553
+ * <label for="singleSelect"> Single select with "not selected" option and dynamic option values: </label><br>
37554
+ * <select name="singleSelect" id="singleSelect" ng-model="data.singleSelect">
37555
+ * <option value="">---Please select---</option> <!-- not selected / blank option -->
37556
+ * <option value="{{data.option1}}">Option 1</option> <!-- interpolation -->
37557
+ * <option value="option-2">Option 2</option>
37558
+ * </select><br>
37559
+ * <button ng-click="forceUnknownOption()">Force unknown option</button><br>
37560
+ * <tt>singleSelect = {{data.singleSelect}}</tt>
37561
+ *
37562
+ * <hr>
37563
+ * <label for="multipleSelect"> Multiple select: </label><br>
37564
+ * <select name="multipleSelect" id="multipleSelect" ng-model="data.multipleSelect" multiple>
37565
+ * <option value="option-1">Option 1</option>
37566
+ * <option value="option-2">Option 2</option>
37567
+ * <option value="option-3">Option 3</option>
37568
+ * </select><br>
37569
+ * <tt>multipleSelect = {{data.multipleSelect}}</tt><br/>
37570
+ * </form>
37571
+ * </div>
37572
+ * </file>
37573
+ * <file name="app.js">
37574
+ * angular.module('staticSelect', [])
37575
+ * .controller('ExampleController', ['$scope', function($scope) {
37576
+ * $scope.data = {
37577
+ * singleSelect: null,
37578
+ * multipleSelect: [],
37579
+ * option1: 'option-1',
37580
+ * };
37581
+ *
37582
+ * $scope.forceUnknownOption = function() {
37583
+ * $scope.data.singleSelect = 'nonsense';
37584
+ * };
37585
+ * }]);
37586
+ * </file>
37587
+ *</example>
37588
+ *
37589
+ * ### Using `ngRepeat` to generate `select` options
37590
+ * <example name="ngrepeat-select" module="ngrepeatSelect">
37591
+ * <file name="index.html">
37592
+ * <div ng-controller="ExampleController">
37593
+ * <form name="myForm">
37594
+ * <label for="repeatSelect"> Repeat select: </label>
37595
+ * <select name="repeatSelect" id="repeatSelect" ng-model="data.repeatSelect">
37596
+ * <option ng-repeat="option in data.availableOptions" value="{{option.id}}">{{option.name}}</option>
37597
+ * </select>
37598
+ * </form>
37599
+ * <hr>
37600
+ * <tt>repeatSelect = {{data.repeatSelect}}</tt><br/>
37367
37601
  * </div>
37602
+ * </file>
37603
+ * <file name="app.js">
37604
+ * angular.module('ngrepeatSelect', [])
37605
+ * .controller('ExampleController', ['$scope', function($scope) {
37606
+ * $scope.data = {
37607
+ * repeatSelect: null,
37608
+ * availableOptions: [
37609
+ * {id: '1', name: 'Option A'},
37610
+ * {id: '2', name: 'Option B'},
37611
+ * {id: '3', name: 'Option C'}
37612
+ * ],
37613
+ * };
37614
+ * }]);
37615
+ * </file>
37616
+ *</example>
37368
37617
  *
37369
- * ### Example (binding `select` to a non-string value)
37618
+ *
37619
+ * ### Using `select` with `ngOptions` and setting a default value
37620
+ * See the {@link ngOptions ngOptions documentation} for more `ngOptions` usage examples.
37621
+ *
37622
+ * <example name="select-with-default-values" module="defaultValueSelect">
37623
+ * <file name="index.html">
37624
+ * <div ng-controller="ExampleController">
37625
+ * <form name="myForm">
37626
+ * <label for="mySelect">Make a choice:</label>
37627
+ * <select name="mySelect" id="mySelect"
37628
+ * ng-options="option.name for option in data.availableOptions track by option.id"
37629
+ * ng-model="data.selectedOption"></select>
37630
+ * </form>
37631
+ * <hr>
37632
+ * <tt>option = {{data.selectedOption}}</tt><br/>
37633
+ * </div>
37634
+ * </file>
37635
+ * <file name="app.js">
37636
+ * angular.module('defaultValueSelect', [])
37637
+ * .controller('ExampleController', ['$scope', function($scope) {
37638
+ * $scope.data = {
37639
+ * availableOptions: [
37640
+ * {id: '1', name: 'Option A'},
37641
+ * {id: '2', name: 'Option B'},
37642
+ * {id: '3', name: 'Option C'}
37643
+ * ],
37644
+ * selectedOption: {id: '3', name: 'Option C'} //This sets the default value of the select in the ui
37645
+ * };
37646
+ * }]);
37647
+ * </file>
37648
+ *</example>
37649
+ *
37650
+ *
37651
+ * ### Binding `select` to a non-string value via `ngModel` parsing / formatting
37370
37652
  *
37371
37653
  * <example name="select-with-non-string-options" module="nonStringSelect">
37372
37654
  * <file name="index.html">
@@ -37504,9 +37786,12 @@ var optionDirective = ['$interpolate', function($interpolate) {
37504
37786
  priority: 100,
37505
37787
  compile: function(element, attr) {
37506
37788
 
37507
- // If the value attribute is not defined then we fall back to the
37508
- // text content of the option element, which may be interpolated
37509
- if (isUndefined(attr.value)) {
37789
+ if (isDefined(attr.value)) {
37790
+ // If the value attribute is defined, check if it contains an interpolation
37791
+ var valueInterpolated = $interpolate(attr.value, true);
37792
+ } else {
37793
+ // If the value attribute is not defined then we fall back to the
37794
+ // text content of the option element, which may be interpolated
37510
37795
  var interpolateFn = $interpolate(element.text(), true);
37511
37796
  if (!interpolateFn) {
37512
37797
  attr.$set('value', element.text());
@@ -37522,24 +37807,38 @@ var optionDirective = ['$interpolate', function($interpolate) {
37522
37807
  selectCtrl = parent.data(selectCtrlName) ||
37523
37808
  parent.parent().data(selectCtrlName); // in case we are in optgroup
37524
37809
 
37810
+ function addOption(optionValue) {
37811
+ selectCtrl.addOption(optionValue, element);
37812
+ selectCtrl.ngModelCtrl.$render();
37813
+ chromeHack(element);
37814
+ }
37815
+
37525
37816
  // Only update trigger option updates if this is an option within a `select`
37526
37817
  // that also has `ngModel` attached
37527
37818
  if (selectCtrl && selectCtrl.ngModelCtrl) {
37528
37819
 
37529
- if (interpolateFn) {
37820
+ if (valueInterpolated) {
37821
+ // The value attribute is interpolated
37822
+ var oldVal;
37823
+ attr.$observe('value', function valueAttributeObserveAction(newVal) {
37824
+ if (isDefined(oldVal)) {
37825
+ selectCtrl.removeOption(oldVal);
37826
+ }
37827
+ oldVal = newVal;
37828
+ addOption(newVal);
37829
+ });
37830
+ } else if (interpolateFn) {
37831
+ // The text content is interpolated
37530
37832
  scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
37531
37833
  attr.$set('value', newVal);
37532
37834
  if (oldVal !== newVal) {
37533
37835
  selectCtrl.removeOption(oldVal);
37534
37836
  }
37535
- selectCtrl.addOption(newVal, element);
37536
- selectCtrl.ngModelCtrl.$render();
37537
- chromeHack(element);
37837
+ addOption(newVal);
37538
37838
  });
37539
37839
  } else {
37540
- selectCtrl.addOption(attr.value, element);
37541
- selectCtrl.ngModelCtrl.$render();
37542
- chromeHack(element);
37840
+ // The value attribute is static
37841
+ addOption(attr.value);
37543
37842
  }
37544
37843
 
37545
37844
  element.on('$destroy', function() {
@@ -37600,8 +37899,9 @@ var patternDirective = function() {
37600
37899
  ctrl.$validate();
37601
37900
  });
37602
37901
 
37603
- ctrl.$validators.pattern = function(value) {
37604
- return ctrl.$isEmpty(value) || isUndefined(regexp) || regexp.test(value);
37902
+ ctrl.$validators.pattern = function(modelValue, viewValue) {
37903
+ // HTML5 pattern constraint validates the input value, so we validate the viewValue
37904
+ return ctrl.$isEmpty(viewValue) || isUndefined(regexp) || regexp.test(viewValue);
37605
37905
  };
37606
37906
  }
37607
37907
  };
@@ -38079,7 +38379,7 @@ _jQuery.fn.bindings = function(windowJquery, bindExp) {
38079
38379
  }
38080
38380
 
38081
38381
  function push(value) {
38082
- if (value === undefined) {
38382
+ if (angular.isUndefined(value)) {
38083
38383
  value = '';
38084
38384
  } else if (typeof value !== 'string') {
38085
38385
  value = angular.toJson(value);