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.
data/README.md CHANGED
@@ -19,7 +19,5 @@ If you desire to require (optional) Angular files, you may include them as well
19
19
 
20
20
  ## Versioning
21
21
 
22
- angularjs-rails 1.0.0 == Angular.js 1.0.0
23
-
24
22
  Every attempt is made to mirror the currently shipping Angular.js version number wherever possible.
25
23
  The major, minor, and patch version numbers will always represent the Angular.js version.
@@ -1,5 +1,5 @@
1
1
  module AngularJS
2
2
  module Rails
3
- VERSION = "1.0.2"
3
+ VERSION = "1.0.3"
4
4
  end
5
5
  end
@@ -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
  */
@@ -216,7 +216,7 @@ directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location',
216
216
  }, $delegate);
217
217
  }]);
218
218
  $provide.decorator('$rootScope', ['$delegate', function(embedRootScope) {
219
- docsRootScope.$watch(function() {
219
+ docsRootScope.$watch(function embedRootScopeDigestWatch() {
220
220
  embedRootScope.$digest();
221
221
  });
222
222
  return embedRootScope;
@@ -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
  */
@@ -15,7 +15,7 @@ directive.dropdownToggle =
15
15
  return {
16
16
  restrict: 'C',
17
17
  link: function(scope, element, attrs) {
18
- scope.$watch(function(){return $location.path();}, function() {
18
+ scope.$watch(function dropdownTogglePathWatch(){return $location.path();}, function dropdownTogglePathWatchAction() {
19
19
  close && close();
20
20
  });
21
21
 
@@ -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
  */
@@ -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
  */
@@ -36,7 +36,7 @@ function setupModuleLoader(window) {
36
36
  *
37
37
  * # Module
38
38
  *
39
- * A module is a collocation of services, directives, filters, and configure information. Module
39
+ * A module is a collocation of services, directives, filters, and configuration information. Module
40
40
  * is used to configure the {@link AUTO.$injector $injector}.
41
41
  *
42
42
  * <pre>
@@ -67,7 +67,7 @@ function setupModuleLoader(window) {
67
67
  * @param {!string} name The name of the module to create or retrieve.
68
68
  * @param {Array.<string>=} requires If specified then new module is being created. If unspecified then the
69
69
  * the module is being retrieved for further configuration.
70
- * @param {Function} configFn Option configuration function for the module. Same as
70
+ * @param {Function} configFn Optional configuration function for the module. Same as
71
71
  * {@link angular.Module#config Module#config()}.
72
72
  * @returns {module} new module with the {@link angular.Module} api.
73
73
  */
@@ -222,8 +222,8 @@ function setupModuleLoader(window) {
222
222
  * @param {Function} initializationFn Execute this function after injector creation.
223
223
  * Useful for application initialization.
224
224
  * @description
225
- * Use this method to register work which needs to be performed when the injector with
226
- * with the current module is finished loading.
225
+ * Use this method to register work which should be performed when the injector is done
226
+ * loading all modules.
227
227
  */
228
228
  run: function(block) {
229
229
  runBlocks.push(block);
@@ -1,6 +1,6 @@
1
1
 
2
2
  /**
3
- * @license AngularJS v1.0.2
3
+ * @license AngularJS v1.0.3
4
4
  * (c) 2010-2012 Google, Inc. http://angularjs.org
5
5
  * License: MIT
6
6
  *
@@ -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
  */
@@ -231,7 +231,7 @@ angular.module('ngResource', ['ng']).
231
231
  };
232
232
 
233
233
  /**
234
- * We need our custom mehtod because encodeURIComponent is too agressive and doesn't follow
234
+ * We need our custom mehtod because encodeURIComponent is too aggressive and doesn't follow
235
235
  * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
236
236
  * segments:
237
237
  * segment = *pchar
@@ -285,12 +285,18 @@ angular.module('ngResource', ['ng']).
285
285
  url: function(params) {
286
286
  var self = this,
287
287
  url = this.template,
288
+ val,
288
289
  encodedVal;
289
290
 
290
291
  params = params || {};
291
292
  forEach(this.urlParams, function(_, urlParam){
292
- encodedVal = encodeUriSegment(params[urlParam] || self.defaults[urlParam] || "");
293
- url = url.replace(new RegExp(":" + urlParam + "(\\W)"), encodedVal + "$1");
293
+ val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
294
+ if (angular.isDefined(val) && val !== null) {
295
+ encodedVal = encodeUriSegment(val);
296
+ url = url.replace(new RegExp(":" + urlParam + "(\\W)", "g"), encodedVal + "$1");
297
+ } else {
298
+ url = url.replace(new RegExp("/?:" + urlParam + "(\\W)", "g"), '$1');
299
+ }
294
300
  });
295
301
  url = url.replace(/\/?#$/, '');
296
302
  var query = [];
@@ -311,9 +317,10 @@ angular.module('ngResource', ['ng']).
311
317
 
312
318
  actions = extend({}, DEFAULT_ACTIONS, actions);
313
319
 
314
- function extractParams(data){
320
+ function extractParams(data, actionParams){
315
321
  var ids = {};
316
- forEach(paramDefaults || {}, function(value, key){
322
+ actionParams = extend({}, paramDefaults, actionParams);
323
+ forEach(actionParams, function(value, key){
317
324
  ids[key] = value.charAt && value.charAt(0) == '@' ? getter(data, value.substr(1)) : value;
318
325
  });
319
326
  return ids;
@@ -367,7 +374,7 @@ angular.module('ngResource', ['ng']).
367
374
  var value = this instanceof Resource ? this : (action.isArray ? [] : new Resource(data));
368
375
  $http({
369
376
  method: action.method,
370
- url: route.url(extend({}, extractParams(data), action.params || {}, params)),
377
+ url: route.url(extend({}, extractParams(data, action.params || {}), params)),
371
378
  data: data
372
379
  }).then(function(response) {
373
380
  var data = response.data;
@@ -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
  */
@@ -416,7 +416,7 @@ angular.module('ngSanitize', []).value('$sanitize', $sanitize);
416
416
  angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($sanitize) {
417
417
  return function(scope, element, attr) {
418
418
  element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
419
- scope.$watch(attr.ngBindHtml, function(value) {
419
+ scope.$watch(attr.ngBindHtml, function ngBindHtmlWatchAction(value) {
420
420
  value = $sanitize(value);
421
421
  element.html(value || '');
422
422
  });
@@ -9404,7 +9404,7 @@ if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
9404
9404
 
9405
9405
  })( window );
9406
9406
  /**
9407
- * @license AngularJS v1.0.2
9407
+ * @license AngularJS v1.0.3
9408
9408
  * (c) 2010-2012 Google, Inc. http://angularjs.org
9409
9409
  * License: MIT
9410
9410
  */
@@ -10199,7 +10199,7 @@ function toKeyValue(obj) {
10199
10199
 
10200
10200
 
10201
10201
  /**
10202
- * We need our custom mehtod because encodeURIComponent is too agressive and doesn't follow
10202
+ * We need our custom method because encodeURIComponent is too agressive and doesn't follow
10203
10203
  * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
10204
10204
  * segments:
10205
10205
  * segment = *pchar
@@ -10243,7 +10243,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
10243
10243
  * @name ng.directive:ngApp
10244
10244
  *
10245
10245
  * @element ANY
10246
- * @param {angular.Module} ngApp on optional application
10246
+ * @param {angular.Module} ngApp an optional application
10247
10247
  * {@link angular.module module} name to load.
10248
10248
  *
10249
10249
  * @description
@@ -10420,7 +10420,7 @@ function setupModuleLoader(window) {
10420
10420
  *
10421
10421
  * # Module
10422
10422
  *
10423
- * A module is a collocation of services, directives, filters, and configure information. Module
10423
+ * A module is a collocation of services, directives, filters, and configuration information. Module
10424
10424
  * is used to configure the {@link AUTO.$injector $injector}.
10425
10425
  *
10426
10426
  * <pre>
@@ -10450,7 +10450,7 @@ function setupModuleLoader(window) {
10450
10450
  * @param {!string} name The name of the module to create or retrieve.
10451
10451
  * @param {Array.<string>=} requires If specified then new module is being created. If unspecified then the
10452
10452
  * the module is being retrieved for further configuration.
10453
- * @param {Function} configFn Option configuration function for the module. Same as
10453
+ * @param {Function} configFn Optional configuration function for the module. Same as
10454
10454
  * {@link angular.Module#config Module#config()}.
10455
10455
  * @returns {module} new module with the {@link angular.Module} api.
10456
10456
  */
@@ -10605,8 +10605,8 @@ function setupModuleLoader(window) {
10605
10605
  * @param {Function} initializationFn Execute this function after injector creation.
10606
10606
  * Useful for application initialization.
10607
10607
  * @description
10608
- * Use this method to register work which needs to be performed when the injector with
10609
- * with the current module is finished loading.
10608
+ * Use this method to register work which should be performed when the injector is done
10609
+ * loading all modules.
10610
10610
  */
10611
10611
  run: function(block) {
10612
10612
  runBlocks.push(block);
@@ -10652,11 +10652,11 @@ function setupModuleLoader(window) {
10652
10652
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
10653
10653
  */
10654
10654
  var version = {
10655
- full: '1.0.2', // all of these placeholder strings will be replaced by rake's
10655
+ full: '1.0.3', // all of these placeholder strings will be replaced by rake's
10656
10656
  major: 1, // compile task
10657
10657
  minor: 0,
10658
- dot: 2,
10659
- codeName: 'debilitating-awesomeness'
10658
+ dot: 3,
10659
+ codeName: 'bouncy-thunder'
10660
10660
  };
10661
10661
 
10662
10662
 
@@ -10823,6 +10823,7 @@ function publishExternalAPI(angular){
10823
10823
  * - [replaceWith()](http://api.jquery.com/replaceWith/)
10824
10824
  * - [text()](http://api.jquery.com/text/)
10825
10825
  * - [toggleClass()](http://api.jquery.com/toggleClass/)
10826
+ * - [triggerHandler()](http://api.jquery.com/triggerHandler/) - Doesn't pass native event objects to handlers.
10826
10827
  * - [unbind()](http://api.jquery.com/unbind/)
10827
10828
  * - [val()](http://api.jquery.com/val/)
10828
10829
  * - [wrap()](http://api.jquery.com/wrap/)
@@ -10898,12 +10899,7 @@ function JQLitePatchJQueryRemove(name, dispatchThis) {
10898
10899
  for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
10899
10900
  element = jqLite(set[setIndex]);
10900
10901
  if (fireEvent) {
10901
- events = element.data('events');
10902
- if ( (fns = events && events.$destroy) ) {
10903
- forEach(fns, function(fn){
10904
- fn.handler();
10905
- });
10906
- }
10902
+ element.triggerHandler('$destroy');
10907
10903
  } else {
10908
10904
  fireEvent = !fireEvent;
10909
10905
  }
@@ -11035,9 +11031,9 @@ function JQLiteHasClass(element, selector) {
11035
11031
  indexOf( " " + selector + " " ) > -1);
11036
11032
  }
11037
11033
 
11038
- function JQLiteRemoveClass(element, selector) {
11039
- if (selector) {
11040
- forEach(selector.split(' '), function(cssClass) {
11034
+ function JQLiteRemoveClass(element, cssClasses) {
11035
+ if (cssClasses) {
11036
+ forEach(cssClasses.split(' '), function(cssClass) {
11041
11037
  element.className = trim(
11042
11038
  (" " + element.className + " ")
11043
11039
  .replace(/[\n\t]/g, " ")
@@ -11047,9 +11043,9 @@ function JQLiteRemoveClass(element, selector) {
11047
11043
  }
11048
11044
  }
11049
11045
 
11050
- function JQLiteAddClass(element, selector) {
11051
- if (selector) {
11052
- forEach(selector.split(' '), function(cssClass) {
11046
+ function JQLiteAddClass(element, cssClasses) {
11047
+ if (cssClasses) {
11048
+ forEach(cssClasses.split(' '), function(cssClass) {
11053
11049
  if (!JQLiteHasClass(element, cssClass)) {
11054
11050
  element.className = trim(element.className + ' ' + trim(cssClass));
11055
11051
  }
@@ -11497,7 +11493,15 @@ forEach({
11497
11493
  return element.getElementsByTagName(selector);
11498
11494
  },
11499
11495
 
11500
- clone: JQLiteClone
11496
+ clone: JQLiteClone,
11497
+
11498
+ triggerHandler: function(element, eventName) {
11499
+ var eventFns = (JQLiteExpandoStore(element, 'events') || {})[eventName];
11500
+
11501
+ forEach(eventFns, function(fn) {
11502
+ fn.call(element, null);
11503
+ });
11504
+ }
11501
11505
  }, function(fn, name){
11502
11506
  /**
11503
11507
  * chaining functions
@@ -11615,6 +11619,16 @@ HashQueueMap.prototype = {
11615
11619
  return array.shift();
11616
11620
  }
11617
11621
  }
11622
+ },
11623
+
11624
+ /**
11625
+ * return the first item without deleting it
11626
+ */
11627
+ peek: function(key) {
11628
+ var array = this[hashKey(key)];
11629
+ if (array) {
11630
+ return array[0];
11631
+ }
11618
11632
  }
11619
11633
  };
11620
11634
 
@@ -11638,7 +11652,7 @@ HashQueueMap.prototype = {
11638
11652
  * // create an injector
11639
11653
  * var $injector = angular.injector(['ng']);
11640
11654
  *
11641
- * // use the injector to kick of your application
11655
+ * // use the injector to kick off your application
11642
11656
  * // use the type inference to auto inject arguments, or use implicit injection
11643
11657
  * $injector.invoke(function($rootScope, $compile, $document){
11644
11658
  * $compile($document)($rootScope);
@@ -11658,7 +11672,7 @@ HashQueueMap.prototype = {
11658
11672
 
11659
11673
  var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
11660
11674
  var FN_ARG_SPLIT = /,/;
11661
- var FN_ARG = /^\s*(_?)(.+?)\1\s*$/;
11675
+ var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
11662
11676
  var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
11663
11677
  function annotate(fn) {
11664
11678
  var $inject,
@@ -12277,9 +12291,10 @@ function $AnchorScrollProvider() {
12277
12291
  // does not scroll when user clicks on anchor link that is currently on
12278
12292
  // (no url change, no $locaiton.hash() change), browser native does scroll
12279
12293
  if (autoScrollingEnabled) {
12280
- $rootScope.$watch(function() {return $location.hash();}, function() {
12281
- $rootScope.$evalAsync(scroll);
12282
- });
12294
+ $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
12295
+ function autoScrollWatchAction() {
12296
+ $rootScope.$evalAsync(scroll);
12297
+ });
12283
12298
  }
12284
12299
 
12285
12300
  return scroll;
@@ -12663,10 +12678,10 @@ function $BrowserProvider(){
12663
12678
  *
12664
12679
  * - `{object}` `info()` — Returns id, size, and options of cache.
12665
12680
  * - `{void}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache.
12666
- * - `{{*}} `get({string} key) — Returns cached value for `key` or undefined for cache miss.
12667
- * - `{void}` `remove({string} key) — Removes a key-value pair from the cache.
12668
- * - `{void}` `removeAll() — Removes all cached values.
12669
- * - `{void}` `destroy() — Removes references to this cache from $cacheFactory.
12681
+ * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
12682
+ * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
12683
+ * - `{void}` `removeAll()` — Removes all cached values.
12684
+ * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
12670
12685
  *
12671
12686
  */
12672
12687
  function $CacheFactoryProvider() {
@@ -12718,6 +12733,8 @@ function $CacheFactoryProvider() {
12718
12733
  remove: function(key) {
12719
12734
  var lruEntry = lruHash[key];
12720
12735
 
12736
+ if (!lruEntry) return;
12737
+
12721
12738
  if (lruEntry == freshEnd) freshEnd = lruEntry.p;
12722
12739
  if (lruEntry == staleEnd) staleEnd = lruEntry.n;
12723
12740
  link(lruEntry.n,lruEntry.p);
@@ -13125,26 +13142,26 @@ function $CompileProvider($provide) {
13125
13142
 
13126
13143
  //================================
13127
13144
 
13128
- function compile($compileNode, transcludeFn, maxPriority) {
13129
- if (!($compileNode instanceof jqLite)) {
13145
+ function compile($compileNodes, transcludeFn, maxPriority) {
13146
+ if (!($compileNodes instanceof jqLite)) {
13130
13147
  // jquery always rewraps, where as we need to preserve the original selector so that we can modify it.
13131
- $compileNode = jqLite($compileNode);
13148
+ $compileNodes = jqLite($compileNodes);
13132
13149
  }
13133
13150
  // We can not compile top level text elements since text nodes can be merged and we will
13134
13151
  // not be able to attach scope data to them, so we will wrap them in <span>
13135
- forEach($compileNode, function(node, index){
13152
+ forEach($compileNodes, function(node, index){
13136
13153
  if (node.nodeType == 3 /* text node */) {
13137
- $compileNode[index] = jqLite(node).wrap('<span></span>').parent()[0];
13154
+ $compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
13138
13155
  }
13139
13156
  });
13140
- var compositeLinkFn = compileNodes($compileNode, transcludeFn, $compileNode, maxPriority);
13141
- return function(scope, cloneConnectFn){
13157
+ var compositeLinkFn = compileNodes($compileNodes, transcludeFn, $compileNodes, maxPriority);
13158
+ return function publicLinkFn(scope, cloneConnectFn){
13142
13159
  assertArg(scope, 'scope');
13143
13160
  // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
13144
13161
  // and sometimes changes the structure of the DOM.
13145
13162
  var $linkNode = cloneConnectFn
13146
- ? JQLitePrototype.clone.call($compileNode) // IMPORTANT!!!
13147
- : $compileNode;
13163
+ ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
13164
+ : $compileNodes;
13148
13165
  $linkNode.data('$scope', scope);
13149
13166
  safeAddClass($linkNode, 'ng-scope');
13150
13167
  if (cloneConnectFn) cloneConnectFn($linkNode, scope);
@@ -13195,7 +13212,7 @@ function $CompileProvider($provide) {
13195
13212
  ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement)
13196
13213
  : null;
13197
13214
 
13198
- childLinkFn = (nodeLinkFn && nodeLinkFn.terminal)
13215
+ childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes.length)
13199
13216
  ? null
13200
13217
  : compileNodes(nodeList[i].childNodes,
13201
13218
  nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
@@ -13247,13 +13264,14 @@ function $CompileProvider($provide) {
13247
13264
 
13248
13265
 
13249
13266
  /**
13250
- * Looks for directives on the given node ands them to the directive collection which is sorted.
13267
+ * Looks for directives on the given node and adds them to the directive collection which is
13268
+ * sorted.
13251
13269
  *
13252
- * @param node node to search
13253
- * @param directives an array to which the directives are added to. This array is sorted before
13270
+ * @param node Node to search.
13271
+ * @param directives An array to which the directives are added to. This array is sorted before
13254
13272
  * the function returns.
13255
- * @param attrs the shared attrs object which is used to populate the normalized attributes.
13256
- * @param {number=} max directive priority
13273
+ * @param attrs The shared attrs object which is used to populate the normalized attributes.
13274
+ * @param {number=} maxPriority Max directive priority.
13257
13275
  */
13258
13276
  function collectDirectives(node, directives, attrs, maxPriority) {
13259
13277
  var nodeType = node.nodeType,
@@ -13288,7 +13306,7 @@ function $CompileProvider($provide) {
13288
13306
 
13289
13307
  // use class as directive
13290
13308
  className = node.className;
13291
- if (isString(className)) {
13309
+ if (isString(className) && className !== '') {
13292
13310
  while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
13293
13311
  nName = directiveNormalize(match[2]);
13294
13312
  if (addDirective(directives, nName, 'C', maxPriority)) {
@@ -13342,7 +13360,7 @@ function $CompileProvider($provide) {
13342
13360
  preLinkFns = [],
13343
13361
  postLinkFns = [],
13344
13362
  newScopeDirective = null,
13345
- newIsolatedScopeDirective = null,
13363
+ newIsolateScopeDirective = null,
13346
13364
  templateDirective = null,
13347
13365
  $compileNode = templateAttrs.$$element = jqLite(compileNode),
13348
13366
  directive,
@@ -13364,10 +13382,10 @@ function $CompileProvider($provide) {
13364
13382
  }
13365
13383
 
13366
13384
  if (directiveValue = directive.scope) {
13367
- assertNoDuplicate('isolated scope', newIsolatedScopeDirective, directive, $compileNode);
13385
+ assertNoDuplicate('isolated scope', newIsolateScopeDirective, directive, $compileNode);
13368
13386
  if (isObject(directiveValue)) {
13369
13387
  safeAddClass($compileNode, 'ng-isolate-scope');
13370
- newIsolatedScopeDirective = directive;
13388
+ newIsolateScopeDirective = directive;
13371
13389
  }
13372
13390
  safeAddClass($compileNode, 'ng-scope');
13373
13391
  newScopeDirective = newScopeDirective || directive;
@@ -13521,12 +13539,12 @@ function $CompileProvider($provide) {
13521
13539
  }
13522
13540
  $element = attrs.$$element;
13523
13541
 
13524
- if (newScopeDirective && isObject(newScopeDirective.scope)) {
13542
+ if (newIsolateScopeDirective) {
13525
13543
  var LOCAL_REGEXP = /^\s*([@=&])\s*(\w*)\s*$/;
13526
13544
 
13527
13545
  var parentScope = scope.$parent || scope;
13528
13546
 
13529
- forEach(newScopeDirective.scope, function(definiton, scopeName) {
13547
+ forEach(newIsolateScopeDirective.scope, function(definiton, scopeName) {
13530
13548
  var match = definiton.match(LOCAL_REGEXP) || [],
13531
13549
  attrName = match[2]|| scopeName,
13532
13550
  mode = match[1], // @, =, or &
@@ -13549,10 +13567,10 @@ function $CompileProvider($provide) {
13549
13567
  // reset the change, or we will throw this exception on every $digest
13550
13568
  lastValue = scope[scopeName] = parentGet(parentScope);
13551
13569
  throw Error(NON_ASSIGNABLE_MODEL_EXPRESSION + attrs[attrName] +
13552
- ' (directive: ' + newScopeDirective.name + ')');
13570
+ ' (directive: ' + newIsolateScopeDirective.name + ')');
13553
13571
  };
13554
13572
  lastValue = scope[scopeName] = parentGet(parentScope);
13555
- scope.$watch(function() {
13573
+ scope.$watch(function parentValueWatch() {
13556
13574
  var parentValue = parentGet(parentScope);
13557
13575
 
13558
13576
  if (parentValue !== scope[scopeName]) {
@@ -13562,7 +13580,7 @@ function $CompileProvider($provide) {
13562
13580
  lastValue = scope[scopeName] = parentValue;
13563
13581
  } else {
13564
13582
  // if the parent can be assigned then do so
13565
- parentSet(parentScope, lastValue = scope[scopeName]);
13583
+ parentSet(parentScope, parentValue = lastValue = scope[scopeName]);
13566
13584
  }
13567
13585
  }
13568
13586
  return parentValue;
@@ -13580,7 +13598,7 @@ function $CompileProvider($provide) {
13580
13598
 
13581
13599
  default: {
13582
13600
  throw Error('Invalid isolate scope definition for directive ' +
13583
- newScopeDirective.name + ': ' + definiton);
13601
+ newIsolateScopeDirective.name + ': ' + definiton);
13584
13602
  }
13585
13603
  }
13586
13604
  });
@@ -13714,7 +13732,7 @@ function $CompileProvider($provide) {
13714
13732
  origAsyncDirective = directives.shift(),
13715
13733
  // The fact that we have to copy and patch the directive seems wrong!
13716
13734
  derivedSyncDirective = extend({}, origAsyncDirective, {
13717
- controller: null, templateUrl: null, transclude: null
13735
+ controller: null, templateUrl: null, transclude: null, scope: null
13718
13736
  });
13719
13737
 
13720
13738
  $compileNode.html('');
@@ -13806,12 +13824,12 @@ function $CompileProvider($provide) {
13806
13824
  if (interpolateFn) {
13807
13825
  directives.push({
13808
13826
  priority: 0,
13809
- compile: valueFn(function(scope, node) {
13827
+ compile: valueFn(function textInterpolateLinkFn(scope, node) {
13810
13828
  var parent = node.parent(),
13811
13829
  bindings = parent.data('$binding') || [];
13812
13830
  bindings.push(interpolateFn);
13813
13831
  safeAddClass(parent.data('$binding', bindings), 'ng-binding');
13814
- scope.$watch(interpolateFn, function(value) {
13832
+ scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
13815
13833
  node[0].nodeValue = value;
13816
13834
  });
13817
13835
  })
@@ -13829,7 +13847,7 @@ function $CompileProvider($provide) {
13829
13847
 
13830
13848
  directives.push({
13831
13849
  priority: 100,
13832
- compile: valueFn(function(scope, element, attr) {
13850
+ compile: valueFn(function attrInterpolateLinkFn(scope, element, attr) {
13833
13851
  var $$observers = (attr.$$observers || (attr.$$observers = {}));
13834
13852
 
13835
13853
  if (name === 'class') {
@@ -13841,7 +13859,7 @@ function $CompileProvider($provide) {
13841
13859
  attr[name] = undefined;
13842
13860
  ($$observers[name] || ($$observers[name] = [])).$$inter = true;
13843
13861
  (attr.$$observers && attr.$$observers[name].$$scope || scope).
13844
- $watch(interpolateFn, function(value) {
13862
+ $watch(interpolateFn, function interpolateFnWatchAction(value) {
13845
13863
  attr.$set(name, value);
13846
13864
  });
13847
13865
  })
@@ -14839,6 +14857,7 @@ function $LocationProvider(){
14839
14857
  var changeCounter = 0;
14840
14858
  $rootScope.$watch(function $locationWatch() {
14841
14859
  var oldUrl = $browser.url();
14860
+ var currentReplace = $location.$$replace;
14842
14861
 
14843
14862
  if (!changeCounter || oldUrl != $location.absUrl()) {
14844
14863
  changeCounter++;
@@ -14847,12 +14866,12 @@ function $LocationProvider(){
14847
14866
  defaultPrevented) {
14848
14867
  $location.$$parse(oldUrl);
14849
14868
  } else {
14850
- $browser.url($location.absUrl(), $location.$$replace);
14851
- $location.$$replace = false;
14869
+ $browser.url($location.absUrl(), currentReplace);
14852
14870
  afterLocationChange(oldUrl);
14853
14871
  }
14854
14872
  });
14855
14873
  }
14874
+ $location.$$replace = false;
14856
14875
 
14857
14876
  return changeCounter;
14858
14877
  });
@@ -14983,7 +15002,15 @@ var OPERATORS = {
14983
15002
  'true':function(){return true;},
14984
15003
  'false':function(){return false;},
14985
15004
  undefined:noop,
14986
- '+':function(self, locals, a,b){a=a(self, locals); b=b(self, locals); return (isDefined(a)?a:0)+(isDefined(b)?b:0);},
15005
+ '+':function(self, locals, a,b){
15006
+ a=a(self, locals); b=b(self, locals);
15007
+ if (isDefined(a)) {
15008
+ if (isDefined(b)) {
15009
+ return a + b;
15010
+ }
15011
+ return a;
15012
+ }
15013
+ return isDefined(b)?b:undefined;},
14987
15014
  '-':function(self, locals, a,b){a=a(self, locals); b=b(self, locals); return (isDefined(a)?a:0)-(isDefined(b)?b:0);},
14988
15015
  '*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
14989
15016
  '/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
@@ -15878,7 +15905,7 @@ function $ParseProvider() {
15878
15905
  * alert('Success: ' + greeting);
15879
15906
  * }, function(reason) {
15880
15907
  * alert('Failed: ' + reason);
15881
- * );
15908
+ * });
15882
15909
  * </pre>
15883
15910
  *
15884
15911
  * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
@@ -16253,7 +16280,7 @@ function $RouteProvider(){
16253
16280
  * Object properties:
16254
16281
  *
16255
16282
  * - `controller` – `{(string|function()=}` – Controller fn that should be associated with newly
16256
- * created scope or the name of a {@link angular.Module#controller registered controller}
16283
+ * created scope or the name of a {@link angular.Module#controller registered controller}
16257
16284
  * if passed as a string.
16258
16285
  * - `template` – `{string=}` – html template as a string that should be used by
16259
16286
  * {@link ng.directive:ngView ngView} or
@@ -16264,7 +16291,7 @@ function $RouteProvider(){
16264
16291
  * - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
16265
16292
  * be injected into the controller. If any of these dependencies are promises, they will be
16266
16293
  * resolved and converted to a value before the controller is instantiated and the
16267
- * `$afterRouteChange` event is fired. The map object is:
16294
+ * `$routeChangeSuccess` event is fired. The map object is:
16268
16295
  *
16269
16296
  * - `key` – `{string}`: a name of a dependency to be injected into the controller.
16270
16297
  * - `factory` - `{string|function}`: If `string` then it is an alias for a service.
@@ -16598,7 +16625,7 @@ function $RouteProvider(){
16598
16625
 
16599
16626
  forEach(next.resolve || {}, function(value, key) {
16600
16627
  keys.push(key);
16601
- values.push(isFunction(value) ? $injector.invoke(value) : $injector.get(value));
16628
+ values.push(isString(value) ? $injector.get(value) : $injector.invoke(value));
16602
16629
  });
16603
16630
  if (isDefined(template = next.template)) {
16604
16631
  } else if (isDefined(template = next.templateUrl)) {
@@ -16869,9 +16896,9 @@ function $RootScopeProvider(){
16869
16896
  * the scope and its child scopes to be permanently detached from the parent and thus stop
16870
16897
  * participating in model change detection and listener notification by invoking.
16871
16898
  *
16872
- * @param {boolean} isolate if true then the scoped does not prototypically inherit from the
16873
- * parent scope. The scope is isolated, as it can not se parent scope properties.
16874
- * When creating widgets it is useful for the widget to not accidently read parent
16899
+ * @param {boolean} isolate if true then the scope does not prototypically inherit from the
16900
+ * parent scope. The scope is isolated, as it can not see parent scope properties.
16901
+ * When creating widgets it is useful for the widget to not accidentally read parent
16875
16902
  * state.
16876
16903
  *
16877
16904
  * @returns {Object} The newly created child scope.
@@ -16925,18 +16952,18 @@ function $RootScopeProvider(){
16925
16952
  * reruns when it detects changes the `watchExpression` can execute multiple times per
16926
16953
  * {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
16927
16954
  * - The `listener` is called only when the value from the current `watchExpression` and the
16928
- * previous call to `watchExpression' are not equal (with the exception of the initial run
16955
+ * previous call to `watchExpression` are not equal (with the exception of the initial run,
16929
16956
  * see below). The inequality is determined according to
16930
- * {@link angular.equals} function. To save the value of the object for later comparison
16957
+ * {@link angular.equals} function. To save the value of the object for later comparison, the
16931
16958
  * {@link angular.copy} function is used. It also means that watching complex options will
16932
16959
  * have adverse memory and performance implications.
16933
16960
  * - The watch `listener` may change the model, which may trigger other `listener`s to fire. This
16934
16961
  * is achieved by rerunning the watchers until no changes are detected. The rerun iteration
16935
- * limit is 100 to prevent infinity loop deadlock.
16962
+ * limit is 10 to prevent an infinite loop deadlock.
16936
16963
  *
16937
16964
  *
16938
16965
  * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
16939
- * you can register an `watchExpression` function with no `listener`. (Since `watchExpression`,
16966
+ * you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
16940
16967
  * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a change is
16941
16968
  * detected, be prepared for multiple calls to your listener.)
16942
16969
  *
@@ -16982,7 +17009,7 @@ function $RootScopeProvider(){
16982
17009
  * - `string`: Evaluated as {@link guide/expression expression}
16983
17010
  * - `function(newValue, oldValue, scope)`: called with current and previous values as parameters.
16984
17011
  *
16985
- * @param {boolean=} objectEquality Compare object for equality rather then for refference.
17012
+ * @param {boolean=} objectEquality Compare object for equality rather than for reference.
16986
17013
  * @returns {function()} Returns a deregistration function for this listener.
16987
17014
  */
16988
17015
  $watch: function(watchExp, listener, objectEquality) {
@@ -17157,7 +17184,7 @@ function $RootScopeProvider(){
17157
17184
  * @function
17158
17185
  *
17159
17186
  * @description
17160
- * Remove the current scope (and all of its children) from the parent scope. Removal implies
17187
+ * Removes the current scope (and all of its children) from the parent scope. Removal implies
17161
17188
  * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
17162
17189
  * propagate to the current scope and its children. Removal also implies that the current
17163
17190
  * scope is eligible for garbage collection.
@@ -17180,6 +17207,11 @@ function $RootScopeProvider(){
17180
17207
  if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
17181
17208
  if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
17182
17209
  if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
17210
+
17211
+ // This is bogus code that works around Chrome's GC leak
17212
+ // see: https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
17213
+ this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
17214
+ this.$$childTail = null;
17183
17215
  },
17184
17216
 
17185
17217
  /**
@@ -17190,7 +17222,7 @@ function $RootScopeProvider(){
17190
17222
  *
17191
17223
  * @description
17192
17224
  * Executes the `expression` on the current scope returning the result. Any exceptions in the
17193
- * expression are propagated (uncaught). This is useful when evaluating engular expressions.
17225
+ * expression are propagated (uncaught). This is useful when evaluating Angular expressions.
17194
17226
  *
17195
17227
  * # Example
17196
17228
  * <pre>
@@ -17311,7 +17343,7 @@ function $RootScopeProvider(){
17311
17343
  * @function
17312
17344
  *
17313
17345
  * @description
17314
- * Listen on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for discussion of
17346
+ * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for discussion of
17315
17347
  * event life cycle.
17316
17348
  *
17317
17349
  * @param {string} name Event name to listen on.
@@ -17321,13 +17353,13 @@ function $RootScopeProvider(){
17321
17353
  * The event listener function format is: `function(event, args...)`. The `event` object
17322
17354
  * passed into the listener has the following attributes:
17323
17355
  *
17324
- * - `targetScope` - {Scope}: the scope on which the event was `$emit`-ed or `$broadcast`-ed.
17325
- * - `currentScope` - {Scope}: the current scope which is handling the event.
17326
- * - `name` - {string}: Name of the event.
17327
- * - `stopPropagation` - {function=}: calling `stopPropagation` function will cancel further event propagation
17328
- * (available only for events that were `$emit`-ed).
17329
- * - `preventDefault` - {function}: calling `preventDefault` sets `defaultPrevented` flag to true.
17330
- * - `defaultPrevented` - {boolean}: true if `preventDefault` was called.
17356
+ * - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or `$broadcast`-ed.
17357
+ * - `currentScope` - `{Scope}`: the current scope which is handling the event.
17358
+ * - `name` - `{string}`: Name of the event.
17359
+ * - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel further event
17360
+ * propagation (available only for events that were `$emit`-ed).
17361
+ * - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag to true.
17362
+ * - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
17331
17363
  */
17332
17364
  $on: function(name, listener) {
17333
17365
  var namedListeners = this.$$listeners[name];
@@ -17337,7 +17369,7 @@ function $RootScopeProvider(){
17337
17369
  namedListeners.push(listener);
17338
17370
 
17339
17371
  return function() {
17340
- arrayRemove(namedListeners, listener);
17372
+ namedListeners[indexOf(namedListeners, listener)] = null;
17341
17373
  };
17342
17374
  },
17343
17375
 
@@ -17385,6 +17417,14 @@ function $RootScopeProvider(){
17385
17417
  namedListeners = scope.$$listeners[name] || empty;
17386
17418
  event.currentScope = scope;
17387
17419
  for (i=0, length=namedListeners.length; i<length; i++) {
17420
+
17421
+ // if listeners were deregistered, defragment the array
17422
+ if (!namedListeners[i]) {
17423
+ namedListeners.splice(i, 1);
17424
+ i--;
17425
+ length--;
17426
+ continue;
17427
+ }
17388
17428
  try {
17389
17429
  namedListeners[i].apply(null, listenerArgs);
17390
17430
  if (stopPropagation) return event;
@@ -17434,19 +17474,29 @@ function $RootScopeProvider(){
17434
17474
  },
17435
17475
  defaultPrevented: false
17436
17476
  },
17437
- listenerArgs = concat([event], arguments, 1);
17477
+ listenerArgs = concat([event], arguments, 1),
17478
+ listeners, i, length;
17438
17479
 
17439
17480
  //down while you can, then up and next sibling or up and next sibling until back at root
17440
17481
  do {
17441
17482
  current = next;
17442
17483
  event.currentScope = current;
17443
- forEach(current.$$listeners[name], function(listener) {
17484
+ listeners = current.$$listeners[name] || [];
17485
+ for (i=0, length = listeners.length; i<length; i++) {
17486
+ // if listeners were deregistered, defragment the array
17487
+ if (!listeners[i]) {
17488
+ listeners.splice(i, 1);
17489
+ i--;
17490
+ length--;
17491
+ continue;
17492
+ }
17493
+
17444
17494
  try {
17445
- listener.apply(null, listenerArgs);
17495
+ listeners[i].apply(null, listenerArgs);
17446
17496
  } catch(e) {
17447
17497
  $exceptionHandler(e);
17448
17498
  }
17449
- });
17499
+ }
17450
17500
 
17451
17501
  // Insanity Warning: scope depth-first traversal
17452
17502
  // yes, this code is a bit crazy, but it works and we have tests to prove it!
@@ -18554,7 +18604,7 @@ function $TimeoutProvider() {
18554
18604
  * @param {number=} [delay=0] Delay in milliseconds.
18555
18605
  * @param {boolean=} [invokeApply=true] If set to false skips model dirty checking, otherwise
18556
18606
  * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
18557
- * @returns {*} Promise that will be resolved when the timeout is reached. The value this
18607
+ * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
18558
18608
  * promise will be resolved with is the return value of the `fn` function.
18559
18609
  */
18560
18610
  function timeout(fn, delay, invokeApply) {
@@ -18993,9 +19043,18 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
18993
19043
  formatedText = '',
18994
19044
  parts = [];
18995
19045
 
19046
+ var hasExponent = false;
18996
19047
  if (numStr.indexOf('e') !== -1) {
18997
- formatedText = numStr;
18998
- } else {
19048
+ var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
19049
+ if (match && match[2] == '-' && match[3] > fractionSize + 1) {
19050
+ numStr = '0';
19051
+ } else {
19052
+ formatedText = numStr;
19053
+ hasExponent = true;
19054
+ }
19055
+ }
19056
+
19057
+ if (!hasExponent) {
18999
19058
  var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
19000
19059
 
19001
19060
  // determine fractionSize if it is not specified
@@ -19196,7 +19255,7 @@ dateFilter.$inject = ['$locale'];
19196
19255
  function dateFilter($locale) {
19197
19256
 
19198
19257
 
19199
- var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
19258
+ var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
19200
19259
  function jsonStringToDate(string){
19201
19260
  var match;
19202
19261
  if (match = string.match(R_ISO8601_STR)) {
@@ -19575,6 +19634,7 @@ var htmlAnchorDirective = valueFn({
19575
19634
  // if we have no href url, then don't navigate anywhere.
19576
19635
  if (!element.attr('href')) {
19577
19636
  event.preventDefault();
19637
+ return false; // Needed for opera
19578
19638
  }
19579
19639
  });
19580
19640
  }
@@ -19865,7 +19925,7 @@ forEach(BOOLEAN_ATTR, function(propName, attrName) {
19865
19925
  priority: 100,
19866
19926
  compile: function() {
19867
19927
  return function(scope, element, attr) {
19868
- scope.$watch(attr[normalized], function(value) {
19928
+ scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
19869
19929
  attr.$set(attrName, !!value);
19870
19930
  });
19871
19931
  };
@@ -19883,6 +19943,9 @@ forEach(['src', 'href'], function(attrName) {
19883
19943
  priority: 99, // it needs to run after the attributes are interpolated
19884
19944
  link: function(scope, element, attr) {
19885
19945
  attr.$observe(normalized, function(value) {
19946
+ if (!value)
19947
+ return;
19948
+
19886
19949
  attr.$set(attrName, value);
19887
19950
 
19888
19951
  // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
@@ -20011,6 +20074,7 @@ function FormController(element, attrs) {
20011
20074
  element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
20012
20075
  form.$dirty = true;
20013
20076
  form.$pristine = false;
20077
+ parentForm.$setDirty();
20014
20078
  };
20015
20079
 
20016
20080
  }
@@ -20196,7 +20260,10 @@ var inputType = {
20196
20260
  *
20197
20261
  * @param {string} ngModel Assignable angular expression to data-bind to.
20198
20262
  * @param {string=} name Property name of the form under which the control is published.
20199
- * @param {string=} required Sets `required` validation error key if the value is not entered.
20263
+ * @param {string=} required Adds `required` validation error key if the value is not entered.
20264
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20265
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20266
+ * `required` when you want to data-bind to the `required` attribute.
20200
20267
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
20201
20268
  * minlength.
20202
20269
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -20266,6 +20333,9 @@ var inputType = {
20266
20333
  * @param {string=} min Sets the `min` validation error key if the value entered is less then `min`.
20267
20334
  * @param {string=} max Sets the `max` validation error key if the value entered is greater then `min`.
20268
20335
  * @param {string=} required Sets `required` validation error key if the value is not entered.
20336
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20337
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20338
+ * `required` when you want to data-bind to the `required` attribute.
20269
20339
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
20270
20340
  * minlength.
20271
20341
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -20332,6 +20402,9 @@ var inputType = {
20332
20402
  * @param {string} ngModel Assignable angular expression to data-bind to.
20333
20403
  * @param {string=} name Property name of the form under which the control is published.
20334
20404
  * @param {string=} required Sets `required` validation error key if the value is not entered.
20405
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20406
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20407
+ * `required` when you want to data-bind to the `required` attribute.
20335
20408
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
20336
20409
  * minlength.
20337
20410
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -20397,6 +20470,9 @@ var inputType = {
20397
20470
  * @param {string} ngModel Assignable angular expression to data-bind to.
20398
20471
  * @param {string=} name Property name of the form under which the control is published.
20399
20472
  * @param {string=} required Sets `required` validation error key if the value is not entered.
20473
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20474
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20475
+ * `required` when you want to data-bind to the `required` attribute.
20400
20476
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
20401
20477
  * minlength.
20402
20478
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -20819,6 +20895,9 @@ function checkboxInputType(scope, element, attr, ctrl) {
20819
20895
  * @param {string} ngModel Assignable angular expression to data-bind to.
20820
20896
  * @param {string=} name Property name of the form under which the control is published.
20821
20897
  * @param {string=} required Sets `required` validation error key if the value is not entered.
20898
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20899
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20900
+ * `required` when you want to data-bind to the `required` attribute.
20822
20901
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
20823
20902
  * minlength.
20824
20903
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -20843,6 +20922,7 @@ function checkboxInputType(scope, element, attr, ctrl) {
20843
20922
  * @param {string} ngModel Assignable angular expression to data-bind to.
20844
20923
  * @param {string=} name Property name of the form under which the control is published.
20845
20924
  * @param {string=} required Sets `required` validation error key if the value is not entered.
20925
+ * @param {boolean=} ngRequired Sets `required` attribute if set to true
20846
20926
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
20847
20927
  * minlength.
20848
20928
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -21176,22 +21256,25 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
21176
21256
 
21177
21257
  // model -> value
21178
21258
  var ctrl = this;
21179
- $scope.$watch(ngModelGet, function(value) {
21180
21259
 
21181
- // ignore change from view
21182
- if (ctrl.$modelValue === value) return;
21260
+ $scope.$watch(function ngModelWatch() {
21261
+ var value = ngModelGet($scope);
21183
21262
 
21184
- var formatters = ctrl.$formatters,
21185
- idx = formatters.length;
21263
+ // if scope model value and ngModel value are out of sync
21264
+ if (ctrl.$modelValue !== value) {
21186
21265
 
21187
- ctrl.$modelValue = value;
21188
- while(idx--) {
21189
- value = formatters[idx](value);
21190
- }
21266
+ var formatters = ctrl.$formatters,
21267
+ idx = formatters.length;
21191
21268
 
21192
- if (ctrl.$viewValue !== value) {
21193
- ctrl.$viewValue = value;
21194
- ctrl.$render();
21269
+ ctrl.$modelValue = value;
21270
+ while(idx--) {
21271
+ value = formatters[idx](value);
21272
+ }
21273
+
21274
+ if (ctrl.$viewValue !== value) {
21275
+ ctrl.$viewValue = value;
21276
+ ctrl.$render();
21277
+ }
21195
21278
  }
21196
21279
  });
21197
21280
  }];
@@ -21340,7 +21423,7 @@ var requiredDirective = function() {
21340
21423
  * @name ng.directive:ngList
21341
21424
  *
21342
21425
  * @description
21343
- * Text input that converts between comma-seperated string into an array of strings.
21426
+ * Text input that converts between comma-separated string into an array of strings.
21344
21427
  *
21345
21428
  * @element input
21346
21429
  * @param {string=} ngList optional delimiter that should be used to split the value. If
@@ -21423,7 +21506,7 @@ var ngValueDirective = function() {
21423
21506
  };
21424
21507
  } else {
21425
21508
  return function(scope, elm, attr) {
21426
- scope.$watch(attr.ngValue, function(value) {
21509
+ scope.$watch(attr.ngValue, function valueWatchAction(value) {
21427
21510
  attr.$set('value', value, false);
21428
21511
  });
21429
21512
  };
@@ -21481,7 +21564,7 @@ var ngValueDirective = function() {
21481
21564
  */
21482
21565
  var ngBindDirective = ngDirective(function(scope, element, attr) {
21483
21566
  element.addClass('ng-binding').data('$binding', attr.ngBind);
21484
- scope.$watch(attr.ngBind, function(value) {
21567
+ scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
21485
21568
  element.text(value == undefined ? '' : value);
21486
21569
  });
21487
21570
  });
@@ -21564,7 +21647,7 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
21564
21647
  var ngBindHtmlUnsafeDirective = [function() {
21565
21648
  return function(scope, element, attr) {
21566
21649
  element.addClass('ng-binding').data('$binding', attr.ngBindHtmlUnsafe);
21567
- scope.$watch(attr.ngBindHtmlUnsafe, function(value) {
21650
+ scope.$watch(attr.ngBindHtmlUnsafe, function ngBindHtmlUnsafeWatchAction(value) {
21568
21651
  element.html(value || '');
21569
21652
  });
21570
21653
  };
@@ -21573,17 +21656,55 @@ var ngBindHtmlUnsafeDirective = [function() {
21573
21656
  function classDirective(name, selector) {
21574
21657
  name = 'ngClass' + name;
21575
21658
  return ngDirective(function(scope, element, attr) {
21576
- scope.$watch(attr[name], function(newVal, oldVal) {
21659
+
21660
+ scope.$watch(attr[name], ngClassWatchAction, true);
21661
+
21662
+ attr.$observe('class', function(value) {
21663
+ var ngClass = scope.$eval(attr[name]);
21664
+ ngClassWatchAction(ngClass, ngClass);
21665
+ });
21666
+
21667
+
21668
+ if (name !== 'ngClass') {
21669
+ scope.$watch('$index', function($index, old$index) {
21670
+ var mod = $index % 2;
21671
+ if (mod !== old$index % 2) {
21672
+ if (mod == selector) {
21673
+ addClass(scope.$eval(attr[name]));
21674
+ } else {
21675
+ removeClass(scope.$eval(attr[name]));
21676
+ }
21677
+ }
21678
+ });
21679
+ }
21680
+
21681
+
21682
+ function ngClassWatchAction(newVal, oldVal) {
21577
21683
  if (selector === true || scope.$index % 2 === selector) {
21578
21684
  if (oldVal && (newVal !== oldVal)) {
21579
- if (isObject(oldVal) && !isArray(oldVal))
21580
- oldVal = map(oldVal, function(v, k) { if (v) return k });
21581
- element.removeClass(isArray(oldVal) ? oldVal.join(' ') : oldVal);
21582
- }
21583
- if (isObject(newVal) && !isArray(newVal))
21584
- newVal = map(newVal, function(v, k) { if (v) return k });
21585
- if (newVal) element.addClass(isArray(newVal) ? newVal.join(' ') : newVal); }
21586
- }, true);
21685
+ removeClass(oldVal);
21686
+ }
21687
+ addClass(newVal);
21688
+ }
21689
+ }
21690
+
21691
+
21692
+ function removeClass(classVal) {
21693
+ if (isObject(classVal) && !isArray(classVal)) {
21694
+ classVal = map(classVal, function(v, k) { if (v) return k });
21695
+ }
21696
+ element.removeClass(isArray(classVal) ? classVal.join(' ') : classVal);
21697
+ }
21698
+
21699
+
21700
+ function addClass(classVal) {
21701
+ if (isObject(classVal) && !isArray(classVal)) {
21702
+ classVal = map(classVal, function(v, k) { if (v) return k });
21703
+ }
21704
+ if (classVal) {
21705
+ element.addClass(isArray(classVal) ? classVal.join(' ') : classVal);
21706
+ }
21707
+ }
21587
21708
  });
21588
21709
  }
21589
21710
 
@@ -22242,7 +22363,7 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
22242
22363
  element.html('');
22243
22364
  };
22244
22365
 
22245
- scope.$watch(srcExp, function(src) {
22366
+ scope.$watch(srcExp, function ngIncludeWatchAction(src) {
22246
22367
  var thisChangeId = ++changeCounter;
22247
22368
 
22248
22369
  if (src) {
@@ -22527,7 +22648,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
22527
22648
  offset + endSymbol));
22528
22649
  });
22529
22650
 
22530
- scope.$watch(function() {
22651
+ scope.$watch(function ngPluralizeWatch() {
22531
22652
  var value = parseFloat(scope.$eval(numberExp));
22532
22653
 
22533
22654
  if (!isNaN(value)) {
@@ -22538,7 +22659,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
22538
22659
  } else {
22539
22660
  return '';
22540
22661
  }
22541
- }, function(newVal) {
22662
+ }, function ngPluralizeWatchAction(newVal) {
22542
22663
  element.text(newVal);
22543
22664
  });
22544
22665
  }
@@ -22633,7 +22754,8 @@ var ngRepeatDirective = ngDirective({
22633
22754
  // We need an array of these objects since the same object can be returned from the iterator.
22634
22755
  // We expect this to be a rare case.
22635
22756
  var lastOrder = new HashQueueMap();
22636
- scope.$watch(function(scope){
22757
+
22758
+ scope.$watch(function ngRepeatWatch(scope){
22637
22759
  var index, length,
22638
22760
  collection = scope.$eval(rhs),
22639
22761
  collectionLength = size(collection, true),
@@ -22662,7 +22784,9 @@ var ngRepeatDirective = ngDirective({
22662
22784
  for (index = 0, length = array.length; index < length; index++) {
22663
22785
  key = (collection === array) ? index : array[index];
22664
22786
  value = collection[key];
22787
+
22665
22788
  last = lastOrder.shift(value);
22789
+
22666
22790
  if (last) {
22667
22791
  // if we have already seen this object, then we need to reuse the
22668
22792
  // associated scope/element
@@ -22759,7 +22883,7 @@ var ngRepeatDirective = ngDirective({
22759
22883
  */
22760
22884
  //TODO(misko): refactor to remove element from the DOM
22761
22885
  var ngShowDirective = ngDirective(function(scope, element, attr){
22762
- scope.$watch(attr.ngShow, function(value){
22886
+ scope.$watch(attr.ngShow, function ngShowWatchAction(value){
22763
22887
  element.css('display', toBoolean(value) ? '' : 'none');
22764
22888
  });
22765
22889
  });
@@ -22770,11 +22894,11 @@ var ngShowDirective = ngDirective(function(scope, element, attr){
22770
22894
  * @name ng.directive:ngHide
22771
22895
  *
22772
22896
  * @description
22773
- * The `ngHide` and `ngShow` directives hide or show a portion
22774
- * of the HTML conditionally.
22897
+ * The `ngHide` and `ngShow` directives hide or show a portion of the DOM tree (HTML)
22898
+ * conditionally.
22775
22899
  *
22776
22900
  * @element ANY
22777
- * @param {expression} ngHide If the {@link guide/expression expression} truthy then
22901
+ * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
22778
22902
  * the element is shown or hidden respectively.
22779
22903
  *
22780
22904
  * @example
@@ -22799,7 +22923,7 @@ var ngShowDirective = ngDirective(function(scope, element, attr){
22799
22923
  */
22800
22924
  //TODO(misko): refactor to remove element from the DOM
22801
22925
  var ngHideDirective = ngDirective(function(scope, element, attr){
22802
- scope.$watch(attr.ngHide, function(value){
22926
+ scope.$watch(attr.ngHide, function ngHideWatchAction(value){
22803
22927
  element.css('display', toBoolean(value) ? 'none' : '');
22804
22928
  });
22805
22929
  });
@@ -22842,7 +22966,7 @@ var ngHideDirective = ngDirective(function(scope, element, attr){
22842
22966
  </example>
22843
22967
  */
22844
22968
  var ngStyleDirective = ngDirective(function(scope, element, attr) {
22845
- scope.$watch(attr.ngStyle, function(newStyles, oldStyles) {
22969
+ scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
22846
22970
  if (oldStyles && (newStyles !== oldStyles)) {
22847
22971
  forEach(oldStyles, function(val, style) { element.css(style, '');});
22848
22972
  }
@@ -22922,7 +23046,7 @@ var ngSwitchDirective = valueFn({
22922
23046
  selectedElement,
22923
23047
  selectedScope;
22924
23048
 
22925
- scope.$watch(watchExpr, function(value) {
23049
+ scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
22926
23050
  if (selectedElement) {
22927
23051
  selectedScope.$destroy();
22928
23052
  selectedElement.remove();
@@ -23256,6 +23380,9 @@ var scriptDirective = ['$templateCache', function($templateCache) {
23256
23380
  *
23257
23381
  * @param {string} name assignable expression to data-bind to.
23258
23382
  * @param {string=} required The control is considered valid only if value is entered.
23383
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
23384
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
23385
+ * `required` when you want to data-bind to the `required` attribute.
23259
23386
  * @param {comprehension_expression=} ngOptions in one of the following forms:
23260
23387
  *
23261
23388
  * * for array data sources:
@@ -23496,7 +23623,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
23496
23623
 
23497
23624
  // we have to do it on each watch since ngModel watches reference, but
23498
23625
  // we need to work of an array, so we need to see if anything was inserted/removed
23499
- scope.$watch(function() {
23626
+ scope.$watch(function selectMultipleWatch() {
23500
23627
  if (!equals(lastView, ctrl.$viewValue)) {
23501
23628
  lastView = copy(ctrl.$viewValue);
23502
23629
  ctrl.$render();
@@ -23613,7 +23740,8 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
23613
23740
  selected,
23614
23741
  selectedSet = false, // nothing is selected yet
23615
23742
  lastElement,
23616
- element;
23743
+ element,
23744
+ label;
23617
23745
 
23618
23746
  if (multiple) {
23619
23747
  selectedSet = new HashMap(modelValue);
@@ -23637,9 +23765,11 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
23637
23765
  selected = modelValue === valueFn(scope, locals);
23638
23766
  selectedSet = selectedSet || selected; // see if at least one item is selected
23639
23767
  }
23768
+ label = displayFn(scope, locals); // what will be seen by the user
23769
+ label = label === undefined ? '' : label; // doing displayFn(scope, locals) || '' overwrites zero values
23640
23770
  optionGroup.push({
23641
23771
  id: keyName ? keys[index] : index, // either the index into array or key from object
23642
- label: displayFn(scope, locals) || '', // what will be seen by the user
23772
+ label: label,
23643
23773
  selected: selected // determine if we should be selected
23644
23774
  });
23645
23775
  }
@@ -23771,7 +23901,7 @@ var optionDirective = ['$interpolate', function($interpolate) {
23771
23901
  }
23772
23902
 
23773
23903
  if (interpolateFn) {
23774
- scope.$watch(interpolateFn, function(newVal, oldVal) {
23904
+ scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
23775
23905
  attr.$set('value', newVal);
23776
23906
  if (newVal !== oldVal) selectCtrl.removeOption(oldVal);
23777
23907
  selectCtrl.addOption(newVal);
@@ -24086,10 +24216,11 @@ function browserTrigger(element, type, keys) {
24086
24216
  iframe = _jQuery('#application iframe')[0],
24087
24217
  appWindow = iframe ? iframe.contentWindow : window,
24088
24218
  fakeProcessDefault = true,
24089
- finalProcessDefault;
24219
+ finalProcessDefault,
24220
+ angular = appWindow.angular || {};
24090
24221
 
24091
24222
  // igor: temporary fix for https://bugzilla.mozilla.org/show_bug.cgi?id=684208
24092
- appWindow.angular['ff-684208-preventDefault'] = false;
24223
+ angular['ff-684208-preventDefault'] = false;
24093
24224
  evnt.preventDefault = function() {
24094
24225
  fakeProcessDefault = false;
24095
24226
  return originalPreventDefault.apply(evnt, arguments);
@@ -24099,9 +24230,9 @@ function browserTrigger(element, type, keys) {
24099
24230
  pressed('shift'), pressed('meta'), 0, element);
24100
24231
 
24101
24232
  element.dispatchEvent(evnt);
24102
- finalProcessDefault = !(appWindow.angular['ff-684208-preventDefault'] || !fakeProcessDefault);
24233
+ finalProcessDefault = !(angular['ff-684208-preventDefault'] || !fakeProcessDefault);
24103
24234
 
24104
- delete appWindow.angular['ff-684208-preventDefault'];
24235
+ delete angular['ff-684208-preventDefault'];
24105
24236
 
24106
24237
  return finalProcessDefault;
24107
24238
  }
@@ -24637,6 +24768,9 @@ angular.scenario.ObjectModel = function(runner) {
24637
24768
  self.emit('StepError', it, modelStep, error);
24638
24769
  });
24639
24770
 
24771
+ runner.on('RunnerBegin', function() {
24772
+ self.emit('RunnerBegin');
24773
+ });
24640
24774
  runner.on('RunnerEnd', function() {
24641
24775
  self.emit('RunnerEnd');
24642
24776
  });
@@ -25276,7 +25410,9 @@ angular.scenario.SpecRunner.prototype.addFutureAction = function(name, behavior,
25276
25410
  });
25277
25411
  var result = $document.find(selector);
25278
25412
  if (selector.match(NG)) {
25279
- result = result.add(selector.replace(NG, '[ng-'), $document);
25413
+ angular.forEach(['[ng-','[data-ng-','[x-ng-'], function(value, index){
25414
+ result = result.add(selector.replace(NG, value), $document);
25415
+ });
25280
25416
  }
25281
25417
  if (!result.length) {
25282
25418
  throw {