angularjs-rails 1.2.16 → 1.2.18

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.2.16
2
+ * @license AngularJS v1.2.18
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -187,13 +187,16 @@ ngTouch.factory('$swipe', [function() {
187
187
  * upon tap. (Event object is available as `$event`)
188
188
  *
189
189
  * @example
190
- <example>
190
+ <example module="ngClickExample" deps="angular-touch.js">
191
191
  <file name="index.html">
192
192
  <button ng-click="count = count + 1" ng-init="count=0">
193
193
  Increment
194
194
  </button>
195
195
  count: {{ count }}
196
196
  </file>
197
+ <file name="script.js">
198
+ angular.module('ngClickExample', ['ngTouch']);
199
+ </file>
197
200
  </example>
198
201
  */
199
202
 
@@ -230,7 +233,7 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
230
233
  //
231
234
  // What happens when the browser then generates a click event?
232
235
  // The browser, of course, also detects the tap and fires a click after a delay. This results in
233
- // tapping/clicking twice. So we do "clickbusting" to prevent it.
236
+ // tapping/clicking twice. We do "clickbusting" to prevent it.
234
237
  //
235
238
  // How does it work?
236
239
  // We attach global touchstart and click handlers, that run during the capture (early) phase.
@@ -253,9 +256,9 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
253
256
  // encapsulates this ugly logic away from the user.
254
257
  //
255
258
  // Why not just put click handlers on the element?
256
- // We do that too, just to be sure. The problem is that the tap event might have caused the DOM
257
- // to change, so that the click fires in the same position but something else is there now. So
258
- // the handlers are global and care only about coordinates and not elements.
259
+ // We do that too, just to be sure. If the tap event caused the DOM to change,
260
+ // it is possible another element is now in that position. To take account for these possibly
261
+ // distinct elements, the handlers are global and care only about coordinates.
259
262
 
260
263
  // Checks if the coordinates are close enough to be within the region.
261
264
  function hit(x1, y1, x2, y2) {
@@ -469,7 +472,7 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
469
472
  * upon left swipe. (Event object is available as `$event`)
470
473
  *
471
474
  * @example
472
- <example>
475
+ <example module="ngSwipeLeftExample" deps="angular-touch.js">
473
476
  <file name="index.html">
474
477
  <div ng-show="!showActions" ng-swipe-left="showActions = true">
475
478
  Some list content, like an email in the inbox
@@ -479,6 +482,9 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
479
482
  <button ng-click="delete()">Delete</button>
480
483
  </div>
481
484
  </file>
485
+ <file name="script.js">
486
+ angular.module('ngSwipeLeftExample', ['ngTouch']);
487
+ </file>
482
488
  </example>
483
489
  */
484
490
 
@@ -499,7 +505,7 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
499
505
  * upon right swipe. (Event object is available as `$event`)
500
506
  *
501
507
  * @example
502
- <example>
508
+ <example module="ngSwipeRightExample" deps="angular-touch.js">
503
509
  <file name="index.html">
504
510
  <div ng-show="!showActions" ng-swipe-left="showActions = true">
505
511
  Some list content, like an email in the inbox
@@ -509,6 +515,9 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
509
515
  <button ng-click="delete()">Delete</button>
510
516
  </div>
511
517
  </file>
518
+ <file name="script.js">
519
+ angular.module('ngSwipeRightExample', ['ngTouch']);
520
+ </file>
512
521
  </example>
513
522
  */
514
523
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.2.16
2
+ * @license AngularJS v1.2.18
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -68,7 +68,7 @@ function minErr(module) {
68
68
  return match;
69
69
  });
70
70
 
71
- message = message + '\nhttp://errors.angularjs.org/1.2.16/' +
71
+ message = message + '\nhttp://errors.angularjs.org/1.2.18/' +
72
72
  (module ? module + '/' : '') + code;
73
73
  for (i = 2; i < arguments.length; i++) {
74
74
  message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
@@ -89,7 +89,6 @@ function minErr(module) {
89
89
  -push,
90
90
  -toString,
91
91
  -ngMinErr,
92
- -_angular,
93
92
  -angularModule,
94
93
  -nodeName_,
95
94
  -uid,
@@ -186,7 +185,7 @@ function minErr(module) {
186
185
  * @ngdoc function
187
186
  * @name angular.lowercase
188
187
  * @module ng
189
- * @function
188
+ * @kind function
190
189
  *
191
190
  * @description Converts the specified string to lowercase.
192
191
  * @param {string} string String to be converted to lowercase.
@@ -199,7 +198,7 @@ var hasOwnProperty = Object.prototype.hasOwnProperty;
199
198
  * @ngdoc function
200
199
  * @name angular.uppercase
201
200
  * @module ng
202
- * @function
201
+ * @kind function
203
202
  *
204
203
  * @description Converts the specified string to uppercase.
205
204
  * @param {string} string String to be converted to uppercase.
@@ -240,8 +239,6 @@ var /** holds major version number for IE or NaN for real browsers */
240
239
  toString = Object.prototype.toString,
241
240
  ngMinErr = minErr('ng'),
242
241
 
243
-
244
- _angular = window.angular,
245
242
  /** @name angular */
246
243
  angular = window.angular || (window.angular = {}),
247
244
  angularModule,
@@ -283,7 +280,7 @@ function isArrayLike(obj) {
283
280
  * @ngdoc function
284
281
  * @name angular.forEach
285
282
  * @module ng
286
- * @function
283
+ * @kind function
287
284
  *
288
285
  * @description
289
286
  * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
@@ -297,7 +294,7 @@ function isArrayLike(obj) {
297
294
  ```js
298
295
  var values = {name: 'misko', gender: 'male'};
299
296
  var log = [];
300
- angular.forEach(values, function(value, key){
297
+ angular.forEach(values, function(value, key) {
301
298
  this.push(key + ': ' + value);
302
299
  }, log);
303
300
  expect(log).toEqual(['name: misko', 'gender: male']);
@@ -311,7 +308,7 @@ function isArrayLike(obj) {
311
308
  function forEach(obj, iterator, context) {
312
309
  var key;
313
310
  if (obj) {
314
- if (isFunction(obj)){
311
+ if (isFunction(obj)) {
315
312
  for (key in obj) {
316
313
  // Need to check if hasOwnProperty exists,
317
314
  // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
@@ -412,7 +409,7 @@ function setHashKey(obj, h) {
412
409
  * @ngdoc function
413
410
  * @name angular.extend
414
411
  * @module ng
415
- * @function
412
+ * @kind function
416
413
  *
417
414
  * @description
418
415
  * Extends the destination object `dst` by copying all of the properties from the `src` object(s)
@@ -424,9 +421,9 @@ function setHashKey(obj, h) {
424
421
  */
425
422
  function extend(dst) {
426
423
  var h = dst.$$hashKey;
427
- forEach(arguments, function(obj){
424
+ forEach(arguments, function(obj) {
428
425
  if (obj !== dst) {
429
- forEach(obj, function(value, key){
426
+ forEach(obj, function(value, key) {
430
427
  dst[key] = value;
431
428
  });
432
429
  }
@@ -449,7 +446,7 @@ function inherit(parent, extra) {
449
446
  * @ngdoc function
450
447
  * @name angular.noop
451
448
  * @module ng
452
- * @function
449
+ * @kind function
453
450
  *
454
451
  * @description
455
452
  * A function that performs no operations. This function can be useful when writing code in the
@@ -469,7 +466,7 @@ noop.$inject = [];
469
466
  * @ngdoc function
470
467
  * @name angular.identity
471
468
  * @module ng
472
- * @function
469
+ * @kind function
473
470
  *
474
471
  * @description
475
472
  * A function that returns its first argument. This function is useful when writing code in the
@@ -491,7 +488,7 @@ function valueFn(value) {return function() {return value;};}
491
488
  * @ngdoc function
492
489
  * @name angular.isUndefined
493
490
  * @module ng
494
- * @function
491
+ * @kind function
495
492
  *
496
493
  * @description
497
494
  * Determines if a reference is undefined.
@@ -506,7 +503,7 @@ function isUndefined(value){return typeof value === 'undefined';}
506
503
  * @ngdoc function
507
504
  * @name angular.isDefined
508
505
  * @module ng
509
- * @function
506
+ * @kind function
510
507
  *
511
508
  * @description
512
509
  * Determines if a reference is defined.
@@ -521,7 +518,7 @@ function isDefined(value){return typeof value !== 'undefined';}
521
518
  * @ngdoc function
522
519
  * @name angular.isObject
523
520
  * @module ng
524
- * @function
521
+ * @kind function
525
522
  *
526
523
  * @description
527
524
  * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
@@ -537,7 +534,7 @@ function isObject(value){return value != null && typeof value === 'object';}
537
534
  * @ngdoc function
538
535
  * @name angular.isString
539
536
  * @module ng
540
- * @function
537
+ * @kind function
541
538
  *
542
539
  * @description
543
540
  * Determines if a reference is a `String`.
@@ -552,7 +549,7 @@ function isString(value){return typeof value === 'string';}
552
549
  * @ngdoc function
553
550
  * @name angular.isNumber
554
551
  * @module ng
555
- * @function
552
+ * @kind function
556
553
  *
557
554
  * @description
558
555
  * Determines if a reference is a `Number`.
@@ -567,7 +564,7 @@ function isNumber(value){return typeof value === 'number';}
567
564
  * @ngdoc function
568
565
  * @name angular.isDate
569
566
  * @module ng
570
- * @function
567
+ * @kind function
571
568
  *
572
569
  * @description
573
570
  * Determines if a value is a date.
@@ -575,7 +572,7 @@ function isNumber(value){return typeof value === 'number';}
575
572
  * @param {*} value Reference to check.
576
573
  * @returns {boolean} True if `value` is a `Date`.
577
574
  */
578
- function isDate(value){
575
+ function isDate(value) {
579
576
  return toString.call(value) === '[object Date]';
580
577
  }
581
578
 
@@ -584,7 +581,7 @@ function isDate(value){
584
581
  * @ngdoc function
585
582
  * @name angular.isArray
586
583
  * @module ng
587
- * @function
584
+ * @kind function
588
585
  *
589
586
  * @description
590
587
  * Determines if a reference is an `Array`.
@@ -592,16 +589,20 @@ function isDate(value){
592
589
  * @param {*} value Reference to check.
593
590
  * @returns {boolean} True if `value` is an `Array`.
594
591
  */
595
- function isArray(value) {
596
- return toString.call(value) === '[object Array]';
597
- }
598
-
592
+ var isArray = (function() {
593
+ if (!isFunction(Array.isArray)) {
594
+ return function(value) {
595
+ return toString.call(value) === '[object Array]';
596
+ };
597
+ }
598
+ return Array.isArray;
599
+ })();
599
600
 
600
601
  /**
601
602
  * @ngdoc function
602
603
  * @name angular.isFunction
603
604
  * @module ng
604
- * @function
605
+ * @kind function
605
606
  *
606
607
  * @description
607
608
  * Determines if a reference is a `Function`.
@@ -675,7 +676,7 @@ var trim = (function() {
675
676
  * @ngdoc function
676
677
  * @name angular.isElement
677
678
  * @module ng
678
- * @function
679
+ * @kind function
679
680
  *
680
681
  * @description
681
682
  * Determines if a reference is a DOM element (or wrapped jQuery element).
@@ -693,7 +694,7 @@ function isElement(node) {
693
694
  * @param str 'key1,key2,...'
694
695
  * @returns {object} in the form of {key1:true, key2:true, ...}
695
696
  */
696
- function makeMap(str){
697
+ function makeMap(str) {
697
698
  var obj = {}, items = str.split(","), i;
698
699
  for ( i = 0; i < items.length; i++ )
699
700
  obj[ items[i] ] = true;
@@ -740,7 +741,7 @@ function size(obj, ownPropsOnly) {
740
741
 
741
742
  if (isArray(obj) || isString(obj)) {
742
743
  return obj.length;
743
- } else if (isObject(obj)){
744
+ } else if (isObject(obj)) {
744
745
  for (key in obj)
745
746
  if (!ownPropsOnly || obj.hasOwnProperty(key))
746
747
  count++;
@@ -786,7 +787,7 @@ function isLeafNode (node) {
786
787
  * @ngdoc function
787
788
  * @name angular.copy
788
789
  * @module ng
789
- * @function
790
+ * @kind function
790
791
  *
791
792
  * @description
792
793
  * Creates a deep copy of `source`, which should be an object or an array.
@@ -839,7 +840,7 @@ function isLeafNode (node) {
839
840
  </file>
840
841
  </example>
841
842
  */
842
- function copy(source, destination){
843
+ function copy(source, destination, stackSource, stackDest) {
843
844
  if (isWindow(source) || isScope(source)) {
844
845
  throw ngMinErr('cpws',
845
846
  "Can't copy! Making copies of Window or Scope instances is not supported.");
@@ -849,52 +850,82 @@ function copy(source, destination){
849
850
  destination = source;
850
851
  if (source) {
851
852
  if (isArray(source)) {
852
- destination = copy(source, []);
853
+ destination = copy(source, [], stackSource, stackDest);
853
854
  } else if (isDate(source)) {
854
855
  destination = new Date(source.getTime());
855
856
  } else if (isRegExp(source)) {
856
857
  destination = new RegExp(source.source);
857
858
  } else if (isObject(source)) {
858
- destination = copy(source, {});
859
+ destination = copy(source, {}, stackSource, stackDest);
859
860
  }
860
861
  }
861
862
  } else {
862
863
  if (source === destination) throw ngMinErr('cpi',
863
864
  "Can't copy! Source and destination are identical.");
865
+
866
+ stackSource = stackSource || [];
867
+ stackDest = stackDest || [];
868
+
869
+ if (isObject(source)) {
870
+ var index = indexOf(stackSource, source);
871
+ if (index !== -1) return stackDest[index];
872
+
873
+ stackSource.push(source);
874
+ stackDest.push(destination);
875
+ }
876
+
877
+ var result;
864
878
  if (isArray(source)) {
865
879
  destination.length = 0;
866
880
  for ( var i = 0; i < source.length; i++) {
867
- destination.push(copy(source[i]));
881
+ result = copy(source[i], null, stackSource, stackDest);
882
+ if (isObject(source[i])) {
883
+ stackSource.push(source[i]);
884
+ stackDest.push(result);
885
+ }
886
+ destination.push(result);
868
887
  }
869
888
  } else {
870
889
  var h = destination.$$hashKey;
871
- forEach(destination, function(value, key){
890
+ forEach(destination, function(value, key) {
872
891
  delete destination[key];
873
892
  });
874
893
  for ( var key in source) {
875
- destination[key] = copy(source[key]);
894
+ result = copy(source[key], null, stackSource, stackDest);
895
+ if (isObject(source[key])) {
896
+ stackSource.push(source[key]);
897
+ stackDest.push(result);
898
+ }
899
+ destination[key] = result;
876
900
  }
877
901
  setHashKey(destination,h);
878
902
  }
903
+
879
904
  }
880
905
  return destination;
881
906
  }
882
907
 
883
908
  /**
884
- * Create a shallow copy of an object
909
+ * Creates a shallow copy of an object, an array or a primitive
885
910
  */
886
911
  function shallowCopy(src, dst) {
887
- dst = dst || {};
912
+ if (isArray(src)) {
913
+ dst = dst || [];
914
+
915
+ for ( var i = 0; i < src.length; i++) {
916
+ dst[i] = src[i];
917
+ }
918
+ } else if (isObject(src)) {
919
+ dst = dst || {};
888
920
 
889
- for(var key in src) {
890
- // shallowCopy is only ever called by $compile nodeLinkFn, which has control over src
891
- // so we don't need to worry about using our custom hasOwnProperty here
892
- if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
893
- dst[key] = src[key];
921
+ for (var key in src) {
922
+ if (hasOwnProperty.call(src, key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
923
+ dst[key] = src[key];
924
+ }
894
925
  }
895
926
  }
896
927
 
897
- return dst;
928
+ return dst || src;
898
929
  }
899
930
 
900
931
 
@@ -902,7 +933,7 @@ function shallowCopy(src, dst) {
902
933
  * @ngdoc function
903
934
  * @name angular.equals
904
935
  * @module ng
905
- * @function
936
+ * @kind function
906
937
  *
907
938
  * @description
908
939
  * Determines if two objects or two values are equivalent. Supports value types, regular
@@ -914,7 +945,7 @@ function shallowCopy(src, dst) {
914
945
  * * Both objects or values are of the same type and all of their properties are equal by
915
946
  * comparing them with `angular.equals`.
916
947
  * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
917
- * * Both values represent the same regular expression (In JavasScript,
948
+ * * Both values represent the same regular expression (In JavaScript,
918
949
  * /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
919
950
  * representation matches).
920
951
  *
@@ -989,7 +1020,7 @@ function sliceArgs(args, startIndex) {
989
1020
  * @ngdoc function
990
1021
  * @name angular.bind
991
1022
  * @module ng
992
- * @function
1023
+ * @kind function
993
1024
  *
994
1025
  * @description
995
1026
  * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
@@ -1045,7 +1076,7 @@ function toJsonReplacer(key, value) {
1045
1076
  * @ngdoc function
1046
1077
  * @name angular.toJson
1047
1078
  * @module ng
1048
- * @function
1079
+ * @kind function
1049
1080
  *
1050
1081
  * @description
1051
1082
  * Serializes input into a JSON-formatted string. Properties with leading $ characters will be
@@ -1065,7 +1096,7 @@ function toJson(obj, pretty) {
1065
1096
  * @ngdoc function
1066
1097
  * @name angular.fromJson
1067
1098
  * @module ng
1068
- * @function
1099
+ * @kind function
1069
1100
  *
1070
1101
  * @description
1071
1102
  * Deserializes a JSON string.
@@ -1142,7 +1173,7 @@ function tryDecodeURIComponent(value) {
1142
1173
  */
1143
1174
  function parseKeyValue(/**string*/keyValue) {
1144
1175
  var obj = {}, key_value, key;
1145
- forEach((keyValue || "").split('&'), function(keyValue){
1176
+ forEach((keyValue || "").split('&'), function(keyValue) {
1146
1177
  if ( keyValue ) {
1147
1178
  key_value = keyValue.split('=');
1148
1179
  key = tryDecodeURIComponent(key_value[0]);
@@ -1404,7 +1435,7 @@ function bootstrap(element, modules) {
1404
1435
  }
1405
1436
 
1406
1437
  var SNAKE_CASE_REGEXP = /[A-Z]/g;
1407
- function snake_case(name, separator){
1438
+ function snake_case(name, separator) {
1408
1439
  separator = separator || '_';
1409
1440
  return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
1410
1441
  return (pos ? separator : '') + letter.toLowerCase();
@@ -1414,8 +1445,9 @@ function snake_case(name, separator){
1414
1445
  function bindJQuery() {
1415
1446
  // bind to jQuery if present;
1416
1447
  jQuery = window.jQuery;
1417
- // reset to jQuery or default to us.
1418
- if (jQuery) {
1448
+ // Use jQuery if it exists with proper functionality, otherwise default to us.
1449
+ // Angular 1.2+ requires jQuery 1.7.1+ for on()/off() support.
1450
+ if (jQuery && jQuery.fn.on) {
1419
1451
  jqLite = jQuery;
1420
1452
  extend(jQuery.fn, {
1421
1453
  scope: JQLitePrototype.scope,
@@ -1561,7 +1593,7 @@ function setupModuleLoader(window) {
1561
1593
  *
1562
1594
  * # Module
1563
1595
  *
1564
- * A module is a collection of services, directives, filters, and configuration information.
1596
+ * A module is a collection of services, directives, controllers, filters, and configuration information.
1565
1597
  * `angular.module` is used to configure the {@link auto.$injector $injector}.
1566
1598
  *
1567
1599
  * ```js
@@ -1589,9 +1621,9 @@ function setupModuleLoader(window) {
1589
1621
  * {@link angular.bootstrap} to simplify this process for you.
1590
1622
  *
1591
1623
  * @param {!string} name The name of the module to create or retrieve.
1592
- <<<<<* @param {!Array.<string>=} requires If specified then new module is being created. If
1593
- >>>>>* unspecified then the module is being retrieved for further configuration.
1594
- * @param {Function} configFn Optional configuration function for the module. Same as
1624
+ * @param {!Array.<string>=} requires If specified then new module is being created. If
1625
+ * unspecified then the module is being retrieved for further configuration.
1626
+ * @param {Function=} configFn Optional configuration function for the module. Same as
1595
1627
  * {@link angular.Module#config Module#config()}.
1596
1628
  * @returns {module} new module with the {@link angular.Module} api.
1597
1629
  */
@@ -1783,6 +1815,8 @@ function setupModuleLoader(window) {
1783
1815
  * configuration.
1784
1816
  * @description
1785
1817
  * Use this method to register work which needs to be performed on module loading.
1818
+ * For more about how to configure services, see
1819
+ * {@link providers#providers_provider-recipe Provider Recipe}.
1786
1820
  */
1787
1821
  config: config,
1788
1822
 
@@ -1919,11 +1953,11 @@ function setupModuleLoader(window) {
1919
1953
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
1920
1954
  */
1921
1955
  var version = {
1922
- full: '1.2.16', // all of these placeholder strings will be replaced by grunt's
1956
+ full: '1.2.18', // all of these placeholder strings will be replaced by grunt's
1923
1957
  major: 1, // package task
1924
1958
  minor: 2,
1925
- dot: 16,
1926
- codeName: 'badger-enumeration'
1959
+ dot: 18,
1960
+ codeName: 'ear-extendability'
1927
1961
  };
1928
1962
 
1929
1963
 
@@ -2063,7 +2097,7 @@ function publishExternalAPI(angular){
2063
2097
  * @ngdoc function
2064
2098
  * @name angular.element
2065
2099
  * @module ng
2066
- * @function
2100
+ * @kind function
2067
2101
  *
2068
2102
  * @description
2069
2103
  * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
@@ -2146,7 +2180,7 @@ function publishExternalAPI(angular){
2146
2180
  */
2147
2181
 
2148
2182
  var jqCache = JQLite.cache = {},
2149
- jqName = JQLite.expando = 'ng-' + new Date().getTime(),
2183
+ jqName = JQLite.expando = 'ng' + new Date().getTime(),
2150
2184
  jqId = 1,
2151
2185
  addEventListenerFn = (window.document.addEventListener
2152
2186
  ? function(element, type, fn) {element.addEventListener(type, fn, false);}
@@ -2699,6 +2733,7 @@ forEach({
2699
2733
  */
2700
2734
  JQLite.prototype[name] = function(arg1, arg2) {
2701
2735
  var i, key;
2736
+ var nodeCount = this.length;
2702
2737
 
2703
2738
  // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
2704
2739
  // in a way that survives minification.
@@ -2708,7 +2743,7 @@ forEach({
2708
2743
  if (isObject(arg1)) {
2709
2744
 
2710
2745
  // we are a write, but the object properties are the key/values
2711
- for (i = 0; i < this.length; i++) {
2746
+ for (i = 0; i < nodeCount; i++) {
2712
2747
  if (fn === jqLiteData) {
2713
2748
  // data() takes the whole object in jQuery
2714
2749
  fn(this[i], arg1);
@@ -2722,9 +2757,10 @@ forEach({
2722
2757
  return this;
2723
2758
  } else {
2724
2759
  // we are a read, so read the first child.
2760
+ // TODO: do we still need this?
2725
2761
  var value = fn.$dv;
2726
2762
  // Only if we have $dv do we iterate over all, otherwise it is just the first element.
2727
- var jj = (value === undefined) ? Math.min(this.length, 1) : this.length;
2763
+ var jj = (value === undefined) ? Math.min(nodeCount, 1) : nodeCount;
2728
2764
  for (var j = 0; j < jj; j++) {
2729
2765
  var nodeValue = fn(this[j], arg1, arg2);
2730
2766
  value = value ? value + nodeValue : nodeValue;
@@ -2733,7 +2769,7 @@ forEach({
2733
2769
  }
2734
2770
  } else {
2735
2771
  // we are a write, so apply to all children
2736
- for (i = 0; i < this.length; i++) {
2772
+ for (i = 0; i < nodeCount; i++) {
2737
2773
  fn(this[i], arg1, arg2);
2738
2774
  }
2739
2775
  // return self for chaining
@@ -3102,7 +3138,7 @@ HashMap.prototype = {
3102
3138
  * @ngdoc function
3103
3139
  * @module ng
3104
3140
  * @name angular.injector
3105
- * @function
3141
+ * @kind function
3106
3142
  *
3107
3143
  * @description
3108
3144
  * Creates an injector function that can be used for retrieving services as well as for
@@ -3129,7 +3165,7 @@ HashMap.prototype = {
3129
3165
  *
3130
3166
  * Sometimes you want to get access to the injector of a currently running Angular app
3131
3167
  * from outside Angular. Perhaps, you want to inject and compile some markup after the
3132
- * application has been bootstrapped. You can do this using extra `injector()` added
3168
+ * application has been bootstrapped. You can do this using the extra `injector()` added
3133
3169
  * to JQuery/jqLite elements. See {@link angular.element}.
3134
3170
  *
3135
3171
  * *This is fairly rare but could be the case if a third party library is injecting the
@@ -3199,7 +3235,7 @@ function annotate(fn) {
3199
3235
  /**
3200
3236
  * @ngdoc service
3201
3237
  * @name $injector
3202
- * @function
3238
+ * @kind function
3203
3239
  *
3204
3240
  * @description
3205
3241
  *
@@ -3242,7 +3278,7 @@ function annotate(fn) {
3242
3278
  * minification, and obfuscation tools since these tools change the argument names.
3243
3279
  *
3244
3280
  * ## `$inject` Annotation
3245
- * By adding a `$inject` property onto a function the injection parameters can be specified.
3281
+ * By adding an `$inject` property onto a function the injection parameters can be specified.
3246
3282
  *
3247
3283
  * ## Inline
3248
3284
  * As an array of injection names, where the last item in the array is the function to call.
@@ -3279,7 +3315,7 @@ function annotate(fn) {
3279
3315
  * @name $injector#has
3280
3316
  *
3281
3317
  * @description
3282
- * Allows the user to query if the particular service exist.
3318
+ * Allows the user to query if the particular service exists.
3283
3319
  *
3284
3320
  * @param {string} Name of the service to query.
3285
3321
  * @returns {boolean} returns true if injector has given service.
@@ -3289,8 +3325,8 @@ function annotate(fn) {
3289
3325
  * @ngdoc method
3290
3326
  * @name $injector#instantiate
3291
3327
  * @description
3292
- * Create a new instance of JS type. The method takes a constructor function invokes the new
3293
- * operator and supplies all of the arguments to the constructor function as specified by the
3328
+ * Create a new instance of JS type. The method takes a constructor function, invokes the new
3329
+ * operator, and supplies all of the arguments to the constructor function as specified by the
3294
3330
  * constructor annotation.
3295
3331
  *
3296
3332
  * @param {Function} Type Annotated constructor function.
@@ -3822,7 +3858,8 @@ function createInjector(modulesToLoad) {
3822
3858
  function getService(serviceName) {
3823
3859
  if (cache.hasOwnProperty(serviceName)) {
3824
3860
  if (cache[serviceName] === INSTANTIATING) {
3825
- throw $injectorMinErr('cdep', 'Circular dependency found: {0}', path.join(' <- '));
3861
+ throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
3862
+ serviceName + ' <- ' + path.join(' <- '));
3826
3863
  }
3827
3864
  return cache[serviceName];
3828
3865
  } else {
@@ -3903,7 +3940,7 @@ function createInjector(modulesToLoad) {
3903
3940
  * @requires $rootScope
3904
3941
  *
3905
3942
  * @description
3906
- * When called, it checks current value of `$location.hash()` and scroll to related element,
3943
+ * When called, it checks current value of `$location.hash()` and scrolls to the related element,
3907
3944
  * according to rules specified in
3908
3945
  * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
3909
3946
  *
@@ -4105,7 +4142,7 @@ var $AnimateProvider = ['$provide', function($provide) {
4105
4142
  *
4106
4143
  * @ngdoc method
4107
4144
  * @name $animate#enter
4108
- * @function
4145
+ * @kind function
4109
4146
  * @description Inserts the element into the DOM either after the `after` element or within
4110
4147
  * the `parent` element. Once complete, the done() callback will be fired (if provided).
4111
4148
  * @param {DOMElement} element the element which will be inserted into the DOM
@@ -4132,7 +4169,7 @@ var $AnimateProvider = ['$provide', function($provide) {
4132
4169
  *
4133
4170
  * @ngdoc method
4134
4171
  * @name $animate#leave
4135
- * @function
4172
+ * @kind function
4136
4173
  * @description Removes the element from the DOM. Once complete, the done() callback will be
4137
4174
  * fired (if provided).
4138
4175
  * @param {DOMElement} element the element which will be removed from the DOM
@@ -4148,7 +4185,7 @@ var $AnimateProvider = ['$provide', function($provide) {
4148
4185
  *
4149
4186
  * @ngdoc method
4150
4187
  * @name $animate#move
4151
- * @function
4188
+ * @kind function
4152
4189
  * @description Moves the position of the provided element within the DOM to be placed
4153
4190
  * either after the `after` element or inside of the `parent` element. Once complete, the
4154
4191
  * done() callback will be fired (if provided).
@@ -4172,7 +4209,7 @@ var $AnimateProvider = ['$provide', function($provide) {
4172
4209
  *
4173
4210
  * @ngdoc method
4174
4211
  * @name $animate#addClass
4175
- * @function
4212
+ * @kind function
4176
4213
  * @description Adds the provided className CSS class value to the provided element. Once
4177
4214
  * complete, the done() callback will be fired (if provided).
4178
4215
  * @param {DOMElement} element the element which will have the className value
@@ -4195,7 +4232,7 @@ var $AnimateProvider = ['$provide', function($provide) {
4195
4232
  *
4196
4233
  * @ngdoc method
4197
4234
  * @name $animate#removeClass
4198
- * @function
4235
+ * @kind function
4199
4236
  * @description Removes the provided className CSS class value from the provided element.
4200
4237
  * Once complete, the done() callback will be fired (if provided).
4201
4238
  * @param {DOMElement} element the element which will have the className value
@@ -4218,10 +4255,10 @@ var $AnimateProvider = ['$provide', function($provide) {
4218
4255
  *
4219
4256
  * @ngdoc method
4220
4257
  * @name $animate#setClass
4221
- * @function
4258
+ * @kind function
4222
4259
  * @description Adds and/or removes the given CSS classes to and from the element.
4223
4260
  * Once complete, the done() callback will be fired (if provided).
4224
- * @param {DOMElement} element the element which will it's CSS classes changed
4261
+ * @param {DOMElement} element the element which will have its CSS classes changed
4225
4262
  * removed from it
4226
4263
  * @param {string} add the CSS classes which will be added to the element
4227
4264
  * @param {string} remove the CSS class which will be removed from the element
@@ -4775,7 +4812,7 @@ function $CacheFactoryProvider() {
4775
4812
  /**
4776
4813
  * @ngdoc method
4777
4814
  * @name $cacheFactory.Cache#put
4778
- * @function
4815
+ * @kind function
4779
4816
  *
4780
4817
  * @description
4781
4818
  * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
@@ -4811,7 +4848,7 @@ function $CacheFactoryProvider() {
4811
4848
  /**
4812
4849
  * @ngdoc method
4813
4850
  * @name $cacheFactory.Cache#get
4814
- * @function
4851
+ * @kind function
4815
4852
  *
4816
4853
  * @description
4817
4854
  * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
@@ -4835,7 +4872,7 @@ function $CacheFactoryProvider() {
4835
4872
  /**
4836
4873
  * @ngdoc method
4837
4874
  * @name $cacheFactory.Cache#remove
4838
- * @function
4875
+ * @kind function
4839
4876
  *
4840
4877
  * @description
4841
4878
  * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
@@ -4863,7 +4900,7 @@ function $CacheFactoryProvider() {
4863
4900
  /**
4864
4901
  * @ngdoc method
4865
4902
  * @name $cacheFactory.Cache#removeAll
4866
- * @function
4903
+ * @kind function
4867
4904
  *
4868
4905
  * @description
4869
4906
  * Clears the cache object of any entries.
@@ -4879,7 +4916,7 @@ function $CacheFactoryProvider() {
4879
4916
  /**
4880
4917
  * @ngdoc method
4881
4918
  * @name $cacheFactory.Cache#destroy
4882
- * @function
4919
+ * @kind function
4883
4920
  *
4884
4921
  * @description
4885
4922
  * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
@@ -4896,7 +4933,7 @@ function $CacheFactoryProvider() {
4896
4933
  /**
4897
4934
  * @ngdoc method
4898
4935
  * @name $cacheFactory.Cache#info
4899
- * @function
4936
+ * @kind function
4900
4937
  *
4901
4938
  * @description
4902
4939
  * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
@@ -4951,7 +4988,7 @@ function $CacheFactoryProvider() {
4951
4988
  * @name $cacheFactory#info
4952
4989
  *
4953
4990
  * @description
4954
- * Get information about all the of the caches that have been created
4991
+ * Get information about all the caches that have been created
4955
4992
  *
4956
4993
  * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
4957
4994
  */
@@ -5052,7 +5089,7 @@ function $TemplateCacheProvider() {
5052
5089
  /**
5053
5090
  * @ngdoc service
5054
5091
  * @name $compile
5055
- * @function
5092
+ * @kind function
5056
5093
  *
5057
5094
  * @description
5058
5095
  * Compiles an HTML string or DOM into a template and produces a template function, which
@@ -5090,7 +5127,6 @@ function $TemplateCacheProvider() {
5090
5127
  * template: '<div></div>', // or // function(tElement, tAttrs) { ... },
5091
5128
  * // or
5092
5129
  * // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
5093
- * replace: false,
5094
5130
  * transclude: false,
5095
5131
  * restrict: 'A',
5096
5132
  * scope: false,
@@ -5266,7 +5302,7 @@ function $TemplateCacheProvider() {
5266
5302
  * api/ng.$sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
5267
5303
  *
5268
5304
  *
5269
- * #### `replace`
5305
+ * #### `replace` ([*DEPRECATED*!], will be removed in next major release)
5270
5306
  * specify where the template should be inserted. Defaults to `false`.
5271
5307
  *
5272
5308
  * * `true` - the template will replace the current element.
@@ -5293,11 +5329,7 @@ function $TemplateCacheProvider() {
5293
5329
  * ```
5294
5330
  *
5295
5331
  * The compile function deals with transforming the template DOM. Since most directives do not do
5296
- * template transformation, it is not used often. Examples that require compile functions are
5297
- * directives that transform template DOM, such as {@link
5298
- * api/ng.directive:ngRepeat ngRepeat}, or load the contents
5299
- * asynchronously, such as {@link ngRoute.directive:ngView ngView}. The
5300
- * compile function takes the following arguments.
5332
+ * template transformation, it is not used often. The compile function takes the following arguments:
5301
5333
  *
5302
5334
  * * `tElement` - template element - The element where the directive has been declared. It is
5303
5335
  * safe to do template transformation on the element and child elements only.
@@ -5535,7 +5567,7 @@ var $compileMinErr = minErr('$compile');
5535
5567
  /**
5536
5568
  * @ngdoc provider
5537
5569
  * @name $compileProvider
5538
- * @function
5570
+ * @kind function
5539
5571
  *
5540
5572
  * @description
5541
5573
  */
@@ -5543,8 +5575,8 @@ $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
5543
5575
  function $CompileProvider($provide, $$sanitizeUriProvider) {
5544
5576
  var hasDirectives = {},
5545
5577
  Suffix = 'Directive',
5546
- COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
5547
- CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/;
5578
+ COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w_\-]+)\s+(.*)$/,
5579
+ CLASS_DIRECTIVE_REGEXP = /(([\d\w_\-]+)(?:\:([^;]+))?;?)/;
5548
5580
 
5549
5581
  // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
5550
5582
  // The assumption is that future DOM event attribute names will begin with
@@ -5554,7 +5586,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
5554
5586
  /**
5555
5587
  * @ngdoc method
5556
5588
  * @name $compileProvider#directive
5557
- * @function
5589
+ * @kind function
5558
5590
  *
5559
5591
  * @description
5560
5592
  * Register a new directive with the compiler.
@@ -5607,7 +5639,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
5607
5639
  /**
5608
5640
  * @ngdoc method
5609
5641
  * @name $compileProvider#aHrefSanitizationWhitelist
5610
- * @function
5642
+ * @kind function
5611
5643
  *
5612
5644
  * @description
5613
5645
  * Retrieves or overrides the default regular expression that is used for whitelisting of safe
@@ -5637,7 +5669,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
5637
5669
  /**
5638
5670
  * @ngdoc method
5639
5671
  * @name $compileProvider#imgSrcSanitizationWhitelist
5640
- * @function
5672
+ * @kind function
5641
5673
  *
5642
5674
  * @description
5643
5675
  * Retrieves or overrides the default regular expression that is used for whitelisting of safe
@@ -5681,7 +5713,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
5681
5713
  /**
5682
5714
  * @ngdoc method
5683
5715
  * @name $compile.directive.Attributes#$addClass
5684
- * @function
5716
+ * @kind function
5685
5717
  *
5686
5718
  * @description
5687
5719
  * Adds the CSS class value specified by the classVal parameter to the element. If animations
@@ -5698,7 +5730,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
5698
5730
  /**
5699
5731
  * @ngdoc method
5700
5732
  * @name $compile.directive.Attributes#$removeClass
5701
- * @function
5733
+ * @kind function
5702
5734
  *
5703
5735
  * @description
5704
5736
  * Removes the CSS class value specified by the classVal parameter from the element. If
@@ -5715,7 +5747,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
5715
5747
  /**
5716
5748
  * @ngdoc method
5717
5749
  * @name $compile.directive.Attributes#$updateClass
5718
- * @function
5750
+ * @kind function
5719
5751
  *
5720
5752
  * @description
5721
5753
  * Adds and removes the appropriate CSS class values to the element based on the difference
@@ -5803,7 +5835,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
5803
5835
  /**
5804
5836
  * @ngdoc method
5805
5837
  * @name $compile.directive.Attributes#$observe
5806
- * @function
5838
+ * @kind function
5807
5839
  *
5808
5840
  * @description
5809
5841
  * Observes an interpolated attribute.
@@ -5866,7 +5898,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
5866
5898
  compileNodes($compileNodes, transcludeFn, $compileNodes,
5867
5899
  maxPriority, ignoreDirective, previousCompileContext);
5868
5900
  safeAddClass($compileNodes, 'ng-scope');
5869
- return function publicLinkFn(scope, cloneConnectFn, transcludeControllers){
5901
+ return function publicLinkFn(scope, cloneConnectFn, transcludeControllers, parentBoundTranscludeFn){
5870
5902
  assertArg(scope, 'scope');
5871
5903
  // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
5872
5904
  // and sometimes changes the structure of the DOM.
@@ -5888,7 +5920,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
5888
5920
  }
5889
5921
 
5890
5922
  if (cloneConnectFn) cloneConnectFn($linkNode, scope);
5891
- if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode);
5923
+ if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
5892
5924
  return $linkNode;
5893
5925
  };
5894
5926
  }
@@ -5943,7 +5975,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
5943
5975
  !childNodes.length)
5944
5976
  ? null
5945
5977
  : compileNodes(childNodes,
5946
- nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
5978
+ nodeLinkFn ? (
5979
+ (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
5980
+ && nodeLinkFn.transclude) : transcludeFn);
5947
5981
 
5948
5982
  linkFns.push(nodeLinkFn, childLinkFn);
5949
5983
  linkFnFound = linkFnFound || nodeLinkFn || childLinkFn;
@@ -5954,8 +5988,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
5954
5988
  // return a linking function if we have found anything, null otherwise
5955
5989
  return linkFnFound ? compositeLinkFn : null;
5956
5990
 
5957
- function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
5958
- var nodeLinkFn, childLinkFn, node, $node, childScope, childTranscludeFn, i, ii, n;
5991
+ function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
5992
+ var nodeLinkFn, childLinkFn, node, $node, childScope, i, ii, n, childBoundTranscludeFn;
5959
5993
 
5960
5994
  // copy nodeList so that linking doesn't break due to live list updates.
5961
5995
  var nodeListLength = nodeList.length,
@@ -5977,23 +6011,32 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
5977
6011
  } else {
5978
6012
  childScope = scope;
5979
6013
  }
5980
- childTranscludeFn = nodeLinkFn.transclude;
5981
- if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
5982
- nodeLinkFn(childLinkFn, childScope, node, $rootElement,
5983
- createBoundTranscludeFn(scope, childTranscludeFn || transcludeFn)
5984
- );
6014
+
6015
+ if ( nodeLinkFn.transcludeOnThisElement ) {
6016
+ childBoundTranscludeFn = createBoundTranscludeFn(scope, nodeLinkFn.transclude, parentBoundTranscludeFn);
6017
+
6018
+ } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
6019
+ childBoundTranscludeFn = parentBoundTranscludeFn;
6020
+
6021
+ } else if (!parentBoundTranscludeFn && transcludeFn) {
6022
+ childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
6023
+
5985
6024
  } else {
5986
- nodeLinkFn(childLinkFn, childScope, node, $rootElement, boundTranscludeFn);
6025
+ childBoundTranscludeFn = null;
5987
6026
  }
6027
+
6028
+ nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
6029
+
5988
6030
  } else if (childLinkFn) {
5989
- childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
6031
+ childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
5990
6032
  }
5991
6033
  }
5992
6034
  }
5993
6035
  }
5994
6036
 
5995
- function createBoundTranscludeFn(scope, transcludeFn) {
5996
- return function boundTranscludeFn(transcludedScope, cloneFn, controllers) {
6037
+ function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
6038
+
6039
+ var boundTranscludeFn = function(transcludedScope, cloneFn, controllers) {
5997
6040
  var scopeCreated = false;
5998
6041
 
5999
6042
  if (!transcludedScope) {
@@ -6002,12 +6045,14 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6002
6045
  scopeCreated = true;
6003
6046
  }
6004
6047
 
6005
- var clone = transcludeFn(transcludedScope, cloneFn, controllers);
6048
+ var clone = transcludeFn(transcludedScope, cloneFn, controllers, previousBoundTranscludeFn);
6006
6049
  if (scopeCreated) {
6007
- clone.on('$destroy', bind(transcludedScope, transcludedScope.$destroy));
6050
+ clone.on('$destroy', function() { transcludedScope.$destroy(); });
6008
6051
  }
6009
6052
  return clone;
6010
6053
  };
6054
+
6055
+ return boundTranscludeFn;
6011
6056
  }
6012
6057
 
6013
6058
  /**
@@ -6185,6 +6230,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6185
6230
  templateDirective = previousCompileContext.templateDirective,
6186
6231
  nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
6187
6232
  hasTranscludeDirective = false,
6233
+ hasTemplate = false,
6188
6234
  hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
6189
6235
  $compileNode = templateAttrs.$$element = jqLite(compileNode),
6190
6236
  directive,
@@ -6275,6 +6321,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6275
6321
  }
6276
6322
 
6277
6323
  if (directive.template) {
6324
+ hasTemplate = true;
6278
6325
  assertNoDuplicate('template', templateDirective, directive, $compileNode);
6279
6326
  templateDirective = directive;
6280
6327
 
@@ -6289,7 +6336,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6289
6336
  if (jqLiteIsTextNode(directiveValue)) {
6290
6337
  $template = [];
6291
6338
  } else {
6292
- $template = jqLite(directiveValue);
6339
+ $template = jqLite(trim(directiveValue));
6293
6340
  }
6294
6341
  compileNode = $template[0];
6295
6342
 
@@ -6324,6 +6371,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6324
6371
  }
6325
6372
 
6326
6373
  if (directive.templateUrl) {
6374
+ hasTemplate = true;
6327
6375
  assertNoDuplicate('template', templateDirective, directive, $compileNode);
6328
6376
  templateDirective = directive;
6329
6377
 
@@ -6332,7 +6380,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6332
6380
  }
6333
6381
 
6334
6382
  nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
6335
- templateAttrs, jqCollection, childTranscludeFn, preLinkFns, postLinkFns, {
6383
+ templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
6336
6384
  controllerDirectives: controllerDirectives,
6337
6385
  newIsolateScopeDirective: newIsolateScopeDirective,
6338
6386
  templateDirective: templateDirective,
@@ -6360,7 +6408,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6360
6408
  }
6361
6409
 
6362
6410
  nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
6363
- nodeLinkFn.transclude = hasTranscludeDirective && childTranscludeFn;
6411
+ nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
6412
+ nodeLinkFn.templateOnThisElement = hasTemplate;
6413
+ nodeLinkFn.transclude = childTranscludeFn;
6414
+
6364
6415
  previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
6365
6416
 
6366
6417
  // might be normal or delayed nodeLinkFn depending on if templateUrl is present
@@ -6372,6 +6423,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6372
6423
  if (pre) {
6373
6424
  if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
6374
6425
  pre.require = directive.require;
6426
+ pre.directiveName = directiveName;
6375
6427
  if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
6376
6428
  pre = cloneAndAnnotateFn(pre, {isolateScope: true});
6377
6429
  }
@@ -6380,6 +6432,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6380
6432
  if (post) {
6381
6433
  if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
6382
6434
  post.require = directive.require;
6435
+ post.directiveName = directiveName;
6383
6436
  if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
6384
6437
  post = cloneAndAnnotateFn(post, {isolateScope: true});
6385
6438
  }
@@ -6388,7 +6441,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6388
6441
  }
6389
6442
 
6390
6443
 
6391
- function getControllers(require, $element, elementControllers) {
6444
+ function getControllers(directiveName, require, $element, elementControllers) {
6392
6445
  var value, retrievalMethod = 'data', optional = false;
6393
6446
  if (isString(require)) {
6394
6447
  while((value = require.charAt(0)) == '^' || value == '?') {
@@ -6414,7 +6467,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6414
6467
  } else if (isArray(require)) {
6415
6468
  value = [];
6416
6469
  forEach(require, function(require) {
6417
- value.push(getControllers(require, $element, elementControllers));
6470
+ value.push(getControllers(directiveName, require, $element, elementControllers));
6418
6471
  });
6419
6472
  }
6420
6473
  return value;
@@ -6437,7 +6490,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6437
6490
 
6438
6491
  isolateScope = scope.$new(true);
6439
6492
 
6440
- if (templateDirective && (templateDirective === newIsolateScopeDirective.$$originalDirective)) {
6493
+ if (templateDirective && (templateDirective === newIsolateScopeDirective ||
6494
+ templateDirective === newIsolateScopeDirective.$$originalDirective)) {
6441
6495
  $linkNode.data('$isolateScope', isolateScope) ;
6442
6496
  } else {
6443
6497
  $linkNode.data('$isolateScopeNoTemplate', isolateScope);
@@ -6557,7 +6611,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6557
6611
  try {
6558
6612
  linkFn = preLinkFns[i];
6559
6613
  linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
6560
- linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn);
6614
+ linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn);
6561
6615
  } catch (e) {
6562
6616
  $exceptionHandler(e, startingTag($element));
6563
6617
  }
@@ -6577,7 +6631,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6577
6631
  try {
6578
6632
  linkFn = postLinkFns[i];
6579
6633
  linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
6580
- linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn);
6634
+ linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn);
6581
6635
  } catch (e) {
6582
6636
  $exceptionHandler(e, startingTag($element));
6583
6637
  }
@@ -6663,7 +6717,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6663
6717
  // reapply the old attributes to the new element
6664
6718
  forEach(dst, function(value, key) {
6665
6719
  if (key.charAt(0) != '$') {
6666
- if (src[key]) {
6720
+ if (src[key] && src[key] !== value) {
6667
6721
  value += (key === 'style' ? ';' : ' ') + src[key];
6668
6722
  }
6669
6723
  dst.$set(key, value, true, srcAttr[key]);
@@ -6716,7 +6770,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6716
6770
  if (jqLiteIsTextNode(content)) {
6717
6771
  $template = [];
6718
6772
  } else {
6719
- $template = jqLite(content);
6773
+ $template = jqLite(trim(content));
6720
6774
  }
6721
6775
  compileNode = $template[0];
6722
6776
 
@@ -6752,7 +6806,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6752
6806
  });
6753
6807
  afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
6754
6808
 
6755
-
6756
6809
  while(linkQueue.length) {
6757
6810
  var scope = linkQueue.shift(),
6758
6811
  beforeTemplateLinkNode = linkQueue.shift(),
@@ -6774,8 +6827,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6774
6827
  // Copy in CSS classes from original node
6775
6828
  safeAddClass(jqLite(linkNode), oldClasses);
6776
6829
  }
6777
- if (afterTemplateNodeLinkFn.transclude) {
6778
- childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude);
6830
+ if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
6831
+ childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
6779
6832
  } else {
6780
6833
  childBoundTranscludeFn = boundTranscludeFn;
6781
6834
  }
@@ -6789,13 +6842,17 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6789
6842
  });
6790
6843
 
6791
6844
  return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
6845
+ var childBoundTranscludeFn = boundTranscludeFn;
6792
6846
  if (linkQueue) {
6793
6847
  linkQueue.push(scope);
6794
6848
  linkQueue.push(node);
6795
6849
  linkQueue.push(rootElement);
6796
- linkQueue.push(boundTranscludeFn);
6850
+ linkQueue.push(childBoundTranscludeFn);
6797
6851
  } else {
6798
- afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, boundTranscludeFn);
6852
+ if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
6853
+ childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
6854
+ }
6855
+ afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
6799
6856
  }
6800
6857
  };
6801
6858
  }
@@ -6820,23 +6877,31 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6820
6877
  }
6821
6878
 
6822
6879
 
6823
- function addTextInterpolateDirective(directives, text) {
6824
- var interpolateFn = $interpolate(text, true);
6825
- if (interpolateFn) {
6826
- directives.push({
6827
- priority: 0,
6828
- compile: valueFn(function textInterpolateLinkFn(scope, node) {
6829
- var parent = node.parent(),
6830
- bindings = parent.data('$binding') || [];
6831
- bindings.push(interpolateFn);
6832
- safeAddClass(parent.data('$binding', bindings), 'ng-binding');
6833
- scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
6834
- node[0].nodeValue = value;
6835
- });
6836
- })
6837
- });
6880
+ function addTextInterpolateDirective(directives, text) {
6881
+ var interpolateFn = $interpolate(text, true);
6882
+ if (interpolateFn) {
6883
+ directives.push({
6884
+ priority: 0,
6885
+ compile: function textInterpolateCompileFn(templateNode) {
6886
+ // when transcluding a template that has bindings in the root
6887
+ // then we don't have a parent and should do this in the linkFn
6888
+ var parent = templateNode.parent(), hasCompileParent = parent.length;
6889
+ if (hasCompileParent) safeAddClass(templateNode.parent(), 'ng-binding');
6890
+
6891
+ return function textInterpolateLinkFn(scope, node) {
6892
+ var parent = node.parent(),
6893
+ bindings = parent.data('$binding') || [];
6894
+ bindings.push(interpolateFn);
6895
+ parent.data('$binding', bindings);
6896
+ if (!hasCompileParent) safeAddClass(parent, 'ng-binding');
6897
+ scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
6898
+ node[0].nodeValue = value;
6899
+ });
6900
+ };
6901
+ }
6902
+ });
6903
+ }
6838
6904
  }
6839
- }
6840
6905
 
6841
6906
 
6842
6907
  function getTrustedContext(node, attrNormalizedName) {
@@ -6997,7 +7062,9 @@ function directiveNormalize(name) {
6997
7062
  * element attributes. The values reflect current binding state `{{ }}`. The normalization is
6998
7063
  * needed since all of these are treated as equivalent in Angular:
6999
7064
  *
7065
+ * ```
7000
7066
  * <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
7067
+ * ```
7001
7068
  */
7002
7069
 
7003
7070
  /**
@@ -7011,7 +7078,7 @@ function directiveNormalize(name) {
7011
7078
  /**
7012
7079
  * @ngdoc method
7013
7080
  * @name $compile.directive.Attributes#$set
7014
- * @function
7081
+ * @kind function
7015
7082
  *
7016
7083
  * @description
7017
7084
  * Set DOM element attribute value.
@@ -7329,9 +7396,9 @@ function $HttpProvider() {
7329
7396
  common: {
7330
7397
  'Accept': 'application/json, text/plain, */*'
7331
7398
  },
7332
- post: copy(CONTENT_TYPE_APPLICATION_JSON),
7333
- put: copy(CONTENT_TYPE_APPLICATION_JSON),
7334
- patch: copy(CONTENT_TYPE_APPLICATION_JSON)
7399
+ post: shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
7400
+ put: shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
7401
+ patch: shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
7335
7402
  },
7336
7403
 
7337
7404
  xsrfCookieName: 'XSRF-TOKEN',
@@ -7573,14 +7640,14 @@ function $HttpProvider() {
7573
7640
  *
7574
7641
  * There are two kinds of interceptors (and two kinds of rejection interceptors):
7575
7642
  *
7576
- * * `request`: interceptors get called with http `config` object. The function is free to
7577
- * modify the `config` or create a new one. The function needs to return the `config`
7578
- * directly or as a promise.
7643
+ * * `request`: interceptors get called with a http `config` object. The function is free to
7644
+ * modify the `config` object or create a new one. The function needs to return the `config`
7645
+ * object directly, or a promise containing the `config` or a new `config` object.
7579
7646
  * * `requestError`: interceptor gets called when a previous interceptor threw an error or
7580
7647
  * resolved with a rejection.
7581
7648
  * * `response`: interceptors get called with http `response` object. The function is free to
7582
- * modify the `response` or create a new one. The function needs to return the `response`
7583
- * directly or as a promise.
7649
+ * modify the `response` object or create a new one. The function needs to return the `response`
7650
+ * object directly, or as a promise containing the `response` or a new `response` object.
7584
7651
  * * `responseError`: interceptor gets called when a previous interceptor threw an error or
7585
7652
  * resolved with a rejection.
7586
7653
  *
@@ -7592,7 +7659,7 @@ function $HttpProvider() {
7592
7659
  * // optional method
7593
7660
  * 'request': function(config) {
7594
7661
  * // do something on success
7595
- * return config || $q.when(config);
7662
+ * return config;
7596
7663
  * },
7597
7664
  *
7598
7665
  * // optional method
@@ -7609,7 +7676,7 @@ function $HttpProvider() {
7609
7676
  * // optional method
7610
7677
  * 'response': function(response) {
7611
7678
  * // do something on success
7612
- * return response || $q.when(response);
7679
+ * return response;
7613
7680
  * },
7614
7681
  *
7615
7682
  * // optional method
@@ -7770,7 +7837,7 @@ function $HttpProvider() {
7770
7837
  * caching.
7771
7838
  * - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
7772
7839
  * that should abort the request when resolved.
7773
- * - **withCredentials** - `{boolean}` - whether to to set the `withCredentials` flag on the
7840
+ * - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
7774
7841
  * XHR object. See [requests with credentials]https://developer.mozilla.org/en/http_access_control#section_5
7775
7842
  * for more information.
7776
7843
  * - **responseType** - `{string}` - see
@@ -7808,11 +7875,11 @@ function $HttpProvider() {
7808
7875
  <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
7809
7876
  <button id="samplejsonpbtn"
7810
7877
  ng-click="updateModel('JSONP',
7811
- 'http://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
7878
+ 'https://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
7812
7879
  Sample JSONP
7813
7880
  </button>
7814
7881
  <button id="invalidjsonpbtn"
7815
- ng-click="updateModel('JSONP', 'http://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
7882
+ ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
7816
7883
  Invalid JSONP
7817
7884
  </button>
7818
7885
  <pre>http status code: {{status}}</pre>
@@ -7892,14 +7959,6 @@ function $HttpProvider() {
7892
7959
  config.headers = headers;
7893
7960
  config.method = uppercase(config.method);
7894
7961
 
7895
- var xsrfValue = urlIsSameOrigin(config.url)
7896
- ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName]
7897
- : undefined;
7898
- if (xsrfValue) {
7899
- headers[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
7900
- }
7901
-
7902
-
7903
7962
  var serverRequest = function(config) {
7904
7963
  headers = config.headers;
7905
7964
  var reqData = transformData(config.data, headersGetter(headers), config.transformRequest);
@@ -8164,7 +8223,7 @@ function $HttpProvider() {
8164
8223
  } else {
8165
8224
  // serving from cache
8166
8225
  if (isArray(cachedResp)) {
8167
- resolvePromise(cachedResp[1], cachedResp[0], copy(cachedResp[2]), cachedResp[3]);
8226
+ resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
8168
8227
  } else {
8169
8228
  resolvePromise(cachedResp, 200, {}, 'OK');
8170
8229
  }
@@ -8175,8 +8234,17 @@ function $HttpProvider() {
8175
8234
  }
8176
8235
  }
8177
8236
 
8178
- // if we won't have the response in cache, send the request to the backend
8237
+
8238
+ // if we won't have the response in cache, set the xsrf headers and
8239
+ // send the request to the backend
8179
8240
  if (isUndefined(cachedResp)) {
8241
+ var xsrfValue = urlIsSameOrigin(config.url)
8242
+ ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName]
8243
+ : undefined;
8244
+ if (xsrfValue) {
8245
+ reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
8246
+ }
8247
+
8180
8248
  $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
8181
8249
  config.withCredentials, config.responseType);
8182
8250
  }
@@ -8303,16 +8371,13 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
8303
8371
  var callbackId = '_' + (callbacks.counter++).toString(36);
8304
8372
  callbacks[callbackId] = function(data) {
8305
8373
  callbacks[callbackId].data = data;
8374
+ callbacks[callbackId].called = true;
8306
8375
  };
8307
8376
 
8308
8377
  var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
8309
- function() {
8310
- if (callbacks[callbackId].data) {
8311
- completeRequest(callback, 200, callbacks[callbackId].data);
8312
- } else {
8313
- completeRequest(callback, status || -2);
8314
- }
8315
- callbacks[callbackId] = angular.noop;
8378
+ callbackId, function(status, text) {
8379
+ completeRequest(callback, status, callbacks[callbackId].data, "", text);
8380
+ callbacks[callbackId] = noop;
8316
8381
  });
8317
8382
  } else {
8318
8383
 
@@ -8414,34 +8479,52 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
8414
8479
  }
8415
8480
  };
8416
8481
 
8417
- function jsonpReq(url, done) {
8482
+ function jsonpReq(url, callbackId, done) {
8418
8483
  // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
8419
8484
  // - fetches local scripts via XHR and evals them
8420
8485
  // - adds and immediately removes script elements from the document
8421
- var script = rawDocument.createElement('script'),
8422
- doneWrapper = function() {
8423
- script.onreadystatechange = script.onload = script.onerror = null;
8424
- rawDocument.body.removeChild(script);
8425
- if (done) done();
8426
- };
8427
-
8428
- script.type = 'text/javascript';
8486
+ var script = rawDocument.createElement('script'), callback = null;
8487
+ script.type = "text/javascript";
8429
8488
  script.src = url;
8489
+ script.async = true;
8490
+
8491
+ callback = function(event) {
8492
+ removeEventListenerFn(script, "load", callback);
8493
+ removeEventListenerFn(script, "error", callback);
8494
+ rawDocument.body.removeChild(script);
8495
+ script = null;
8496
+ var status = -1;
8497
+ var text = "unknown";
8498
+
8499
+ if (event) {
8500
+ if (event.type === "load" && !callbacks[callbackId].called) {
8501
+ event = { type: "error" };
8502
+ }
8503
+ text = event.type;
8504
+ status = event.type === "error" ? 404 : 200;
8505
+ }
8506
+
8507
+ if (done) {
8508
+ done(status, text);
8509
+ }
8510
+ };
8511
+
8512
+ addEventListenerFn(script, "load", callback);
8513
+ addEventListenerFn(script, "error", callback);
8430
8514
 
8431
- if (msie && msie <= 8) {
8515
+ if (msie <= 8) {
8432
8516
  script.onreadystatechange = function() {
8433
- if (/loaded|complete/.test(script.readyState)) {
8434
- doneWrapper();
8517
+ if (isString(script.readyState) && /loaded|complete/.test(script.readyState)) {
8518
+ script.onreadystatechange = null;
8519
+ callback({
8520
+ type: 'load'
8521
+ });
8435
8522
  }
8436
8523
  };
8437
- } else {
8438
- script.onload = script.onerror = function() {
8439
- doneWrapper();
8440
- };
8441
8524
  }
8442
8525
 
8443
8526
  rawDocument.body.appendChild(script);
8444
- return doneWrapper;
8527
+ return callback;
8445
8528
  }
8446
8529
  }
8447
8530
 
@@ -8450,7 +8533,7 @@ var $interpolateMinErr = minErr('$interpolate');
8450
8533
  /**
8451
8534
  * @ngdoc provider
8452
8535
  * @name $interpolateProvider
8453
- * @function
8536
+ * @kind function
8454
8537
  *
8455
8538
  * @description
8456
8539
  *
@@ -8468,7 +8551,7 @@ var $interpolateMinErr = minErr('$interpolate');
8468
8551
  });
8469
8552
 
8470
8553
 
8471
- customInterpolationApp.controller('DemoController', function DemoController() {
8554
+ customInterpolationApp.controller('DemoController', function() {
8472
8555
  this.label = "This binding is brought you by // interpolation symbols.";
8473
8556
  });
8474
8557
  </script>
@@ -8531,7 +8614,7 @@ function $InterpolateProvider() {
8531
8614
  /**
8532
8615
  * @ngdoc service
8533
8616
  * @name $interpolate
8534
- * @function
8617
+ * @kind function
8535
8618
  *
8536
8619
  * @requires $parse
8537
8620
  * @requires $sce
@@ -8623,10 +8706,24 @@ function $InterpolateProvider() {
8623
8706
  } else {
8624
8707
  part = $sce.valueOf(part);
8625
8708
  }
8626
- if (part === null || isUndefined(part)) {
8709
+ if (part == null) { // null || undefined
8627
8710
  part = '';
8628
- } else if (typeof part != 'string') {
8629
- part = toJson(part);
8711
+ } else {
8712
+ switch (typeof part) {
8713
+ case 'string':
8714
+ {
8715
+ break;
8716
+ }
8717
+ case 'number':
8718
+ {
8719
+ part = '' + part;
8720
+ break;
8721
+ }
8722
+ default:
8723
+ {
8724
+ part = toJson(part);
8725
+ }
8726
+ }
8630
8727
  }
8631
8728
  }
8632
8729
  concat[i] = part;
@@ -9137,7 +9234,7 @@ function LocationHashbangUrl(appBase, hashPrefix) {
9137
9234
  Matches paths for file protocol on windows,
9138
9235
  such as /C:/foo/bar, and captures only /foo/bar.
9139
9236
  */
9140
- var windowsFilePathExp = /^\/?.*?:(\/.*)/;
9237
+ var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
9141
9238
 
9142
9239
  var firstPathSegmentMatch;
9143
9240
 
@@ -9146,10 +9243,7 @@ function LocationHashbangUrl(appBase, hashPrefix) {
9146
9243
  url = url.replace(base, '');
9147
9244
  }
9148
9245
 
9149
- /*
9150
- * The input URL intentionally contains a
9151
- * first path segment that ends with a colon.
9152
- */
9246
+ // The input URL intentionally contains a first path segment that ends with a colon.
9153
9247
  if (windowsFilePathExp.exec(url)) {
9154
9248
  return path;
9155
9249
  }
@@ -9205,6 +9299,16 @@ function LocationHashbangInHtml5Url(appBase, hashPrefix) {
9205
9299
  return appBaseNoFile;
9206
9300
  }
9207
9301
  };
9302
+
9303
+ this.$$compose = function() {
9304
+ var search = toKeyValue(this.$$search),
9305
+ hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
9306
+
9307
+ this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
9308
+ // include hashPrefix in $$absUrl when $$url is empty so IE8 & 9 do not reload page because of removal of '#'
9309
+ this.$$absUrl = appBase + hashPrefix + this.$$url;
9310
+ };
9311
+
9208
9312
  }
9209
9313
 
9210
9314
 
@@ -9336,15 +9440,37 @@ LocationHashbangInHtml5Url.prototype =
9336
9440
  *
9337
9441
  * Change search part when called with parameter and return `$location`.
9338
9442
  *
9443
+ *
9444
+ * ```js
9445
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
9446
+ * var searchObject = $location.search();
9447
+ * // => {foo: 'bar', baz: 'xoxo'}
9448
+ *
9449
+ *
9450
+ * // set foo to 'yipee'
9451
+ * $location.search('foo', 'yipee');
9452
+ * // => $location
9453
+ * ```
9454
+ *
9339
9455
  * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
9340
- * hash object. Hash object may contain an array of values, which will be decoded as duplicates in
9341
- * the url.
9456
+ * hash object.
9457
+ *
9458
+ * When called with a single argument the method acts as a setter, setting the `search` component
9459
+ * of `$location` to the specified value.
9460
+ *
9461
+ * If the argument is a hash object containing an array of values, these values will be encoded
9462
+ * as duplicate search parameters in the url.
9342
9463
  *
9343
- * @param {(string|Array<string>)=} paramValue If `search` is a string, then `paramValue` will override only a
9344
- * single search parameter. If `paramValue` is an array, it will set the parameter as a
9345
- * comma-separated value. If `paramValue` is `null`, the parameter will be deleted.
9464
+ * @param {(string|Array<string>)=} paramValue If `search` is a string, then `paramValue` will
9465
+ * override only a single search property.
9346
9466
  *
9347
- * @return {string} search
9467
+ * If `paramValue` is an array, it will override the property of the `search` component of
9468
+ * `$location` specified via the first argument.
9469
+ *
9470
+ * If `paramValue` is `null`, the property specified via the first argument will be deleted.
9471
+ *
9472
+ * @return {Object} If called with no arguments returns the parsed `search` object. If called with
9473
+ * one or more arguments returns `$location` object itself.
9348
9474
  */
9349
9475
  search: function(search, paramValue) {
9350
9476
  switch (arguments.length) {
@@ -9557,6 +9683,39 @@ function $LocationProvider(){
9557
9683
  absHref = urlResolve(absHref.animVal).href;
9558
9684
  }
9559
9685
 
9686
+ // Make relative links work in HTML5 mode for legacy browsers (or at least IE8 & 9)
9687
+ // The href should be a regular url e.g. /link/somewhere or link/somewhere or ../somewhere or
9688
+ // somewhere#anchor or http://example.com/somewhere
9689
+ if (LocationMode === LocationHashbangInHtml5Url) {
9690
+ // get the actual href attribute - see
9691
+ // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
9692
+ var href = elm.attr('href') || elm.attr('xlink:href');
9693
+
9694
+ if (href.indexOf('://') < 0) { // Ignore absolute URLs
9695
+ var prefix = '#' + hashPrefix;
9696
+ if (href[0] == '/') {
9697
+ // absolute path - replace old path
9698
+ absHref = appBase + prefix + href;
9699
+ } else if (href[0] == '#') {
9700
+ // local anchor
9701
+ absHref = appBase + prefix + ($location.path() || '/') + href;
9702
+ } else {
9703
+ // relative path - join with current path
9704
+ var stack = $location.path().split("/"),
9705
+ parts = href.split("/");
9706
+ for (var i=0; i<parts.length; i++) {
9707
+ if (parts[i] == ".")
9708
+ continue;
9709
+ else if (parts[i] == "..")
9710
+ stack.pop();
9711
+ else if (parts[i].length)
9712
+ stack.push(parts[i]);
9713
+ }
9714
+ absHref = appBase + prefix + stack.join('/');
9715
+ }
9716
+ }
9717
+ }
9718
+
9560
9719
  var rewrittenUrl = $location.$$rewrite(absHref);
9561
9720
 
9562
9721
  if (absHref && !elm.attr('target') && rewrittenUrl && !event.isDefaultPrevented()) {
@@ -9917,9 +10076,6 @@ Lexer.prototype = {
9917
10076
 
9918
10077
  this.tokens = [];
9919
10078
 
9920
- var token;
9921
- var json = [];
9922
-
9923
10079
  while (this.index < this.text.length) {
9924
10080
  this.ch = this.text.charAt(this.index);
9925
10081
  if (this.is('"\'')) {
@@ -9928,19 +10084,11 @@ Lexer.prototype = {
9928
10084
  this.readNumber();
9929
10085
  } else if (this.isIdent(this.ch)) {
9930
10086
  this.readIdent();
9931
- // identifiers can only be if the preceding char was a { or ,
9932
- if (this.was('{,') && json[0] === '{' &&
9933
- (token = this.tokens[this.tokens.length - 1])) {
9934
- token.json = token.text.indexOf('.') === -1;
9935
- }
9936
10087
  } else if (this.is('(){}[].,;:?')) {
9937
10088
  this.tokens.push({
9938
10089
  index: this.index,
9939
- text: this.ch,
9940
- json: (this.was(':[,') && this.is('{[')) || this.is('}]:,')
10090
+ text: this.ch
9941
10091
  });
9942
- if (this.is('{[')) json.unshift(this.ch);
9943
- if (this.is('}]')) json.shift();
9944
10092
  this.index++;
9945
10093
  } else if (this.isWhitespace(this.ch)) {
9946
10094
  this.index++;
@@ -9961,8 +10109,7 @@ Lexer.prototype = {
9961
10109
  this.tokens.push({
9962
10110
  index: this.index,
9963
10111
  text: this.ch,
9964
- fn: fn,
9965
- json: (this.was('[,:') && this.is('+-'))
10112
+ fn: fn
9966
10113
  });
9967
10114
  this.index += 1;
9968
10115
  } else {
@@ -10045,7 +10192,8 @@ Lexer.prototype = {
10045
10192
  this.tokens.push({
10046
10193
  index: start,
10047
10194
  text: number,
10048
- json: true,
10195
+ literal: true,
10196
+ constant: true,
10049
10197
  fn: function() { return number; }
10050
10198
  });
10051
10199
  },
@@ -10097,7 +10245,8 @@ Lexer.prototype = {
10097
10245
  // OPERATORS is our own object so we don't need to use special hasOwnPropertyFn
10098
10246
  if (OPERATORS.hasOwnProperty(ident)) {
10099
10247
  token.fn = OPERATORS[ident];
10100
- token.json = OPERATORS[ident];
10248
+ token.literal = true;
10249
+ token.constant = true;
10101
10250
  } else {
10102
10251
  var getter = getterFn(ident, this.options, this.text);
10103
10252
  token.fn = extend(function(self, locals) {
@@ -10114,13 +10263,11 @@ Lexer.prototype = {
10114
10263
  if (methodName) {
10115
10264
  this.tokens.push({
10116
10265
  index:lastDot,
10117
- text: '.',
10118
- json: false
10266
+ text: '.'
10119
10267
  });
10120
10268
  this.tokens.push({
10121
10269
  index: lastDot + 1,
10122
- text: methodName,
10123
- json: false
10270
+ text: methodName
10124
10271
  });
10125
10272
  }
10126
10273
  },
@@ -10158,7 +10305,8 @@ Lexer.prototype = {
10158
10305
  index: start,
10159
10306
  text: rawString,
10160
10307
  string: string,
10161
- json: true,
10308
+ literal: true,
10309
+ constant: true,
10162
10310
  fn: function() { return string; }
10163
10311
  });
10164
10312
  return;
@@ -10190,28 +10338,12 @@ Parser.ZERO = extend(function () {
10190
10338
  Parser.prototype = {
10191
10339
  constructor: Parser,
10192
10340
 
10193
- parse: function (text, json) {
10341
+ parse: function (text) {
10194
10342
  this.text = text;
10195
10343
 
10196
- //TODO(i): strip all the obsolte json stuff from this file
10197
- this.json = json;
10198
-
10199
10344
  this.tokens = this.lexer.lex(text);
10200
10345
 
10201
- if (json) {
10202
- // The extra level of aliasing is here, just in case the lexer misses something, so that
10203
- // we prevent any accidental execution in JSON.
10204
- this.assignment = this.logicalOR;
10205
-
10206
- this.functionCall =
10207
- this.fieldAccess =
10208
- this.objectIndex =
10209
- this.filterChain = function() {
10210
- this.throwError('is not valid json', {text: text, index: 0});
10211
- };
10212
- }
10213
-
10214
- var value = json ? this.primary() : this.statements();
10346
+ var value = this.statements();
10215
10347
 
10216
10348
  if (this.tokens.length !== 0) {
10217
10349
  this.throwError('is an unexpected token', this.tokens[0]);
@@ -10238,10 +10370,8 @@ Parser.prototype = {
10238
10370
  if (!primary) {
10239
10371
  this.throwError('not a primary expression', token);
10240
10372
  }
10241
- if (token.json) {
10242
- primary.constant = true;
10243
- primary.literal = true;
10244
- }
10373
+ primary.literal = !!token.literal;
10374
+ primary.constant = !!token.constant;
10245
10375
  }
10246
10376
 
10247
10377
  var next, context;
@@ -10289,9 +10419,6 @@ Parser.prototype = {
10289
10419
  expect: function(e1, e2, e3, e4){
10290
10420
  var token = this.peek(e1, e2, e3, e4);
10291
10421
  if (token) {
10292
- if (this.json && !token.json) {
10293
- this.throwError('is not valid json', token);
10294
- }
10295
10422
  this.tokens.shift();
10296
10423
  return token;
10297
10424
  }
@@ -10926,7 +11053,7 @@ function getterFn(path, options, fullExp) {
10926
11053
  /**
10927
11054
  * @ngdoc provider
10928
11055
  * @name $parseProvider
10929
- * @function
11056
+ * @kind function
10930
11057
  *
10931
11058
  * @description
10932
11059
  * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
@@ -11045,7 +11172,7 @@ function $ParseProvider() {
11045
11172
 
11046
11173
  var lexer = new Lexer($parseOptions);
11047
11174
  var parser = new Parser(lexer, $filter, $parseOptions);
11048
- parsedExpression = parser.parse(exp, false);
11175
+ parsedExpression = parser.parse(exp);
11049
11176
 
11050
11177
  if (exp !== 'hasOwnProperty') {
11051
11178
  // Only cache the value if it's not going to mess up the cache object
@@ -11256,7 +11383,7 @@ function qFactory(nextTick, exceptionHandler) {
11256
11383
  /**
11257
11384
  * @ngdoc method
11258
11385
  * @name $q#defer
11259
- * @function
11386
+ * @kind function
11260
11387
  *
11261
11388
  * @description
11262
11389
  * Creates a `Deferred` object which represents a task which will finish in the future.
@@ -11413,7 +11540,7 @@ function qFactory(nextTick, exceptionHandler) {
11413
11540
  /**
11414
11541
  * @ngdoc method
11415
11542
  * @name $q#reject
11416
- * @function
11543
+ * @kind function
11417
11544
  *
11418
11545
  * @description
11419
11546
  * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
@@ -11473,7 +11600,7 @@ function qFactory(nextTick, exceptionHandler) {
11473
11600
  /**
11474
11601
  * @ngdoc method
11475
11602
  * @name $q#when
11476
- * @function
11603
+ * @kind function
11477
11604
  *
11478
11605
  * @description
11479
11606
  * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
@@ -11545,7 +11672,7 @@ function qFactory(nextTick, exceptionHandler) {
11545
11672
  /**
11546
11673
  * @ngdoc method
11547
11674
  * @name $q#all
11548
- * @function
11675
+ * @kind function
11549
11676
  *
11550
11677
  * @description
11551
11678
  * Combines multiple promises into a single promise that is resolved when all of the input
@@ -11636,7 +11763,7 @@ function $$RAFProvider(){ //rAF
11636
11763
  *
11637
11764
  * Loop operations are optimized by using while(count--) { ... }
11638
11765
  * - this means that in order to keep the same order of execution as addition we have to add
11639
- * items to the array at the beginning (shift) instead of at the end (push)
11766
+ * items to the array at the beginning (unshift) instead of at the end (push)
11640
11767
  *
11641
11768
  * Child scopes are created and removed often
11642
11769
  * - Using an array would be slow since inserts in middle are expensive so we use linked list
@@ -11770,7 +11897,7 @@ function $RootScopeProvider(){
11770
11897
  /**
11771
11898
  * @ngdoc method
11772
11899
  * @name $rootScope.Scope#$new
11773
- * @function
11900
+ * @kind function
11774
11901
  *
11775
11902
  * @description
11776
11903
  * Creates a new child {@link ng.$rootScope.Scope scope}.
@@ -11802,18 +11929,23 @@ function $RootScopeProvider(){
11802
11929
  child.$$asyncQueue = this.$$asyncQueue;
11803
11930
  child.$$postDigestQueue = this.$$postDigestQueue;
11804
11931
  } else {
11805
- ChildScope = function() {}; // should be anonymous; This is so that when the minifier munges
11806
- // the name it does not become random set of chars. This will then show up as class
11807
- // name in the web inspector.
11808
- ChildScope.prototype = this;
11809
- child = new ChildScope();
11810
- child.$id = nextUid();
11932
+ // Only create a child scope class if somebody asks for one,
11933
+ // but cache it to allow the VM to optimize lookups.
11934
+ if (!this.$$childScopeClass) {
11935
+ this.$$childScopeClass = function() {
11936
+ this.$$watchers = this.$$nextSibling =
11937
+ this.$$childHead = this.$$childTail = null;
11938
+ this.$$listeners = {};
11939
+ this.$$listenerCount = {};
11940
+ this.$id = nextUid();
11941
+ this.$$childScopeClass = null;
11942
+ };
11943
+ this.$$childScopeClass.prototype = this;
11944
+ }
11945
+ child = new this.$$childScopeClass();
11811
11946
  }
11812
11947
  child['this'] = child;
11813
- child.$$listeners = {};
11814
- child.$$listenerCount = {};
11815
11948
  child.$parent = this;
11816
- child.$$watchers = child.$$nextSibling = child.$$childHead = child.$$childTail = null;
11817
11949
  child.$$prevSibling = this.$$childTail;
11818
11950
  if (this.$$childHead) {
11819
11951
  this.$$childTail.$$nextSibling = child;
@@ -11827,7 +11959,7 @@ function $RootScopeProvider(){
11827
11959
  /**
11828
11960
  * @ngdoc method
11829
11961
  * @name $rootScope.Scope#$watch
11830
- * @function
11962
+ * @kind function
11831
11963
  *
11832
11964
  * @description
11833
11965
  * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
@@ -11839,10 +11971,14 @@ function $RootScopeProvider(){
11839
11971
  * {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
11840
11972
  * - The `listener` is called only when the value from the current `watchExpression` and the
11841
11973
  * previous call to `watchExpression` are not equal (with the exception of the initial run,
11842
- * see below). The inequality is determined according to
11843
- * {@link angular.equals} function. To save the value of the object for later comparison,
11844
- * the {@link angular.copy} function is used. It also means that watching complex options
11845
- * will have adverse memory and performance implications.
11974
+ * see below). Inequality is determined according to reference inequality,
11975
+ * [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
11976
+ * via the `!==` Javascript operator, unless `objectEquality == true`
11977
+ * (see next point)
11978
+ * - When `objectEquality == true`, inequality of the `watchExpression` is determined
11979
+ * according to the {@link angular.equals} function. To save the value of the object for
11980
+ * later comparison, the {@link angular.copy} function is used. This therefore means that
11981
+ * watching complex objects will have adverse memory and performance implications.
11846
11982
  * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
11847
11983
  * This is achieved by rerunning the watchers until no changes are detected. The rerun
11848
11984
  * iteration limit is 10 to prevent an infinite loop deadlock.
@@ -11877,13 +12013,17 @@ function $RootScopeProvider(){
11877
12013
  expect(scope.counter).toEqual(0);
11878
12014
 
11879
12015
  scope.$digest();
11880
- // no variable change
11881
- expect(scope.counter).toEqual(0);
12016
+ // the listener is always called during the first $digest loop after it was registered
12017
+ expect(scope.counter).toEqual(1);
11882
12018
 
11883
- scope.name = 'adam';
11884
12019
  scope.$digest();
12020
+ // but now it will not be called unless the value changes
11885
12021
  expect(scope.counter).toEqual(1);
11886
12022
 
12023
+ scope.name = 'adam';
12024
+ scope.$digest();
12025
+ expect(scope.counter).toEqual(2);
12026
+
11887
12027
 
11888
12028
 
11889
12029
  // Using a listener function
@@ -11969,7 +12109,7 @@ function $RootScopeProvider(){
11969
12109
  // the while loop reads in reverse order.
11970
12110
  array.unshift(watcher);
11971
12111
 
11972
- return function() {
12112
+ return function deregisterWatch() {
11973
12113
  arrayRemove(array, watcher);
11974
12114
  lastDirtyWatch = null;
11975
12115
  };
@@ -11979,7 +12119,7 @@ function $RootScopeProvider(){
11979
12119
  /**
11980
12120
  * @ngdoc method
11981
12121
  * @name $rootScope.Scope#$watchCollection
11982
- * @function
12122
+ * @kind function
11983
12123
  *
11984
12124
  * @description
11985
12125
  * Shallow watches the properties of an object and fires whenever any of the properties change
@@ -12155,7 +12295,7 @@ function $RootScopeProvider(){
12155
12295
  /**
12156
12296
  * @ngdoc method
12157
12297
  * @name $rootScope.Scope#$digest
12158
- * @function
12298
+ * @kind function
12159
12299
  *
12160
12300
  * @description
12161
12301
  * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
@@ -12190,12 +12330,16 @@ function $RootScopeProvider(){
12190
12330
  expect(scope.counter).toEqual(0);
12191
12331
 
12192
12332
  scope.$digest();
12193
- // no variable change
12194
- expect(scope.counter).toEqual(0);
12333
+ // the listener is always called during the first $digest loop after it was registered
12334
+ expect(scope.counter).toEqual(1);
12195
12335
 
12196
- scope.name = 'adam';
12197
12336
  scope.$digest();
12337
+ // but now it will not be called unless the value changes
12198
12338
  expect(scope.counter).toEqual(1);
12339
+
12340
+ scope.name = 'adam';
12341
+ scope.$digest();
12342
+ expect(scope.counter).toEqual(2);
12199
12343
  * ```
12200
12344
  *
12201
12345
  */
@@ -12247,7 +12391,7 @@ function $RootScopeProvider(){
12247
12391
  && isNaN(value) && isNaN(last)))) {
12248
12392
  dirty = true;
12249
12393
  lastDirtyWatch = watch;
12250
- watch.last = watch.eq ? copy(value) : value;
12394
+ watch.last = watch.eq ? copy(value, null) : value;
12251
12395
  watch.fn(value, ((last === initWatchVal) ? value : last), current);
12252
12396
  if (ttl < 5) {
12253
12397
  logIdx = 4 - ttl;
@@ -12322,7 +12466,7 @@ function $RootScopeProvider(){
12322
12466
  /**
12323
12467
  * @ngdoc method
12324
12468
  * @name $rootScope.Scope#$destroy
12325
- * @function
12469
+ * @kind function
12326
12470
  *
12327
12471
  * @description
12328
12472
  * Removes the current scope (and all of its children) from the parent scope. Removal implies
@@ -12383,7 +12527,7 @@ function $RootScopeProvider(){
12383
12527
  /**
12384
12528
  * @ngdoc method
12385
12529
  * @name $rootScope.Scope#$eval
12386
- * @function
12530
+ * @kind function
12387
12531
  *
12388
12532
  * @description
12389
12533
  * Executes the `expression` on the current scope and returns the result. Any exceptions in
@@ -12415,7 +12559,7 @@ function $RootScopeProvider(){
12415
12559
  /**
12416
12560
  * @ngdoc method
12417
12561
  * @name $rootScope.Scope#$evalAsync
12418
- * @function
12562
+ * @kind function
12419
12563
  *
12420
12564
  * @description
12421
12565
  * Executes the expression on the current scope at a later point in time.
@@ -12462,7 +12606,7 @@ function $RootScopeProvider(){
12462
12606
  /**
12463
12607
  * @ngdoc method
12464
12608
  * @name $rootScope.Scope#$apply
12465
- * @function
12609
+ * @kind function
12466
12610
  *
12467
12611
  * @description
12468
12612
  * `$apply()` is used to execute an expression in angular from outside of the angular
@@ -12524,7 +12668,7 @@ function $RootScopeProvider(){
12524
12668
  /**
12525
12669
  * @ngdoc method
12526
12670
  * @name $rootScope.Scope#$on
12527
- * @function
12671
+ * @kind function
12528
12672
  *
12529
12673
  * @description
12530
12674
  * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
@@ -12573,7 +12717,7 @@ function $RootScopeProvider(){
12573
12717
  /**
12574
12718
  * @ngdoc method
12575
12719
  * @name $rootScope.Scope#$emit
12576
- * @function
12720
+ * @kind function
12577
12721
  *
12578
12722
  * @description
12579
12723
  * Dispatches an event `name` upwards through the scope hierarchy notifying the
@@ -12641,7 +12785,7 @@ function $RootScopeProvider(){
12641
12785
  /**
12642
12786
  * @ngdoc method
12643
12787
  * @name $rootScope.Scope#$broadcast
12644
- * @function
12788
+ * @kind function
12645
12789
  *
12646
12790
  * @description
12647
12791
  * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
@@ -12889,7 +13033,7 @@ function adjustMatchers(matchers) {
12889
13033
  /**
12890
13034
  * @ngdoc service
12891
13035
  * @name $sceDelegate
12892
- * @function
13036
+ * @kind function
12893
13037
  *
12894
13038
  * @description
12895
13039
  *
@@ -12961,7 +13105,7 @@ function $SceDelegateProvider() {
12961
13105
  /**
12962
13106
  * @ngdoc method
12963
13107
  * @name $sceDelegateProvider#resourceUrlWhitelist
12964
- * @function
13108
+ * @kind function
12965
13109
  *
12966
13110
  * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
12967
13111
  * provided. This must be an array or null. A snapshot of this array is used so further
@@ -12990,7 +13134,7 @@ function $SceDelegateProvider() {
12990
13134
  /**
12991
13135
  * @ngdoc method
12992
13136
  * @name $sceDelegateProvider#resourceUrlBlacklist
12993
- * @function
13137
+ * @kind function
12994
13138
  *
12995
13139
  * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
12996
13140
  * provided. This must be an array or null. A snapshot of this array is used so further
@@ -13217,7 +13361,7 @@ function $SceDelegateProvider() {
13217
13361
  /**
13218
13362
  * @ngdoc service
13219
13363
  * @name $sce
13220
- * @function
13364
+ * @kind function
13221
13365
  *
13222
13366
  * @description
13223
13367
  *
@@ -13343,7 +13487,7 @@ function $SceDelegateProvider() {
13343
13487
  *
13344
13488
  * | Context | Notes |
13345
13489
  * |---------------------|----------------|
13346
- * | `$sce.HTML` | For HTML that's safe to source into the application. The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. |
13490
+ * | `$sce.HTML` | For HTML that's safe to source into the application. The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. If an unsafe value is encountered and the {@link ngSanitize $sanitize} module is present this will sanitize the value instead of throwing an error. |
13347
13491
  * | `$sce.CSS` | For CSS that's safe to source into the application. Currently unused. Feel free to use it in your own directives. |
13348
13492
  * | `$sce.URL` | For URLs that are safe to follow as links. Currently unused (`<a href=` and `<img src=` sanitize their urls and don't constitute an SCE context. |
13349
13493
  * | `$sce.RESOURCE_URL` | For URLs that are not only safe to follow as links, but whose contents are also safe to include in your application. Examples include `ng-include`, `src` / `ngSrc` bindings for tags other than `IMG` (e.g. `IFRAME`, `OBJECT`, etc.) <br><br>Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` does and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` are required. |
@@ -13367,7 +13511,7 @@ function $SceDelegateProvider() {
13367
13511
  * - `**`: matches zero or more occurrences of *any* character. As such, it's not
13368
13512
  * not appropriate to use in for a scheme, domain, etc. as it would match too much. (e.g.
13369
13513
  * http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
13370
- * not have been the intention.) It's usage at the very end of the path is ok. (e.g.
13514
+ * not have been the intention.) Its usage at the very end of the path is ok. (e.g.
13371
13515
  * http://foo.example.com/templates/**).
13372
13516
  * - **RegExp** (*see caveat below*)
13373
13517
  * - *Caveat*: While regular expressions are powerful and offer great flexibility, their syntax
@@ -13488,7 +13632,7 @@ function $SceProvider() {
13488
13632
  /**
13489
13633
  * @ngdoc method
13490
13634
  * @name $sceProvider#enabled
13491
- * @function
13635
+ * @kind function
13492
13636
  *
13493
13637
  * @param {boolean=} value If provided, then enables/disables SCE.
13494
13638
  * @return {boolean} true if SCE is enabled, false otherwise.
@@ -13561,12 +13705,12 @@ function $SceProvider() {
13561
13705
  'document. See http://docs.angularjs.org/api/ng.$sce for more information.');
13562
13706
  }
13563
13707
 
13564
- var sce = copy(SCE_CONTEXTS);
13708
+ var sce = shallowCopy(SCE_CONTEXTS);
13565
13709
 
13566
13710
  /**
13567
13711
  * @ngdoc method
13568
13712
  * @name $sce#isEnabled
13569
- * @function
13713
+ * @kind function
13570
13714
  *
13571
13715
  * @return {Boolean} true if SCE is enabled, false otherwise. If you want to set the value, you
13572
13716
  * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
@@ -14101,7 +14245,7 @@ var originUrl = urlResolve(window.location.href, true);
14101
14245
  * https://github.com/angular/angular.js/pull/2902
14102
14246
  * http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
14103
14247
  *
14104
- * @function
14248
+ * @kind function
14105
14249
  * @param {string} url The URL to be parsed.
14106
14250
  * @description Normalizes and parses a URL.
14107
14251
  * @returns {object} Returns the normalized URL as a dictionary.
@@ -14265,7 +14409,7 @@ function $WindowProvider(){
14265
14409
  /**
14266
14410
  * @ngdoc service
14267
14411
  * @name $filter
14268
- * @function
14412
+ * @kind function
14269
14413
  * @description
14270
14414
  * Filters are used for formatting data displayed to the user.
14271
14415
  *
@@ -14275,7 +14419,24 @@ function $WindowProvider(){
14275
14419
  *
14276
14420
  * @param {String} name Name of the filter function to retrieve
14277
14421
  * @return {Function} the filter function
14278
- */
14422
+ * @example
14423
+ <example name="$filter" module="filterExample">
14424
+ <file name="index.html">
14425
+ <div ng-controller="MainCtrl">
14426
+ <h3>{{ originalText }}</h3>
14427
+ <h3>{{ filteredText }}</h3>
14428
+ </div>
14429
+ </file>
14430
+
14431
+ <file name="script.js">
14432
+ angular.module('filterExample', [])
14433
+ .controller('MainCtrl', function($scope, $filter) {
14434
+ $scope.originalText = 'hello';
14435
+ $scope.filteredText = $filter('uppercase')($scope.originalText);
14436
+ });
14437
+ </file>
14438
+ </example>
14439
+ */
14279
14440
  $FilterProvider.$inject = ['$provide'];
14280
14441
  function $FilterProvider($provide) {
14281
14442
  var suffix = 'Filter';
@@ -14335,7 +14496,7 @@ function $FilterProvider($provide) {
14335
14496
  /**
14336
14497
  * @ngdoc filter
14337
14498
  * @name filter
14338
- * @function
14499
+ * @kind function
14339
14500
  *
14340
14501
  * @description
14341
14502
  * Selects a subset of items from `array` and returns it as a new array.
@@ -14367,15 +14528,15 @@ function $FilterProvider($provide) {
14367
14528
  *
14368
14529
  * Can be one of:
14369
14530
  *
14370
- * - `function(actual, expected)`:
14371
- * The function will be given the object value and the predicate value to compare and
14372
- * should return true if the item should be included in filtered result.
14531
+ * - `function(actual, expected)`:
14532
+ * The function will be given the object value and the predicate value to compare and
14533
+ * should return true if the item should be included in filtered result.
14373
14534
  *
14374
- * - `true`: A shorthand for `function(actual, expected) { return angular.equals(expected, actual)}`.
14375
- * this is essentially strict comparison of expected and actual.
14535
+ * - `true`: A shorthand for `function(actual, expected) { return angular.equals(expected, actual)}`.
14536
+ * this is essentially strict comparison of expected and actual.
14376
14537
  *
14377
- * - `false|undefined`: A short hand for a function which will look for a substring match in case
14378
- * insensitive way.
14538
+ * - `false|undefined`: A short hand for a function which will look for a substring match in case
14539
+ * insensitive way.
14379
14540
  *
14380
14541
  * @example
14381
14542
  <example>
@@ -14554,7 +14715,7 @@ function filterFilter() {
14554
14715
  /**
14555
14716
  * @ngdoc filter
14556
14717
  * @name currency
14557
- * @function
14718
+ * @kind function
14558
14719
  *
14559
14720
  * @description
14560
14721
  * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
@@ -14611,7 +14772,7 @@ function currencyFilter($locale) {
14611
14772
  /**
14612
14773
  * @ngdoc filter
14613
14774
  * @name number
14614
- * @function
14775
+ * @kind function
14615
14776
  *
14616
14777
  * @description
14617
14778
  * Formats a number as text.
@@ -14696,8 +14857,8 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
14696
14857
  fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
14697
14858
  }
14698
14859
 
14699
- var pow = Math.pow(10, fractionSize);
14700
- number = Math.round(number * pow) / pow;
14860
+ var pow = Math.pow(10, fractionSize + 1);
14861
+ number = Math.floor(number * pow + 5) / pow;
14701
14862
  var fraction = ('' + number).split(DECIMAL_SEP);
14702
14863
  var whole = fraction[0];
14703
14864
  fraction = fraction[1] || '';
@@ -14823,7 +14984,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
14823
14984
  /**
14824
14985
  * @ngdoc filter
14825
14986
  * @name date
14826
- * @function
14987
+ * @kind function
14827
14988
  *
14828
14989
  * @description
14829
14990
  * Formats `date` to a string based on the requested `format`.
@@ -14980,7 +15141,7 @@ function dateFilter($locale) {
14980
15141
  /**
14981
15142
  * @ngdoc filter
14982
15143
  * @name json
14983
- * @function
15144
+ * @kind function
14984
15145
  *
14985
15146
  * @description
14986
15147
  * Allows you to convert a JavaScript object into JSON string.
@@ -15015,7 +15176,7 @@ function jsonFilter() {
15015
15176
  /**
15016
15177
  * @ngdoc filter
15017
15178
  * @name lowercase
15018
- * @function
15179
+ * @kind function
15019
15180
  * @description
15020
15181
  * Converts string to lowercase.
15021
15182
  * @see angular.lowercase
@@ -15026,7 +15187,7 @@ var lowercaseFilter = valueFn(lowercase);
15026
15187
  /**
15027
15188
  * @ngdoc filter
15028
15189
  * @name uppercase
15029
- * @function
15190
+ * @kind function
15030
15191
  * @description
15031
15192
  * Converts string to uppercase.
15032
15193
  * @see angular.uppercase
@@ -15036,7 +15197,7 @@ var uppercaseFilter = valueFn(uppercase);
15036
15197
  /**
15037
15198
  * @ngdoc filter
15038
15199
  * @name limitTo
15039
- * @function
15200
+ * @kind function
15040
15201
  *
15041
15202
  * @description
15042
15203
  * Creates a new array or string containing only a specified number of elements. The elements
@@ -15106,7 +15267,11 @@ function limitToFilter(){
15106
15267
  return function(input, limit) {
15107
15268
  if (!isArray(input) && !isString(input)) return input;
15108
15269
 
15109
- limit = int(limit);
15270
+ if (Math.abs(Number(limit)) === Infinity) {
15271
+ limit = Number(limit);
15272
+ } else {
15273
+ limit = int(limit);
15274
+ }
15110
15275
 
15111
15276
  if (isString(input)) {
15112
15277
  //NaN check on limit
@@ -15145,10 +15310,12 @@ function limitToFilter(){
15145
15310
  /**
15146
15311
  * @ngdoc filter
15147
15312
  * @name orderBy
15148
- * @function
15313
+ * @kind function
15149
15314
  *
15150
15315
  * @description
15151
- * Orders a specified `array` by the `expression` predicate.
15316
+ * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
15317
+ * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
15318
+ * correctly, make sure they are actually being saved as numbers and not strings.
15152
15319
  *
15153
15320
  * @param {Array} array The array to sort.
15154
15321
  * @param {function(*)|string|Array.<(function(*)|string)>} expression A predicate to be
@@ -15201,6 +15368,51 @@ function limitToFilter(){
15201
15368
  </div>
15202
15369
  </file>
15203
15370
  </example>
15371
+ *
15372
+ * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
15373
+ * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the
15374
+ * desired parameters.
15375
+ *
15376
+ * Example:
15377
+ *
15378
+ * @example
15379
+ <example>
15380
+ <file name="index.html">
15381
+ <div ng-controller="Ctrl">
15382
+ <table class="friend">
15383
+ <tr>
15384
+ <th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
15385
+ (<a href="" ng-click="order('-name',false)">^</a>)</th>
15386
+ <th><a href="" ng-click="reverse=!reverse;order('phone', reverse)">Phone Number</a></th>
15387
+ <th><a href="" ng-click="reverse=!reverse;order('age',reverse)">Age</a></th>
15388
+ </tr>
15389
+ <tr ng-repeat="friend in friends">
15390
+ <td>{{friend.name}}</td>
15391
+ <td>{{friend.phone}}</td>
15392
+ <td>{{friend.age}}</td>
15393
+ </tr>
15394
+ </table>
15395
+ </div>
15396
+ </file>
15397
+
15398
+ <file name="script.js">
15399
+ function Ctrl($scope, $filter) {
15400
+ var orderBy = $filter('orderBy');
15401
+ $scope.friends = [
15402
+ { name: 'John', phone: '555-1212', age: 10 },
15403
+ { name: 'Mary', phone: '555-9876', age: 19 },
15404
+ { name: 'Mike', phone: '555-4321', age: 21 },
15405
+ { name: 'Adam', phone: '555-5678', age: 35 },
15406
+ { name: 'Julie', phone: '555-8765', age: 29 }
15407
+ ];
15408
+
15409
+ $scope.order = function(predicate, reverse) {
15410
+ $scope.friends = orderBy($scope.friends, predicate, reverse);
15411
+ };
15412
+ $scope.order('-age',false);
15413
+ }
15414
+ </file>
15415
+ </example>
15204
15416
  */
15205
15417
  orderByFilter.$inject = ['$parse'];
15206
15418
  function orderByFilter($parse){
@@ -15752,7 +15964,7 @@ var nullFormCtrl = {
15752
15964
  * - `url`
15753
15965
  *
15754
15966
  * @description
15755
- * `FormController` keeps track of all its controls and nested forms as well as state of them,
15967
+ * `FormController` keeps track of all its controls and nested forms as well as the state of them,
15756
15968
  * such as being valid/invalid or dirty/pristine.
15757
15969
  *
15758
15970
  * Each {@link ng.directive:form form} directive creates an instance
@@ -16594,6 +16806,8 @@ function addNativeHtml5Validators(ctrl, validatorName, element) {
16594
16806
 
16595
16807
  function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16596
16808
  var validity = element.prop('validity');
16809
+ var placeholder = element[0].placeholder, noevent = {};
16810
+
16597
16811
  // In composition mode, users are still inputing intermediate text buffer,
16598
16812
  // hold the listener until composition is done.
16599
16813
  // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
@@ -16610,10 +16824,19 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16610
16824
  });
16611
16825
  }
16612
16826
 
16613
- var listener = function() {
16827
+ var listener = function(ev) {
16614
16828
  if (composing) return;
16615
16829
  var value = element.val();
16616
16830
 
16831
+ // IE (11 and under) seem to emit an 'input' event if the placeholder value changes.
16832
+ // We don't want to dirty the value when this happens, so we abort here. Unfortunately,
16833
+ // IE also sends input events for other non-input-related things, (such as focusing on a
16834
+ // form control), so this change is not entirely enough to solve this.
16835
+ if (msie && (ev || noevent).type === 'input' && element[0].placeholder !== placeholder) {
16836
+ placeholder = element[0].placeholder;
16837
+ return;
16838
+ }
16839
+
16617
16840
  // By default we will trim the value
16618
16841
  // If the attribute ng-trim exists we will avoid trimming
16619
16842
  // e.g. <input ng-model="foo" ng-trim="false">
@@ -16877,6 +17100,7 @@ function checkboxInputType(scope, element, attr, ctrl) {
16877
17100
  * patterns defined as scope expressions.
16878
17101
  * @param {string=} ngChange Angular expression to be executed when input changes due to user
16879
17102
  * interaction with the input element.
17103
+ * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
16880
17104
  */
16881
17105
 
16882
17106
 
@@ -17026,14 +17250,14 @@ var VALID_CLASS = 'ng-valid',
17026
17250
  * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
17027
17251
  the model value changes. Each function is called, in turn, passing the value through to the
17028
17252
  next. Used to format / convert values for display in the control and validation.
17029
- * ```js
17030
- * function formatter(value) {
17031
- * if (value) {
17032
- * return value.toUpperCase();
17033
- * }
17034
- * }
17035
- * ngModel.$formatters.push(formatter);
17036
- * ```
17253
+ * ```js
17254
+ * function formatter(value) {
17255
+ * if (value) {
17256
+ * return value.toUpperCase();
17257
+ * }
17258
+ * }
17259
+ * ngModel.$formatters.push(formatter);
17260
+ * ```
17037
17261
  *
17038
17262
  * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
17039
17263
  * view value has changed. It is called with no arguments, and its return value is ignored.
@@ -17062,7 +17286,12 @@ var VALID_CLASS = 'ng-valid',
17062
17286
  * Note that `contenteditable` is an HTML5 attribute, which tells the browser to let the element
17063
17287
  * contents be edited in place by the user. This will not work on older browsers.
17064
17288
  *
17065
- * <example name="NgModelController" module="customControl">
17289
+ * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
17290
+ * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
17291
+ * However, as we are using `$sce` the model can still decide to to provide unsafe content if it marks
17292
+ * that content using the `$sce` service.
17293
+ *
17294
+ * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
17066
17295
  <file name="style.css">
17067
17296
  [contenteditable] {
17068
17297
  border: 1px solid black;
@@ -17076,8 +17305,8 @@ var VALID_CLASS = 'ng-valid',
17076
17305
 
17077
17306
  </file>
17078
17307
  <file name="script.js">
17079
- angular.module('customControl', []).
17080
- directive('contenteditable', function() {
17308
+ angular.module('customControl', ['ngSanitize']).
17309
+ directive('contenteditable', ['$sce', function($sce) {
17081
17310
  return {
17082
17311
  restrict: 'A', // only activate on element attribute
17083
17312
  require: '?ngModel', // get a hold of NgModelController
@@ -17086,7 +17315,7 @@ var VALID_CLASS = 'ng-valid',
17086
17315
 
17087
17316
  // Specify how UI should be updated
17088
17317
  ngModel.$render = function() {
17089
- element.html(ngModel.$viewValue || '');
17318
+ element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
17090
17319
  };
17091
17320
 
17092
17321
  // Listen for change events to enable binding
@@ -17107,7 +17336,7 @@ var VALID_CLASS = 'ng-valid',
17107
17336
  }
17108
17337
  }
17109
17338
  };
17110
- });
17339
+ }]);
17111
17340
  </file>
17112
17341
  <file name="index.html">
17113
17342
  <form name="myForm">
@@ -17781,14 +18010,19 @@ var ngValueDirective = function() {
17781
18010
  </file>
17782
18011
  </example>
17783
18012
  */
17784
- var ngBindDirective = ngDirective(function(scope, element, attr) {
17785
- element.addClass('ng-binding').data('$binding', attr.ngBind);
17786
- scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
17787
- // We are purposefully using == here rather than === because we want to
17788
- // catch when value is "null or undefined"
17789
- // jshint -W041
17790
- element.text(value == undefined ? '' : value);
17791
- });
18013
+ var ngBindDirective = ngDirective({
18014
+ compile: function(templateElement) {
18015
+ templateElement.addClass('ng-binding');
18016
+ return function (scope, element, attr) {
18017
+ element.data('$binding', attr.ngBind);
18018
+ scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
18019
+ // We are purposefully using == here rather than === because we want to
18020
+ // catch when value is "null or undefined"
18021
+ // jshint -W041
18022
+ element.text(value == undefined ? '' : value);
18023
+ });
18024
+ };
18025
+ }
17792
18026
  });
17793
18027
 
17794
18028
 
@@ -17932,7 +18166,7 @@ function classDirective(name, selector) {
17932
18166
  scope.$watch('$index', function($index, old$index) {
17933
18167
  // jshint bitwise: false
17934
18168
  var mod = $index & 1;
17935
- if (mod !== old$index & 1) {
18169
+ if (mod !== (old$index & 1)) {
17936
18170
  var classes = arrayClasses(scope.$eval(attr[name]));
17937
18171
  mod === selector ?
17938
18172
  addClasses(classes) :
@@ -17991,7 +18225,7 @@ function classDirective(name, selector) {
17991
18225
  updateClasses(oldClasses, newClasses);
17992
18226
  }
17993
18227
  }
17994
- oldVal = copy(newVal);
18228
+ oldVal = shallowCopy(newVal);
17995
18229
  }
17996
18230
  }
17997
18231
  };
@@ -18019,7 +18253,7 @@ function classDirective(name, selector) {
18019
18253
  var classes = [], i = 0;
18020
18254
  forEach(classVal, function(v, k) {
18021
18255
  if (v) {
18022
- classes.push(k);
18256
+ classes = classes.concat(k.split(' '));
18023
18257
  }
18024
18258
  });
18025
18259
  return classes;
@@ -18344,7 +18578,7 @@ var ngCloakDirective = ngDirective({
18344
18578
  *
18345
18579
  * MVC components in angular:
18346
18580
  *
18347
- * * Model — The Model is scope properties; scopes are attached to the DOM where scope properties
18581
+ * * Model — Models are the properties of a scope; scopes are attached to the DOM where scope properties
18348
18582
  * are accessed through bindings.
18349
18583
  * * View — The template (HTML with data bindings) that is rendered into the View.
18350
18584
  * * Controller — The `ngController` directive specifies a Controller class; the class contains business
@@ -18365,165 +18599,186 @@ var ngCloakDirective = ngDirective({
18365
18599
  * @example
18366
18600
  * Here is a simple form for editing user contact information. Adding, removing, clearing, and
18367
18601
  * greeting are methods declared on the controller (see source tab). These methods can
18368
- * easily be called from the angular markup. Notice that the scope becomes the `this` for the
18369
- * controller's instance. This allows for easy access to the view data from the controller. Also
18370
- * notice that any changes to the data are automatically reflected in the View without the need
18371
- * for a manual update. The example is shown in two different declaration styles you may use
18372
- * according to preference.
18373
- <example>
18374
- <file name="index.html">
18375
- <script>
18376
- function SettingsController1() {
18377
- this.name = "John Smith";
18378
- this.contacts = [
18379
- {type: 'phone', value: '408 555 1212'},
18380
- {type: 'email', value: 'john.smith@example.org'} ];
18381
- };
18382
-
18383
- SettingsController1.prototype.greet = function() {
18384
- alert(this.name);
18385
- };
18386
-
18387
- SettingsController1.prototype.addContact = function() {
18388
- this.contacts.push({type: 'email', value: 'yourname@example.org'});
18389
- };
18390
-
18391
- SettingsController1.prototype.removeContact = function(contactToRemove) {
18392
- var index = this.contacts.indexOf(contactToRemove);
18393
- this.contacts.splice(index, 1);
18394
- };
18395
-
18396
- SettingsController1.prototype.clearContact = function(contact) {
18397
- contact.type = 'phone';
18398
- contact.value = '';
18399
- };
18400
- </script>
18401
- <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
18402
- Name: <input type="text" ng-model="settings.name"/>
18403
- [ <a href="" ng-click="settings.greet()">greet</a> ]<br/>
18404
- Contact:
18405
- <ul>
18406
- <li ng-repeat="contact in settings.contacts">
18407
- <select ng-model="contact.type">
18408
- <option>phone</option>
18409
- <option>email</option>
18410
- </select>
18411
- <input type="text" ng-model="contact.value"/>
18412
- [ <a href="" ng-click="settings.clearContact(contact)">clear</a>
18413
- | <a href="" ng-click="settings.removeContact(contact)">X</a> ]
18414
- </li>
18415
- <li>[ <a href="" ng-click="settings.addContact()">add</a> ]</li>
18416
- </ul>
18417
- </div>
18418
- </file>
18419
- <file name="protractor.js" type="protractor">
18420
- it('should check controller as', function() {
18421
- var container = element(by.id('ctrl-as-exmpl'));
18422
-
18423
- expect(container.findElement(by.model('settings.name'))
18424
- .getAttribute('value')).toBe('John Smith');
18425
-
18426
- var firstRepeat =
18427
- container.findElement(by.repeater('contact in settings.contacts').row(0));
18428
- var secondRepeat =
18429
- container.findElement(by.repeater('contact in settings.contacts').row(1));
18430
-
18431
- expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18432
- .toBe('408 555 1212');
18433
- expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18434
- .toBe('john.smith@example.org');
18435
-
18436
- firstRepeat.findElement(by.linkText('clear')).click();
18437
-
18438
- expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18439
- .toBe('');
18440
-
18441
- container.findElement(by.linkText('add')).click();
18442
-
18443
- expect(container.findElement(by.repeater('contact in settings.contacts').row(2))
18444
- .findElement(by.model('contact.value'))
18445
- .getAttribute('value'))
18446
- .toBe('yourname@example.org');
18447
- });
18448
- </file>
18449
- </example>
18450
- <example>
18451
- <file name="index.html">
18452
- <script>
18453
- function SettingsController2($scope) {
18454
- $scope.name = "John Smith";
18455
- $scope.contacts = [
18456
- {type:'phone', value:'408 555 1212'},
18457
- {type:'email', value:'john.smith@example.org'} ];
18458
-
18459
- $scope.greet = function() {
18460
- alert(this.name);
18461
- };
18462
-
18463
- $scope.addContact = function() {
18464
- this.contacts.push({type:'email', value:'yourname@example.org'});
18465
- };
18466
-
18467
- $scope.removeContact = function(contactToRemove) {
18468
- var index = this.contacts.indexOf(contactToRemove);
18469
- this.contacts.splice(index, 1);
18470
- };
18471
-
18472
- $scope.clearContact = function(contact) {
18473
- contact.type = 'phone';
18474
- contact.value = '';
18475
- };
18476
- }
18477
- </script>
18478
- <div id="ctrl-exmpl" ng-controller="SettingsController2">
18479
- Name: <input type="text" ng-model="name"/>
18480
- [ <a href="" ng-click="greet()">greet</a> ]<br/>
18481
- Contact:
18482
- <ul>
18483
- <li ng-repeat="contact in contacts">
18484
- <select ng-model="contact.type">
18485
- <option>phone</option>
18486
- <option>email</option>
18487
- </select>
18488
- <input type="text" ng-model="contact.value"/>
18489
- [ <a href="" ng-click="clearContact(contact)">clear</a>
18490
- | <a href="" ng-click="removeContact(contact)">X</a> ]
18491
- </li>
18492
- <li>[ <a href="" ng-click="addContact()">add</a> ]</li>
18493
- </ul>
18494
- </div>
18495
- </file>
18496
- <file name="protractor.js" type="protractor">
18497
- it('should check controller', function() {
18498
- var container = element(by.id('ctrl-exmpl'));
18499
-
18500
- expect(container.findElement(by.model('name'))
18501
- .getAttribute('value')).toBe('John Smith');
18502
-
18503
- var firstRepeat =
18504
- container.findElement(by.repeater('contact in contacts').row(0));
18505
- var secondRepeat =
18506
- container.findElement(by.repeater('contact in contacts').row(1));
18507
-
18508
- expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18509
- .toBe('408 555 1212');
18510
- expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18511
- .toBe('john.smith@example.org');
18512
-
18513
- firstRepeat.findElement(by.linkText('clear')).click();
18514
-
18515
- expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18516
- .toBe('');
18517
-
18518
- container.findElement(by.linkText('add')).click();
18519
-
18520
- expect(container.findElement(by.repeater('contact in contacts').row(2))
18521
- .findElement(by.model('contact.value'))
18522
- .getAttribute('value'))
18523
- .toBe('yourname@example.org');
18524
- });
18525
- </file>
18526
- </example>
18602
+ * easily be called from the angular markup. Any changes to the data are automatically reflected
18603
+ * in the View without the need for a manual update.
18604
+ *
18605
+ * Two different declaration styles are included below:
18606
+ *
18607
+ * * one binds methods and properties directly onto the controller using `this`:
18608
+ * `ng-controller="SettingsController1 as settings"`
18609
+ * * one injects `$scope` into the controller:
18610
+ * `ng-controller="SettingsController2"`
18611
+ *
18612
+ * The second option is more common in the Angular community, and is generally used in boilerplates
18613
+ * and in this guide. However, there are advantages to binding properties directly to the controller
18614
+ * and avoiding scope.
18615
+ *
18616
+ * * Using `controller as` makes it obvious which controller you are accessing in the template when
18617
+ * multiple controllers apply to an element.
18618
+ * * If you are writing your controllers as classes you have easier access to the properties and
18619
+ * methods, which will appear on the scope, from inside the controller code.
18620
+ * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
18621
+ * inheritance masking primitives.
18622
+ *
18623
+ * This example demonstrates the `controller as` syntax.
18624
+ *
18625
+ * <example name="ngControllerAs">
18626
+ * <file name="index.html">
18627
+ * <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
18628
+ * Name: <input type="text" ng-model="settings.name"/>
18629
+ * [ <a href="" ng-click="settings.greet()">greet</a> ]<br/>
18630
+ * Contact:
18631
+ * <ul>
18632
+ * <li ng-repeat="contact in settings.contacts">
18633
+ * <select ng-model="contact.type">
18634
+ * <option>phone</option>
18635
+ * <option>email</option>
18636
+ * </select>
18637
+ * <input type="text" ng-model="contact.value"/>
18638
+ * [ <a href="" ng-click="settings.clearContact(contact)">clear</a>
18639
+ * | <a href="" ng-click="settings.removeContact(contact)">X</a> ]
18640
+ * </li>
18641
+ * <li>[ <a href="" ng-click="settings.addContact()">add</a> ]</li>
18642
+ * </ul>
18643
+ * </div>
18644
+ * </file>
18645
+ * <file name="app.js">
18646
+ * function SettingsController1() {
18647
+ * this.name = "John Smith";
18648
+ * this.contacts = [
18649
+ * {type: 'phone', value: '408 555 1212'},
18650
+ * {type: 'email', value: 'john.smith@example.org'} ];
18651
+ * }
18652
+ *
18653
+ * SettingsController1.prototype.greet = function() {
18654
+ * alert(this.name);
18655
+ * };
18656
+ *
18657
+ * SettingsController1.prototype.addContact = function() {
18658
+ * this.contacts.push({type: 'email', value: 'yourname@example.org'});
18659
+ * };
18660
+ *
18661
+ * SettingsController1.prototype.removeContact = function(contactToRemove) {
18662
+ * var index = this.contacts.indexOf(contactToRemove);
18663
+ * this.contacts.splice(index, 1);
18664
+ * };
18665
+ *
18666
+ * SettingsController1.prototype.clearContact = function(contact) {
18667
+ * contact.type = 'phone';
18668
+ * contact.value = '';
18669
+ * };
18670
+ * </file>
18671
+ * <file name="protractor.js" type="protractor">
18672
+ * it('should check controller as', function() {
18673
+ * var container = element(by.id('ctrl-as-exmpl'));
18674
+ * expect(container.findElement(by.model('settings.name'))
18675
+ * .getAttribute('value')).toBe('John Smith');
18676
+ *
18677
+ * var firstRepeat =
18678
+ * container.findElement(by.repeater('contact in settings.contacts').row(0));
18679
+ * var secondRepeat =
18680
+ * container.findElement(by.repeater('contact in settings.contacts').row(1));
18681
+ *
18682
+ * expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18683
+ * .toBe('408 555 1212');
18684
+ *
18685
+ * expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18686
+ * .toBe('john.smith@example.org');
18687
+ *
18688
+ * firstRepeat.findElement(by.linkText('clear')).click();
18689
+ *
18690
+ * expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18691
+ * .toBe('');
18692
+ *
18693
+ * container.findElement(by.linkText('add')).click();
18694
+ *
18695
+ * expect(container.findElement(by.repeater('contact in settings.contacts').row(2))
18696
+ * .findElement(by.model('contact.value'))
18697
+ * .getAttribute('value'))
18698
+ * .toBe('yourname@example.org');
18699
+ * });
18700
+ * </file>
18701
+ * </example>
18702
+ *
18703
+ * This example demonstrates the "attach to `$scope`" style of controller.
18704
+ *
18705
+ * <example name="ngController">
18706
+ * <file name="index.html">
18707
+ * <div id="ctrl-exmpl" ng-controller="SettingsController2">
18708
+ * Name: <input type="text" ng-model="name"/>
18709
+ * [ <a href="" ng-click="greet()">greet</a> ]<br/>
18710
+ * Contact:
18711
+ * <ul>
18712
+ * <li ng-repeat="contact in contacts">
18713
+ * <select ng-model="contact.type">
18714
+ * <option>phone</option>
18715
+ * <option>email</option>
18716
+ * </select>
18717
+ * <input type="text" ng-model="contact.value"/>
18718
+ * [ <a href="" ng-click="clearContact(contact)">clear</a>
18719
+ * | <a href="" ng-click="removeContact(contact)">X</a> ]
18720
+ * </li>
18721
+ * <li>[ <a href="" ng-click="addContact()">add</a> ]</li>
18722
+ * </ul>
18723
+ * </div>
18724
+ * </file>
18725
+ * <file name="app.js">
18726
+ * function SettingsController2($scope) {
18727
+ * $scope.name = "John Smith";
18728
+ * $scope.contacts = [
18729
+ * {type:'phone', value:'408 555 1212'},
18730
+ * {type:'email', value:'john.smith@example.org'} ];
18731
+ *
18732
+ * $scope.greet = function() {
18733
+ * alert($scope.name);
18734
+ * };
18735
+ *
18736
+ * $scope.addContact = function() {
18737
+ * $scope.contacts.push({type:'email', value:'yourname@example.org'});
18738
+ * };
18739
+ *
18740
+ * $scope.removeContact = function(contactToRemove) {
18741
+ * var index = $scope.contacts.indexOf(contactToRemove);
18742
+ * $scope.contacts.splice(index, 1);
18743
+ * };
18744
+ *
18745
+ * $scope.clearContact = function(contact) {
18746
+ * contact.type = 'phone';
18747
+ * contact.value = '';
18748
+ * };
18749
+ * }
18750
+ * </file>
18751
+ * <file name="protractor.js" type="protractor">
18752
+ * it('should check controller', function() {
18753
+ * var container = element(by.id('ctrl-exmpl'));
18754
+ *
18755
+ * expect(container.findElement(by.model('name'))
18756
+ * .getAttribute('value')).toBe('John Smith');
18757
+ *
18758
+ * var firstRepeat =
18759
+ * container.findElement(by.repeater('contact in contacts').row(0));
18760
+ * var secondRepeat =
18761
+ * container.findElement(by.repeater('contact in contacts').row(1));
18762
+ *
18763
+ * expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18764
+ * .toBe('408 555 1212');
18765
+ * expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18766
+ * .toBe('john.smith@example.org');
18767
+ *
18768
+ * firstRepeat.findElement(by.linkText('clear')).click();
18769
+ *
18770
+ * expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18771
+ * .toBe('');
18772
+ *
18773
+ * container.findElement(by.linkText('add')).click();
18774
+ *
18775
+ * expect(container.findElement(by.repeater('contact in contacts').row(2))
18776
+ * .findElement(by.model('contact.value'))
18777
+ * .getAttribute('value'))
18778
+ * .toBe('yourname@example.org');
18779
+ * });
18780
+ * </file>
18781
+ *</example>
18527
18782
 
18528
18783
  */
18529
18784
  var ngControllerDirective = [function() {
@@ -18621,7 +18876,7 @@ forEach(
18621
18876
  return {
18622
18877
  compile: function($element, attr) {
18623
18878
  var fn = $parse(attr[directiveName]);
18624
- return function(scope, element, attr) {
18879
+ return function ngEventHandler(scope, element) {
18625
18880
  element.on(lowercase(name), function(event) {
18626
18881
  scope.$apply(function() {
18627
18882
  fn(scope, {$event:event});
@@ -18838,8 +19093,13 @@ forEach(
18838
19093
  * @example
18839
19094
  <example>
18840
19095
  <file name="index.html">
18841
- <input ng-keyup="count = count + 1" ng-init="count=0">
18842
- key up count: {{count}}
19096
+ <p>Typing in the input box below updates the key count</p>
19097
+ <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
19098
+
19099
+ <p>Typing in the input box below updates the keycode</p>
19100
+ <input ng-keyup="event=$event">
19101
+ <p>event keyCode: {{ event.keyCode }}</p>
19102
+ <p>event altKey: {{ event.altKey }}</p>
18843
19103
  </file>
18844
19104
  </example>
18845
19105
  */
@@ -19111,7 +19371,7 @@ var ngIfDirective = ['$animate', function($animate) {
19111
19371
  clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
19112
19372
  // Note: We only need the first/last node of the cloned nodes.
19113
19373
  // However, we need to keep the reference to the jqlite wrapper as it might be changed later
19114
- // by a directive with templateUrl when it's template arrives.
19374
+ // by a directive with templateUrl when its template arrives.
19115
19375
  block = {
19116
19376
  clone: clone
19117
19377
  };
@@ -19810,7 +20070,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
19810
20070
  * mapped to the same DOM element, which is not possible.) Filters should be applied to the expression,
19811
20071
  * before specifying a tracking expression.
19812
20072
  *
19813
- * For example: `item in items` is equivalent to `item in items track by $id(item)'. This implies that the DOM elements
20073
+ * For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
19814
20074
  * will be associated by item identity in the array.
19815
20075
  *
19816
20076
  * For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
@@ -20088,7 +20348,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
20088
20348
  block.scope = childScope;
20089
20349
  // Note: We only need the first/last node of the cloned nodes.
20090
20350
  // However, we need to keep the reference to the jqlite wrapper as it might be changed later
20091
- // by a directive with templateUrl when it's template arrives.
20351
+ // by a directive with templateUrl when its template arrives.
20092
20352
  block.clone = clone;
20093
20353
  nextBlockMap[block.id] = block;
20094
20354
  });
@@ -20131,6 +20391,11 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
20131
20391
  * on the element causing it to become hidden. When true, the ng-hide CSS class is removed
20132
20392
  * from the element causing the element not to appear hidden.
20133
20393
  *
20394
+ * <div class="alert alert-warning">
20395
+ * **Note:** Here is a list of values that ngShow will consider as a falsy value (case insensitive):<br />
20396
+ * "f" / "0" / "false" / "no" / "n" / "[]"
20397
+ * </div>
20398
+ *
20134
20399
  * ## Why is !important used?
20135
20400
  *
20136
20401
  * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
@@ -20144,26 +20409,21 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
20144
20409
  *
20145
20410
  * ### Overriding .ng-hide
20146
20411
  *
20147
- * If you wish to change the hide behavior with ngShow/ngHide then this can be achieved by
20148
- * restating the styles for the .ng-hide class in CSS:
20412
+ * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
20413
+ * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
20414
+ * class in CSS:
20415
+ *
20149
20416
  * ```css
20150
20417
  * .ng-hide {
20151
- * //!annotate CSS Specificity|Not to worry, this will override the AngularJS default...
20152
- * display:block!important;
20153
- *
20154
20418
  * //this is just another form of hiding an element
20419
+ * display:block!important;
20155
20420
  * position:absolute;
20156
20421
  * top:-9999px;
20157
20422
  * left:-9999px;
20158
20423
  * }
20159
20424
  * ```
20160
20425
  *
20161
- * Just remember to include the important flag so the CSS override will function.
20162
- *
20163
- * <div class="alert alert-warning">
20164
- * **Note:** Here is a list of values that ngShow will consider as a falsy value (case insensitive):<br />
20165
- * "f" / "0" / "false" / "no" / "n" / "[]"
20166
- * </div>
20426
+ * By default you don't need to override in CSS anything and the animations will work around the display style.
20167
20427
  *
20168
20428
  * ## A note about animations with ngShow
20169
20429
  *
@@ -20178,7 +20438,6 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
20178
20438
  * //
20179
20439
  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
20180
20440
  * transition:0.5s linear all;
20181
- * display:block!important;
20182
20441
  * }
20183
20442
  *
20184
20443
  * .my-element.ng-hide-add { ... }
@@ -20187,6 +20446,9 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
20187
20446
  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
20188
20447
  * ```
20189
20448
  *
20449
+ * Keep in mind that, as of AngularJS version 1.2.17 (and 1.3.0-beta.11), there is no need to change the display
20450
+ * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
20451
+ *
20190
20452
  * @animations
20191
20453
  * addClass: .ng-hide - happens after the ngShow expression evaluates to a truthy value and the just before contents are set to visible
20192
20454
  * removeClass: .ng-hide - happens after the ngShow expression evaluates to a non truthy value and just before the contents are set to hidden
@@ -20226,11 +20488,6 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
20226
20488
  background:white;
20227
20489
  }
20228
20490
 
20229
- .animate-show.ng-hide-add,
20230
- .animate-show.ng-hide-remove {
20231
- display:block!important;
20232
- }
20233
-
20234
20491
  .animate-show.ng-hide {
20235
20492
  line-height:0;
20236
20493
  opacity:0;
@@ -20281,16 +20538,21 @@ var ngShowDirective = ['$animate', function($animate) {
20281
20538
  *
20282
20539
  * ```html
20283
20540
  * <!-- when $scope.myValue is truthy (element is hidden) -->
20284
- * <div ng-hide="myValue"></div>
20541
+ * <div ng-hide="myValue" class="ng-hide"></div>
20285
20542
  *
20286
20543
  * <!-- when $scope.myValue is falsy (element is visible) -->
20287
- * <div ng-hide="myValue" class="ng-hide"></div>
20544
+ * <div ng-hide="myValue"></div>
20288
20545
  * ```
20289
20546
  *
20290
20547
  * When the ngHide expression evaluates to true then the .ng-hide CSS class is added to the class attribute
20291
20548
  * on the element causing it to become hidden. When false, the ng-hide CSS class is removed
20292
20549
  * from the element causing the element not to appear hidden.
20293
20550
  *
20551
+ * <div class="alert alert-warning">
20552
+ * **Note:** Here is a list of values that ngHide will consider as a falsy value (case insensitive):<br />
20553
+ * "f" / "0" / "false" / "no" / "n" / "[]"
20554
+ * </div>
20555
+ *
20294
20556
  * ## Why is !important used?
20295
20557
  *
20296
20558
  * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
@@ -20304,33 +20566,27 @@ var ngShowDirective = ['$animate', function($animate) {
20304
20566
  *
20305
20567
  * ### Overriding .ng-hide
20306
20568
  *
20307
- * If you wish to change the hide behavior with ngShow/ngHide then this can be achieved by
20308
- * restating the styles for the .ng-hide class in CSS:
20569
+ * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
20570
+ * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
20571
+ * class in CSS:
20572
+ *
20309
20573
  * ```css
20310
20574
  * .ng-hide {
20311
- * //!annotate CSS Specificity|Not to worry, this will override the AngularJS default...
20312
- * display:block!important;
20313
- *
20314
20575
  * //this is just another form of hiding an element
20576
+ * display:block!important;
20315
20577
  * position:absolute;
20316
20578
  * top:-9999px;
20317
20579
  * left:-9999px;
20318
20580
  * }
20319
20581
  * ```
20320
20582
  *
20321
- * Just remember to include the important flag so the CSS override will function.
20322
- *
20323
- * <div class="alert alert-warning">
20324
- * **Note:** Here is a list of values that ngHide will consider as a falsy value (case insensitive):<br />
20325
- * "f" / "0" / "false" / "no" / "n" / "[]"
20326
- * </div>
20583
+ * By default you don't need to override in CSS anything and the animations will work around the display style.
20327
20584
  *
20328
20585
  * ## A note about animations with ngHide
20329
20586
  *
20330
20587
  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
20331
- * is true and false. This system works like the animation system present with ngClass, except that
20332
- * you must also include the !important flag to override the display property so
20333
- * that you can perform an animation when the element is hidden during the time of the animation.
20588
+ * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
20589
+ * CSS class is added and removed for you instead of your own CSS class.
20334
20590
  *
20335
20591
  * ```css
20336
20592
  * //
@@ -20338,7 +20594,6 @@ var ngShowDirective = ['$animate', function($animate) {
20338
20594
  * //
20339
20595
  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
20340
20596
  * transition:0.5s linear all;
20341
- * display:block!important;
20342
20597
  * }
20343
20598
  *
20344
20599
  * .my-element.ng-hide-add { ... }
@@ -20347,6 +20602,9 @@ var ngShowDirective = ['$animate', function($animate) {
20347
20602
  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
20348
20603
  * ```
20349
20604
  *
20605
+ * Keep in mind that, as of AngularJS version 1.2.17 (and 1.3.0-beta.11), there is no need to change the display
20606
+ * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
20607
+ *
20350
20608
  * @animations
20351
20609
  * removeClass: .ng-hide - happens after the ngHide expression evaluates to a truthy value and just before the contents are set to hidden
20352
20610
  * addClass: .ng-hide - happens after the ngHide expression evaluates to a non truthy value and just before the contents are set to visible
@@ -20386,11 +20644,6 @@ var ngShowDirective = ['$animate', function($animate) {
20386
20644
  background:white;
20387
20645
  }
20388
20646
 
20389
- .animate-hide.ng-hide-add,
20390
- .animate-hide.ng-hide-remove {
20391
- display:block!important;
20392
- }
20393
-
20394
20647
  .animate-hide.ng-hide {
20395
20648
  line-height:0;
20396
20649
  opacity:0;
@@ -20436,14 +20689,20 @@ var ngHideDirective = ['$animate', function($animate) {
20436
20689
  * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
20437
20690
  *
20438
20691
  * @element ANY
20439
- * @param {expression} ngStyle {@link guide/expression Expression} which evals to an
20440
- * object whose keys are CSS style names and values are corresponding values for those CSS
20441
- * keys.
20692
+ * @param {expression} ngStyle
20693
+ *
20694
+ * {@link guide/expression Expression} which evals to an
20695
+ * object whose keys are CSS style names and values are corresponding values for those CSS
20696
+ * keys.
20697
+ *
20698
+ * Since some CSS style names are not valid keys for an object, they must be quoted.
20699
+ * See the 'background-color' style in the example below.
20442
20700
  *
20443
20701
  * @example
20444
20702
  <example>
20445
20703
  <file name="index.html">
20446
- <input type="button" value="set" ng-click="myStyle={color:'red'}">
20704
+ <input type="button" value="set color" ng-click="myStyle={color:'red'}">
20705
+ <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
20447
20706
  <input type="button" value="clear" ng-click="myStyle={}">
20448
20707
  <br/>
20449
20708
  <span ng-style="myStyle">Sample Text</span>
@@ -20457,9 +20716,9 @@ var ngHideDirective = ['$animate', function($animate) {
20457
20716
  <file name="protractor.js" type="protractor">
20458
20717
  var colorSpan = element(by.css('span'));
20459
20718
 
20460
- it('should check ng-style', function() {
20719
+ iit('should check ng-style', function() {
20461
20720
  expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
20462
- element(by.css('input[value=set]')).click();
20721
+ element(by.css('input[value=\'set color\']')).click();
20463
20722
  expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
20464
20723
  element(by.css('input[value=clear]')).click();
20465
20724
  expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
@@ -20507,11 +20766,14 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
20507
20766
  * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
20508
20767
  *
20509
20768
  * @usage
20769
+ *
20770
+ * ```
20510
20771
  * <ANY ng-switch="expression">
20511
20772
  * <ANY ng-switch-when="matchValue1">...</ANY>
20512
20773
  * <ANY ng-switch-when="matchValue2">...</ANY>
20513
20774
  * <ANY ng-switch-default>...</ANY>
20514
20775
  * </ANY>
20776
+ * ```
20515
20777
  *
20516
20778
  *
20517
20779
  * @scope
@@ -20611,37 +20873,29 @@ var ngSwitchDirective = ['$animate', function($animate) {
20611
20873
  }],
20612
20874
  link: function(scope, element, attr, ngSwitchController) {
20613
20875
  var watchExpr = attr.ngSwitch || attr.on,
20614
- selectedTranscludes,
20615
- selectedElements,
20616
- previousElements,
20876
+ selectedTranscludes = [],
20877
+ selectedElements = [],
20878
+ previousElements = [],
20617
20879
  selectedScopes = [];
20618
20880
 
20619
20881
  scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
20620
- var i, ii = selectedScopes.length;
20621
- if(ii > 0) {
20622
- if(previousElements) {
20623
- for (i = 0; i < ii; i++) {
20624
- previousElements[i].remove();
20625
- }
20626
- previousElements = null;
20627
- }
20628
-
20629
- previousElements = [];
20630
- for (i= 0; i<ii; i++) {
20631
- var selected = selectedElements[i];
20632
- selectedScopes[i].$destroy();
20633
- previousElements[i] = selected;
20634
- $animate.leave(selected, function() {
20635
- previousElements.splice(i, 1);
20636
- if(previousElements.length === 0) {
20637
- previousElements = null;
20638
- }
20639
- });
20640
- }
20882
+ var i, ii;
20883
+ for (i = 0, ii = previousElements.length; i < ii; ++i) {
20884
+ previousElements[i].remove();
20885
+ }
20886
+ previousElements.length = 0;
20887
+
20888
+ for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
20889
+ var selected = selectedElements[i];
20890
+ selectedScopes[i].$destroy();
20891
+ previousElements[i] = selected;
20892
+ $animate.leave(selected, function() {
20893
+ previousElements.splice(i, 1);
20894
+ });
20641
20895
  }
20642
20896
 
20643
- selectedElements = [];
20644
- selectedScopes = [];
20897
+ selectedElements.length = 0;
20898
+ selectedScopes.length = 0;
20645
20899
 
20646
20900
  if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
20647
20901
  scope.$eval(attr.change);
@@ -20885,7 +21139,7 @@ var ngOptionsMinErr = minErr('ngOptions');
20885
21139
  {name:'blue', shade:'dark'},
20886
21140
  {name:'yellow', shade:'light'}
20887
21141
  ];
20888
- $scope.color = $scope.colors[2]; // red
21142
+ $scope.myColor = $scope.colors[2]; // red
20889
21143
  }
20890
21144
  </script>
20891
21145
  <div ng-controller="MyCntrl">
@@ -20900,37 +21154,37 @@ var ngOptionsMinErr = minErr('ngOptions');
20900
21154
  </ul>
20901
21155
  <hr/>
20902
21156
  Color (null not allowed):
20903
- <select ng-model="color" ng-options="c.name for c in colors"></select><br>
21157
+ <select ng-model="myColor" ng-options="color.name for color in colors"></select><br>
20904
21158
 
20905
21159
  Color (null allowed):
20906
21160
  <span class="nullable">
20907
- <select ng-model="color" ng-options="c.name for c in colors">
21161
+ <select ng-model="myColor" ng-options="color.name for color in colors">
20908
21162
  <option value="">-- choose color --</option>
20909
21163
  </select>
20910
21164
  </span><br/>
20911
21165
 
20912
21166
  Color grouped by shade:
20913
- <select ng-model="color" ng-options="c.name group by c.shade for c in colors">
21167
+ <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
20914
21168
  </select><br/>
20915
21169
 
20916
21170
 
20917
- Select <a href ng-click="color={name:'not in list'}">bogus</a>.<br>
21171
+ Select <a href ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</a>.<br>
20918
21172
  <hr/>
20919
- Currently selected: {{ {selected_color:color} }}
21173
+ Currently selected: {{ {selected_color:myColor} }}
20920
21174
  <div style="border:solid 1px black; height:20px"
20921
- ng-style="{'background-color':color.name}">
21175
+ ng-style="{'background-color':myColor.name}">
20922
21176
  </div>
20923
21177
  </div>
20924
21178
  </file>
20925
21179
  <file name="protractor.js" type="protractor">
20926
21180
  it('should check ng-options', function() {
20927
- expect(element(by.binding('{selected_color:color}')).getText()).toMatch('red');
20928
- element.all(by.select('color')).first().click();
20929
- element.all(by.css('select[ng-model="color"] option')).first().click();
20930
- expect(element(by.binding('{selected_color:color}')).getText()).toMatch('black');
20931
- element(by.css('.nullable select[ng-model="color"]')).click();
20932
- element.all(by.css('.nullable select[ng-model="color"] option')).first().click();
20933
- expect(element(by.binding('{selected_color:color}')).getText()).toMatch('null');
21181
+ expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
21182
+ element.all(by.select('myColor')).first().click();
21183
+ element.all(by.css('select[ng-model="myColor"] option')).first().click();
21184
+ expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
21185
+ element(by.css('.nullable select[ng-model="myColor"]')).click();
21186
+ element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
21187
+ expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
20934
21188
  });
20935
21189
  </file>
20936
21190
  </example>
@@ -21085,7 +21339,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
21085
21339
  // we need to work of an array, so we need to see if anything was inserted/removed
21086
21340
  scope.$watch(function selectMultipleWatch() {
21087
21341
  if (!equals(lastView, ctrl.$viewValue)) {
21088
- lastView = copy(ctrl.$viewValue);
21342
+ lastView = shallowCopy(ctrl.$viewValue);
21089
21343
  ctrl.$render();
21090
21344
  }
21091
21345
  });
@@ -21461,4 +21715,4 @@ var styleDirective = valueFn({
21461
21715
 
21462
21716
  })(window, document);
21463
21717
 
21464
- !angular.$$csp() && angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}.ng-animate-block-transitions{transition:0s all!important;-webkit-transition:0s all!important;}</style>');
21718
+ !window.angular.$$csp() && window.angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}.ng-animate-block-transitions{transition:0s all!important;-webkit-transition:0s all!important;}.ng-hide-add-active,.ng-hide-remove{display:block!important;}</style>');