engine2 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/conf/message.yaml +7 -0
  3. data/conf/message_pl.yaml +7 -0
  4. data/engine2.gemspec +1 -1
  5. data/lib/engine2/action.rb +0 -5
  6. data/lib/engine2/core.rb +9 -8
  7. data/lib/engine2/handler.rb +2 -2
  8. data/lib/engine2/meta.rb +196 -33
  9. data/lib/engine2/meta/decode_meta.rb +2 -1
  10. data/lib/engine2/meta/form_meta.rb +3 -132
  11. data/lib/engine2/meta/infra_meta.rb +14 -9
  12. data/lib/engine2/meta/list_meta.rb +1 -4
  13. data/lib/engine2/meta/view_meta.rb +0 -14
  14. data/lib/engine2/models/UserInfo.rb +0 -4
  15. data/lib/engine2/scheme.rb +5 -5
  16. data/lib/engine2/type_info.rb +0 -1
  17. data/lib/engine2/version.rb +1 -1
  18. data/public/assets/javascripts.js +13 -13
  19. data/public/js/angular-animate.js +52 -20
  20. data/public/js/angular-cookies.js +2 -2
  21. data/public/js/angular-route.js +10 -7
  22. data/public/js/angular-sanitize.js +4 -4
  23. data/public/js/angular.js +322 -168
  24. data/public/js/lodash.custom.min.js +95 -93
  25. data/views/engine2.coffee +34 -29
  26. data/views/engine2actions.coffee +62 -60
  27. data/views/infra/index.slim +2 -2
  28. data/views/infra/inspect.slim +5 -1
  29. data/views/scaffold/confirm.slim +1 -1
  30. data/views/scaffold/list.slim +11 -23
  31. data/views/scaffold/message.slim +1 -1
  32. data/views/scaffold/search.slim +1 -2
  33. data/views/scaffold/view.slim +1 -1
  34. data/views/search_fields/checkbox2.slim +1 -1
  35. data/views/search_fields/checkbox_buttons.slim +3 -3
  36. data/views/search_fields/date_range.slim +4 -4
  37. data/views/search_fields/decimal_date_range.slim +4 -4
  38. data/views/search_fields/input_text.slim +2 -2
  39. data/views/search_fields/integer.slim +2 -2
  40. data/views/search_fields/integer_range.slim +2 -2
  41. data/views/search_fields/list_bsmselect.slim +2 -2
  42. data/views/search_fields/list_bsselect.slim +2 -2
  43. data/views/search_fields/list_buttons.slim +2 -2
  44. data/views/search_fields/list_select.slim +2 -2
  45. metadata +4 -4
@@ -1,9 +1,9 @@
1
1
  /**
2
- * @license AngularJS v1.5.3
2
+ * @license AngularJS v1.5.5
3
3
  * (c) 2010-2016 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
6
- (function(window, angular, undefined) {'use strict';
6
+ (function(window, angular) {'use strict';
7
7
 
8
8
  /**
9
9
  * @ngdoc module
@@ -1,9 +1,9 @@
1
1
  /**
2
- * @license AngularJS v1.5.3
2
+ * @license AngularJS v1.5.5
3
3
  * (c) 2010-2016 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
6
- (function(window, angular, undefined) {'use strict';
6
+ (function(window, angular) {'use strict';
7
7
 
8
8
  /**
9
9
  * @ngdoc module
@@ -22,11 +22,7 @@
22
22
  */
23
23
  /* global -ngRouteModule */
24
24
  var ngRouteModule = angular.module('ngRoute', ['ng']).
25
- provider('$route', $RouteProvider).
26
- // Ensure `$route` will be instantiated in time to capture the initial
27
- // `$locationChangeSuccess` event. This is necessary in case `ngView` is
28
- // included in an asynchronously loaded template.
29
- run(['$route', angular.noop]),
25
+ provider('$route', $RouteProvider),
30
26
  $routeMinErr = angular.$$minErr('ngRoute');
31
27
 
32
28
  /**
@@ -760,6 +756,13 @@ ngRouteModule.directive('ngView', ngViewFillContentFactory);
760
756
  *
761
757
  * The enter and leave animation occur concurrently.
762
758
  *
759
+ * @knownIssue If `ngView` is contained in an asynchronously loaded template (e.g. in another
760
+ * directive's templateUrl or in a template loaded using `ngInclude`), then you need to
761
+ * make sure that `$route` is instantiated in time to capture the initial
762
+ * `$locationChangeStart` event and load the appropriate view. One way to achieve this
763
+ * is to have it as a dependency in a `.run` block:
764
+ * `myModule.run(['$route', function() {}]);`
765
+ *
763
766
  * @scope
764
767
  * @priority 400
765
768
  * @param {string=} onload Expression to evaluate whenever the view updates.
@@ -1,9 +1,9 @@
1
1
  /**
2
- * @license AngularJS v1.5.3
2
+ * @license AngularJS v1.5.5
3
3
  * (c) 2010-2016 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
6
- (function(window, angular, undefined) {'use strict';
6
+ (function(window, angular) {'use strict';
7
7
 
8
8
  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
9
9
  * Any commits to this file should be reviewed with security in mind. *
@@ -349,7 +349,7 @@ function htmlParser(html, handler) {
349
349
  mXSSAttempts--;
350
350
 
351
351
  // strip custom-namespaced attributes on IE<=11
352
- if (document.documentMode <= 11) {
352
+ if (window.document.documentMode) {
353
353
  stripCustomNsAttrs(inertBodyElement);
354
354
  }
355
355
  html = inertBodyElement.innerHTML; //trigger mXSS
@@ -489,7 +489,7 @@ function htmlSanitizeWriter(buf, uriValidator) {
489
489
  * @param node Root element to process
490
490
  */
