angularjs-rails 1.3.4 → 1.3.6

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 (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 +121 -120
  4. data/vendor/assets/javascripts/angular-aria.js +39 -28
  5. data/vendor/assets/javascripts/angular-cookies.js +1 -1
  6. data/vendor/assets/javascripts/angular-loader.js +2 -2
  7. data/vendor/assets/javascripts/angular-messages.js +1 -1
  8. data/vendor/assets/javascripts/angular-mocks.js +10 -8
  9. data/vendor/assets/javascripts/angular-resource.js +1 -1
  10. data/vendor/assets/javascripts/angular-route.js +2 -3
  11. data/vendor/assets/javascripts/angular-sanitize.js +7 -5
  12. data/vendor/assets/javascripts/angular-scenario.js +316 -231
  13. data/vendor/assets/javascripts/angular-touch.js +1 -1
  14. data/vendor/assets/javascripts/angular.js +314 -229
  15. data/vendor/assets/javascripts/unstable/angular-animate.js +121 -120
  16. data/vendor/assets/javascripts/unstable/angular-aria.js +39 -28
  17. data/vendor/assets/javascripts/unstable/angular-cookies.js +1 -1
  18. data/vendor/assets/javascripts/unstable/angular-loader.js +2 -2
  19. data/vendor/assets/javascripts/unstable/angular-messages.js +1 -1
  20. data/vendor/assets/javascripts/unstable/angular-mocks.js +10 -8
  21. data/vendor/assets/javascripts/unstable/angular-resource.js +1 -1
  22. data/vendor/assets/javascripts/unstable/angular-route.js +2 -3
  23. data/vendor/assets/javascripts/unstable/angular-sanitize.js +7 -5
  24. data/vendor/assets/javascripts/unstable/angular-scenario.js +316 -231
  25. data/vendor/assets/javascripts/unstable/angular-touch.js +1 -1
  26. data/vendor/assets/javascripts/unstable/angular.js +314 -229
  27. metadata +2 -2
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.3.4
2
+ * @license AngularJS v1.3.36
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.4
2
+ * @license AngularJS v1.3.36
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -54,7 +54,7 @@ function minErr(module, ErrorConstructor) {
54
54
  return match;
55
55
  });
56
56
 
57
- message = message + '\nhttp://errors.angularjs.org/1.3.4/' +
57
+ message = message + '\nhttp://errors.angularjs.org/1.3.36/' +
58
58
  (module ? module + '/' : '') + code;
59
59
  for (i = 2; i < arguments.length; i++) {
60
60
  message = message + (i == 2 ? '?' : '&') + 'p' + (i - 2) + '=' +
@@ -226,8 +226,8 @@ if ('i' !== 'I'.toLowerCase()) {
226
226
  }
227
227
 
228
228
 
229
- var /** holds major version number for IE or NaN for real browsers */
230
- msie,
229
+ var
230
+ msie, // holds major version number for IE, or NaN if UA is not IE.
231
231
  jqLite, // delay binding since jQuery could be loaded after us.
232
232
  jQuery, // delay binding
233
233
  slice = [].slice,
@@ -1028,12 +1028,16 @@ function toJsonReplacer(key, value) {
1028
1028
  * stripped since angular uses this notation internally.
1029
1029
  *
1030
1030
  * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
1031
- * @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace.
1031
+ * @param {boolean|number=} pretty If set to true, the JSON output will contain newlines and whitespace.
1032
+ * If set to an integer, the JSON output will contain that many spaces per indentation (the default is 2).
1032
1033
  * @returns {string|undefined} JSON-ified string representing `obj`.
1033
1034
  */
1034
1035
  function toJson(obj, pretty) {
1035
1036
  if (typeof obj === 'undefined') return undefined;
1036
- return JSON.stringify(obj, toJsonReplacer, pretty ? ' ' : null);
1037
+ if (!isNumber(pretty)) {
1038
+ pretty = pretty ? 2 : null;
1039
+ }
1040
+ return JSON.stringify(obj, toJsonReplacer, pretty);
1037
1041
  }
1038
1042
 
1039
1043
 
@@ -2081,7 +2085,8 @@ function toDebugString(obj) {
2081
2085
  $TimeoutProvider,
2082
2086
  $$RAFProvider,
2083
2087
  $$AsyncCallbackProvider,
2084
- $WindowProvider
2088
+ $WindowProvider,
2089
+ $$jqLiteProvider
2085
2090
  */
2086
2091
 
2087
2092
 
@@ -2100,11 +2105,11 @@ function toDebugString(obj) {
2100
2105
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
2101
2106
  */
2102
2107
  var version = {
2103
- full: '1.3.4', // all of these placeholder strings will be replaced by grunt's
2108
+ full: '1.3.36', // all of these placeholder strings will be replaced by grunt's
2104
2109
  major: 1, // package task
2105
2110
  minor: 3,
2106
- dot: 4,
2107
- codeName: 'highfalutin-petroglyph'
2111
+ dot: 36,
2112
+ codeName: 'robofunky-danceblaster'
2108
2113
  };
2109
2114
 
2110
2115
 
@@ -2234,7 +2239,8 @@ function publishExternalAPI(angular) {
2234
2239
  $timeout: $TimeoutProvider,
2235
2240
  $window: $WindowProvider,
2236
2241
  $$rAF: $$RAFProvider,
2237
- $$asyncCallback: $$AsyncCallbackProvider
2242
+ $$asyncCallback: $$AsyncCallbackProvider,
2243
+ $$jqLite: $$jqLiteProvider
2238
2244
  });
2239
2245
  }
2240
2246
  ]);
@@ -3244,6 +3250,27 @@ forEach({
3244
3250
  JQLite.prototype.unbind = JQLite.prototype.off;
3245
3251
  });
3246
3252
 
