angularjs-rails 1.2.26 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (27) hide show
  1. checksums.yaml +4 -4
  2. data/lib/angularjs-rails/version.rb +2 -2
  3. data/vendor/assets/javascripts/angular-animate.js +879 -456
  4. data/vendor/assets/javascripts/angular-aria.js +250 -0
  5. data/vendor/assets/javascripts/angular-cookies.js +1 -1
  6. data/vendor/assets/javascripts/angular-loader.js +17 -10
  7. data/vendor/assets/javascripts/angular-messages.js +400 -0
  8. data/vendor/assets/javascripts/angular-mocks.js +220 -110
  9. data/vendor/assets/javascripts/angular-resource.js +287 -247
  10. data/vendor/assets/javascripts/angular-route.js +111 -54
  11. data/vendor/assets/javascripts/angular-sanitize.js +1 -1
  12. data/vendor/assets/javascripts/angular-scenario.js +11579 -8665
  13. data/vendor/assets/javascripts/angular-touch.js +49 -11
  14. data/vendor/assets/javascripts/angular.js +6660 -3106
  15. data/vendor/assets/javascripts/unstable/angular-animate.js +240 -71
  16. data/vendor/assets/javascripts/unstable/angular-aria.js +12 -12
  17. data/vendor/assets/javascripts/unstable/angular-cookies.js +1 -1
  18. data/vendor/assets/javascripts/unstable/angular-loader.js +4 -4
  19. data/vendor/assets/javascripts/unstable/angular-messages.js +1 -1
  20. data/vendor/assets/javascripts/unstable/angular-mocks.js +21 -14
  21. data/vendor/assets/javascripts/unstable/angular-resource.js +2 -2
  22. data/vendor/assets/javascripts/unstable/angular-route.js +1 -1
  23. data/vendor/assets/javascripts/unstable/angular-sanitize.js +1 -1
  24. data/vendor/assets/javascripts/unstable/angular-scenario.js +562 -262
  25. data/vendor/assets/javascripts/unstable/angular-touch.js +1 -1
  26. data/vendor/assets/javascripts/unstable/angular.js +562 -262
  27. metadata +16 -14
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.3.0-rc.5
2
+ * @license AngularJS v1.3.0
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.3.0-rc.5
2
+ * @license AngularJS v1.3.0
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -71,7 +71,7 @@ function minErr(module, ErrorConstructor) {
71
71
  return match;
72
72
  });
73
73
 
74
- message = message + '\nhttp://errors.angularjs.org/1.3.0-rc.5/' +
74
+ message = message + '\nhttp://errors.angularjs.org/1.3.0/' +
75
75
  (module ? module + '/' : '') + code;
76
76
  for (i = 2; i < arguments.length; i++) {
77
77
  message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
@@ -413,7 +413,8 @@ function setHashKey(obj, h) {
413
413
  *
414
414
  * @description
415
415
  * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
416
- * to `dst`. You can specify multiple `src` objects.
416
+ * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
417
+ * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
417
418
  *
418
419
  * @param {Object} dst Destination object.
419
420
  * @param {...Object} src Source object(s).
@@ -1924,7 +1925,7 @@ function setupModuleLoader(window) {
1924
1925
  * })
1925
1926
  * ```
1926
1927
  *
1927
- * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and
1928
+ * See {@link ng.$animateProvider#register $animateProvider.register()} and
1928
1929
  * {@link ngAnimate ngAnimate module} for more information.
1929
1930
  */
1930
1931
  animation: invokeLater('$animateProvider', 'register'),
@@ -1974,7 +1975,7 @@ function setupModuleLoader(window) {
1974
1975
  * @description
1975
1976
  * Use this method to register work which needs to be performed on module loading.
1976
1977
  * For more about how to configure services, see
1977
- * {@link providers#providers_provider-recipe Provider Recipe}.
1978
+ * {@link providers#provider-recipe Provider Recipe}.
1978
1979
  */
1979
1980
  config: config,
1980
1981
 
@@ -2121,11 +2122,11 @@ function setupModuleLoader(window) {
2121
2122
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
2122
2123
  */
2123
2124
  var version = {
2124
- full: '1.3.0-rc.5', // all of these placeholder strings will be replaced by grunt's
2125
+ full: '1.3.0', // all of these placeholder strings will be replaced by grunt's
2125
2126
  major: 1, // package task
2126
2127
  minor: 3,
2127
2128
  dot: 0,
2128
- codeName: 'impossible-choreography'
2129
+ codeName: 'superluminal-nudge'
2129
2130
  };
2130
2131
 
2131
2132
 
@@ -2300,7 +2301,7 @@ function publishExternalAPI(angular){
2300
2301
  * - [`addClass()`](http://api.jquery.com/addClass/)
2301
2302
  * - [`after()`](http://api.jquery.com/after/)
2302
2303
  * - [`append()`](http://api.jquery.com/append/)
2303
- * - [`attr()`](http://api.jquery.com/attr/)
2304
+ * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
2304
2305
  * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
2305
2306
  * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
2306
2307
  * - [`clone()`](http://api.jquery.com/clone/)
@@ -2535,18 +2536,22 @@ function jqLiteOff(element, type, fn, unsupported) {
2535
2536
  if (!type) {
2536
2537
  for (type in events) {
2537
2538
  if (type !== '$destroy') {
2538
- removeEventListenerFn(element, type, events[type]);
2539
+ removeEventListenerFn(element, type, handle);
2539
2540
  }
2540
2541
  delete events[type];
2541
2542
  }
2542
2543
  } else {
2543
2544
  forEach(type.split(' '), function(type) {
2544
- if (isUndefined(fn)) {
2545
- removeEventListenerFn(element, type, events[type]);
2546
- delete events[type];
2547
- } else {
2548
- arrayRemove(events[type] || [], fn);
2545
+ if (isDefined(fn)) {
2546
+ var listenerFns = events[type];
2547
+ arrayRemove(listenerFns || [], fn);
2548
+ if (listenerFns && listenerFns.length > 0) {
2549
+ return;
2550
+ }
2549
2551
  }
2552
+
2553
+ removeEventListenerFn(element, type, handle);
2554
+ delete events[type];
2550
2555
  });
2551
2556
  }
2552
2557
  }
@@ -2710,6 +2715,20 @@ function jqLiteRemove(element, keepData) {
2710
2715
  if (parent) parent.removeChild(element);
2711
2716
  }
2712
2717
 
2718
+
2719
+ function jqLiteDocumentLoaded(action, win) {
2720
+ win = win || window;
2721
+ if (win.document.readyState === 'complete') {
2722
+ // Force the action to be run async for consistent behaviour
2723
+ // from the action's point of view
2724
+ // i.e. it will definitely not be in a $apply
2725
+ win.setTimeout(action);
2726
+ } else {
2727
+ // No need to unbind this handler as load is only ever called once
2728
+ jqLite(win).on('load', action);
2729
+ }
2730
+ }
2731
+
2713
2732
  //////////////////////////////////////////
2714
2733
  // Functions which are declared directly.
2715
2734
  //////////////////////////////////////////
@@ -3332,7 +3351,7 @@ HashMap.prototype = {
3332
3351
 
3333
3352
  * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
3334
3353
  * {@link angular.module}. The `ng` module must be explicitly added.
3335
- * @returns {function()} Injector object. See {@link auto.$injector $injector}.
3354
+ * @returns {injector} Injector object. See {@link auto.$injector $injector}.
3336
3355
  *
3337
3356
  * @example
3338
3357
  * Typical usage
@@ -3983,7 +4002,7 @@ function createInjector(modulesToLoad, strictDi) {
3983
4002
 
3984
4003
  function enforceReturnValue(name, factory) {
3985
4004
  return function enforcedReturnValue() {
3986
- var result = instanceInjector.invoke(factory);
4005
+ var result = instanceInjector.invoke(factory, this, undefined, name);
3987
4006
  if (isUndefined(result)) {
3988
4007
  throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
3989
4008
  }
@@ -4161,93 +4180,252 @@ function createInjector(modulesToLoad, strictDi) {
4161
4180
  createInjector.$$annotate = annotate;
4162
4181
 
4163
4182
  /**
4164
- * @ngdoc service
4165
- * @name $anchorScroll
4166
- * @kind function
4167
- * @requires $window
4168
- * @requires $location
4169
- * @requires $rootScope
4183
+ * @ngdoc provider
4184
+ * @name $anchorScrollProvider
4170
4185
  *
4171
4186
  * @description
4172
- * When called, it checks current value of `$location.hash()` and scrolls to the related element,
4173
- * according to rules specified in
4174
- * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
4175
- *
4176
- * It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor.
4177
- * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
4178
- *
4179
- * @example
4180
- <example module="anchorScrollExample">
4181
- <file name="index.html">
4182
- <div id="scrollArea" ng-controller="ScrollController">
4183
- <a ng-click="gotoBottom()">Go to bottom</a>
4184
- <a id="bottom"></a> You're at the bottom!
4185
- </div>
4186
- </file>
4187
- <file name="script.js">
4188
- angular.module('anchorScrollExample', [])
4189
- .controller('ScrollController', ['$scope', '$location', '$anchorScroll',
4190
- function ($scope, $location, $anchorScroll) {
4191
- $scope.gotoBottom = function() {
4192
- // set the location.hash to the id of
4193
- // the element you wish to scroll to.
4194
- $location.hash('bottom');
4195
-
4196
- // call $anchorScroll()
4197
- $anchorScroll();
4198
- };
4199
- }]);
4200
- </file>
4201
- <file name="style.css">
4202
- #scrollArea {
4203
- height: 350px;
4204
- overflow: auto;
4205
- }
4206
-
4207
- #bottom {
4208
- display: block;
4209
- margin-top: 2000px;
4210
- }
4211
- </file>
4212
- </example>
4187
+ * Use `$anchorScrollProvider` to disable automatic scrolling whenever
4188
+ * {@link ng.$location#hash $location.hash()} changes.
4213
4189
  */
4214
4190
  function $AnchorScrollProvider() {
4215
4191
 
4216
4192
  var autoScrollingEnabled = true;
4217
4193
 
4194
+ /**
4195
+ * @ngdoc method
4196
+ * @name $anchorScrollProvider#disableAutoScrolling
4197
+ *
4198
+ * @description
4199
+ * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically will detect changes to
4200
+ * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
4201
+ * Use this method to disable automatic scrolling.
4202
+ *
4203
+ * If automatic scrolling is disabled, one must explicitly call
4204
+ * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
4205
+ * current hash.
4206
+ */
4218
4207
  this.disableAutoScrolling = function() {
4219
4208
  autoScrollingEnabled = false;
4220
4209
  };
4221
4210
 
4211
+ /**
4212
+ * @ngdoc service
4213
+ * @name $anchorScroll
4214
+ * @kind function
4215
+ * @requires $window
4216
+ * @requires $location
4217
+ * @requires $rootScope
4218
+ *
4219
+ * @description
4220
+ * When called, it checks the current value of {@link ng.$location#hash $location.hash()} and
4221
+ * scrolls to the related element, according to the rules specified in the
4222
+ * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
4223
+ *
4224
+ * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
4225
+ * match any anchor whenever it changes. This can be disabled by calling
4226
+ * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
4227
+ *
4228
+ * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
4229
+ * vertical scroll-offset (either fixed or dynamic).
4230
+ *
4231
+ * @property {(number|function|jqLite)} yOffset
4232
+ * If set, specifies a vertical scroll-offset. This is often useful when there are fixed
4233
+ * positioned elements at the top of the page, such as navbars, headers etc.
4234
+ *
4235
+ * `yOffset` can be specified in various ways:
4236
+ * - **number**: A fixed number of pixels to be used as offset.<br /><br />
4237
+ * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
4238
+ * a number representing the offset (in pixels).<br /><br />
4239
+ * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
4240
+ * the top of the page to the element's bottom will be used as offset.<br />
4241
+ * **Note**: The element will be taken into account only as long as its `position` is set to
4242
+ * `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust
4243
+ * their height and/or positioning according to the viewport's size.
4244
+ *
4245
+ * <br />
4246
+ * <div class="alert alert-warning">
4247
+ * In order for `yOffset` to work properly, scrolling should take place on the document's root and
4248
+ * not some child element.
4249
+ * </div>
4250
+ *
4251
+ * @example
4252
+ <example module="anchorScrollExample">
4253
+ <file name="index.html">
4254
+ <div id="scrollArea" ng-controller="ScrollController">
4255
+ <a ng-click="gotoBottom()">Go to bottom</a>
4256
+ <a id="bottom"></a> You're at the bottom!
4257
+ </div>
4258
+ </file>
4259
+ <file name="script.js">
4260
+ angular.module('anchorScrollExample', [])
4261
+ .controller('ScrollController', ['$scope', '$location', '$anchorScroll',
4262
+ function ($scope, $location, $anchorScroll) {
4263
+ $scope.gotoBottom = function() {
4264
+ // set the location.hash to the id of
4265
+ // the element you wish to scroll to.
4266
+ $location.hash('bottom');
4267
+
4268
+ // call $anchorScroll()
4269
+ $anchorScroll();
4270
+ };
4271
+ }]);
4272
+ </file>
4273
+ <file name="style.css">
4274
+ #scrollArea {
4275
+ height: 280px;
4276
+ overflow: auto;
4277
+ }
4278
+
4279
+ #bottom {
4280
+ display: block;
4281
+ margin-top: 2000px;
4282
+ }
4283
+ </file>
4284
+ </example>
4285
+ *
4286
+ * <hr />
4287
+ * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).
4288
+ * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details.
4289
+ *
4290
+ * @example
4291
+ <example module="anchorScrollOffsetExample">
4292
+ <file name="index.html">
4293
+ <div class="fixed-header" ng-controller="headerCtrl">
4294
+ <a href="" ng-click="gotoAnchor(x)" ng-repeat="x in [1,2,3,4,5]">
4295
+ Go to anchor {{x}}
4296
+ </a>
4297
+ </div>
4298
+ <div id="anchor{{x}}" class="anchor" ng-repeat="x in [1,2,3,4,5]">
4299
+ Anchor {{x}} of 5
4300
+ </div>
4301
+ </file>
4302
+ <file name="script.js">
4303
+ angular.module('anchorScrollOffsetExample', [])
4304
+ .run(['$anchorScroll', function($anchorScroll) {
4305
+ $anchorScroll.yOffset = 50; // always scroll by 50 extra pixels
4306
+ }])
4307
+ .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
4308
+ function ($anchorScroll, $location, $scope) {
4309
+ $scope.gotoAnchor = function(x) {
4310
+ var newHash = 'anchor' + x;
4311
+ if ($location.hash() !== newHash) {
4312
+ // set the $location.hash to `newHash` and
4313
+ // $anchorScroll will automatically scroll to it
4314
+ $location.hash('anchor' + x);
4315
+ } else {
4316
+ // call $anchorScroll() explicitly,
4317
+ // since $location.hash hasn't changed
4318
+ $anchorScroll();
4319
+ }
4320
+ };
4321
+ }
4322
+ ]);
4323
+ </file>
4324
+ <file name="style.css">
4325
+ body {
4326
+ padding-top: 50px;
4327
+ }
4328
+
4329
+ .anchor {
4330
+ border: 2px dashed DarkOrchid;
4331
+ padding: 10px 10px 200px 10px;
4332
+ }
4333
+
4334
+ .fixed-header {
4335
+ background-color: rgba(0, 0, 0, 0.2);
4336
+ height: 50px;
4337
+ position: fixed;
4338
+ top: 0; left: 0; right: 0;
4339
+ }
4340
+
4341
+ .fixed-header > a {
4342
+ display: inline-block;
4343
+ margin: 5px 15px;
4344
+ }
4345
+ </file>
4346
+ </example>
4347
+ */
4222
4348
  this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