491
491
  function stripCustomNsAttrs(node) {
492
- if (node.nodeType === Node.ELEMENT_NODE) {
492
+ if (node.nodeType === window.Node.ELEMENT_NODE) {
493
493
  var attrs = node.attributes;
494
494
  for (var i = 0, l = attrs.length; i < l; i++) {
495
495
  var attrNode = attrs[i];
data/public/js/angular.js CHANGED
@@ -1,9 +1,9 @@
1
1
  /**
2
- * @license AngularJS v1.5.3
2
+ * @license AngularJS v1.5.5
3
3
  * (c) 2010-2016 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
6
- (function(window, document, undefined) {'use strict';
6
+ (function(window) {'use strict';
7
7
 
8
8
  /**
9
9
  * @description
@@ -57,7 +57,7 @@ function minErr(module, ErrorConstructor) {
57
57
  return match;
58
58
  });
59
59
 
60
- message += '\nhttp://errors.angularjs.org/1.5.3/' +
60
+ message += '\nhttp://errors.angularjs.org/1.5.5/' +
61
61
  (module ? module + '/' : '') + code;
62
62
 
63
63
  for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
@@ -171,6 +171,7 @@ function minErr(module, ErrorConstructor) {
171
171
  * @ngdoc module
172
172
  * @name ng
173
173
  * @module ng
174
+ * @installation
174
175
  * @description
175
176
  *
176
177
  * # ng (core module)
@@ -237,7 +238,7 @@ var
237
238
  * documentMode is an IE-only property
238
239
  * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
239
240
  */
240
- msie = document.documentMode;
241
+ msie = window.document.documentMode;
241
242
 
242
243
 
243
244
  /**
@@ -1047,6 +1048,41 @@ function shallowCopy(src, dst) {
1047
1048
  * @param {*} o1 Object or value to compare.
1048
1049
  * @param {*} o2 Object or value to compare.
1049
1050
  * @returns {boolean} True if arguments are equal.
1051
+ *
1052
+ * @example
1053
+ <example module="equalsExample" name="equalsExample">
1054
+ <file name="index.html">
1055
+ <div ng-controller="ExampleController">
1056
+ <form novalidate>
1057
+ <h3>User 1</h3>
1058
+ Name: <input type="text" ng-model="user1.name">
1059
+ Age: <input type="number" ng-model="user1.age">
1060
+
1061
+ <h3>User 2</h3>
1062
+ Name: <input type="text" ng-model="user2.name">
1063
+ Age: <input type="number" ng-model="user2.age">
1064
+
1065
+ <div>
1066
+ <br/>
1067
+ <input type="button" value="Compare" ng-click="compare()">
1068
+ </div>
1069
+ User 1: <pre>{{user1 | json}}</pre>
1070
+ User 2: <pre>{{user2 | json}}</pre>
1071
+ Equal: <pre>{{result}}</pre>
1072
+ </form>
1073
+ </div>
1074
+ </file>
1075
+ <file name="script.js">
1076
+ angular.module('equalsExample', []).controller('ExampleController', ['$scope', function($scope) {
1077
+ $scope.user1 = {};
1078
+ $scope.user2 = {};
1079
+ $scope.result;
1080
+ $scope.compare = function() {
1081
+ $scope.result = angular.equals($scope.user1, $scope.user2);
1082
+ };
1083
+ }]);
1084
+ </file>
1085
+ </example>
1050
1086
  */
1051
1087
  function equals(o1, o2) {
1052
1088
  if (o1 === o2) return true;
@@ -1093,8 +1129,8 @@ var csp = function() {
1093
1129
  if (!isDefined(csp.rules)) {
1094
1130
 
1095
1131
 
1096
- var ngCspElement = (document.querySelector('[ng-csp]') ||
1097
- document.querySelector('[data-ng-csp]'));
1132
+ var ngCspElement = (window.document.querySelector('[ng-csp]') ||
1133
+ window.document.querySelector('[data-ng-csp]'));
1098
1134
 
1099
1135
  if (ngCspElement) {
1100
1136
  var ngCspAttribute = ngCspElement.getAttribute('ng-csp') ||
@@ -1169,7 +1205,7 @@ var jq = function() {
1169
1205
  var i, ii = ngAttrPrefixes.length, prefix, name;
1170
1206
  for (i = 0; i < ii; ++i) {
1171
1207
  prefix = ngAttrPrefixes[i];
1172
- if (el = document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) {
1208
+ if (el = window.document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) {
1173
1209
  name = el.getAttribute(prefix + 'jq');
1174
1210
  break;
1175
1211
  }
@@ -1234,7 +1270,7 @@ function toJsonReplacer(key, value) {
1234
1270
  val = undefined;
1235
1271
  } else if (isWindow(value)) {
1236
1272
  val = '$WINDOW';
1237
- } else if (value && document === value) {
1273
+ } else if (value && window.document === value) {
1238
1274
  val = '$DOCUMENT';
1239
1275
  } else if (isScope(value)) {
1240
1276
  val = '$SCOPE';
@@ -1686,11 +1722,11 @@ function bootstrap(element, modules, config) {
1686
1722
  element = jqLite(element);
1687
1723
 
1688
1724
  if (element.injector()) {
1689
- var tag = (element[0] === document) ? 'document' : startingTag(element);
1725
+ var tag = (element[0] === window.document) ? 'document' : startingTag(element);
1690
1726
  //Encode angle brackets to prevent input from being sanitized to empty string #8683
1691
1727
  throw ngMinErr(
1692
1728
  'btstrpd',
1693
- "App Already Bootstrapped with this Element '{0}'",
1729
+ "App already bootstrapped with this element '{0}'",
1694
1730
  tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
1695
1731
  }
1696
1732
 
@@ -2137,9 +2173,9 @@ function setupModuleLoader(window) {
2137
2173
  * @ngdoc method
2138
2174
  * @name angular.Module#decorator
2139
2175
  * @module ng
2140
- * @param {string} The name of the service to decorate.
2141
- * @param {Function} This function will be invoked when the service needs to be
2142
- * instantiated and should return the decorated service instance.
2176
+ * @param {string} name The name of the service to decorate.
2177
+ * @param {Function} decorFn This function will be invoked when the service needs to be
2178
+ * instantiated and should return the decorated service instance.
2143
2179
  * @description
2144
2180
  * See {@link auto.$provide#decorator $provide.decorator()}.
2145
2181
  */
@@ -2443,11 +2479,11 @@ function toDebugString(obj) {
2443
2479
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
2444
2480
  */
2445
2481
  var version = {
2446
- full: '1.5.3', // all of these placeholder strings will be replaced by grunt's
2482
+ full: '1.5.5', // all of these placeholder strings will be replaced by grunt's
2447
2483
  major: 1, // package task
2448
2484
  minor: 5,
2449
- dot: 3,
2450
- codeName: 'diplohaplontic-meiosis'
2485
+ dot: 5,
2486
+ codeName: 'material-conspiration'
2451
2487
  };
2452
2488
 
2453
2489
 
@@ -2704,6 +2740,9 @@ function publishExternalAPI(angular) {
2704
2740
  * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2705
2741
  * parent element is reached.
2706
2742
  *
2743
+ * @knownIssue You cannot spy on `angular.element` if you are using Jasmine version 1.x. See
2744
+ * https://github.com/angular/angular.js/issues/14251 for more information.
2745
+ *
2707
2746
  * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
2708
2747
  * @returns {Object} jQuery object.
2709
2748
  */
@@ -2830,7 +2869,7 @@ function jqLiteBuildFragment(html, context) {
2830
2869
  }
2831
2870
 
2832
2871
  function jqLiteParseHTML(html, context) {
2833
- context = context || document;
2872
+ context = context || window.document;
2834
2873
  var parsed;
2835
2874
 
2836
2875
  if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
@@ -2856,7 +2895,7 @@ function jqLiteWrapNode(node, wrapper) {
2856
2895
 
2857
2896
 
2858
2897
  // IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
2859
- var jqLiteContains = Node.prototype.contains || function(arg) {
2898
+ var jqLiteContains = window.Node.prototype.contains || function(arg) {
2860
2899
  // jshint bitwise: false
2861
2900
  return !!(this.compareDocumentPosition(arg) & 16);
2862
2901
  // jshint bitwise: true
@@ -3128,8 +3167,8 @@ var JQLitePrototype = JQLite.prototype = {
3128
3167
  }
3129
3168
 
3130
3169
  // check if document is already loaded
3131
- if (document.readyState === 'complete') {
3132
- setTimeout(trigger);
3170
+ if (window.document.readyState === 'complete') {
3171
+ window.setTimeout(trigger);
3133
3172
  } else {
3134
3173
  this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
3135
3174
  // we can not use jqLite since we are not done loading and jQuery could be loaded later.
@@ -3819,6 +3858,7 @@ var $$HashMapProvider = [function() {
3819
3858
  /**
3820
3859
  * @ngdoc module
3821
3860
  * @name auto
3861
+ * @installation
3822
3862
  * @description
3823
3863
  *
3824
3864
  * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
@@ -3832,7 +3872,7 @@ var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
3832
3872
  var $injectorMinErr = minErr('$injector');
3833
3873
 
3834
3874
  function extractArgs(fn) {
3835
- var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
3875
+ var fnText = Function.prototype.toString.call(fn).replace(STRIP_COMMENTS, ''),
3836
3876
  args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS);
3837
3877
  return args;
3838
3878
  }
@@ -5252,6 +5292,9 @@ var $AnimateProvider = ['$provide', function($provide) {
5252
5292
  * // remove all the animation event listeners listening for `enter`
5253
5293
  * $animate.off('enter');
5254
5294
  *
5295
+ * // remove listeners for all animation events from the container element
5296
+ * $animate.off(container);
5297
+ *
5255
5298
  * // remove all the animation event listeners listening for `enter` on the given element and its children
5256
5299
  * $animate.off('enter', container);
5257
5300
  *
@@ -5260,7 +5303,9 @@ var $AnimateProvider = ['$provide', function($provide) {
5260
5303
  * $animate.off('enter', container, callback);
5261
5304
  * ```
5262
5305
  *
5263
- * @param {string} event the animation event (e.g. enter, leave, move, addClass, removeClass, etc...)
5306
+ * @param {string|DOMElement} event|container the animation event (e.g. enter, leave, move,
5307
+ * addClass, removeClass, etc...), or the container element. If it is the element, all other
5308
+ * arguments are ignored.
5264
5309
  * @param {DOMElement=} container the container element the event listener was placed on
5265
5310
  * @param {Function=} callback the callback function that was registered as the listener
5266
5311
  */
@@ -6833,8 +6878,8 @@ function $TemplateCacheProvider() {
6833
6878
  * this element). This is a good place to put initialization code for your controller.
6834
6879
  * * `$onChanges(changesObj)` - Called whenever one-way (`<`) or interpolation (`@`) bindings are updated. The
6835
6880
  * `changesObj` is a hash whose keys are the names of the bound properties that have changed, and the values are an
6836
- * object of the form `{ currentValue: ..., previousValue: ... }`. Use this hook to trigger updates within a component
6837
- * such as cloning the bound value to prevent accidental mutation of the outer value.
6881
+ * object of the form `{ currentValue, previousValue, isFirstChange() }`. Use this hook to trigger updates within a
6882
+ * component such as cloning the bound value to prevent accidental mutation of the outer value.
6838
6883
  * * `$onDestroy()` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
6839
6884
  * external resources, watches and event handlers. Note that components have their `$onDestroy()` hooks called in
6840
6885
  * the same order as the `$scope.$broadcast` events are triggered, which is top down. This means that parent
@@ -7381,6 +7426,9 @@ function $TemplateCacheProvider() {
7381
7426
 
7382
7427
  var $compileMinErr = minErr('$compile');
7383
7428
 
7429
+ function UNINITIALIZED_VALUE() {}
7430
+ var _UNINITIALIZED_VALUE = new UNINITIALIZED_VALUE();
7431
+
7384
7432
  /**
7385
7433
  * @ngdoc provider
7386
7434
  * @name $compileProvider
@@ -7405,7 +7453,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7405
7453
  function parseIsolateBindings(scope, directiveName, isController) {
7406
7454
  var LOCAL_REGEXP = /^\s*([@&<]|=(\*?))(\??)\s*(\w*)\s*$/;
7407
7455
 
7408
- var bindings = {};
7456
+ var bindings = createMap();
7409
7457
 
7410
7458
  forEach(scope, function(definition, scopeName) {
7411
7459
  if (definition in bindingCache) {
@@ -7579,6 +7627,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7579
7627
  * See {@link ng.$compile#-bindtocontroller- `bindToController`}.
7580
7628
  * - `transclude` – `{boolean=}` – whether {@link $compile#transclusion content transclusion} is enabled.
7581
7629
  * Disabled by default.
7630
+ * - `require` - `{Object<string, string>=}` - requires the controllers of other directives and binds them to
7631
+ * this component's controller. The object keys specify the property names under which the required
7632
+ * controllers (object values) will be bound. See {@link ng.$compile#-require- `require`}.
7582
7633
  * - `$...` – additional properties to attach to the directive factory function and the controller
7583
7634
  * constructor function. (This is used by the component router to annotate)
7584
7635
  *
@@ -7624,7 +7675,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7624
7675
  * See also {@link ng.$compileProvider#directive $compileProvider.directive()}.
7625
7676
  */
7626
7677
  this.component = function registerComponent(name, options) {
7627
- var controller = options.controller || noop;
7678
+ var controller = options.controller || function() {};
7628
7679
 
7629
7680
  function factory($injector) {
7630
7681
  function makeInjectable(fn) {
@@ -7638,7 +7689,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7638
7689
  }
7639
7690
 
7640
7691
  var template = (!options.template && !options.templateUrl ? '' : options.template);
7641
- return {
7692
+ var ddo = {
7642
7693
  controller: controller,
7643
7694
  controllerAs: identifierForController(options.controller) || options.controllerAs || '$ctrl',
7644
7695
  template: makeInjectable(template),
@@ -7649,14 +7700,27 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7649
7700
  restrict: 'E',
7650
7701
  require: options.require
7651
7702
  };
7703
+
7704
+ // Copy annotations (starting with $) over to the DDO
7705
+ forEach(options, function(val, key) {
7706
+ if (key.charAt(0) === '$') ddo[key] = val;
7707
+ });
7708
+
7709
+ return ddo;
7652
7710
  }
7653
7711
 
7654
- // Copy any annotation properties (starting with $) over to the factory function
7712
+ // TODO(pete) remove the following `forEach` before we release 1.6.0
7713
+ // The component-router@0.2.0 looks for the annotations on the controller constructor
7714
+ // Nothing in Angular looks for annotations on the factory function but we can't remove
7715
+ // it from 1.5.x yet.
7716
+
7717
+ // Copy any annotation properties (starting with $) over to the factory and controller constructor functions
7655
7718
  // These could be used by libraries such as the new component router
7656
7719
  forEach(options, function(val, key) {
7657
7720
  if (key.charAt(0) === '$') {
7658
7721
  factory[key] = val;
7659
- controller[key] = val;
7722
+ // Don't try to copy over annotations to named controller
7723
+ if (isFunction(controller)) controller[key] = val;
7660
7724
  }
7661
7725
  });
7662
7726
 
@@ -7793,7 +7857,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7793
7857
  $controller, $rootScope, $sce, $animate, $$sanitizeUri) {
7794
7858
 
7795
7859
  var SIMPLE_ATTR_NAME = /^\w/;
7796
- var specialAttrHolder = document.createElement('div');
7860
+ var specialAttrHolder = window.document.createElement('div');
7797
7861
 
7798
7862
 
7799
7863
 
@@ -8124,7 +8188,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8124
8188
  if (debugInfoEnabled) {
8125
8189
  content = ' ' + (directiveName || '') + ': ' + (comment || '') + ' ';
8126
8190
  }
8127
- return document.createComment(content);
8191
+ return window.document.createComment(content);
8128
8192
  };
8129
8193
 
8130
8194
  return compile;
@@ -8147,7 +8211,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8147
8211
  var domNode = $compileNodes[i];
8148
8212
 
8149
8213
  if (domNode.nodeType === NODE_TYPE_TEXT && domNode.nodeValue.match(NOT_EMPTY) /* non-empty */) {
8150
- jqLiteWrapNode(domNode, $compileNodes[i] = document.createElement('span'));
8214
+ jqLiteWrapNode(domNode, $compileNodes[i] = window.document.createElement('span'));
8151
8215
  }
8152
8216
  }
8153
8217
 
@@ -8840,7 +8904,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8840
8904
  replaceDirective = directive;
8841
8905
  }
8842
8906
 
8907
+ /* jshint -W021 */
8843
8908
  nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
8909
+ /* jshint +W021 */
8844
8910
  templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
8845
8911
  controllerDirectives: controllerDirectives,
8846
8912
  newScopeDirective: (newScopeDirective !== directive) && newScopeDirective,
@@ -8904,7 +8970,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8904
8970
 
8905
8971
  function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
8906
8972
  var i, ii, linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
8907
- attrs, removeScopeBindingWatches, removeControllerBindingWatches;
8973
+ attrs, scopeBindingInfo;
8908
8974
 
8909
8975
  if (compileNode === linkNode) {
8910
8976
  attrs = templateAttrs;
@@ -8943,11 +9009,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8943
9009
  compile.$$addScopeClass($element, true);
8944
9010
  isolateScope.$$isolateBindings =
8945
9011
  newIsolateScopeDirective.$$isolateBindings;
8946
- removeScopeBindingWatches = initializeDirectiveBindings(scope, attrs, isolateScope,
9012
+ scopeBindingInfo = initializeDirectiveBindings(scope, attrs, isolateScope,
8947
9013
  isolateScope.$$isolateBindings,
8948
9014
  newIsolateScopeDirective);
8949
- if (removeScopeBindingWatches) {
8950
- isolateScope.$on('$destroy', removeScopeBindingWatches);
9015
+ if (scopeBindingInfo.removeWatches) {
9016
+ isolateScope.$on('$destroy', scopeBindingInfo.removeWatches);
8951
9017
  }
8952
9018
  }
8953
9019
 
@@ -8958,8 +9024,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8958
9024
  var bindings = controllerDirective.$$bindings.bindToController;
8959
9025
 
8960
9026
  if (controller.identifier && bindings) {
8961
- removeControllerBindingWatches =
9027
+ controller.bindingInfo =
8962
9028
  initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
9029
+ } else {
9030
+ controller.bindingInfo = {};
8963
9031
  }
8964
9032
 
8965
9033
  var controllerResult = controller();
@@ -8968,8 +9036,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8968
9036
  // from setupControllers
8969
9037
  controller.instance = controllerResult;
8970
9038
  $element.data('$' + controllerDirective.name + 'Controller', controllerResult);
8971
- removeControllerBindingWatches && removeControllerBindingWatches();
8972
- removeControllerBindingWatches =
9039
+ controller.bindingInfo.removeWatches && controller.bindingInfo.removeWatches();
9040
+ controller.bindingInfo =
8973
9041
  initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
8974
9042
  }
8975
9043
  }
@@ -8985,6 +9053,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8985
9053
  // Handle the init and destroy lifecycle hooks on all controllers that have them
8986
9054
  forEach(elementControllers, function(controller) {
8987
9055
  var controllerInstance = controller.instance;
9056
+ if (isFunction(controllerInstance.$onChanges)) {
9057
+ controllerInstance.$onChanges(controller.bindingInfo.initialChanges);
9058
+ }
8988
9059
  if (isFunction(controllerInstance.$onInit)) {
8989
9060
  controllerInstance.$onInit();
8990
9061
  }
@@ -9441,7 +9512,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
9441
9512
  switch (type) {
9442
9513
  case 'svg':
9443
9514
  case 'math':
9444
- var wrapper = document.createElement('div');
9515
+ var wrapper = window.document.createElement('div');
9445
9516
  wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
9446
9517
  return wrapper.childNodes[0].childNodes;
9447
9518
  default:
@@ -9585,7 +9656,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
9585
9656
  // - remove them from the DOM
9586
9657
  // - allow them to still be traversed with .nextSibling
9587
9658
  // - allow a single fragment.qSA to fetch all elements being removed
9588
- var fragment = document.createDocumentFragment();
9659
+ var fragment = window.document.createDocumentFragment();
9589
9660
  for (i = 0; i < removeCount; i++) {
9590
9661
  fragment.appendChild(elementsToRemove[i]);
9591
9662
  }
@@ -9631,6 +9702,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
9631
9702
  // only occurs for isolate scopes and new scopes with controllerAs.
9632
9703
  function initializeDirectiveBindings(scope, attrs, destination, bindings, directive) {
9633
9704
  var removeWatchCollection = [];
9705
+ var initialChanges = {};
9634
9706
  var changes;
9635
9707
  forEach(bindings, function initializeBinding(definition, scopeName) {
9636
9708
  var attrName = definition.attrName,
@@ -9646,7 +9718,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
9646
9718
  destination[scopeName] = attrs[attrName] = void 0;
9647
9719
  }
9648
9720
  attrs.$observe(attrName, function(value) {
9649
- if (isString(value)) {
9721
+ if (isString(value) || isBoolean(value)) {
9650
9722
  var oldValue = destination[scopeName];
9651
9723
  recordChanges(scopeName, value, oldValue);
9652
9724
  destination[scopeName] = value;
@@ -9663,6 +9735,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
9663
9735
  // the value to boolean rather than a string, so we special case this situation
9664
9736
  destination[scopeName] = lastValue;
9665
9737
  }
9738
+ initialChanges[scopeName] = new SimpleChange(_UNINITIALIZED_VALUE, destination[scopeName]);
9666
9739
  break;
9667
9740
 
9668
9741
  case '=':
@@ -9718,11 +9791,16 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
9718
9791
  parentGet = $parse(attrs[attrName]);
9719
9792
 
9720
9793
  destination[scopeName] = parentGet(scope);
9794
+ initialChanges[scopeName] = new SimpleChange(_UNINITIALIZED_VALUE, destination[scopeName]);
9721
9795
 
9722
- removeWatch = scope.$watch(parentGet, function parentValueWatchAction(newParentValue) {
9723
- var oldValue = destination[scopeName];
9724
- recordChanges(scopeName, newParentValue, oldValue);
9725
- destination[scopeName] = newParentValue;
9796
+ removeWatch = scope.$watch(parentGet, function parentValueWatchAction(newValue, oldValue) {
9797
+ if (newValue === oldValue) {
9798
+ // If the new and old values are identical then this is the first time the watch has been triggered
9799
+ // So instead we use the current value on the destination as the old value
9800
+ oldValue = destination[scopeName];
9801
+ }
9802
+ recordChanges(scopeName, newValue, oldValue);
9803
+ destination[scopeName] = newValue;
9726
9804
  }, parentGet.literal);
9727
9805
 
9728
9806
  removeWatchCollection.push(removeWatch);
@@ -9759,7 +9837,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
9759
9837
  previousValue = changes[key].previousValue;
9760
9838
  }
9761
9839
  // Store this change
9762
- changes[key] = {previousValue: previousValue, currentValue: currentValue};
9840
+ changes[key] = new SimpleChange(previousValue, currentValue);
9763
9841
  }
9764
9842
  }
9765
9843
 
@@ -9769,15 +9847,25 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
9769
9847
  changes = undefined;
9770
9848
  }
9771
9849
 
9772
- return removeWatchCollection.length && function removeWatches() {
9773
- for (var i = 0, ii = removeWatchCollection.length; i < ii; ++i) {
9774
- removeWatchCollection[i]();
9850
+ return {
9851
+ initialChanges: initialChanges,
9852
+ removeWatches: removeWatchCollection.length && function removeWatches() {
9853
+ for (var i = 0, ii = removeWatchCollection.length; i < ii; ++i) {
9854
+ removeWatchCollection[i]();
9855
+ }
9775
9856
  }
9776
9857
  };
9777
9858
  }
9778
9859
  }];
9779
9860
  }
9780
9861
 
9862
+ function SimpleChange(previous, current) {
9863
+ this.previousValue = previous;
9864
+ this.currentValue = current;
9865
+ }
9866
+ SimpleChange.prototype.isFirstChange = function() { return this.previousValue === _UNINITIALIZED_VALUE; };
9867
+
9868
+
9781
9869
  var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
9782
9870
  /**
9783
9871
  * Converts all accepted directives format into proper directive name.
@@ -10717,7 +10805,7 @@ function $HttpProvider() {
10717
10805
  * That means changes to the properties of `data` are not local to the transform function (since Javascript passes objects by reference).
10718
10806
  * For example, when calling `$http.get(url, $scope.myObject)`, modifications to the object's properties in a transformRequest
10719
10807
  * function will be reflected on the scope and in any templates where the object is data-bound.
10720
- * To prevent his, transform functions should have no side-effects.
10808
+ * To prevent this, transform functions should have no side-effects.
10721
10809
  * If you need to modify properties, it is recommended to make a copy of the data, or create new object to return.
10722
10810
  * </div>
10723
10811
  *
@@ -10963,6 +11051,12 @@ function $HttpProvider() {
10963
11051
  * - **headers** – `{Object}` – Map of strings or functions which return strings representing
10964
11052
  * HTTP headers to send to the server. If the return value of a function is null, the
10965
11053
  * header will not be sent. Functions accept a config object as an argument.
11054
+ * - **eventHandlers** - `{Object}` - Event listeners to be bound to the XMLHttpRequest object.
11055
+ * To bind events to the XMLHttpRequest upload object, use `uploadEventHandlers`.
11056
+ * The handler will be called in the context of a `$apply` block.
11057
+ * - **uploadEventHandlers** - `{Object}` - Event listeners to be bound to the XMLHttpRequest upload
11058
+ * object. To bind events to the XMLHttpRequest object, use `eventHandlers`.
11059
+ * The handler will be called in the context of a `$apply` block.
10966
11060
  * - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
10967
11061
  * - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
10968
11062
  * - **transformRequest** –
@@ -11421,11 +11515,35 @@ function $HttpProvider() {
11421
11515
  }
11422
11516
 
11423
11517
  $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
11424
- config.withCredentials, config.responseType);
11518
+ config.withCredentials, config.responseType,
11519
+ createApplyHandlers(config.eventHandlers),
11520
+ createApplyHandlers(config.uploadEventHandlers));
11425
11521
  }
11426
11522
 
11427
11523
  return promise;
11428
11524
 
11525
+ function createApplyHandlers(eventHandlers) {
11526
+ if (eventHandlers) {
11527
+ var applyHandlers = {};
11528
+ forEach(eventHandlers, function(eventHandler, key) {
11529
+ applyHandlers[key] = function(event) {
11530
+ if (useApplyAsync) {
11531
+ $rootScope.$applyAsync(callEventHandler);
11532
+ } else if ($rootScope.$$phase) {
11533
+ callEventHandler();
11534
+ } else {
11535
+ $rootScope.$apply(callEventHandler);
11536
+ }
11537
+
11538
+ function callEventHandler() {
11539
+ eventHandler(event);
11540
+ }
11541
+ };
11542
+ });
11543
+ return applyHandlers;
11544
+ }
11545
+ }
11546
+
11429
11547
 
11430
11548
  /**
11431
11549
  * Callback registered to $httpBackend():
@@ -11546,7 +11664,7 @@ function $HttpBackendProvider() {
11546
11664
 
11547
11665
  function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
11548
11666
  // TODO(vojta): fix the signature
11549
- return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
11667
+ return function(method, url, post, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers) {
11550
11668
  $browser.$$incOutstandingRequestCount();
11551
11669
  url = url || $browser.url();
11552
11670
 
@@ -11606,6 +11724,14 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
11606
11724
  xhr.onerror = requestError;
11607
11725
  xhr.onabort = requestError;
11608
11726
 
11727
+ forEach(eventHandlers, function(value, key) {
11728
+ xhr.addEventListener(key, value);
11729
+ });
11730
+
11731
+ forEach(uploadEventHandlers, function(value, key) {
11732
+ xhr.upload.addEventListener(key, value);
11733
+ });
11734
+
11609
11735
  if (withCredentials) {
11610
11736
  xhr.withCredentials = true;
11611
11737
  }
@@ -13584,7 +13710,7 @@ Lexer.prototype = {
13584
13710
  this.readString(ch);
13585
13711
  } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
13586
13712
  this.readNumber();
13587
- } else if (this.isIdent(ch)) {
13713
+ } else if (this.isIdentifierStart(this.peekMultichar())) {
13588
13714
  this.readIdent();
13589
13715
  } else if (this.is(ch, '(){}[].,;:?')) {
13590
13716
  this.tokens.push({index: this.index, text: ch});
@@ -13628,12 +13754,49 @@ Lexer.prototype = {
13628
13754
  ch === '\n' || ch === '\v' || ch === '\u00A0');
13629
13755
  },
13630
13756
 
13631
- isIdent: function(ch) {
13757
+ isIdentifierStart: function(ch) {
13758
+ return this.options.isIdentifierStart ?
13759
+ this.options.isIdentifierStart(ch, this.codePointAt(ch)) :
13760
+ this.isValidIdentifierStart(ch);
13761
+ },
13762
+
13763
+ isValidIdentifierStart: function(ch) {
13632
13764
  return ('a' <= ch && ch <= 'z' ||
13633
13765
  'A' <= ch && ch <= 'Z' ||
13634
13766
  '_' === ch || ch === '$');
13635
13767
  },
13636
13768
 
13769
+ isIdentifierContinue: function(ch) {
13770
+ return this.options.isIdentifierContinue ?
13771
+ this.options.isIdentifierContinue(ch, this.codePointAt(ch)) :
13772
+ this.isValidIdentifierContinue(ch);
13773
+ },
13774
+
13775
+ isValidIdentifierContinue: function(ch, cp) {
13776
+ return this.isValidIdentifierStart(ch, cp) || this.isNumber(ch);
13777
+ },
13778
+
13779
+ codePointAt: function(ch) {
13780
+ if (ch.length === 1) return ch.charCodeAt(0);
13781
+ /*jshint bitwise: false*/
13782
+ return (ch.charCodeAt(0) << 10) + ch.charCodeAt(1) - 0x35FDC00;
13783
+ /*jshint bitwise: true*/
13784
+ },
13785
+
13786
+ peekMultichar: function() {
13787
+ var ch = this.text.charAt(this.index);
13788
+ var peek = this.peek();
13789
+ if (!peek) {
13790
+ return ch;
13791
+ }
13792
+ var cp1 = ch.charCodeAt(0);
13793
+ var cp2 = peek.charCodeAt(0);
13794
+ if (cp1 >= 0xD800 && cp1 <= 0xDBFF && cp2 >= 0xDC00 && cp2 <= 0xDFFF) {
13795
+ return ch + peek;
13796
+ }
13797
+ return ch;
13798
+ },
13799
+
13637
13800
  isExpOperator: function(ch) {
13638
13801
  return (ch === '-' || ch === '+' || this.isNumber(ch));
13639
13802
  },
@@ -13682,12 +13845,13 @@ Lexer.prototype = {
13682
13845
 
13683
13846
  readIdent: function() {
13684
13847
  var start = this.index;
13848
+ this.index += this.peekMultichar().length;
13685
13849
  while (this.index < this.text.length) {
13686
- var ch = this.text.charAt(this.index);
13687
- if (!(this.isIdent(ch) || this.isNumber(ch))) {
13850
+ var ch = this.peekMultichar();
13851
+ if (!this.isIdentifierContinue(ch)) {
13688
13852
  break;
13689
13853
  }
13690
- this.index++;
13854
+ this.index += ch.length;
13691
13855
  }
13692
13856
  this.tokens.push({
13693
13857
  index: start,
@@ -14617,7 +14781,13 @@ ASTCompiler.prototype = {
14617
14781
  },
14618
14782
 
14619
14783
  nonComputedMember: function(left, right) {
14620
- return left + '.' + right;
14784
+ var SAFE_IDENTIFIER = /[$_a-zA-Z][$_a-zA-Z0-9]*/;
14785
+ var UNSAFE_CHARACTERS = /[^$_a-zA-Z0-9]/g;
14786
+ if (SAFE_IDENTIFIER.test(right)) {
14787
+ return left + '.' + right;
14788
+ } else {
14789
+ return left + '["' + right.replace(UNSAFE_CHARACTERS, this.stringEscapeFn) + '"]';
14790
+ }
14621
14791
  },
14622
14792
 
14623
14793
  computedMember: function(left, right) {
@@ -15180,6 +15350,7 @@ function $ParseProvider() {
15180
15350
  'null': null,
15181
15351
  'undefined': undefined
15182
15352
  };
15353
+ var identStart, identContinue;
15183
15354
 
15184
15355
  /**
15185
15356
  * @ngdoc method
@@ -15196,17 +15367,50 @@ function $ParseProvider() {
15196
15367
  literals[literalName] = literalValue;
15197
15368
  };
15198
15369
 
15370
+ /**
15371
+ * @ngdoc method
15372
+ * @name $parseProvider#setIdentifierFns
15373
+ * @description
15374
+ *
15375
+ * Allows defining the set of characters that are allowed in Angular expressions. The function
15376
+ * `identifierStart` will get called to know if a given character is a valid character to be the
15377
+ * first character for an identifier. The function `identifierContinue` will get called to know if
15378
+ * a given character is a valid character to be a follow-up identifier character. The functions
15379
+ * `identifierStart` and `identifierContinue` will receive as arguments the single character to be
15380
+ * identifier and the character code point. These arguments will be `string` and `numeric`. Keep in
15381
+ * mind that the `string` parameter can be two characters long depending on the character
15382
+ * representation. It is expected for the function to return `true` or `false`, whether that
15383
+ * character is allowed or not.
15384
+ *
15385
+ * Since this function will be called extensivelly, keep the implementation of these functions fast,
15386
+ * as the performance of these functions have a direct impact on the expressions parsing speed.
15387
+ *
15388
+ * @param {function=} identifierStart The function that will decide whether the given character is
15389
+ * a valid identifier start character.
15390
+ * @param {function=} identifierContinue The function that will decide whether the given character is
15391
+ * a valid identifier continue character.
15392
+ */
15393
+ this.setIdentifierFns = function(identifierStart, identifierContinue) {
15394
+ identStart = identifierStart;
15395
+ identContinue = identifierContinue;
15396
+ return this;
15397
+ };
15398
+
15199
15399
  this.$get = ['$filter', function($filter) {
15200
15400
  var noUnsafeEval = csp().noUnsafeEval;
15201
15401
  var $parseOptions = {
15202
15402
  csp: noUnsafeEval,
15203
15403
  expensiveChecks: false,
15204
- literals: copy(literals)
15404
+ literals: copy(literals),
15405
+ isIdentifierStart: isFunction(identStart) && identStart,
15406
+ isIdentifierContinue: isFunction(identContinue) && identContinue
15205
15407
  },
15206
15408
  $parseOptionsExpensive = {
15207
15409
  csp: noUnsafeEval,
15208
15410
  expensiveChecks: true,
15209
- literals: copy(literals)
15411
+ literals: copy(literals),
15412
+ isIdentifierStart: isFunction(identStart) && identStart,
15413
+ isIdentifierContinue: isFunction(identContinue) && identContinue
15210
15414
  };
15211
15415
  var runningChecksEnabled = false;
15212
15416
 
@@ -19001,7 +19205,7 @@ function $TimeoutProvider() {
19001
19205
  // doesn't know about mocked locations and resolves URLs to the real document - which is
19002
19206
  // exactly the behavior needed here. There is little value is mocking these out for this
19003
19207
  // service.
19004
- var urlParsingNode = document.createElement("a");
19208
+ var urlParsingNode = window.document.createElement("a");
19005
19209
  var originUrl = urlResolve(window.location.href);
19006
19210
 
19007
19211
 
@@ -19701,7 +19905,9 @@ function currencyFilter($locale) {
19701
19905
  * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
19702
19906
  * If this is not provided then the fraction size is computed from the current locale's number
19703
19907
  * formatting pattern. In the case of the default locale, it will be 3.
19704
- * @returns {string} Number rounded to fractionSize and places a “,” after each third digit.
19908
+ * @returns {string} Number rounded to `fractionSize` appropriately formatted based on the current
19909
+ * locale (e.g., in the en_US locale it will have "." as the decimal separator and
19910
+ * include "," group separators after each third digit).
19705
19911
  *
19706
19912
  * @example
19707
19913
  <example module="numberFilterExample">
@@ -23930,7 +24136,11 @@ function classDirective(name, selector) {
23930
24136
  updateClasses(oldClasses, newClasses);
23931
24137
  }
23932
24138
  }
23933
- oldVal = shallowCopy(newVal);
24139
+ if (isArray(newVal)) {
24140
+ oldVal = newVal.map(function(v) { return shallowCopy(v); });
24141
+ } else {
24142
+ oldVal = shallowCopy(newVal);
24143
+ }
23934
24144
  }
23935
24145
  }
23936
24146
  };
@@ -25646,7 +25856,7 @@ var ngIncludeFillContentDirective = ['$compile',
25646
25856
  // support innerHTML, so detect this here and try to generate the contents
25647
25857
  // specially.
25648
25858
  $element.empty();
25649
- $compile(jqLiteBuildFragment(ctrl.template, document).childNodes)(scope,
25859
+ $compile(jqLiteBuildFragment(ctrl.template, window.document).childNodes)(scope,
25650
25860
  function namespaceAdaptedClone(clone) {
25651
25861
  $element.append(clone);
25652
25862
  }, {futureParentElement: $element});
@@ -27560,7 +27770,7 @@ var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s
27560
27770
  // jshint maxlen: 100
27561
27771
 
27562
27772
 
27563
- var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
27773
+ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile, $document, $parse) {
27564
27774
 
27565
27775
  function parseOptionsExpression(optionsExp, selectElement, scope) {
27566
27776
 
@@ -27721,8 +27931,8 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
27721
27931
 
27722
27932
  // we can't just jqLite('<option>') since jqLite is not smart enough
27723
27933
  // to create it in <select> and IE barfs otherwise.
27724
- var optionTemplate = document.createElement('option'),
27725
- optGroupTemplate = document.createElement('optgroup');
27934
+ var optionTemplate = window.document.createElement('option'),
27935
+ optGroupTemplate = window.document.createElement('optgroup');
27726
27936
 
27727
27937
  function ngOptionsPostLink(scope, selectElement, attr, ctrls) {
27728
27938
 
@@ -27747,7 +27957,10 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
27747
27957
 
27748
27958
  var options;
27749
27959
  var ngOptions = parseOptionsExpression(attr.ngOptions, selectElement, scope);
27750
-
27960
+ // This stores the newly created options before they are appended to the select.
27961
+ // Since the contents are removed from the fragment when it is appended,
27962
+ // we only need to create it once.
27963
+ var listFragment = $document[0].createDocumentFragment();
27751
27964
 
27752
27965
  var renderEmptyOption = function() {
27753
27966
  if (!providedEmptyOption) {
@@ -27782,7 +27995,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
27782
27995
  selectCtrl.writeValue = function writeNgOptionsValue(value) {
27783
27996
  var option = options.getOptionFromViewValue(value);
27784
27997
 
27785
- if (option && !option.disabled) {
27998
+ if (option) {
27786
27999
  // Don't update the option when it is already selected.
27787
28000
  // For example, the browser will select the first option by default. In that case,
27788
28001
  // most properties are set automatically - except the `selected` attribute, which we
@@ -27844,7 +28057,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
27844
28057
  if (value) {
27845
28058
  value.forEach(function(item) {
27846
28059
  var option = options.getOptionFromViewValue(item);
27847
- if (option && !option.disabled) option.element.selected = true;
28060
+ if (option) option.element.selected = true;
27848
28061
  });
27849
28062
  }
27850
28063
  };
@@ -27896,6 +28109,8 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
27896
28109
  emptyOption = jqLite(optionTemplate.cloneNode(false));
27897
28110
  }
27898
28111
 
28112
+ selectElement.empty();
28113
+
27899
28114
  // We need to do this here to ensure that the options object is defined
27900
28115
  // when we first hit it in writeNgOptionsValue
27901
28116
  updateOptions();
@@ -27905,6 +28120,12 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
27905
28120
 
27906
28121
  // ------------------------------------------------------------------ //
27907
28122
 
28123
+ function addOptionElement(option, parent) {
28124
+ var optionElement = optionTemplate.cloneNode(false);
28125
+ parent.appendChild(optionElement);
28126
+ updateOptionElement(option, optionElement);
28127
+ }
28128
+
27908
28129
 
27909
28130
  function updateOptionElement(option, element) {
27910
28131
  option.element = element;
@@ -27921,133 +28142,66 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
27921
28142
  if (option.value !== element.value) element.value = option.selectValue;
27922
28143
  }
27923
28144
 
27924
- function addOrReuseElement(parent, current, type, templateElement) {
27925
- var element;
27926
- // Check whether we can reuse the next element
27927
- if (current && lowercase(current.nodeName) === type) {
27928
- // The next element is the right type so reuse it
27929
- element = current;
27930
- } else {
27931
- // The next element is not the right type so create a new one
27932
- element = templateElement.cloneNode(false);
27933
- if (!current) {
27934
- // There are no more elements so just append it to the select
27935
- parent.appendChild(element);
27936
- } else {
27937
- // The next element is not a group so insert the new one
27938
- parent.insertBefore(element, current);
27939
- }
27940
- }
27941
- return element;
27942
- }
27943
-
27944
-
27945
- function removeExcessElements(current) {
27946
- var next;
27947
- while (current) {
27948
- next = current.nextSibling;
27949
- jqLiteRemove(current);
27950
- current = next;
27951
- }
27952
- }
27953
-
27954
-
27955
- function skipEmptyAndUnknownOptions(current) {
27956
- var emptyOption_ = emptyOption && emptyOption[0];
27957
- var unknownOption_ = unknownOption && unknownOption[0];
28145
+ function updateOptions() {
28146
+ var previousValue = options && selectCtrl.readValue();
27958
28147
 
27959
- // We cannot rely on the extracted empty option being the same as the compiled empty option,
27960
- // because the compiled empty option might have been replaced by a comment because
27961
- // it had an "element" transclusion directive on it (such as ngIf)
27962
- if (emptyOption_ || unknownOption_) {
27963
- while (current &&
27964
- (current === emptyOption_ ||
27965
- current === unknownOption_ ||
27966
- current.nodeType === NODE_TYPE_COMMENT ||
27967
- (nodeName_(current) === 'option' && current.value === ''))) {
27968
- current = current.nextSibling;
28148
+ // We must remove all current options, but cannot simply set innerHTML = null
28149
+ // since the providedEmptyOption might have an ngIf on it that inserts comments which we
28150
+ // must preserve.
28151
+ // Instead, iterate over the current option elements and remove them or their optgroup
28152
+ // parents
28153
+ if (options) {
28154
+
28155
+ for (var i = options.items.length - 1; i >= 0; i--) {
28156
+ var option = options.items[i];
28157
+ if (option.group) {
28158
+ jqLiteRemove(option.element.parentNode);
28159
+ } else {
28160
+ jqLiteRemove(option.element);
28161
+ }
27969
28162
  }
27970
28163
  }
27971
- return current;
27972
- }
27973
-
27974
-
27975
- function updateOptions() {
27976
-
27977
- var previousValue = options && selectCtrl.readValue();
27978
28164
 
27979
28165
  options = ngOptions.getOptions();
27980
28166
 
27981
- var groupMap = {};
27982
- var currentElement = selectElement[0].firstChild;
28167
+ var groupElementMap = {};
27983
28168
 
27984
28169
  // Ensure that the empty option is always there if it was explicitly provided
27985
28170
  if (providedEmptyOption) {
27986
28171
  selectElement.prepend(emptyOption);
27987
28172
  }
27988
28173
 
27989
- currentElement = skipEmptyAndUnknownOptions(currentElement);
27990
-
27991
- options.items.forEach(function updateOption(option) {
27992
- var group;
28174
+ options.items.forEach(function addOption(option) {
27993
28175
  var groupElement;
27994
- var optionElement;
27995
28176
 
27996
28177
  if (isDefined(option.group)) {
27997
28178
 
27998
28179
  // This option is to live in a group
27999
28180
  // See if we have already created this group
28000
- group = groupMap[option.group];
28181
+ groupElement = groupElementMap[option.group];
28001
28182
 
28002
- if (!group) {
28183
+ if (!groupElement) {
28003
28184
 
28004
- // We have not already created this group
28005
- groupElement = addOrReuseElement(selectElement[0],
28006
- currentElement,
28007
- 'optgroup',
28008
- optGroupTemplate);
28009
- // Move to the next element
28010
- currentElement = groupElement.nextSibling;
28185
+ groupElement = optGroupTemplate.cloneNode(false);
28186
+ listFragment.appendChild(groupElement);
28011
28187
 
28012
28188
  // Update the label on the group element
28013
28189
  groupElement.label = option.group;
28014
28190
 
28015
28191
  // Store it for use later
28016
- group = groupMap[option.group] = {
28017
- groupElement: groupElement,
28018
- currentOptionElement: groupElement.firstChild
28019
- };
28020
-
28192
+ groupElementMap[option.group] = groupElement;
28021
28193
  }
28022
28194
 
28023
- // So now we have a group for this option we add the option to the group
28024
- optionElement = addOrReuseElement(group.groupElement,
28025
- group.currentOptionElement,
28026
- 'option',
28027
- optionTemplate);
28028
- updateOptionElement(option, optionElement);
28029
- // Move to the next element
28030
- group.currentOptionElement = optionElement.nextSibling;
28195
+ addOptionElement(option, groupElement);
28031
28196
 
28032
28197
  } else {
28033
28198
 
28034
28199
  // This option is not in a group
28035
- optionElement = addOrReuseElement(selectElement[0],
28036
- currentElement,
28037
- 'option',
28038
- optionTemplate);
28039
- updateOptionElement(option, optionElement);
28040
- // Move to the next element
28041
- currentElement = optionElement.nextSibling;
28200
+ addOptionElement(option, listFragment);
28042
28201
  }
28043
28202
  });
28044
28203
 
28045
-
28046
- // Now remove all excess options and group
28047
- Object.keys(groupMap).forEach(function(key) {
28048
- removeExcessElements(groupMap[key].currentOptionElement);
28049
- });
28050
- removeExcessElements(currentElement);
28204
+ selectElement[0].appendChild(listFragment);
28051
28205
 
28052
28206
  ngModelCtrl.$render();
28053
28207
 
@@ -29742,7 +29896,7 @@ var SelectController =
29742
29896
  //
29743
29897
  // We can't just jqLite('<option>') since jqLite is not smart enough
29744
29898
  // to create it in <select> and IE barfs otherwise.
29745
- self.unknownOption = jqLite(document.createElement('option'));
29899
+ self.unknownOption = jqLite(window.document.createElement('option'));
29746
29900
  self.renderUnknownOption = function(val) {
29747
29901
  var unknownVal = '? ' + hashKey(val) + ' ?';
29748
29902
  self.unknownOption.val(unknownVal);
@@ -30705,10 +30859,10 @@ $provide.value("$locale", {
30705
30859
  });
30706
30860
  }]);
30707
30861
 
30708
- jqLite(document).ready(function() {
30709
- angularInit(document, bootstrap);
30862
+ jqLite(window.document).ready(function() {
30863
+ angularInit(window.document, bootstrap);
30710
30864
  });
30711
30865
 
30712
- })(window, document);
30866
+ })(window);
30713
30867
 
30714
30868
  !window.angular.$$csp().noInlineStyle && window.angular.element(document.head).prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}.ng-animate-shim{visibility:hidden;}.ng-anchor{position:absolute;}</style>');