angularjs-rails 1.2.20 → 1.2.21

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,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.3.0-beta.15
2
+ * @license AngularJS v1.3.0-beta.17
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -50,9 +50,9 @@
50
50
  * }
51
51
  *
52
52
  * .slide.ng-enter { } /* starting animations for enter */
53
- * .slide.ng-enter-active { } /* terminal animations for enter */
53
+ * .slide.ng-enter.ng-enter-active { } /* terminal animations for enter */
54
54
  * .slide.ng-leave { } /* starting animations for leave */
55
- * .slide.ng-leave-active { } /* terminal animations for leave */
55
+ * .slide.ng-leave.ng-leave-active { } /* terminal animations for leave */
56
56
  * </style>
57
57
  *
58
58
  * <!--
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.3.0-beta.15
2
+ * @license AngularJS v1.3.0-beta.17
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.3.0-beta.15
2
+ * @license AngularJS v1.3.0-beta.17
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -69,7 +69,7 @@ function minErr(module) {
69
69
  return match;
70
70
  });
71
71
 
72
- message = message + '\nhttp://errors.angularjs.org/1.3.0-beta.15/' +
72
+ message = message + '\nhttp://errors.angularjs.org/1.3.0-beta.17/' +
73
73
  (module ? module + '/' : '') + code;