4223
4349
  var document = $window.document;
4350
+ var scrollScheduled = false;
4224
4351
 
4225
- // helper function to get first anchor from a NodeList
4226
- // can't use filter.filter, as it accepts only instances of Array
4227
- // and IE can't convert NodeList to an array using [].slice
4228
- // TODO(vojta): use filter if we change it to accept lists as well
4352
+ // Helper function to get first anchor from a NodeList
4353
+ // (using `Array#some()` instead of `angular#forEach()` since it's more performant
4354
+ // and working in all supported browsers.)
4229
4355
  function getFirstAnchor(list) {
4230
4356
  var result = null;
4231
- forEach(list, function(element) {
4232
- if (!result && nodeName_(element) === 'a') result = element;
4357
+ Array.prototype.some.call(list, function(element) {
4358
+ if (nodeName_(element) === 'a') {
4359
+ result = element;
4360
+ return true;
4361
+ }
4233
4362
  });
4234
4363
  return result;
4235
4364
  }
4236
4365
 
4366
+ function getYOffset() {
4367
+
4368
+ var offset = scroll.yOffset;
4369
+
4370
+ if (isFunction(offset)) {
4371
+ offset = offset();
4372
+ } else if (isElement(offset)) {
4373
+ var elem = offset[0];
4374
+ var style = $window.getComputedStyle(elem);
4375
+ if (style.position !== 'fixed') {
4376
+ offset = 0;
4377
+ } else {
4378
+ offset = elem.getBoundingClientRect().bottom;
4379
+ }
4380
+ } else if (!isNumber(offset)) {
4381
+ offset = 0;
4382
+ }
4383
+
4384
+ return offset;
4385
+ }
4386
+
4387
+ function scrollTo(elem) {
4388
+ if (elem) {
4389
+ elem.scrollIntoView();
4390
+
4391
+ var offset = getYOffset();
4392
+
4393
+ if (offset) {
4394
+ // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
4395
+ // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
4396
+ // top of the viewport.
4397
+ //
4398
+ // IF the number of pixels from the top of `elem` to the end of the page's content is less
4399
+ // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
4400
+ // way down the page.
4401
+ //
4402
+ // This is often the case for elements near the bottom of the page.
4403
+ //
4404
+ // In such cases we do not need to scroll the whole `offset` up, just the difference between
4405
+ // the top of the element and the offset, which is enough to align the top of `elem` at the
4406
+ // desired position.
4407
+ var elemTop = elem.getBoundingClientRect().top;
4408
+ $window.scrollBy(0, elemTop - offset);
4409
+ }
4410
+ } else {
4411
+ $window.scrollTo(0, 0);
4412
+ }
4413
+ }
4414
+
4237
4415
  function scroll() {
4238
4416
  var hash = $location.hash(), elm;
4239
4417
 
4240
4418
  // empty hash, scroll to the top of the page
4241
- if (!hash) $window.scrollTo(0, 0);
4419
+ if (!hash) scrollTo(null);
4242
4420
 
4243
4421
  // element with given id
4244
- else if ((elm = document.getElementById(hash))) elm.scrollIntoView();
4422
+ else if ((elm = document.getElementById(hash))) scrollTo(elm);
4245
4423
 
4246
4424
  // first anchor with given name :-D
4247
- else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) elm.scrollIntoView();
4425
+ else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
4248
4426
 
4249
4427
  // no element and hash == 'top', scroll to the top of the page
4250
- else if (hash === 'top') $window.scrollTo(0, 0);
4428
+ else if (hash === 'top') scrollTo(null);
4251
4429
  }
4252
4430
 
4253
4431
  // does not scroll when user clicks on anchor link that is currently on
@@ -4258,7 +4436,9 @@ function $AnchorScrollProvider() {
4258
4436
  // skip the initial scroll if $location.hash is empty
4259
4437
  if (newVal === oldVal && newVal === '') return;
4260
4438
 
4261
- $rootScope.$evalAsync(scroll);
4439
+ jqLiteDocumentLoaded(function() {
4440
+ $rootScope.$evalAsync(scroll);
4441
+ });
4262
4442
  });
