angular-gem 1.1.2 → 1.1.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.
Files changed (29) hide show
  1. data/README.md +9 -2
  2. data/Rakefile +86 -19
  3. data/lib/angular-gem/version.rb +1 -1
  4. data/lib/generators/angular/resource_helpers.rb +13 -13
  5. data/test/dummy/log/test.log +1 -3
  6. data/test/dummy/tmp/cache/assets/{DF8/FD0/sprockets%2F87b01decd5c7fd3c6f174b8cba0d810f → D65/250/sprockets%2F54a960d46bb0b354e8bd46fa03f5e0e4} +0 -0
  7. data/test/dummy/tmp/cache/assets/{D73/C00/sprockets%2Fa3620dc4bbd0562669b546e9c58eede4 → D6A/FB0/sprockets%2F92721e9941b77adcfdfba3d060622de2} +0 -0
  8. data/test/dummy/tmp/cache/assets/E07/040/sprockets%2Ff55b8ce9d0f28ce36b768a1c7aeb2ef3 +0 -0
  9. data/test/test_helper.rb +3 -0
  10. data/vendor/assets/javascripts/1.0.5/angular-1.0.5.js +14733 -0
  11. data/vendor/assets/javascripts/1.0.5/angular-resource-1.0.5.js +445 -0
  12. data/vendor/assets/javascripts/1.0.5/angular-sanitize-1.0.5.js +535 -0
  13. data/{test/dummy/tmp/cache/assets/CF7/120/sprockets%2Fd6adf41113c67a57c4a1330845ba0d08 → vendor/assets/javascripts/1.1.2/angular-1.1.2.js} +0 -0
  14. data/vendor/assets/javascripts/1.1.2/angular-resource-1.1.2.js +472 -0
  15. data/vendor/assets/javascripts/1.1.2/angular-sanitize-1.1.2.js +556 -0
  16. data/{test/dummy/tmp/cache/assets/CD5/C60/sprockets%2F4348b099c4aadda10262e757261e0f81 → vendor/assets/javascripts/1.1.3/angular-1.1.3.js} +0 -0
  17. data/vendor/assets/javascripts/1.1.3/angular-resource-1.1.3.js +507 -0
  18. data/vendor/assets/javascripts/1.1.3/angular-sanitize-1.1.3.js +556 -0
  19. data/vendor/assets/javascripts/angular-resource-unstable.js +507 -0
  20. data/vendor/assets/javascripts/angular-resource.js +23 -50
  21. data/vendor/assets/javascripts/angular-sanitize-unstable.js +556 -0
  22. data/vendor/assets/javascripts/angular-sanitize.js +4 -25
  23. data/{test/dummy/tmp/cache/assets/CE3/300/sprockets%2Fc11999ba09d72e745355212e48bc72dd → vendor/assets/javascripts/angular-unstable.js} +0 -0
  24. data/vendor/assets/javascripts/angular.js +305 -454
  25. metadata +53 -21
  26. data/test/dummy/tmp/cache/assets/D71/060/sprockets%2Fc434a3f93ecb87049eb12e766005fede +0 -0
  27. data/test/dummy/tmp/cache/assets/D79/F40/sprockets%2F9088cfe323d1b81dd526e6a9e3ed358c +0 -0
  28. data/test/dummy/tmp/cache/assets/D9E/830/sprockets%2Fbb7eb0f50f1afed5705594e9d812b8d0 +0 -0
  29. data/test/dummy/tmp/cache/assets/DD4/250/sprockets%2Feaa70f0d0954a5edffe77c9ca1e93860 +0 -0
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.1.2
2
+ * @license AngularJS v1.0.5
3
3
  * (c) 2010-2012 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -129,7 +129,7 @@ var START_TAG_REGEXP = /^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:
129
129
  BEGING_END_TAGE_REGEXP = /^<\s*\//,
130
130
  COMMENT_REGEXP = /<!--(.*?)-->/g,
131
131
  CDATA_REGEXP = /<!\[CDATA\[(.*?)]]>/g,
