engine2 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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>');