angularjs-rails 1.2.20 → 1.2.21

Sign up to get free protection for your applications and to get access to all the features.
@@ -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