angularjs-rails 1.5.0 → 1.5.5

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