angularjs-rails 1.5.0 → 1.5.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1,9 @@
1
1
  /**
2
- * @license AngularJS v1.5.0
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
  /* global ngTouchClickDirectiveFactory: false,
9
9
  */
@@ -1,9 +1,9 @@
1
1
  /**
2
- * @license AngularJS v1.5.0
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.0/' +
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
  /**
@@ -285,7 +286,7 @@ function isArrayLike(obj) {
285
286
  *
286
287
  * Unlike ES262's
287
288
  * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
288
- * Providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
289
+ * providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
289
290
  * return the value provided.
290
291
  *
291
292
  ```js
@@ -526,7 +527,7 @@ function identity($) {return $;}
526
527
  identity.$inject = [];
527
528
 
528
529
 
529
- function valueFn(value) {return function() {return value;};}
530
+ function valueFn(value) {return function valueRef() {return value;};}
530
531
 
531
532
  function hasCustomToString(obj) {
532
533
  return isFunction(obj.toString) && obj.toString !== toString;
@@ -888,7 +889,7 @@ function copy(source, destination) {
888
889
 
889
890
  function copyRecurse(source, destination) {
890
891
  var h = destination.$$hashKey;
891
- var result, key;
892
+ var key;
892
893
  if (isArray(source)) {
893
894
  for (var i = 0, ii = source.length; i < ii; i++) {
894
895
  destination.push(copyElement(source[i]));
@@ -982,6 +983,9 @@ function copy(source, destination) {
982
983
  var re = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
983
984
  re.lastIndex = source.lastIndex;
984
985
  return re;
986
+
987
+ case '[object Blob]':
988
+ return new source.constructor([source], {type: source.type});
985
989
  }
986
990
 
987
991
  if (isFunction(source.cloneNode)) {
@@ -1044,6 +1048,41 @@ function shallowCopy(src, dst) {
1044
1048
  * @param {*} o1 Object or value to compare.
1045
1049
  * @param {*} o2 Object or value to compare.
1046
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>
1047
1086
  */
