angularjs-rails 1.0.2 → 1.0.3

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.0.2
2
+ * @license AngularJS v1.0.3
3
3
  * (c) 2010-2012 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -794,7 +794,7 @@ function toKeyValue(obj) {
794
794
 
795
795
 
796
796
  /**
797
- * We need our custom mehtod because encodeURIComponent is too agressive and doesn't follow
797
+ * We need our custom method because encodeURIComponent is too agressive and doesn't follow
798
798
  * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
799
799
  * segments:
800
800
  * segment = *pchar
@@ -838,7 +838,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
838
838
  * @name ng.directive:ngApp
839
839
  *
840
840
  * @element ANY
841
- * @param {angular.Module} ngApp on optional application
841
+ * @param {angular.Module} ngApp an optional application
842
842
  * {@link angular.module module} name to load.
843
843
  *
844
844
  * @description
@@ -1015,7 +1015,7 @@ function setupModuleLoader(window) {
1015
1015
  *
1016
1016
  * # Module
1017
1017
  *
1018
- * A module is a collocation of services, directives, filters, and configure information. Module
1018
+ * A module is a collocation of services, directives, filters, and configuration information. Module
1019
1019
  * is used to configure the {@link AUTO.$injector $injector}.
1020
1020
  *
1021
1021
  * <pre>
@@ -1045,7 +1045,7 @@ function setupModuleLoader(window) {
1045
1045
  * @param {!string} name The name of the module to create or retrieve.
1046
1046
  * @param {Array.<string>=} requires If specified then new module is being created. If unspecified then the
1047
1047
  * the module is being retrieved for further configuration.
1048
- * @param {Function} configFn Option configuration function for the module. Same as
1048
+ * @param {Function} configFn Optional configuration function for the module. Same as
1049
1049
  * {@link angular.Module#config Module#config()}.
1050
1050
  * @returns {module} new module with the {@link angular.Module} api.
1051
1051
  */
@@ -1200,8 +1200,8 @@ function setupModuleLoader(window) {
1200
1200
  * @param {Function} initializationFn Execute this function after injector creation.
1201
1201
  * Useful for application initialization.
1202
1202
  * @description
1203
- * Use this method to register work which needs to be performed when the injector with
1204
- * with the current module is finished loading.
1203
+ * Use this method to register work which should be performed when the injector is done
1204
+ * loading all modules.
1205
1205
  */
1206
1206
  run: function(block) {
1207
1207
  runBlocks.push(block);
@@ -1247,11 +1247,11 @@ function setupModuleLoader(window) {
1247
1247
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
1248
1248
  */
1249
1249
  var version = {
1250
- full: '1.0.2', // all of these placeholder strings will be replaced by rake's
1250
+ full: '1.0.3', // all of these placeholder strings will be replaced by rake's
1251
1251
  major: 1, // compile task
1252
1252
  minor: 0,
1253
- dot: 2,
1254
- codeName: 'debilitating-awesomeness'
1253
+ dot: 3,
1254
+ codeName: 'bouncy-thunder'
1255
1255
  };
1256
1256
 
1257
1257
 
@@ -1418,6 +1418,7 @@ function publishExternalAPI(angular){
1418
1418
  * - [replaceWith()](http://api.jquery.com/replaceWith/)
1419
1419
  * - [text()](http://api.jquery.com/text/)
1420
1420
  * - [toggleClass()](http://api.jquery.com/toggleClass/)
1421
+ * - [triggerHandler()](http://api.jquery.com/triggerHandler/) - Doesn't pass native event objects to handlers.
1421
1422
  * - [unbind()](http://api.jquery.com/unbind/)
1422
1423
  * - [val()](http://api.jquery.com/val/)
1423
1424
  * - [wrap()](http://api.jquery.com/wrap/)
@@ -1493,12 +1494,7 @@ function JQLitePatchJQueryRemove(name, dispatchThis) {
1493
1494
  for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
1494
1495
  element = jqLite(set[setIndex]);
1495
1496
  if (fireEvent) {
1496
- events = element.data('events');
1497
- if ( (fns = events && events.$destroy) ) {
1498
- forEach(fns, function(fn){
1499
- fn.handler();
1500
- });
1501
- }
1497
+ element.triggerHandler('$destroy');
1502
1498
  } else {
1503
1499
  fireEvent = !fireEvent;
1504
1500
  }
@@ -1630,9 +1626,9 @@ function JQLiteHasClass(element, selector) {
1630
1626
  indexOf( " " + selector + " " ) > -1);
1631
1627
  }
1632
1628
 
1633
- function JQLiteRemoveClass(element, selector) {
1634
- if (selector) {
1635
- forEach(selector.split(' '), function(cssClass) {
1629
+ function JQLiteRemoveClass(element, cssClasses) {
1630
+ if (cssClasses) {
1631
+ forEach(cssClasses.split(' '), function(cssClass) {
1636
1632
  element.className = trim(
1637
1633
  (" " + element.className + " ")
1638
1634
  .replace(/[\n\t]/g, " ")
@@ -1642,9 +1638,9 @@ function JQLiteRemoveClass(element, selector) {
1642
1638
  }
1643
1639
  }
1644
1640
 
1645
- function JQLiteAddClass(element, selector) {
1646
- if (selector) {
1647
- forEach(selector.split(' '), function(cssClass) {
1641
+ function JQLiteAddClass(element, cssClasses) {
1642
+ if (cssClasses) {
1643
+ forEach(cssClasses.split(' '), function(cssClass) {
1648
1644
  if (!JQLiteHasClass(element, cssClass)) {
1649
1645
  element.className = trim(element.className + ' ' + trim(cssClass));
1650
1646
  }
@@ -2092,7 +2088,15 @@ forEach({
2092
2088
  return element.getElementsByTagName(selector);
2093
2089
  },
2094
2090
 
2095
- clone: JQLiteClone
2091
+ clone: JQLiteClone,
2092
+
2093
+ triggerHandler: function(element, eventName) {
2094
+ var eventFns = (JQLiteExpandoStore(element, 'events') || {})[eventName];
2095
+
2096
+ forEach(eventFns, function(fn) {
2097
+ fn.call(element, null);
2098
+ });
2099
+ }
2096
2100
  }, function(fn, name){
2097
2101
  /**
2098
2102
  * chaining functions
@@ -2210,6 +2214,16 @@ HashQueueMap.prototype = {
2210
2214
  return array.shift();
2211
2215
  }
2212
2216
  }
2217
+ },
2218
+
2219
+ /**
2220
+ * return the first item without deleting it
2221
+ */
2222
+ peek: function(key) {
2223
+ var array = this[hashKey(key)];
2224
+ if (array) {
2225
+ return array[0];
2226
+ }
2213
2227
  }
2214
2228
  };
2215
2229
 
@@ -2233,7 +2247,7 @@ HashQueueMap.prototype = {
2233
2247
  * // create an injector
2234
2248
  * var $injector = angular.injector(['ng']);
2235
2249
  *
2236
- * // use the injector to kick of your application
2250
+ * // use the injector to kick off your application
2237
2251
  * // use the type inference to auto inject arguments, or use implicit injection
2238
2252
  * $injector.invoke(function($rootScope, $compile, $document){
2239
2253
  * $compile($document)($rootScope);
@@ -2253,7 +2267,7 @@ HashQueueMap.prototype = {
2253
2267
 
2254
2268
  var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
2255
2269
  var FN_ARG_SPLIT = /,/;
2256
- var FN_ARG = /^\s*(_?)(.+?)\1\s*$/;
2270
+ var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
2257
2271
  var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
2258
2272
  function annotate(fn) {
2259
2273
  var $inject,
@@ -2872,9 +2886,10 @@ function $AnchorScrollProvider() {
2872
2886
  // does not scroll when user clicks on anchor link that is currently on
2873
2887
  // (no url change, no $locaiton.hash() change), browser native does scroll
2874
2888
  if (autoScrollingEnabled) {
2875
- $rootScope.$watch(function() {return $location.hash();}, function() {
2876
- $rootScope.$evalAsync(scroll);
2877
- });
2889
+ $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
2890
+ function autoScrollWatchAction() {
2891
+ $rootScope.$evalAsync(scroll);
2892
+ });
2878
2893
  }
2879
2894
 
2880
2895
  return scroll;
@@ -3258,10 +3273,10 @@ function $BrowserProvider(){
3258
3273
  *
3259
3274
  * - `{object}` `info()` — Returns id, size, and options of cache.
3260
3275
  * - `{void}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache.
3261
- * - `{{*}} `get({string} key) — Returns cached value for `key` or undefined for cache miss.
3262
- * - `{void}` `remove({string} key) — Removes a key-value pair from the cache.
3263
- * - `{void}` `removeAll() — Removes all cached values.
3264
- * - `{void}` `destroy() — Removes references to this cache from $cacheFactory.
3276
+ * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
3277
+ * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
3278
+ * - `{void}` `removeAll()` — Removes all cached values.
3279
+ * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
3265
3280
  *
3266
3281
  */
3267
3282
  function $CacheFactoryProvider() {
@@ -3313,6 +3328,8 @@ function $CacheFactoryProvider() {
3313
3328
  remove: function(key) {
3314
3329
  var lruEntry = lruHash[key];
3315
3330
 
3331
+ if (!lruEntry) return;
3332
+
3316
3333
  if (lruEntry == freshEnd) freshEnd = lruEntry.p;
3317
3334
  if (lruEntry == staleEnd) staleEnd = lruEntry.n;
3318
3335
  link(lruEntry.n,lruEntry.p);
@@ -3720,26 +3737,26 @@ function $CompileProvider($provide) {
3720
3737
 
3721
3738
  //================================
3722
3739
 
3723
- function compile($compileNode, transcludeFn, maxPriority) {
3724
- if (!($compileNode instanceof jqLite)) {
3740
+ function compile($compileNodes, transcludeFn, maxPriority) {
3741
+ if (!($compileNodes instanceof jqLite)) {
3725
3742
  // jquery always rewraps, where as we need to preserve the original selector so that we can modify it.
3726
- $compileNode = jqLite($compileNode);
3743
+ $compileNodes = jqLite($compileNodes);
3727
3744
  }
3728
3745
  // We can not compile top level text elements since text nodes can be merged and we will
3729
3746
  // not be able to attach scope data to them, so we will wrap them in <span>
3730
- forEach($compileNode, function(node, index){
3747
+ forEach($compileNodes, function(node, index){
3731
3748
  if (node.nodeType == 3 /* text node */) {
3732
- $compileNode[index] = jqLite(node).wrap('<span></span>').parent()[0];
3749
+ $compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
3733
3750
  }
3734
3751
  });
3735
- var compositeLinkFn = compileNodes($compileNode, transcludeFn, $compileNode, maxPriority);
3736
- return function(scope, cloneConnectFn){
3752
+ var compositeLinkFn = compileNodes($compileNodes, transcludeFn, $compileNodes, maxPriority);
3753
+ return function publicLinkFn(scope, cloneConnectFn){
3737
3754
  assertArg(scope, 'scope');
3738
3755
  // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
3739
3756
  // and sometimes changes the structure of the DOM.
3740
3757
  var $linkNode = cloneConnectFn
3741
- ? JQLitePrototype.clone.call($compileNode) // IMPORTANT!!!
3742
- : $compileNode;
3758
+ ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
3759
+ : $compileNodes;
3743
3760
  $linkNode.data('$scope', scope);
3744
3761
  safeAddClass($linkNode, 'ng-scope');
3745
3762
  if (cloneConnectFn) cloneConnectFn($linkNode, scope);
@@ -3790,7 +3807,7 @@ function $CompileProvider($provide) {
3790
3807
  ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement)
3791
3808
  : null;
3792
3809
 
3793
- childLinkFn = (nodeLinkFn && nodeLinkFn.terminal)
3810
+ childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes.length)
3794
3811
  ? null
3795
3812
  : compileNodes(nodeList[i].childNodes,
3796
3813
  nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
@@ -3842,13 +3859,14 @@ function $CompileProvider($provide) {
3842
3859
 
3843
3860
 
3844
3861
  /**
3845
- * Looks for directives on the given node ands them to the directive collection which is sorted.
3862
+ * Looks for directives on the given node and adds them to the directive collection which is
3863
+ * sorted.
3846
3864
  *
3847
- * @param node node to search
3848
- * @param directives an array to which the directives are added to. This array is sorted before
3865
+ * @param node Node to search.
3866
+ * @param directives An array to which the directives are added to. This array is sorted before
3849
3867
  * the function returns.
3850
- * @param attrs the shared attrs object which is used to populate the normalized attributes.
3851
- * @param {number=} max directive priority
3868
+ * @param attrs The shared attrs object which is used to populate the normalized attributes.
3869
+ * @param {number=} maxPriority Max directive priority.
3852
3870
  */
3853
3871
  function collectDirectives(node, directives, attrs, maxPriority) {
3854
3872
  var nodeType = node.nodeType,
@@ -3883,7 +3901,7 @@ function $CompileProvider($provide) {
3883
3901
 
3884
3902
  // use class as directive
3885
3903
  className = node.className;
3886
- if (isString(className)) {
3904
+ if (isString(className) && className !== '') {
3887
3905
  while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
3888
3906
  nName = directiveNormalize(match[2]);
3889
3907
  if (addDirective(directives, nName, 'C', maxPriority)) {
@@ -3937,7 +3955,7 @@ function $CompileProvider($provide) {
3937
3955
  preLinkFns = [],
3938
3956
  postLinkFns = [],
3939
3957
  newScopeDirective = null,
3940
- newIsolatedScopeDirective = null,
3958
+ newIsolateScopeDirective = null,
3941
3959
  templateDirective = null,
3942
3960
  $compileNode = templateAttrs.$$element = jqLite(compileNode),
3943
3961
  directive,
@@ -3959,10 +3977,10 @@ function $CompileProvider($provide) {
3959
3977
  }
3960
3978
 
3961
3979
  if (directiveValue = directive.scope) {
3962
- assertNoDuplicate('isolated scope', newIsolatedScopeDirective, directive, $compileNode);
3980
+ assertNoDuplicate('isolated scope', newIsolateScopeDirective, directive, $compileNode);
3963
3981
  if (isObject(directiveValue)) {
3964
3982
  safeAddClass($compileNode, 'ng-isolate-scope');
3965
- newIsolatedScopeDirective = directive;
3983
+ newIsolateScopeDirective = directive;
3966
3984
  }
3967
3985
  safeAddClass($compileNode, 'ng-scope');
3968
3986
  newScopeDirective = newScopeDirective || directive;
@@ -4116,12 +4134,12 @@ function $CompileProvider($provide) {
4116
4134
  }
4117
4135
  $element = attrs.$$element;
4118
4136
 
4119
- if (newScopeDirective && isObject(newScopeDirective.scope)) {
4137
+ if (newIsolateScopeDirective) {
4120
4138
  var LOCAL_REGEXP = /^\s*([@=&])\s*(\w*)\s*$/;
4121
4139
 
4122
4140
  var parentScope = scope.$parent || scope;
4123
4141
 
4124
- forEach(newScopeDirective.scope, function(definiton, scopeName) {
4142
+ forEach(newIsolateScopeDirective.scope, function(definiton, scopeName) {
4125
4143
  var match = definiton.match(LOCAL_REGEXP) || [],
4126
4144
  attrName = match[2]|| scopeName,
4127
4145
  mode = match[1], // @, =, or &
@@ -4144,10 +4162,10 @@ function $CompileProvider($provide) {
4144
4162
  // reset the change, or we will throw this exception on every $digest
4145
4163
  lastValue = scope[scopeName] = parentGet(parentScope);
4146
4164
  throw Error(NON_ASSIGNABLE_MODEL_EXPRESSION + attrs[attrName] +
4147
- ' (directive: ' + newScopeDirective.name + ')');
4165
+ ' (directive: ' + newIsolateScopeDirective.name + ')');
4148
4166
  };
4149
4167
  lastValue = scope[scopeName] = parentGet(parentScope);
4150
- scope.$watch(function() {
4168
+ scope.$watch(function parentValueWatch() {
4151
4169
  var parentValue = parentGet(parentScope);
4152
4170
 
4153
4171
  if (parentValue !== scope[scopeName]) {
@@ -4157,7 +4175,7 @@ function $CompileProvider($provide) {
4157
4175
  lastValue = scope[scopeName] = parentValue;
4158
4176
  } else {
4159
4177
  // if the parent can be assigned then do so
4160
- parentSet(parentScope, lastValue = scope[scopeName]);
4178
+ parentSet(parentScope, parentValue = lastValue = scope[scopeName]);
4161
4179
  }
4162
4180
  }
4163
4181
  return parentValue;
@@ -4175,7 +4193,7 @@ function $CompileProvider($provide) {
4175
4193
 
4176
4194
  default: {
4177
4195
  throw Error('Invalid isolate scope definition for directive ' +
4178
- newScopeDirective.name + ': ' + definiton);
4196
+ newIsolateScopeDirective.name + ': ' + definiton);
4179
4197
  }
4180
4198
  }
4181
4199
  });
@@ -4309,7 +4327,7 @@ function $CompileProvider($provide) {
4309
4327
  origAsyncDirective = directives.shift(),
4310
4328
  // The fact that we have to copy and patch the directive seems wrong!
4311
4329
  derivedSyncDirective = extend({}, origAsyncDirective, {
4312
- controller: null, templateUrl: null, transclude: null
4330
+ controller: null, templateUrl: null, transclude: null, scope: null
4313
4331
  });
4314
4332
 
4315
4333
  $compileNode.html('');
@@ -4401,12 +4419,12 @@ function $CompileProvider($provide) {
4401
4419
  if (interpolateFn) {
4402
4420
  directives.push({
4403
4421
  priority: 0,
4404
- compile: valueFn(function(scope, node) {
4422
+ compile: valueFn(function textInterpolateLinkFn(scope, node) {
4405
4423
  var parent = node.parent(),
4406
4424
  bindings = parent.data('$binding') || [];
4407
4425
  bindings.push(interpolateFn);
4408
4426
  safeAddClass(parent.data('$binding', bindings), 'ng-binding');
4409
- scope.$watch(interpolateFn, function(value) {
4427
+ scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
4410
4428
  node[0].nodeValue = value;
4411
4429
  });
4412
4430
  })
@@ -4424,7 +4442,7 @@ function $CompileProvider($provide) {
4424
4442
 
4425
4443
  directives.push({
4426
4444
  priority: 100,
4427
- compile: valueFn(function(scope, element, attr) {
4445
+ compile: valueFn(function attrInterpolateLinkFn(scope, element, attr) {
4428
4446
  var $$observers = (attr.$$observers || (attr.$$observers = {}));
4429
4447
 
4430
4448
  if (name === 'class') {
@@ -4436,7 +4454,7 @@ function $CompileProvider($provide) {
4436
4454
  attr[name] = undefined;
4437
4455
  ($$observers[name] || ($$observers[name] = [])).$$inter = true;
4438
4456
  (attr.$$observers && attr.$$observers[name].$$scope || scope).
4439
- $watch(interpolateFn, function(value) {
4457
+ $watch(interpolateFn, function interpolateFnWatchAction(value) {
4440
4458
  attr.$set(name, value);
4441
4459
  });
4442
4460
  })
@@ -5434,6 +5452,7 @@ function $LocationProvider(){
5434
5452
  var changeCounter = 0;
5435
5453
  $rootScope.$watch(function $locationWatch() {
5436
5454
  var oldUrl = $browser.url();
5455
+ var currentReplace = $location.$$replace;
5437
5456
 
5438
5457
  if (!changeCounter || oldUrl != $location.absUrl()) {
5439
5458
  changeCounter++;
@@ -5442,12 +5461,12 @@ function $LocationProvider(){
5442
5461
  defaultPrevented) {
5443
5462
  $location.$$parse(oldUrl);
5444
5463
  } else {
5445
- $browser.url($location.absUrl(), $location.$$replace);
5446
- $location.$$replace = false;
5464
+ $browser.url($location.absUrl(), currentReplace);
5447
5465
  afterLocationChange(oldUrl);
5448
5466
  }
5449
5467
  });
5450
5468
  }
5469
+ $location.$$replace = false;
5451
5470
 
5452
5471
  return changeCounter;
5453
5472
  });
@@ -5578,7 +5597,15 @@ var OPERATORS = {
5578
5597
  'true':function(){return true;},
5579
5598
  'false':function(){return false;},
5580
5599
  undefined:noop,
5581
- '+':function(self, locals, a,b){a=a(self, locals); b=b(self, locals); return (isDefined(a)?a:0)+(isDefined(b)?b:0);},
5600
+ '+':function(self, locals, a,b){
5601
+ a=a(self, locals); b=b(self, locals);
5602
+ if (isDefined(a)) {
5603
+ if (isDefined(b)) {
5604
+ return a + b;
5605
+ }
5606
+ return a;
5607
+ }
5608
+ return isDefined(b)?b:undefined;},
5582
5609
  '-':function(self, locals, a,b){a=a(self, locals); b=b(self, locals); return (isDefined(a)?a:0)-(isDefined(b)?b:0);},
5583
5610
  '*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
5584
5611
  '/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
@@ -6473,7 +6500,7 @@ function $ParseProvider() {
6473
6500
  * alert('Success: ' + greeting);
6474
6501
  * }, function(reason) {
6475
6502
  * alert('Failed: ' + reason);
6476
- * );
6503
+ * });
6477
6504
  * </pre>
6478
6505
  *
6479
6506
  * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
@@ -6848,7 +6875,7 @@ function $RouteProvider(){
6848
6875
  * Object properties:
6849
6876
  *
6850
6877
  * - `controller` – `{(string|function()=}` – Controller fn that should be associated with newly
6851
- * created scope or the name of a {@link angular.Module#controller registered controller}
6878
+ * created scope or the name of a {@link angular.Module#controller registered controller}
6852
6879
  * if passed as a string.
6853
6880
  * - `template` – `{string=}` – html template as a string that should be used by
6854
6881
  * {@link ng.directive:ngView ngView} or
@@ -6859,7 +6886,7 @@ function $RouteProvider(){
6859
6886
  * - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
6860
6887
  * be injected into the controller. If any of these dependencies are promises, they will be
6861
6888
  * resolved and converted to a value before the controller is instantiated and the
6862
- * `$afterRouteChange` event is fired. The map object is:
6889
+ * `$routeChangeSuccess` event is fired. The map object is:
6863
6890
  *
6864
6891
  * - `key` – `{string}`: a name of a dependency to be injected into the controller.
6865
6892
  * - `factory` - `{string|function}`: If `string` then it is an alias for a service.
@@ -7193,7 +7220,7 @@ function $RouteProvider(){
7193
7220
 
7194
7221
  forEach(next.resolve || {}, function(value, key) {
7195
7222
  keys.push(key);
7196
- values.push(isFunction(value) ? $injector.invoke(value) : $injector.get(value));
7223
+ values.push(isString(value) ? $injector.get(value) : $injector.invoke(value));
7197
7224
  });
7198
7225
  if (isDefined(template = next.template)) {
7199
7226
  } else if (isDefined(template = next.templateUrl)) {
@@ -7464,9 +7491,9 @@ function $RootScopeProvider(){
7464
7491
  * the scope and its child scopes to be permanently detached from the parent and thus stop
7465
7492
  * participating in model change detection and listener notification by invoking.
7466
7493
  *
7467
- * @param {boolean} isolate if true then the scoped does not prototypically inherit from the
7468
- * parent scope. The scope is isolated, as it can not se parent scope properties.
7469
- * When creating widgets it is useful for the widget to not accidently read parent
7494
+ * @param {boolean} isolate if true then the scope does not prototypically inherit from the
7495
+ * parent scope. The scope is isolated, as it can not see parent scope properties.
7496
+ * When creating widgets it is useful for the widget to not accidentally read parent
7470
7497
  * state.
7471
7498
  *
7472
7499
  * @returns {Object} The newly created child scope.
@@ -7520,18 +7547,18 @@ function $RootScopeProvider(){
7520
7547
  * reruns when it detects changes the `watchExpression` can execute multiple times per
7521
7548
  * {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
7522
7549
  * - The `listener` is called only when the value from the current `watchExpression` and the
7523
- * previous call to `watchExpression' are not equal (with the exception of the initial run
7550
+ * previous call to `watchExpression` are not equal (with the exception of the initial run,
7524
7551
  * see below). The inequality is determined according to
7525
- * {@link angular.equals} function. To save the value of the object for later comparison
7552
+ * {@link angular.equals} function. To save the value of the object for later comparison, the
7526
7553
  * {@link angular.copy} function is used. It also means that watching complex options will
7527
7554
  * have adverse memory and performance implications.
7528
7555
  * - The watch `listener` may change the model, which may trigger other `listener`s to fire. This
7529
7556
  * is achieved by rerunning the watchers until no changes are detected. The rerun iteration
7530
- * limit is 100 to prevent infinity loop deadlock.
7557
+ * limit is 10 to prevent an infinite loop deadlock.
7531
7558
  *
7532
7559
  *
7533
7560
  * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
7534
- * you can register an `watchExpression` function with no `listener`. (Since `watchExpression`,
7561
+ * you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
7535
7562
  * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a change is
7536
7563
  * detected, be prepared for multiple calls to your listener.)
7537
7564
  *
@@ -7577,7 +7604,7 @@ function $RootScopeProvider(){
7577
7604
  * - `string`: Evaluated as {@link guide/expression expression}
7578
7605
  * - `function(newValue, oldValue, scope)`: called with current and previous values as parameters.
7579
7606
  *
7580
- * @param {boolean=} objectEquality Compare object for equality rather then for refference.
7607
+ * @param {boolean=} objectEquality Compare object for equality rather than for reference.
7581
7608
  * @returns {function()} Returns a deregistration function for this listener.
7582
7609
  */
7583
7610
  $watch: function(watchExp, listener, objectEquality) {
@@ -7752,7 +7779,7 @@ function $RootScopeProvider(){
7752
7779
  * @function
7753
7780
  *
7754
7781
  * @description
7755
- * Remove the current scope (and all of its children) from the parent scope. Removal implies
7782
+ * Removes the current scope (and all of its children) from the parent scope. Removal implies
7756
7783
  * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
7757
7784
  * propagate to the current scope and its children. Removal also implies that the current
7758
7785
  * scope is eligible for garbage collection.
@@ -7775,6 +7802,11 @@ function $RootScopeProvider(){
7775
7802
  if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
7776
7803
  if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
7777
7804
  if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
7805
+
7806
+ // This is bogus code that works around Chrome's GC leak
7807
+ // see: https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
7808
+ this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
7809
+ this.$$childTail = null;
7778
7810
  },
7779
7811
 
7780
7812
  /**
@@ -7785,7 +7817,7 @@ function $RootScopeProvider(){
7785
7817
  *
7786
7818
  * @description
7787
7819
  * Executes the `expression` on the current scope returning the result. Any exceptions in the
7788
- * expression are propagated (uncaught). This is useful when evaluating engular expressions.
7820
+ * expression are propagated (uncaught). This is useful when evaluating Angular expressions.
7789
7821
  *
7790
7822
  * # Example
7791
7823
  * <pre>
@@ -7906,7 +7938,7 @@ function $RootScopeProvider(){
7906
7938
  * @function
7907
7939
  *
7908
7940
  * @description
7909
- * Listen on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for discussion of
7941
+ * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for discussion of
7910
7942
  * event life cycle.
7911
7943
  *
7912
7944
  * @param {string} name Event name to listen on.
@@ -7916,13 +7948,13 @@ function $RootScopeProvider(){
7916
7948
  * The event listener function format is: `function(event, args...)`. The `event` object
7917
7949
  * passed into the listener has the following attributes:
7918
7950
  *
7919
- * - `targetScope` - {Scope}: the scope on which the event was `$emit`-ed or `$broadcast`-ed.
7920
- * - `currentScope` - {Scope}: the current scope which is handling the event.
7921
- * - `name` - {string}: Name of the event.
7922
- * - `stopPropagation` - {function=}: calling `stopPropagation` function will cancel further event propagation
7923
- * (available only for events that were `$emit`-ed).
7924
- * - `preventDefault` - {function}: calling `preventDefault` sets `defaultPrevented` flag to true.
7925
- * - `defaultPrevented` - {boolean}: true if `preventDefault` was called.
7951
+ * - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or `$broadcast`-ed.
7952
+ * - `currentScope` - `{Scope}`: the current scope which is handling the event.
7953
+ * - `name` - `{string}`: Name of the event.
7954
+ * - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel further event
7955
+ * propagation (available only for events that were `$emit`-ed).
7956
+ * - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag to true.
7957
+ * - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
7926
7958
  */
7927
7959
  $on: function(name, listener) {
7928
7960
  var namedListeners = this.$$listeners[name];
@@ -7932,7 +7964,7 @@ function $RootScopeProvider(){
7932
7964
  namedListeners.push(listener);
7933
7965
 
7934
7966
  return function() {
7935
- arrayRemove(namedListeners, listener);
7967
+ namedListeners[indexOf(namedListeners, listener)] = null;
7936
7968
  };
7937
7969
  },
7938
7970
 
@@ -7980,6 +8012,14 @@ function $RootScopeProvider(){
7980
8012
  namedListeners = scope.$$listeners[name] || empty;
7981
8013
  event.currentScope = scope;
7982
8014
  for (i=0, length=namedListeners.length; i<length; i++) {
8015
+
8016
+ // if listeners were deregistered, defragment the array
8017
+ if (!namedListeners[i]) {
8018
+ namedListeners.splice(i, 1);
8019
+ i--;
8020
+ length--;
8021
+ continue;
8022
+ }
7983
8023
  try {
7984
8024
  namedListeners[i].apply(null, listenerArgs);
7985
8025
  if (stopPropagation) return event;
@@ -8029,19 +8069,29 @@ function $RootScopeProvider(){
8029
8069
  },
8030
8070
  defaultPrevented: false
8031
8071
  },
8032
- listenerArgs = concat([event], arguments, 1);
8072
+ listenerArgs = concat([event], arguments, 1),
8073
+ listeners, i, length;
8033
8074
 
8034
8075
  //down while you can, then up and next sibling or up and next sibling until back at root
8035
8076
  do {
8036
8077
  current = next;
8037
8078
  event.currentScope = current;
8038
- forEach(current.$$listeners[name], function(listener) {
8079
+ listeners = current.$$listeners[name] || [];
8080
+ for (i=0, length = listeners.length; i<length; i++) {
8081
+ // if listeners were deregistered, defragment the array
8082
+ if (!listeners[i]) {
8083
+ listeners.splice(i, 1);
8084
+ i--;
8085
+ length--;
8086
+ continue;
8087
+ }
8088
+
8039
8089
  try {
8040
- listener.apply(null, listenerArgs);
8090
+ listeners[i].apply(null, listenerArgs);
8041
8091
  } catch(e) {
8042
8092
  $exceptionHandler(e);
8043
8093
  }
8044
- });
8094
+ }
8045
8095
 
8046
8096
  // Insanity Warning: scope depth-first traversal
8047
8097
  // yes, this code is a bit crazy, but it works and we have tests to prove it!
@@ -9149,7 +9199,7 @@ function $TimeoutProvider() {
9149
9199
  * @param {number=} [delay=0] Delay in milliseconds.
9150
9200
  * @param {boolean=} [invokeApply=true] If set to false skips model dirty checking, otherwise
9151
9201
  * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
9152
- * @returns {*} Promise that will be resolved when the timeout is reached. The value this
9202
+ * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
9153
9203
  * promise will be resolved with is the return value of the `fn` function.
9154
9204
  */
9155
9205
  function timeout(fn, delay, invokeApply) {
@@ -9588,9 +9638,18 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
9588
9638
  formatedText = '',
9589
9639
  parts = [];
9590
9640
 
9641
+ var hasExponent = false;
9591
9642
  if (numStr.indexOf('e') !== -1) {
9592
- formatedText = numStr;
9593
- } else {
9643
+ var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
9644
+ if (match && match[2] == '-' && match[3] > fractionSize + 1) {
9645
+ numStr = '0';
9646
+ } else {
9647
+ formatedText = numStr;
9648
+ hasExponent = true;
9649
+ }
9650
+ }
9651
+
9652
+ if (!hasExponent) {
9594
9653
  var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
9595
9654
 
9596
9655
  // determine fractionSize if it is not specified
@@ -9791,7 +9850,7 @@ dateFilter.$inject = ['$locale'];
9791
9850
  function dateFilter($locale) {
9792
9851
 
9793
9852
 
9794
- var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
9853
+ var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
9795
9854
  function jsonStringToDate(string){
9796
9855
  var match;
9797
9856
  if (match = string.match(R_ISO8601_STR)) {
@@ -10170,6 +10229,7 @@ var htmlAnchorDirective = valueFn({
10170
10229
  // if we have no href url, then don't navigate anywhere.
10171
10230
  if (!element.attr('href')) {
10172
10231
  event.preventDefault();
10232
+ return false; // Needed for opera
10173
10233
  }
10174
10234
  });
10175
10235
  }
@@ -10460,7 +10520,7 @@ forEach(BOOLEAN_ATTR, function(propName, attrName) {
10460
10520
  priority: 100,
10461
10521
  compile: function() {
10462
10522
  return function(scope, element, attr) {
10463
- scope.$watch(attr[normalized], function(value) {
10523
+ scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
10464
10524
  attr.$set(attrName, !!value);
10465
10525
  });
10466
10526
  };
@@ -10478,6 +10538,9 @@ forEach(['src', 'href'], function(attrName) {
10478
10538
  priority: 99, // it needs to run after the attributes are interpolated
10479
10539
  link: function(scope, element, attr) {
10480
10540
  attr.$observe(normalized, function(value) {
10541
+ if (!value)
10542
+ return;
10543
+
10481
10544
  attr.$set(attrName, value);
10482
10545
 
10483
10546
  // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
@@ -10606,6 +10669,7 @@ function FormController(element, attrs) {
10606
10669
  element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
10607
10670
  form.$dirty = true;
10608
10671
  form.$pristine = false;
10672
+ parentForm.$setDirty();
10609
10673
  };
10610
10674
 
10611
10675
  }
@@ -10791,7 +10855,10 @@ var inputType = {
10791
10855
  *
10792
10856
  * @param {string} ngModel Assignable angular expression to data-bind to.
10793
10857
  * @param {string=} name Property name of the form under which the control is published.
10794
- * @param {string=} required Sets `required` validation error key if the value is not entered.
10858
+ * @param {string=} required Adds `required` validation error key if the value is not entered.
10859
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
10860
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
10861
+ * `required` when you want to data-bind to the `required` attribute.
10795
10862
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
10796
10863
  * minlength.
10797
10864
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -10861,6 +10928,9 @@ var inputType = {
10861
10928
  * @param {string=} min Sets the `min` validation error key if the value entered is less then `min`.
10862
10929
  * @param {string=} max Sets the `max` validation error key if the value entered is greater then `min`.
10863
10930
  * @param {string=} required Sets `required` validation error key if the value is not entered.
10931
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
10932
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
10933
+ * `required` when you want to data-bind to the `required` attribute.
10864
10934
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
10865
10935
  * minlength.
10866
10936
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -10927,6 +10997,9 @@ var inputType = {
10927
10997
  * @param {string} ngModel Assignable angular expression to data-bind to.
10928
10998
  * @param {string=} name Property name of the form under which the control is published.
10929
10999
  * @param {string=} required Sets `required` validation error key if the value is not entered.
11000
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
11001
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
11002
+ * `required` when you want to data-bind to the `required` attribute.
10930
11003
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
10931
11004
  * minlength.
10932
11005
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -10992,6 +11065,9 @@ var inputType = {
10992
11065
  * @param {string} ngModel Assignable angular expression to data-bind to.
10993
11066
  * @param {string=} name Property name of the form under which the control is published.
10994
11067
  * @param {string=} required Sets `required` validation error key if the value is not entered.
11068
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
11069
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
11070
+ * `required` when you want to data-bind to the `required` attribute.
10995
11071
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
10996
11072
  * minlength.
10997
11073
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -11414,6 +11490,9 @@ function checkboxInputType(scope, element, attr, ctrl) {
11414
11490
  * @param {string} ngModel Assignable angular expression to data-bind to.
11415
11491
  * @param {string=} name Property name of the form under which the control is published.
11416
11492
  * @param {string=} required Sets `required` validation error key if the value is not entered.
11493
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
11494
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
11495
+ * `required` when you want to data-bind to the `required` attribute.
11417
11496
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
11418
11497
  * minlength.
11419
11498
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -11438,6 +11517,7 @@ function checkboxInputType(scope, element, attr, ctrl) {
11438
11517
  * @param {string} ngModel Assignable angular expression to data-bind to.
11439
11518
  * @param {string=} name Property name of the form under which the control is published.
11440
11519
  * @param {string=} required Sets `required` validation error key if the value is not entered.
11520
+ * @param {boolean=} ngRequired Sets `required` attribute if set to true
11441
11521
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
11442
11522
  * minlength.
11443
11523
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -11771,22 +11851,25 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
11771
11851
 
11772
11852
  // model -> value
11773
11853
  var ctrl = this;
11774
- $scope.$watch(ngModelGet, function(value) {
11775
11854
 
11776
- // ignore change from view
11777
- if (ctrl.$modelValue === value) return;
11855
+ $scope.$watch(function ngModelWatch() {
11856
+ var value = ngModelGet($scope);
11778
11857
 
11779
- var formatters = ctrl.$formatters,
11780
- idx = formatters.length;
11858
+ // if scope model value and ngModel value are out of sync
11859
+ if (ctrl.$modelValue !== value) {
11781
11860
 
11782
- ctrl.$modelValue = value;
11783
- while(idx--) {
11784
- value = formatters[idx](value);
11785
- }
11861
+ var formatters = ctrl.$formatters,
11862
+ idx = formatters.length;
11786
11863
 
11787
- if (ctrl.$viewValue !== value) {
11788
- ctrl.$viewValue = value;
11789
- ctrl.$render();
11864
+ ctrl.$modelValue = value;
11865
+ while(idx--) {
11866
+ value = formatters[idx](value);
11867
+ }
11868
+
11869
+ if (ctrl.$viewValue !== value) {
11870
+ ctrl.$viewValue = value;
11871
+ ctrl.$render();
11872
+ }
11790
11873
  }
11791
11874
  });
11792
11875
  }];
@@ -11935,7 +12018,7 @@ var requiredDirective = function() {
11935
12018
  * @name ng.directive:ngList
11936
12019
  *
11937
12020
  * @description
11938
- * Text input that converts between comma-seperated string into an array of strings.
12021
+ * Text input that converts between comma-separated string into an array of strings.
11939
12022
  *
11940
12023
  * @element input
11941
12024
  * @param {string=} ngList optional delimiter that should be used to split the value. If
@@ -12018,7 +12101,7 @@ var ngValueDirective = function() {
12018
12101
  };
12019
12102
  } else {
12020
12103
  return function(scope, elm, attr) {
12021
- scope.$watch(attr.ngValue, function(value) {
12104
+ scope.$watch(attr.ngValue, function valueWatchAction(value) {
12022
12105
  attr.$set('value', value, false);
12023
12106
  });
12024
12107
  };
@@ -12076,7 +12159,7 @@ var ngValueDirective = function() {
12076
12159
  */
12077
12160
  var ngBindDirective = ngDirective(function(scope, element, attr) {
12078
12161
  element.addClass('ng-binding').data('$binding', attr.ngBind);
12079
- scope.$watch(attr.ngBind, function(value) {
12162
+ scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
12080
12163
  element.text(value == undefined ? '' : value);
12081
12164
  });
12082
12165
  });
@@ -12159,7 +12242,7 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
12159
12242
  var ngBindHtmlUnsafeDirective = [function() {
12160
12243
  return function(scope, element, attr) {
12161
12244
  element.addClass('ng-binding').data('$binding', attr.ngBindHtmlUnsafe);
12162
- scope.$watch(attr.ngBindHtmlUnsafe, function(value) {
12245
+ scope.$watch(attr.ngBindHtmlUnsafe, function ngBindHtmlUnsafeWatchAction(value) {
12163
12246
  element.html(value || '');
12164
12247
  });
12165
12248
  };
@@ -12168,17 +12251,55 @@ var ngBindHtmlUnsafeDirective = [function() {
12168
12251
  function classDirective(name, selector) {
12169
12252
  name = 'ngClass' + name;
12170
12253
  return ngDirective(function(scope, element, attr) {
12171
- scope.$watch(attr[name], function(newVal, oldVal) {
12254
+
12255
+ scope.$watch(attr[name], ngClassWatchAction, true);
12256
+
12257
+ attr.$observe('class', function(value) {
12258
+ var ngClass = scope.$eval(attr[name]);
12259
+ ngClassWatchAction(ngClass, ngClass);
12260
+ });
12261
+
12262
+
12263
+ if (name !== 'ngClass') {
12264
+ scope.$watch('$index', function($index, old$index) {
12265
+ var mod = $index % 2;
12266
+ if (mod !== old$index % 2) {
12267
+ if (mod == selector) {
12268
+ addClass(scope.$eval(attr[name]));
12269
+ } else {
12270
+ removeClass(scope.$eval(attr[name]));
12271
+ }
12272
+ }
12273
+ });
12274
+ }
12275
+
12276
+
12277
+ function ngClassWatchAction(newVal, oldVal) {
12172
12278
  if (selector === true || scope.$index % 2 === selector) {
12173
12279
  if (oldVal && (newVal !== oldVal)) {
12174
- if (isObject(oldVal) && !isArray(oldVal))
12175
- oldVal = map(oldVal, function(v, k) { if (v) return k });
12176
- element.removeClass(isArray(oldVal) ? oldVal.join(' ') : oldVal);
12177
- }
12178
- if (isObject(newVal) && !isArray(newVal))
12179
- newVal = map(newVal, function(v, k) { if (v) return k });
12180
- if (newVal) element.addClass(isArray(newVal) ? newVal.join(' ') : newVal); }
12181
- }, true);
12280
+ removeClass(oldVal);
12281
+ }
12282
+ addClass(newVal);
12283
+ }
12284
+ }
12285
+
12286
+
12287
+ function removeClass(classVal) {
12288
+ if (isObject(classVal) && !isArray(classVal)) {
12289
+ classVal = map(classVal, function(v, k) { if (v) return k });
12290
+ }
12291
+ element.removeClass(isArray(classVal) ? classVal.join(' ') : classVal);
12292
+ }
12293
+
12294
+
12295
+ function addClass(classVal) {
12296
+ if (isObject(classVal) && !isArray(classVal)) {
12297
+ classVal = map(classVal, function(v, k) { if (v) return k });
12298
+ }
12299
+ if (classVal) {
12300
+ element.addClass(isArray(classVal) ? classVal.join(' ') : classVal);
12301
+ }
12302
+ }
12182
12303
  });
12183
12304
  }
12184
12305
 
@@ -12837,7 +12958,7 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
12837
12958
  element.html('');
12838
12959
  };
12839
12960
 
12840
- scope.$watch(srcExp, function(src) {
12961
+ scope.$watch(srcExp, function ngIncludeWatchAction(src) {
12841
12962
  var thisChangeId = ++changeCounter;
12842
12963
 
12843
12964
  if (src) {
@@ -13122,7 +13243,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
13122
13243
  offset + endSymbol));
13123
13244
  });
13124
13245
 
13125
- scope.$watch(function() {
13246
+ scope.$watch(function ngPluralizeWatch() {
13126
13247
  var value = parseFloat(scope.$eval(numberExp));
13127
13248
 
13128
13249
  if (!isNaN(value)) {
@@ -13133,7 +13254,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
13133
13254
  } else {
13134
13255
  return '';
13135
13256
  }
13136
- }, function(newVal) {
13257
+ }, function ngPluralizeWatchAction(newVal) {
13137
13258
  element.text(newVal);
13138
13259
  });
13139
13260
  }
@@ -13228,7 +13349,8 @@ var ngRepeatDirective = ngDirective({
13228
13349
  // We need an array of these objects since the same object can be returned from the iterator.
13229
13350
  // We expect this to be a rare case.
13230
13351
  var lastOrder = new HashQueueMap();
13231
- scope.$watch(function(scope){
13352
+
13353
+ scope.$watch(function ngRepeatWatch(scope){
13232
13354
  var index, length,
13233
13355
  collection = scope.$eval(rhs),
13234
13356
  collectionLength = size(collection, true),
@@ -13257,7 +13379,9 @@ var ngRepeatDirective = ngDirective({
13257
13379
  for (index = 0, length = array.length; index < length; index++) {
13258
13380
  key = (collection === array) ? index : array[index];
13259
13381
  value = collection[key];
13382
+
13260
13383
  last = lastOrder.shift(value);
13384
+
13261
13385
  if (last) {
13262
13386
  // if we have already seen this object, then we need to reuse the
13263
13387
  // associated scope/element
@@ -13354,7 +13478,7 @@ var ngRepeatDirective = ngDirective({
13354
13478
  */
13355
13479
  //TODO(misko): refactor to remove element from the DOM
13356
13480
  var ngShowDirective = ngDirective(function(scope, element, attr){
13357
- scope.$watch(attr.ngShow, function(value){
13481
+ scope.$watch(attr.ngShow, function ngShowWatchAction(value){
13358
13482
  element.css('display', toBoolean(value) ? '' : 'none');
13359
13483
  });
13360
13484
  });
@@ -13365,11 +13489,11 @@ var ngShowDirective = ngDirective(function(scope, element, attr){
13365
13489
  * @name ng.directive:ngHide
13366
13490
  *
13367
13491
  * @description
13368
- * The `ngHide` and `ngShow` directives hide or show a portion
13369
- * of the HTML conditionally.
13492
+ * The `ngHide` and `ngShow` directives hide or show a portion of the DOM tree (HTML)
13493
+ * conditionally.
13370
13494
  *
13371
13495
  * @element ANY
13372
- * @param {expression} ngHide If the {@link guide/expression expression} truthy then
13496
+ * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
13373
13497
  * the element is shown or hidden respectively.
13374
13498
  *
13375
13499
  * @example
@@ -13394,7 +13518,7 @@ var ngShowDirective = ngDirective(function(scope, element, attr){
13394
13518
  */
13395
13519
  //TODO(misko): refactor to remove element from the DOM
13396
13520
  var ngHideDirective = ngDirective(function(scope, element, attr){
13397
- scope.$watch(attr.ngHide, function(value){
13521
+ scope.$watch(attr.ngHide, function ngHideWatchAction(value){
13398
13522
  element.css('display', toBoolean(value) ? 'none' : '');
13399
13523
  });
13400
13524
  });
@@ -13437,7 +13561,7 @@ var ngHideDirective = ngDirective(function(scope, element, attr){
13437
13561
  </example>
13438
13562
  */
13439
13563
  var ngStyleDirective = ngDirective(function(scope, element, attr) {
13440
- scope.$watch(attr.ngStyle, function(newStyles, oldStyles) {
13564
+ scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
13441
13565
  if (oldStyles && (newStyles !== oldStyles)) {
13442
13566
  forEach(oldStyles, function(val, style) { element.css(style, '');});
13443
13567
  }
@@ -13517,7 +13641,7 @@ var ngSwitchDirective = valueFn({
13517
13641
  selectedElement,
13518
13642
  selectedScope;
13519
13643
 
13520
- scope.$watch(watchExpr, function(value) {
13644
+ scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
13521
13645
  if (selectedElement) {
13522
13646
  selectedScope.$destroy();
13523
13647
  selectedElement.remove();
@@ -13851,6 +13975,9 @@ var scriptDirective = ['$templateCache', function($templateCache) {
13851
13975
  *
13852
13976
  * @param {string} name assignable expression to data-bind to.
13853
13977
  * @param {string=} required The control is considered valid only if value is entered.
13978
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
13979
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
13980
+ * `required` when you want to data-bind to the `required` attribute.
13854
13981
  * @param {comprehension_expression=} ngOptions in one of the following forms:
13855
13982
  *
13856
13983
  * * for array data sources:
@@ -14091,7 +14218,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
14091
14218
 
14092
14219
  // we have to do it on each watch since ngModel watches reference, but
14093
14220
  // we need to work of an array, so we need to see if anything was inserted/removed
14094
- scope.$watch(function() {
14221
+ scope.$watch(function selectMultipleWatch() {
14095
14222
  if (!equals(lastView, ctrl.$viewValue)) {
14096
14223
  lastView = copy(ctrl.$viewValue);
14097
14224
  ctrl.$render();
@@ -14208,7 +14335,8 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
14208
14335
  selected,
14209
14336
  selectedSet = false, // nothing is selected yet
14210
14337
  lastElement,
14211
- element;
14338
+ element,
14339
+ label;
14212
14340
 
14213
14341
  if (multiple) {
14214
14342
  selectedSet = new HashMap(modelValue);
@@ -14232,9 +14360,11 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
14232
14360
  selected = modelValue === valueFn(scope, locals);
14233
14361
  selectedSet = selectedSet || selected; // see if at least one item is selected
14234
14362
  }
14363
+ label = displayFn(scope, locals); // what will be seen by the user
14364
+ label = label === undefined ? '' : label; // doing displayFn(scope, locals) || '' overwrites zero values
14235
14365
  optionGroup.push({
14236
14366
  id: keyName ? keys[index] : index, // either the index into array or key from object
14237
- label: displayFn(scope, locals) || '', // what will be seen by the user
14367
+ label: label,
14238
14368
  selected: selected // determine if we should be selected
14239
14369
  });
14240
14370
  }
@@ -14366,7 +14496,7 @@ var optionDirective = ['$interpolate', function($interpolate) {
14366
14496
  }
14367
14497
 
14368
14498
  if (interpolateFn) {
14369
- scope.$watch(interpolateFn, function(newVal, oldVal) {
14499
+ scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
14370
14500
  attr.$set('value', newVal);
14371
14501
  if (newVal !== oldVal) selectCtrl.removeOption(oldVal);
14372
14502
  selectCtrl.addOption(newVal);