3253
+
3254
+ // Provider for private $$jqLite service
3255
+ function $$jqLiteProvider() {
3256
+ this.$get = function $$jqLite() {
3257
+ return extend(JQLite, {
3258
+ hasClass: function(node, classes) {
3259
+ if (node.attr) node = node[0];
3260
+ return jqLiteHasClass(node, classes);
3261
+ },
3262
+ addClass: function(node, classes) {
3263
+ if (node.attr) node = node[0];
3264
+ return jqLiteAddClass(node, classes);
3265
+ },
3266
+ removeClass: function(node, classes) {
3267
+ if (node.attr) node = node[0];
3268
+ return jqLiteRemoveClass(node, classes);
3269
+ }
3270
+ });
3271
+ };
3272
+ }
3273
+
3247
3274
  /**
3248
3275
  * Computes a hash of an 'obj'.
3249
3276
  * Hash of a:
@@ -3496,6 +3523,7 @@ function annotate(fn, strictDi, name) {
3496
3523
  * Return an instance of the service.
3497
3524
  *
3498
3525
  * @param {string} name The name of the instance to retrieve.
3526
+ * @param {string} caller An optional string to provide the origin of the function call for error messages.
3499
3527
  * @return {*} The instance.
3500
3528
  */
3501
3529
 
@@ -3946,14 +3974,17 @@ function createInjector(modulesToLoad, strictDi) {
3946
3974
  }
3947
3975
  },