4263
4443
  }
4264
4444
 
@@ -4366,7 +4546,7 @@ var $AnimateProvider = ['$provide', function($provide) {
4366
4546
  return defer.promise;
4367
4547
  }
4368
4548
 
4369
- function resolveElementClasses(element, cache) {
4549
+ function resolveElementClasses(element, classes) {
4370
4550
  var toAdd = [], toRemove = [];
4371
4551
 
4372
4552
  var hasClasses = createMap();
@@ -4374,7 +4554,7 @@ var $AnimateProvider = ['$provide', function($provide) {
4374
4554
  hasClasses[className] = true;
4375
4555
  });
4376
4556
 
4377
- forEach(cache.classes, function(status, className) {
4557
+ forEach(classes, function(status, className) {
4378
4558
  var hasClass = hasClasses[className];
4379
4559
 
4380
4560
  // If the most recent class manipulation (via $animate) was to remove the class, and the
@@ -4388,7 +4568,8 @@ var $AnimateProvider = ['$provide', function($provide) {
4388
4568
  }
4389
4569
  });
4390
4570
 
4391
- return (toAdd.length + toRemove.length) > 0 && [toAdd.length && toAdd, toRemove.length && toRemove];
4571
+ return (toAdd.length + toRemove.length) > 0 &&
4572
+ [toAdd.length ? toAdd : null, toRemove.length ? toRemove : null];
4392
4573
  }
4393
4574
 
4394
4575
  function cachedClassManipulation(cache, classes, op) {
@@ -4410,6 +4591,13 @@ var $AnimateProvider = ['$provide', function($provide) {
4410
4591
  return currentDefer.promise;
4411
4592
  }
4412
4593
 
4594
+ function applyStyles(element, options) {
4595
+ if (angular.isObject(options)) {
4596
+ var styles = extend(options.from || {}, options.to || {});
4597
+ element.css(styles);
4598
+ }
4599
+ }
4600
+
4413
4601
  /**
4414
4602
  *
4415
4603
  * @ngdoc service
@@ -4428,6 +4616,10 @@ var $AnimateProvider = ['$provide', function($provide) {
4428
4616
  * page}.
4429
4617
  */
4430
4618
  return {
4619
+ animate : function(element, from, to) {
4620
+ applyStyles(element, { from: from, to: to });
4621
+ return asyncPromise();
4622
+ },
4431
4623
 
4432
4624
  /**
4433
4625
  *
@@ -4442,9 +4634,11 @@ var $AnimateProvider = ['$provide', function($provide) {
4442
4634
  * a child (if the after element is not present)
4443
4635
  * @param {DOMElement} after the sibling element which will append the element
4444
4636
  * after itself
4637
+ * @param {object=} options an optional collection of styles that will be applied to the element.
4445
4638
  * @return {Promise} the animation callback promise
4446
4639
  */
4447
- enter : function(element, parent, after) {
4640
+ enter : function(element, parent, after, options) {
4641
+ applyStyles(element, options);
4448
4642
  after ? after.after(element)
4449
4643
  : parent.prepend(element);
4450
4644
  return asyncPromise();
@@ -4458,9 +4652,10 @@ var $AnimateProvider = ['$provide', function($provide) {
4458
4652
  * @description Removes the element from the DOM. When the function is called a promise
4459
4653
  * is returned that will be resolved at a later time.
4460
4654
  * @param {DOMElement} element the element which will be removed from the DOM
4655
+ * @param {object=} options an optional collection of options that will be applied to the element.
4461
4656
  * @return {Promise} the animation callback promise
4462
4657
  */
4463
- leave : function(element) {
4658
+ leave : function(element, options) {
4464
4659
  element.remove();
4465
4660
  return asyncPromise();
4466
4661
  },
@@ -4480,12 +4675,13 @@ var $AnimateProvider = ['$provide', function($provide) {
4480
4675
  * inserted into (if the after element is not present)
4481
4676
  * @param {DOMElement} after the sibling element where the element will be
4482
4677
  * positioned next to
4678
+ * @param {object=} options an optional collection of options that will be applied to the element.
4483
4679
  * @return {Promise} the animation callback promise
4484
4680
  */
4485
- move : function(element, parent, after) {
4681
+ move : function(element, parent, after, options) {
4486
4682
  // Do not remove element before insert. Removing will cause data associated with the
4487
4683
  // element to be dropped. Insert will implicitly do the remove.
4488
- return this.enter(element, parent, after);
4684
+ return this.enter(element, parent, after, options);
4489
4685
  },
4490
4686
 
4491
4687
  /**
@@ -4498,13 +4694,14 @@ var $AnimateProvider = ['$provide', function($provide) {
4498
4694
  * @param {DOMElement} element the element which will have the className value
4499
4695
  * added to it
4500
4696
  * @param {string} className the CSS class which will be added to the element
4697
+ * @param {object=} options an optional collection of options that will be applied to the element.
4501
4698
  * @return {Promise} the animation callback promise
4502
4699
  */
4503
- addClass : function(element, className) {
4504
- return this.setClass(element, className, []);
4700
+ addClass : function(element, className, options) {
4701
+ return this.setClass(element, className, [], options);
4505
4702
  },
4506
4703
 
4507
- $$addClassImmediately : function addClassImmediately(element, className) {
4704
+ $$addClassImmediately : function(element, className, options) {
4508
4705
  element = jqLite(element);
4509
4706
  className = !isString(className)
4510
4707
  ? (isArray(className) ? className.join(' ') : '')
@@ -4512,6 +4709,8 @@ var $AnimateProvider = ['$provide', function($provide) {
4512
4709
  forEach(element, function (element) {
4513
4710
  jqLiteAddClass(element, className);
4514
4711
  });
4712
+ applyStyles(element, options);
4713
+ return asyncPromise();
4515
4714
  },
4516
4715
 
4517
4716
  /**
@@ -4524,13 +4723,14 @@ var $AnimateProvider = ['$provide', function($provide) {
4524
4723
  * @param {DOMElement} element the element which will have the className value
4525
4724
  * removed from it
4526
4725
  * @param {string} className the CSS class which will be removed from the element
4726
+ * @param {object=} options an optional collection of options that will be applied to the element.
4527
4727
  * @return {Promise} the animation callback promise
4528
4728
  */
4529
- removeClass : function(element, className) {
4530
- return this.setClass(element, [], className);
4729
+ removeClass : function(element, className, options) {
4730
+ return this.setClass(element, [], className, options);
4531
4731
  },
4532
4732
 
4533
- $$removeClassImmediately : function removeClassImmediately(element, className) {
4733
+ $$removeClassImmediately : function(element, className, options) {
4534
4734
  element = jqLite(element);
4535
4735
  className = !isString(className)
4536
4736
  ? (isArray(className) ? className.join(' ') : '')
@@ -4538,6 +4738,7 @@ var $AnimateProvider = ['$provide', function($provide) {
4538
4738
  forEach(element, function (element) {
4539
4739
  jqLiteRemoveClass(element, className);
4540
4740
  });
4741
+ applyStyles(element, options);
4541
4742
  return asyncPromise();
4542
4743
  },
4543
4744
 
@@ -4552,28 +4753,24 @@ var $AnimateProvider = ['$provide', function($provide) {
4552
4753
  * removed from it
4553
4754
  * @param {string} add the CSS classes which will be added to the element
4554
4755
  * @param {string} remove the CSS class which will be removed from the element
4756
+ * @param {object=} options an optional collection of options that will be applied to the element.
4555
4757
  * @return {Promise} the animation callback promise
4556
4758
  */
4557
- setClass : function(element, add, remove, runSynchronously) {
4759
+ setClass : function(element, add, remove, options) {
4558
4760
  var self = this;
4559
4761
  var STORAGE_KEY = '$$animateClasses';
4560
4762
  var createdCache = false;
4561
4763
  element = jqLite(element);
4562
4764
 
4563
- if (runSynchronously) {
4564
- // TODO(@caitp/@matsko): Remove undocumented `runSynchronously` parameter, and always
4565
- // perform DOM manipulation asynchronously or in postDigest.
4566
- self.$$addClassImmediately(element, add);
4567
- self.$$removeClassImmediately(element, remove);
4568
- return asyncPromise();
4569
- }
4570
-
4571
4765
  var cache = element.data(STORAGE_KEY);
4572
4766
  if (!cache) {
4573
4767
  cache = {
4574
- classes: {}
4768
+ classes: {},
4769
+ options : options
4575
4770
  };
4576
4771
  createdCache = true;
4772
+ } else if (options && cache.options) {
4773
+ cache.options = angular.extend(cache.options || {}, options);
4577
4774
  }
4578
4775
 
4579
4776
  var classes = cache.classes;
@@ -4588,11 +4785,14 @@ var $AnimateProvider = ['$provide', function($provide) {
4588
4785
  var cache = element.data(STORAGE_KEY);
4589
4786
  element.removeData(STORAGE_KEY);
4590
4787
 
4591
- var classes = cache && resolveElementClasses(element, cache);
4592
-
4593
- if (classes) {
4594
- if (classes[0]) self.$$addClassImmediately(element, classes[0]);
4595
- if (classes[1]) self.$$removeClassImmediately(element, classes[1]);
4788
+ // in the event that the element is removed before postDigest
4789
+ // is run then the cache will be undefined and there will be
4790
+ // no need anymore to add or remove and of the element classes
4791
+ if (cache) {
4792
+ var classes = resolveElementClasses(element, cache.classes);
4793
+ if (classes) {
4794
+ self.$$setClassImmediately(element, classes[0], classes[1], cache.options);
4795
+ }
4596
4796
  }
4597
4797
 
4598
4798
  done();
@@ -4603,6 +4803,13 @@ var $AnimateProvider = ['$provide', function($provide) {
4603
4803
  return cache.promise;
4604
4804
  },
4605
4805
 
4806
+ $$setClassImmediately : function(element, add, remove, options) {
4807
+ add && this.$$addClassImmediately(element, add);
4808
+ remove && this.$$removeClassImmediately(element, remove);
4809
+ applyStyles(element, options);
4810
+ return asyncPromise();
4811
+ },
4812
+
4606
4813
  enabled : noop,
4607
4814
  cancel : noop
4608
4815
  };
@@ -4743,11 +4950,14 @@ function Browser(window, document, $log, $sniffer) {
4743
4950
  // URL API
4744
4951
  //////////////////////////////////////////////////////////////
4745
4952
 
4746
- var lastBrowserUrl = location.href,
4747
- lastHistoryState = history.state,
4953
+ var cachedState, lastHistoryState,
4954
+ lastBrowserUrl = location.href,
4748
4955
  baseElement = document.find('base'),
4749
4956
  reloadLocation = null;
4750
4957
 
4958
+ cacheState();
4959
+ lastHistoryState = cachedState;
4960
+
4751
4961
  /**
4752
4962
  * @name $browser#url
4753
4963
  *
@@ -4782,21 +4992,26 @@ function Browser(window, document, $log, $sniffer) {
4782
4992
 
4783
4993
  // setter
4784
4994
  if (url) {
4995
+ var sameState = lastHistoryState === state;
4996
+
4785
4997
  // Don't change anything if previous and current URLs and states match. This also prevents
4786
4998
  // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
4787
4999
  // See https://github.com/angular/angular.js/commit/ffb2701
4788
- if (lastBrowserUrl === url && (!$sniffer.history || history.state === state)) {
5000
+ if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
4789
5001
  return;
4790
5002
  }
4791
5003
  var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
4792
5004
  lastBrowserUrl = url;
5005
+ lastHistoryState = state;
4793
5006
  // Don't use history API if only the hash changed
4794
5007
  // due to a bug in IE10/IE11 which leads
4795
5008
  // to not firing a `hashchange` nor `popstate` event
4796
5009
  // in some cases (see #9143).
4797
- if ($sniffer.history && (!sameBase || history.state !== state)) {
5010
+ if ($sniffer.history && (!sameBase || !sameState)) {
4798
5011
  history[replace ? 'replaceState' : 'pushState'](state, '', url);
4799
- lastHistoryState = history.state;
5012
+ cacheState();
5013
+ // Do the assignment again so that those two variables are referentially identical.
5014
+ lastHistoryState = cachedState;
4800
5015
  } else {
4801
5016
  if (!sameBase) {
4802
5017
  reloadLocation = url;
@@ -4828,20 +5043,40 @@ function Browser(window, document, $log, $sniffer) {
4828
5043
  * @returns {object} state
4829
5044
  */
4830
5045
  self.state = function() {
4831
- return isUndefined(history.state) ? null : history.state;
5046
+ return cachedState;
4832
5047
  };
4833
5048
 
4834
5049
  var urlChangeListeners = [],
4835
5050
  urlChangeInit = false;
4836
5051
 
5052
+ function cacheStateAndFireUrlChange() {
5053
+ cacheState();
5054
+ fireUrlChange();
5055
+ }
5056
+
5057
+ // This variable should be used *only* inside the cacheState function.
5058
+ var lastCachedState = null;
5059
+ function cacheState() {
5060
+ // This should be the only place in $browser where `history.state` is read.
5061
+ cachedState = window.history.state;
5062
+ cachedState = isUndefined(cachedState) ? null : cachedState;
5063
+
5064
+ // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
5065
+ if (equals(cachedState, lastCachedState)) {
5066
+ cachedState = lastCachedState;
5067
+ }
5068
+ lastCachedState = cachedState;
5069
+ }
5070
+
4837
5071
  function fireUrlChange() {
4838
- if (lastBrowserUrl === self.url() && lastHistoryState === history.state) {
5072
+ if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
4839
5073
  return;
4840
5074
  }
4841
5075
 
4842
5076
  lastBrowserUrl = self.url();
5077
+ lastHistoryState = cachedState;
4843
5078
  forEach(urlChangeListeners, function(listener) {
4844
- listener(self.url(), history.state);
5079
+ listener(self.url(), cachedState);
4845
5080
  });
4846
5081
  }
4847
5082
 
@@ -4874,9 +5109,9 @@ function Browser(window, document, $log, $sniffer) {
4874
5109
  // changed by push/replaceState
4875
5110
 
4876
5111
  // html5 history api - popstate event
4877
- if ($sniffer.history) jqLite(window).on('popstate', fireUrlChange);
5112
+ if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
4878
5113
  // hashchange event
4879
- jqLite(window).on('hashchange', fireUrlChange);
5114
+ jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
4880
5115
 
4881
5116
  urlChangeInit = true;
4882
5117
  }
@@ -4917,6 +5152,14 @@ function Browser(window, document, $log, $sniffer) {
4917
5152
  var lastCookieString = '';
4918
5153
  var cookiePath = self.baseHref();
4919
5154
 
5155
+ function safeDecodeURIComponent(str) {
5156
+ try {
5157
+ return decodeURIComponent(str);
5158
+ } catch (e) {
5159
+ return str;
5160
+ }
5161
+ }
5162
+
4920
5163
  /**
4921
5164
  * @name $browser#cookies
4922
5165
  *
@@ -4970,12 +5213,12 @@ function Browser(window, document, $log, $sniffer) {
4970
5213
  cookie = cookieArray[i];
4971
5214
  index = cookie.indexOf('=');
4972
5215
  if (index > 0) { //ignore nameless cookies
4973
- name = decodeURIComponent(cookie.substring(0, index));
5216
+ name = safeDecodeURIComponent(cookie.substring(0, index));
4974
5217
  // the first value that is seen for a cookie is the most
4975
5218
  // specific one. values for the same cookie name that
4976
5219
  // follow are for less specific paths.
4977
5220
  if (lastCookies[name] === undefined) {
4978
- lastCookies[name] = decodeURIComponent(cookie.substring(index + 1));
5221
+ lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
4979
5222
  }
4980
5223
  }
4981
5224
  }
@@ -5500,6 +5743,7 @@ function $TemplateCacheProvider() {
5500
5743
  * // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
5501
5744
  * transclude: false,
5502
5745
  * restrict: 'A',
5746
+ * templateNamespace: 'html',
5503
5747
  * scope: false,
5504
5748
  * controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
5505
5749
  * controllerAs: 'stringAlias',
@@ -5554,8 +5798,8 @@ function $TemplateCacheProvider() {
5554
5798
  * When this property is set to true, the HTML compiler will collect DOM nodes between
5555
5799
  * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
5556
5800
  * together as the directive elements. It is recomended that this feature be used on directives
5557
- * which are not strictly behavioural (such as {@link api/ng.directive:ngClick ngClick}), and which
5558
- * do not manipulate or replace child nodes (such as {@link api/ng.directive:ngInclude ngInclude}).
5801
+ * which are not strictly behavioural (such as {@link ngClick}), and which
5802
+ * do not manipulate or replace child nodes (such as {@link ngInclude}).
5559
5803
  *
5560
5804
  * #### `priority`
5561
5805
  * When there are multiple directives defined on a single DOM element, sometimes it
@@ -5568,7 +5812,8 @@ function $TemplateCacheProvider() {
5568
5812
  * #### `terminal`
5569
5813
  * If set to true then the current `priority` will be the last set of directives
5570
5814
  * which will execute (any directives at the current priority will still execute
5571
- * as the order of execution on same `priority` is undefined).
5815
+ * as the order of execution on same `priority` is undefined). Note that expressions
5816
+ * and other directives used in the directive's template will also be excluded from execution.
5572
5817
  *
5573
5818
  * #### `scope`
5574
5819
  * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the
@@ -5715,7 +5960,7 @@ function $TemplateCacheProvider() {
5715
5960
  * You can specify `templateUrl` as a string representing the URL or as a function which takes two
5716
5961
  * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
5717
5962
  * a string value representing the url. In either case, the template URL is passed through {@link
5718
- * api/ng.$sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
5963
+ * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
5719
5964
  *
5720
5965
  *
5721
5966
  * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0)
@@ -5725,7 +5970,7 @@ function $TemplateCacheProvider() {
5725
5970
  * * `false` - the template will replace the contents of the directive's element.
5726
5971
  *
5727
5972
  * The replacement process migrates all of the attributes / classes from the old element to the new
5728
- * one. See the {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
5973
+ * one. See the {@link guide/directive#template-expanding-directive
5729
5974
  * Directives Guide} for an example.
5730
5975
  *
5731
5976
  * There are very few scenarios where element replacement is required for the application function,
@@ -5880,7 +6125,7 @@ function $TemplateCacheProvider() {
5880
6125
  * then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
5881
6126
  * object that contains the compiled DOM, which is linked to the correct transclusion scope.
5882
6127
  *
5883
- * When you call a transclusion function you can pass in a **clone attach function**. This function is accepts
6128
+ * When you call a transclusion function you can pass in a **clone attach function**. This function accepts
5884
6129
  * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
5885
6130
  * content and the `scope` is the newly created transclusion scope, to which the clone is bound.
5886
6131
  *
@@ -6500,12 +6745,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6500
6745
  * @param {string} key Normalized key. (ie ngAttribute) .
6501
6746
  * @param {function(interpolatedValue)} fn Function that will be called whenever
6502
6747
  the interpolated value of the attribute changes.
6503
- * See {@link ng.$compile#attributes $compile} for more info.
6748
+ * See the {@link guide/directive#text-and-attribute-bindings Directives} guide for more info.
6504
6749
  * @returns {function()} Returns a deregistration function for this observer.
6505
6750
  */
6506
6751
  $observe: function(key, fn) {
6507
6752
  var attrs = this,
6508
- $$observers = (attrs.$$observers || (attrs.$$observers = Object.create(null))),
6753
+ $$observers = (attrs.$$observers || (attrs.$$observers = createMap())),
6509
6754
  listeners = ($$observers[key] || ($$observers[key] = []));
6510
6755
 
6511
6756
  listeners.push(fn);
@@ -8181,6 +8426,14 @@ function $DocumentProvider(){
8181
8426
  * This example will override the normal action of `$exceptionHandler`, to make angular
8182
8427
  * exceptions fail hard when they happen, instead of just logging to the console.
8183
8428
  *
8429
+ * <hr />
8430
+ * Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`
8431
+ * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler}
8432
+ * (unless executed during a digest).
8433
+ *
8434
+ * If you wish, you can manually delegate exceptions, e.g.
8435
+ * `try { ... } catch(e) { $exceptionHandler(e); }`
8436
+ *
8184
8437
  * @param {Error} exception Exception associated with the error.
8185
8438
  * @param {string=} cause optional information about the context in which
8186
8439
  * the error was thrown.
@@ -8348,7 +8601,7 @@ function $HttpProvider() {
8348
8601
  * @description
8349
8602
  *
8350
8603
  * Configure $http service to combine processing of multiple http responses received at around
8351
- * the same time via {@link ng.$rootScope#applyAsync $rootScope.$applyAsync}. This can result in
8604
+ * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in
8352
8605
  * significant performance improvement for bigger applications that make many HTTP requests
8353
8606
  * concurrently (common during application bootstrap).
8354
8607
  *
@@ -8424,7 +8677,21 @@ function $HttpProvider() {
8424
8677
  * with two $http specific methods: `success` and `error`.
8425
8678
  *
8426
8679
  * ```js
8427
- * $http({method: 'GET', url: '/someUrl'}).
8680
+ * // Simple GET request example :
8681
+ * $http.get('/someUrl').
8682
+ * success(function(data, status, headers, config) {
8683
+ * // this callback will be called asynchronously
8684
+ * // when the response is available
8685
+ * }).
8686
+ * error(function(data, status, headers, config) {
8687
+ * // called asynchronously if an error occurs
8688
+ * // or server returns response with an error status.
8689
+ * });
8690
+ * ```
8691
+ *
8692
+ * ```js
8693
+ * // Simple POST request example (passing data) :
8694
+ * $http.post('/someUrl', {msg:'hello word!'}).
8428
8695
  * success(function(data, status, headers, config) {
8429
8696
  * // this callback will be called asynchronously
8430
8697
  * // when the response is available
@@ -8435,6 +8702,7 @@ function $HttpProvider() {
8435
8702
  * });
8436
8703
  * ```
8437
8704
  *
8705
+ *
8438
8706
  * Since the returned value of calling the $http function is a `promise`, you can also use
8439
8707
  * the `then` method to register callbacks, and these callbacks will receive a single argument –
8440
8708
  * an object representing the response. See the API signature and type info below for more
@@ -8587,7 +8855,7 @@ function $HttpProvider() {
8587
8855
  *
8588
8856
  * You can change the default cache to a new object (built with
8589
8857
  * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
8590
- * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set
8858
+ * {@link ng.$http#defaults `$http.defaults.cache`} property. All requests who set
8591
8859
  * their `cache` property to `true` will now use this cache object.
8592
8860
  *
8593
8861
  * If you set the default cache to `false` then only requests that specify their own custom
@@ -8949,9 +9217,12 @@ function $HttpProvider() {
8949
9217
 
8950
9218
  function transformResponse(response) {
8951
9219
  // make a copy since the response must be cacheable
8952
- var resp = extend({}, response, {
8953
- data: transformData(response.data, response.headers, config.transformResponse)
8954
- });
9220
+ var resp = extend({}, response);
9221
+ if (!response.data) {
9222
+ resp.data = response.data;
9223
+ } else {
9224
+ resp.data = transformData(response.data, response.headers, config.transformResponse);
9225
+ }
8955
9226
  return (isSuccess(response.status))
8956
9227
  ? resp
8957
9228
  : $q.reject(resp);
@@ -9694,16 +9965,13 @@ function $InterpolateProvider() {
9694
9965
  return '';
9695
9966
  }
9696
9967
  switch (typeof value) {
9697
- case 'string': {
9968
+ case 'string':
9698
9969
  break;
9699
- }
9700
- case 'number': {
9970
+ case 'number':
9701
9971
  value = '' + value;
9702
9972
  break;
9703
- }
9704
- default: {
9973
+ default:
9705
9974
  value = toJson(value);
9706
- }
9707
9975
  }
9708
9976
 
9709
9977
  return value;
@@ -10525,6 +10793,7 @@ var locationPrototype = {
10525
10793
  search = search.toString();
10526
10794
  this.$$search = parseKeyValue(search);
10527
10795
  } else if (isObject(search)) {
10796
+ search = copy(search, {});
10528
10797
  // remove object undefined or null properties
10529
10798
  forEach(search, function(value, key) {
10530
10799
  if (value == null) delete search[key];
@@ -10710,8 +10979,8 @@ function $LocationProvider(){
10710
10979
  * whether or not a <base> tag is required to be present. If `enabled` and `requireBase` are
10711
10980
  * true, and a base tag is not present, an error will be thrown when `$location` is injected.
10712
10981
  * See the {@link guide/$location $location guide for more information}
10713
- * - **rewriteLinks** - `{boolean}` - (default: `false`) When html5Mode is enabled, disables
10714
- * url rewriting for relative linksTurns off url rewriting for relative links.
10982
+ * - **rewriteLinks** - `{boolean}` - (default: `true`) When html5Mode is enabled,
10983
+ * enables/disables url rewriting for relative links.
10715
10984
  *
10716
10985
  * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
10717
10986
  */
@@ -10722,7 +10991,7 @@ function $LocationProvider(){
10722
10991
  } else if (isObject(mode)) {
10723
10992
 
10724
10993
  if (isBoolean(mode.enabled)) {
10725
- html5Mode.enabled = mode.enabled;
10994
+ html5Mode.enabled = mode.enabled;
10726
10995
  }
10727
10996
 
10728
10997
  if (isBoolean(mode.requireBase)) {
@@ -10730,7 +10999,7 @@ function $LocationProvider(){
10730
10999
  }
10731
11000
 
10732
11001
  if (isBoolean(mode.rewriteLinks)) {
10733
- html5Mode.rewriteLinks = mode.rewriteLinks;
11002
+ html5Mode.rewriteLinks = mode.rewriteLinks;
10734
11003
  }
10735
11004
 
10736
11005
  return this;
@@ -10749,7 +11018,7 @@ function $LocationProvider(){
10749
11018
  * This change can be prevented by calling
10750
11019
  * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
10751
11020
  * details about event object. Upon successful change
10752
- * {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
11021
+ * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
10753
11022
  *
10754
11023
  * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
10755
11024
  * the browser supports the HTML5 History API.
@@ -10901,9 +11170,10 @@ function $LocationProvider(){
10901
11170
  var oldUrl = $browser.url();
10902
11171
  var oldState = $browser.state();
10903
11172
  var currentReplace = $location.$$replace;
11173
+ var urlOrStateChanged = oldUrl !== $location.absUrl() ||
11174
+ ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);
10904
11175
 
10905
- if (initializing || oldUrl !== $location.absUrl() ||
10906
- ($location.$$html5 && $sniffer.history && oldState !== $location.$$state)) {
11176
+ if (initializing || urlOrStateChanged) {
10907
11177
  initializing = false;
10908
11178
 
10909
11179
  $rootScope.$evalAsync(function() {
@@ -10912,8 +11182,10 @@ function $LocationProvider(){
10912
11182
  $location.$$parse(oldUrl);
10913
11183
  $location.$$state = oldState;
10914
11184
  } else {
10915
- setBrowserUrlWithFallback($location.absUrl(), currentReplace,
10916
- oldState === $location.$$state ? null : $location.$$state);
11185
+ if (urlOrStateChanged) {
11186
+ setBrowserUrlWithFallback($location.absUrl(), currentReplace,
11187
+ oldState === $location.$$state ? null : $location.$$state);
11188
+ }
10917
11189
  afterLocationChange(oldUrl, oldState);
10918
11190
  }
10919
11191
  });
@@ -11195,7 +11467,6 @@ CONSTANTS['this'].sharedGetter = true;
11195
11467
 
11196
11468
  //Operators - will be wrapped by binaryFn/unaryFn/assignment/filter
11197
11469
  var OPERATORS = extend(createMap(), {
11198
- /* jshint bitwise : false */
11199
11470
  '+':function(self, locals, a,b){
11200
11471
  a=a(self, locals); b=b(self, locals);
11201
11472
  if (isDefined(a)) {
@@ -11212,7 +11483,6 @@ var OPERATORS = extend(createMap(), {
11212
11483
  '*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
11213
11484
  '/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
11214
11485
  '%':function(self, locals, a,b){return a(self, locals)%b(self, locals);},
11215
- '^':function(self, locals, a,b){return a(self, locals)^b(self, locals);},
11216
11486
  '===':function(self, locals, a, b){return a(self, locals)===b(self, locals);},
11217
11487
  '!==':function(self, locals, a, b){return a(self, locals)!==b(self, locals);},
11218
11488
  '==':function(self, locals, a,b){return a(self, locals)==b(self, locals);},
@@ -11223,14 +11493,12 @@ var OPERATORS = extend(createMap(), {
11223
11493
  '>=':function(self, locals, a,b){return a(self, locals)>=b(self, locals);},
11224
11494
  '&&':function(self, locals, a,b){return a(self, locals)&&b(self, locals);},
11225
11495
  '||':function(self, locals, a,b){return a(self, locals)||b(self, locals);},
11226
- '&':function(self, locals, a,b){return a(self, locals)&b(self, locals);},
11227
11496
  '!':function(self, locals, a){return !a(self, locals);},
11228
11497
 
11229
11498
  //Tokenized as operators but parsed as assignment/filters
11230
11499
  '=':true,
11231
11500
  '|':true
11232
11501
  });
11233
- /* jshint bitwise: true */
11234
11502
  var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
11235
11503
 
11236
11504
 
@@ -12268,16 +12536,17 @@ function $ParseProvider() {
12268
12536
  }
12269
12537
 
12270
12538
  function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
12271
- var unwatch;
12539
+ var unwatch, lastValue;
12272
12540
  return unwatch = scope.$watch(function oneTimeWatch(scope) {
12273
12541
  return parsedExpression(scope);
12274
12542
  }, function oneTimeListener(value, old, scope) {
12543
+ lastValue = value;
12275
12544
  if (isFunction(listener)) {
12276
12545
  listener.call(this, value, old, scope);
12277
12546
  }
12278
12547
  if (isAllDefined(value)) {
12279
12548
  scope.$$postDigest(function () {
12280
- if(isAllDefined(value)) unwatch();
12549
+ if(isAllDefined(lastValue)) unwatch();
12281
12550
  });
12282
12551
  }
12283
12552
  }, objectEquality);
@@ -12353,24 +12622,27 @@ function $ParseProvider() {
12353
12622
  * It can be used like so:
12354
12623
  *
12355
12624
  * ```js
12356
- * return $q(function(resolve, reject) {
12357
- * // perform some asynchronous operation, resolve or reject the promise when appropriate.
12358
- * setInterval(function() {
12359
- * if (pollStatus > 0) {
12360
- * resolve(polledValue);
12361
- * } else if (pollStatus < 0) {
12362
- * reject(polledValue);
12363
- * } else {
12364
- * pollStatus = pollAgain(function(value) {
12365
- * polledValue = value;
12366
- * });
12367
- * }
12368
- * }, 10000);
12369
- * }).
12370
- * then(function(value) {
12371
- * // handle success
12625
+ * // for the purpose of this example let's assume that variables `$q` and `okToGreet`
12626
+ * // are available in the current lexical scope (they could have been injected or passed in).
12627
+ *
12628
+ * function asyncGreet(name) {
12629
+ * // perform some asynchronous operation, resolve or reject the promise when appropriate.
12630
+ * return $q(function(resolve, reject) {
12631
+ * setTimeout(function() {
12632
+ * if (okToGreet(name)) {
12633
+ * resolve('Hello, ' + name + '!');
12634
+ * } else {
12635
+ * reject('Greeting ' + name + ' is not allowed.');
12636
+ * }
12637
+ * }, 1000);
12638
+ * });
12639
+ * }
12640
+ *
12641
+ * var promise = asyncGreet('Robin Hood');
12642
+ * promise.then(function(greeting) {
12643
+ * alert('Success: ' + greeting);
12372
12644
  * }, function(reason) {
12373
- * // handle failure
12645
+ * alert('Failed: ' + reason);
12374
12646
  * });
12375
12647
  * ```
12376
12648
  *
@@ -12386,7 +12658,7 @@ function $ParseProvider() {
12386
12658
  * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
12387
12659
  *
12388
12660
  * ```js
12389
- * // for the purpose of this example let's assume that variables `$q`, `scope` and `okToGreet`
12661
+ * // for the purpose of this example let's assume that variables `$q` and `okToGreet`
12390
12662
  * // are available in the current lexical scope (they could have been injected or passed in).
12391
12663
  *
12392
12664
  * function asyncGreet(name) {
@@ -14726,7 +14998,7 @@ function $SceDelegateProvider() {
14726
14998
  *
14727
14999
  * As of version 1.2, Angular ships with SCE enabled by default.
14728
15000
  *
14729
- * Note: When enabled (the default), IE8 in quirks mode is not supported. In this mode, IE8 allows
15001
+ * Note: When enabled (the default), IE<11 in quirks mode is not supported. In this mode, IE<11 allow
14730
15002
  * one to execute arbitrary javascript by the use of the expression() syntax. Refer
14731
15003
  * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
14732
15004
  * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
@@ -14773,7 +15045,7 @@ function $SceDelegateProvider() {
14773
15045
  *
14774
15046
  * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
14775
15047
  * $sce.getTrusted(context, value)} rather than to the value directly. Directives use {@link
14776
- * ng.$sce#parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
15048
+ * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
14777
15049
  * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
14778
15050
  *
14779
15051
  * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
@@ -15043,13 +15315,13 @@ function $SceProvider() {
15043
15315
  * sce.js and sceSpecs.js would need to be aware of this detail.
15044
15316
  */
15045
15317
 
15046
- this.$get = ['$parse', '$sniffer', '$sceDelegate', function(
15047
- $parse, $sniffer, $sceDelegate) {
15048
- // Prereq: Ensure that we're not running in IE8 quirks mode. In that mode, IE allows
15318
+ this.$get = ['$document', '$parse', '$sceDelegate', function(
15319
+ $document, $parse, $sceDelegate) {
15320
+ // Prereq: Ensure that we're not running in IE<11 quirks mode. In that mode, IE < 11 allow
15049
15321
  // the "expression(javascript expression)" syntax which is insecure.
15050
- if (enabled && $sniffer.msie && $sniffer.msieDocumentMode < 8) {
15322
+ if (enabled && $document[0].documentMode < 8) {
15051
15323
  throw $sceMinErr('iequirks',
15052
- 'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' +
15324
+ 'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' +
15053
15325
  'mode. You can fix this by adding the text <!doctype html> to the top of your HTML ' +
15054
15326
  'document. See http://docs.angularjs.org/api/ng.$sce for more information.');
15055
15327
  }
@@ -15272,7 +15544,7 @@ function $SceProvider() {
15272
15544
  *
15273
15545
  * @description
15274
15546
  * Shorthand method. `$sce.parseAsHtml(expression string)` →
15275
- * {@link ng.$sce#parse `$sce.parseAs($sce.HTML, value)`}
15547
+ * {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`}
15276
15548
  *
15277
15549
  * @param {string} expression String expression to compile.
15278
15550
  * @returns {function(context, locals)} a function which represents the compiled expression:
@@ -15289,7 +15561,7 @@ function $SceProvider() {
15289
15561
  *
15290
15562
  * @description
15291
15563
  * Shorthand method. `$sce.parseAsCss(value)` →
15292
- * {@link ng.$sce#parse `$sce.parseAs($sce.CSS, value)`}
15564
+ * {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`}
15293
15565
  *
15294
15566
  * @param {string} expression String expression to compile.
15295
15567
  * @returns {function(context, locals)} a function which represents the compiled expression:
@@ -15306,7 +15578,7 @@ function $SceProvider() {
15306
15578
  *
15307
15579
  * @description
15308
15580
  * Shorthand method. `$sce.parseAsUrl(value)` →
15309
- * {@link ng.$sce#parse `$sce.parseAs($sce.URL, value)`}
15581
+ * {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`}
15310
15582
  *
15311
15583
  * @param {string} expression String expression to compile.
15312
15584
  * @returns {function(context, locals)} a function which represents the compiled expression:
@@ -15323,7 +15595,7 @@ function $SceProvider() {
15323
15595
  *
15324
15596
  * @description
15325
15597
  * Shorthand method. `$sce.parseAsResourceUrl(value)` →
15326
- * {@link ng.$sce#parse `$sce.parseAs($sce.RESOURCE_URL, value)`}
15598
+ * {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`}
15327
15599
  *
15328
15600
  * @param {string} expression String expression to compile.
15329
15601
  * @returns {function(context, locals)} a function which represents the compiled expression:
@@ -15340,7 +15612,7 @@ function $SceProvider() {
15340
15612
  *
15341
15613
  * @description
15342
15614
  * Shorthand method. `$sce.parseAsJs(value)` →
15343
- * {@link ng.$sce#parse `$sce.parseAs($sce.JS, value)`}
15615
+ * {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`}
15344
15616
  *
15345
15617
  * @param {string} expression String expression to compile.
15346
15618
  * @returns {function(context, locals)} a function which represents the compiled expression:
@@ -15394,7 +15666,6 @@ function $SnifferProvider() {
15394
15666
  int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
15395
15667
  boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
15396
15668
  document = $document[0] || {},
15397
- documentMode = document.documentMode,
15398
15669
  vendorPrefix,
15399
15670
  vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/,
15400
15671
  bodyStyle = document.body && document.body.style,
@@ -15454,9 +15725,7 @@ function $SnifferProvider() {
15454
15725
  vendorPrefix: vendorPrefix,
15455
15726
  transitions : transitions,
15456
15727
  animations : animations,
15457
- android: android,
15458
- msie : msie,
15459
- msieDocumentMode: documentMode
15728
+ android: android
15460
15729
  };
15461
15730
  }];
15462
15731
  }
@@ -16161,17 +16430,17 @@ function filterFilter() {
16161
16430
  }
16162
16431
 
16163
16432
  var search = function(obj, text){
16164
- if (typeof text == 'string' && text.charAt(0) === '!') {
16433
+ if (typeof text === 'string' && text.charAt(0) === '!') {
16165
16434
  return !search(obj, text.substr(1));
16166
16435
  }
16167
16436
  switch (typeof obj) {
16168
- case "boolean":
16169
- case "number":
16170
- case "string":
16437
+ case 'boolean':
16438
+ case 'number':
16439
+ case 'string':
16171
16440
  return comparator(obj, text);
16172
- case "object":
16441
+ case 'object':
16173
16442
  switch (typeof text) {
16174
- case "object":
16443
+ case 'object':
16175
16444
  return comparator(obj, text);
16176
16445
  default:
16177
16446
  for ( var objKey in obj) {
@@ -16182,7 +16451,7 @@ function filterFilter() {
16182
16451
  break;
16183
16452
  }
16184
16453
  return false;
16185
- case "array":
16454
+ case 'array':
16186
16455
  for ( var i = 0; i < obj.length; i++) {
16187
16456
  if (search(obj[i], text)) {
16188
16457
  return true;
@@ -16194,13 +16463,13 @@ function filterFilter() {
16194
16463
  }
16195
16464
  };
16196
16465
  switch (typeof expression) {
16197
- case "boolean":
16198
- case "number":
16199
- case "string":
16466
+ case 'boolean':
16467
+ case 'number':
16468
+ case 'string':
16200
16469
  // Set up expression object and fall through
16201
16470
  expression = {$:expression};
16202
16471
  // jshint -W086
16203
- case "object":
16472
+ case 'object':
16204
16473
  // jshint +W086
16205
16474
  for (var key in expression) {
16206
16475
  (function(path) {
@@ -16239,6 +16508,7 @@ function filterFilter() {
16239
16508
  *
16240
16509
  * @param {number} amount Input to filter.
16241
16510
  * @param {string=} symbol Currency symbol or identifier to be displayed.
16511
+ * @param {number=} fractionSize Number of decimal places to round the amount to.
16242
16512
  * @returns {string} Formatted number.
16243
16513
  *
16244
16514
  *
@@ -16254,13 +16524,15 @@ function filterFilter() {
16254
16524
  <div ng-controller="ExampleController">
16255
16525
  <input type="number" ng-model="amount"> <br>
16256
16526
  default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
16257
- custom currency identifier (USD$): <span>{{amount | currency:"USD$"}}</span>
16527
+ custom currency identifier (USD$): <span id="currency-custom">{{amount | currency:"USD$"}}</span>
16528
+ no fractions (0): <span id="currency-no-fractions">{{amount | currency:"USD$":0}}</span>
16258
16529
  </div>
16259
16530
  </file>
16260
16531
  <file name="protractor.js" type="protractor">
16261
16532
  it('should init with 1234.56', function() {
16262
16533
  expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
16263
- expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('USD$1,234.56');
16534
+ expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56');
16535
+ expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235');
16264
16536
  });
16265
16537
  it('should update', function() {
16266
16538
  if (browser.params.browser == 'safari') {
@@ -16271,7 +16543,8 @@ function filterFilter() {
16271
16543
  element(by.model('amount')).clear();
16272
16544
  element(by.model('amount')).sendKeys('-1234');
16273
16545
  expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)');
16274
- expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('(USD$1,234.00)');
16546
+ expect(element(by.id('currency-custom')).getText()).toBe('(USD$1,234.00)');
16547
+ expect(element(by.id('currency-no-fractions')).getText()).toBe('(USD$1,234)');
16275
16548
  });
16276
16549
  </file>
16277
16550
  </example>
@@ -16279,13 +16552,20 @@ function filterFilter() {
16279
16552
  currencyFilter.$inject = ['$locale'];
16280
16553
  function currencyFilter($locale) {
16281
16554
  var formats = $locale.NUMBER_FORMATS;
16282
- return function(amount, currencySymbol){
16283
- if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM;
16555
+ return function(amount, currencySymbol, fractionSize){
16556
+ if (isUndefined(currencySymbol)) {
16557
+ currencySymbol = formats.CURRENCY_SYM;
16558
+ }
16559
+
16560
+ if (isUndefined(fractionSize)) {
16561
+ // TODO: read the default value from the locale file
16562
+ fractionSize = 2;
16563
+ }
16284
16564
 
16285
16565
  // if null or undefined pass it through
16286
16566
  return (amount == null)
16287
16567
  ? amount
16288
- : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).
16568
+ : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize).
16289
16569
  replace(/\u00A4/g, currencySymbol);
16290
16570
  };
16291
16571
  }
@@ -16802,7 +17082,7 @@ var uppercaseFilter = valueFn(uppercase);
16802
17082
  <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
16803
17083
  Limit {{letters}} to: <input type="number" step="1" ng-model="letterLimit">
16804
17084
  <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
16805
- Limit {{longNumber}} to: <input type="integer" ng-model="longNumberLimit">
17085
+ Limit {{longNumber}} to: <input type="number" step="1" ng-model="longNumberLimit">
16806
17086
  <p>Output long number: {{ longNumber | limitTo:longNumberLimit }}</p>
16807
17087
  </div>
16808
17088
  </file>
@@ -18039,15 +18319,13 @@ var formDirectiveFactory = function(isNgForm) {
18039
18319
  parentFormCtrl.$$renameControl(controller, alias);
18040
18320
  });
18041
18321
  }
18042
- if (parentFormCtrl !== nullFormCtrl) {
18043
- formElement.on('$destroy', function() {
18044
- parentFormCtrl.$removeControl(controller);
18045
- if (alias) {
18046
- setter(scope, alias, undefined, alias);
18047
- }
18048
- extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
18049
- });
18050
- }
18322
+ formElement.on('$destroy', function() {
18323
+ parentFormCtrl.$removeControl(controller);
18324
+ if (alias) {
18325
+ setter(scope, alias, undefined, alias);
18326
+ }
18327
+ extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
18328
+ });
18051
18329
  }
18052
18330
  };
18053
18331
  }
@@ -21294,7 +21572,7 @@ var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate
21294
21572
  *
21295
21573
  * You may also bypass sanitization for values you know are safe. To do so, bind to
21296
21574
  * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}. See the example
21297
- * under {@link ng.$sce#Example Strict Contextual Escaping (SCE)}.
21575
+ * under {@link ng.$sce#show-me-an-example-using-sce- Strict Contextual Escaping (SCE)}.
21298
21576
  *
21299
21577
  * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
21300
21578
  * will have an exception (instead of an exploit.)
@@ -21606,8 +21884,8 @@ function classDirective(name, selector) {
21606
21884
  The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
21607
21885
  Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
21608
21886
  any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
21609
- to view the step by step details of {@link ngAnimate.$animate#addclass $animate.addClass} and
21610
- {@link ngAnimate.$animate#removeclass $animate.removeClass}.
21887
+ to view the step by step details of {@link ng.$animate#addClass $animate.addClass} and
21888
+ {@link ng.$animate#removeClass $animate.removeClass}.
21611
21889
  */
21612
21890
  var ngClassDirective = classDirective('', true);
21613
21891
 
@@ -22013,7 +22291,7 @@ var ngControllerDirective = [function() {
22013
22291
  * @description
22014
22292
  * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
22015
22293
  *
22016
- * This is necessary when developing things like Google Chrome Extensions.
22294
+ * This is necessary when developing things like Google Chrome Extensions or Universal Windows Apps.
22017
22295
  *
22018
22296
  * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
22019
22297
  * For Angular to be CSP compatible there are only two things that we need to do differently:
@@ -22709,7 +22987,7 @@ forEach(
22709
22987
  Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>
22710
22988
  Show when checked:
22711
22989
  <span ng-if="checked" class="animate-if">
22712
- I'm removed when the checkbox is unchecked.
22990
+ This is removed when the checkbox is unchecked.
22713
22991
  </span>
22714
22992
  </file>
22715
22993
  <file name="animations.css">
@@ -22763,15 +23041,15 @@ var ngIfDirective = ['$animate', function($animate) {
22763
23041
  });
22764
23042
  }
22765
23043
  } else {
22766
- if(previousElements) {
23044
+ if (previousElements) {
22767
23045
  previousElements.remove();
22768
23046
  previousElements = null;
22769
23047
  }
22770
- if(childScope) {
23048
+ if (childScope) {
22771
23049
  childScope.$destroy();
22772
23050
  childScope = null;
22773
23051
  }
22774
- if(block) {
23052
+ if (block) {
22775
23053
  previousElements = getBlockNodes(block.clone);
22776
23054
  $animate.leave(previousElements).then(function() {
22777
23055
  previousElements = null;
@@ -22793,10 +23071,10 @@ var ngIfDirective = ['$animate', function($animate) {
22793
23071
  * Fetches, compiles and includes an external HTML fragment.
22794
23072
  *
22795
23073
  * By default, the template URL is restricted to the same domain and protocol as the
22796
- * application document. This is done by calling {@link ng.$sce#getTrustedResourceUrl
23074
+ * application document. This is done by calling {@link $sce#getTrustedResourceUrl
22797
23075
  * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
22798
23076
  * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
22799
- * [wrap them](ng.$sce#trustAsResourceUrl) as trusted values. Refer to Angular's {@link
23077
+ * {@link $sce#trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
22800
23078
  * ng.$sce Strict Contextual Escaping}.
22801
23079
  *
22802
23080
  * In addition, the browser's
@@ -23495,13 +23773,6 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
23495
23773
  * For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
23496
23774
  * will be associated by item identity in the array.
23497
23775
  *
23498
- * * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
23499
- * intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
23500
- * when a filter is active on the repeater, but the filtered result set is empty.
23501
- *
23502
- * For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
23503
- * the items have been processed through the filter.
23504
- *
23505
23776
  * For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
23506
23777
  * `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
23507
23778
  * with the corresponding item in the array by identity. Moving the same object in array would move the DOM
@@ -23514,6 +23785,13 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
23514
23785
  * For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
23515
23786
  * to items in conjunction with a tracking expression.
23516
23787
  *
23788
+ * * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
23789
+ * intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
23790
+ * when a filter is active on the repeater, but the filtered result set is empty.
23791
+ *
23792
+ * For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
23793
+ * the items have been processed through the filter.
23794
+ *
23517
23795
  * @example
23518
23796
  * This example initializes the scope to a list of names and
23519
23797
  * then uses `ngRepeat` to display every person:
@@ -24001,7 +24279,9 @@ var ngShowDirective = ['$animate', function($animate) {
24001
24279
  // we can control when the element is actually displayed on screen without having
24002
24280
  // to have a global/greedy CSS selector that breaks when other animations are run.
24003
24281
  // Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
24004
- $animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, NG_HIDE_IN_PROGRESS_CLASS);
24282
+ $animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, {
24283
+ tempClasses : NG_HIDE_IN_PROGRESS_CLASS
24284
+ });
24005
24285
  });
24006
24286
  }
24007
24287
  };
@@ -24158,7 +24438,9 @@ var ngHideDirective = ['$animate', function($animate) {
24158
24438
  scope.$watch(attr.ngHide, function ngHideWatchAction(value){
24159
24439
  // The comment inside of the ngShowDirective explains why we add and
24160
24440
  // remove a temporary class for the show/hide animation
24161
- $animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, NG_HIDE_IN_PROGRESS_CLASS);
24441
+ $animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, {
24442
+ tempClasses : NG_HIDE_IN_PROGRESS_CLASS
24443
+ });
24162
24444
  });
24163
24445
  }
24164
24446
  };
@@ -24583,9 +24865,23 @@ var ngOptionsMinErr = minErr('ngOptions');
24583
24865
  * <div class="alert alert-info">
24584
24866
  * **Note:** Using `select as` will bind the result of the `select as` expression to the model, but
24585
24867
  * the value of the `<select>` and `<option>` html elements will be either the index (for array data sources)
24586
- * or property name (for object data sources) of the value within the collection.
24868
+ * or property name (for object data sources) of the value within the collection.
24587
24869
  * </div>
24588
24870
  *
24871
+ * **Note:** Using `select as` together with `trackexpr` is not recommended.
24872
+ * Reasoning:
24873
+ * - Example: &lt;select ng-options="item.subItem as item.label for item in values track by item.id" ng-model="selected"&gt;
24874
+ * values: [{id: 1, label: 'aLabel', subItem: {name: 'aSubItem'}}, {id: 2, label: 'bLabel', subItem: {name: 'bSubItem'}}],
24875
+ * $scope.selected = {name: 'aSubItem'};
24876
+ * - track by is always applied to `value`, with the purpose of preserving the selection,
24877
+ * (to `item` in this case)
24878
+ * - to calculate whether an item is selected we do the following:
24879
+ * 1. apply `track by` to the values in the array, e.g.
24880
+ * In the example: [1,2]
24881
+ * 2. apply `track by` to the already selected value in `ngModel`:
24882
+ * In the example: this is not possible, as `track by` refers to `item.id`, but the selected
24883
+ * value from `ngModel` is `{name: aSubItem}`.
24884
+ *
24589
24885
  * @param {string} ngModel Assignable angular expression to data-bind to.
24590
24886
  * @param {string=} name Property name of the form under which the control is published.
24591
24887
  * @param {string=} required The control is considered valid only if value is entered.
@@ -24622,23 +24918,6 @@ var ngOptionsMinErr = minErr('ngOptions');
24622
24918
  * used to identify the objects in the array. The `trackexpr` will most likely refer to the
24623
24919
  * `value` variable (e.g. `value.propertyName`). With this the selection is preserved
24624
24920
  * even when the options are recreated (e.g. reloaded from the server).
24625
-
24626
- * <div class="alert alert-info">
24627
- * **Note:** Using `select as` together with `trackexpr` is not possible (and will throw).
24628
- * Reasoning:
24629
- * - Example: <select ng-options="item.subItem as item.label for item in values track by item.id" ng-model="selected">
24630
- * values: [{id: 1, label: 'aLabel', subItem: {name: 'aSubItem'}}, {id: 2, label: 'bLabel', subItem: {name: 'bSubItemß'}}],
24631
- * $scope.selected = {name: 'aSubItem'};
24632
- * - track by is always applied to `value`, with purpose to preserve the selection,
24633
- * (to `item` in this case)
24634
- * - to calculate whether an item is selected we do the following:
24635
- * 1. apply `track by` to the values in the array, e.g.
24636
- * In the example: [1,2]
24637
- * 2. apply `track by` to the already selected value in `ngModel`:
24638
- * In the example: this is not possible, as `track by` refers to `item.id`, but the selected
24639
- * value from `ngModel` is `{name: aSubItem}`.
24640
- *
24641
- * </div>
24642
24921
  *
24643
24922
  * @example
24644
24923
  <example module="selectExample">
@@ -24748,7 +25027,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
24748
25027
  // Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
24749
25028
  // Adding an <option selected="selected"> element to a <select required="required"> should
24750
25029
  // automatically select the new element
24751
- if (element[0].hasAttribute('selected')) {
25030
+ if (element && element[0].hasAttribute('selected')) {
24752
25031
  element[0].selected = true;
24753
25032
  }
24754
25033
  };
@@ -24911,13 +25190,6 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
24911
25190
  //re-usable object to represent option's locals
24912
25191
  locals = {};
24913
25192
 
24914
- if (trackFn && selectAsFn) {
24915
- throw ngOptionsMinErr('trkslct',
24916
- "Comprehension expression cannot contain both selectAs '{0}' " +
24917
- "and trackBy '{1}' expressions.",
24918
- selectAs, track);
24919
- }
24920
-
24921
25193
  if (nullOption) {
24922
25194
  // compile the element since there might be bindings in it
24923
25195
  $compile(nullOption)(scope);
@@ -25008,7 +25280,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
25008
25280
  function createIsSelectedFn(viewValue) {
25009
25281
  var selectedSet;
25010
25282
  if (multiple) {
25011
- if (!selectAs && trackFn && isArray(viewValue)) {
25283
+ if (trackFn && isArray(viewValue)) {
25012
25284
 
25013
25285
  selectedSet = new HashMap([]);
25014
25286
  for (var trackIndex = 0; trackIndex < viewValue.length; trackIndex++) {
@@ -25018,15 +25290,16 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
25018
25290
  } else {
25019
25291
  selectedSet = new HashMap(viewValue);
25020
25292
  }
25021
- } else if (!selectAsFn && trackFn) {
25293
+ } else if (trackFn) {
25022
25294
  viewValue = callExpression(trackFn, null, viewValue);
25023
25295
  }
25296
+
25024
25297
  return function isSelected(key, value) {
25025
25298
  var compareValueFn;
25026
- if (selectAsFn) {
25027
- compareValueFn = selectAsFn;
25028
- } else if (trackFn) {
25299
+ if (trackFn) {
25029
25300
  compareValueFn = trackFn;
25301
+ } else if (selectAsFn) {
25302
+ compareValueFn = selectAsFn;
25030
25303
  } else {
25031
25304
  compareValueFn = valueFn;
25032
25305
  }
@@ -25046,6 +25319,23 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
25046
25319
  }
25047
25320
  }
25048
25321
 
25322
+ /**
25323
+ * A new labelMap is created with each render.
25324
+ * This function is called for each existing option with added=false,
25325
+ * and each new option with added=true.
25326
+ * - Labels that are passed to this method twice,
25327
+ * (once with added=true and once with added=false) will end up with a value of 0, and
25328
+ * will cause no change to happen to the corresponding option.
25329
+ * - Labels that are passed to this method only once with added=false will end up with a
25330
+ * value of -1 and will eventually be passed to selectCtrl.removeOption()
25331
+ * - Labels that are passed to this method only once with added=true will end up with a
25332
+ * value of 1 and will eventually be passed to selectCtrl.addOption()
25333
+ */
25334
+ function updateLabelMap(labelMap, label, added) {
25335
+ labelMap[label] = labelMap[label] || 0;
25336
+ labelMap[label] += (added ? 1 : -1);
25337
+ }
25338
+
25049
25339
  function render() {
25050
25340
  renderScheduled = false;
25051
25341
 
@@ -25063,6 +25353,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
25063
25353
  value,
25064
25354
  groupLength, length,
25065
25355
  groupIndex, index,
25356
+ labelMap = {},
25066
25357
  selected,
25067
25358
  isSelected = createIsSelectedFn(viewValue),
25068
25359
  anySelected = false,
@@ -25145,6 +25436,8 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
25145
25436
  // reuse elements
25146
25437
  lastElement = existingOption.element;
25147
25438
  if (existingOption.label !== option.label) {
25439
+ updateLabelMap(labelMap, existingOption.label, false);
25440
+ updateLabelMap(labelMap, option.label, true);
25148
25441
  lastElement.text(existingOption.label = option.label);
25149
25442
  }
25150
25443
  if (existingOption.id !== option.id) {
@@ -25184,7 +25477,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
25184
25477
  id: option.id,
25185
25478
  selected: option.selected
25186
25479
  });
25187
- selectCtrl.addOption(option.label, element);
25480
+ updateLabelMap(labelMap, option.label, true);
25188
25481
  if (lastElement) {
25189
25482
  lastElement.after(element);
25190
25483
  } else {
@@ -25197,9 +25490,16 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
25197
25490
  index++; // increment since the existingOptions[0] is parent element not OPTION
25198
25491
  while(existingOptions.length > index) {
25199
25492
  option = existingOptions.pop();
25200
- selectCtrl.removeOption(option.label);
25493
+ updateLabelMap(labelMap, option.label, false);
25201
25494
  option.element.remove();
25202
25495
  }
25496
+ forEach(labelMap, function (count, label) {
25497
+ if (count > 0) {
25498
+ selectCtrl.addOption(label);
25499
+ } else if (count < 0) {
25500
+ selectCtrl.removeOption(label);
25501
+ }
25502
+ });
25203
25503
  }
25204
25504
  // remove any excessive OPTGROUPs from select
25205
25505
  while(optionGroupsCache.length > groupIndex) {