74
74
  for (i = 2; i < arguments.length; i++) {
75
75
  message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.3.0-beta.15
2
+ * @license AngularJS v1.3.0-beta.17
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.3.0-beta.15
2
+ * @license AngularJS v1.3.0-beta.17
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -1739,6 +1739,7 @@ angular.mock.$RootElementProvider = function() {
1739
1739
  /**
1740
1740
  * @ngdoc module
1741
1741
  * @name ngMock
1742
+ * @packageName angular-mocks
1742
1743
  * @description
1743
1744
  *
1744
1745
  * # ngMock
@@ -1768,6 +1769,7 @@ angular.module('ngMock', ['ng']).provider({
1768
1769
  * @ngdoc module
1769
1770
  * @name ngMockE2E
1770
1771
  * @module ngMockE2E
1772
+ * @packageName angular-mocks
1771
1773
  * @description
1772
1774
  *
1773
1775
  * The `ngMockE2E` is an angular module which contains mocks suitable for end-to-end testing.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.3.0-beta.15
2
+ * @license AngularJS v1.3.0-beta.17
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -126,8 +126,8 @@ function shallowClearAndCopy(src, dst) {
126
126
  *
127
127
  * - **`action`** – {string} – The name of action. This name becomes the name of the method on
128
128
  * your resource object.
129
- * - **`method`** – {string} – HTTP request method. Valid methods are: `GET`, `POST`, `PUT`,
130
- * `DELETE`, and `JSONP`.
129
+ * - **`method`** – {string} – Case insensitive HTTP method (e.g. `GET`, `POST`, `PUT`,
130
+ * `DELETE`, `JSONP`, etc).
131
131
  * - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of
132
132
  * the parameter value is a function, it will be executed every time when a param value needs to
133
133
  * be obtained for a request (unless the param was overridden).
@@ -315,20 +315,20 @@ function shallowClearAndCopy(src, dst) {
315
315
  * # Creating a custom 'PUT' request
316
316
  * In this example we create a custom method on our resource to make a PUT request
317
317
  * ```js
318
- * var app = angular.module('app', ['ngResource', 'ngRoute']);
318
+ * var app = angular.module('app', ['ngResource', 'ngRoute']);
319
319
  *
320
- * // Some APIs expect a PUT request in the format URL/object/ID
321
- * // Here we are creating an 'update' method
322
- * app.factory('Notes', ['$resource', function($resource) {
320
+ * // Some APIs expect a PUT request in the format URL/object/ID
321
+ * // Here we are creating an 'update' method
322
+ * app.factory('Notes', ['$resource', function($resource) {
323
323
  * return $resource('/notes/:id', null,
324
324
  * {
325
325
  * 'update': { method:'PUT' }
326
326
  * });
327
- * }]);
327
+ * }]);
328
328
  *
329
- * // In our controller we get the ID from the URL using ngRoute and $routeParams
330
- * // We pass in $routeParams and our Notes factory along with $scope
331
- * app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
329
+ * // In our controller we get the ID from the URL using ngRoute and $routeParams
330
+ * // We pass in $routeParams and our Notes factory along with $scope
331
+ * app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
332
332
  function($scope, $routeParams, Notes) {
333
333
  * // First get a note object from the factory
334
334
  * var note = Notes.get({ id:$routeParams.id });
@@ -338,7 +338,7 @@ function shallowClearAndCopy(src, dst) {
338
338
  * Notes.update({ id:$id }, note);
339
339
  *
340
340
  * // This will PUT /notes/ID with the note object in the request payload
341
- * }]);
341
+ * }]);
342
342
  * ```
343
343
  */
344
344
  angular.module('ngResource', ['ng']).
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.3.0-beta.15
2
+ * @license AngularJS v1.3.0-beta.17
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -473,9 +473,7 @@ function $RouteProvider(){
473
473
  for (var i = 1, len = m.length; i < len; ++i) {
474
474
  var key = keys[i - 1];
475
475
 
476
- var val = 'string' == typeof m[i]
477
- ? decodeURIComponent(m[i])
478
- : m[i];
476
+ var val = m[i];
479
477
 
480
478
  if (key && val) {
481
479
  params[key.name] = val;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.3.0-beta.15
2
+ * @license AngularJS v1.3.0-beta.17
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -159,11 +159,11 @@ function sanitizeText(chars) {
159
159
 
160
160
  // Regular Expressions for parsing tags and attributes
161
161
  var START_TAG_REGEXP =
162
- /^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/,
163
- END_TAG_REGEXP = /^<\s*\/\s*([\w:-]+)[^>]*>/,
162
+ /^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/,
163
+ END_TAG_REGEXP = /^<\/\s*([\w:-]+)[^>]*>/,
164
164
  ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,
165
165
  BEGIN_TAG_REGEXP = /^</,
166
- BEGING_END_TAGE_REGEXP = /^<\s*\//,
166
+ BEGING_END_TAGE_REGEXP = /^<\//,
167
167
  COMMENT_REGEXP = /<!--(.*?)-->/g,
168
168
  DOCTYPE_REGEXP = /<!DOCTYPE([^>]*?)>/i,
169
169
  CDATA_REGEXP = /<!\[CDATA\[(.*?)]]>/g,
@@ -237,10 +237,11 @@ function makeMap(str) {
237
237
  * @param {object} handler
238
238
  */
239
239
  function htmlParser( html, handler ) {
240
- var index, chars, match, stack = [], last = html;
240
+ var index, chars, match, stack = [], last = html, text;
241
241
  stack.last = function() { return stack[ stack.length - 1 ]; };
242
242
 
243
243
  while ( html ) {
244
+ text = '';
244
245
  chars = true;
245
246
 
246
247
  // Make sure we're not in a script or style element
@@ -279,16 +280,23 @@ function htmlParser( html, handler ) {
279
280
  match = html.match( START_TAG_REGEXP );
280
281
 
281
282
  if ( match ) {
282
- html = html.substring( match[0].length );
283
- match[0].replace( START_TAG_REGEXP, parseStartTag );
283
+ // We only have a valid start-tag if there is a '>'.
284
+ if ( match[4] ) {
285
+ html = html.substring( match[0].length );
286
+ match[0].replace( START_TAG_REGEXP, parseStartTag );
287
+ }
284
288
  chars = false;
289
+ } else {
290
+ // no ending tag found --- this piece should be encoded as an entity.
291
+ text += '<';
292
+ html = html.substring(1);
285
293
  }
286
294
  }
287
295
 
288
296
  if ( chars ) {
289
297
  index = html.indexOf("<");
290
298
 
291
- var text = index < 0 ? html : html.substring( 0, index );
299
+ text += index < 0 ? html : html.substring( 0, index );
292
300
  html = index < 0 ? "" : html.substring( index );
293
301
 
294
302
  if (handler.chars) handler.chars( decodeEntities(text) );
@@ -9790,7 +9790,7 @@ if ( typeof module === "object" && module && typeof module.exports === "object"
9790
9790
  })( window );
9791
9791
 
9792
9792
  /**
9793
- * @license AngularJS v1.3.0-beta.15
9793
+ * @license AngularJS v1.3.0-beta.17
9794
9794
  * (c) 2010-2014 Google, Inc. http://angularjs.org
9795
9795
  * License: MIT
9796
9796
  */
@@ -9860,7 +9860,7 @@ function minErr(module) {
9860
9860
  return match;
9861
9861
  });
9862
9862
 
9863
- message = message + '\nhttp://errors.angularjs.org/1.3.0-beta.15/' +
9863
+ message = message + '\nhttp://errors.angularjs.org/1.3.0-beta.17/' +
9864
9864
  (module ? module + '/' : '') + code;
9865
9865
  for (i = 2; i < arguments.length; i++) {
9866
9866
  message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
@@ -9918,6 +9918,7 @@ function minErr(module) {
9918
9918
  isFile: true,
9919
9919
  isBlob: true,
9920
9920
  isBoolean: true,
9921
+ isPromiseLike: true,
9921
9922
  trim: true,
9922
9923
  isElement: true,
9923
9924
  makeMap: true,
@@ -10440,6 +10441,11 @@ function isBoolean(value) {
10440
10441
  }
10441
10442
 
10442
10443
 
10444
+ function isPromiseLike(obj) {
10445
+ return obj && isFunction(obj.then);
10446
+ }
10447
+
10448
+
10443
10449
  var trim = (function() {
10444
10450
  // native trim is way faster: http://jsperf.com/angular-trim-test
10445
10451
  // but IE doesn't have it... :-(
@@ -10606,7 +10612,7 @@ function isLeafNode (node) {
10606
10612
  </div>
10607
10613
 
10608
10614
  <script>
10609
- angular.module('copyExample')
10615
+ angular.module('copyExample', [])
10610
10616
  .controller('ExampleController', ['$scope', function($scope) {
10611
10617
  $scope.master= {};
10612
10618
 
@@ -10640,7 +10646,8 @@ function copy(source, destination, stackSource, stackDest) {
10640
10646
  } else if (isDate(source)) {
10641
10647
  destination = new Date(source.getTime());
10642
10648
  } else if (isRegExp(source)) {
10643
- destination = new RegExp(source.source);
10649
+ destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
10650
+ destination.lastIndex = source.lastIndex;
10644
10651
  } else if (isObject(source)) {
10645
10652
  var emptyObject = Object.create(Object.getPrototypeOf(source));
10646
10653
  destination = copy(source, emptyObject, stackSource, stackDest);
@@ -10792,12 +10799,25 @@ function equals(o1, o2) {
10792
10799
  return false;
10793
10800
  }
10794
10801
 
10802
+ var csp = function() {
10803
+ if (isDefined(csp.isActive_)) return csp.isActive_;
10804
+
10805
+ var active = !!(document.querySelector('[ng-csp]') ||
10806
+ document.querySelector('[data-ng-csp]'));
10807
+
10808
+ if (!active) {
10809
+ try {
10810
+ /* jshint -W031, -W054 */
10811
+ new Function('');
10812
+ /* jshint +W031, +W054 */
10813
+ } catch (e) {
10814
+ active = true;
10815
+ }
10816
+ }
10817
+
10818
+ return (csp.isActive_ = active);
10819
+ };
10795
10820
 
10796
- function csp() {
10797
- return (document.securityPolicy && document.securityPolicy.isActive) ||
10798
- (document.querySelector &&
10799
- !!(document.querySelector('[ng-csp]') || document.querySelector('[data-ng-csp]')));
10800
- }
10801
10821
 
10802
10822
 
10803
10823
  function concat(array1, array2, index) {
@@ -10957,7 +10977,7 @@ function parseKeyValue(/**string*/keyValue) {
10957
10977
  var obj = {}, key_value, key;
10958
10978
  forEach((keyValue || "").split('&'), function(keyValue) {
10959
10979
  if ( keyValue ) {
10960
- key_value = keyValue.split('=');
10980
+ key_value = keyValue.replace(/\+/g,'%20').split('=');
10961
10981
  key = tryDecodeURIComponent(key_value[0]);
10962
10982
  if ( isDefined(key) ) {
10963
10983
  var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
@@ -11033,7 +11053,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
11033
11053
  var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
11034
11054
 
11035
11055
  function getNgAttribute(element, ngAttr) {
11036
- var attr, i, ii = ngAttrPrefixes.length, j, jj;
11056
+ var attr, i, ii = ngAttrPrefixes.length;
11037
11057
  element = jqLite(element);
11038
11058
  for (i=0; i<ii; ++i) {
11039
11059
  attr = ngAttrPrefixes[i] + ngAttr;
@@ -11172,46 +11192,26 @@ function getNgAttribute(element, ngAttr) {
11172
11192
  </example>
11173
11193
  */
11174
11194
  function angularInit(element, bootstrap) {
11175
- var elements = [element],
11176
- appElement,
11195
+ var appElement,
11177
11196
  module,
11178
- config = {},
11179
- names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'],
11180
- options = {
11181
- 'boolean': ['strict-di']
11182
- },
11183
- NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;
11197
+ config = {};
11184
11198
 
11185
- function append(element) {
11186
- element && elements.push(element);
11187
- }
11199
+ // The element `element` has priority over any other element
11200
+ forEach(ngAttrPrefixes, function(prefix) {
11201
+ var name = prefix + 'app';
11188
11202
 
11189
- forEach(names, function(name) {
11190
- names[name] = true;
11191
- append(document.getElementById(name));
11192
- name = name.replace(':', '\\:');
11193
- if (element.querySelectorAll) {
11194
- forEach(element.querySelectorAll('.' + name), append);
11195
- forEach(element.querySelectorAll('.' + name + '\\:'), append);
11196
- forEach(element.querySelectorAll('[' + name + ']'), append);
11203
+ if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
11204
+ appElement = element;
11205
+ module = element.getAttribute(name);
11197
11206
  }
11198
11207
  });
11208
+ forEach(ngAttrPrefixes, function(prefix) {
11209
+ var name = prefix + 'app';
11210
+ var candidate;
11199
11211
 
11200
- forEach(elements, function(element) {
11201
- if (!appElement) {
11202
- var className = ' ' + element.className + ' ';
11203
- var match = NG_APP_CLASS_REGEXP.exec(className);
11204
- if (match) {
11205
- appElement = element;
11206
- module = (match[2] || '').replace(/\s+/g, ',');
11207
- } else {
11208
- forEach(element.attributes, function(attr) {
11209
- if (!appElement && names[attr.name]) {
11210
- appElement = element;
11211
- module = attr.value;
11212
- }
11213
- });
11214
- }
11212
+ if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
11213
+ appElement = candidate;
11214
+ module = candidate.getAttribute(name);
11215
11215
  }
11216
11216
  });
11217
11217
  if (appElement) {
@@ -11859,11 +11859,11 @@ function setupModuleLoader(window) {
11859
11859
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
11860
11860
  */
11861
11861
  var version = {
11862
- full: '1.3.0-beta.15', // all of these placeholder strings will be replaced by grunt's
11862
+ full: '1.3.0-beta.17', // all of these placeholder strings will be replaced by grunt's
11863
11863
  major: 1, // package task
11864
11864
  minor: 3,
11865
11865
  dot: 0,
11866
- codeName: 'unbelievable-advancement'
11866
+ codeName: 'turing-autocompletion'
11867
11867
  };
11868
11868
 
11869
11869
 
@@ -12406,25 +12406,22 @@ function jqLiteController(element, name) {
12406
12406
  }
12407
12407
 
12408
12408
  function jqLiteInheritedData(element, name, value) {
12409
- element = jqLite(element);
12410
-
12411
12409
  // if element is the document object work with the html element instead
12412
12410
  // this makes $(document).scope() possible
12413
- if(element[0].nodeType == 9) {
12414
- element = element.find('html');
12411
+ if(element.nodeType == 9) {
12412
+ element = element.documentElement;
12415
12413
  }
12416
12414
  var names = isArray(name) ? name : [name];
12417
12415
 
12418
- while (element.length) {
12419
- var node = element[0];
12416
+ while (element) {
12420
12417
  for (var i = 0, ii = names.length; i < ii; i++) {
12421
- if ((value = element.data(names[i])) !== undefined) return value;
12418
+ if ((value = jqLite.data(element, names[i])) !== undefined) return value;
12422
12419
  }
12423
12420
 
12424
12421
  // If dealing with a document fragment node with a host element, and no parent, use the host
12425
12422
  // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
12426
12423
  // to lookup parent controllers.
12427
- element = jqLite(node.parentNode || (node.nodeType === 11 && node.host));
12424
+ element = element.parentNode || (element.nodeType === 11 && element.host);
12428
12425
  }
12429
12426
  }
12430
12427
 
@@ -12507,18 +12504,25 @@ function getAliasedAttrName(element, name) {
12507
12504
  return (nodeName === 'INPUT' || nodeName === 'TEXTAREA') && ALIASED_ATTR[name];
12508
12505
  }
12509
12506
 
12507
+ forEach({
12508
+ data: jqLiteData,
12509
+ removeData: jqLiteRemoveData
12510
+ }, function(fn, name) {
12511
+ JQLite[name] = fn;
12512
+ });
12513
+
12510
12514
  forEach({
12511
12515
  data: jqLiteData,
12512
12516
  inheritedData: jqLiteInheritedData,
12513
12517
 
12514
12518
  scope: function(element) {
12515
12519
  // Can't use jqLiteData here directly so we stay compatible with jQuery!
12516
- return jqLite(element).data('$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
12520
+ return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
12517
12521
  },
12518
12522
 
12519
12523
  isolateScope: function(element) {
12520
12524
  // Can't use jqLiteData here directly so we stay compatible with jQuery!
12521
- return jqLite(element).data('$isolateScope') || jqLite(element).data('$isolateScopeNoTemplate');
12525
+ return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
12522
12526
  },
12523
12527
 
12524
12528
  controller: jqLiteController,
@@ -12939,7 +12943,9 @@ forEach({
12939
12943
  clone: jqLiteClone,
12940
12944
 
12941
12945
  triggerHandler: function(element, eventName, eventData) {
12942
- var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName];
12946
+ // Copy event handlers in case event handlers array is modified during execution.
12947
+ var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName],
12948
+ eventFnsCopy = shallowCopy(eventFns || []);
12943
12949
 
12944
12950
  eventData = eventData || [];
12945
12951
 
@@ -12953,7 +12959,7 @@ forEach({
12953
12959
  stopPropagation: noop
12954
12960
  }];
12955
12961
 
12956
- forEach(eventFns, function(fn) {
12962
+ forEach(eventFnsCopy, function(fn) {
12957
12963
  fn.apply(element, event.concat(eventData));
12958
12964
  });
12959
12965
  }
@@ -13076,7 +13082,7 @@ HashMap.prototype = {
13076
13082
  *
13077
13083
  * // use the injector to kick off your application
13078
13084
  * // use the type inference to auto inject arguments, or use implicit injection
13079
- * $injector.invoke(function($rootScope, $compile, $document){
13085
+ * $injector.invoke(function($rootScope, $compile, $document) {
13080
13086
  * $compile($document)($rootScope);
13081
13087
  * $rootScope.$digest();
13082
13088
  * });
@@ -13150,8 +13156,8 @@ function annotate(fn, strictDi, name) {
13150
13156
  }
13151
13157
  fnText = fn.toString().replace(STRIP_COMMENTS, '');
13152
13158
  argDecl = fnText.match(FN_ARGS);
13153
- forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
13154
- arg.replace(FN_ARG, function(all, underscore, name){
13159
+ forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
13160
+ arg.replace(FN_ARG, function(all, underscore, name) {
13155
13161
  $inject.push(name);
13156
13162
  });
13157
13163
  });
@@ -13186,7 +13192,7 @@ function annotate(fn, strictDi, name) {
13186
13192
  * ```js
13187
13193
  * var $injector = angular.injector();
13188
13194
  * expect($injector.get('$injector')).toBe($injector);
13189
- * expect($injector.invoke(function($injector){
13195
+ * expect($injector.invoke(function($injector) {
13190
13196
  * return $injector;
13191
13197
  * }).toBe($injector);
13192
13198
  * ```
@@ -13822,7 +13828,7 @@ function createInjector(modulesToLoad, strictDi) {
13822
13828
  }
13823
13829
  }
13824
13830
 
13825
- function invoke(fn, self, locals, serviceName){
13831
+ function invoke(fn, self, locals, serviceName) {
13826
13832
  if (typeof locals === 'string') {
13827
13833
  serviceName = locals;
13828
13834
  locals = null;
@@ -14521,16 +14527,15 @@ function Browser(window, document, $log, $sniffer) {
14521
14527
  * @returns {Object} Hash of all cookies (if called without any parameter)
14522
14528
  */
14523
14529
  self.cookies = function(name, value) {
14524
- /* global escape: false, unescape: false */
14525
14530
  var cookieLength, cookieArray, cookie, i, index;
14526
14531
 
14527
14532
  if (name) {
14528
14533
  if (value === undefined) {
14529
- rawDocument.cookie = escape(name) + "=;path=" + cookiePath +
14534
+ rawDocument.cookie = encodeURIComponent(name) + "=;path=" + cookiePath +
14530
14535
  ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
14531
14536
  } else {
14532
14537
  if (isString(value)) {
14533
- cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) +
14538
+ cookieLength = (rawDocument.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value) +
14534
14539
  ';path=' + cookiePath).length + 1;
14535
14540
 
14536
14541
  // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
@@ -14554,12 +14559,12 @@ function Browser(window, document, $log, $sniffer) {
14554
14559
  cookie = cookieArray[i];
14555
14560
  index = cookie.indexOf('=');
14556
14561
  if (index > 0) { //ignore nameless cookies
14557
- name = unescape(cookie.substring(0, index));
14562
+ name = decodeURIComponent(cookie.substring(0, index));
14558
14563
  // the first value that is seen for a cookie is the most
14559
14564
  // specific one. values for the same cookie name that
14560
14565
  // follow are for less specific paths.
14561
14566
  if (lastCookies[name] === undefined) {
14562
- lastCookies[name] = unescape(cookie.substring(index + 1));
14567
+ lastCookies[name] = decodeURIComponent(cookie.substring(index + 1));
14563
14568
  }
14564
14569
  }
14565
14570
  }
@@ -15132,6 +15137,13 @@ function $TemplateCacheProvider() {
15132
15137
  * The directive definition object provides instructions to the {@link ng.$compile
15133
15138
  * compiler}. The attributes are:
15134
15139
  *
15140
+ * ### `multiElement`
15141
+ * When this property is set to true, the HTML compiler will collect DOM nodes between
15142
+ * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
15143
+ * together as the directive elements. It is recomended that this feature be used on directives
15144
+ * which are not strictly behavioural (such as {@link api/ng.directive:ngClick ngClick}), and which
15145
+ * do not manipulate or replace child nodes (such as {@link api/ng.directive:ngInclude ngInclude}).
15146
+ *
15135
15147
  * #### `priority`
15136
15148
  * When there are multiple directives defined on a single DOM element, sometimes it
15137
15149
  * is necessary to specify the order in which the directives are applied. The `priority` is used
@@ -15227,7 +15239,7 @@ function $TemplateCacheProvider() {
15227
15239
  * String of subset of `EACM` which restricts the directive to a specific directive
15228
15240
  * declaration style. If omitted, the default (attributes only) is used.
15229
15241
  *
15230
- * * `E` - Element name: `<my-directive></my-directive>`
15242
+ * * `E` - Element name (default): `<my-directive></my-directive>`
15231
15243
  * * `A` - Attribute (default): `<div my-directive="exp"></div>`
15232
15244
  * * `C` - Class: `<div class="my-directive: exp;"></div>`
15233
15245
  * * `M` - Comment: `<!-- directive: my-directive exp -->`
@@ -15247,14 +15259,16 @@ function $TemplateCacheProvider() {
15247
15259
  * If no `type` is specified, then the type is considered to be html.
15248
15260
  *
15249
15261
  * #### `template`
15250
- * replace the current element with the contents of the HTML. The replacement process
15251
- * migrates all of the attributes / classes from the old element to the new one. See the
15252
- * {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
15253
- * Directives Guide} for an example.
15262
+ * HTML markup that may:
15263
+ * * Replace the contents of the directive's element (defualt).
15264
+ * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
15265
+ * * Wrap the contents of the directive's element (if `transclude` is true).
15266
+ *
15267
+ * Value may be:
15254
15268
  *
15255
- * You can specify `template` as a string representing the template or as a function which takes
15256
- * two arguments `tElement` and `tAttrs` (described in the `compile` function api below) and
15257
- * returns a string value representing the template.
15269
+ * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
15270
+ * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
15271
+ * function api below) and returns a string value.
15258
15272
  *
15259
15273
  *
15260
15274
  * #### `templateUrl`
@@ -15269,11 +15283,14 @@ function $TemplateCacheProvider() {
15269
15283
  *
15270
15284
  *
15271
15285
  * #### `replace` ([*DEPRECATED*!], will be removed in next major release)
15272
- * specify where the template should be inserted. Defaults to `false`.
15286
+ * specify what the template should replace. Defaults to `false`.
15273
15287
  *
15274
- * * `true` - the template will replace the current element.
15275
- * * `false` - the template will replace the contents of the current element.
15288
+ * * `true` - the template will replace the directive's element.
15289
+ * * `false` - the template will replace the contents of the directive's element.
15276
15290
  *
15291
+ * The replacement process migrates all of the attributes / classes from the old element to the new
15292
+ * one. See the {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
15293
+ * Directives Guide} for an example.
15277
15294
  *
15278
15295
  * #### `transclude`
15279
15296
  * compile the content of the element and make it available to the directive.
@@ -15287,6 +15304,11 @@ function $TemplateCacheProvider() {
15287
15304
  * * `true` - transclude the content of the directive.
15288
15305
  * * `'element'` - transclude the whole element including any directives defined at lower priority.
15289
15306
  *
15307
+ * <div class="alert alert-warning">
15308
+ * **Note:** When testing an element transclude directive you must not place the directive at the root of the
15309
+ * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
15310
+ * Testing Transclusion Directives}.
15311
+ * </div>
15290
15312
  *
15291
15313
  * #### `compile`
15292
15314
  *
@@ -15585,7 +15607,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15585
15607
  directive.index = index;
15586
15608
  directive.name = directive.name || name;
15587
15609
  directive.require = directive.require || (directive.controller && directive.name);
15588
- directive.restrict = directive.restrict || 'A';
15610
+ directive.restrict = directive.restrict || 'EA';
15589
15611
  directives.push(directive);
15590
15612
  } catch (e) {
15591
15613
  $exceptionHandler(e);
@@ -15935,7 +15957,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15935
15957
  : null;
15936
15958
 
15937
15959
  if (nodeLinkFn && nodeLinkFn.scope) {
15938
- safeAddClass(jqLite(nodeList[i]), 'ng-scope');
15960
+ safeAddClass(attrs.$$element, 'ng-scope');
15939
15961
  }
15940
15962
 
15941
15963
  childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
@@ -15957,7 +15979,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15957
15979
  return linkFnFound ? compositeLinkFn : null;
15958
15980
 
15959
15981
  function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
15960
- var nodeLinkFn, childLinkFn, node, $node, childScope, i, ii, n, childBoundTranscludeFn;
15982
+ var nodeLinkFn, childLinkFn, node, childScope, i, ii, n, childBoundTranscludeFn;
15961
15983
 
15962
15984
  // copy nodeList so that linking doesn't break due to live list updates.
15963
15985
  var nodeListLength = nodeList.length,
@@ -15970,12 +15992,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15970
15992
  node = stableNodeList[n];
15971
15993
  nodeLinkFn = linkFns[i++];
15972
15994
  childLinkFn = linkFns[i++];
15973
- $node = jqLite(node);
15974
15995
 
15975
15996
  if (nodeLinkFn) {
15976
15997
  if (nodeLinkFn.scope) {
15977
15998
  childScope = scope.$new();
15978
- $node.data('$scope', childScope);
15999
+ jqLite.data(node, '$scope', childScope);
15979
16000
  } else {
15980
16001
  childScope = scope;
15981
16002
  }
@@ -16063,10 +16084,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16063
16084
  }
16064
16085
 
16065
16086
  var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
16066
- if (ngAttrName === directiveNName + 'Start') {
16067
- attrStartName = name;
16068
- attrEndName = name.substr(0, name.length - 5) + 'end';
16069
- name = name.substr(0, name.length - 6);
16087
+ if (directiveIsMultiElement(directiveNName)) {
16088
+ if (ngAttrName === directiveNName + 'Start') {
16089
+ attrStartName = name;
16090
+ attrEndName = name.substr(0, name.length - 5) + 'end';
16091
+ name = name.substr(0, name.length - 6);
16092
+ }
16070
16093
  }
16071
16094
 
16072
16095
  nName = directiveNormalize(name.toLowerCase());
@@ -16275,12 +16298,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16275
16298
  if (directiveValue == 'element') {
16276
16299
  hasElementTranscludeDirective = true;
16277
16300
  terminalPriority = directive.priority;
16278
- $template = groupScan(compileNode, attrStart, attrEnd);
16301
+ $template = $compileNode;
16279
16302
  $compileNode = templateAttrs.$$element =
16280
16303
  jqLite(document.createComment(' ' + directiveName + ': ' +
16281
16304
  templateAttrs[directiveName] + ' '));
16282
16305
  compileNode = $compileNode[0];
16283
- replaceWith(jqCollection, jqLite(sliceArgs($template)), compileNode);
16306
+ replaceWith(jqCollection, sliceArgs($template), compileNode);
16284
16307
 
16285
16308
  childTranscludeFn = compile($template, transcludeFn, terminalPriority,
16286
16309
  replaceDirective && replaceDirective.name, {
@@ -16457,29 +16480,26 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16457
16480
  function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
16458
16481
  var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn;
16459
16482
 
16460
- if (compileNode === linkNode) {
16461
- attrs = templateAttrs;
16462
- } else {
16463
- attrs = shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
16464
- }
16483
+ attrs = (compileNode === linkNode)
16484
+ ? templateAttrs
16485
+ : shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
16465
16486
  $element = attrs.$$element;
16466
16487
 
16467
16488
  if (newIsolateScopeDirective) {
16468
16489
  var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
16469
- var $linkNode = jqLite(linkNode);
16470
16490
 
16471
16491
  isolateScope = scope.$new(true);
16472
16492
 
16473
16493
  if (templateDirective && (templateDirective === newIsolateScopeDirective ||
16474
16494
  templateDirective === newIsolateScopeDirective.$$originalDirective)) {
16475
- $linkNode.data('$isolateScope', isolateScope) ;
16495
+ $element.data('$isolateScope', isolateScope);
16476
16496
  } else {
16477
- $linkNode.data('$isolateScopeNoTemplate', isolateScope);
16497
+ $element.data('$isolateScopeNoTemplate', isolateScope);
16478
16498
  }
16479
16499
 
16480
16500
 
16481
16501
 
16482
- safeAddClass($linkNode, 'ng-isolate-scope');
16502
+ safeAddClass($element, 'ng-isolate-scope');
16483
16503
 
16484
16504
  forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
16485
16505
  var match = definition.match(LOCAL_REGEXP) || [],
@@ -16523,8 +16543,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16523
16543
  attrs[attrName], newIsolateScopeDirective.name);
16524
16544
  };
16525
16545
  lastValue = isolateScope[scopeName] = parentGet(scope);
16526
- isolateScope.$watch(function parentValueWatch() {
16527
- var parentValue = parentGet(scope);
16546
+ var unwatch = scope.$watch($parse(attrs[attrName], function parentValueWatch(parentValue) {
16528
16547
  if (!compare(parentValue, isolateScope[scopeName])) {
16529
16548
  // we are out of sync and need to copy
16530
16549
  if (!compare(parentValue, lastValue)) {
@@ -16535,9 +16554,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16535
16554
  parentSet(scope, parentValue = isolateScope[scopeName]);
16536
16555
  }
16537
16556
  }
16538
- parentValueWatch.$$unwatch = parentGet.$$unwatch;
16539
16557
  return lastValue = parentValue;
16540
- }, null, parentGet.literal);
16558
+ }), null, parentGet.literal);
16559
+ isolateScope.$on('$destroy', unwatch);
16541
16560
  break;
16542
16561
 
16543
16562
  case '&':
@@ -16682,6 +16701,27 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16682
16701
  }
16683
16702
 
16684
16703
 
16704
+ /**
16705
+ * looks up the directive and returns true if it is a multi-element directive,
16706
+ * and therefore requires DOM nodes between -start and -end markers to be grouped
16707
+ * together.
16708
+ *
16709
+ * @param {string} name name of the directive to look up.
16710
+ * @returns true if directive was registered as multi-element.
16711
+ */
16712
+ function directiveIsMultiElement(name) {
16713
+ if (hasDirectives.hasOwnProperty(name)) {
16714
+ for(var directive, directives = $injector.get(name + Suffix),
16715
+ i = 0, ii = directives.length; i<ii; i++) {
16716
+ directive = directives[i];
16717
+ if (directive.multiElement) {
16718
+ return true;
16719
+ }
16720
+ }
16721
+ }
16722
+ return false;
16723
+ }
16724
+
16685
16725
  /**
16686
16726
  * When the element is replaced with HTML template then the new attributes
16687
16727
  * on the template need to be merged with the existing attributes in the DOM.
@@ -16873,9 +16913,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16873
16913
  return function textInterpolateLinkFn(scope, node) {
16874
16914
  var parent = node.parent(),
16875
16915
  bindings = parent.data('$binding') || [];
16876
- // Need to interpolate again in case this is using one-time bindings in multiple clones
16877
- // of transcluded templates.
16878
- interpolateFn = $interpolate(text);
16879
16916
  bindings.push(interpolateFn);
16880
16917
  parent.data('$binding', bindings);
16881
16918
  if (!hasCompileParent) safeAddClass(parent, 'ng-binding');
@@ -17317,11 +17354,7 @@ function parseHeaders(headers) {
17317
17354
  val = trim(line.substr(i + 1));
17318
17355
 
17319
17356
  if (key) {
17320
- if (parsed[key]) {
17321
- parsed[key] += ', ' + val;
17322
- } else {
17323
- parsed[key] = val;
17324
- }
17357
+ parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
17325
17358
  }
17326
17359
  });
17327
17360
 
@@ -18086,7 +18119,7 @@ function $HttpProvider() {
18086
18119
  * Shortcut method to perform `JSONP` request.
18087
18120
  *
18088
18121
  * @param {string} url Relative or absolute URL specifying the destination of the request.
18089
- * Should contain `JSON_CALLBACK` string.
18122
+ * The name of the callback should be the string `JSON_CALLBACK`.
18090
18123
  * @param {Object=} config Optional configuration object
18091
18124
  * @returns {HttpPromise} Future object
18092
18125
  */
@@ -18120,8 +18153,7 @@ function $HttpProvider() {
18120
18153
 
18121
18154
  /**
18122
18155
  * @ngdoc method
18123
- * @name ng.$http#patch
18124
- * @methodOf ng.$http
18156
+ * @name $http#patch
18125
18157
  *
18126
18158
  * @description
18127
18159
  * Shortcut method to perform `PATCH` request.
@@ -18200,7 +18232,7 @@ function $HttpProvider() {
18200
18232
  if (cache) {
18201
18233
  cachedResp = cache.get(url);
18202
18234
  if (isDefined(cachedResp)) {
18203
- if (cachedResp.then) {
18235
+ if (isPromiseLike(cachedResp)) {
18204
18236
  // cached request has already been sent, but there is no response yet
18205
18237
  cachedResp.then(removePendingReq, removePendingReq);
18206
18238
  return cachedResp;
@@ -18282,27 +18314,29 @@ function $HttpProvider() {
18282
18314
 
18283
18315
 
18284
18316
  function buildUrl(url, params) {
18285
- if (!params) return url;
18286
- var parts = [];
18287
- forEachSorted(params, function(value, key) {
18288
- if (value === null || isUndefined(value)) return;
18289
- if (!isArray(value)) value = [value];
18290
-
18291
- forEach(value, function(v) {
18292
- if (isObject(v)) {
18293
- v = toJson(v);
18294
- }
18295
- parts.push(encodeUriQuery(key) + '=' +
18296
- encodeUriQuery(v));
18297
- });
18298
- });
18299
- if(parts.length > 0) {
18300
- url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
18317
+ if (!params) return url;
18318
+ var parts = [];
18319
+ forEachSorted(params, function(value, key) {
18320
+ if (value === null || isUndefined(value)) return;
18321
+ if (!isArray(value)) value = [value];
18322
+
18323
+ forEach(value, function(v) {
18324
+ if (isObject(v)) {
18325
+ if (isDate(v)){
18326
+ v = v.toISOString();
18327
+ } else if (isObject(v)) {
18328
+ v = toJson(v);
18329
+ }
18301
18330
  }
18302
- return url;
18303
- }
18304
-
18305
-
18331
+ parts.push(encodeUriQuery(key) + '=' +
18332
+ encodeUriQuery(v));
18333
+ });
18334
+ });
18335
+ if(parts.length > 0) {
18336
+ url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
18337
+ }
18338
+ return url;
18339
+ }
18306
18340
  }];
18307
18341
  }
18308
18342
 
@@ -18438,7 +18472,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
18438
18472
 
18439
18473
  if (timeout > 0) {
18440
18474
  var timeoutId = $browserDefer(timeoutRequest, timeout);
18441
- } else if (timeout && timeout.then) {
18475
+ } else if (isPromiseLike(timeout)) {
18442
18476
  timeout.then(timeoutRequest);
18443
18477
  }
18444
18478
 
@@ -18632,9 +18666,9 @@ function $InterpolateProvider() {
18632
18666
  *
18633
18667
  * // "allOrNothing" mode
18634
18668
  * exp = $interpolate('{{greeting}} {{name}}!', false, null, true);
18635
- * expect(exp(context, true)).toBeUndefined();
18669
+ * expect(exp(context)).toBeUndefined();
18636
18670
  * context.name = 'Angular';
18637
- * expect(exp(context, true)).toEqual('Hello Angular!');
18671
+ * expect(exp(context)).toEqual('Hello Angular!');
18638
18672
  * ```
18639
18673
  *
18640
18674
  * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
@@ -18702,8 +18736,7 @@ function $InterpolateProvider() {
18702
18736
  hasInterpolation = false,
18703
18737
  hasText = false,
18704
18738
  exp,
18705
- concat = [],
18706
- lastValuesCache = { values: {}, results: {}};
18739
+ concat = [];
18707
18740
 
18708
18741
  while(index < textLength) {
18709
18742
  if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
@@ -18712,7 +18745,7 @@ function $InterpolateProvider() {
18712
18745
  separators.push(text.substring(index, startIndex));
18713
18746
  exp = text.substring(startIndex + startSymbolLength, endIndex);
18714
18747
  expressions.push(exp);
18715
- parseFns.push($parse(exp));
18748
+ parseFns.push($parse(exp, parseStringifyInterceptor));
18716
18749
  index = endIndex + endSymbolLength;
18717
18750
  hasInterpolation = true;
18718
18751
  } else {
@@ -18753,6 +18786,7 @@ function $InterpolateProvider() {
18753
18786
 
18754
18787
  var compute = function(values) {
18755
18788
  for(var i = 0, ii = expressions.length; i < ii; i++) {
18789
+ if (allOrNothing && isUndefined(values[i])) return;
18756
18790
  concat[2*i] = separators[i];
18757
18791
  concat[(2*i)+1] = values[i];
18758
18792
  }
@@ -18761,13 +18795,9 @@ function $InterpolateProvider() {
18761
18795
  };
18762
18796
 
18763
18797
  var getValue = function (value) {
18764
- if (trustedContext) {
18765
- value = $sce.getTrusted(trustedContext, value);
18766
- } else {
18767
- value = $sce.valueOf(value);
18768
- }
18769
-
18770
- return value;
18798
+ return trustedContext ?
18799
+ $sce.getTrusted(trustedContext, value) :
18800
+ $sce.valueOf(value);
18771
18801
  };
18772
18802
 
18773
18803
  var stringify = function (value) {
@@ -18791,64 +18821,49 @@ function $InterpolateProvider() {
18791
18821
  };
18792
18822
 
18793
18823
  return extend(function interpolationFn(context) {
18794
- var scopeId = (context && context.$id) || 'notAScope';
18795
- var lastValues = lastValuesCache.values[scopeId];
18796
- var lastResult = lastValuesCache.results[scopeId];
18797
18824
  var i = 0;
18798
18825
  var ii = expressions.length;
18799
18826
  var values = new Array(ii);
18800
- var val;
18801
- var inputsChanged = lastResult === undefined ? true: false;
18802
-
18803
-
18804
- // if we haven't seen this context before, initialize the cache and try to setup
18805
- // a cleanup routine that purges the cache when the scope goes away.
18806
- if (!lastValues) {
18807
- lastValues = [];
18808
- inputsChanged = true;
18809
- if (context && context.$on) {
18810
- context.$on('$destroy', function() {
18811
- lastValuesCache.values[scopeId] = null;
18812
- lastValuesCache.results[scopeId] = null;
18813
- });
18814
- }
18815
- }
18816
-
18817
18827
 
18818
18828
  try {
18819
- interpolationFn.$$unwatch = true;
18820
18829
  for (; i < ii; i++) {
18821
- val = getValue(parseFns[i](context));
18822
- if (allOrNothing && isUndefined(val)) {
18823
- interpolationFn.$$unwatch = undefined;
18824
- return;
18825
- }
18826
- val = stringify(val);
18827
- if (val !== lastValues[i]) {
18828
- inputsChanged = true;
18829
- }
18830
- values[i] = val;
18831
- interpolationFn.$$unwatch = interpolationFn.$$unwatch && parseFns[i].$$unwatch;
18830
+ values[i] = parseFns[i](context);
18832
18831
  }
18833
18832
 
18834
- if (inputsChanged) {
18835
- lastValuesCache.values[scopeId] = values;
18836
- lastValuesCache.results[scopeId] = lastResult = compute(values);
18837
- }
18833
+ return compute(values);
18838
18834
  } catch(err) {
18839
18835
  var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
18840
18836
  err.toString());
18841
18837
  $exceptionHandler(newErr);
18842
18838
  }
18843
18839
 
18844
- return lastResult;
18845
18840
  }, {
18846
18841
  // all of these properties are undocumented for now
18847
18842
  exp: text, //just for compatibility with regular watchers created via $watch
18848
18843
  separators: separators,
18849
- expressions: expressions
18844
+ expressions: expressions,
18845
+ $$watchDelegate: function (scope, listener, objectEquality, deregisterNotifier) {
18846
+ var lastValue;
18847
+ return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) {
18848
+ var currValue = compute(values);
18849
+ if (isFunction(listener)) {
18850
+ listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);
18851
+ }
18852
+ lastValue = currValue;
18853
+ }, objectEquality, deregisterNotifier);
18854
+ }
18850
18855
  });
18851
18856
  }
18857
+
18858
+ function parseStringifyInterceptor(value) {
18859
+ try {
18860
+ return stringify(getValue(value));
18861
+ } catch(err) {
18862
+ var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
18863
+ err.toString());
18864
+ $exceptionHandler(newErr);
18865
+ }
18866
+ }
18852
18867
  }
18853
18868
 
18854
18869
 
@@ -18969,7 +18984,7 @@ function $IntervalProvider() {
18969
18984
  * // Make sure that the interval nis destroyed too
18970
18985
  * $scope.stopFight();
18971
18986
  * });
18972
- * })
18987
+ * }])
18973
18988
  * // Register the 'myCurrentTime' directive factory method.
18974
18989
  * // We inject $interval and dateFilter service since the factory method is DI.
18975
18990
  * .directive('myCurrentTime', ['$interval', 'dateFilter',
@@ -18998,7 +19013,7 @@ function $IntervalProvider() {
18998
19013
  * $interval.cancel(stopTime);
18999
19014
  * });
19000
19015
  * }
19001
- * });
19016
+ * }]);
19002
19017
  * </script>
19003
19018
  *
19004
19019
  * <div>
@@ -20414,11 +20429,7 @@ Lexer.prototype = {
20414
20429
  string += String.fromCharCode(parseInt(hex, 16));
20415
20430
  } else {
20416
20431
  var rep = ESCAPE[ch];
20417
- if (rep) {
20418
- string += rep;
20419
- } else {
20420
- string += ch;
20421
- }
20432
+ string = string + (rep || ch);
20422
20433
  }
20423
20434
  escape = false;
20424
20435
  } else if (ch === '\\') {
@@ -20979,7 +20990,7 @@ function getterFn(path, options, fullExp) {
20979
20990
  // we simply dereference 's' on any .dot notation
20980
20991
  ? 's'
20981
20992
  // but if we are first then we check locals first, and if so read it first
20982
- : '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n';
20993
+ : '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '.' + key + ';\n';
20983
20994
  });
20984
20995
  code += 'return s;';
20985
20996
 
@@ -21061,69 +21072,89 @@ function $ParseProvider() {
21061
21072
  this.$get = ['$filter', '$sniffer', function($filter, $sniffer) {
21062
21073
  $parseOptions.csp = $sniffer.csp;
21063
21074
 
21064
- return function(exp) {
21065
- var parsedExpression,
21066
- oneTime;
21075
+ return function(exp, interceptorFn) {
21076
+ var parsedExpression, oneTime,
21077
+ cacheKey = (exp = trim(exp));
21067
21078
 
21068
21079
  switch (typeof exp) {
21069
21080
  case 'string':
21081
+ if (cache.hasOwnProperty(cacheKey)) {
21082
+ parsedExpression = cache[cacheKey];
21083
+ } else {
21084
+ if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
21085
+ oneTime = true;
21086
+ exp = exp.substring(2);
21087
+ }
21070
21088
 
21071
- exp = trim(exp);
21072
-
21073
- if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
21074
- oneTime = true;
21075
- exp = exp.substring(2);
21076
- }
21077
-
21078
- if (cache.hasOwnProperty(exp)) {
21079
- return oneTime ? oneTimeWrapper(cache[exp]) : cache[exp];
21080
- }
21089
+ var lexer = new Lexer($parseOptions);
21090
+ var parser = new Parser(lexer, $filter, $parseOptions);
21091
+ parsedExpression = parser.parse(exp);
21081
21092
 
21082
- var lexer = new Lexer($parseOptions);
21083
- var parser = new Parser(lexer, $filter, $parseOptions);
21084
- parsedExpression = parser.parse(exp);
21093
+ if (parsedExpression.constant) parsedExpression.$$watchDelegate = constantWatch;
21094
+ else if (oneTime) parsedExpression.$$watchDelegate = oneTimeWatch;
21085
21095
 
21086
- if (exp !== 'hasOwnProperty') {
21087
- // Only cache the value if it's not going to mess up the cache object
21088
- // This is more performant that using Object.prototype.hasOwnProperty.call
21089
- cache[exp] = parsedExpression;
21096
+ if (cacheKey !== 'hasOwnProperty') {
21097
+ // Only cache the value if it's not going to mess up the cache object
21098
+ // This is more performant that using Object.prototype.hasOwnProperty.call
21099
+ cache[cacheKey] = parsedExpression;
21100
+ }
21090
21101
  }
21091
-
21092
- return oneTime || parsedExpression.constant ? oneTimeWrapper(parsedExpression) : parsedExpression;
21102
+ return addInterceptor(parsedExpression, interceptorFn);
21093
21103
 
21094
21104
  case 'function':
21095
- return exp;
21105
+ return addInterceptor(exp, interceptorFn);
21096
21106
 
21097
21107
  default:
21098
- return noop;
21099
- }
21100
-
21101
- function oneTimeWrapper(expression) {
21102
- var stable = false,
21103
- lastValue;
21104
- oneTimeParseFn.literal = expression.literal;
21105
- oneTimeParseFn.constant = expression.constant;
21106
- oneTimeParseFn.assign = expression.assign;
21107
- return oneTimeParseFn;
21108
-
21109
- function oneTimeParseFn(self, locals) {
21110
- if (!stable) {
21111
- lastValue = expression.constant && lastValue ? lastValue : expression(self, locals);
21112
- oneTimeParseFn.$$unwatch = isDefined(lastValue);
21113
- if (oneTimeParseFn.$$unwatch && self && self.$$postDigestQueue) {
21114
- self.$$postDigestQueue.push(function () {
21115
- // create a copy if the value is defined and it is not a $sce value
21116
- if ((stable = isDefined(lastValue)) &&
21117
- (lastValue === null || !lastValue.$$unwrapTrustedValue)) {
21118
- lastValue = copy(lastValue, null);
21119
- }
21120
- });
21108
+ return addInterceptor(noop, interceptorFn);
21109
+ }
21110
+ };
21111
+
21112
+ function oneTimeWatch(scope, listener, objectEquality, deregisterNotifier, parsedExpression) {
21113
+ var unwatch, lastValue;
21114
+ return unwatch = scope.$watch(function oneTimeWatch(scope) {
21115
+ return parsedExpression(scope);
21116
+ }, function oneTimeListener(value, old, scope) {
21117
+ lastValue = value;
21118
+ if (isFunction(listener)) {
21119
+ listener.apply(this, arguments);
21120
+ }
21121
+ if (isDefined(value)) {
21122
+ scope.$$postDigest(function () {
21123
+ if (isDefined(lastValue)) {
21124
+ unwatch();
21121
21125
  }
21122
- }
21123
- return lastValue;
21126
+ });
21127
+ }
21128
+ }, objectEquality, deregisterNotifier);
21129
+ }
21130
+
21131
+ function constantWatch(scope, listener, objectEquality, deregisterNotifier, parsedExpression) {
21132
+ var unwatch;
21133
+ return unwatch = scope.$watch(function constantWatch(scope) {
21134
+ return parsedExpression(scope);
21135
+ }, function constantListener(value, old, scope) {
21136
+ if (isFunction(listener)) {
21137
+ listener.apply(this, arguments);
21124
21138
  }
21139
+ unwatch();
21140
+ }, objectEquality, deregisterNotifier);
21141
+ }
21142
+
21143
+ function addInterceptor(parsedExpression, interceptorFn) {
21144
+ if (isFunction(interceptorFn)) {
21145
+ var fn = function interceptedExpression(scope, locals) {
21146
+ var value = parsedExpression(scope, locals);
21147
+ var result = interceptorFn(value, scope, locals);
21148
+ // we only return the interceptor's result if the
21149
+ // initial value is defined (for bind-once)
21150
+ return isDefined(value) ? result : value;
21151
+ };
21152
+ fn.$$watchDelegate = parsedExpression.$$watchDelegate;
21153
+ return fn;
21154
+ } else {
21155
+ return parsedExpression;
21125
21156
  }
21126
- };
21157
+ }
21127
21158
  }];
21128
21159
  }
21129
21160
 
@@ -21135,6 +21166,46 @@ function $ParseProvider() {
21135
21166
  * @description
21136
21167
  * A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
21137
21168
  *
21169
+ * $q can be used in two fashions --- One, which is more similar to Kris Kowal's Q or jQuery's Deferred
21170
+ * implementations, the other resembles ES6 promises to some degree.
21171
+ *
21172
+ * # $q constructor
21173
+ *
21174
+ * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`
21175
+ * function as the first argument). This is similar to the native Promise implementation from ES6 Harmony,
21176
+ * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
21177
+ *
21178
+ * While the constructor-style use is supported, not all of the supporting methods from Harmony promises are
21179
+ * available yet.
21180
+ *
21181
+ * It can be used like so:
21182
+ *
21183
+ * ```js
21184
+ * return $q(function(resolve, reject) {
21185
+ * // perform some asynchronous operation, resolve or reject the promise when appropriate.
21186
+ * setInterval(function() {
21187
+ * if (pollStatus > 0) {
21188
+ * resolve(polledValue);
21189
+ * } else if (pollStatus < 0) {
21190
+ * reject(polledValue);
21191
+ * } else {
21192
+ * pollStatus = pollAgain(function(value) {
21193
+ * polledValue = value;
21194
+ * });
21195
+ * }
21196
+ * }, 10000);
21197
+ * }).
21198
+ * then(function(value) {
21199
+ * // handle success
21200
+ * }, function(reason) {
21201
+ * // handle failure
21202
+ * });
21203
+ * ```
21204
+ *
21205
+ * Note, progress/notify callbacks are not currently supported via the ES6-style interface.
21206
+ *
21207
+ * However, the more traditional CommonJS style usage is still available, and documented below.
21208
+ *
21138
21209
  * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
21139
21210
  * interface for interacting with an object that represents the result of an action that is
21140
21211
  * performed asynchronously, and may or may not be finished at any given point in time.
@@ -21181,7 +21252,6 @@ function $ParseProvider() {
21181
21252
  * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
21182
21253
  * section on serial or parallel joining of promises.
21183
21254
  *
21184
- *
21185
21255
  * # The Deferred API
21186
21256
  *
21187
21257
  * A new instance of deferred is constructed by calling `$q.defer()`.
@@ -21290,6 +21360,12 @@ function $ParseProvider() {
21290
21360
  * expect(resolvedValue).toEqual(123);
21291
21361
  * }));
21292
21362
  * ```
21363
+ *
21364
+ * @param {function(function, function)} resolver Function which is responsible for resolving or
21365
+ * rejecting the newly created promise. The first parameteter is a function which resolves the
21366
+ * promise, the second parameter is a function which rejects the promise.
21367
+ *
21368
+ * @returns {Promise} The newly created promise.
21293
21369
  */
21294
21370
  function $QProvider() {
21295
21371
 
@@ -21437,7 +21513,7 @@ function qFactory(nextTick, exceptionHandler) {
21437
21513
  } catch(e) {
21438
21514
  return makePromise(e, false);
21439
21515
  }
21440
- if (callbackOutput && isFunction(callbackOutput.then)) {
21516
+ if (isPromiseLike(callbackOutput)) {
21441
21517
  return callbackOutput.then(function() {
21442
21518
  return makePromise(value, isResolved);
21443
21519
  }, function(error) {
@@ -21462,7 +21538,7 @@ function qFactory(nextTick, exceptionHandler) {
21462
21538
 
21463
21539
 
21464
21540
  var ref = function(value) {
21465
- if (value && isFunction(value.then)) return value;
21541
+ if (isPromiseLike(value)) return value;
21466
21542
  return {
21467
21543
  then: function(callback) {
21468
21544
  var result = defer();
@@ -21646,12 +21722,38 @@ function qFactory(nextTick, exceptionHandler) {
21646
21722
  return deferred.promise;
21647
21723
  }
21648
21724
 
21649
- return {
21650
- defer: defer,
21651
- reject: reject,
21652
- when: when,
21653
- all: all
21725
+ var $Q = function Q(resolver) {
21726
+ if (!isFunction(resolver)) {
21727
+ // TODO(@caitp): minErr this
21728
+ throw new TypeError('Expected resolverFn');
21729
+ }
21730
+
21731
+ if (!(this instanceof Q)) {
21732
+ // More useful when $Q is the Promise itself.
21733
+ return new Q(resolver);
21734
+ }
21735
+
21736
+ var deferred = defer();
21737
+
21738
+ function resolveFn(value) {
21739
+ deferred.resolve(value);
21740
+ }
21741
+
21742
+ function rejectFn(reason) {
21743
+ deferred.reject(reason);
21744
+ }
21745
+
21746
+ resolver(resolveFn, rejectFn);
21747
+
21748
+ return deferred.promise;
21654
21749
  };
21750
+
21751
+ $Q.defer = defer;
21752
+ $Q.reject = reject;
21753
+ $Q.when = when;
21754
+ $Q.all = all;
21755
+
21756
+ return $Q;
21655
21757
  }
21656
21758
 
21657
21759
  function $$RAFProvider(){ //rAF
@@ -22001,20 +22103,25 @@ function $RootScopeProvider(){
22001
22103
  *
22002
22104
  * - `string`: Evaluated as {@link guide/expression expression}
22003
22105
  * - `function(scope)`: called with current `scope` as a parameter.
22004
- * @param {(function()|string)=} listener Callback called whenever the return value of
22005
- * the `watchExpression` changes.
22006
- *
22007
- * - `string`: Evaluated as {@link guide/expression expression}
22008
- * - `function(newValue, oldValue, scope)`: called with current and previous values as
22009
- * parameters.
22106
+ * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value
22107
+ * of `watchExpression` changes.
22010
22108
  *
22109
+ * - `newVal` contains the current value of the `watchExpression`
22110
+ * - `oldVal` contains the previous value of the `watchExpression`
22111
+ * - `scope` refers to the current scope
22011
22112
  * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
22012
22113
  * comparing for reference equality.
22114
+ * @param {function()=} deregisterNotifier Function to call when the deregistration function
22115
+ * get called.
22013
22116
  * @returns {function()} Returns a deregistration function for this listener.
22014
22117
  */
22015
- $watch: function(watchExp, listener, objectEquality) {
22118
+ $watch: function(watchExp, listener, objectEquality, deregisterNotifier) {
22119
+ var get = compileToFn(watchExp, 'watch');
22120
+
22121
+ if (get.$$watchDelegate) {
22122
+ return get.$$watchDelegate(this, listener, objectEquality, deregisterNotifier, get);
22123
+ }
22016
22124
  var scope = this,
22017
- get = compileToFn(watchExp, 'watch'),
22018
22125
  array = scope.$$watchers,
22019
22126
  watcher = {
22020
22127
  fn: listener,
@@ -22026,10 +22133,8 @@ function $RootScopeProvider(){
22026
22133
 
22027
22134
  lastDirtyWatch = null;
22028
22135
 
22029
- // in the case user pass string, we need to compile it, do we really need this ?
22030
22136
  if (!isFunction(listener)) {
22031
- var listenFn = compileToFn(listener || noop, 'listener');
22032
- watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);};
22137
+ watcher.fn = noop;
22033
22138
  }
22034
22139
 
22035
22140
  if (!array) {
@@ -22042,6 +22147,9 @@ function $RootScopeProvider(){
22042
22147
  return function deregisterWatch() {
22043
22148
  arrayRemove(array, watcher);
22044
22149
  lastDirtyWatch = null;
22150
+ if (isFunction(deregisterNotifier)) {
22151
+ deregisterNotifier();
22152
+ }
22045
22153
  };
22046
22154
  },
22047
22155
 
@@ -22068,7 +22176,6 @@ function $RootScopeProvider(){
22068
22176
  * and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching
22069
22177
  * those of `watchExpression`
22070
22178
  * The `scope` refers to the current scope.
22071
- *
22072
22179
  * @returns {function()} Returns a de-registration function for all listeners.
22073
22180
  */
22074
22181
  $watchGroup: function(watchExpressions, listener) {
@@ -22077,37 +22184,43 @@ function $RootScopeProvider(){
22077
22184
  var deregisterFns = [];
22078
22185
  var changeCount = 0;
22079
22186
  var self = this;
22080
- var unwatchFlags = new Array(watchExpressions.length);
22081
- var unwatchCount = watchExpressions.length;
22187
+ var masterUnwatch;
22188
+
22189
+ if (watchExpressions.length === 1) {
22190
+ // Special case size of one
22191
+ return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) {
22192
+ newValues[0] = value;
22193
+ oldValues[0] = oldValue;
22194
+ listener.call(this, newValues, (value === oldValue) ? newValues : oldValues, scope);
22195
+ });
22196
+ }
22082
22197
 
22083
22198
  forEach(watchExpressions, function (expr, i) {
22084
- var exprFn = $parse(expr);
22085
- deregisterFns.push(self.$watch(exprFn, function (value, oldValue) {
22199
+ var unwatch = self.$watch(expr, function watchGroupSubAction(value, oldValue) {
22086
22200
  newValues[i] = value;
22087
22201
  oldValues[i] = oldValue;
22088
22202
  changeCount++;
22089
- if (unwatchFlags[i] && !exprFn.$$unwatch) unwatchCount++;
22090
- if (!unwatchFlags[i] && exprFn.$$unwatch) unwatchCount--;
22091
- unwatchFlags[i] = exprFn.$$unwatch;
22092
- }));
22203
+ }, false, function watchGroupDeregNotifier() {
22204
+ arrayRemove(deregisterFns, unwatch);
22205
+ if (!deregisterFns.length) {
22206
+ masterUnwatch();
22207
+ }
22208
+ });
22209
+
22210
+ deregisterFns.push(unwatch);
22093
22211
  }, this);
22094
22212
 
22095
- deregisterFns.push(self.$watch(watchGroupFn, function () {
22096
- listener(newValues, oldValues, self);
22097
- if (unwatchCount === 0) {
22098
- watchGroupFn.$$unwatch = true;
22099
- } else {
22100
- watchGroupFn.$$unwatch = false;
22101
- }
22102
- }));
22213
+ masterUnwatch = self.$watch(function watchGroupChangeWatch() {
22214
+ return changeCount;
22215
+ }, function watchGroupChangeAction(value, oldValue) {
22216
+ listener(newValues, (value === oldValue) ? newValues : oldValues, self);
22217
+ });
22103
22218
 
22104
22219
  return function deregisterWatchGroup() {
22105
- forEach(deregisterFns, function (fn) {
22106
- fn();
22107
- });
22220
+ while (deregisterFns.length) {
22221
+ deregisterFns[0]();
22222
+ }
22108
22223
  };
22109
-
22110
- function watchGroupFn() {return changeCount;}
22111
22224
  },
22112
22225
 
22113
22226
 
@@ -22178,15 +22291,15 @@ function $RootScopeProvider(){
22178
22291
  // only track veryOldValue if the listener is asking for it
22179
22292
  var trackVeryOldValue = (listener.length > 1);
22180
22293
  var changeDetected = 0;
22181
- var objGetter = $parse(obj);
22294
+ var changeDetector = $parse(obj, $watchCollectionInterceptor);
22182
22295
  var internalArray = [];
22183
22296
  var internalObject = {};
22184
22297
  var initRun = true;
22185
22298
  var oldLength = 0;
22186
22299
 
22187
- function $watchCollectionWatch() {
22188
- newValue = objGetter(self);
22189
- var newLength, key;
22300
+ function $watchCollectionInterceptor(_value) {
22301
+ newValue = _value;
22302
+ var newLength, key, bothNaN;
22190
22303
 
22191
22304
  if (!isObject(newValue)) { // if primitive
22192
22305
  if (oldValue !== newValue) {
@@ -22210,7 +22323,7 @@ function $RootScopeProvider(){
22210
22323
  }
22211
22324
  // copy the items to oldValue and look for changes.
22212
22325
  for (var i = 0; i < newLength; i++) {
22213
- var bothNaN = (oldValue[i] !== oldValue[i]) &&
22326
+ bothNaN = (oldValue[i] !== oldValue[i]) &&
22214
22327
  (newValue[i] !== newValue[i]);
22215
22328
  if (!bothNaN && (oldValue[i] !== newValue[i])) {
22216
22329
  changeDetected++;
@@ -22230,7 +22343,9 @@ function $RootScopeProvider(){
22230
22343
  if (newValue.hasOwnProperty(key)) {
22231
22344
  newLength++;
22232
22345
  if (oldValue.hasOwnProperty(key)) {
22233
- if (oldValue[key] !== newValue[key]) {
22346
+ bothNaN = (oldValue[key] !== oldValue[key]) &&
22347
+ (newValue[key] !== newValue[key]);
22348
+ if (!bothNaN && (oldValue[key] !== newValue[key])) {
22234
22349
  changeDetected++;
22235
22350
  oldValue[key] = newValue[key];
22236
22351
  }
@@ -22252,7 +22367,6 @@ function $RootScopeProvider(){
22252
22367
  }
22253
22368
  }
22254
22369
  }
22255
- $watchCollectionWatch.$$unwatch = objGetter.$$unwatch;
22256
22370
  return changeDetected;
22257
22371
  }
22258
22372
 
@@ -22285,7 +22399,7 @@ function $RootScopeProvider(){
22285
22399
  }
22286
22400
  }
22287
22401
 
22288
- return this.$watch($watchCollectionWatch, $watchCollectionAction);
22402
+ return this.$watch(changeDetector, $watchCollectionAction);
22289
22403
  },
22290
22404
 
22291
22405
  /**
@@ -22348,7 +22462,6 @@ function $RootScopeProvider(){
22348
22462
  dirty, ttl = TTL,
22349
22463
  next, current, target = this,
22350
22464
  watchLog = [],
22351
- stableWatchesCandidates = [],
22352
22465
  logIdx, logMsg, asyncTask;
22353
22466
 
22354
22467
  beginPhase('$digest');
@@ -22399,7 +22512,6 @@ function $RootScopeProvider(){
22399
22512
  logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
22400
22513
  watchLog[logIdx].push(logMsg);
22401
22514
  }
22402
- if (watch.get.$$unwatch) stableWatchesCandidates.push({watch: watch, array: watchers});
22403
22515
  } else if (watch === lastDirtyWatch) {
22404
22516
  // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
22405
22517
  // have already been tested.
@@ -22446,13 +22558,6 @@ function $RootScopeProvider(){
22446
22558
  $exceptionHandler(e);
22447
22559
  }
22448
22560
  }
22449
-
22450
- for (length = stableWatchesCandidates.length - 1; length >= 0; --length) {
22451
- var candidate = stableWatchesCandidates[length];
22452
- if (candidate.watch.get.$$unwatch) {
22453
- arrayRemove(candidate.array, candidate.watch);
22454
- }
22455
- }
22456
22561
  },
22457
22562
 
22458
22563
 
@@ -23767,11 +23872,9 @@ function $SceProvider() {
23767
23872
  if (parsed.literal && parsed.constant) {
23768
23873
  return parsed;
23769
23874
  } else {
23770
- return function sceParseAsTrusted(self, locals) {
23771
- var result = sce.getTrusted(type, parsed(self, locals));
23772
- sceParseAsTrusted.$$unwatch = parsed.$$unwatch;
23773
- return result;
23774
- };
23875
+ return $parse(expr, function (value) {
23876
+ return sce.getTrusted(type, value);
23877
+ });
23775
23878
  }
23776
23879
  };
23777
23880
 
@@ -25164,11 +25267,7 @@ function dateFilter($locale) {
25164
25267
  format = format || 'mediumDate';
25165
25268
  format = $locale.DATETIME_FORMATS[format] || format;
25166
25269
  if (isString(date)) {
25167
- if (NUMBER_STRING.test(date)) {
25168
- date = int(date);
25169
- } else {
25170
- date = jsonStringToDate(date);
25171
- }
25270
+ date = NUMBER_STRING.test(date) ? int(date) : jsonStringToDate(date);
25172
25271
  }
25173
25272
 
25174
25273
  if (isNumber(date)) {
@@ -25443,7 +25542,7 @@ function limitToFilter(){
25443
25542
  * @example
25444
25543
  <example module="orderByExample">
25445
25544
  <file name="index.html">
25446
- <div ng-controller="Ctrl">
25545
+ <div ng-controller="ExampleController">
25447
25546
  <table class="friend">
25448
25547
  <tr>
25449
25548
  <th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
@@ -25524,6 +25623,10 @@ function orderByFilter($parse){
25524
25623
  var t1 = typeof v1;
25525
25624
  var t2 = typeof v2;
25526
25625
  if (t1 == t2) {
25626
+ if (isDate(v1) && isDate(v2)) {
25627
+ v1 = v1.valueOf();
25628
+ v2 = v2.valueOf();
25629
+ }
25527
25630
  if (t1 == "string") {
25528
25631
  v1 = v1.toLowerCase();
25529
25632
  v2 = v2.toLowerCase();
@@ -25946,6 +26049,7 @@ forEach(BOOLEAN_ATTR, function(propName, attrName) {
25946
26049
  var normalized = directiveNormalize('ng-' + attrName);
25947
26050
  ngAttributeAliasDirectives[normalized] = function() {
25948
26051
  return {
26052
+ restrict: 'A',
25949
26053
  priority: 100,
25950
26054
  link: function(scope, element, attr) {
25951
26055
  scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
@@ -25998,8 +26102,12 @@ forEach(['src', 'srcset', 'href'], function(attrName) {
25998
26102
  }
25999
26103
 
26000
26104
  attr.$observe(normalized, function(value) {
26001
- if (!value)
26002
- return;
26105
+ if (!value) {
26106
+ if (attrName === 'href') {
26107
+ attr.$set(name, null);
26108
+ }
26109
+ return;
26110
+ }
26003
26111
 
26004
26112
  attr.$set(name, value);
26005
26113
 
@@ -26587,7 +26695,9 @@ var inputType = {
26587
26695
  * @description
26588
26696
  * Input with date validation and transformation. In browsers that do not yet support
26589
26697
  * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601
26590
- * date format (yyyy-MM-dd), for example: `2009-01-06`. The model must always be a Date object.
26698
+ * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many
26699
+ * modern browsers do not yet support this input type, it is important to provide cues to users on the
26700
+ * expected input format via a placeholder or label. The model must always be a Date object.
26591
26701
  *
26592
26702
  * @param {string} ngModel Assignable angular expression to data-bind to.
26593
26703
  * @param {string=} name Property name of the form under which the control is published.
@@ -28630,6 +28740,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
28630
28740
  */
28631
28741
  var ngModelDirective = function() {
28632
28742
  return {
28743
+ restrict: 'A',
28633
28744
  require: ['ngModel', '^?form', '^?ngModelOptions'],
28634
28745
  controller: NgModelController,
28635
28746
  link: {
@@ -28731,6 +28842,7 @@ var ngModelDirective = function() {
28731
28842
  * </example>
28732
28843
  */
28733
28844
  var ngChangeDirective = valueFn({
28845
+ restrict: 'A',
28734
28846
  require: 'ngModel',
28735
28847
  link: function(scope, element, attr, ctrl) {
28736
28848
  ctrl.$viewChangeListeners.push(function() {
@@ -28742,6 +28854,7 @@ var ngChangeDirective = valueFn({
28742
28854
 
28743
28855
  var requiredDirective = function() {
28744
28856
  return {
28857
+ restrict: 'A',
28745
28858
  require: '?ngModel',
28746
28859
  link: function(scope, elm, attr, ctrl) {
28747
28860
  if (!ctrl) return;
@@ -28761,6 +28874,7 @@ var requiredDirective = function() {
28761
28874
 
28762
28875
  var patternDirective = function() {
28763
28876
  return {
28877
+ restrict: 'A',
28764
28878
  require: '?ngModel',
28765
28879
  link: function(scope, elm, attr, ctrl) {
28766
28880
  if (!ctrl) return;
@@ -28791,6 +28905,7 @@ var patternDirective = function() {
28791
28905
 
28792
28906
  var maxlengthDirective = function() {
28793
28907
  return {
28908
+ restrict: 'A',
28794
28909
  require: '?ngModel',
28795
28910
  link: function(scope, elm, attr, ctrl) {
28796
28911
  if (!ctrl) return;
@@ -28809,6 +28924,7 @@ var maxlengthDirective = function() {
28809
28924
 
28810
28925
  var minlengthDirective = function() {
28811
28926
  return {
28927
+ restrict: 'A',
28812
28928
  require: '?ngModel',
28813
28929
  link: function(scope, elm, attr, ctrl) {
28814
28930
  if (!ctrl) return;
@@ -28831,62 +28947,93 @@ var minlengthDirective = function() {
28831
28947
  * @name ngList
28832
28948
  *
28833
28949
  * @description
28834
- * Text input that converts between a delimited string and an array of strings. The delimiter
28835
- * can be a fixed string (by default a comma) or a regular expression.
28950
+ * Text input that converts between a delimited string and an array of strings. The default
28951
+ * delimiter is a comma followed by a space - equivalent to `ng-list=", "`. You can specify a custom
28952
+ * delimiter as the value of the `ngList` attribute - for example, `ng-list=" | "`.
28953
+ *
28954
+ * The behaviour of the directive is affected by the use of the `ngTrim` attribute.
28955
+ * * If `ngTrim` is set to `"false"` then whitespace around both the separator and each
28956
+ * list item is respected. This implies that the user of the directive is responsible for
28957
+ * dealing with whitespace but also allows you to use whitespace as a delimiter, such as a
28958
+ * tab or newline character.
28959
+ * * Otherwise whitespace around the delimiter is ignored when splitting (although it is respected
28960
+ * when joining the list items back together) and whitespace around each list item is stripped
28961
+ * before it is added to the model.
28962
+ *
28963
+ * ### Example with Validation
28964
+ *
28965
+ * <example name="ngList-directive" module="listExample">
28966
+ * <file name="app.js">
28967
+ * angular.module('listExample', [])
28968
+ * .controller('ExampleController', ['$scope', function($scope) {
28969
+ * $scope.names = ['morpheus', 'neo', 'trinity'];
28970
+ * }]);
28971
+ * </file>
28972
+ * <file name="index.html">
28973
+ * <form name="myForm" ng-controller="ExampleController">
28974
+ * List: <input name="namesInput" ng-model="names" ng-list required>
28975
+ * <span class="error" ng-show="myForm.namesInput.$error.required">
28976
+ * Required!</span>
28977
+ * <br>
28978
+ * <tt>names = {{names}}</tt><br/>
28979
+ * <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
28980
+ * <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
28981
+ * <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
28982
+ * <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
28983
+ * </form>
28984
+ * </file>
28985
+ * <file name="protractor.js" type="protractor">
28986
+ * var listInput = element(by.model('names'));
28987
+ * var names = element(by.binding('{{names}}'));
28988
+ * var valid = element(by.binding('myForm.namesInput.$valid'));
28989
+ * var error = element(by.css('span.error'));
28990
+ *
28991
+ * it('should initialize to model', function() {
28992
+ * expect(names.getText()).toContain('["morpheus","neo","trinity"]');
28993
+ * expect(valid.getText()).toContain('true');
28994
+ * expect(error.getCssValue('display')).toBe('none');
28995
+ * });
28836
28996
  *
28837
- * @element input
28838
- * @param {string=} ngList optional delimiter that should be used to split the value. If
28839
- * specified in form `/something/` then the value will be converted into a regular expression.
28997
+ * it('should be invalid if empty', function() {
28998
+ * listInput.clear();
28999
+ * listInput.sendKeys('');
28840
29000
  *
28841
- * @example
28842
- <example name="ngList-directive" module="listExample">
28843
- <file name="index.html">
28844
- <script>
28845
- angular.module('listExample', [])
28846
- .controller('ExampleController', ['$scope', function($scope) {
28847
- $scope.names = ['igor', 'misko', 'vojta'];
28848
- }]);
28849
- </script>
28850
- <form name="myForm" ng-controller="ExampleController">
28851
- List: <input name="namesInput" ng-model="names" ng-list required>
28852
- <span class="error" ng-show="myForm.namesInput.$error.required">
28853
- Required!</span>
28854
- <br>
28855
- <tt>names = {{names}}</tt><br/>
28856
- <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
28857
- <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
28858
- <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
28859
- <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
28860
- </form>
28861
- </file>
28862
- <file name="protractor.js" type="protractor">
28863
- var listInput = element(by.model('names'));
28864
- var names = element(by.binding('{{names}}'));
28865
- var valid = element(by.binding('myForm.namesInput.$valid'));
28866
- var error = element(by.css('span.error'));
28867
-
28868
- it('should initialize to model', function() {
28869
- expect(names.getText()).toContain('["igor","misko","vojta"]');
28870
- expect(valid.getText()).toContain('true');
28871
- expect(error.getCssValue('display')).toBe('none');
28872
- });
28873
-
28874
- it('should be invalid if empty', function() {
28875
- listInput.clear();
28876
- listInput.sendKeys('');
28877
-
28878
- expect(names.getText()).toContain('');
28879
- expect(valid.getText()).toContain('false');
28880
- expect(error.getCssValue('display')).not.toBe('none'); });
28881
- </file>
28882
- </example>
29001
+ * expect(names.getText()).toContain('');
29002
+ * expect(valid.getText()).toContain('false');
29003
+ * expect(error.getCssValue('display')).not.toBe('none');
29004
+ * });
29005
+ * </file>
29006
+ * </example>
29007
+ *
29008
+ * ### Example - splitting on whitespace
29009
+ * <example name="ngList-directive-newlines">
29010
+ * <file name="index.html">
29011
+ * <textarea ng-model="list" ng-list="&#10;" ng-trim="false"></textarea>
29012
+ * <pre>{{ list | json }}</pre>
29013
+ * </file>
29014
+ * <file name="protractor.js" type="protractor">
29015
+ * it("should split the text by newlines", function() {
29016
+ * var listInput = element(by.model('list'));
29017
+ * var output = element(by.binding('{{ list | json }}'));
29018
+ * listInput.sendKeys('abc\ndef\nghi');
29019
+ * expect(output.getText()).toContain('[\n "abc",\n "def",\n "ghi"\n]');
29020
+ * });
29021
+ * </file>
29022
+ * </example>
29023
+ *
29024
+ * @element input
29025
+ * @param {string=} ngList optional delimiter that should be used to split the value.
28883
29026
  */
28884
29027
  var ngListDirective = function() {
28885
29028
  return {
29029
+ restrict: 'A',
28886
29030
  require: 'ngModel',
28887
29031
  link: function(scope, element, attr, ctrl) {
28888
- var match = /\/(.*)\//.exec(attr.ngList),
28889
- separator = match && new RegExp(match[1]) || attr.ngList || ',';
29032
+ // We want to control whitespace trimming so we use this convoluted approach
29033
+ // to access the ngList attribute, which doesn't pre-trim the attribute
29034
+ var ngList = element.attr(attr.$attr.ngList) || ', ';
29035
+ var trimValues = attr.ngTrim !== 'false';
29036
+ var separator = trimValues ? trim(ngList) : ngList;
28890
29037
 
28891
29038
  var parse = function(viewValue) {
28892
29039
  // If the viewValue is invalid (say required but empty) it will be `undefined`
@@ -28896,7 +29043,7 @@ var ngListDirective = function() {
28896
29043
 
28897
29044
  if (viewValue) {
28898
29045
  forEach(viewValue.split(separator), function(value) {
28899
- if (value) list.push(trim(value));
29046
+ if (value) list.push(trimValues ? trim(value) : value);
28900
29047
  });
28901
29048
  }
28902
29049
 
@@ -28906,7 +29053,7 @@ var ngListDirective = function() {
28906
29053
  ctrl.$parsers.push(parse);
28907
29054
  ctrl.$formatters.push(function(value) {
28908
29055
  if (isArray(value)) {
28909
- return value.join(', ');
29056
+ return value.join(ngList);
28910
29057
  }
28911
29058
 
28912
29059
  return undefined;
@@ -28976,6 +29123,7 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
28976
29123
  */
28977
29124
  var ngValueDirective = function() {
28978
29125
  return {
29126
+ restrict: 'A',
28979
29127
  priority: 100,
28980
29128
  compile: function(tpl, tplAttr) {
28981
29129
  if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
@@ -29138,6 +29286,7 @@ var ngValueDirective = function() {
29138
29286
  */
29139
29287
  var ngModelOptionsDirective = function() {
29140
29288
  return {
29289
+ restrict: 'A',
29141
29290
  controller: ['$scope', '$attrs', function($scope, $attrs) {
29142
29291
  var that = this;
29143
29292
  this.$options = $scope.$eval($attrs.ngModelOptions);
@@ -29169,7 +29318,7 @@ var ngModelOptionsDirective = function() {
29169
29318
  * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
29170
29319
  * `{{ expression }}` which is similar but less verbose.
29171
29320
  *
29172
- * It is preferable to use `ngBind` instead of `{{ expression }}` when a template is momentarily
29321
+ * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
29173
29322
  * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
29174
29323
  * element attribute, it makes the bindings invisible to the user while the page is loading.
29175
29324
  *
@@ -29333,19 +29482,25 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
29333
29482
  </example>
29334
29483
  */
29335
29484
  var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
29336
- return function(scope, element, attr) {
29337
- element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
29485
+ return {
29486
+ restrict: 'A',
29487
+ compile: function (tElement, tAttrs) {
29488
+ tElement.addClass('ng-binding');
29338
29489
 
29339
- var parsed = $parse(attr.ngBindHtml);
29340
- function getStringValue() {
29341
- var value = parsed(scope);
29342
- getStringValue.$$unwatch = parsed.$$unwatch;
29343
- return (value || '').toString();
29344
- }
29490
+ return function (scope, element, attr) {
29491
+ element.data('$binding', attr.ngBindHtml);
29492
+ var parsed = $parse(attr.ngBindHtml);
29493
+ var changeDetector = $parse(attr.ngBindHtml, function getStringValue(value) {
29494
+ return (value || '').toString();
29495
+ });
29345
29496
 
29346
- scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
29347
- element.html($sce.getTrustedHtml(parsed(scope)) || '');
29348
- });
29497
+ scope.$watch(changeDetector, function ngBindHtmlWatchAction() {
29498
+ // we re-evaluate the expr because we want a TrustedValueHolderType
29499
+ // for $sce, not a string
29500
+ element.html($sce.getTrustedHtml(parsed(scope)) || '');
29501
+ });
29502
+ };
29503
+ }
29349
29504
  };
29350
29505
  }];
29351
29506
 
@@ -29991,6 +30146,7 @@ var ngCloakDirective = ngDirective({
29991
30146
  */
29992
30147
  var ngControllerDirective = [function() {
29993
30148
  return {
30149
+ restrict: 'A',
29994
30150
  scope: true,
29995
30151
  controller: '@',
29996
30152
  priority: 500
@@ -30008,8 +30164,10 @@ var ngControllerDirective = [function() {
30008
30164
  * This is necessary when developing things like Google Chrome Extensions.
30009
30165
  *
30010
30166
  * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
30011
- * For us to be compatible, we just need to implement the "getterFn" in $parse without violating
30012
- * any of these restrictions.
30167
+ * For Angular to be CSP compatible there are only two things that we need to do differently:
30168
+ *
30169
+ * - don't use `Function` constructor to generate optimized value getters
30170
+ * - don't inject custom stylesheet into the document
30013
30171
  *
30014
30172
  * AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
30015
30173
  * directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
@@ -30020,7 +30178,18 @@ var ngControllerDirective = [function() {
30020
30178
  * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
30021
30179
  * To make those directives work in CSP mode, include the `angular-csp.css` manually.
30022
30180
  *
30023
- * In order to use this feature put the `ngCsp` directive on the root element of the application.
30181
+ * Angular tries to autodetect if CSP is active and automatically turn on the CSP-safe mode. This
30182
+ * autodetection however triggers a CSP error to be logged in the console:
30183
+ *
30184
+ * ```
30185
+ * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
30186
+ * script in the following Content Security Policy directive: "default-src 'self'". Note that
30187
+ * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
30188
+ * ```
30189
+ *
30190
+ * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
30191
+ * directive on the root element of the application or on the `angular.js` script tag, whichever
30192
+ * appears first in the html document.
30024
30193
  *
30025
30194
  * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
30026
30195
  *
@@ -30035,9 +30204,9 @@ var ngControllerDirective = [function() {
30035
30204
  ```
30036
30205
  */
30037
30206
 
30038
- // ngCsp is not implemented as a proper directive any more, because we need it be processed while we bootstrap
30039
- // the system (before $parse is instantiated), for this reason we just have a csp() fn that looks for ng-csp attribute
30040
- // anywhere in the current doc
30207
+ // ngCsp is not implemented as a proper directive any more, because we need it be processed while we
30208
+ // bootstrap the system (before $parse is instantiated), for this reason we just have
30209
+ // the csp.isActive() fn that looks for ng-csp attribute anywhere in the current doc
30041
30210
 
30042
30211
  /**
30043
30212
  * @ngdoc directive
@@ -30082,6 +30251,7 @@ forEach(
30082
30251
  var directiveName = directiveNormalize('ng-' + name);
30083
30252
  ngEventDirectives[directiveName] = ['$parse', function($parse) {
30084
30253
  return {
30254
+ restrict: 'A',
30085
30255
  compile: function($element, attr) {
30086
30256
  var fn = $parse(attr[directiveName]);
30087
30257
  return function ngEventHandler(scope, element) {
@@ -30564,6 +30734,7 @@ forEach(
30564
30734
  */
30565
30735
  var ngIfDirective = ['$animate', function($animate) {
30566
30736
  return {
30737
+ multiElement: true,
30567
30738
  transclude: 'element',
30568
30739
  priority: 600,
30569
30740
  terminal: true,
@@ -31297,6 +31468,13 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
31297
31468
  * For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
31298
31469
  * will be associated by item identity in the array.
31299
31470
  *
31471
+ * * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
31472
+ * intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
31473
+ * when a filter is active on the repeater, but the filtered result set is empty.
31474
+ *
31475
+ * For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
31476
+ * the items have been processed through the filter.
31477
+ *
31300
31478
  * For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
31301
31479
  * `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
31302
31480
  * with the corresponding item in the array by identity. Moving the same object in array would move the DOM
@@ -31329,9 +31507,12 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
31329
31507
  I have {{friends.length}} friends. They are:
31330
31508
  <input type="search" ng-model="q" placeholder="filter friends..." />
31331
31509
  <ul class="example-animate-container">
31332
- <li class="animate-repeat" ng-repeat="friend in friends | filter:q">
31510
+ <li class="animate-repeat" ng-repeat="friend in friends | filter:q as results">
31333
31511
  [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
31334
31512
  </li>
31513
+ <li class="animate-repeat" ng-if="results.length == 0">
31514
+ <strong>No results found...</strong>
31515
+ </li>
31335
31516
  </ul>
31336
31517
  </div>
31337
31518
  </file>
@@ -31399,14 +31580,16 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
31399
31580
  var NG_REMOVED = '$$NG_REMOVED';
31400
31581
  var ngRepeatMinErr = minErr('ngRepeat');
31401
31582
  return {
31583
+ restrict: 'A',
31584
+ multiElement: true,
31402
31585
  transclude: 'element',
31403
31586
  priority: 1000,
31404
31587
  terminal: true,
31405
31588
  $$tlb: true,
31406
31589
  link: function($scope, $element, $attr, ctrl, $transclude){
31407
31590
  var expression = $attr.ngRepeat;
31408
- var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),
31409
- trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
31591
+ 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*$/),
31592
+ trackByExp, trackByExpGetter, aliasAs, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
31410
31593
  lhs, rhs, valueIdentifier, keyIdentifier,
31411
31594
  hashFnLocals = {$id: hashKey};
31412
31595
 
@@ -31417,7 +31600,8 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
31417
31600
 
31418
31601
  lhs = match[1];
31419
31602
  rhs = match[2];
31420
- trackByExp = match[3];
31603
+ aliasAs = match[3];
31604
+ trackByExp = match[4];
31421
31605
 
31422
31606
  if (trackByExp) {
31423
31607
  trackByExpGetter = $parse(trackByExp);
@@ -31469,6 +31653,10 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
31469
31653
  nextBlockOrder = [],
31470
31654
  elementsToRemove;
31471
31655
 
31656
+ if (aliasAs) {
31657
+ $scope[aliasAs] = collection;
31658
+ }
31659
+
31472
31660
  var updateScope = function(scope, index) {
31473
31661
  scope[valueIdentifier] = value;
31474
31662
  if (keyIdentifier) scope[keyIdentifier] = key;
@@ -31744,10 +31932,14 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
31744
31932
  </example>
31745
31933
  */
31746
31934
  var ngShowDirective = ['$animate', function($animate) {
31747
- return function(scope, element, attr) {
31748
- scope.$watch(attr.ngShow, function ngShowWatchAction(value){
31749
- $animate[value ? 'removeClass' : 'addClass'](element, 'ng-hide');
31750
- });
31935
+ return {
31936
+ restrict: 'A',
31937
+ multiElement: true,
31938
+ link: function(scope, element, attr) {
31939
+ scope.$watch(attr.ngShow, function ngShowWatchAction(value){
31940
+ $animate[value ? 'removeClass' : 'addClass'](element, 'ng-hide');
31941
+ });
31942
+ }
31751
31943
  };
31752
31944
  }];
31753
31945
 
@@ -31895,10 +32087,14 @@ var ngShowDirective = ['$animate', function($animate) {
31895
32087
  </example>
31896
32088
  */
31897
32089
  var ngHideDirective = ['$animate', function($animate) {
31898
- return function(scope, element, attr) {
31899
- scope.$watch(attr.ngHide, function ngHideWatchAction(value){
31900
- $animate[value ? 'addClass' : 'removeClass'](element, 'ng-hide');
31901
- });
32090
+ return {
32091
+ restrict: 'A',
32092
+ multiElement: true,
32093
+ link: function(scope, element, attr) {
32094
+ scope.$watch(attr.ngHide, function ngHideWatchAction(value){
32095
+ $animate[value ? 'addClass' : 'removeClass'](element, 'ng-hide');
32096
+ });
32097
+ }
31902
32098
  };
31903
32099
  }];
31904
32100
 
@@ -32109,7 +32305,7 @@ var ngSwitchDirective = ['$animate', function($animate) {
32109
32305
  previousElements.length = 0;
32110
32306
 
32111
32307
  for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
32112
- var selected = selectedElements[i];
32308
+ var selected = getBlockElements(selectedElements[i].clone);
32113
32309
  selectedScopes[i].$destroy();
32114
32310
  previousElements[i] = selected;
32115
32311
  $animate.leave(selected, function() {
@@ -32123,12 +32319,13 @@ var ngSwitchDirective = ['$animate', function($animate) {
32123
32319
  if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
32124
32320
  scope.$eval(attr.change);
32125
32321
  forEach(selectedTranscludes, function(selectedTransclude) {
32126
- var selectedScope = scope.$new();
32127
- selectedScopes.push(selectedScope);
32128
- selectedTransclude.transclude(selectedScope, function(caseElement) {
32322
+ selectedTransclude.transclude(function(caseElement, selectedScope) {
32323
+ selectedScopes.push(selectedScope);
32129
32324
  var anchor = selectedTransclude.element;
32325
+ caseElement[caseElement.length++] = document.createComment(' end ngSwitchWhen: ');
32326
+ var block = { clone: caseElement };
32130
32327
 
32131
- selectedElements.push(caseElement);
32328
+ selectedElements.push(block);
32132
32329
  $animate.enter(caseElement, anchor.parent(), anchor);
32133
32330
  });
32134
32331
  });
@@ -32140,8 +32337,9 @@ var ngSwitchDirective = ['$animate', function($animate) {
32140
32337
 
32141
32338
  var ngSwitchWhenDirective = ngDirective({
32142
32339
  transclude: 'element',
32143
- priority: 800,
32340
+ priority: 1200,
32144
32341
  require: '^ngSwitch',
32342
+ multiElement: true,
32145
32343
  link: function(scope, element, attrs, ctrl, $transclude) {
32146
32344
  ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
32147
32345
  ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
@@ -32150,8 +32348,9 @@ var ngSwitchWhenDirective = ngDirective({
32150
32348
 
32151
32349
  var ngSwitchDefaultDirective = ngDirective({
32152
32350
  transclude: 'element',
32153
- priority: 800,
32351
+ priority: 1200,
32154
32352
  require: '^ngSwitch',
32353
+ multiElement: true,
32155
32354
  link: function(scope, element, attr, ctrl, $transclude) {
32156
32355
  ctrl.cases['?'] = (ctrl.cases['?'] || []);
32157
32356
  ctrl.cases['?'].push({ transclude: $transclude, element: element });
@@ -32161,7 +32360,7 @@ var ngSwitchDefaultDirective = ngDirective({
32161
32360
  /**
32162
32361
  * @ngdoc directive
32163
32362
  * @name ngTransclude
32164
- * @restrict AC
32363
+ * @restrict EAC
32165
32364
  *
32166
32365
  * @description
32167
32366
  * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
@@ -32182,7 +32381,7 @@ var ngSwitchDefaultDirective = ngDirective({
32182
32381
  scope: { title:'@' },
32183
32382
  template: '<div style="border: 1px solid black;">' +
32184
32383
  '<div style="background-color: gray">{{title}}</div>' +
32185
- '<div ng-transclude></div>' +
32384
+ '<ng-transclude></ng-transclude>' +
32186
32385
  '</div>'
32187
32386
  };
32188
32387
  })
@@ -32213,6 +32412,7 @@ var ngSwitchDefaultDirective = ngDirective({
32213
32412
  *
32214
32413
  */
32215
32414
  var ngTranscludeDirective = ngDirective({
32415
+ restrict: 'EAC',
32216
32416
  link: function($scope, $element, $attrs, controller, $transclude) {
32217
32417
  if (!$transclude) {
32218
32418
  throw minErr('ngTransclude')('orphan',
@@ -32413,7 +32613,11 @@ var ngOptionsMinErr = minErr('ngOptions');
32413
32613
  </example>
32414
32614
  */
32415
32615
 
32416
- var ngOptionsDirective = valueFn({ terminal: true });
32616
+ var ngOptionsDirective = valueFn({
32617
+ restrict: 'A',
32618
+ terminal: true
32619
+ });
32620
+
32417
32621
  // jshint maxlen: false
32418
32622
  var selectDirective = ['$compile', '$parse', function($compile, $parse) {
32419
32623
  //000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
@@ -32824,6 +33028,12 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
32824
33028
  // lastElement.prop('selected') provided by jQuery has side-effects
32825
33029
  if (existingOption.selected !== option.selected) {
32826
33030
  lastElement.prop('selected', (existingOption.selected = option.selected));
33031
+ if (msie) {
33032
+ // See #7692
33033
+ // The selected item wouldn't visually update on IE without this.
33034
+ // Tested on Win7: IE9, IE10 and IE11. Future IEs should be tested as well
33035
+ lastElement.prop('selected', existingOption.selected);
33036
+ }
32827
33037
  }
32828
33038
  } else {
32829
33039
  // grow elements