3948
3976
  providerInjector = (providerCache.$injector =
3949
- createInternalInjector(providerCache, function() {
3977
+ createInternalInjector(providerCache, function(serviceName, caller) {
3978
+ if (angular.isString(caller)) {
3979
+ path.push(caller);
3980
+ }
3950
3981
  throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
3951
3982
  })),
3952
3983
  instanceCache = {},
3953
3984
  instanceInjector = (instanceCache.$injector =
3954
- createInternalInjector(instanceCache, function(servicename) {
3955
- var provider = providerInjector.get(servicename + providerSuffix);
3956
- return instanceInjector.invoke(provider.$get, provider, undefined, servicename);
3985
+ createInternalInjector(instanceCache, function(serviceName, caller) {
3986
+ var provider = providerInjector.get(serviceName + providerSuffix, caller);
3987
+ return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
3957
3988
  }));
3958
3989
 
3959
3990
 
@@ -3988,7 +4019,7 @@ function createInjector(modulesToLoad, strictDi) {
3988
4019
 
3989
4020
  function enforceReturnValue(name, factory) {
3990
4021
  return function enforcedReturnValue() {
3991
- var result = instanceInjector.invoke(factory, this, undefined, name);
4022
+ var result = instanceInjector.invoke(factory, this);
3992
4023
  if (isUndefined(result)) {
3993
4024
  throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
3994
4025
  }
@@ -4083,7 +4114,7 @@ function createInjector(modulesToLoad, strictDi) {
4083
4114
 
4084
4115
  function createInternalInjector(cache, factory) {
4085
4116
 
4086
- function getService(serviceName) {
4117
+ function getService(serviceName, caller) {
4087
4118
  if (cache.hasOwnProperty(serviceName)) {
4088
4119
  if (cache[serviceName] === INSTANTIATING) {
4089
4120
  throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
@@ -4094,7 +4125,7 @@ function createInjector(modulesToLoad, strictDi) {
4094
4125
  try {
4095
4126
  path.unshift(serviceName);
4096
4127
  cache[serviceName] = INSTANTIATING;
4097
- return cache[serviceName] = factory(serviceName);
4128
+ return cache[serviceName] = factory(serviceName, caller);
4098
4129
  } catch (err) {
4099
4130
  if (cache[serviceName] === INSTANTIATING) {
4100
4131
  delete cache[serviceName];
@@ -4126,7 +4157,7 @@ function createInjector(modulesToLoad, strictDi) {
4126
4157
  args.push(
4127
4158
  locals && locals.hasOwnProperty(key)
4128
4159
  ? locals[key]
4129
- : getService(key)
4160
+ : getService(key, serviceName)
4130
4161
  );
4131
4162
  }
4132
4163
  if (isArray(fn)) {
@@ -4870,6 +4901,11 @@ function Browser(window, document, $log, $sniffer) {
4870
4901
  }
4871
4902
  }
4872
4903
 
4904
+ function getHash(url) {
4905
+ var index = url.indexOf('#');
4906
+ return index === -1 ? '' : url.substr(index + 1);
4907
+ }
4908
+
4873
4909
  /**
4874
4910
  * @private
4875
4911
  * Note: this method is used only by scenario runner
@@ -4999,8 +5035,10 @@ function Browser(window, document, $log, $sniffer) {
4999
5035
  }
5000
5036
  if (replace) {
5001
5037
  location.replace(url);
5002
- } else {
5038
+ } else if (!sameBase) {
5003
5039
  location.href = url;
5040
+ } else {
5041
+ location.hash = getHash(url);
5004
5042
  }
5005
5043
  }
5006
5044
  return self;
@@ -5779,7 +5817,7 @@ function $TemplateCacheProvider() {
5779
5817
  * #### `multiElement`
5780
5818
  * When this property is set to true, the HTML compiler will collect DOM nodes between
5781
5819
  * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
5782
- * together as the directive elements. It is recomended that this feature be used on directives
5820
+ * together as the directive elements. It is recommended that this feature be used on directives
5783
5821
  * which are not strictly behavioural (such as {@link ngClick}), and which
5784
5822
  * do not manipulate or replace child nodes (such as {@link ngInclude}).
5785
5823
  *
@@ -6467,7 +6505,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6467
6505
  * Retrieves or overrides the default regular expression that is used for whitelisting of safe
6468
6506
  * urls during a[href] sanitization.
6469
6507
  *
6470
- * The sanitization is a security measure aimed at prevent XSS attacks via html links.
6508
+ * The sanitization is a security measure aimed at preventing XSS attacks via html links.
6471
6509
  *
6472
6510
  * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
6473
6511
  * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
@@ -6534,7 +6572,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6534
6572
  * * `ng-binding` CSS class
6535
6573
  * * `$binding` data property containing an array of the binding expressions
6536
6574
  *
6537
- * You may want to use this in production for a significant performance boost. See
6575
+ * You may want to disable this in production for a significant performance boost. See
6538
6576
  * {@link guide/production#disabling-debug-data Disabling Debug Data} for more.
6539
6577
  *
6540
6578
  * The default value is true.
@@ -6571,6 +6609,21 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6571
6609
  };
6572
6610
 
6573
6611
  Attributes.prototype = {
6612
+ /**
6613
+ * @ngdoc method
6614
+ * @name $compile.directive.Attributes#$normalize
6615
+ * @kind function
6616
+ *
6617
+ * @description
6618
+ * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
6619
+ * `data-`) to its normalized, camelCase form.
6620
+ *
6621
+ * Also there is special case for Moz prefix starting with upper case letter.
6622
+ *
6623
+ * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
6624
+ *
6625
+ * @param {string} name Name to normalize
6626
+ */
6574
6627
  $normalize: directiveNormalize,
6575
6628
 
6576
6629
 
@@ -8149,13 +8202,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8149
8202
  var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
8150
8203
  /**
8151
8204
  * Converts all accepted directives format into proper directive name.
8152
- * All of these will become 'myDirective':
8153
- * my:Directive
8154
- * my-directive
8155
- * x-my-directive
8156
- * data-my:directive
8157
- *
8158
- * Also there is special case for Moz prefix starting with upper case letter.
8159
8205
  * @param name Name to normalize
8160
8206
  */
8161
8207
  function directiveNormalize(name) {
@@ -9091,12 +9137,14 @@ function $HttpProvider() {
9091
9137
  * `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
9092
9138
  * transform function or an array of such functions. The transform function takes the http
9093
9139
  * request body and headers and returns its transformed (typically serialized) version.
9094
- * See {@link #overriding-the-default-transformations-per-request Overriding the Default Transformations}
9140
+ * See {@link ng.$http#overriding-the-default-transformations-per-request
9141
+ * Overriding the Default Transformations}
9095
9142
  * - **transformResponse** –
9096
9143
  * `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
9097
9144
  * transform function or an array of such functions. The transform function takes the http
9098
9145
  * response body and headers and returns its transformed (typically deserialized) version.
9099
- * See {@link #overriding-the-default-transformations-per-request Overriding the Default Transformations}
9146
+ * See {@link ng.$http#overriding-the-default-transformations-per-request
9147
+ * Overriding the Default Transformations}
9100
9148
  * - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
9101
9149
  * GET request, otherwise if a cache instance built with
9102
9150
  * {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
@@ -9506,8 +9554,7 @@ function $HttpProvider() {
9506
9554
  if (isDefined(cachedResp)) {
9507
9555
  if (isPromiseLike(cachedResp)) {
9508
9556
  // cached request has already been sent, but there is no response yet
9509
- cachedResp.then(removePendingReq, removePendingReq);
9510
- return cachedResp;
9557
+ cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult);
9511
9558
  } else {
9512
9559
  // serving from cache
9513
9560
  if (isArray(cachedResp)) {
@@ -9585,6 +9632,9 @@ function $HttpProvider() {
9585
9632
  });
9586
9633
  }
9587
9634
 
9635
+ function resolvePromiseWithResult(result) {
9636
+ resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText);
9637
+ }
9588
9638
 
9589
9639
  function removePendingReq() {
9590
9640
  var idx = $http.pendingRequests.indexOf(config);
@@ -9746,7 +9796,9 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
9746
9796
 
9747
9797
  function completeRequest(callback, status, response, headersString, statusText) {
9748
9798
  // cancel timeout and subsequent timeout promise resolution
9749
- timeoutId && $browserDefer.cancel(timeoutId);
9799
+ if (timeoutId !== undefined) {
9800
+ $browserDefer.cancel(timeoutId);
9801
+ }
9750
9802
  jsonpDone = xhr = null;
9751
9803
 
9752
9804
  callback(status, response, headersString, statusText);
@@ -10194,33 +10246,33 @@ function $IntervalProvider() {
10194
10246
  * // Don't start a new fight if we are already fighting
10195
10247
  * if ( angular.isDefined(stop) ) return;
10196
10248
  *
10197
- * stop = $interval(function() {
10198
- * if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
10199
- * $scope.blood_1 = $scope.blood_1 - 3;
10200
- * $scope.blood_2 = $scope.blood_2 - 4;
10201
- * } else {
10202
- * $scope.stopFight();
10203
- * }
10204
- * }, 100);
10205
- * };
10249
+ * stop = $interval(function() {
10250
+ * if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
10251
+ * $scope.blood_1 = $scope.blood_1 - 3;
10252
+ * $scope.blood_2 = $scope.blood_2 - 4;
10253
+ * } else {
10254
+ * $scope.stopFight();
10255
+ * }
10256
+ * }, 100);
10257
+ * };
10206
10258
  *
10207
- * $scope.stopFight = function() {
10208
- * if (angular.isDefined(stop)) {
10209
- * $interval.cancel(stop);
10210
- * stop = undefined;
10211
- * }
10212
- * };
10259
+ * $scope.stopFight = function() {
10260
+ * if (angular.isDefined(stop)) {
10261
+ * $interval.cancel(stop);
10262
+ * stop = undefined;
10263
+ * }
10264
+ * };
10213
10265
  *
10214
- * $scope.resetFight = function() {
10215
- * $scope.blood_1 = 100;
10216
- * $scope.blood_2 = 120;
10217
- * };
10266
+ * $scope.resetFight = function() {
10267
+ * $scope.blood_1 = 100;
10268
+ * $scope.blood_2 = 120;
10269
+ * };
10218
10270
  *
10219
- * $scope.$on('$destroy', function() {
10220
- * // Make sure that the interval is destroyed too
10221
- * $scope.stopFight();
10222
- * });
10223
- * }])
10271
+ * $scope.$on('$destroy', function() {
10272
+ * // Make sure that the interval is destroyed too
10273
+ * $scope.stopFight();
10274
+ * });
10275
+ * }])
10224
10276
  * // Register the 'myCurrentTime' directive factory method.
10225
10277
  * // We inject $interval and dateFilter service since the factory method is DI.
10226
10278
  * .directive('myCurrentTime', ['$interval', 'dateFilter',
@@ -10463,6 +10515,10 @@ function stripHash(url) {
10463
10515
  return index == -1 ? url : url.substr(0, index);
10464
10516
  }
10465
10517
 
10518
+ function trimEmptyHash(url) {
10519
+ return url.replace(/(#.+)|#$/, '$1');
10520
+ }
10521
+
10466
10522
 
10467
10523
  function stripFile(url) {
10468
10524
  return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
@@ -10574,16 +10630,25 @@ function LocationHashbangUrl(appBase, hashPrefix) {
10574
10630
  */
10575
10631
  this.$$parse = function(url) {
10576
10632
  var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
10577
- var withoutHashUrl = withoutBaseUrl.charAt(0) == '#'
10578
- ? beginsWith(hashPrefix, withoutBaseUrl)
10579
- : (this.$$html5)
10580
- ? withoutBaseUrl
10581
- : '';
10633
+ var withoutHashUrl;
10582
10634
 
10583
- if (!isString(withoutHashUrl)) {
10584
- throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
10585
- hashPrefix);
10635
+ if (withoutBaseUrl.charAt(0) === '#') {
10636
+
10637
+ // The rest of the url starts with a hash so we have
10638
+ // got either a hashbang path or a plain hash fragment
10639
+ withoutHashUrl = beginsWith(hashPrefix, withoutBaseUrl);
10640
+ if (isUndefined(withoutHashUrl)) {
10641
+ // There was no hashbang prefix so we just have a hash fragment
10642
+ withoutHashUrl = withoutBaseUrl;
10643
+ }
10644
+
10645
+ } else {
10646
+ // There was no hashbang path nor hash fragment:
10647
+ // If we are in HTML5 mode we use what is left as the path;
10648
+ // Otherwise we ignore what is left
10649
+ withoutHashUrl = this.$$html5 ? withoutBaseUrl : '';
10586
10650
  }
10651
+
10587
10652
  parseAppUrl(withoutHashUrl, this);
10588
10653
 
10589
10654
  this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
@@ -10946,7 +11011,7 @@ var locationPrototype = {
10946
11011
  *
10947
11012
  *
10948
11013
  * ```js
10949
- * // given url http://example.com/some/path?foo=bar&baz=xoxo#hashValue
11014
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
10950
11015
  * var hash = $location.hash();
10951
11016
  * // => "hashValue"
10952
11017
  * ```
@@ -11298,10 +11363,11 @@ function $LocationProvider() {
11298
11363
 
11299
11364
  // update browser
11300
11365
  $rootScope.$watch(function $locationWatch() {
11301
- var oldUrl = $browser.url();
11366
+ var oldUrl = trimEmptyHash($browser.url());
11367
+ var newUrl = trimEmptyHash($location.absUrl());
11302
11368
  var oldState = $browser.state();
11303
11369
  var currentReplace = $location.$$replace;
11304
- var urlOrStateChanged = oldUrl !== $location.absUrl() ||
11370
+ var urlOrStateChanged = oldUrl !== newUrl ||
11305
11371
  ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);
11306
11372
 
11307
11373
  if (initializing || urlOrStateChanged) {
@@ -12104,8 +12170,8 @@ Parser.prototype = {
12104
12170
  logicalAND: function() {
12105
12171
  var left = this.equality();
12106
12172
  var token;
12107
- if ((token = this.expect('&&'))) {
12108
- left = this.binaryFn(left, token.text, this.logicalAND(), true);
12173
+ while ((token = this.expect('&&'))) {
12174
+ left = this.binaryFn(left, token.text, this.equality(), true);
12109
12175
  }
12110
12176
  return left;
12111
12177
  },
@@ -12113,8 +12179,8 @@ Parser.prototype = {
12113
12179
  equality: function() {
12114
12180
  var left = this.relational();
12115
12181
  var token;
12116
- if ((token = this.expect('==','!=','===','!=='))) {
12117
- left = this.binaryFn(left, token.text, this.equality());
12182
+ while ((token = this.expect('==','!=','===','!=='))) {
12183
+ left = this.binaryFn(left, token.text, this.relational());
12118
12184
  }
12119
12185
  return left;
12120
12186
  },
@@ -12122,8 +12188,8 @@ Parser.prototype = {
12122
12188
  relational: function() {
12123
12189
  var left = this.additive();
12124
12190
  var token;
12125
- if ((token = this.expect('<', '>', '<=', '>='))) {
12126
- left = this.binaryFn(left, token.text, this.relational());
12191
+ while ((token = this.expect('<', '>', '<=', '>='))) {
12192
+ left = this.binaryFn(left, token.text, this.additive());
12127
12193
  }
12128
12194
  return left;
12129
12195
  },
@@ -12215,7 +12281,7 @@ Parser.prototype = {
12215
12281
  var args = argsFn.length ? [] : null;
12216
12282
 
12217
12283
  return function $parseFunctionCall(scope, locals) {
12218
- var context = contextGetter ? contextGetter(scope, locals) : scope;
12284
+ var context = contextGetter ? contextGetter(scope, locals) : isDefined(contextGetter) ? undefined : scope;
12219
12285
  var fn = fnGetter(scope, locals, context) || noop;
12220
12286
 
12221
12287
  if (args) {
@@ -12228,13 +12294,13 @@ Parser.prototype = {
12228
12294
  ensureSafeObject(context, expressionText);
12229
12295
  ensureSafeFunction(fn, expressionText);
12230
12296
 
12231
- // IE stupidity! (IE doesn't have apply for some native functions)
12297
+ // IE doesn't have apply for some native functions
12232
12298
  var v = fn.apply
12233
12299
  ? fn.apply(context, args)
12234
12300
  : fn(args[0], args[1], args[2], args[3], args[4]);
12235
12301
 
12236
12302
  return ensureSafeObject(v, expressionText);
12237
- };
12303
+ };
12238
12304
  },
12239
12305
 
12240
12306
  // This is used with json array declaration
@@ -15870,7 +15936,9 @@ function $SnifferProvider() {
15870
15936
  // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
15871
15937
  // it. In particular the event is not fired when backspace or delete key are pressed or
15872
15938
  // when cut operation is performed.
15873
- if (event == 'input' && msie == 9) return false;
15939
+ // IE10+ implements 'input' event but it erroneously fires under various situations,
15940
+ // e.g. when placeholder changes, or a form is focused.
15941
+ if (event === 'input' && msie <= 11) return false;
15874
15942
 
15875
15943
  if (isUndefined(eventSupport[event])) {
15876
15944
  var divElm = document.createElement('div');
@@ -15916,14 +15984,9 @@ function $TemplateRequestProvider() {
15916
15984
  var transformResponse = $http.defaults && $http.defaults.transformResponse;
15917
15985
 
15918
15986
  if (isArray(transformResponse)) {
15919
- var original = transformResponse;
15920
- transformResponse = [];
15921
- for (var i = 0; i < original.length; ++i) {
15922
- var transformer = original[i];
15923
- if (transformer !== defaultHttpResponseTransform) {
15924
- transformResponse.push(transformer);
15925
- }
15926
- }
15987
+ transformResponse = transformResponse.filter(function(transformer) {
15988
+ return transformer !== defaultHttpResponseTransform;
15989
+ });
15927
15990
  } else if (transformResponse === defaultHttpResponseTransform) {
15928
15991
  transformResponse = null;
15929
15992
  }
@@ -15935,18 +15998,16 @@ function $TemplateRequestProvider() {
15935
15998
 
15936
15999
  return $http.get(tpl, httpOptions)
15937
16000
  .then(function(response) {
15938
- var html = response.data;
15939
16001
  self.totalPendingRequests--;
15940
- $templateCache.put(tpl, html);
15941
- return html;
16002
+ return response.data;
15942
16003
  }, handleError);
15943
16004
 
15944
- function handleError() {
16005
+ function handleError(resp) {
15945
16006
  self.totalPendingRequests--;
15946
16007
  if (!ignoreRequestError) {
15947
16008
  throw $compileMinErr('tpload', 'Failed to load template: {0}', tpl);
15948
16009
  }
15949
- return $q.reject();
16010
+ return $q.reject(resp);
15950
16011
  }
15951
16012
  }
15952
16013
 
@@ -16569,106 +16630,103 @@ function filterFilter() {
16569
16630
  return function(array, expression, comparator) {
16570
16631
  if (!isArray(array)) return array;
16571
16632
 
16572
- var comparatorType = typeof(comparator),
16573
- predicates = [];
16574
-
16575
- predicates.check = function(value, index) {
16576
- for (var j = 0; j < predicates.length; j++) {
16577
- if (!predicates[j](value, index)) {
16578
- return false;
16579
- }
16580
- }
16581
- return true;
16582
- };
16583
-
16584
- if (comparatorType !== 'function') {
16585
- if (comparatorType === 'boolean' && comparator) {
16586
- comparator = function(obj, text) {
16587
- return angular.equals(obj, text);
16588
- };
16589
- } else {
16590
- comparator = function(obj, text) {
16591
- if (obj && text && typeof obj === 'object' && typeof text === 'object') {
16592
- for (var objKey in obj) {
16593
- if (objKey.charAt(0) !== '$' && hasOwnProperty.call(obj, objKey) &&
16594
- comparator(obj[objKey], text[objKey])) {
16595
- return true;
16596
- }
16597
- }
16598
- return false;
16599
- }
16600
- text = ('' + text).toLowerCase();
16601
- return ('' + obj).toLowerCase().indexOf(text) > -1;
16602
- };
16603
- }
16604
- }
16633
+ var predicateFn;
16634
+ var matchAgainstAnyProp;
16605
16635
 
16606
- var search = function(obj, text) {
16607
- if (typeof text === 'string' && text.charAt(0) === '!') {
16608
- return !search(obj, text.substr(1));
16609
- }
16610
- switch (typeof obj) {
16611
- case 'boolean':
16612
- case 'number':
16613
- case 'string':
16614
- return comparator(obj, text);
16615
- case 'object':
16616
- switch (typeof text) {
16617
- case 'object':
16618
- return comparator(obj, text);
16619
- default:
16620
- for (var objKey in obj) {
16621
- if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
16622
- return true;
16623
- }
16624
- }
16625
- break;
16626
- }
16627
- return false;
16628
- case 'array':
16629
- for (var i = 0; i < obj.length; i++) {
16630
- if (search(obj[i], text)) {
16631
- return true;
16632
- }
16633
- }
16634
- return false;
16635
- default:
16636
- return false;
16637
- }
16638
- };
16639
16636
  switch (typeof expression) {
16637
+ case 'function':
16638
+ predicateFn = expression;
16639
+ break;
16640
16640
  case 'boolean':
16641
16641
  case 'number':
16642
16642
  case 'string':
16643
- // Set up expression object and fall through
16644
- expression = {$:expression};
16645
- // jshint -W086
16643
+ matchAgainstAnyProp = true;
16644
+ //jshint -W086
16646
16645
  case 'object':
16647
- // jshint +W086
16648
- for (var key in expression) {
16649
- (function(path) {
16650
- if (typeof expression[path] === 'undefined') return;
16651
- predicates.push(function(value) {
16652
- return search(path == '$' ? value : (value && value[path]), expression[path]);
16653
- });
16654
- })(key);
16655
- }
16656
- break;
16657
- case 'function':
16658
- predicates.push(expression);
16646
+ //jshint +W086
16647
+ predicateFn = createPredicateFn(expression, comparator, matchAgainstAnyProp);
16659
16648
  break;
16660
16649
  default:
16661
16650
  return array;
16662
16651
  }
16663
- var filtered = [];
16664
- for (var j = 0; j < array.length; j++) {
16665
- var value = array[j];
16666
- if (predicates.check(value, j)) {
16667
- filtered.push(value);
16652
+
16653
+ return array.filter(predicateFn);
16654
+ };
16655
+ }
16656
+
16657
+ // Helper functions for `filterFilter`
16658
+ function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
16659
+ var predicateFn;
16660
+
16661
+ if (comparator === true) {
16662
+ comparator = equals;
16663
+ } else if (!isFunction(comparator)) {
16664
+ comparator = function(actual, expected) {
16665
+ if (isObject(actual) || isObject(expected)) {
16666
+ // Prevent an object to be considered equal to a string like `'[object'`
16667
+ return false;
16668
16668
  }
16669
- }
16670
- return filtered;
16669
+
16670
+ actual = lowercase('' + actual);
16671
+ expected = lowercase('' + expected);
16672
+ return actual.indexOf(expected) !== -1;
16673
+ };
16674
+ }
16675
+
16676
+ predicateFn = function(item) {
16677
+ return deepCompare(item, expression, comparator, matchAgainstAnyProp);
16671
16678
  };
16679
+
16680
+ return predicateFn;
16681
+ }
16682
+
16683
+ function deepCompare(actual, expected, comparator, matchAgainstAnyProp) {
16684
+ var actualType = typeof actual;
16685
+ var expectedType = typeof expected;
16686
+
16687
+ if ((expectedType === 'string') && (expected.charAt(0) === '!')) {
16688
+ return !deepCompare(actual, expected.substring(1), comparator, matchAgainstAnyProp);
16689
+ } else if (actualType === 'array') {
16690
+ // In case `actual` is an array, consider it a match
16691
+ // if ANY of it's items matches `expected`
16692
+ return actual.some(function(item) {
16693
+ return deepCompare(item, expected, comparator, matchAgainstAnyProp);
16694
+ });
16695
+ }
16696
+
16697
+ switch (actualType) {
16698
+ case 'object':
16699
+ var key;
16700
+ if (matchAgainstAnyProp) {
16701
+ for (key in actual) {
16702
+ if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator)) {
16703
+ return true;
16704
+ }
16705
+ }
16706
+ return false;
16707
+ } else if (expectedType === 'object') {
16708
+ for (key in expected) {
16709
+ var expectedVal = expected[key];
16710
+ if (isFunction(expectedVal)) {
16711
+ continue;
16712
+ }
16713
+
16714
+ var keyIsDollar = key === '$';
16715
+ var actualVal = keyIsDollar ? actual : actual[key];
16716
+ if (!deepCompare(actualVal, expectedVal, comparator, keyIsDollar)) {
16717
+ return false;
16718
+ }
16719
+ }
16720
+ return true;
16721
+ } else {
16722
+ return comparator(actual, expected);
16723
+ }
16724
+ break;
16725
+ case 'function':
16726
+ return false;
16727
+ default:
16728
+ return comparator(actual, expected);
16729
+ }
16672
16730
  }
16673
16731
 
16674
16732
  /**
@@ -16821,7 +16879,6 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
16821
16879
  if (numStr.indexOf('e') !== -1) {
16822
16880
  var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
16823
16881
  if (match && match[2] == '-' && match[3] > fractionSize + 1) {
16824
- numStr = '0';
16825
16882
  number = 0;
16826
16883
  } else {
16827
16884
  formatedText = numStr;
@@ -16842,10 +16899,6 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
16842
16899
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
16843
16900
  number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
16844
16901
 
16845
- if (number === 0) {
16846
- isNegative = false;
16847
- }
16848
-
16849
16902
  var fraction = ('' + number).split(DECIMAL_SEP);
16850
16903
  var whole = fraction[0];
16851
16904
  fraction = fraction[1] || '';
@@ -16878,12 +16931,16 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
16878
16931
 
16879
16932
  if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
16880
16933
  } else {
16881
-
16882
- if (fractionSize > 0 && number > -1 && number < 1) {
16934
+ if (fractionSize > 0 && number < 1) {
16883
16935
  formatedText = number.toFixed(fractionSize);
16936
+ number = parseFloat(formatedText);
16884
16937
  }
16885
16938
  }
16886
16939
 
16940
+ if (number === 0) {
16941
+ isNegative = false;
16942
+ }
16943
+
16887
16944
  parts.push(isNegative ? pattern.negPre : pattern.posPre,
16888
16945
  formatedText,
16889
16946
  isNegative ? pattern.negSuf : pattern.posSuf);
@@ -17173,25 +17230,31 @@ function dateFilter($locale) {
17173
17230
  * the binding is automatically converted to JSON.
17174
17231
  *
17175
17232
  * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
17233
+ * @param {number=} spacing The number of spaces to use per indentation, defaults to 2.
17176
17234
  * @returns {string} JSON string.
17177
17235
  *
17178
17236
  *
17179
17237
  * @example
17180
17238
  <example>
17181
17239
  <file name="index.html">
17182
- <pre>{{ {'name':'value'} | json }}</pre>
17240
+ <pre id="default-spacing">{{ {'name':'value'} | json }}</pre>
17241
+ <pre id="custom-spacing">{{ {'name':'value'} | json:4 }}</pre>
17183
17242
  </file>
17184
17243
  <file name="protractor.js" type="protractor">
17185
17244
  it('should jsonify filtered objects', function() {
17186
- expect(element(by.binding("{'name':'value'}")).getText()).toMatch(/\{\n "name": ?"value"\n}/);
17245
+ expect(element(by.id('default-spacing')).getText()).toMatch(/\{\n "name": ?"value"\n}/);
17246
+ expect(element(by.id('custom-spacing')).getText()).toMatch(/\{\n "name": ?"value"\n}/);
17187
17247
  });
17188
17248
  </file>
17189
17249
  </example>
17190
17250
  *
17191
17251
  */
17192
17252
  function jsonFilter() {
17193
- return function(object) {
17194
- return toJson(object, true);
17253
+ return function(object, spacing) {
17254
+ if (isUndefined(spacing)) {
17255
+ spacing = 2;
17256
+ }
17257
+ return toJson(object, spacing);
17195
17258
  };
17196
17259
  }
17197
17260
 
@@ -17511,12 +17574,29 @@ function orderByFilter($parse) {
17511
17574
  function compare(v1, v2) {
17512
17575
  var t1 = typeof v1;
17513
17576
  var t2 = typeof v2;
17514
- if (t1 == t2) {
17515
- if (isDate(v1) && isDate(v2)) {
17516
- v1 = v1.valueOf();
17517
- v2 = v2.valueOf();
17577
+ // Prepare values for Abstract Relational Comparison
17578
+ // (http://www.ecma-international.org/ecma-262/5.1/#sec-11.8.5):
17579
+ // If the resulting values are identical, return 0 to prevent
17580
+ // incorrect re-ordering.
17581
+ if (t1 === t2 && t1 === "object") {
17582
+ // If types are both numbers, emulate abstract ToPrimitive() operation
17583
+ // in order to get primitive values suitable for comparison
17584
+ t1 = typeof (v1.valueOf ? v1 = v1.valueOf() : v1);
17585
+ t2 = typeof (v2.valueOf ? v2 = v2.valueOf() : v2);
17586
+ if (t1 === t2 && t1 === "object") {
17587
+ // Object.prototype.valueOf will return the original object, by
17588
+ // default. If we do not receive a primitive value, use ToString()
17589
+ // instead.
17590
+ t1 = typeof (v1.toString ? v1 = v1.toString() : v1);
17591
+ t2 = typeof (v2.toString ? v2 = v2.toString() : v2);
17592
+
17593
+ // If the end result of toString() for each item is the same, do not
17594
+ // perform relational comparison, and do not re-order objects.
17595
+ if (t1 === t2 && v1 === v2 || t1 === "object") return 0;
17518
17596
  }
17519
- if (t1 == "string") {
17597
+ }
17598
+ if (t1 === t2) {
17599
+ if (t1 === "string") {
17520
17600
  v1 = v1.toLowerCase();
17521
17601
  v2 = v2.toLowerCase();
17522
17602
  }
@@ -17582,9 +17662,8 @@ var htmlAnchorDirective = valueFn({
17582
17662
  * make the link go to the wrong URL if the user clicks it before
17583
17663
  * Angular has a chance to replace the `{{hash}}` markup with its
17584
17664
  * value. Until Angular replaces the markup the link will be broken
17585
- * and will most likely return a 404 error.
17586
- *
17587
- * The `ngHref` directive solves this problem.
17665
+ * and will most likely return a 404 error. The `ngHref` directive
17666
+ * solves this problem.
17588
17667
  *
17589
17668
  * The wrong way to write it:
17590
17669
  * ```html
@@ -19466,7 +19545,6 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
19466
19545
  }
19467
19546
 
19468
19547
  function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
19469
- var placeholder = element[0].placeholder, noevent = {};
19470
19548
  var type = lowercase(element[0].type);
19471
19549
 
19472
19550
  // In composition mode, users are still inputing intermediate text buffer,
@@ -19486,19 +19564,14 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
19486
19564
  }
19487
19565
 
19488
19566
  var listener = function(ev) {
19567
+ if (timeout) {
19568
+ $browser.defer.cancel(timeout);
19569
+ timeout = null;
19570
+ }
19489
19571
  if (composing) return;
19490
19572
  var value = element.val(),
19491
19573
  event = ev && ev.type;
19492
19574
 
19493
- // IE (11 and under) seem to emit an 'input' event if the placeholder value changes.
19494
- // We don't want to dirty the value when this happens, so we abort here. Unfortunately,
19495
- // IE also sends input events for other non-input-related things, (such as focusing on a
19496
- // form control), so this change is not entirely enough to solve this.
19497
- if (msie && (ev || noevent).type === 'input' && element[0].placeholder !== placeholder) {
19498
- placeholder = element[0].placeholder;
19499
- return;
19500
- }
19501
-
19502
19575
  // By default we will trim the value
19503
19576
  // If the attribute ng-trim exists we will avoid trimming
19504
19577
  // If input type is 'password', the value is never trimmed
@@ -19521,11 +19594,13 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
19521
19594
  } else {
19522
19595
  var timeout;
19523
19596
 
19524
- var deferListener = function(ev) {
19597
+ var deferListener = function(ev, input, origValue) {
19525
19598
  if (!timeout) {
19526
19599
  timeout = $browser.defer(function() {
19527
- listener(ev);
19528
19600
  timeout = null;
19601
+ if (!input || input.value !== origValue) {
19602
+ listener(ev);
19603
+ }
19529
19604
  });
19530
19605
  }
19531
19606
  };
@@ -19537,7 +19612,7 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
19537
19612
  // command modifiers arrows
19538
19613
  if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
19539
19614
 
19540
- deferListener(event);
19615
+ deferListener(event, this, this.value);
19541
19616
  });
19542
19617
 
19543
19618
  // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
@@ -20712,11 +20787,15 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20712
20787
  var prevModelValue = ctrl.$modelValue;
20713
20788
  var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
20714
20789
  ctrl.$$rawModelValue = modelValue;
20790
+
20715
20791
  if (allowInvalid) {
20716
20792
  ctrl.$modelValue = modelValue;
20717
20793
  writeToModelIfNeeded();
20718
20794
  }
20719
- ctrl.$$runValidators(parserValid, modelValue, viewValue, function(allValid) {
20795
+
20796
+ // Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date.
20797
+ // This can happen if e.g. $setViewValue is called from inside a parser
20798
+ ctrl.$$runValidators(parserValid, modelValue, ctrl.$$lastCommittedViewValue, function(allValid) {
20720
20799
  if (!allowInvalid) {
20721
20800
  // Note: Don't check ctrl.$valid here, as we could have
20722
20801
  // external validators (e.g. calculated on the server),
@@ -25058,7 +25137,7 @@ var ngSwitchDefaultDirective = ngDirective({
25058
25137
  }]);
25059
25138
  </script>
25060
25139
  <div ng-controller="ExampleController">
25061
- <input ng-model="title"><br>
25140
+ <input ng-model="title"> <br/>
25062
25141
  <textarea ng-model="text"></textarea> <br/>
25063
25142
  <pane title="{{title}}">{{text}}</pane>
25064
25143
  </div>
@@ -25136,7 +25215,6 @@ var scriptDirective = ['$templateCache', function($templateCache) {
25136
25215
  compile: function(element, attr) {
25137
25216
  if (attr.type == 'text/ng-template') {
25138
25217
  var templateUrl = attr.id,
25139
- // IE is not consistent, in scripts we have to read .text but in other nodes we have to read .textContent
25140
25218
  text = element[0].text;
25141
25219
 
25142
25220
  $templateCache.put(templateUrl, text);
@@ -25187,9 +25265,9 @@ var ngOptionsMinErr = minErr('ngOptions');
25187
25265
  * or property name (for object data sources) of the value within the collection. If a `track by` expression
25188
25266
  * is used, the result of that expression will be set as the value of the `option` and `select` elements.
25189
25267
  *
25190
- * ### `select as` with `trackexpr`
25268
+ * ### `select as` with `track by`
25191
25269
  *
25192
- * Using `select as` together with `trackexpr` is not recommended. Reasoning:
25270
+ * Using `select as` together with `track by` is not recommended. Reasoning:
25193
25271
  *
25194
25272
  * - Example: &lt;select ng-options="item.subItem as item.label for item in values track by item.id" ng-model="selected"&gt;
25195
25273
  * values: [{id: 1, label: 'aLabel', subItem: {name: 'aSubItem'}}, {id: 2, label: 'bLabel', subItem: {name: 'bSubItem'}}],
@@ -25214,8 +25292,10 @@ var ngOptionsMinErr = minErr('ngOptions');
25214
25292
  * * for array data sources:
25215
25293
  * * `label` **`for`** `value` **`in`** `array`
25216
25294
  * * `select` **`as`** `label` **`for`** `value` **`in`** `array`
25217
- * * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
25218
- * * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
25295
+ * * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
25296
+ * * `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
25297
+ * * `label` **`for`** `value` **`in`** `array` | orderBy:`orderexpr` **`track by`** `trackexpr`
25298
+ * (for including a filter with `track by`)
25219
25299
  * * for object data sources:
25220
25300
  * * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
25221
25301
  * * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
@@ -25357,7 +25437,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
25357
25437
  self.removeOption = function(value) {
25358
25438
  if (this.hasOption(value)) {
25359
25439
  delete optionsMap[value];
25360
- if (ngModelCtrl.$viewValue == value) {
25440
+ if (ngModelCtrl.$viewValue === value) {
25361
25441
  this.renderUnknownOption(value);
25362
25442
  }
25363
25443
  }
@@ -25824,18 +25904,23 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
25824
25904
  updateLabelMap(labelMap, option.label, false);
25825
25905
  option.element.remove();
25826
25906
  }
25827
- forEach(labelMap, function(count, label) {
25828
- if (count > 0) {
25829
- selectCtrl.addOption(label);
25830
- } else if (count < 0) {
25831
- selectCtrl.removeOption(label);
25832
- }
25833
- });
25834
25907
  }
25835
25908
  // remove any excessive OPTGROUPs from select
25836
25909
  while (optionGroupsCache.length > groupIndex) {
25837
- optionGroupsCache.pop()[0].element.remove();
25910
+ // remove all the labels in the option group
25911
+ optionGroup = optionGroupsCache.pop();
25912
+ for (index = 1; index < optionGroup.length; ++index) {
25913
+ updateLabelMap(labelMap, optionGroup[index].label, false);
25914
+ }
25915
+ optionGroup[0].element.remove();
25838
25916
  }
25917
+ forEach(labelMap, function(count, label) {
25918
+ if (count > 0) {
25919
+ selectCtrl.addOption(label);
25920
+ } else if (count < 0) {
25921
+ selectCtrl.removeOption(label);
25922
+ }
25923
+ });
25839
25924
  }
25840
25925
  }
25841
25926
  }