1048
1087
  function equals(o1, o2) {
1049
1088
  if (o1 === o2) return true;
@@ -1090,8 +1129,8 @@ var csp = function() {
1090
1129
  if (!isDefined(csp.rules)) {
1091
1130
 
1092
1131
 
1093
- var ngCspElement = (document.querySelector('[ng-csp]') ||
1094
- document.querySelector('[data-ng-csp]'));
1132
+ var ngCspElement = (window.document.querySelector('[ng-csp]') ||
1133
+ window.document.querySelector('[data-ng-csp]'));
1095
1134
 
1096
1135
  if (ngCspElement) {
1097
1136
  var ngCspAttribute = ngCspElement.getAttribute('ng-csp') ||
@@ -1166,7 +1205,7 @@ var jq = function() {
1166
1205
  var i, ii = ngAttrPrefixes.length, prefix, name;
1167
1206
  for (i = 0; i < ii; ++i) {
1168
1207
  prefix = ngAttrPrefixes[i];
1169
- if (el = document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) {
1208
+ if (el = window.document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) {
1170
1209
  name = el.getAttribute(prefix + 'jq');
1171
1210
  break;
1172
1211
  }
@@ -1231,7 +1270,7 @@ function toJsonReplacer(key, value) {
1231
1270
  val = undefined;
1232
1271
  } else if (isWindow(value)) {
1233
1272
  val = '$WINDOW';
1234
- } else if (value && document === value) {
1273
+ } else if (value && window.document === value) {
1235
1274
  val = '$DOCUMENT';
1236
1275
  } else if (isScope(value)) {
1237
1276
  val = '$SCOPE';
@@ -1471,10 +1510,17 @@ function getNgAttribute(element, ngAttr) {
1471
1510
  * designates the **root element** of the application and is typically placed near the root element
1472
1511
  * of the page - e.g. on the `<body>` or `<html>` tags.
1473
1512
  *
1474
- * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
1475
- * found in the document will be used to define the root element to auto-bootstrap as an
1476
- * application. To run multiple applications in an HTML document you must manually bootstrap them using
1477
- * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
1513
+ * There are a few things to keep in mind when using `ngApp`:
1514
+ * - only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
1515
+ * found in the document will be used to define the root element to auto-bootstrap as an
1516
+ * application. To run multiple applications in an HTML document you must manually bootstrap them using
1517
+ * {@link angular.bootstrap} instead.
1518
+ * - AngularJS applications cannot be nested within each other.
1519
+ * - Do not use a directive that uses {@link ng.$compile#transclusion transclusion} on the same element as `ngApp`.
1520
+ * This includes directives such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and
1521
+ * {@link ngRoute.ngView `ngView`}.
1522
+ * Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
1523
+ * causing animations to stop working and making the injector inaccessible from outside the app.
1478
1524
  *
1479
1525
  * You can specify an **AngularJS module** to be used as the root module for the application. This
1480
1526
  * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
@@ -1614,16 +1660,25 @@ function angularInit(element, bootstrap) {
1614
1660
  * @description
1615
1661
  * Use this function to manually start up angular application.
1616
1662
  *
1617
- * See: {@link guide/bootstrap Bootstrap}
1618
- *
1619
- * Note that Protractor based end-to-end tests cannot use this function to bootstrap manually.
1620
- * They must use {@link ng.directive:ngApp ngApp}.
1663
+ * For more information, see the {@link guide/bootstrap Bootstrap guide}.
1621
1664
  *
1622
1665
  * Angular will detect if it has been loaded into the browser more than once and only allow the
1623
1666
  * first loaded script to be bootstrapped and will report a warning to the browser console for
1624
1667
  * each of the subsequent scripts. This prevents strange results in applications, where otherwise
1625
1668
  * multiple instances of Angular try to work on the DOM.
1626
1669
  *
1670
+ * <div class="alert alert-warning">
1671
+ * **Note:** Protractor based end-to-end tests cannot use this function to bootstrap manually.
1672
+ * They must use {@link ng.directive:ngApp ngApp}.
1673
+ * </div>
1674
+ *
1675
+ * <div class="alert alert-warning">
1676
+ * **Note:** Do not bootstrap the app on an element with a directive that uses {@link ng.$compile#transclusion transclusion},
1677
+ * such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and {@link ngRoute.ngView `ngView`}.
1678
+ * Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
1679
+ * causing animations to stop working and making the injector inaccessible from outside the app.
1680
+ * </div>
1681
+ *
1627
1682
  * ```html
1628
1683
  * <!doctype html>
1629
1684
  * <html>
@@ -1667,11 +1722,11 @@ function bootstrap(element, modules, config) {
1667
1722
  element = jqLite(element);
1668
1723
 
1669
1724
  if (element.injector()) {
1670
- var tag = (element[0] === document) ? 'document' : startingTag(element);
1725
+ var tag = (element[0] === window.document) ? 'document' : startingTag(element);
1671
1726
  //Encode angle brackets to prevent input from being sanitized to empty string #8683
1672
1727
  throw ngMinErr(
1673
1728
  'btstrpd',
1674
- "App Already Bootstrapped with this Element '{0}'",
1729
+ "App already bootstrapped with this element '{0}'",
1675
1730
  tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
1676
1731
  }
1677
1732
 
@@ -2118,9 +2173,9 @@ function setupModuleLoader(window) {
2118
2173
  * @ngdoc method
2119
2174
  * @name angular.Module#decorator
2120
2175
  * @module ng
2121
- * @param {string} The name of the service to decorate.
2122
- * @param {Function} This function will be invoked when the service needs to be
2123
- * 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.
2124
2179
  * @description
2125
2180
  * See {@link auto.$provide#decorator $provide.decorator()}.
2126
2181
  */
@@ -2424,11 +2479,11 @@ function toDebugString(obj) {
2424
2479
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
2425
2480
  */
2426
2481
  var version = {
2427
- full: '1.5.0', // 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
2428
2483
  major: 1, // package task
2429
2484
  minor: 5,
2430
- dot: 0,
2431
- codeName: 'ennoblement-facilitation'
2485
+ dot: 5,
2486
+ codeName: 'material-conspiration'
2432
2487
  };
2433
2488
 
2434
2489
 
@@ -2685,6 +2740,9 @@ function publishExternalAPI(angular) {
2685
2740
  * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2686
2741
  * parent element is reached.
2687
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
+ *
2688
2746
  * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
2689
2747
  * @returns {Object} jQuery object.
2690
2748
  */
@@ -2811,7 +2869,7 @@ function jqLiteBuildFragment(html, context) {
2811
2869
  }
2812
2870
 
2813
2871
  function jqLiteParseHTML(html, context) {
2814
- context = context || document;
2872
+ context = context || window.document;
2815
2873
  var parsed;
2816
2874
 
2817
2875
  if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
@@ -2837,7 +2895,7 @@ function jqLiteWrapNode(node, wrapper) {
2837
2895
 
2838
2896
 
2839
2897
  // IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
2840
- var jqLiteContains = Node.prototype.contains || function(arg) {
2898
+ var jqLiteContains = window.Node.prototype.contains || function(arg) {
2841
2899
  // jshint bitwise: false
2842
2900
  return !!(this.compareDocumentPosition(arg) & 16);
2843
2901
  // jshint bitwise: true
@@ -3109,8 +3167,8 @@ var JQLitePrototype = JQLite.prototype = {
3109
3167
  }
3110
3168
 
3111
3169
  // check if document is already loaded
3112
- if (document.readyState === 'complete') {
3113
- setTimeout(trigger);
3170
+ if (window.document.readyState === 'complete') {
3171
+ window.setTimeout(trigger);
3114
3172
  } else {
3115
3173
  this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
3116
3174
  // we can not use jqLite since we are not done loading and jQuery could be loaded later.
@@ -3800,6 +3858,7 @@ var $$HashMapProvider = [function() {
3800
3858
  /**
3801
3859
  * @ngdoc module
3802
3860
  * @name auto
3861
+ * @installation
3803
3862
  * @description
3804
3863
  *
3805
3864
  * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
@@ -3813,7 +3872,7 @@ var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
3813
3872
  var $injectorMinErr = minErr('$injector');
3814
3873
 
3815
3874
  function extractArgs(fn) {
3816
- var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
3875
+ var fnText = Function.prototype.toString.call(fn).replace(STRIP_COMMENTS, ''),
3817
3876
  args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS);
3818
3877
  return args;
3819
3878
  }
@@ -4287,14 +4346,13 @@ function annotate(fn, strictDi, name) {
4287
4346
  * @description
4288
4347
  *
4289
4348
  * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
4290
- * number, an array, an object or a function. This is short for registering a service where its
4349
+ * number, an array, an object or a function. This is short for registering a service where its
4291
4350
  * provider's `$get` property is a factory function that takes no arguments and returns the **value
4292
- * service**.
4351
+ * service**. That also means it is not possible to inject other services into a value service.
4293
4352
  *
4294
4353
  * Value services are similar to constant services, except that they cannot be injected into a
4295
4354
  * module configuration function (see {@link angular.Module#config}) but they can be overridden by
4296
- * an Angular
4297
- * {@link auto.$provide#decorator decorator}.
4355
+ * an Angular {@link auto.$provide#decorator decorator}.
4298
4356
  *
4299
4357
  * @param {string} name The name of the instance.
4300
4358
  * @param {*} value The value.
@@ -4319,8 +4377,11 @@ function annotate(fn, strictDi, name) {
4319
4377
  * @name $provide#constant
4320
4378
  * @description
4321
4379
  *
4322
- * Register a **constant service**, such as a string, a number, an array, an object or a function,
4323
- * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be
4380
+ * Register a **constant service** with the {@link auto.$injector $injector}, such as a string,
4381
+ * a number, an array, an object or a function. Like the {@link auto.$provide#value value}, it is not
4382
+ * possible to inject other services into a constant.
4383
+ *
4384
+ * But unlike {@link auto.$provide#value value}, a constant can be
4324
4385
  * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
4325
4386
  * be overridden by an Angular {@link auto.$provide#decorator decorator}.
4326
4387
  *
@@ -4959,7 +5020,7 @@ function prepareAnimateOptions(options) {
4959
5020
  }
4960
5021
 
4961
5022
  var $$CoreAnimateJsProvider = function() {
4962
- this.$get = function() {};
5023
+ this.$get = noop;
4963
5024
  };
4964
5025
 
4965
5026
  // this is prefixed with Core since it conflicts with
@@ -5231,6 +5292,9 @@ var $AnimateProvider = ['$provide', function($provide) {
5231
5292
  * // remove all the animation event listeners listening for `enter`
5232
5293
  * $animate.off('enter');
5233
5294
  *
5295
+ * // remove listeners for all animation events from the container element
5296
+ * $animate.off(container);
5297
+ *
5234
5298
  * // remove all the animation event listeners listening for `enter` on the given element and its children
5235
5299
  * $animate.off('enter', container);
5236
5300
  *
@@ -5239,7 +5303,9 @@ var $AnimateProvider = ['$provide', function($provide) {
5239
5303
  * $animate.off('enter', container, callback);
5240
5304
  * ```
5241
5305
  *
5242
- * @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.
5243
5309
  * @param {DOMElement=} container the container element the event listener was placed on
5244
5310
  * @param {Function=} callback the callback function that was registered as the listener
5245
5311
  */
@@ -5779,7 +5845,6 @@ var $CoreAnimateCssProvider = function() {
5779
5845
  */
5780
5846
  function Browser(window, document, $log, $sniffer) {
5781
5847
  var self = this,
5782
- rawDocument = document[0],
5783
5848
  location = window.location,
5784
5849
  history = window.history,
5785
5850
  setTimeout = window.setTimeout,
@@ -5842,7 +5907,14 @@ function Browser(window, document, $log, $sniffer) {
5842
5907
  var cachedState, lastHistoryState,
5843
5908
  lastBrowserUrl = location.href,
5844
5909
  baseElement = document.find('base'),
5845
- pendingLocation = null;
5910
+ pendingLocation = null,
5911
+ getCurrentState = !$sniffer.history ? noop : function getCurrentState() {
5912
+ try {
5913
+ return history.state;
5914
+ } catch (e) {
5915
+ // MSIE can reportedly throw when there is no state (UNCONFIRMED).
5916
+ }
5917
+ };
5846
5918
 
5847
5919
  cacheState();
5848
5920
  lastHistoryState = cachedState;
@@ -5950,14 +6022,6 @@ function Browser(window, document, $log, $sniffer) {
5950
6022
  fireUrlChange();
5951
6023
  }
5952
6024
 
5953
- function getCurrentState() {
5954
- try {
5955
- return history.state;
5956
- } catch (e) {
5957
- // MSIE can reportedly throw when there is no state (UNCONFIRMED).
5958
- }
5959
- }
5960
-
5961
6025
  // This variable should be used *only* inside the cacheState function.
5962
6026
  var lastCachedState = null;
5963
6027
  function cacheState() {
@@ -6809,9 +6873,23 @@ function $TemplateCacheProvider() {
6809
6873
  * `true` if the specified slot contains content (i.e. one or more DOM nodes).
6810
6874
  *
6811
6875
  * The controller can provide the following methods that act as life-cycle hooks:
6812
- * * `$onInit` - Called on each controller after all the controllers on an element have been constructed and
6876
+ * * `$onInit()` - Called on each controller after all the controllers on an element have been constructed and
6813
6877
  * had their bindings initialized (and before the pre &amp; post linking functions for the directives on
6814
6878
  * this element). This is a good place to put initialization code for your controller.
6879
+ * * `$onChanges(changesObj)` - Called whenever one-way (`<`) or interpolation (`@`) bindings are updated. The
6880
+ * `changesObj` is a hash whose keys are the names of the bound properties that have changed, and the values are an
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.
6883
+ * * `$onDestroy()` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
6884
+ * external resources, watches and event handlers. Note that components have their `$onDestroy()` hooks called in
6885
+ * the same order as the `$scope.$broadcast` events are triggered, which is top down. This means that parent
6886
+ * components will have their `$onDestroy()` hook called before child components.
6887
+ * * `$postLink()` - Called after this controller's element and its children have been linked. Similar to the post-link
6888
+ * function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
6889
+ * Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
6890
+ * they are waiting for their template to load asynchronously and their own compilation and linking has been
6891
+ * suspended until that occurs.
6892
+ *
6815
6893
  *
6816
6894
  * #### `require`
6817
6895
  * Require another directive and inject its controller as the fourth argument to the linking function. The
@@ -7348,6 +7426,9 @@ function $TemplateCacheProvider() {
7348
7426
 
7349
7427
  var $compileMinErr = minErr('$compile');
7350
7428
 
7429
+ function UNINITIALIZED_VALUE() {}
7430
+ var _UNINITIALIZED_VALUE = new UNINITIALIZED_VALUE();
7431
+
7351
7432
  /**
7352
7433
  * @ngdoc provider
7353
7434
  * @name $compileProvider
@@ -7367,13 +7448,18 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7367
7448
  // The assumption is that future DOM event attribute names will begin with
7368
7449
  // 'on' and be composed of only English letters.
7369
7450
  var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
7451
+ var bindingCache = createMap();
7370
7452
 
7371
7453
  function parseIsolateBindings(scope, directiveName, isController) {
7372
7454
  var LOCAL_REGEXP = /^\s*([@&<]|=(\*?))(\??)\s*(\w*)\s*$/;
7373
7455
 
7374
- var bindings = {};
7456
+ var bindings = createMap();
7375
7457
 
7376
7458
  forEach(scope, function(definition, scopeName) {
7459
+ if (definition in bindingCache) {
7460
+ bindings[scopeName] = bindingCache[definition];
7461
+ return;
7462
+ }
7377
7463
  var match = definition.match(LOCAL_REGEXP);
7378
7464
 
7379
7465
  if (!match) {
@@ -7391,6 +7477,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7391
7477
  optional: match[3] === '?',
7392
7478
  attrName: match[4] || scopeName
7393
7479
  };
7480
+ if (match[4]) {
7481
+ bindingCache[definition] = bindings[scopeName];
7482
+ }
7394
7483
  });
7395
7484
 
7396
7485
  return bindings;
@@ -7436,11 +7525,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7436
7525
  function assertValidDirectiveName(name) {
7437
7526
  var letter = name.charAt(0);
7438
7527
  if (!letter || letter !== lowercase(letter)) {
7439
- throw $compileMinErr('baddir', "Directive name '{0}' is invalid. The first character must be a lowercase letter", name);
7528
+ throw $compileMinErr('baddir', "Directive/Component name '{0}' is invalid. The first character must be a lowercase letter", name);
7440
7529
  }
7441
7530
  if (name !== name.trim()) {
7442
7531
  throw $compileMinErr('baddir',
7443
- "Directive name '{0}' is invalid. The name should not contain leading or trailing whitespaces",
7532
+ "Directive/Component name '{0}' is invalid. The name should not contain leading or trailing whitespaces",
7444
7533
  name);
7445
7534
  }
7446
7535
  }
@@ -7460,7 +7549,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7460
7549
  * {@link guide/directive directive guide} and the {@link $compile compile API} for more info.
7461
7550
  * @returns {ng.$compileProvider} Self for chaining.
7462
7551
  */
7463
- this.directive = function registerDirective(name, directiveFactory) {
7552
+ this.directive = function registerDirective(name, directiveFactory) {
7464
7553
  assertNotHasOwnProperty(name, 'directive');
7465
7554
  if (isString(name)) {
7466
7555
  assertValidDirectiveName(name);
@@ -7483,11 +7572,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7483
7572
  directive.name = directive.name || name;
7484
7573
  directive.require = directive.require || (directive.controller && directive.name);
7485
7574
  directive.restrict = directive.restrict || 'EA';
7486
- var bindings = directive.$$bindings =
7487
- parseDirectiveBindings(directive, directive.name);
7488
- if (isObject(bindings.isolateScope)) {
7489
- directive.$$isolateBindings = bindings.isolateScope;
7490
- }
7491
7575
  directive.$$moduleName = directiveFactory.$$moduleName;
7492
7576
  directives.push(directive);
7493
7577
  } catch (e) {
@@ -7543,7 +7627,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7543
7627
  * See {@link ng.$compile#-bindtocontroller- `bindToController`}.
7544
7628
  * - `transclude` – `{boolean=}` – whether {@link $compile#transclusion content transclusion} is enabled.
7545
7629
  * Disabled by default.
7546
- * - `$...` `{function()=}` additional annotations to provide to the directive factory function.
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`}.
7633
+ * - `$...` – additional properties to attach to the directive factory function and the controller
7634
+ * constructor function. (This is used by the component router to annotate)
7547
7635
  *
7548
7636
  * @returns {ng.$compileProvider} the compile provider itself, for chaining of function calls.
7549
7637
  * @description
@@ -7575,7 +7663,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7575
7663
  *
7576
7664
  * myMod.component('myComp', {
7577
7665
  * templateUrl: 'views/my-comp.html',
7578
- * controller: 'MyCtrl as ctrl',
7666
+ * controller: 'MyCtrl',
7667
+ * controllerAs: 'ctrl',
7579
7668
  * bindings: {name: '@'}
7580
7669
  * });
7581
7670
  *
@@ -7600,7 +7689,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7600
7689
  }
7601
7690
 
7602
7691
  var template = (!options.template && !options.templateUrl ? '' : options.template);
7603
- return {
7692
+ var ddo = {
7604
7693
  controller: controller,
7605
7694
  controllerAs: identifierForController(options.controller) || options.controllerAs || '$ctrl',
7606
7695
  template: makeInjectable(template),
@@ -7611,13 +7700,27 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7611
7700
  restrict: 'E',
7612
7701
  require: options.require
7613
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;
7614
7710
  }
7615
7711
 
7616
- // 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
7617
7718
  // These could be used by libraries such as the new component router
7618
7719
  forEach(options, function(val, key) {
7619
7720
  if (key.charAt(0) === '$') {
7620
7721
  factory[key] = val;
7722
+ // Don't try to copy over annotations to named controller
7723
+ if (isFunction(controller)) controller[key] = val;
7621
7724
  }
7622
7725
  });
7623
7726
 
@@ -7717,6 +7820,36 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7717
7820
  return debugInfoEnabled;
7718
7821
  };
7719
7822
 
7823
+
7824
+ var TTL = 10;
7825
+ /**
7826
+ * @ngdoc method
7827
+ * @name $compileProvider#onChangesTtl
7828
+ * @description
7829
+ *
7830
+ * Sets the number of times `$onChanges` hooks can trigger new changes before giving up and
7831
+ * assuming that the model is unstable.
7832
+ *
7833
+ * The current default is 10 iterations.
7834
+ *
7835
+ * In complex applications it's possible that dependencies between `$onChanges` hooks and bindings will result
7836
+ * in several iterations of calls to these hooks. However if an application needs more than the default 10
7837
+ * iterations to stabilize then you should investigate what is causing the model to continuously change during
7838
+ * the `$onChanges` hook execution.
7839
+ *
7840
+ * Increasing the TTL could have performance implications, so you should not change it without proper justification.
7841
+ *
7842
+ * @param {number} limit The number of `$onChanges` hook iterations.
7843
+ * @returns {number|object} the current limit (or `this` if called as a setter for chaining)
7844
+ */
7845
+ this.onChangesTtl = function(value) {
7846
+ if (arguments.length) {
7847
+ TTL = value;
7848
+ return this;
7849
+ }
7850
+ return TTL;
7851
+ };
7852
+
7720
7853
  this.$get = [
7721
7854
  '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
7722
7855
  '$controller', '$rootScope', '$sce', '$animate', '$$sanitizeUri',
@@ -7724,8 +7857,38 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7724
7857
  $controller, $rootScope, $sce, $animate, $$sanitizeUri) {
7725
7858
 
7726
7859
  var SIMPLE_ATTR_NAME = /^\w/;
7727
- var specialAttrHolder = document.createElement('div');
7728
- var Attributes = function(element, attributesToCopy) {
7860
+ var specialAttrHolder = window.document.createElement('div');
7861
+
7862
+
7863
+
7864
+ var onChangesTtl = TTL;
7865
+ // The onChanges hooks should all be run together in a single digest
7866
+ // When changes occur, the call to trigger their hooks will be added to this queue
7867
+ var onChangesQueue;
7868
+
7869
+ // This function is called in a $$postDigest to trigger all the onChanges hooks in a single digest
7870
+ function flushOnChangesQueue() {
7871
+ try {
7872
+ if (!(--onChangesTtl)) {
7873
+ // We have hit the TTL limit so reset everything
7874
+ onChangesQueue = undefined;
7875
+ throw $compileMinErr('infchng', '{0} $onChanges() iterations reached. Aborting!\n', TTL);
7876
+ }
7877
+ // We must run this hook in an apply since the $$postDigest runs outside apply
7878
+ $rootScope.$apply(function() {
7879
+ for (var i = 0, ii = onChangesQueue.length; i < ii; ++i) {
7880
+ onChangesQueue[i]();
7881
+ }
7882
+ // Reset the queue to trigger a new schedule next time there is a change
7883
+ onChangesQueue = undefined;
7884
+ });
7885
+ } finally {
7886
+ onChangesTtl++;
7887
+ }
7888
+ }
7889
+
7890
+
7891
+ function Attributes(element, attributesToCopy) {
7729
7892
  if (attributesToCopy) {
7730
7893
  var keys = Object.keys(attributesToCopy);
7731
7894
  var i, l, key;
@@ -7739,7 +7902,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7739
7902
  }
7740
7903
 
7741
7904
  this.$$element = element;
7742
- };
7905
+ }
7743
7906
 
7744
7907
  Attributes.prototype = {
7745
7908
  /**
@@ -8020,6 +8183,14 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8020
8183
  safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope');
8021
8184
  } : noop;
8022
8185
 
8186
+ compile.$$createComment = function(directiveName, comment) {
8187
+ var content = '';
8188
+ if (debugInfoEnabled) {
8189
+ content = ' ' + (directiveName || '') + ': ' + (comment || '') + ' ';
8190
+ }
8191
+ return window.document.createComment(content);
8192
+ };
8193
+
8023
8194
  return compile;
8024
8195
 
8025
8196
  //================================
@@ -8040,7 +8211,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8040
8211
  var domNode = $compileNodes[i];
8041
8212
 
8042
8213
  if (domNode.nodeType === NODE_TYPE_TEXT && domNode.nodeValue.match(NOT_EMPTY) /* non-empty */) {
8043
- jqLiteWrapNode(domNode, $compileNodes[i] = document.createElement('span'));
8214
+ jqLiteWrapNode(domNode, $compileNodes[i] = window.document.createElement('span'));
8044
8215
  }
8045
8216
  }
8046
8217
 
@@ -8233,8 +8404,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8233
8404
  }
8234
8405
 
8235
8406
  function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
8236
-
8237
- var boundTranscludeFn = function(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
8407
+ function boundTranscludeFn(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
8238
8408
 
8239
8409
  if (!transcludedScope) {
8240
8410
  transcludedScope = scope.$new(false, containingScope);
@@ -8246,7 +8416,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8246
8416
  transcludeControllers: controllers,
8247
8417
  futureParentElement: futureParentElement
8248
8418
  });
8249
- };
8419
+ }
8250
8420
 
8251
8421
  // We need to attach the transclusion slots onto the `boundTranscludeFn`
8252
8422
  // so that they are available inside the `controllersBoundTransclude` function
@@ -8411,7 +8581,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8411
8581
  * @returns {Function}
8412
8582
  */
8413
8583
  function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
8414
- return function(scope, element, attrs, controllers, transcludeFn) {
8584
+ return function groupedElementsLink(scope, element, attrs, controllers, transcludeFn) {
8415
8585
  element = groupScan(element[0], attrStart, attrEnd);
8416
8586
  return linkFn(scope, element, attrs, controllers, transcludeFn);
8417
8587
  };
@@ -8429,23 +8599,21 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8429
8599
  * @returns {Function}
8430
8600
  */
8431
8601
  function compilationGenerator(eager, $compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext) {
8432
- if (eager) {
8433
- return compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
8434
- }
8602
+ var compiled;
8435
8603
 
8436
- var compiled;
8437
-
8438
- return function() {
8439
- if (!compiled) {
8440
- compiled = compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
8441
-
8442
- // Null out all of these references in order to make them eligible for garbage collection
8443
- // since this is a potentially long lived closure
8444
- $compileNodes = transcludeFn = previousCompileContext = null;
8445
- }
8604
+ if (eager) {
8605
+ return compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
8606
+ }
8607
+ return function lazyCompilation() {
8608
+ if (!compiled) {
8609
+ compiled = compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
8446
8610
 
8447
- return compiled.apply(this, arguments);
8448
- };
8611
+ // Null out all of these references in order to make them eligible for garbage collection
8612
+ // since this is a potentially long lived closure
8613
+ $compileNodes = transcludeFn = previousCompileContext = null;
8614
+ }
8615
+ return compiled.apply(this, arguments);
8616
+ };
8449
8617
  }
8450
8618
 
8451
8619
  /**
@@ -8581,11 +8749,21 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8581
8749
  terminalPriority = directive.priority;
8582
8750
  $template = $compileNode;
8583
8751
  $compileNode = templateAttrs.$$element =
8584
- jqLite(document.createComment(' ' + directiveName + ': ' +
8585
- templateAttrs[directiveName] + ' '));
8752
+ jqLite(compile.$$createComment(directiveName, templateAttrs[directiveName]));
8586
8753
  compileNode = $compileNode[0];
8587
8754
  replaceWith(jqCollection, sliceArgs($template), compileNode);
8588
8755
 
8756
+ // Support: Chrome < 50
8757
+ // https://github.com/angular/angular.js/issues/14041
8758
+
8759
+ // In the versions of V8 prior to Chrome 50, the document fragment that is created
8760
+ // in the `replaceWith` function is improperly garbage collected despite still
8761
+ // being referenced by the `parentNode` property of all of the child nodes. By adding
8762
+ // a reference to the fragment via a different property, we can avoid that incorrect
8763
+ // behavior.
8764
+ // TODO: remove this line after Chrome 50 has been released
8765
+ $template[0].$$parentNode = $template[0].parentNode;
8766
+
8589
8767
  childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, terminalPriority,
8590
8768
  replaceDirective && replaceDirective.name, {
8591
8769
  // Don't pass in:
@@ -8726,7 +8904,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8726
8904
  replaceDirective = directive;
8727
8905
  }
8728
8906
 
8907
+ /* jshint -W021 */
8729
8908
  nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
8909
+ /* jshint +W021 */
8730
8910
  templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
8731
8911
  controllerDirectives: controllerDirectives,
8732
8912
  newScopeDirective: (newScopeDirective !== directive) && newScopeDirective,
@@ -8788,85 +8968,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8788
8968
  }
8789
8969
  }
8790
8970
 
8791
-
8792
- function getControllers(directiveName, require, $element, elementControllers) {
8793
- var value;
8794
-
8795
- if (isString(require)) {
8796
- var match = require.match(REQUIRE_PREFIX_REGEXP);
8797
- var name = require.substring(match[0].length);
8798
- var inheritType = match[1] || match[3];
8799
- var optional = match[2] === '?';
8800
-
8801
- //If only parents then start at the parent element
8802
- if (inheritType === '^^') {
8803
- $element = $element.parent();
8804
- //Otherwise attempt getting the controller from elementControllers in case
8805
- //the element is transcluded (and has no data) and to avoid .data if possible
8806
- } else {
8807
- value = elementControllers && elementControllers[name];
8808
- value = value && value.instance;
8809
- }
8810
-
8811
- if (!value) {
8812
- var dataName = '$' + name + 'Controller';
8813
- value = inheritType ? $element.inheritedData(dataName) : $element.data(dataName);
8814
- }
8815
-
8816
- if (!value && !optional) {
8817
- throw $compileMinErr('ctreq',
8818
- "Controller '{0}', required by directive '{1}', can't be found!",
8819
- name, directiveName);
8820
- }
8821
- } else if (isArray(require)) {
8822
- value = [];
8823
- for (var i = 0, ii = require.length; i < ii; i++) {
8824
- value[i] = getControllers(directiveName, require[i], $element, elementControllers);
8825
- }
8826
- } else if (isObject(require)) {
8827
- value = {};
8828
- forEach(require, function(controller, property) {
8829
- value[property] = getControllers(directiveName, controller, $element, elementControllers);
8830
- });
8831
- }
8832
-
8833
- return value || null;
8834
- }
8835
-
8836
- function setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope) {
8837
- var elementControllers = createMap();
8838
- for (var controllerKey in controllerDirectives) {
8839
- var directive = controllerDirectives[controllerKey];
8840
- var locals = {
8841
- $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
8842
- $element: $element,
8843
- $attrs: attrs,
8844
- $transclude: transcludeFn
8845
- };
8846
-
8847
- var controller = directive.controller;
8848
- if (controller == '@') {
8849
- controller = attrs[directive.name];
8850
- }
8851
-
8852
- var controllerInstance = $controller(controller, locals, true, directive.controllerAs);
8853
-
8854
- // For directives with element transclusion the element is a comment,
8855
- // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
8856
- // clean up (http://bugs.jquery.com/ticket/8335).
8857
- // Instead, we save the controllers for the element in a local hash and attach to .data
8858
- // later, once we have the actual element.
8859
- elementControllers[directive.name] = controllerInstance;
8860
- if (!hasElementTranscludeDirective) {
8861
- $element.data('$' + directive.name + 'Controller', controllerInstance.instance);
8862
- }
8863
- }
8864
- return elementControllers;
8865
- }
8866
-
8867
8971
  function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
8868
8972
  var i, ii, linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
8869
- attrs, removeScopeBindingWatches, removeControllerBindingWatches;
8973
+ attrs, scopeBindingInfo;
8870
8974
 
8871
8975
  if (compileNode === linkNode) {
8872
8976
  attrs = templateAttrs;
@@ -8895,7 +8999,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8895
8999
  }
8896
9000
 
8897
9001
  if (controllerDirectives) {
8898
- elementControllers = setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope);
9002
+ elementControllers = setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope, newIsolateScopeDirective);
8899
9003
  }
8900
9004
 
8901
9005
  if (newIsolateScopeDirective) {
@@ -8905,11 +9009,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8905
9009
  compile.$$addScopeClass($element, true);
8906
9010
  isolateScope.$$isolateBindings =
8907
9011
  newIsolateScopeDirective.$$isolateBindings;
8908
- removeScopeBindingWatches = initializeDirectiveBindings(scope, attrs, isolateScope,
9012
+ scopeBindingInfo = initializeDirectiveBindings(scope, attrs, isolateScope,
8909
9013
  isolateScope.$$isolateBindings,
8910
9014
  newIsolateScopeDirective);
8911
- if (removeScopeBindingWatches) {
8912
- isolateScope.$on('$destroy', removeScopeBindingWatches);
9015
+ if (scopeBindingInfo.removeWatches) {
9016
+ isolateScope.$on('$destroy', scopeBindingInfo.removeWatches);
8913
9017
  }
8914
9018
  }
8915
9019
 
@@ -8920,8 +9024,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8920
9024
  var bindings = controllerDirective.$$bindings.bindToController;
8921
9025
 
8922
9026
  if (controller.identifier && bindings) {
8923
- removeControllerBindingWatches =
9027
+ controller.bindingInfo =
8924
9028
  initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
9029
+ } else {
9030
+ controller.bindingInfo = {};
8925
9031
  }
8926
9032
 
8927
9033
  var controllerResult = controller();
@@ -8930,8 +9036,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8930
9036
  // from setupControllers
8931
9037
  controller.instance = controllerResult;
8932
9038
  $element.data('$' + controllerDirective.name + 'Controller', controllerResult);
8933
- removeControllerBindingWatches && removeControllerBindingWatches();
8934
- removeControllerBindingWatches =
9039
+ controller.bindingInfo.removeWatches && controller.bindingInfo.removeWatches();
9040
+ controller.bindingInfo =
8935
9041
  initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
8936
9042
  }
8937
9043
  }
@@ -8944,10 +9050,19 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8944
9050
  }
8945
9051
  });
8946
9052
 
8947
- // Trigger the `$onInit` method on all controllers that have one
9053
+ // Handle the init and destroy lifecycle hooks on all controllers that have them
8948
9054
  forEach(elementControllers, function(controller) {
8949
- if (isFunction(controller.instance.$onInit)) {
8950
- controller.instance.$onInit();
9055
+ var controllerInstance = controller.instance;
9056
+ if (isFunction(controllerInstance.$onChanges)) {
9057
+ controllerInstance.$onChanges(controller.bindingInfo.initialChanges);
9058
+ }
9059
+ if (isFunction(controllerInstance.$onInit)) {
9060
+ controllerInstance.$onInit();
9061
+ }
9062
+ if (isFunction(controllerInstance.$onDestroy)) {
9063
+ controllerScope.$on('$destroy', function callOnDestroyHook() {
9064
+ controllerInstance.$onDestroy();
9065
+ });
8951
9066
  }
8952
9067
  });
8953
9068
 
@@ -8984,6 +9099,14 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8984
9099
  );
8985
9100
  }
8986
9101
 
9102
+ // Trigger $postLink lifecycle hooks
9103
+ forEach(elementControllers, function(controller) {
9104
+ var controllerInstance = controller.instance;
9105
+ if (isFunction(controllerInstance.$postLink)) {
9106
+ controllerInstance.$postLink();
9107
+ }
9108
+ });
9109
+
8987
9110
  // This is the function that is injected as `$transclude`.
8988
9111
  // Note: all arguments are optional!
8989
9112
  function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement, slotName) {
@@ -9023,6 +9146,78 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
9023
9146
  }
9024
9147
  }
9025
9148
 
9149
+ function getControllers(directiveName, require, $element, elementControllers) {
9150
+ var value;
9151
+
9152
+ if (isString(require)) {
9153
+ var match = require.match(REQUIRE_PREFIX_REGEXP);
9154
+ var name = require.substring(match[0].length);
9155
+ var inheritType = match[1] || match[3];
9156
+ var optional = match[2] === '?';
9157
+
9158
+ //If only parents then start at the parent element
9159
+ if (inheritType === '^^') {
9160
+ $element = $element.parent();
9161
+ //Otherwise attempt getting the controller from elementControllers in case
9162
+ //the element is transcluded (and has no data) and to avoid .data if possible
9163
+ } else {
9164
+ value = elementControllers && elementControllers[name];
9165
+ value = value && value.instance;
9166
+ }
9167
+
9168
+ if (!value) {
9169
+ var dataName = '$' + name + 'Controller';
9170
+ value = inheritType ? $element.inheritedData(dataName) : $element.data(dataName);
9171
+ }
9172
+
9173
+ if (!value && !optional) {
9174
+ throw $compileMinErr('ctreq',
9175
+ "Controller '{0}', required by directive '{1}', can't be found!",
9176
+ name, directiveName);
9177
+ }
9178
+ } else if (isArray(require)) {
9179
+ value = [];
9180
+ for (var i = 0, ii = require.length; i < ii; i++) {
9181
+ value[i] = getControllers(directiveName, require[i], $element, elementControllers);
9182
+ }
9183
+ } else if (isObject(require)) {
9184
+ value = {};
9185
+ forEach(require, function(controller, property) {
9186
+ value[property] = getControllers(directiveName, controller, $element, elementControllers);
9187
+ });
9188
+ }
9189
+
9190
+ return value || null;
9191
+ }
9192
+
9193
+ function setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope, newIsolateScopeDirective) {
9194
+ var elementControllers = createMap();
9195
+ for (var controllerKey in controllerDirectives) {
9196
+ var directive = controllerDirectives[controllerKey];
9197
+ var locals = {
9198
+ $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
9199
+ $element: $element,
9200
+ $attrs: attrs,
9201
+ $transclude: transcludeFn
9202
+ };
9203
+
9204
+ var controller = directive.controller;
9205
+ if (controller == '@') {
9206
+ controller = attrs[directive.name];
9207
+ }
9208
+
9209
+ var controllerInstance = $controller(controller, locals, true, directive.controllerAs);
9210
+
9211
+ // For directives with element transclusion the element is a comment.
9212
+ // In this case .data will not attach any data.
9213
+ // Instead, we save the controllers for the element in a local hash and attach to .data
9214
+ // later, once we have the actual element.
9215
+ elementControllers[directive.name] = controllerInstance;
9216
+ $element.data('$' + directive.name + 'Controller', controllerInstance.instance);
9217
+ }
9218
+ return elementControllers;
9219
+ }
9220
+
9026
9221
  // Depending upon the context in which a directive finds itself it might need to have a new isolated
9027
9222
  // or child scope created. For instance:
9028
9223
  // * if the directive has been pulled into a template because another directive with a higher priority
@@ -9063,6 +9258,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
9063
9258
  if (startAttrName) {
9064
9259
  directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
9065
9260
  }
9261
+ if (!directive.$$bindings) {
9262
+ var bindings = directive.$$bindings =
9263
+ parseDirectiveBindings(directive, directive.name);
9264
+ if (isObject(bindings.isolateScope)) {
9265
+ directive.$$isolateBindings = bindings.isolateScope;
9266
+ }
9267
+ }
9066
9268
  tDirectives.push(directive);
9067
9269
  match = directive;
9068
9270
  }
@@ -9310,7 +9512,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
9310
9512
  switch (type) {
9311
9513
  case 'svg':
9312
9514
  case 'math':
9313
- var wrapper = document.createElement('div');
9515
+ var wrapper = window.document.createElement('div');
9314
9516
  wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
9315
9517
  return wrapper.childNodes[0].childNodes;
9316
9518
  default:
@@ -9454,7 +9656,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
9454
9656
  // - remove them from the DOM
9455
9657
  // - allow them to still be traversed with .nextSibling
9456
9658
  // - allow a single fragment.qSA to fetch all elements being removed
9457
- var fragment = document.createDocumentFragment();
9659
+ var fragment = window.document.createDocumentFragment();
9458
9660
  for (i = 0; i < removeCount; i++) {
9459
9661
  fragment.appendChild(elementsToRemove[i]);
9460
9662
  }
@@ -9500,7 +9702,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
9500
9702
  // only occurs for isolate scopes and new scopes with controllerAs.
9501
9703
  function initializeDirectiveBindings(scope, attrs, destination, bindings, directive) {
9502
9704
  var removeWatchCollection = [];
9503
- forEach(bindings, function(definition, scopeName) {
9705
+ var initialChanges = {};
9706
+ var changes;
9707
+ forEach(bindings, function initializeBinding(definition, scopeName) {
9504
9708
  var attrName = definition.attrName,
9505
9709
  optional = definition.optional,
9506
9710
  mode = definition.mode, // @, =, or &
@@ -9514,7 +9718,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
9514
9718
  destination[scopeName] = attrs[attrName] = void 0;
9515
9719
  }
9516
9720
  attrs.$observe(attrName, function(value) {
9517
- if (isString(value)) {
9721
+ if (isString(value) || isBoolean(value)) {
9722
+ var oldValue = destination[scopeName];
9723
+ recordChanges(scopeName, value, oldValue);
9518
9724
  destination[scopeName] = value;
9519
9725
  }
9520
9726
  });
@@ -9529,6 +9735,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
9529
9735
  // the value to boolean rather than a string, so we special case this situation
9530
9736
  destination[scopeName] = lastValue;
9531
9737
  }
9738
+ initialChanges[scopeName] = new SimpleChange(_UNINITIALIZED_VALUE, destination[scopeName]);
9532
9739
  break;
9533
9740
 
9534
9741
  case '=':
@@ -9542,7 +9749,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
9542
9749
  if (parentGet.literal) {
9543
9750
  compare = equals;
9544
9751
  } else {
9545
- compare = function(a, b) { return a === b || (a !== a && b !== b); };
9752
+ compare = function simpleCompare(a, b) { return a === b || (a !== a && b !== b); };
9546
9753
  }
9547
9754
  parentSet = parentGet.assign || function() {
9548
9755
  // reset the change, or we will throw this exception on every $digest
@@ -9584,9 +9791,16 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
9584
9791
  parentGet = $parse(attrs[attrName]);
9585
9792
 
9586
9793
  destination[scopeName] = parentGet(scope);
9794
+ initialChanges[scopeName] = new SimpleChange(_UNINITIALIZED_VALUE, destination[scopeName]);
9587
9795
 
9588
- removeWatch = scope.$watch(parentGet, function parentValueWatchAction(newParentValue) {
9589
- 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;
9590
9804
  }, parentGet.literal);
9591
9805
 
9592
9806
  removeWatchCollection.push(removeWatch);
@@ -9606,15 +9820,52 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
9606
9820
  }
9607
9821
  });
9608
9822
 
9609
- return removeWatchCollection.length && function removeWatches() {
9610
- for (var i = 0, ii = removeWatchCollection.length; i < ii; ++i) {
9611
- removeWatchCollection[i]();
9823
+ function recordChanges(key, currentValue, previousValue) {
9824
+ if (isFunction(destination.$onChanges) && currentValue !== previousValue) {
9825
+ // If we have not already scheduled the top level onChangesQueue handler then do so now
9826
+ if (!onChangesQueue) {
9827
+ scope.$$postDigest(flushOnChangesQueue);
9828
+ onChangesQueue = [];
9829
+ }
9830
+ // If we have not already queued a trigger of onChanges for this controller then do so now
9831
+ if (!changes) {
9832
+ changes = {};
9833
+ onChangesQueue.push(triggerOnChangesHook);
9834
+ }
9835
+ // If the has been a change on this property already then we need to reuse the previous value
9836
+ if (changes[key]) {
9837
+ previousValue = changes[key].previousValue;
9838
+ }
9839
+ // Store this change
9840
+ changes[key] = new SimpleChange(previousValue, currentValue);
9841
+ }
9842
+ }
9843
+
9844
+ function triggerOnChangesHook() {
9845
+ destination.$onChanges(changes);
9846
+ // Now clear the changes so that we schedule onChanges when more changes arrive
9847
+ changes = undefined;
9848
+ }
9849
+
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
+ }
9612
9856
  }
9613
9857
  };
9614
9858
  }
9615
9859
  }];
9616
9860
  }
9617
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
+
9618
9869
  var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
9619
9870
  /**
9620
9871
  * Converts all accepted directives format into proper directive name.
@@ -9744,6 +9995,15 @@ function $ControllerProvider() {
9744
9995
  var controllers = {},
9745
9996
  globals = false;
9746
9997
 
9998
+ /**
9999
+ * @ngdoc method
10000
+ * @name $controllerProvider#has
10001
+ * @param {string} name Controller name to check.
10002
+ */
10003
+ this.has = function(name) {
10004
+ return controllers.hasOwnProperty(name);
10005
+ };
10006
+
9747
10007
  /**
9748
10008
  * @ngdoc method
9749
10009
  * @name $controllerProvider#register
@@ -9800,7 +10060,7 @@ function $ControllerProvider() {
9800
10060
  * It's just a simple call to {@link auto.$injector $injector}, but extracted into
9801
10061
  * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
9802
10062
  */
9803
- return function(expression, locals, later, ident) {
10063
+ return function $controller(expression, locals, later, ident) {
9804
10064
  // PRIVATE API:
9805
10065
  // param `later` --- indicates that the controller's constructor is invoked at a later time.
9806
10066
  // If true, $controller will allocate the object with the correct
@@ -9851,7 +10111,7 @@ function $ControllerProvider() {
9851
10111
  }
9852
10112
 
9853
10113
  var instantiate;
9854
- return instantiate = extend(function() {
10114
+ return instantiate = extend(function $controllerInit() {
9855
10115
  var result = $injector.invoke(expression, instance, locals, constructor);
9856
10116
  if (result !== instance && (isObject(result) || isFunction(result))) {
9857
10117
  instance = result;
@@ -10037,7 +10297,7 @@ function $HttpParamSerializerProvider() {
10037
10297
  forEachSorted(params, function(value, key) {
10038
10298
  if (value === null || isUndefined(value)) return;
10039
10299
  if (isArray(value)) {
10040
- forEach(value, function(v, k) {
10300
+ forEach(value, function(v) {
10041
10301
  parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(v)));
10042
10302
  });
10043
10303
  } else {
@@ -10247,10 +10507,9 @@ function $HttpProvider() {
10247
10507
  *
10248
10508
  * Object containing default values for all {@link ng.$http $http} requests.
10249
10509
  *
10250
- * - **`defaults.cache`** - {Object} - an object built with {@link ng.$cacheFactory `$cacheFactory`}
10251
- * that will provide the cache for all requests who set their `cache` property to `true`.
10252
- * If you set the `defaults.cache = false` then only requests that specify their own custom
10253
- * cache object will be cached. See {@link $http#caching $http Caching} for more information.
10510
+ * - **`defaults.cache`** - {boolean|Object} - A boolean value or object created with
10511
+ * {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of HTTP responses
10512
+ * by default. See {@link $http#caching $http Caching} for more information.
10254
10513
  *
10255
10514
  * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
10256
10515
  * Defaults value is `'XSRF-TOKEN'`.
@@ -10541,6 +10800,15 @@ function $HttpProvider() {
10541
10800
  * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions,
10542
10801
  * which allows you to `push` or `unshift` a new transformation function into the transformation chain.
10543
10802
  *
10803
+ * <div class="alert alert-warning">
10804
+ * **Note:** Angular does not make a copy of the `data` parameter before it is passed into the `transformRequest` pipeline.
10805
+ * That means changes to the properties of `data` are not local to the transform function (since Javascript passes objects by reference).
10806
+ * For example, when calling `$http.get(url, $scope.myObject)`, modifications to the object's properties in a transformRequest
10807
+ * function will be reflected on the scope and in any templates where the object is data-bound.
10808
+ * To prevent this, transform functions should have no side-effects.
10809
+ * If you need to modify properties, it is recommended to make a copy of the data, or create new object to return.
10810
+ * </div>
10811
+ *
10544
10812
  * ### Default Transformations
10545
10813
  *
10546
10814
  * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and
@@ -10598,26 +10866,35 @@ function $HttpProvider() {
10598
10866
  *
10599
10867
  * ## Caching
10600
10868
  *
10601
- * To enable caching, set the request configuration `cache` property to `true` (to use default
10602
- * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
10603
- * When the cache is enabled, `$http` stores the response from the server in the specified
10604
- * cache. The next time the same request is made, the response is served from the cache without
10605
- * sending a request to the server.
10869
+ * {@link ng.$http `$http`} responses are not cached by default. To enable caching, you must
10870
+ * set the config.cache value or the default cache value to TRUE or to a cache object (created
10871
+ * with {@link ng.$cacheFactory `$cacheFactory`}). If defined, the value of config.cache takes
10872
+ * precedence over the default cache value.
10873
+ *
10874
+ * In order to:
10875
+ * * cache all responses - set the default cache value to TRUE or to a cache object
10876
+ * * cache a specific response - set config.cache value to TRUE or to a cache object
10877
+ *
10878
+ * If caching is enabled, but neither the default cache nor config.cache are set to a cache object,
10879
+ * then the default `$cacheFactory($http)` object is used.
10606
10880
  *
10607
- * Note that even if the response is served from cache, delivery of the data is asynchronous in
10608
- * the same way that real requests are.
10881
+ * The default cache value can be set by updating the
10882
+ * {@link ng.$http#defaults `$http.defaults.cache`} property or the
10883
+ * {@link $httpProvider#defaults `$httpProvider.defaults.cache`} property.
10609
10884
  *
10610
- * If there are multiple GET requests for the same URL that should be cached using the same
10611
- * cache, but the cache is not populated yet, only one request to the server will be made and
10612
- * the remaining requests will be fulfilled using the response from the first request.
10885
+ * When caching is enabled, {@link ng.$http `$http`} stores the response from the server using
10886
+ * the relevant cache object. The next time the same request is made, the response is returned
10887
+ * from the cache without sending a request to the server.
10613
10888
  *
10614
- * You can change the default cache to a new object (built with
10615
- * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
10616
- * {@link ng.$http#defaults `$http.defaults.cache`} property. All requests who set
10617
- * their `cache` property to `true` will now use this cache object.
10889
+ * Take note that:
10890
+ *
10891
+ * * Only GET and JSONP requests are cached.
10892
+ * * The cache key is the request URL including search parameters; headers are not considered.
10893
+ * * Cached responses are returned asynchronously, in the same way as responses from the server.
10894
+ * * If multiple identical requests are made using the same cache, which is not yet populated,
10895
+ * one request will be made to the server and remaining requests will return the same response.
10896
+ * * A cache-control header on the response does not affect if or how responses are cached.
10618
10897
  *
10619
- * If you set the default cache to `false` then only requests that specify their own custom
10620
- * cache object will be cached.
10621
10898
  *
10622
10899
  * ## Interceptors
10623
10900
  *
@@ -10774,6 +11051,12 @@ function $HttpProvider() {
10774
11051
  * - **headers** – `{Object}` – Map of strings or functions which return strings representing
10775
11052
  * HTTP headers to send to the server. If the return value of a function is null, the
10776
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.
10777
11060
  * - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
10778
11061
  * - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
10779
11062
  * - **transformRequest** –
@@ -10787,7 +11070,7 @@ function $HttpProvider() {
10787
11070
  * transform function or an array of such functions. The transform function takes the http
10788
11071
  * response body, headers and status and returns its transformed (typically deserialized) version.
10789
11072
  * See {@link ng.$http#overriding-the-default-transformations-per-request
10790
- * Overriding the Default TransformationjqLiks}
11073
+ * Overriding the Default Transformations}
10791
11074
  * - **paramSerializer** - `{string|function(Object<string,string>):string}` - A function used to
10792
11075
  * prepare the string representation of request parameters (specified as an object).
10793
11076
  * If specified as string, it is interpreted as function registered with the
@@ -10795,10 +11078,9 @@ function $HttpProvider() {
10795
11078
  * by registering it as a {@link auto.$provide#service service}.
10796
11079
  * The default serializer is the {@link $httpParamSerializer $httpParamSerializer};
10797
11080
  * alternatively, you can use the {@link $httpParamSerializerJQLike $httpParamSerializerJQLike}
10798
- * - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
10799
- * GET request, otherwise if a cache instance built with
10800
- * {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
10801
- * caching.
11081
+ * - **cache** – `{boolean|Object}` – A boolean value or object created with
11082
+ * {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of the HTTP response.
11083
+ * See {@link $http#caching $http Caching} for more information.
10802
11084
  * - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
10803
11085
  * that should abort the request when resolved.
10804
11086
  * - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
@@ -11233,11 +11515,35 @@ function $HttpProvider() {
11233
11515
  }
11234
11516
 
11235
11517
  $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
11236
- config.withCredentials, config.responseType);
11518
+ config.withCredentials, config.responseType,
11519
+ createApplyHandlers(config.eventHandlers),
11520
+ createApplyHandlers(config.uploadEventHandlers));
11237
11521
  }
11238
11522
 
11239
11523
  return promise;
11240
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
+
11241
11547
 
11242
11548
  /**
11243
11549
  * Callback registered to $httpBackend():
@@ -11358,7 +11664,7 @@ function $HttpBackendProvider() {
11358
11664
 
11359
11665
  function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
11360
11666
  // TODO(vojta): fix the signature
11361
- return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
11667
+ return function(method, url, post, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers) {
11362
11668
  $browser.$$incOutstandingRequestCount();
11363
11669
  url = url || $browser.url();
11364
11670
 
@@ -11418,6 +11724,14 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
11418
11724
  xhr.onerror = requestError;
11419
11725
  xhr.onabort = requestError;
11420
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
+
11421
11735
  if (withCredentials) {
11422
11736
  xhr.withCredentials = true;
11423
11737
  }
@@ -13396,7 +13710,7 @@ Lexer.prototype = {
13396
13710
  this.readString(ch);
13397
13711
  } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
13398
13712
  this.readNumber();
13399
- } else if (this.isIdent(ch)) {
13713
+ } else if (this.isIdentifierStart(this.peekMultichar())) {
13400
13714
  this.readIdent();
13401
13715
  } else if (this.is(ch, '(){}[].,;:?')) {
13402
13716
  this.tokens.push({index: this.index, text: ch});
@@ -13440,12 +13754,49 @@ Lexer.prototype = {
13440
13754
  ch === '\n' || ch === '\v' || ch === '\u00A0');
13441
13755
  },
13442
13756
 
13443
- 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) {
13444
13764
  return ('a' <= ch && ch <= 'z' ||
13445
13765
  'A' <= ch && ch <= 'Z' ||
13446
13766
  '_' === ch || ch === '$');
13447
13767
  },
13448
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
+
13449
13800
  isExpOperator: function(ch) {
13450
13801
  return (ch === '-' || ch === '+' || this.isNumber(ch));
13451
13802
  },
@@ -13494,12 +13845,13 @@ Lexer.prototype = {
13494
13845
 
13495
13846
  readIdent: function() {
13496
13847
  var start = this.index;
13848
+ this.index += this.peekMultichar().length;
13497
13849
  while (this.index < this.text.length) {
13498
- var ch = this.text.charAt(this.index);
13499
- if (!(this.isIdent(ch) || this.isNumber(ch))) {
13850
+ var ch = this.peekMultichar();
13851
+ if (!this.isIdentifierContinue(ch)) {
13500
13852
  break;
13501
13853
  }
13502
- this.index++;
13854
+ this.index += ch.length;
13503
13855
  }
13504
13856
  this.tokens.push({
13505
13857
  index: start,
@@ -13709,8 +14061,10 @@ AST.prototype = {
13709
14061
  primary = this.arrayDeclaration();
13710
14062
  } else if (this.expect('{')) {
13711
14063
  primary = this.object();
13712
- } else if (this.constants.hasOwnProperty(this.peek().text)) {
13713
- primary = copy(this.constants[this.consume().text]);
14064
+ } else if (this.selfReferential.hasOwnProperty(this.peek().text)) {
14065
+ primary = copy(this.selfReferential[this.consume().text]);
14066
+ } else if (this.options.literals.hasOwnProperty(this.peek().text)) {
14067
+ primary = { type: AST.Literal, value: this.options.literals[this.consume().text]};
13714
14068
  } else if (this.peek().identifier) {
13715
14069
  primary = this.identifier();
13716
14070
  } else if (this.peek().constant) {
@@ -13862,15 +14216,7 @@ AST.prototype = {
13862
14216
  return false;
13863
14217
  },
13864
14218
 
13865
-
13866
- /* `undefined` is not a constant, it is an identifier,
13867
- * but using it as an identifier is not supported
13868
- */
13869
- constants: {
13870
- 'true': { type: AST.Literal, value: true },
13871
- 'false': { type: AST.Literal, value: false },
13872
- 'null': { type: AST.Literal, value: null },
13873
- 'undefined': {type: AST.Literal, value: undefined },
14219
+ selfReferential: {
13874
14220
  'this': {type: AST.ThisExpression },
13875
14221
  '$locals': {type: AST.LocalsExpression }
13876
14222
  }
@@ -14435,7 +14781,13 @@ ASTCompiler.prototype = {
14435
14781
  },
14436
14782
 
14437
14783
  nonComputedMember: function(left, right) {
14438
- 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
+ }
14439
14791
  },
14440
14792
 
14441
14793
  computedMember: function(left, right) {
@@ -14560,7 +14912,7 @@ ASTInterpreter.prototype = {
14560
14912
  forEach(ast.body, function(expression) {
14561
14913
  expressions.push(self.recurse(expression.expression));
14562
14914
  });
14563
- var fn = ast.body.length === 0 ? function() {} :
14915
+ var fn = ast.body.length === 0 ? noop :
14564
14916
  ast.body.length === 1 ? expressions[0] :
14565
14917
  function(scope, locals) {
14566
14918
  var lastValue;
@@ -14701,7 +15053,7 @@ ASTInterpreter.prototype = {
14701
15053
  return context ? {value: locals} : locals;
14702
15054
  };
14703
15055
  case AST.NGValueParameter:
14704
- return function(scope, locals, assign, inputs) {
15056
+ return function(scope, locals, assign) {
14705
15057
  return context ? {value: assign} : assign;
14706
15058
  };
14707
15059
  }
@@ -14915,7 +15267,7 @@ var Parser = function(lexer, $filter, options) {
14915
15267
  this.lexer = lexer;
14916
15268
  this.$filter = $filter;
14917
15269
  this.options = options;
14918
- this.ast = new AST(this.lexer);
15270
+ this.ast = new AST(lexer, options);
14919
15271
  this.astCompiler = options.csp ? new ASTInterpreter(this.ast, $filter) :
14920
15272
  new ASTCompiler(this.ast, $filter);
14921
15273
  };
@@ -14992,16 +15344,73 @@ function getValueOf(value) {
14992
15344
  function $ParseProvider() {
14993
15345
  var cacheDefault = createMap();
14994
15346
  var cacheExpensive = createMap();
15347
+ var literals = {
15348
+ 'true': true,
15349
+ 'false': false,
15350
+ 'null': null,
15351
+ 'undefined': undefined
15352
+ };
15353
+ var identStart, identContinue;
15354
+
15355
+ /**
15356
+ * @ngdoc method
15357
+ * @name $parseProvider#addLiteral
15358
+ * @description
15359
+ *
15360
+ * Configure $parse service to add literal values that will be present as literal at expressions.
15361
+ *
15362
+ * @param {string} literalName Token for the literal value. The literal name value must be a valid literal name.
15363
+ * @param {*} literalValue Value for this literal. All literal values must be primitives or `undefined`.
15364
+ *
15365
+ **/
15366
+ this.addLiteral = function(literalName, literalValue) {
15367
+ literals[literalName] = literalValue;
15368
+ };
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
+ };
14995
15398
 
14996
15399
  this.$get = ['$filter', function($filter) {
14997
15400
  var noUnsafeEval = csp().noUnsafeEval;
14998
15401
  var $parseOptions = {
14999
15402
  csp: noUnsafeEval,
15000
- expensiveChecks: false
15403
+ expensiveChecks: false,
15404
+ literals: copy(literals),
15405
+ isIdentifierStart: isFunction(identStart) && identStart,
15406
+ isIdentifierContinue: isFunction(identContinue) && identContinue
15001
15407
  },
15002
15408
  $parseOptionsExpensive = {
15003
15409
  csp: noUnsafeEval,
15004
- expensiveChecks: true
15410
+ expensiveChecks: true,
15411
+ literals: copy(literals),
15412
+ isIdentifierStart: isFunction(identStart) && identStart,
15413
+ isIdentifierContinue: isFunction(identContinue) && identContinue
15005
15414
  };
15006
15415
  var runningChecksEnabled = false;
15007
15416
 
@@ -15250,15 +15659,15 @@ function $ParseProvider() {
15250
15659
  * [Kris Kowal's Q](https://github.com/kriskowal/q).
15251
15660
  *
15252
15661
  * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
15253
- * implementations, and the other which resembles ES6 promises to some degree.
15662
+ * implementations, and the other which resembles ES6 (ES2015) promises to some degree.
15254
15663
  *
15255
15664
  * # $q constructor
15256
15665
  *
15257
15666
  * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`
15258
- * function as the first argument. This is similar to the native Promise implementation from ES6 Harmony,
15667
+ * function as the first argument. This is similar to the native Promise implementation from ES6,
15259
15668
  * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
15260
15669
  *
15261
- * While the constructor-style use is supported, not all of the supporting methods from ES6 Harmony promises are
15670
+ * While the constructor-style use is supported, not all of the supporting methods from ES6 promises are
15262
15671
  * available yet.
15263
15672
  *
15264
15673
  * It can be used like so:
@@ -15423,7 +15832,7 @@ function $ParseProvider() {
15423
15832
  * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
15424
15833
  * all the important functionality needed for common async tasks.
15425
15834
  *
15426
- * # Testing
15835
+ * # Testing
15427
15836
  *
15428
15837
  * ```js
15429
15838
  * it('should simulate promise', inject(function($q, $rootScope) {
@@ -16611,7 +17020,7 @@ function $RootScopeProvider() {
16611
17020
  dirty, ttl = TTL,
16612
17021
  next, current, target = this,
16613
17022
  watchLog = [],
16614
- logIdx, logMsg, asyncTask;
17023
+ logIdx, asyncTask;
16615
17024
 
16616
17025
  beginPhase('$digest');
16617
17026
  // Check for changes to browser url that happened in sync before the call to $digest
@@ -18396,6 +18805,10 @@ function $SceProvider() {
18396
18805
  function $SnifferProvider() {
18397
18806
  this.$get = ['$window', '$document', function($window, $document) {
18398
18807
  var eventSupport = {},
18808
+ // Chrome Packaged Apps are not allowed to access `history.pushState`. They can be detected by
18809
+ // the presence of `chrome.app.runtime` (see https://developer.chrome.com/apps/api_index)
18810
+ isChromePackagedApp = $window.chrome && $window.chrome.app && $window.chrome.app.runtime,
18811
+ hasHistoryPushState = !isChromePackagedApp && $window.history && $window.history.pushState,
18399
18812
  android =
18400
18813
  toInt((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
18401
18814
  boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
@@ -18440,7 +18853,7 @@ function $SnifferProvider() {
18440
18853
  // so let's not use the history API also
18441
18854
  // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
18442
18855
  // jshint -W018
18443
- history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
18856
+ history: !!(hasHistoryPushState && !(android < 4) && !boxee),
18444
18857
  // jshint +W018
18445
18858
  hasEvent: function(event) {
18446
18859
  // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
@@ -18466,7 +18879,7 @@ function $SnifferProvider() {
18466
18879
  }];
18467
18880
  }
18468
18881
 
18469
- var $compileMinErr = minErr('$compile');
18882
+ var $templateRequestMinErr = minErr('$compile');
18470
18883
 
18471
18884
  /**
18472
18885
  * @ngdoc provider
@@ -18562,7 +18975,7 @@ function $TemplateRequestProvider() {
18562
18975
 
18563
18976
  function handleError(resp) {
18564
18977
  if (!ignoreRequestError) {
18565
- throw $compileMinErr('tpload', 'Failed to load template: {0} (HTTP status: {1} {2})',
18978
+ throw $templateRequestMinErr('tpload', 'Failed to load template: {0} (HTTP status: {1} {2})',
18566
18979
  tpl, resp.status, resp.statusText);
18567
18980
  }
18568
18981
  return $q.reject(resp);
@@ -18792,7 +19205,7 @@ function $TimeoutProvider() {
18792
19205
  // doesn't know about mocked locations and resolves URLs to the real document - which is
18793
19206
  // exactly the behavior needed here. There is little value is mocking these out for this
18794
19207
  // service.
18795
- var urlParsingNode = document.createElement("a");
19208
+ var urlParsingNode = window.document.createElement("a");
18796
19209
  var originUrl = urlResolve(window.location.href);
18797
19210
 
18798
19211
 
@@ -19484,7 +19897,7 @@ function currencyFilter($locale) {
19484
19897
  * Formats a number as text.
19485
19898
  *
19486
19899
  * If the input is null or undefined, it will just be returned.
19487
- * If the input is infinite (Infinity/-Infinity) the Infinity symbol '∞' is returned.
19900
+ * If the input is infinite (Infinity or -Infinity), the Infinity symbol '∞' or '-∞' is returned, respectively.
19488
19901
  * If the input is not a number an empty string is returned.
19489
19902
  *
19490
19903
  *
@@ -19492,7 +19905,9 @@ function currencyFilter($locale) {
19492
19905
  * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
19493
19906
  * If this is not provided then the fraction size is computed from the current locale's number
19494
19907
  * formatting pattern. In the case of the default locale, it will be 3.
19495
- * @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).
19496
19911
  *
19497
19912
  * @example
19498
19913
  <example module="numberFilterExample">
@@ -19574,7 +19989,7 @@ function parse(numStr) {
19574
19989
  }
19575
19990
 
19576
19991
  // Count the number of leading zeros.
19577
- for (i = 0; numStr.charAt(i) == ZERO_CHAR; i++);
19992
+ for (i = 0; numStr.charAt(i) == ZERO_CHAR; i++) {/* jshint noempty: false */}
19578
19993
 
19579
19994
  if (i == (zeros = numStr.length)) {
19580
19995
  // The digits are all zero.
@@ -19620,18 +20035,37 @@ function roundNumber(parsedNumber, fractionSize, minFrac, maxFrac) {
19620
20035
  var digit = digits[roundAt];
19621
20036
 
19622
20037
  if (roundAt > 0) {
19623
- digits.splice(roundAt);
20038
+ // Drop fractional digits beyond `roundAt`
20039
+ digits.splice(Math.max(parsedNumber.i, roundAt));
20040
+
20041
+ // Set non-fractional digits beyond `roundAt` to 0
20042
+ for (var j = roundAt; j < digits.length; j++) {
20043
+ digits[j] = 0;
20044
+ }
19624
20045
  } else {
19625
20046
  // We rounded to zero so reset the parsedNumber
20047
+ fractionLen = Math.max(0, fractionLen);
19626
20048
  parsedNumber.i = 1;
19627
- digits.length = roundAt = fractionSize + 1;
19628
- for (var i=0; i < roundAt; i++) digits[i] = 0;
20049
+ digits.length = Math.max(1, roundAt = fractionSize + 1);
20050
+ digits[0] = 0;
20051
+ for (var i = 1; i < roundAt; i++) digits[i] = 0;
19629
20052
  }
19630
20053
 
19631
- if (digit >= 5) digits[roundAt - 1]++;
20054
+ if (digit >= 5) {
20055
+ if (roundAt - 1 < 0) {
20056
+ for (var k = 0; k > roundAt; k--) {
20057
+ digits.unshift(0);
20058
+ parsedNumber.i++;
20059
+ }
20060
+ digits.unshift(1);
20061
+ parsedNumber.i++;
20062
+ } else {
20063
+ digits[roundAt - 1]++;
20064
+ }
20065
+ }
19632
20066
 
19633
20067
  // Pad out with zeros to get the required fraction length
19634
- for (; fractionLen < fractionSize; fractionLen++) digits.push(0);
20068
+ for (; fractionLen < Math.max(0, fractionSize); fractionLen++) digits.push(0);
19635
20069
 
19636
20070
 
19637
20071
  // Do any carrying, e.g. a digit was rounded up to 10
@@ -19703,7 +20137,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
19703
20137
 
19704
20138
  // format the integer digits with grouping separators
19705
20139
  var groups = [];
19706
- if (digits.length > pattern.lgSize) {
20140
+ if (digits.length >= pattern.lgSize) {
19707
20141
  groups.unshift(digits.splice(-pattern.lgSize).join(''));
19708
20142
  }
19709
20143
  while (digits.length > pattern.gSize) {
@@ -19730,11 +20164,15 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
19730
20164
  }
19731
20165
  }
19732
20166
 
19733
- function padNumber(num, digits, trim) {
20167
+ function padNumber(num, digits, trim, negWrap) {
19734
20168
  var neg = '';
19735
- if (num < 0) {
19736
- neg = '-';
19737
- num = -num;
20169
+ if (num < 0 || (negWrap && num <= 0)) {
20170
+ if (negWrap) {
20171
+ num = -num + 1;
20172
+ } else {
20173
+ num = -num;
20174
+ neg = '-';
20175
+ }
19738
20176
  }
19739
20177
  num = '' + num;
19740
20178
  while (num.length < digits) num = ZERO_CHAR + num;
@@ -19745,7 +20183,7 @@ function padNumber(num, digits, trim) {
19745
20183
  }
19746
20184
 
19747
20185
 
19748
- function dateGetter(name, size, offset, trim) {
20186
+ function dateGetter(name, size, offset, trim, negWrap) {
19749
20187
  offset = offset || 0;
19750
20188
  return function(date) {
19751
20189
  var value = date['get' + name]();
@@ -19753,14 +20191,15 @@ function dateGetter(name, size, offset, trim) {
19753
20191
  value += offset;
19754
20192
  }
19755
20193
  if (value === 0 && offset == -12) value = 12;
19756
- return padNumber(value, size, trim);
20194
+ return padNumber(value, size, trim, negWrap);
19757
20195
  };
19758
20196
  }
19759
20197
 
19760
- function dateStrGetter(name, shortForm) {
20198
+ function dateStrGetter(name, shortForm, standAlone) {
19761
20199
  return function(date, formats) {
19762
20200
  var value = date['get' + name]();
19763
- var get = uppercase(shortForm ? ('SHORT' + name) : name);
20201
+ var propPrefix = (standAlone ? 'STANDALONE' : '') + (shortForm ? 'SHORT' : '');
20202
+ var get = uppercase(propPrefix + name);
19764
20203
 
19765
20204
  return formats[get][value];
19766
20205
  };
@@ -19815,13 +20254,14 @@ function longEraGetter(date, formats) {
19815
20254
  }
19816
20255
 
19817
20256
  var DATE_FORMATS = {
19818
- yyyy: dateGetter('FullYear', 4),
19819
- yy: dateGetter('FullYear', 2, 0, true),
19820
- y: dateGetter('FullYear', 1),
20257
+ yyyy: dateGetter('FullYear', 4, 0, false, true),
20258
+ yy: dateGetter('FullYear', 2, 0, true, true),
20259
+ y: dateGetter('FullYear', 1, 0, false, true),
19821
20260
  MMMM: dateStrGetter('Month'),
19822
20261
  MMM: dateStrGetter('Month', true),
19823
20262
  MM: dateGetter('Month', 2, 1),
19824
20263
  M: dateGetter('Month', 1, 1),
20264
+ LLLL: dateStrGetter('Month', false, true),
19825
20265
  dd: dateGetter('Date', 2),
19826
20266
  d: dateGetter('Date', 1),
19827
20267
  HH: dateGetter('Hours', 2),
@@ -19847,7 +20287,7 @@ var DATE_FORMATS = {
19847
20287
  GGGG: longEraGetter
19848
20288
  };
19849
20289
 
19850
- var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,
20290
+ var DATE_FORMATS_SPLIT = /((?:[^yMLdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,
19851
20291
  NUMBER_STRING = /^\-?\d+$/;
19852
20292
 
19853
20293
  /**
@@ -19867,6 +20307,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|
19867
20307
  * * `'MMM'`: Month in year (Jan-Dec)
19868
20308
  * * `'MM'`: Month in year, padded (01-12)
19869
20309
  * * `'M'`: Month in year (1-12)
20310
+ * * `'LLLL'`: Stand-alone month in year (January-December)
19870
20311
  * * `'dd'`: Day in month, padded (01-31)
19871
20312
  * * `'d'`: Day in month (1-31)
19872
20313
  * * `'EEEE'`: Day in Week,(Sunday-Saturday)
@@ -21548,8 +21989,8 @@ var ngFormDirective = formDirectiveFactory(true);
21548
21989
  ngModelMinErr: false,
21549
21990
  */
21550
21991
 
21551
- // Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
21552
- var ISO_DATE_REGEXP = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/;
21992
+ // Regex code was initially obtained from SO prior to modification: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
21993
+ var ISO_DATE_REGEXP = /^\d{4,}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-][0-2]\d:[0-5]\d|Z)$/;
21553
21994
  // See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987)
21554
21995
  // Note: We are being more lenient, because browsers are too.
21555
21996
  // 1. Scheme
@@ -21565,12 +22006,18 @@ var ISO_DATE_REGEXP = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-
21565
22006
  var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+\])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
21566
22007
  var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
21567
22008
  var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
21568
- var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
21569
- var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
21570
- var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/;
21571
- var MONTH_REGEXP = /^(\d{4})-(\d\d)$/;
22009
+ var DATE_REGEXP = /^(\d{4,})-(\d{2})-(\d{2})$/;
22010
+ var DATETIMELOCAL_REGEXP = /^(\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
22011
+ var WEEK_REGEXP = /^(\d{4,})-W(\d\d)$/;
22012
+ var MONTH_REGEXP = /^(\d{4,})-(\d\d)$/;
21572
22013
  var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
21573
22014
 
22015
+ var PARTIAL_VALIDATION_EVENTS = 'keydown wheel mousedown';
22016
+ var PARTIAL_VALIDATION_TYPES = createMap();
22017
+ forEach('date,datetime-local,month,time,week'.split(','), function(type) {
22018
+ PARTIAL_VALIDATION_TYPES[type] = true;
22019
+ });
22020
+
21574
22021
  var inputType = {
21575
22022
 
21576
22023
  /**
@@ -21926,7 +22373,7 @@ var inputType = {
21926
22373
  }]);
21927
22374
  </script>
21928
22375
  <form name="myForm" ng-controller="DateController as dateCtrl">
21929
- <label for="exampleInput">Pick a between 8am and 5pm:</label>
22376
+ <label for="exampleInput">Pick a time between 8am and 5pm:</label>
21930
22377
  <input type="time" id="exampleInput" name="input" ng-model="example.value"
21931
22378
  placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
21932
22379
  <div role="alert">
@@ -22647,7 +23094,7 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
22647
23094
  if (!$sniffer.android) {
22648
23095
  var composing = false;
22649
23096
 
22650
- element.on('compositionstart', function(data) {
23097
+ element.on('compositionstart', function() {
22651
23098
  composing = true;
22652
23099
  });
22653
23100
 
@@ -22657,6 +23104,8 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
22657
23104
  });
22658
23105
  }
22659
23106
 
23107
+ var timeout;
23108
+
22660
23109
  var listener = function(ev) {
22661
23110
  if (timeout) {
22662
23111
  $browser.defer.cancel(timeout);
@@ -22686,8 +23135,6 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
22686
23135
  if ($sniffer.hasEvent('input')) {
22687
23136
  element.on('input', listener);
22688
23137
  } else {
22689
- var timeout;
22690
-
22691
23138
  var deferListener = function(ev, input, origValue) {
22692
23139
  if (!timeout) {
22693
23140
  timeout = $browser.defer(function() {
@@ -22719,6 +23166,26 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
22719
23166
  // or form autocomplete on newer browser, we need "change" event to catch it
22720
23167
  element.on('change', listener);
22721
23168
 
23169
+ // Some native input types (date-family) have the ability to change validity without
23170
+ // firing any input/change events.
23171
+ // For these event types, when native validators are present and the browser supports the type,
23172
+ // check for validity changes on various DOM events.
23173
+ if (PARTIAL_VALIDATION_TYPES[type] && ctrl.$$hasNativeValidators && type === attr.type) {
23174
+ element.on(PARTIAL_VALIDATION_EVENTS, function(ev) {
23175
+ if (!timeout) {
23176
+ var validity = this[VALIDITY_STATE_PROPERTY];
23177
+ var origBadInput = validity.badInput;
23178
+ var origTypeMismatch = validity.typeMismatch;
23179
+ timeout = $browser.defer(function() {
23180
+ timeout = null;
23181
+ if (validity.badInput !== origBadInput || validity.typeMismatch !== origTypeMismatch) {
23182
+ listener(ev);
23183
+ }
23184
+ });
23185
+ }
23186
+ });
23187
+ }
23188
+
22722
23189
  ctrl.$render = function() {
22723
23190
  // Workaround for Firefox validation #12102.
22724
23191
  var value = ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue;
@@ -23669,7 +24136,11 @@ function classDirective(name, selector) {
23669
24136
  updateClasses(oldClasses, newClasses);
23670
24137
  }
23671
24138
  }
23672
- oldVal = shallowCopy(newVal);
24139
+ if (isArray(newVal)) {
24140
+ oldVal = newVal.map(function(v) { return shallowCopy(v); });
24141
+ } else {
24142
+ oldVal = shallowCopy(newVal);
24143
+ }
23673
24144
  }
23674
24145
  }
23675
24146
  };
@@ -23739,9 +24210,10 @@ function classDirective(name, selector) {
23739
24210
  * new classes added.
23740
24211
  *
23741
24212
  * @animations
23742
- * **add** - happens just before the class is applied to the elements
23743
- *
23744
- * **remove** - happens just before the class is removed from the element
24213
+ * | Animation | Occurs |
24214
+ * |----------------------------------|-------------------------------------|
24215
+ * | {@link ng.$animate#addClass addClass} | just before the class is applied to the element |
24216
+ * | {@link ng.$animate#removeClass removeClass} | just before the class is removed from the element |
23745
24217
  *
23746
24218
  * @element ANY
23747
24219
  * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
@@ -25000,8 +25472,10 @@ forEach(
25000
25472
  * and `leave` effects.
25001
25473
  *
25002
25474
  * @animations
25003
- * enter - happens just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container
25004
- * leave - happens just before the `ngIf` contents are removed from the DOM
25475
+ * | Animation | Occurs |
25476
+ * |----------------------------------|-------------------------------------|
25477
+ * | {@link ng.$animate#enter enter} | just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container |
25478
+ * | {@link ng.$animate#leave leave} | just before the `ngIf` contents are removed from the DOM |
25005
25479
  *
25006
25480
  * @element ANY
25007
25481
  * @scope
@@ -25042,7 +25516,7 @@ forEach(
25042
25516
  </file>
25043
25517
  </example>
25044
25518
  */
25045
- var ngIfDirective = ['$animate', function($animate) {
25519
+ var ngIfDirective = ['$animate', '$compile', function($animate, $compile) {
25046
25520
  return {
25047
25521
  multiElement: true,
25048
25522
  transclude: 'element',
@@ -25058,7 +25532,7 @@ var ngIfDirective = ['$animate', function($animate) {
25058
25532
  if (!childScope) {
25059
25533
  $transclude(function(clone, newScope) {
25060
25534
  childScope = newScope;
25061
- clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
25535
+ clone[clone.length++] = $compile.$$createComment('end ngIf', $attr.ngIf);
25062
25536
  // Note: We only need the first/last node of the cloned nodes.
25063
25537
  // However, we need to keep the reference to the jqlite wrapper as it might be changed later
25064
25538
  // by a directive with templateUrl when its template arrives.
@@ -25113,8 +25587,10 @@ var ngIfDirective = ['$animate', function($animate) {
25113
25587
  * access on some browsers.
25114
25588
  *
25115
25589
  * @animations
25116
- * enter - animation is used to bring new content into the browser.
25117
- * leave - animation is used to animate existing content away.
25590
+ * | Animation | Occurs |
25591
+ * |----------------------------------|-------------------------------------|
25592
+ * | {@link ng.$animate#enter enter} | when the expression changes, on the new include |
25593
+ * | {@link ng.$animate#leave leave} | when the expression changes, on the old include |
25118
25594
  *
25119
25595
  * The enter and leave animation occur concurrently.
25120
25596
  *
@@ -25380,7 +25856,7 @@ var ngIncludeFillContentDirective = ['$compile',
25380
25856
  // support innerHTML, so detect this here and try to generate the contents
25381
25857
  // specially.
25382
25858
  $element.empty();
25383
- $compile(jqLiteBuildFragment(ctrl.template, document).childNodes)(scope,
25859
+ $compile(jqLiteBuildFragment(ctrl.template, window.document).childNodes)(scope,
25384
25860
  function namespaceAdaptedClone(clone) {
25385
25861
  $element.append(clone);
25386
25862
  }, {futureParentElement: $element});
@@ -25855,9 +26331,9 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
25855
26331
  };
25856
26332
  ngModelSet = function($scope, newValue) {
25857
26333
  if (isFunction(parsedNgModel($scope))) {
25858
- invokeModelSetter($scope, {$$$p: ctrl.$modelValue});
26334
+ invokeModelSetter($scope, {$$$p: newValue});
25859
26335
  } else {
25860
- parsedNgModelAssign($scope, ctrl.$modelValue);
26336
+ parsedNgModelAssign($scope, newValue);
25861
26337
  }
25862
26338
  };
25863
26339
  } else if (!parsedNgModel.assign) {
@@ -25882,7 +26358,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
25882
26358
  * the `$viewValue` are different from last time.
25883
26359
  *
25884
26360
  * Since `ng-model` does not do a deep watch, `$render()` is only invoked if the values of
25885
- * `$modelValue` and `$viewValue` are actually different from their previous value. If `$modelValue`
26361
+ * `$modelValue` and `$viewValue` are actually different from their previous values. If `$modelValue`
25886
26362
  * or `$viewValue` are objects (rather than a string or number) then `$render()` will not be
25887
26363
  * invoked if you only change a property on the objects.
25888
26364
  */
@@ -26234,7 +26710,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
26234
26710
  setValidity(name, undefined);
26235
26711
  validatorPromises.push(promise.then(function() {
26236
26712
  setValidity(name, true);
26237
- }, function(error) {
26713
+ }, function() {
26238
26714
  allValid = false;
26239
26715
  setValidity(name, false);
26240
26716
  }));
@@ -26708,7 +27184,7 @@ var ngModelDirective = ['$rootScope', function($rootScope) {
26708
27184
  });
26709
27185
  }
26710
27186
 
26711
- element.on('blur', function(ev) {
27187
+ element.on('blur', function() {
26712
27188
  if (modelCtrl.$touched) return;
26713
27189
 
26714
27190
  if ($rootScope.$$phase) {
@@ -27294,7 +27770,7 @@ var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s
27294
27770
  // jshint maxlen: 100
27295
27771
 
27296
27772
 
27297
- var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
27773
+ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile, $document, $parse) {
27298
27774
 
27299
27775
  function parseOptionsExpression(optionsExp, selectElement, scope) {
27300
27776
 
@@ -27391,8 +27867,8 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
27391
27867
  var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
27392
27868
  var value = optionValues[key];
27393
27869
 
27394
- var locals = getLocals(optionValues[key], key);
27395
- var selectValue = getTrackByValueFn(optionValues[key], locals);
27870
+ var locals = getLocals(value, key);
27871
+ var selectValue = getTrackByValueFn(value, locals);
27396
27872
  watchedArray.push(selectValue);
27397
27873
 
27398
27874
  // Only need to watch the displayFn if there is a specific label expression
@@ -27455,8 +27931,8 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
27455
27931
 
27456
27932
  // we can't just jqLite('<option>') since jqLite is not smart enough
27457
27933
  // to create it in <select> and IE barfs otherwise.
27458
- var optionTemplate = document.createElement('option'),
27459
- optGroupTemplate = document.createElement('optgroup');
27934
+ var optionTemplate = window.document.createElement('option'),
27935
+ optGroupTemplate = window.document.createElement('optgroup');
27460
27936
 
27461
27937
  function ngOptionsPostLink(scope, selectElement, attr, ctrls) {
27462
27938
 
@@ -27481,7 +27957,10 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
27481
27957
 
27482
27958
  var options;
27483
27959
  var ngOptions = parseOptionsExpression(attr.ngOptions, selectElement, scope);
27484
-
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();
27485
27964
 
27486
27965
  var renderEmptyOption = function() {
27487
27966
  if (!providedEmptyOption) {
@@ -27516,15 +27995,21 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
27516
27995
  selectCtrl.writeValue = function writeNgOptionsValue(value) {
27517
27996
  var option = options.getOptionFromViewValue(value);
27518
27997
 
27519
- if (option && !option.disabled) {
27998
+ if (option) {
27999
+ // Don't update the option when it is already selected.
28000
+ // For example, the browser will select the first option by default. In that case,
28001
+ // most properties are set automatically - except the `selected` attribute, which we
28002
+ // set always
28003
+
27520
28004
  if (selectElement[0].value !== option.selectValue) {
27521
28005
  removeUnknownOption();
27522
28006
  removeEmptyOption();
27523
28007
 
27524
28008
  selectElement[0].value = option.selectValue;
27525
28009
  option.element.selected = true;
27526
- option.element.setAttribute('selected', 'selected');
27527
28010
  }
28011
+
28012
+ option.element.setAttribute('selected', 'selected');
27528
28013
  } else {
27529
28014
  if (value === null || providedEmptyOption) {
27530
28015
  removeUnknownOption();
@@ -27572,7 +28057,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
27572
28057
  if (value) {
27573
28058
  value.forEach(function(item) {
27574
28059
  var option = options.getOptionFromViewValue(item);
27575
- if (option && !option.disabled) option.element.selected = true;
28060
+ if (option) option.element.selected = true;
27576
28061
  });
27577
28062
  }
27578
28063
  };
@@ -27624,6 +28109,8 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
27624
28109
  emptyOption = jqLite(optionTemplate.cloneNode(false));
27625
28110
  }
27626
28111
 
28112
+ selectElement.empty();
28113
+
27627
28114
  // We need to do this here to ensure that the options object is defined
27628
28115
  // when we first hit it in writeNgOptionsValue
27629
28116
  updateOptions();
@@ -27633,6 +28120,12 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
27633
28120
 
27634
28121
  // ------------------------------------------------------------------ //
27635
28122
 
28123
+ function addOptionElement(option, parent) {
28124
+ var optionElement = optionTemplate.cloneNode(false);
28125
+ parent.appendChild(optionElement);
28126
+ updateOptionElement(option, optionElement);
28127
+ }
28128
+
27636
28129
 
27637
28130
  function updateOptionElement(option, element) {
27638
28131
  option.element = element;
@@ -27649,133 +28142,66 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
27649
28142
  if (option.value !== element.value) element.value = option.selectValue;
27650
28143
  }
27651
28144
 
27652
- function addOrReuseElement(parent, current, type, templateElement) {
27653
- var element;
27654
- // Check whether we can reuse the next element
27655
- if (current && lowercase(current.nodeName) === type) {
27656
- // The next element is the right type so reuse it
27657
- element = current;
27658
- } else {
27659
- // The next element is not the right type so create a new one
27660
- element = templateElement.cloneNode(false);
27661
- if (!current) {
27662
- // There are no more elements so just append it to the select
27663
- parent.appendChild(element);
27664
- } else {
27665
- // The next element is not a group so insert the new one
27666
- parent.insertBefore(element, current);
27667
- }
27668
- }
27669
- return element;
27670
- }
27671
-
27672
-
27673
- function removeExcessElements(current) {
27674
- var next;
27675
- while (current) {
27676
- next = current.nextSibling;
27677
- jqLiteRemove(current);
27678
- current = next;
27679
- }
27680
- }
27681
-
27682
-
27683
- function skipEmptyAndUnknownOptions(current) {
27684
- var emptyOption_ = emptyOption && emptyOption[0];
27685
- var unknownOption_ = unknownOption && unknownOption[0];
28145
+ function updateOptions() {
28146
+ var previousValue = options && selectCtrl.readValue();
27686
28147
 
27687
- // We cannot rely on the extracted empty option being the same as the compiled empty option,
27688
- // because the compiled empty option might have been replaced by a comment because
27689
- // it had an "element" transclusion directive on it (such as ngIf)
27690
- if (emptyOption_ || unknownOption_) {
27691
- while (current &&
27692
- (current === emptyOption_ ||
27693
- current === unknownOption_ ||
27694
- current.nodeType === NODE_TYPE_COMMENT ||
27695
- (nodeName_(current) === 'option' && current.value === ''))) {
27696
- 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
+ }
27697
28162
  }
27698
28163
  }
27699
- return current;
27700
- }
27701
-
27702
-
27703
- function updateOptions() {
27704
-
27705
- var previousValue = options && selectCtrl.readValue();
27706
28164
 
27707
28165
  options = ngOptions.getOptions();
27708
28166
 
27709
- var groupMap = {};
27710
- var currentElement = selectElement[0].firstChild;
28167
+ var groupElementMap = {};
27711
28168
 
27712
28169
  // Ensure that the empty option is always there if it was explicitly provided
27713
28170
  if (providedEmptyOption) {
27714
28171
  selectElement.prepend(emptyOption);
27715
28172
  }
27716
28173
 
27717
- currentElement = skipEmptyAndUnknownOptions(currentElement);
27718
-
27719
- options.items.forEach(function updateOption(option) {
27720
- var group;
28174
+ options.items.forEach(function addOption(option) {
27721
28175
  var groupElement;
27722
- var optionElement;
27723
28176
 
27724
28177
  if (isDefined(option.group)) {
27725
28178
 
27726
28179
  // This option is to live in a group
27727
28180
  // See if we have already created this group
27728
- group = groupMap[option.group];
28181
+ groupElement = groupElementMap[option.group];
27729
28182
 
27730
- if (!group) {
28183
+ if (!groupElement) {
27731
28184
 
27732
- // We have not already created this group
27733
- groupElement = addOrReuseElement(selectElement[0],
27734
- currentElement,
27735
- 'optgroup',
27736
- optGroupTemplate);
27737
- // Move to the next element
27738
- currentElement = groupElement.nextSibling;
28185
+ groupElement = optGroupTemplate.cloneNode(false);
28186
+ listFragment.appendChild(groupElement);
27739
28187
 
27740
28188
  // Update the label on the group element
27741
28189
  groupElement.label = option.group;
27742
28190
 
27743
28191
  // Store it for use later
27744
- group = groupMap[option.group] = {
27745
- groupElement: groupElement,
27746
- currentOptionElement: groupElement.firstChild
27747
- };
27748
-
28192
+ groupElementMap[option.group] = groupElement;
27749
28193
  }
27750
28194
 
27751
- // So now we have a group for this option we add the option to the group
27752
- optionElement = addOrReuseElement(group.groupElement,
27753
- group.currentOptionElement,
27754
- 'option',
27755
- optionTemplate);
27756
- updateOptionElement(option, optionElement);
27757
- // Move to the next element
27758
- group.currentOptionElement = optionElement.nextSibling;
28195
+ addOptionElement(option, groupElement);
27759
28196
 
27760
28197
  } else {
27761
28198
 
27762
28199
  // This option is not in a group
27763
- optionElement = addOrReuseElement(selectElement[0],
27764
- currentElement,
27765
- 'option',
27766
- optionTemplate);
27767
- updateOptionElement(option, optionElement);
27768
- // Move to the next element
27769
- currentElement = optionElement.nextSibling;
28200
+ addOptionElement(option, listFragment);
27770
28201
  }
27771
28202
  });
27772
28203
 
27773
-
27774
- // Now remove all excess options and group
27775
- Object.keys(groupMap).forEach(function(key) {
27776
- removeExcessElements(groupMap[key].currentOptionElement);
27777
- });
27778
- removeExcessElements(currentElement);
28204
+ selectElement[0].appendChild(listFragment);
27779
28205
 
27780
28206
  ngModelCtrl.$render();
27781
28207
 
@@ -28083,17 +28509,23 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
28083
28509
  * <div ng-repeat="(key, value) in myObj"> ... </div>
28084
28510
  * ```
28085
28511
  *
28086
- * You need to be aware that the JavaScript specification does not define the order of keys
28087
- * returned for an object. (To mitigate this in Angular 1.3 the `ngRepeat` directive
28088
- * used to sort the keys alphabetically.)
28512
+ * However, there are a limitations compared to array iteration:
28513
+ *
28514
+ * - The JavaScript specification does not define the order of keys
28515
+ * returned for an object, so Angular relies on the order returned by the browser
28516
+ * when running `for key in myObj`. Browsers generally follow the strategy of providing
28517
+ * keys in the order in which they were defined, although there are exceptions when keys are deleted
28518
+ * and reinstated. See the
28519
+ * [MDN page on `delete` for more info](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_notes).
28520
+ *
28521
+ * - `ngRepeat` will silently *ignore* object keys starting with `$`, because
28522
+ * it's a prefix used by Angular for public (`$`) and private (`$$`) properties.
28089
28523
  *
28090
- * Version 1.4 removed the alphabetic sorting. We now rely on the order returned by the browser
28091
- * when running `for key in myObj`. It seems that browsers generally follow the strategy of providing
28092
- * keys in the order in which they were defined, although there are exceptions when keys are deleted
28093
- * and reinstated. See the [MDN page on `delete` for more info](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_notes).
28524
+ * - The built-in filters {@link ng.orderBy orderBy} and {@link ng.filter filter} do not work with
28525
+ * objects, and will throw if used with one.
28094
28526
  *
28095
- * If this is not desired, the recommended workaround is to convert your object into an array
28096
- * that is sorted into the order that you prefer before providing it to `ngRepeat`. You could
28527
+ * If you are hitting any of these limitations, the recommended workaround is to convert your object into an array
28528
+ * that is sorted into the order that you prefer before providing it to `ngRepeat`. You could
28097
28529
  * do this with a filter such as [toArrayFilter](http://ngmodules.org/modules/angular-toArrayFilter)
28098
28530
  * or implement a `$watch` on the object yourself.
28099
28531
  *
@@ -28211,11 +28643,11 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
28211
28643
  * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
28212
28644
  *
28213
28645
  * @animations
28214
- * **.enter** - when a new item is added to the list or when an item is revealed after a filter
28215
- *
28216
- * **.leave** - when an item is removed from the list or when an item is filtered out
28217
- *
28218
- * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
28646
+ * | Animation | Occurs |
28647
+ * |----------------------------------|-------------------------------------|
28648
+ * | {@link ng.$animate#enter enter} | when a new item is added to the list or when an item is revealed after a filter |
28649
+ * | {@link ng.$animate#leave leave} | when an item is removed from the list or when an item is filtered out |
28650
+ * | {@link ng.$animate#move move } | when an adjacent item is filtered out causing a reorder or when the item contents are reordered |
28219
28651
  *
28220
28652
  * See the example below for defining CSS animations with ngRepeat.
28221
28653
  *
@@ -28363,7 +28795,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
28363
28795
  </file>
28364
28796
  </example>
28365
28797
  */
28366
- var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
28798
+ var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $animate, $compile) {
28367
28799
  var NG_REMOVED = '$$NG_REMOVED';
28368
28800
  var ngRepeatMinErr = minErr('ngRepeat');
28369
28801
 
@@ -28398,7 +28830,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
28398
28830
  $$tlb: true,
28399
28831
  compile: function ngRepeatCompile($element, $attr) {
28400
28832
  var expression = $attr.ngRepeat;
28401
- var ngRepeatEndComment = document.createComment(' end ngRepeat: ' + expression + ' ');
28833
+ var ngRepeatEndComment = $compile.$$createComment('end ngRepeat', expression);
28402
28834
 
28403
28835
  var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
28404
28836
 
@@ -28562,7 +28994,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
28562
28994
 
28563
28995
  if (getBlockStart(block) != nextNode) {
28564
28996
  // existing item which got moved
28565
- $animate.move(getBlockNodes(block.clone), null, jqLite(previousNode));
28997
+ $animate.move(getBlockNodes(block.clone), null, previousNode);
28566
28998
  }
28567
28999
  previousNode = getBlockEnd(block);
28568
29000
  updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
@@ -28574,8 +29006,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
28574
29006
  var endNode = ngRepeatEndComment.cloneNode(false);
28575
29007
  clone[clone.length++] = endNode;
28576
29008
 
28577
- // TODO(perf): support naked previousNode in `enter` to avoid creation of jqLite wrapper?
28578
- $animate.enter(clone, null, jqLite(previousNode));
29009
+ $animate.enter(clone, null, previousNode);
28579
29010
  previousNode = endNode;
28580
29011
  // Note: We only need the first/last node of the cloned nodes.
28581
29012
  // However, we need to keep the reference to the jqlite wrapper as it might be changed later
@@ -28678,12 +29109,14 @@ var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
28678
29109
  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
28679
29110
  * ```
28680
29111
  *
28681
- * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
29112
+ * Keep in mind that, as of AngularJS version 1.3, there is no need to change the display
28682
29113
  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
28683
29114
  *
28684
29115
  * @animations
28685
- * addClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a truthy value and the just before contents are set to visible
28686
- * removeClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden
29116
+ * | Animation | Occurs |
29117
+ * |----------------------------------|-------------------------------------|
29118
+ * | {@link $animate#addClass addClass} `.ng-hide` | after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden |
29119
+ * | {@link $animate#removeClass removeClass} `.ng-hide` | after the `ngShow` expression evaluates to a truthy value and just before contents are set to visible |
28687
29120
  *
28688
29121
  * @element ANY
28689
29122
  * @param {expression} ngShow If the {@link guide/expression expression} is truthy
@@ -28842,12 +29275,15 @@ var ngShowDirective = ['$animate', function($animate) {
28842
29275
  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
28843
29276
  * ```
28844
29277
  *
28845
- * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
29278
+ * Keep in mind that, as of AngularJS version 1.3, there is no need to change the display
28846
29279
  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
28847
29280
  *
28848
29281
  * @animations
28849
- * removeClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden
28850
- * addClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a non truthy value and just before the contents are set to visible
29282
+ * | Animation | Occurs |
29283
+ * |----------------------------------|-------------------------------------|
29284
+ * | {@link $animate#addClass addClass} `.ng-hide` | after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden |
29285
+ * | {@link $animate#removeClass removeClass} `.ng-hide` | after the `ngHide` expression evaluates to a non truthy value and just before contents are set to visible |
29286
+ *
28851
29287
  *
28852
29288
  * @element ANY
28853
29289
  * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
@@ -29009,8 +29445,10 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
29009
29445
  * </div>
29010
29446
 
29011
29447
  * @animations
29012
- * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
29013
- * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
29448
+ * | Animation | Occurs |
29449
+ * |----------------------------------|-------------------------------------|
29450
+ * | {@link ng.$animate#enter enter} | after the ngSwitch contents change and the matched child element is placed inside the container |
29451
+ * | {@link ng.$animate#leave leave} | after the ngSwitch contents change and just before the former contents are removed from the DOM |
29014
29452
  *
29015
29453
  * @usage
29016
29454
  *
@@ -29109,7 +29547,7 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
29109
29547
  </file>
29110
29548
  </example>
29111
29549
  */
29112
- var ngSwitchDirective = ['$animate', function($animate) {
29550
+ var ngSwitchDirective = ['$animate', '$compile', function($animate, $compile) {
29113
29551
  return {
29114
29552
  require: 'ngSwitch',
29115
29553
 
@@ -29150,7 +29588,7 @@ var ngSwitchDirective = ['$animate', function($animate) {
29150
29588
  selectedTransclude.transclude(function(caseElement, selectedScope) {
29151
29589
  selectedScopes.push(selectedScope);
29152
29590
  var anchor = selectedTransclude.element;
29153
- caseElement[caseElement.length++] = document.createComment(' end ngSwitchWhen: ');
29591
+ caseElement[caseElement.length++] = $compile.$$createComment('end ngSwitchWhen');
29154
29592
  var block = { clone: caseElement };
29155
29593
 
29156
29594
  selectedElements.push(block);
@@ -29444,7 +29882,7 @@ function chromeHack(optionElement) {
29444
29882
  * added `<option>` elements, perhaps by an `ngRepeat` directive.
29445
29883
  */
29446
29884
  var SelectController =
29447
- ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
29885
+ ['$element', '$scope', function($element, $scope) {
29448
29886
 
29449
29887
  var self = this,
29450
29888
  optionsMap = new HashMap();
@@ -29458,7 +29896,7 @@ var SelectController =
29458
29896
  //
29459
29897
  // We can't just jqLite('<option>') since jqLite is not smart enough
29460
29898
  // to create it in <select> and IE barfs otherwise.
29461
- self.unknownOption = jqLite(document.createElement('option'));
29899
+ self.unknownOption = jqLite(window.document.createElement('option'));
29462
29900
  self.renderUnknownOption = function(val) {
29463
29901
  var unknownVal = '? ' + hashKey(val) + ' ?';
29464
29902
  self.unknownOption.val(unknownVal);
@@ -30266,7 +30704,9 @@ var minlengthDirective = function() {
30266
30704
 
30267
30705
  if (window.angular.bootstrap) {
30268
30706
  //AngularJS is already loaded, so we can return here...
30269
- console.log('WARNING: Tried to load angular more than once.');
30707
+ if (window.console) {
30708
+ console.log('WARNING: Tried to load angular more than once.');
30709
+ }
30270
30710
  return;
30271
30711
  }
30272
30712
 
@@ -30419,10 +30859,10 @@ $provide.value("$locale", {
30419
30859
  });
30420
30860
  }]);
30421
30861
 
30422
- jqLite(document).ready(function() {
30423
- angularInit(document, bootstrap);
30862
+ jqLite(window.document).ready(function() {
30863
+ angularInit(window.document, bootstrap);
30424
30864
  });
30425
30865
 
30426
- })(window, document);
30866
+ })(window);
30427
30867
 
30428
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>');