132
- URI_REGEXP = /^((ftp|https?):\/\/|mailto:|tel:|#)/,
132
+ URI_REGEXP = /^((ftp|https?):\/\/|mailto:|#)/,
133
133
  NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g; // Match everything outside of normal chars and " (quote character)
134
134
 
135
135
 
@@ -432,7 +432,6 @@ angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($san
432
432
  * plain email address links.
433
433
  *
434
434
  * @param {string} text Input text.
435
- * @param {string} target Window (_blank|_self|_parent|_top) or named frame to open links in.
436
435
  * @returns {string} Html-linkified text.
437
436
  *
438
437
  * @usage
@@ -449,7 +448,6 @@ angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($san
449
448
  'mailto:us@somewhere.org,\n'+
450
449
  'another@somewhere.org,\n'+
451
450
  'and one more: ftp://127.0.0.1/.';
452
- $scope.snippetWithTarget = 'http://angularjs.org/';
453
451
  }
454
452
  </script>
455
453
  <div ng-controller="Ctrl">
@@ -469,15 +467,6 @@ angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($san
469
467
  <div ng-bind-html="snippet | linky"></div>
470
468
  </td>
471
469
  </tr>
472
- <tr id="linky-target">
473
- <td>linky target</td>
474
- <td>
475
- <pre>&lt;div ng-bind-html="snippetWithTarget | linky:'_blank'"&gt;<br>&lt;/div&gt;</pre>
476
- </td>
477
- <td>
478
- <div ng-bind-html="snippetWithTarget | linky:'_blank'"></div>
479
- </td>
480
- </tr>
481
470
  <tr id="escaped-html">
482
471
  <td>no filter</td>
483
472
  <td><pre>&lt;div ng-bind="snippet"&gt;<br>&lt;/div&gt;</pre></td>
@@ -510,11 +499,6 @@ angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($san
510
499
  toBe('new <a href="http://link">http://link</a>.');
511
500
  expect(using('#escaped-html').binding('snippet')).toBe('new http://link.');
512
501
  });
513
-
514
- it('should work with the target property', function() {
515
- expect(using('#linky-target').binding("snippetWithTarget | linky:'_blank'")).
516
- toBe('<a target="_blank" href="http://angularjs.org/">http://angularjs.org/</a>');
517
- });
518
502
  </doc:scenario>
519
503
  </doc:example>
520
504
  */
@@ -522,7 +506,7 @@ angular.module('ngSanitize').filter('linky', function() {
522
506
  var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.\;\,\(\)\{\}\<\>]/,
523
507
  MAILTO_REGEXP = /^mailto:/;
524
508
 
525
- return function(text, target) {
509
+ return function(text) {
526
510
  if (!text) return text;
527
511
  var match;
528
512
  var raw = text;
@@ -531,10 +515,6 @@ angular.module('ngSanitize').filter('linky', function() {
531
515
  var writer = htmlSanitizeWriter(html);
532
516
  var url;
533
517
  var i;
534
- var properties = {};
535
- if (angular.isDefined(target)) {
536
- properties.target = target;
537
- }
538
518
  while ((match = raw.match(LINKY_URL_REGEXP))) {
539
519
  // We can not end in these as they are sometimes found at the end of the sentence
540
520
  url = match[0];
@@ -542,8 +522,7 @@ angular.module('ngSanitize').filter('linky', function() {
542
522
  if (match[2] == match[3]) url = 'mailto:' + url;
543
523
  i = match.index;
544
524
  writer.chars(raw.substr(0, i));
545
- properties.href = url;
546
- writer.start('a', properties);
525
+ writer.start('a', {href:url});
547
526
  writer.chars(match[0].replace(MAILTO_REGEXP, ''));
548
527
  writer.end('a');
549
528
  raw = raw.substring(i + match[0].length);
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.1.2
2
+ * @license AngularJS v1.0.5
3
3
  * (c) 2010-2012 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -55,8 +55,7 @@ if ('i' !== 'I'.toLowerCase()) {
55
55
  function fromCharCode(code) {return String.fromCharCode(code);}
56
56
 
57
57
 
58
- var Error = window.Error,
59
- /** holds major version number for IE or NaN for real browsers */
58
+ var /** holds major version number for IE or NaN for real browsers */
60
59
  msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]),
61
60
  jqLite, // delay binding since jQuery could be loaded after us.
62
61
  jQuery, // delay binding
@@ -97,6 +96,30 @@ var Error = window.Error,
97
96
  * @param {Object=} context Object to become context (`this`) for the iterator function.
98
97
  * @returns {Object|Array} Reference to `obj`.
99
98
  */
99
+
100
+
101
+ /**
102
+ * @private
103
+ * @param {*} obj
104
+ * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...)
105
+ */
106
+ function isArrayLike(obj) {
107
+ if (!obj || (typeof obj.length !== 'number')) return false;
108
+
109
+ // We have on object which has length property. Should we treat it as array?
110
+ if (typeof obj.hasOwnProperty != 'function' &&
111
+ typeof obj.constructor != 'function') {
112
+ // This is here for IE8: it is a bogus object treat it as array;
113
+ return true;
114
+ } else {
115
+ return obj instanceof JQLite || // JQLite
116
+ (jQuery && obj instanceof jQuery) || // jQuery
117
+ toString.call(obj) !== '[object Object]' || // some browser native object
118
+ typeof obj.callee === 'function'; // arguments (on IE8 looks like regular obj)
119
+ }
120
+ }
121
+
122
+
100
123
  function forEach(obj, iterator, context) {
101
124
  var key;
102
125
  if (obj) {
@@ -108,7 +131,7 @@ function forEach(obj, iterator, context) {
108
131
  }
109
132
  } else if (obj.forEach && obj.forEach !== forEach) {
110
133
  obj.forEach(iterator, context);
111
- } else if (isObject(obj) && isNumber(obj.length)) {
134
+ } else if (isArrayLike(obj)) {
112
135
  for (key = 0; key < obj.length; key++)
113
136
  iterator.call(context, obj[key], key);
114
137
  } else {
@@ -153,7 +176,7 @@ function reverseParams(iteratorFn) {
153
176
  /**
154
177
  * A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
155
178
  * characters such as '012ABC'. The reason why we are not using simply a number counter is that
156
- * the number string gets longer over time, and it can also overflow, where as the the nextId
179
+ * the number string gets longer over time, and it can also overflow, where as the nextId
157
180
  * will grow much slower, it is a string, and it will never overflow.
158
181
  *
159
182
  * @returns an unique alpha-numeric string
@@ -549,9 +572,7 @@ function copy(source, destination){
549
572
  } else {
550
573
  if (source === destination) throw Error("Can't copy equivalent objects or arrays");
551
574
  if (isArray(source)) {
552
- while(destination.length) {
553
- destination.pop();
554
- }
575
+ destination.length = 0;
555
576
  for ( var i = 0; i < source.length; i++) {
556
577
  destination.push(copy(source[i]));
557
578
  }
@@ -762,9 +783,18 @@ function startingTag(element) {
762
783
  // are not allowed to have children. So we just ignore it.
763
784
  element.html('');
764
785
  } catch(e) {}
765
- return jqLite('<div>').append(element).html().
766
- match(/^(<[^>]+>)/)[1].
767
- replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
786
+ // As Per DOM Standards
787
+ var TEXT_NODE = 3;
788
+ var elemHtml = jqLite('<div>').append(element).html();
789
+ try {
790
+ return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) :
791
+ elemHtml.
792
+ match(/^(<[^>]+>)/)[1].
793
+ replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
794
+ } catch(e) {
795
+ return lowercase(elemHtml);
796
+ }
797
+
768
798
  }
769
799
 
770
800
 
@@ -848,7 +878,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
848
878
  * Use this directive to auto-bootstrap on application. Only
849
879
  * one directive can be used per HTML document. The directive
850
880
  * designates the root of the application and is typically placed
851
- * ot the root of the page.
881
+ * at the root of the page.
852
882
  *
853
883
  * In the example below if the `ngApp` directive would not be placed
854
884
  * on the `html` element then the document would not be compiled
@@ -1249,11 +1279,11 @@ function setupModuleLoader(window) {
1249
1279
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
1250
1280
  */
1251
1281
  var version = {
1252
- full: '1.1.2', // all of these placeholder strings will be replaced by rake's
1282
+ full: '1.0.5', // all of these placeholder strings will be replaced by rake's
1253
1283
  major: 1, // compile task
1254
- minor: 1,
1255
- dot: 2,
1256
- codeName: 'tofu-animation'
1284
+ minor: 0,
1285
+ dot: 5,
1286
+ codeName: 'flatulent-propulsion'
1257
1287
  };
1258
1288
 
1259
1289
 
@@ -1719,11 +1749,11 @@ var JQLitePrototype = JQLite.prototype = {
1719
1749
  // value on get.
1720
1750
  //////////////////////////////////////////
1721
1751
  var BOOLEAN_ATTR = {};
1722
- forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
1752
+ forEach('multiple,selected,checked,disabled,readOnly,required'.split(','), function(value) {
1723
1753
  BOOLEAN_ATTR[lowercase(value)] = value;
1724
1754
  });
1725
1755
  var BOOLEAN_ELEMENTS = {};
1726
- forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
1756
+ forEach('input,select,option,textarea,button,form'.split(','), function(value) {
1727
1757
  BOOLEAN_ELEMENTS[uppercase(value)] = true;
1728
1758
  });
1729
1759
 
@@ -2025,9 +2055,8 @@ forEach({
2025
2055
 
2026
2056
  append: function(element, node) {
2027
2057
  forEach(new JQLite(node), function(child){
2028
- if (element.nodeType === 1 || element.nodeType === 11) {
2058
+ if (element.nodeType === 1)
2029
2059
  element.appendChild(child);
2030
- }
2031
2060
  });
2032
2061
  },
2033
2062
 
@@ -2431,7 +2460,7 @@ function annotate(fn) {
2431
2460
  * This method does not work with code minfication / obfuscation. For this reason the following annotation strategies
2432
2461
  * are supported.
2433
2462
  *
2434
- * # The `$injector` property
2463
+ * # The `$inject` property
2435
2464
  *
2436
2465
  * If a function has an `$inject` property and its value is an array of strings, then the strings represent names of
2437
2466
  * services to be injected into the function.
@@ -2649,10 +2678,9 @@ function createInjector(modulesToLoad) {
2649
2678
  decorator: decorator
2650
2679
  }
2651
2680
  },
2652
- providerInjector = (providerCache.$injector =
2653
- createInternalInjector(providerCache, function() {
2654
- throw Error("Unknown provider: " + path.join(' <- '));
2655
- })),
2681
+ providerInjector = createInternalInjector(providerCache, function() {
2682
+ throw Error("Unknown provider: " + path.join(' <- '));
2683
+ }),
2656
2684
  instanceCache = {},
2657
2685
  instanceInjector = (instanceCache.$injector =
2658
2686
  createInternalInjector(instanceCache, function(servicename) {
@@ -2729,7 +2757,9 @@ function createInjector(modulesToLoad) {
2729
2757
  try {
2730
2758
  for(var invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
2731
2759
  var invokeArgs = invokeQueue[i],
2732
- provider = providerInjector.get(invokeArgs[0]);
2760
+ provider = invokeArgs[0] == '$injector'
2761
+ ? providerInjector
2762
+ : providerInjector.get(invokeArgs[0]);
2733
2763
 
2734
2764
  provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
2735
2765
  }
@@ -3144,7 +3174,7 @@ function Browser(window, document, $log, $sniffer) {
3144
3174
  */
3145
3175
  self.baseHref = function() {
3146
3176
  var href = baseElement.attr('href');
3147
- return href ? href.replace(/^https?\:\/\/[^\/]*/, '') : href;
3177
+ return href ? href.replace(/^https?\:\/\/[^\/]*/, '') : '';
3148
3178
  };
3149
3179
 
3150
3180
  //////////////////////////////////////////////////////////////
@@ -3284,7 +3314,7 @@ function $BrowserProvider(){
3284
3314
  * @returns {object} Newly created cache object with the following set of methods:
3285
3315
  *
3286
3316
  * - `{object}` `info()` — Returns id, size, and options of cache.
3287
- * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns it.
3317
+ * - `{void}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache.
3288
3318
  * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
3289
3319
  * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
3290
3320
  * - `{void}` `removeAll()` — Removes all cached values.
@@ -3323,8 +3353,6 @@ function $CacheFactoryProvider() {
3323
3353
  if (size > capacity) {
3324
3354
  this.remove(staleEnd.key);
3325
3355
  }
3326
-
3327
- return value;
3328
3356
  },
3329
3357
 
3330
3358
 
@@ -3596,7 +3624,8 @@ function $CompileProvider($provide) {
3596
3624
  Suffix = 'Directive',
3597
3625
  COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
3598
3626
  CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
3599
- MULTI_ROOT_TEMPLATE_ERROR = 'Template must have exactly one root element. was: ';
3627
+ MULTI_ROOT_TEMPLATE_ERROR = 'Template must have exactly one root element. was: ',
3628
+ urlSanitizationWhitelist = /^\s*(https?|ftp|mailto):/;
3600
3629
 
3601
3630
 
3602
3631
  /**
@@ -3650,11 +3679,41 @@ function $CompileProvider($provide) {
3650
3679
  };
3651
3680
 
3652
3681
 
3682
+ /**
3683
+ * @ngdoc function
3684
+ * @name ng.$compileProvider#urlSanitizationWhitelist
3685
+ * @methodOf ng.$compileProvider
3686
+ * @function
3687
+ *
3688
+ * @description
3689
+ * Retrieves or overrides the default regular expression that is used for whitelisting of safe
3690
+ * urls during a[href] sanitization.
3691
+ *
3692
+ * The sanitization is a security measure aimed at prevent XSS attacks via html links.
3693
+ *
3694
+ * Any url about to be assigned to a[href] via data-binding is first normalized and turned into an
3695
+ * absolute url. Afterwards the url is matched against the `urlSanitizationWhitelist` regular
3696
+ * expression. If a match is found the original url is written into the dom. Otherwise the
3697
+ * absolute url is prefixed with `'unsafe:'` string and only then it is written into the DOM.
3698
+ *
3699
+ * @param {RegExp=} regexp New regexp to whitelist urls with.
3700
+ * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
3701
+ * chaining otherwise.
3702
+ */
3703
+ this.urlSanitizationWhitelist = function(regexp) {
3704
+ if (isDefined(regexp)) {
3705
+ urlSanitizationWhitelist = regexp;
3706
+ return this;
3707
+ }
3708
+ return urlSanitizationWhitelist;
3709
+ };
3710
+
3711
+
3653
3712
  this.$get = [
3654
3713
  '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
3655
- '$controller', '$rootScope',
3714
+ '$controller', '$rootScope', '$document',
3656
3715
  function($injector, $interpolate, $exceptionHandler, $http, $templateCache, $parse,
3657
- $controller, $rootScope) {
3716
+ $controller, $rootScope, $document) {
3658
3717
 
3659
3718
  var Attributes = function(element, attr) {
3660
3719
  this.$$element = element;
@@ -3676,7 +3735,8 @@ function $CompileProvider($provide) {
3676
3735
  */
3677
3736
  $set: function(key, value, writeAttr, attrName) {
3678
3737
  var booleanKey = getBooleanAttrName(this.$$element[0], key),
3679
- $$observers = this.$$observers;
3738
+ $$observers = this.$$observers,
3739
+ normalizedVal;
3680
3740
 
3681
3741
  if (booleanKey) {
3682
3742
  this.$$element.prop(key, value);
@@ -3695,6 +3755,19 @@ function $CompileProvider($provide) {
3695
3755
  }
3696
3756
  }
3697
3757
 
3758
+
3759
+ // sanitize a[href] values
3760
+ if (nodeName_(this.$$element[0]) === 'A' && key === 'href') {
3761
+ urlSanitizationNode.setAttribute('href', value);
3762
+
3763
+ // href property always returns normalized absolute url, so we can match against that
3764
+ normalizedVal = urlSanitizationNode.href;
3765
+ if (!normalizedVal.match(urlSanitizationWhitelist)) {
3766
+ this[key] = value = 'unsafe:' + normalizedVal;
3767
+ }
3768
+ }
3769
+
3770
+
3698
3771
  if (writeAttr !== false) {
3699
3772
  if (value === null || value === undefined) {
3700
3773
  this.$$element.removeAttr(attrName);
@@ -3738,7 +3811,8 @@ function $CompileProvider($provide) {
3738
3811
  }
3739
3812
  };
3740
3813
 
3741
- var startSymbol = $interpolate.startSymbol(),
3814
+ var urlSanitizationNode = $document[0].createElement('a'),
3815
+ startSymbol = $interpolate.startSymbol(),
3742
3816
  endSymbol = $interpolate.endSymbol(),
3743
3817
  denormalizeTemplate = (startSymbol == '{{' || endSymbol == '}}')
3744
3818
  ? identity
@@ -3771,7 +3845,14 @@ function $CompileProvider($provide) {
3771
3845
  var $linkNode = cloneConnectFn
3772
3846
  ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
3773
3847
  : $compileNodes;
3774
- $linkNode.data('$scope', scope);
3848
+
3849
+ // Attach scope only to non-text nodes.
3850
+ for(var i = 0, ii = $linkNode.length; i<ii; i++) {
3851
+ var node = $linkNode[i];
3852
+ if (node.nodeType == 1 /* element */ || node.nodeType == 9 /* document */) {
3853
+ $linkNode.eq(i).data('$scope', scope);
3854
+ }
3855
+ }
3775
3856
  safeAddClass($linkNode, 'ng-scope');
3776
3857
  if (cloneConnectFn) cloneConnectFn($linkNode, scope);
3777
3858
  if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode);
@@ -3861,6 +3942,7 @@ function $CompileProvider($provide) {
3861
3942
  (function(transcludeFn) {
3862
3943
  return function(cloneFn) {
3863
3944
  var transcludeScope = scope.$new();
3945
+ transcludeScope.$$transcluded = true;
3864
3946
 
3865
3947
  return transcludeFn(transcludeScope, cloneFn).
3866
3948
  bind('$destroy', bind(transcludeScope, transcludeScope.$destroy));
@@ -4166,6 +4248,8 @@ function $CompileProvider($provide) {
4166
4248
  lastValue,
4167
4249
  parentGet, parentSet;
4168
4250
 
4251
+ scope.$$isolateBindings[scopeName] = mode + attrName;
4252
+
4169
4253
  switch (mode) {
4170
4254
 
4171
4255
  case '@': {
@@ -4376,7 +4460,7 @@ function $CompileProvider($provide) {
4376
4460
  }
4377
4461
 
4378
4462
  directives.unshift(derivedSyncDirective);
4379
- afterTemplateNodeLinkFn = applyDirectivesToNode(directives, $compileNode, tAttrs, childTranscludeFn);
4463
+ afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, childTranscludeFn);
4380
4464
  afterTemplateChildLinkFn = compileNodes($compileNode.contents(), childTranscludeFn);
4381
4465
 
4382
4466
 
@@ -4456,10 +4540,10 @@ function $CompileProvider($provide) {
4456
4540
  function addAttrInterpolateDirective(node, directives, value, name) {
4457
4541
  var interpolateFn = $interpolate(value, true);
4458
4542
 
4459
-
4460
4543
  // no interpolation found -> ignore
4461
4544
  if (!interpolateFn) return;
4462
4545
 
4546
+
4463
4547
  directives.push({
4464
4548
  priority: 100,
4465
4549
  compile: valueFn(function attrInterpolateLinkFn(scope, element, attr) {
@@ -4754,7 +4838,7 @@ function $InterpolateProvider() {
4754
4838
  };
4755
4839
 
4756
4840
 
4757
- this.$get = ['$parse', '$exceptionHandler', function($parse, $exceptionHandler) {
4841
+ this.$get = ['$parse', function($parse) {
4758
4842
  var startSymbolLength = startSymbol.length,
4759
4843
  endSymbolLength = endSymbol.length;
4760
4844
 
@@ -4826,24 +4910,18 @@ function $InterpolateProvider() {
4826
4910
  if (!mustHaveExpression || hasInterpolation) {
4827
4911
  concat.length = length;
4828
4912
  fn = function(context) {
4829
- try {
4830
- for(var i = 0, ii = length, part; i<ii; i++) {
4831
- if (typeof (part = parts[i]) == 'function') {
4832
- part = part(context);
4833
- if (part == null || part == undefined) {
4834
- part = '';
4835
- } else if (typeof part != 'string') {
4836
- part = toJson(part);
4837
- }
4913
+ for(var i = 0, ii = length, part; i<ii; i++) {
4914
+ if (typeof (part = parts[i]) == 'function') {
4915
+ part = part(context);
4916
+ if (part == null || part == undefined) {
4917
+ part = '';
4918
+ } else if (typeof part != 'string') {
4919
+ part = toJson(part);
4838
4920
  }
4839
- concat[i] = part;
4840
4921
  }
4841
- return concat.join('');
4842
- }
4843
- catch(err) {
4844
- var newErr = new Error('Error while interpolating: ' + text + '\n' + err.toString());
4845
- $exceptionHandler(newErr);
4922
+ concat[i] = part;
4846
4923
  }
4924
+ return concat.join('');
4847
4925
  };
4848
4926
  fn.exp = text;
4849
4927
  fn.parts = parts;
@@ -5539,33 +5617,7 @@ function $LocationProvider(){
5539
5617
  </example>
5540
5618
  */
5541
5619
 
5542
- /**
5543
- * @ngdoc object
5544
- * @name ng.$logProvider
5545
- * @description
5546
- * Use the `$logProvider` to configure how the application logs messages
5547
- */
5548
5620
  function $LogProvider(){
5549
- var debug = true,
5550
- self = this;
5551
-
5552
- /**
5553
- * @ngdoc property
5554
- * @name ng.$logProvider#debugEnabled
5555
- * @methodOf ng.$logProvider
5556
- * @description
5557
- * @param {string=} flag enable or disable debug level messages
5558
- * @returns {*} current value if used as getter or itself (chaining) if used as setter
5559
- */
5560
- this.debugEnabled = function(flag) {
5561
- if (isDefined(flag)) {
5562
- debug = flag;
5563
- return this;
5564
- } else {
5565
- return debug;
5566
- }
5567
- };
5568
-
5569
5621
  this.$get = ['$window', function($window){
5570
5622
  return {
5571
5623
  /**
@@ -5606,25 +5658,7 @@ function $LogProvider(){
5606
5658
  * @description
5607
5659
  * Write an error message
5608
5660
  */
5609
- error: consoleLog('error'),
5610
-
5611
- /**
5612
- * @ngdoc method
5613
- * @name ng.$log#debug
5614
- * @methodOf ng.$log
5615
- *
5616
- * @description
5617
- * Write a debug message
5618
- */
5619
- debug: (function () {
5620
- var fn = consoleLog('debug');
5621
-
5622
- return function() {
5623
- if (debug) {
5624
- fn.apply(self, arguments);
5625
- }
5626
- }
5627
- }())
5661
+ error: consoleLog('error')
5628
5662
  };
5629
5663
 
5630
5664
  function formatError(arg) {
@@ -5683,8 +5717,6 @@ var OPERATORS = {
5683
5717
  '%':function(self, locals, a,b){return a(self, locals)%b(self, locals);},
5684
5718
  '^':function(self, locals, a,b){return a(self, locals)^b(self, locals);},
5685
5719
  '=':noop,
5686
- '===':function(self, locals, a, b){return a(self, locals)===b(self, locals);},
5687
- '!==':function(self, locals, a, b){return a(self, locals)!==b(self, locals);},
5688
5720
  '==':function(self, locals, a,b){return a(self, locals)==b(self, locals);},
5689
5721
  '!=':function(self, locals, a,b){return a(self, locals)!=b(self, locals);},
5690
5722
  '<':function(self, locals, a,b){return a(self, locals)<b(self, locals);},
@@ -5735,14 +5767,9 @@ function lex(text, csp){
5735
5767
  continue;
5736
5768
  } else {
5737
5769
  var ch2 = ch + peek(),
5738
- ch3 = ch2 + peek(2),
5739
5770
  fn = OPERATORS[ch],
5740
- fn2 = OPERATORS[ch2],
5741
- fn3 = OPERATORS[ch3];
5742
- if (fn3) {
5743
- tokens.push({index:index, text:ch3, fn:fn3});
5744
- index += 3;
5745
- } else if (fn2) {
5771
+ fn2 = OPERATORS[ch2];
5772
+ if (fn2) {
5746
5773
  tokens.push({index:index, text:ch2, fn:fn2});
5747
5774
  index += 2;
5748
5775
  } else if (fn) {
@@ -5764,9 +5791,8 @@ function lex(text, csp){
5764
5791
  return chars.indexOf(lastCh) != -1;
5765
5792
  }
5766
5793
 
5767
- function peek(i) {
5768
- var num = i || 1;
5769
- return index + num < text.length ? text.charAt(index + num) : false;
5794
+ function peek() {
5795
+ return index + 1 < text.length ? text.charAt(index + 1) : false;
5770
5796
  }
5771
5797
  function isNumber(ch) {
5772
5798
  return '0' <= ch && ch <= '9';
@@ -6127,7 +6153,7 @@ function parser(text, json, $filter, csp){
6127
6153
  function equality() {
6128
6154
  var left = relational();
6129
6155
  var token;
6130
- if ((token = expect('==','!=','===','!=='))) {
6156
+ if ((token = expect('==','!='))) {
6131
6157
  left = binaryFn(left, token.fn, equality());
6132
6158
  }
6133
6159
  return left;
@@ -6511,9 +6537,10 @@ function getterFn(path, csp) {
6511
6537
  * @param {string} expression String expression to compile.
6512
6538
  * @returns {function(context, locals)} a function which represents the compiled expression:
6513
6539
  *
6514
- * * `context`: an object against which any expressions embedded in the strings are evaluated
6515
- * against (Topically a scope object).
6516
- * * `locals`: local variables context object, useful for overriding values in `context`.
6540
+ * * `context` – `{object}` – an object against which any expressions embedded in the strings
6541
+ * are evaluated against (tipically a scope object).
6542
+ * * `locals` – `{object=}` – local variables context object, useful for overriding values in
6543
+ * `context`.
6517
6544
  *
6518
6545
  * The return function also has an `assign` property, if the expression is assignable, which
6519
6546
  * allows one to set values to expressions.
@@ -6549,7 +6576,7 @@ function $ParseProvider() {
6549
6576
  * interface for interacting with an object that represents the result of an action that is
6550
6577
  * performed asynchronously, and may or may not be finished at any given point in time.
6551
6578
  *
6552
- * From the perspective of dealing with error handling, deferred and promise apis are to
6579
+ * From the perspective of dealing with error handling, deferred and promise APIs are to
6553
6580
  * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
6554
6581
  *
6555
6582
  * <pre>
@@ -6584,7 +6611,7 @@ function $ParseProvider() {
6584
6611
  *
6585
6612
  * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
6586
6613
  * comes in the way of
6587
- * [guarantees that promise and deferred apis make](https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md).
6614
+ * [guarantees that promise and deferred APIs make](https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md).
6588
6615
  *
6589
6616
  * Additionally the promise api allows for composition that is very hard to do with the
6590
6617
  * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
@@ -6596,7 +6623,7 @@ function $ParseProvider() {
6596
6623
  *
6597
6624
  * A new instance of deferred is constructed by calling `$q.defer()`.
6598
6625
  *
6599
- * The purpose of the deferred object is to expose the associated Promise instance as well as apis
6626
+ * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
6600
6627
  * that can be used for signaling the successful or unsuccessful completion of the task.
6601
6628
  *
6602
6629
  * **Methods**
@@ -6639,7 +6666,7 @@ function $ParseProvider() {
6639
6666
  * return result + 1;
6640
6667
  * });
6641
6668
  *
6642
- * // promiseB will be resolved immediately after promiseA is resolved and it's value will be
6669
+ * // promiseB will be resolved immediately after promiseA is resolved and its value will be
6643
6670
  * // the result of promiseA incremented by 1
6644
6671
  * </pre>
6645
6672
  *
@@ -6664,7 +6691,7 @@ function $ParseProvider() {
6664
6691
  * # Testing
6665
6692
  *
6666
6693
  * <pre>
6667
- * it('should simulate promise', inject(function($q, $rootSCope) {
6694
+ * it('should simulate promise', inject(function($q, $rootScope) {
6668
6695
  * var deferred = $q.defer();
6669
6696
  * var promise = deferred.promise;
6670
6697
  * var resolvedValue;
@@ -6673,7 +6700,7 @@ function $ParseProvider() {
6673
6700
  * expect(resolvedValue).toBeUndefined();
6674
6701
  *
6675
6702
  * // Simulate resolving of promise
6676
- * defered.resolve(123);
6703
+ * deferred.resolve(123);
6677
6704
  * // Note that the 'then' function does not get called synchronously.
6678
6705
  * // This is because we want the promise API to always be async, whether or not
6679
6706
  * // it got called synchronously or asynchronously.
@@ -6849,12 +6876,12 @@ function qFactory(nextTick, exceptionHandler) {
6849
6876
  * @methodOf ng.$q
6850
6877
  * @description
6851
6878
  * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
6852
- * This is useful when you are dealing with on object that might or might not be a promise, or if
6879
+ * This is useful when you are dealing with an object that might or might not be a promise, or if
6853
6880
  * the promise comes from a source that can't be trusted.
6854
6881
  *
6855
6882
  * @param {*} value Value or a promise
6856
6883
  * @returns {Promise} Returns a single promise that will be resolved with an array of values,
6857
- * each value coresponding to the promise at the same index in the `promises` array. If any of
6884
+ * each value corresponding to the promise at the same index in the `promises` array. If any of
6858
6885
  * the promises is resolved with a rejection, this resulting promise will be resolved with the
6859
6886
  * same rejection.
6860
6887
  */
@@ -6916,7 +6943,7 @@ function qFactory(nextTick, exceptionHandler) {
6916
6943
  *
6917
6944
  * @param {Array.<Promise>} promises An array of promises.
6918
6945
  * @returns {Promise} Returns a single promise that will be resolved with an array of values,
6919
- * each value coresponding to the promise at the same index in the `promises` array. If any of
6946
+ * each value corresponding to the promise at the same index in the `promises` array. If any of
6920
6947
  * the promises is resolved with a rejection, this resulting promise will be resolved with the
6921
6948
  * same rejection.
6922
6949
  */
@@ -6985,24 +7012,12 @@ function $RouteProvider(){
6985
7012
  * - `controller` – `{(string|function()=}` – Controller fn that should be associated with newly
6986
7013
  * created scope or the name of a {@link angular.Module#controller registered controller}
6987
7014
  * if passed as a string.
6988
- * - `template` – `{string=|function()=}` – html template as a string or function that returns
6989
- * an html template as a string which should be used by {@link ng.directive:ngView ngView} or
7015
+ * - `template` – `{string=}` – html template as a string that should be used by
7016
+ * {@link ng.directive:ngView ngView} or
6990
7017
  * {@link ng.directive:ngInclude ngInclude} directives.
6991
- * This property takes precedence over `templateUrl`.
6992
- *
6993
- * If `template` is a function, it will be called with the following parameters:
6994
- *
6995
- * - `{Array.<Object>}` - route parameters extracted from the current
6996
- * `$location.path()` by applying the current route
6997
- *
6998
- * - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
6999
- * template that should be used by {@link ng.directive:ngView ngView}.
7000
- *
7001
- * If `templateUrl` is a function, it will be called with the following parameters:
7002
- *
7003
- * - `{Array.<Object>}` - route parameters extracted from the current
7004
- * `$location.path()` by applying the current route
7005
- *
7018
+ * this property takes precedence over `templateUrl`.
7019
+ * - `templateUrl` – `{string=}` – path to an html template that should be used by
7020
+ * {@link ng.directive:ngView ngView}.
7006
7021
  * - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
7007
7022
  * be injected into the controller. If any of these dependencies are promises, they will be
7008
7023
  * resolved and converted to a value before the controller is instantiated and the
@@ -7357,18 +7372,9 @@ function $RouteProvider(){
7357
7372
  values.push(isString(value) ? $injector.get(value) : $injector.invoke(value));
7358
7373
  });
7359
7374
  if (isDefined(template = next.template)) {
7360
- if (isFunction(template)) {
7361
- template = template(next.params);
7362
- }
7363
7375
  } else if (isDefined(template = next.templateUrl)) {
7364
- if (isFunction(template)) {
7365
- template = template(next.params);
7366
- }
7367
- if (isDefined(template)) {
7368
- next.loadedTemplateUrl = template;
7369
- template = $http.get(template, {cache: $templateCache}).
7370
- then(function(response) { return response.data; });
7371
- }
7376
+ template = $http.get(template, {cache: $templateCache}).
7377
+ then(function(response) { return response.data; });
7372
7378
  }
7373
7379
  if (isDefined(template)) {
7374
7380
  keys.push('$template');
@@ -7606,6 +7612,7 @@ function $RootScopeProvider(){
7606
7612
  this.$$destroyed = false;
7607
7613
  this.$$asyncQueue = [];
7608
7614
  this.$$listeners = {};
7615
+ this.$$isolateBindings = {};
7609
7616
  }
7610
7617
 
7611
7618
  /**
@@ -7665,6 +7672,7 @@ function $RootScopeProvider(){
7665
7672
  child['this'] = child;
7666
7673
  child.$$listeners = {};
7667
7674
  child.$parent = this;
7675
+ child.$$asyncQueue = [];
7668
7676
  child.$$watchers = child.$$nextSibling = child.$$childHead = child.$$childTail = null;
7669
7677
  child.$$prevSibling = this.$$childTail;
7670
7678
  if (this.$$childHead) {
@@ -7831,7 +7839,7 @@ function $RootScopeProvider(){
7831
7839
  $digest: function() {
7832
7840
  var watch, value, last,
7833
7841
  watchers,
7834
- asyncQueue = this.$$asyncQueue,
7842
+ asyncQueue,
7835
7843
  length,
7836
7844
  dirty, ttl = TTL,
7837
7845
  next, current, target = this,
@@ -7840,19 +7848,18 @@ function $RootScopeProvider(){
7840
7848
 
7841
7849
  beginPhase('$digest');
7842
7850
 
7843
- do { // "while dirty" loop
7851
+ do {
7844
7852
  dirty = false;
7845
7853
  current = target;
7846
-
7847
- while(asyncQueue.length) {
7848
- try {
7849
- current.$eval(asyncQueue.shift());
7850
- } catch (e) {
7851
- $exceptionHandler(e);
7854
+ do {
7855
+ asyncQueue = current.$$asyncQueue;
7856
+ while(asyncQueue.length) {
7857
+ try {
7858
+ current.$eval(asyncQueue.shift());
7859
+ } catch (e) {
7860
+ $exceptionHandler(e);
7861
+ }
7852
7862
  }
7853
- }
7854
-
7855
- do { // "traverse the scopes" loop
7856
7863
  if ((watchers = current.$$watchers)) {
7857
7864
  // process our watches
7858
7865
  length = watchers.length;
@@ -8087,10 +8094,6 @@ function $RootScopeProvider(){
8087
8094
  * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for discussion of
8088
8095
  * event life cycle.
8089
8096
  *
8090
- * @param {string} name Event name to listen on.
8091
- * @param {function(event)} listener Function to call when the event is emitted.
8092
- * @returns {function()} Returns a deregistration function for this listener.
8093
- *
8094
8097
  * The event listener function format is: `function(event, args...)`. The `event` object
8095
8098
  * passed into the listener has the following attributes:
8096
8099
  *
@@ -8101,6 +8104,10 @@ function $RootScopeProvider(){
8101
8104
  * propagation (available only for events that were `$emit`-ed).
8102
8105
  * - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag to true.
8103
8106
  * - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
8107
+ *
8108
+ * @param {string} name Event name to listen on.
8109
+ * @param {function(event, args...)} listener Function to call when the event is emitted.
8110
+ * @returns {function()} Returns a deregistration function for this listener.
8104
8111
  */
8105
8112
  $on: function(name, listener) {
8106
8113
  var namedListeners = this.$$listeners[name];
@@ -8278,7 +8285,7 @@ function $RootScopeProvider(){
8278
8285
 
8279
8286
  /**
8280
8287
  * function used as an initial value for watchers.
8281
- * because it's uniqueue we can easily tell it apart from other values
8288
+ * because it's unique we can easily tell it apart from other values
8282
8289
  */
8283
8290
  function initWatchVal() {}
8284
8291
  }];
@@ -8289,7 +8296,6 @@ function $RootScopeProvider(){
8289
8296
  *
8290
8297
  * @name ng.$sniffer
8291
8298
  * @requires $window
8292
- * @requires $document
8293
8299
  *
8294
8300
  * @property {boolean} history Does the browser support html5 history api ?
8295
8301
  * @property {boolean} hashchange Does the browser support hashchange event ?
@@ -8298,10 +8304,9 @@ function $RootScopeProvider(){
8298
8304
  * This is very simple implementation of testing browser's features.
8299
8305
  */
8300
8306
  function $SnifferProvider() {
8301
- this.$get = ['$window', '$document', function($window, $document) {
8307
+ this.$get = ['$window', function($window) {
8302
8308
  var eventSupport = {},
8303
- android = int((/android (\d+)/.exec(lowercase($window.navigator.userAgent)) || [])[1]),
8304
- document = $document[0];
8309
+ android = int((/android (\d+)/.exec(lowercase($window.navigator.userAgent)) || [])[1]);
8305
8310
 
8306
8311
  return {
8307
8312
  // Android has history.pushState, but it does not update location correctly
@@ -8311,7 +8316,7 @@ function $SnifferProvider() {
8311
8316
  history: !!($window.history && $window.history.pushState && !(android < 4)),
8312
8317
  hashchange: 'onhashchange' in $window &&
8313
8318
  // IE8 compatible mode lies
8314
- (!document.documentMode || document.documentMode > 7),
8319
+ (!$window.document.documentMode || $window.document.documentMode > 7),
8315
8320
  hasEvent: function(event) {
8316
8321
  // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
8317
8322
  // it. In particular the event is not fired when backspace or delete key are pressed or
@@ -8319,13 +8324,14 @@ function $SnifferProvider() {
8319
8324
  if (event == 'input' && msie == 9) return false;
8320
8325
 
8321
8326
  if (isUndefined(eventSupport[event])) {
8322
- var divElm = document.createElement('div');
8327
+ var divElm = $window.document.createElement('div');
8323
8328
  eventSupport[event] = 'on' + event in divElm;
8324
8329
  }
8325
8330
 
8326
8331
  return eventSupport[event];
8327
8332
  },
8328
- csp: document.securityPolicy ? document.securityPolicy.isActive : false
8333
+ // TODO(i): currently there is no way to feature detect CSP without triggering alerts
8334
+ csp: false
8329
8335
  };
8330
8336
  }];
8331
8337
  }
@@ -8386,43 +8392,6 @@ function parseHeaders(headers) {
8386
8392
  }
8387
8393
 
8388
8394
 
8389
- var IS_SAME_DOMAIN_URL_MATCH = /^(([^:]+):)?\/\/(\w+:{0,1}\w*@)?([\w\.-]*)?(:([0-9]+))?(.*)$/;
8390
-
8391
-
8392
- /**
8393
- * Parse a request and location URL and determine whether this is a same-domain request.
8394
- *
8395
- * @param {string} requestUrl The url of the request.
8396
- * @param {string} locationUrl The current browser location url.
8397
- * @returns {boolean} Whether the request is for the same domain.
8398
- */
8399
- function isSameDomain(requestUrl, locationUrl) {
8400
- var match = IS_SAME_DOMAIN_URL_MATCH.exec(requestUrl);
8401
- // if requestUrl is relative, the regex does not match.
8402
- if (match == null) return true;
8403
-
8404
- var domain1 = {
8405
- protocol: match[2],
8406
- host: match[4],
8407
- port: int(match[6]) || DEFAULT_PORTS[match[2]] || null,
8408
- // IE8 sets unmatched groups to '' instead of undefined.
8409
- relativeProtocol: match[2] === undefined || match[2] === ''
8410
- };
8411
-
8412
- match = URL_MATCH.exec(locationUrl);
8413
- var domain2 = {
8414
- protocol: match[1],
8415
- host: match[3],
8416
- port: int(match[5]) || DEFAULT_PORTS[match[1]] || null
8417
- };
8418
-
8419
- return (domain1.protocol == domain2.protocol || domain1.relativeProtocol) &&
8420
- domain1.host == domain2.host &&
8421
- (domain1.port == domain2.port || (domain1.relativeProtocol &&
8422
- domain2.port == DEFAULT_PORTS[domain2.protocol]));
8423
- }
8424
-
8425
-
8426
8395
  /**
8427
8396
  * Returns a function that provides access to parsed headers.
8428
8397
  *
@@ -8482,7 +8451,7 @@ function $HttpProvider() {
8482
8451
  JSON_END = /[\}\]]\s*$/,
8483
8452
  PROTECTION_PREFIX = /^\)\]\}',?\n/;
8484
8453
 
8485
- var defaults = this.defaults = {
8454
+ var $config = this.defaults = {
8486
8455
  // transform incoming response data
8487
8456
  transformResponse: [function(data) {
8488
8457
  if (isString(data)) {
@@ -8502,7 +8471,8 @@ function $HttpProvider() {
8502
8471
  // default headers
8503
8472
  headers: {
8504
8473
  common: {
8505
- 'Accept': 'application/json, text/plain, */*'
8474
+ 'Accept': 'application/json, text/plain, */*',
8475
+ 'X-Requested-With': 'XMLHttpRequest'
8506
8476
  },
8507
8477
  post: {'Content-Type': 'application/json;charset=utf-8'},
8508
8478
  put: {'Content-Type': 'application/json;charset=utf-8'}
@@ -8608,6 +8578,7 @@ function $HttpProvider() {
8608
8578
  *
8609
8579
  * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
8610
8580
  * - `Accept: application/json, text/plain, * / *`
8581
+ * - `X-Requested-With: XMLHttpRequest`
8611
8582
  * - `$httpProvider.defaults.headers.post`: (header defaults for HTTP POST requests)
8612
8583
  * - `Content-Type: application/json`
8613
8584
  * - `$httpProvider.defaults.headers.put` (header defaults for HTTP PUT requests)
@@ -8742,7 +8713,7 @@ function $HttpProvider() {
8742
8713
  * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
8743
8714
  * called `XSRF-TOKEN` and sets it as the HTTP header `X-XSRF-TOKEN`. Since only JavaScript that
8744
8715
  * runs on your domain could read the cookie, your server can be assured that the XHR came from
8745
- * JavaScript running on your domain. The header will not be set for cross-domain requests.
8716
+ * JavaScript running on your domain.
8746
8717
  *
8747
8718
  * To take advantage of this, your server needs to set a token in a JavaScript readable session
8748
8719
  * cookie called `XSRF-TOKEN` on first HTTP GET request. On subsequent non-GET requests the
@@ -8776,8 +8747,6 @@ function $HttpProvider() {
8776
8747
  * - **withCredentials** - `{boolean}` - whether to to set the `withCredentials` flag on the
8777
8748
  * XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5
8778
8749
  * requests with credentials} for more information.
8779
- * - **responseType** - `{string}` - see {@link
8780
- * https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}.
8781
8750
  *
8782
8751
  * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
8783
8752
  * standard `then` method and two http specific methods: `success` and `error`. The `then`
@@ -8870,12 +8839,10 @@ function $HttpProvider() {
8870
8839
  function $http(config) {
8871
8840
  config.method = uppercase(config.method);
8872
8841
 
8873
- var reqTransformFn = config.transformRequest || defaults.transformRequest,
8874
- respTransformFn = config.transformResponse || defaults.transformResponse,
8875
- defHeaders = defaults.headers,
8876
- xsrfToken = isSameDomain(config.url, $browser.url()) ?
8877
- $browser.cookies()['XSRF-TOKEN'] : undefined,
8878
- reqHeaders = extend({'X-XSRF-TOKEN': xsrfToken},
8842
+ var reqTransformFn = config.transformRequest || $config.transformRequest,
8843
+ respTransformFn = config.transformResponse || $config.transformResponse,
8844
+ defHeaders = $config.headers,
8845
+ reqHeaders = extend({'X-XSRF-TOKEN': $browser.cookies()['XSRF-TOKEN']},
8879
8846
  defHeaders.common, defHeaders[lowercase(config.method)], config.headers),
8880
8847
  reqData = transformData(config.data, headersGetter(reqHeaders), reqTransformFn),
8881
8848
  promise;
@@ -8885,10 +8852,6 @@ function $HttpProvider() {
8885
8852
  delete reqHeaders['Content-Type'];
8886
8853
  }
8887
8854
 
8888
- if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
8889
- config.withCredentials = defaults.withCredentials;
8890
- }
8891
-
8892
8855
  // send request
8893
8856
  promise = sendReq(config, reqData, reqHeaders);
8894
8857
 
@@ -9020,11 +8983,11 @@ function $HttpProvider() {
9020
8983
  *
9021
8984
  * @description
9022
8985
  * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
9023
- * default headers, withCredentials as well as request and response transformations.
8986
+ * default headers as well as request and response transformations.
9024
8987
  *
9025
8988
  * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
9026
8989
  */
9027
- $http.defaults = defaults;
8990
+ $http.defaults = $config;
9028
8991
 
9029
8992
 
9030
8993
  return $http;
@@ -9059,7 +9022,7 @@ function $HttpProvider() {
9059
9022
  * Makes the request
9060
9023
  *
9061
9024
  * !!! ACCESSES CLOSURE VARS:
9062
- * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
9025
+ * $httpBackend, $config, $log, $rootScope, defaultCache, $http.pendingRequests
9063
9026
  */
9064
9027
  function sendReq(config, reqData, reqHeaders) {
9065
9028
  var deferred = $q.defer(),
@@ -9100,7 +9063,7 @@ function $HttpProvider() {
9100
9063
  // if we won't have the response in cache, send the request to the backend
9101
9064
  if (!cachedResp) {
9102
9065
  $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
9103
- config.withCredentials, config.responseType);
9066
+ config.withCredentials);
9104
9067
  }
9105
9068
 
9106
9069
  return promise;
@@ -9155,15 +9118,10 @@ function $HttpProvider() {
9155
9118
  var parts = [];
9156
9119
  forEachSorted(params, function(value, key) {
9157
9120
  if (value == null || value == undefined) return;
9158
- if (!isArray(value)) value = [value];
9159
-
9160
- forEach(value, function(v) {
9161
- if (isObject(v)) {
9162
- v = toJson(v);
9163
- }
9164
- parts.push(encodeURIComponent(key) + '=' +
9165
- encodeURIComponent(v));
9166
- });
9121
+ if (isObject(value)) {
9122
+ value = toJson(value);
9123
+ }
9124
+ parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
9167
9125
  });
9168
9126
  return url + ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
9169
9127
  }
@@ -9205,7 +9163,7 @@ function $HttpBackendProvider() {
9205
9163
 
9206
9164
  function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument, locationProtocol) {
9207
9165
  // TODO(vojta): fix the signature
9208
- return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
9166
+ return function(method, url, post, callback, headers, timeout, withCredentials) {
9209
9167
  $browser.$$incOutstandingRequestCount();
9210
9168
  url = url || $browser.url();
9211
9169
 
@@ -9238,8 +9196,30 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
9238
9196
  // always async
9239
9197
  xhr.onreadystatechange = function() {
9240
9198
  if (xhr.readyState == 4) {
9241
- completeRequest(callback, status || xhr.status, xhr.response || xhr.responseText,
9242
- xhr.getAllResponseHeaders());
9199
+ var responseHeaders = xhr.getAllResponseHeaders();
9200
+
9201
+ // TODO(vojta): remove once Firefox 21 gets released.
9202
+ // begin: workaround to overcome Firefox CORS http response headers bug
9203
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=608735
9204
+ // Firefox already patched in nightly. Should land in Firefox 21.
9205
+
9206
+ // CORS "simple response headers" http://www.w3.org/TR/cors/
9207
+ var value,
9208
+ simpleHeaders = ["Cache-Control", "Content-Language", "Content-Type",
9209
+ "Expires", "Last-Modified", "Pragma"];
9210
+ if (!responseHeaders) {
9211
+ responseHeaders = "";
9212
+ forEach(simpleHeaders, function (header) {
9213
+ var value = xhr.getResponseHeader(header);
9214
+ if (value) {
9215
+ responseHeaders += header + ": " + value + "\n";
9216
+ }
9217
+ });
9218
+ }
9219
+ // end of the workaround.
9220
+
9221
+ completeRequest(callback, status || xhr.status, xhr.responseText,
9222
+ responseHeaders);
9243
9223
  }
9244
9224
  };
9245
9225
 
@@ -9247,10 +9227,6 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
9247
9227
  xhr.withCredentials = true;
9248
9228
  }
9249
9229
 
9250
- if (responseType) {
9251
- xhr.responseType = responseType;
9252
- }
9253
-
9254
9230
  xhr.send(post || '');
9255
9231
 
9256
9232
  if (timeout > 0) {
@@ -9642,7 +9618,7 @@ function $FilterProvider($provide) {
9642
9618
  */
9643
9619
  function filterFilter() {
9644
9620
  return function(array, expression) {
9645
- if (!(array instanceof Array)) return array;
9621
+ if (!isArray(array)) return array;
9646
9622
  var predicates = [];
9647
9623
  predicates.check = function(value) {
9648
9624
  for (var j = 0; j < predicates.length; j++) {
@@ -9891,7 +9867,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
9891
9867
  fraction += '0';
9892
9868
  }
9893
9869
 
9894
- if (fractionSize) formatedText += decimalSep + fraction.substr(0, fractionSize);
9870
+ if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
9895
9871
  }
9896
9872
 
9897
9873
  parts.push(isNegative ? pattern.negPre : pattern.posPre);
@@ -9934,8 +9910,12 @@ function dateStrGetter(name, shortForm) {
9934
9910
  }
9935
9911
 
9936
9912
  function timeZoneGetter(date) {
9937
- var offset = date.getTimezoneOffset();
9938
- return padNumber(offset / 60, 2) + padNumber(Math.abs(offset % 60), 2);
9913
+ var zone = -1 * date.getTimezoneOffset();
9914
+ var paddedZone = (zone >= 0) ? "+" : "";
9915
+
9916
+ paddedZone += padNumber(zone / 60, 2) + padNumber(Math.abs(zone % 60), 2);
9917
+
9918
+ return paddedZone;
9939
9919
  }
9940
9920
 
9941
9921
  function ampmGetter(date, formats) {
@@ -10021,7 +10001,8 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
10021
10001
  *
10022
10002
  * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
10023
10003
  * number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and it's
10024
- * shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ).
10004
+ * shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
10005
+ * specified in the string input, the time is considered to be in the local timezone.
10025
10006
  * @param {string=} format Formatting rules (see Description). If not specified,
10026
10007
  * `mediumDate` is used.
10027
10008
  * @returns {string} Formatted string or the input if input is not recognized as date/millis.
@@ -10041,7 +10022,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
10041
10022
  expect(binding("1288323623006 | date:'medium'")).
10042
10023
  toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
10043
10024
  expect(binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).
10044
- toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} \-?\d{4}/);
10025
+ toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
10045
10026
  expect(binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).
10046
10027
  toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
10047
10028
  });
@@ -10053,22 +10034,18 @@ function dateFilter($locale) {
10053
10034
 
10054
10035
 
10055
10036
  var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
10056
- // 1 2 3 4 5 6 7 8 9 10 11
10057
- function jsonStringToDate(string) {
10037
+ function jsonStringToDate(string){
10058
10038
  var match;
10059
10039
  if (match = string.match(R_ISO8601_STR)) {
10060
10040
  var date = new Date(0),
10061
10041
  tzHour = 0,
10062
- tzMin = 0,
10063
- dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
10064
- timeSetter = match[8] ? date.setUTCHours : date.setHours;
10065
-
10042
+ tzMin = 0;
10066
10043
  if (match[9]) {
10067
10044
  tzHour = int(match[9] + match[10]);
10068
10045
  tzMin = int(match[9] + match[11]);
10069
10046
  }
10070
- dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
10071
- timeSetter.call(date, int(match[4]||0) - tzHour, int(match[5]||0) - tzMin, int(match[6]||0), int(match[7]||0));
10047
+ date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
10048
+ date.setUTCHours(int(match[4]||0) - tzHour, int(match[5]||0) - tzMin, int(match[6]||0), int(match[7]||0));
10072
10049
  return date;
10073
10050
  }
10074
10051
  return string;
@@ -10182,20 +10159,20 @@ var uppercaseFilter = valueFn(uppercase);
10182
10159
  * @function
10183
10160
  *
10184
10161
  * @description
10185
- * Creates a new array or string containing only a specified number of elements. The elements
10186
- * are taken from either the beginning or the end of the source array or string, as specified by
10187
- * the value and sign (positive or negative) of `limit`.
10162
+ * Creates a new array containing only a specified number of elements in an array. The elements
10163
+ * are taken from either the beginning or the end of the source array, as specified by the
10164
+ * value and sign (positive or negative) of `limit`.
10188
10165
  *
10189
10166
  * Note: This function is used to augment the `Array` type in Angular expressions. See
10190
10167
  * {@link ng.$filter} for more information about Angular arrays.
10191
10168
  *
10192
- * @param {Array|string} input Source array or string to be limited.
10193
- * @param {string|number} limit The length of the returned array or string. If the `limit` number
10194
- * is positive, `limit` number of items from the beginning of the source array/string are copied.
10195
- * If the number is negative, `limit` number of items from the end of the source array/string
10196
- * are copied. The `limit` will be trimmed if it exceeds `array.length`
10197
- * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
10198
- * had less than `limit` elements.
10169
+ * @param {Array} array Source array to be limited.
10170
+ * @param {string|Number} limit The length of the returned array. If the `limit` number is
10171
+ * positive, `limit` number of items from the beginning of the source array are copied.
10172
+ * If the number is negative, `limit` number of items from the end of the source array are
10173
+ * copied. The `limit` will be trimmed if it exceeds `array.length`
10174
+ * @returns {Array} A new sub-array of length `limit` or less if input array had less than `limit`
10175
+ * elements.
10199
10176
  *
10200
10177
  * @example
10201
10178
  <doc:example>
@@ -10203,76 +10180,59 @@ var uppercaseFilter = valueFn(uppercase);
10203
10180
  <script>
10204
10181
  function Ctrl($scope) {
10205
10182
  $scope.numbers = [1,2,3,4,5,6,7,8,9];
10206
- $scope.letters = "abcdefghi";
10207
- $scope.numLimit = 3;
10208
- $scope.letterLimit = 3;
10183
+ $scope.limit = 3;
10209
10184
  }
10210
10185
  </script>
10211
10186
  <div ng-controller="Ctrl">
10212
- Limit {{numbers}} to: <input type="integer" ng-model="numLimit">
10213
- <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
10214
- Limit {{letters}} to: <input type="integer" ng-model="letterLimit">
10215
- <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
10187
+ Limit {{numbers}} to: <input type="integer" ng-model="limit">
10188
+ <p>Output: {{ numbers | limitTo:limit }}</p>
10216
10189
  </div>
10217
10190
  </doc:source>
10218
10191
  <doc:scenario>
10219
- it('should limit the number array to first three items', function() {
10220
- expect(element('.doc-example-live input[ng-model=numLimit]').val()).toBe('3');
10221
- expect(element('.doc-example-live input[ng-model=letterLimit]').val()).toBe('3');
10222
- expect(binding('numbers | limitTo:numLimit')).toEqual('[1,2,3]');
10223
- expect(binding('letters | limitTo:letterLimit')).toEqual('abc');
10192
+ it('should limit the numer array to first three items', function() {
10193
+ expect(element('.doc-example-live input[ng-model=limit]').val()).toBe('3');
10194
+ expect(binding('numbers | limitTo:limit')).toEqual('[1,2,3]');
10224
10195
  });
10225
10196
 
10226
10197
  it('should update the output when -3 is entered', function() {
10227
- input('numLimit').enter(-3);
10228
- input('letterLimit').enter(-3);
10229
- expect(binding('numbers | limitTo:numLimit')).toEqual('[7,8,9]');
10230
- expect(binding('letters | limitTo:letterLimit')).toEqual('ghi');
10198
+ input('limit').enter(-3);
10199
+ expect(binding('numbers | limitTo:limit')).toEqual('[7,8,9]');
10231
10200
  });
10232
10201
 
10233
10202
  it('should not exceed the maximum size of input array', function() {
10234
- input('numLimit').enter(100);
10235
- input('letterLimit').enter(100);
10236
- expect(binding('numbers | limitTo:numLimit')).toEqual('[1,2,3,4,5,6,7,8,9]');
10237
- expect(binding('letters | limitTo:letterLimit')).toEqual('abcdefghi');
10203
+ input('limit').enter(100);
10204
+ expect(binding('numbers | limitTo:limit')).toEqual('[1,2,3,4,5,6,7,8,9]');
10238
10205
  });
10239
10206
  </doc:scenario>
10240
10207
  </doc:example>
10241
10208
  */
10242
10209
  function limitToFilter(){
10243
- return function(input, limit) {
10244
- if (!isArray(input) && !isString(input)) return input;
10245
-
10210
+ return function(array, limit) {
10211
+ if (!(array instanceof Array)) return array;
10246
10212
  limit = int(limit);
10247
-
10248
- if (isString(input)) {
10249
- //NaN check on limit
10250
- if (limit) {
10251
- return limit >= 0 ? input.slice(0, limit) : input.slice(limit, input.length);
10252
- } else {
10253
- return "";
10254
- }
10255
- }
10256
-
10257
10213
  var out = [],
10258
10214
  i, n;
10259
10215
 
10216
+ // check that array is iterable
10217
+ if (!array || !(array instanceof Array))
10218
+ return out;
10219
+
10260
10220
  // if abs(limit) exceeds maximum length, trim it
10261
- if (limit > input.length)
10262
- limit = input.length;
10263
- else if (limit < -input.length)
10264
- limit = -input.length;
10221
+ if (limit > array.length)
10222
+ limit = array.length;
10223
+ else if (limit < -array.length)
10224
+ limit = -array.length;
10265
10225
 
10266
10226
  if (limit > 0) {
10267
10227
  i = 0;
10268
10228
  n = limit;
10269
10229
  } else {
10270
- i = input.length + limit;
10271
- n = input.length;
10230
+ i = array.length + limit;
10231
+ n = array.length;
10272
10232
  }
10273
10233
 
10274
10234
  for (; i<n; i++) {
10275
- out.push(input[i]);
10235
+ out.push(array[i]);
10276
10236
  }
10277
10237
 
10278
10238
  return out;
@@ -10368,7 +10328,7 @@ function limitToFilter(){
10368
10328
  orderByFilter.$inject = ['$parse'];
10369
10329
  function orderByFilter($parse){
10370
10330
  return function(array, sortPredicate, reverseOrder) {
10371
- if (!(array instanceof Array)) return array;
10331
+ if (!isArray(array)) return array;
10372
10332
  if (!sortPredicate) return array;
10373
10333
  sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
10374
10334
  sortPredicate = map(sortPredicate, function(predicate){
@@ -10436,15 +10396,25 @@ function ngDirective(directive) {
10436
10396
  *
10437
10397
  * The reasoning for this change is to allow easy creation of action links with `ngClick` directive
10438
10398
  * without changing the location or causing page reloads, e.g.:
10439
- * <a href="" ng-click="model.$save()">Save</a>
10399
+ * `<a href="" ng-click="model.$save()">Save</a>`
10440
10400
  */
10441
10401
  var htmlAnchorDirective = valueFn({
10442
10402
  restrict: 'E',
10443
10403
  compile: function(element, attr) {
10444
- // turn <a href ng-click="..">link</a> into a link in IE
10445
- // but only if it doesn't have name attribute, in which case it's an anchor
10446
- if (!attr.href) {
10447
- attr.$set('href', '');
10404
+
10405
+ if (msie <= 8) {
10406
+
10407
+ // turn <a href ng-click="..">link</a> into a stylable link in IE
10408
+ // but only if it doesn't have name attribute, in which case it's an anchor
10409
+ if (!attr.href && !attr.name) {
10410
+ attr.$set('href', '');
10411
+ }
10412
+
10413
+ // add a comment node to anchors to workaround IE bug that causes element content to be reset
10414
+ // to new attribute content if attribute is updated with value containing @ and element also
10415
+ // contains value with @
10416
+ // see issue #1949
10417
+ element.append(document.createComment('IE fix'));
10448
10418
  }
10449
10419
 
10450
10420
  return function(scope, element) {
@@ -10524,7 +10494,7 @@ var htmlAnchorDirective = valueFn({
10524
10494
  it('should execute ng-click but not reload when no href but name specified', function() {
10525
10495
  element('#link-5').click();
10526
10496
  expect(input('value').val()).toEqual('5');
10527
- expect(element('#link-5').attr('href')).toBe('');
10497
+ expect(element('#link-5').attr('href')).toBe(undefined);
10528
10498
  });
10529
10499
 
10530
10500
  it('should only change url when only ng-href', function() {
@@ -10730,37 +10700,6 @@ var htmlAnchorDirective = valueFn({
10730
10700
  * @param {string} expression Angular expression that will be evaluated.
10731
10701
  */
10732
10702
 
10733
- /**
10734
- * @ngdoc directive
10735
- * @name ng.directive:ngOpen
10736
- * @restrict A
10737
- *
10738
- * @description
10739
- * The HTML specs do not require browsers to preserve the special attributes such as open.
10740
- * (The presence of them means true and absence means false)
10741
- * This prevents the angular compiler from correctly retrieving the binding expression.
10742
- * To solve this problem, we introduce the `ngOpen` directive.
10743
- *
10744
- * @example
10745
- <doc:example>
10746
- <doc:source>
10747
- Check me check multiple: <input type="checkbox" ng-model="open"><br/>
10748
- <details id="details" ng-open="open">
10749
- <summary>Show/Hide me</summary>
10750
- </details>
10751
- </doc:source>
10752
- <doc:scenario>
10753
- it('should toggle open', function() {
10754
- expect(element('#details').prop('open')).toBeFalsy();
10755
- input('open').check();
10756
- expect(element('#details').prop('open')).toBeTruthy();
10757
- });
10758
- </doc:scenario>
10759
- </doc:example>
10760
- *
10761
- * @element DETAILS
10762
- * @param {string} expression Angular expression that will be evaluated.
10763
- */
10764
10703
 
10765
10704
  var ngAttributeAliasDirectives = {};
10766
10705
 
@@ -10798,8 +10737,9 @@ forEach(['src', 'href'], function(attrName) {
10798
10737
 
10799
10738
  // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
10800
10739
  // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
10801
- // to set the property as well to achieve the desired effect
10802
- if (msie) element.prop(attrName, value);
10740
+ // to set the property as well to achieve the desired effect.
10741
+ // we use attr[attrName] value since $set can sanitize the url.
10742
+ if (msie) element.prop(attrName, attr[attrName]);
10803
10743
  });
10804
10744
  }
10805
10745
  };
@@ -10810,8 +10750,7 @@ var nullFormCtrl = {
10810
10750
  $addControl: noop,
10811
10751
  $removeControl: noop,
10812
10752
  $setValidity: noop,
10813
- $setDirty: noop,
10814
- $setPristine: noop
10753
+ $setDirty: noop
10815
10754
  };
10816
10755
 
10817
10756
  /**
@@ -10843,8 +10782,7 @@ function FormController(element, attrs) {
10843
10782
  var form = this,
10844
10783
  parentForm = element.parent().controller('form') || nullFormCtrl,
10845
10784
  invalidCount = 0, // used to easily determine if we are valid
10846
- errors = form.$error = {},
10847
- controls = [];
10785
+ errors = form.$error = {};
10848
10786
 
10849
10787
  // init state
10850
10788
  form.$name = attrs.name;
@@ -10868,8 +10806,6 @@ function FormController(element, attrs) {
10868
10806
  }
10869
10807
 
10870
10808
  form.$addControl = function(control) {
10871
- controls.push(control);
10872
-
10873
10809
  if (control.$name && !form.hasOwnProperty(control.$name)) {
10874
10810
  form[control.$name] = control;
10875
10811
  }
@@ -10882,8 +10818,6 @@ function FormController(element, attrs) {
10882
10818
  forEach(errors, function(queue, validationToken) {
10883
10819
  form.$setValidity(validationToken, true, control);
10884
10820
  });
10885
-
10886
- arrayRemove(controls, control);
10887
10821
  };
10888
10822
 
10889
10823
  form.$setValidity = function(validationToken, isValid, control) {
@@ -10931,29 +10865,6 @@ function FormController(element, attrs) {
10931
10865
  parentForm.$setDirty();
10932
10866
  };
10933
10867
 
10934
- /**
10935
- * @ngdoc function
10936
- * @name ng.directive:form.FormController#$setPristine
10937
- * @methodOf ng.directive:form.FormController
10938
- *
10939
- * @description
10940
- * Sets the form to its pristine state.
10941
- *
10942
- * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
10943
- * state (ng-pristine class). This method will also propagate to all the controls contained
10944
- * in this form.
10945
- *
10946
- * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
10947
- * saving or resetting it.
10948
- */
10949
- form.$setPristine = function () {
10950
- element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
10951
- form.$dirty = false;
10952
- form.$pristine = true;
10953
- forEach(controls, function(control) {
10954
- control.$setPristine();
10955
- });
10956
- };
10957
10868
  }
10958
10869
 
10959
10870
 
@@ -11150,8 +11061,6 @@ var inputType = {
11150
11061
  * patterns defined as scope expressions.
11151
11062
  * @param {string=} ngChange Angular expression to be executed when input changes due to user
11152
11063
  * interaction with the input element.
11153
- * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trimming the
11154
- * input.
11155
11064
  *
11156
11065
  * @example
11157
11066
  <doc:example>
@@ -11159,12 +11068,12 @@ var inputType = {
11159
11068
  <script>
11160
11069
  function Ctrl($scope) {
11161
11070
  $scope.text = 'guest';
11162
- $scope.word = /^\s*\w*\s*$/;
11071
+ $scope.word = /^\w*$/;
11163
11072
  }
11164
11073
  </script>
11165
11074
  <form name="myForm" ng-controller="Ctrl">
11166
11075
  Single word: <input type="text" name="input" ng-model="text"
11167
- ng-pattern="word" required ng-trim="false">
11076
+ ng-pattern="word" required>
11168
11077
  <span class="error" ng-show="myForm.input.$error.required">
11169
11078
  Required!</span>
11170
11079
  <span class="error" ng-show="myForm.input.$error.pattern">
@@ -11193,12 +11102,6 @@ var inputType = {
11193
11102
  input('text').enter('hello world');
11194
11103
  expect(binding('myForm.input.$valid')).toEqual('false');
11195
11104
  });
11196
-
11197
- it('should not be trimmed', function() {
11198
- input('text').enter('untrimmed ');
11199
- expect(binding('text')).toEqual('untrimmed ');
11200
- expect(binding('myForm.input.$valid')).toEqual('true');
11201
- });
11202
11105
  </doc:scenario>
11203
11106
  </doc:example>
11204
11107
  */
@@ -11512,14 +11415,7 @@ function isEmpty(value) {
11512
11415
  function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
11513
11416
 
11514
11417
  var listener = function() {
11515
- var value = element.val();
11516
-
11517
- // By default we will trim the value
11518
- // If the attribute ng-trim exists we will avoid trimming
11519
- // e.g. <input ng-model="foo" ng-trim="false">
11520
- if (toBoolean(attr.ngTrim || 'T')) {
11521
- value = trim(value);
11522
- }
11418
+ var value = trim(element.val());
11523
11419
 
11524
11420
  if (ctrl.$viewValue !== value) {
11525
11421
  scope.$apply(function() {
@@ -12100,22 +11996,6 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
12100
11996
  parentForm.$setValidity(validationErrorKey, isValid, this);
12101
11997
  };
12102
11998
 
12103
- /**
12104
- * @ngdoc function
12105
- * @name ng.directive:ngModel.NgModelController#$setPristine
12106
- * @methodOf ng.directive:ngModel.NgModelController
12107
- *
12108
- * @description
12109
- * Sets the control to its pristine state.
12110
- *
12111
- * This method can be called to remove the 'ng-dirty' class and set the control to its pristine
12112
- * state (ng-pristine class).
12113
- */
12114
- this.$setPristine = function () {
12115
- this.$dirty = false;
12116
- this.$pristine = true;
12117
- $element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
12118
- };
12119
11999
 
12120
12000
  /**
12121
12001
  * @ngdoc function
@@ -12564,6 +12444,7 @@ var ngBindHtmlUnsafeDirective = [function() {
12564
12444
  function classDirective(name, selector) {
12565
12445
  name = 'ngClass' + name;
12566
12446
  return ngDirective(function(scope, element, attr) {
12447
+ var oldVal = undefined;
12567
12448
 
12568
12449
  scope.$watch(attr[name], ngClassWatchAction, true);
12569
12450
 
@@ -12587,13 +12468,14 @@ function classDirective(name, selector) {
12587
12468
  }
12588
12469
 
12589
12470
 
12590
- function ngClassWatchAction(newVal, oldVal) {
12471
+ function ngClassWatchAction(newVal) {
12591
12472
  if (selector === true || scope.$index % 2 === selector) {
12592
12473
  if (oldVal && (newVal !== oldVal)) {
12593
12474
  removeClass(oldVal);
12594
12475
  }
12595
12476
  addClass(newVal);
12596
12477
  }
12478
+ oldVal = newVal;
12597
12479
  }
12598
12480
 
12599
12481
 
@@ -12626,7 +12508,7 @@ function classDirective(name, selector) {
12626
12508
  *
12627
12509
  * The directive won't add duplicate classes if a particular class was already set.
12628
12510
  *
12629
- * When the expression changes, the previously added classes are removed and only then the classes
12511
+ * When the expression changes, the previously added classes are removed and only then the
12630
12512
  * new classes are added.
12631
12513
  *
12632
12514
  * @element ANY
@@ -12986,7 +12868,7 @@ var ngCspDirective = ['$sniffer', function($sniffer) {
12986
12868
  */
12987
12869
  var ngEventDirectives = {};
12988
12870
  forEach(
12989
- 'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup'.split(' '),
12871
+ 'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave'.split(' '),
12990
12872
  function(name) {
12991
12873
  var directiveName = directiveNormalize('ng-' + name);
12992
12874
  ngEventDirectives[directiveName] = ['$parse', function($parse) {
@@ -13113,38 +12995,6 @@ forEach(
13113
12995
  */
13114
12996
 
13115
12997
 
13116
- /**
13117
- * @ngdoc directive
13118
- * @name ng.directive:ngKeydown
13119
- *
13120
- * @description
13121
- * Specify custom behavior on keydown event.
13122
- *
13123
- * @element ANY
13124
- * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
13125
- * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
13126
- *
13127
- * @example
13128
- * See {@link ng.directive:ngClick ngClick}
13129
- */
13130
-
13131
-
13132
- /**
13133
- * @ngdoc directive
13134
- * @name ng.directive:ngKeyup
13135
- *
13136
- * @description
13137
- * Specify custom behavior on keyup event.
13138
- *
13139
- * @element ANY
13140
- * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
13141
- * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
13142
- *
13143
- * @example
13144
- * See {@link ng.directive:ngClick ngClick}
13145
- */
13146
-
13147
-
13148
12998
  /**
13149
12999
  * @ngdoc directive
13150
13000
  * @name ng.directive:ngSubmit
@@ -13982,9 +13832,10 @@ var NG_SWITCH = 'ng-switch';
13982
13832
  var ngSwitchDirective = valueFn({
13983
13833
  restrict: 'EA',
13984
13834
  require: 'ngSwitch',
13985
- controller: function ngSwitchController() {
13835
+ // asks for $scope to fool the BC controller module
13836
+ controller: ['$scope', function ngSwitchController() {
13986
13837
  this.cases = {};
13987
- },
13838
+ }],
13988
13839
  link: function(scope, element, attr, ctrl) {
13989
13840
  var watchExpr = attr.ngSwitch || attr.on,
13990
13841
  selectedTransclude,
@@ -14235,7 +14086,7 @@ var ngViewDirective = ['$http', '$templateCache', '$route', '$anchorScroll', '$c
14235
14086
  if (current.controller) {
14236
14087
  locals.$scope = lastScope;
14237
14088
  controller = $controller(current.controller, locals);
14238
- element.contents().data('$ngControllerController', controller);
14089
+ element.children().data('$ngControllerController', controller);
14239
14090
  }
14240
14091
 
14241
14092
  link(lastScope);