angularjs-rails 1.3.4 → 1.3.6

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 +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
  }