angularjs-on-rails 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -9790,7 +9790,7 @@ if ( typeof module === "object" && module && typeof module.exports === "object"
9790
9790
  })( window );
9791
9791
 
9792
9792
  /**
9793
- * @license AngularJS v1.2.18
9793
+ * @license AngularJS v1.2.21
9794
9794
  * (c) 2010-2014 Google, Inc. http://angularjs.org
9795
9795
  * License: MIT
9796
9796
  */
@@ -9860,7 +9860,7 @@ function minErr(module) {
9860
9860
  return match;
9861
9861
  });
9862
9862
 
9863
- message = message + '\nhttp://errors.angularjs.org/1.2.18/' +
9863
+ message = message + '\nhttp://errors.angularjs.org/1.2.21/' +
9864
9864
  (module ? module + '/' : '') + code;
9865
9865
  for (i = 2; i < arguments.length; i++) {
9866
9866
  message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
@@ -9872,88 +9872,88 @@ function minErr(module) {
9872
9872
  }
9873
9873
 
9874
9874
  /* We need to tell jshint what variables are being exported */
9875
- /* global
9876
- -angular,
9877
- -msie,
9878
- -jqLite,
9879
- -jQuery,
9880
- -slice,
9881
- -push,
9882
- -toString,
9883
- -ngMinErr,
9884
- -angularModule,
9885
- -nodeName_,
9886
- -uid,
9887
-
9888
- -lowercase,
9889
- -uppercase,
9890
- -manualLowercase,
9891
- -manualUppercase,
9892
- -nodeName_,
9893
- -isArrayLike,
9894
- -forEach,
9895
- -sortedKeys,
9896
- -forEachSorted,
9897
- -reverseParams,
9898
- -nextUid,
9899
- -setHashKey,
9900
- -extend,
9901
- -int,
9902
- -inherit,
9903
- -noop,
9904
- -identity,
9905
- -valueFn,
9906
- -isUndefined,
9907
- -isDefined,
9908
- -isObject,
9909
- -isString,
9910
- -isNumber,
9911
- -isDate,
9912
- -isArray,
9913
- -isFunction,
9914
- -isRegExp,
9915
- -isWindow,
9916
- -isScope,
9917
- -isFile,
9918
- -isBlob,
9919
- -isBoolean,
9920
- -trim,
9921
- -isElement,
9922
- -makeMap,
9923
- -map,
9924
- -size,
9925
- -includes,
9926
- -indexOf,
9927
- -arrayRemove,
9928
- -isLeafNode,
9929
- -copy,
9930
- -shallowCopy,
9931
- -equals,
9932
- -csp,
9933
- -concat,
9934
- -sliceArgs,
9935
- -bind,
9936
- -toJsonReplacer,
9937
- -toJson,
9938
- -fromJson,
9939
- -toBoolean,
9940
- -startingTag,
9941
- -tryDecodeURIComponent,
9942
- -parseKeyValue,
9943
- -toKeyValue,
9944
- -encodeUriSegment,
9945
- -encodeUriQuery,
9946
- -angularInit,
9947
- -bootstrap,
9948
- -snake_case,
9949
- -bindJQuery,
9950
- -assertArg,
9951
- -assertArgFn,
9952
- -assertNotHasOwnProperty,
9953
- -getter,
9954
- -getBlockElements,
9955
- -hasOwnProperty,
9956
-
9875
+ /* global angular: true,
9876
+ msie: true,
9877
+ jqLite: true,
9878
+ jQuery: true,
9879
+ slice: true,
9880
+ push: true,
9881
+ toString: true,
9882
+ ngMinErr: true,
9883
+ angularModule: true,
9884
+ nodeName_: true,
9885
+ uid: true,
9886
+ VALIDITY_STATE_PROPERTY: true,
9887
+
9888
+ lowercase: true,
9889
+ uppercase: true,
9890
+ manualLowercase: true,
9891
+ manualUppercase: true,
9892
+ nodeName_: true,
9893
+ isArrayLike: true,
9894
+ forEach: true,
9895
+ sortedKeys: true,
9896
+ forEachSorted: true,
9897
+ reverseParams: true,
9898
+ nextUid: true,
9899
+ setHashKey: true,
9900
+ extend: true,
9901
+ int: true,
9902
+ inherit: true,
9903
+ noop: true,
9904
+ identity: true,
9905
+ valueFn: true,
9906
+ isUndefined: true,
9907
+ isDefined: true,
9908
+ isObject: true,
9909
+ isString: true,
9910
+ isNumber: true,
9911
+ isDate: true,
9912
+ isArray: true,
9913
+ isFunction: true,
9914
+ isRegExp: true,
9915
+ isWindow: true,
9916
+ isScope: true,
9917
+ isFile: true,
9918
+ isBlob: true,
9919
+ isBoolean: true,
9920
+ isPromiseLike: true,
9921
+ trim: true,
9922
+ isElement: true,
9923
+ makeMap: true,
9924
+ map: true,
9925
+ size: true,
9926
+ includes: true,
9927
+ indexOf: true,
9928
+ arrayRemove: true,
9929
+ isLeafNode: true,
9930
+ copy: true,
9931
+ shallowCopy: true,
9932
+ equals: true,
9933
+ csp: true,
9934
+ concat: true,
9935
+ sliceArgs: true,
9936
+ bind: true,
9937
+ toJsonReplacer: true,
9938
+ toJson: true,
9939
+ fromJson: true,
9940
+ toBoolean: true,
9941
+ startingTag: true,
9942
+ tryDecodeURIComponent: true,
9943
+ parseKeyValue: true,
9944
+ toKeyValue: true,
9945
+ encodeUriSegment: true,
9946
+ encodeUriQuery: true,
9947
+ angularInit: true,
9948
+ bootstrap: true,
9949
+ snake_case: true,
9950
+ bindJQuery: true,
9951
+ assertArg: true,
9952
+ assertArgFn: true,
9953
+ assertNotHasOwnProperty: true,
9954
+ getter: true,
9955
+ getBlockElements: true,
9956
+ hasOwnProperty: true,
9957
9957
  */
9958
9958
 
9959
9959
  ////////////////////////////////////
@@ -9973,6 +9973,10 @@ function minErr(module) {
9973
9973
  * <div doc-module-components="ng"></div>
9974
9974
  */
9975
9975
 
9976
+ // The name of a form control's ValidityState property.
9977
+ // This is used so that it's possible for internal tests to create mock ValidityStates.
9978
+ var VALIDITY_STATE_PROPERTY = 'validity';
9979
+
9976
9980
  /**
9977
9981
  * @ngdoc function
9978
9982
  * @name angular.lowercase
@@ -10108,11 +10112,12 @@ function forEach(obj, iterator, context) {
10108
10112
  iterator.call(context, obj[key], key);
10109
10113
  }
10110
10114
  }
10111
- } else if (obj.forEach && obj.forEach !== forEach) {
10112
- obj.forEach(iterator, context);
10113
- } else if (isArrayLike(obj)) {
10114
- for (key = 0; key < obj.length; key++)
10115
+ } else if (isArray(obj) || isArrayLike(obj)) {
10116
+ for (key = 0; key < obj.length; key++) {
10115
10117
  iterator.call(context, obj[key], key);
10118
+ }
10119
+ } else if (obj.forEach && obj.forEach !== forEach) {
10120
+ obj.forEach(iterator, context);
10116
10121
  } else {
10117
10122
  for (key in obj) {
10118
10123
  if (obj.hasOwnProperty(key)) {
@@ -10449,6 +10454,11 @@ function isBoolean(value) {
10449
10454
  }
10450
10455
 
10451
10456
 
10457
+ function isPromiseLike(obj) {
10458
+ return obj && isFunction(obj.then);
10459
+ }
10460
+
10461
+
10452
10462
  var trim = (function() {
10453
10463
  // native trim is way faster: http://jsperf.com/angular-trim-test
10454
10464
  // but IE doesn't have it... :-(
@@ -10597,9 +10607,9 @@ function isLeafNode (node) {
10597
10607
  * @returns {*} The copy or updated `destination`, if `destination` was specified.
10598
10608
  *
10599
10609
  * @example
10600
- <example>
10610
+ <example module="copyExample">
10601
10611
  <file name="index.html">
10602
- <div ng-controller="Controller">
10612
+ <div ng-controller="ExampleController">
10603
10613
  <form novalidate class="simple-form">
10604
10614
  Name: <input type="text" ng-model="user.name" /><br />
10605
10615
  E-mail: <input type="email" ng-model="user.email" /><br />
@@ -10613,21 +10623,22 @@ function isLeafNode (node) {
10613
10623
  </div>
10614
10624
 
10615
10625
  <script>
10616
- function Controller($scope) {
10617
- $scope.master= {};
10626
+ angular.module('copyExample', [])
10627
+ .controller('ExampleController', ['$scope', function($scope) {
10628
+ $scope.master= {};
10618
10629
 
10619
- $scope.update = function(user) {
10620
- // Example with 1 argument
10621
- $scope.master= angular.copy(user);
10622
- };
10630
+ $scope.update = function(user) {
10631
+ // Example with 1 argument
10632
+ $scope.master= angular.copy(user);
10633
+ };
10623
10634
 
10624
- $scope.reset = function() {
10625
- // Example with 2 arguments
10626
- angular.copy($scope.master, $scope.user);
10627
- };
10635
+ $scope.reset = function() {
10636
+ // Example with 2 arguments
10637
+ angular.copy($scope.master, $scope.user);
10638
+ };
10628
10639
 
10629
- $scope.reset();
10630
- }
10640
+ $scope.reset();
10641
+ }]);
10631
10642
  </script>
10632
10643
  </file>
10633
10644
  </example>
@@ -10646,7 +10657,8 @@ function copy(source, destination, stackSource, stackDest) {
10646
10657
  } else if (isDate(source)) {
10647
10658
  destination = new Date(source.getTime());
10648
10659
  } else if (isRegExp(source)) {
10649
- destination = new RegExp(source.source);
10660
+ destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
10661
+ destination.lastIndex = source.lastIndex;
10650
10662
  } else if (isObject(source)) {
10651
10663
  destination = copy(source, {}, stackSource, stackDest);
10652
10664
  }
@@ -10790,12 +10802,25 @@ function equals(o1, o2) {
10790
10802
  return false;
10791
10803
  }
10792
10804
 
10805
+ var csp = function() {
10806
+ if (isDefined(csp.isActive_)) return csp.isActive_;
10807
+
10808
+ var active = !!(document.querySelector('[ng-csp]') ||
10809
+ document.querySelector('[data-ng-csp]'));
10810
+
10811
+ if (!active) {
10812
+ try {
10813
+ /* jshint -W031, -W054 */
10814
+ new Function('');
10815
+ /* jshint +W031, +W054 */
10816
+ } catch (e) {
10817
+ active = true;
10818
+ }
10819
+ }
10820
+
10821
+ return (csp.isActive_ = active);
10822
+ };
10793
10823
 
10794
- function csp() {
10795
- return (document.securityPolicy && document.securityPolicy.isActive) ||
10796
- (document.querySelector &&
10797
- !!(document.querySelector('[ng-csp]') || document.querySelector('[data-ng-csp]')));
10798
- }
10799
10824
 
10800
10825
 
10801
10826
  function concat(array1, array2, index) {
@@ -10967,11 +10992,11 @@ function parseKeyValue(/**string*/keyValue) {
10967
10992
  var obj = {}, key_value, key;
10968
10993
  forEach((keyValue || "").split('&'), function(keyValue) {
10969
10994
  if ( keyValue ) {
10970
- key_value = keyValue.split('=');
10995
+ key_value = keyValue.replace(/\+/g,'%20').split('=');
10971
10996
  key = tryDecodeURIComponent(key_value[0]);
10972
10997
  if ( isDefined(key) ) {
10973
10998
  var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
10974
- if (!obj[key]) {
10999
+ if (!hasOwnProperty.call(obj, key)) {
10975
11000
  obj[key] = val;
10976
11001
  } else if(isArray(obj[key])) {
10977
11002
  obj[key].push(val);
@@ -11145,7 +11170,7 @@ function angularInit(element, bootstrap) {
11145
11170
  *
11146
11171
  * Angular will detect if it has been loaded into the browser more than once and only allow the
11147
11172
  * first loaded script to be bootstrapped and will report a warning to the browser console for
11148
- * each of the subsequent scripts. This prevents strange results in applications, where otherwise
11173
+ * each of the subsequent scripts. This prevents strange results in applications, where otherwise
11149
11174
  * multiple instances of Angular try to work on the DOM.
11150
11175
  *
11151
11176
  * <example name="multi-bootstrap" module="multi-bootstrap">
@@ -11275,7 +11300,7 @@ function assertArgFn(arg, name, acceptArrayAnnotation) {
11275
11300
  }
11276
11301
 
11277
11302
  assertArg(isFunction(arg), name, 'not a function, got ' +
11278
- (arg && typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg));
11303
+ (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
11279
11304
  return arg;
11280
11305
  }
11281
11306
 
@@ -11652,12 +11677,11 @@ function setupModuleLoader(window) {
11652
11677
 
11653
11678
  }
11654
11679
 
11655
- /* global
11656
- angularModule: true,
11657
- version: true,
11680
+ /* global angularModule: true,
11681
+ version: true,
11658
11682
 
11659
- $LocaleProvider,
11660
- $CompileProvider,
11683
+ $LocaleProvider,
11684
+ $CompileProvider,
11661
11685
 
11662
11686
  htmlAnchorDirective,
11663
11687
  inputDirective,
@@ -11745,11 +11769,11 @@ function setupModuleLoader(window) {
11745
11769
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
11746
11770
  */
11747
11771
  var version = {
11748
- full: '1.2.18', // all of these placeholder strings will be replaced by grunt's
11772
+ full: '1.2.21', // all of these placeholder strings will be replaced by grunt's
11749
11773
  major: 1, // package task
11750
11774
  minor: 2,
11751
- dot: 18,
11752
- codeName: 'ear-extendability'
11775
+ dot: 21,
11776
+ codeName: 'wizard-props'
11753
11777
  };
11754
11778
 
11755
11779
 
@@ -11873,12 +11897,10 @@ function publishExternalAPI(angular){
11873
11897
  ]);
11874
11898
  }
11875
11899
 
11876
- /* global
11877
-
11878
- -JQLitePrototype,
11879
- -addEventListenerFn,
11880
- -removeEventListenerFn,
11881
- -BOOLEAN_ATTR
11900
+ /* global JQLitePrototype: true,
11901
+ addEventListenerFn: true,
11902
+ removeEventListenerFn: true,
11903
+ BOOLEAN_ATTR: true
11882
11904
  */
11883
11905
 
11884
11906
  //////////////////////////////////
@@ -11971,8 +11993,9 @@ function publishExternalAPI(angular){
11971
11993
  * @returns {Object} jQuery object.
11972
11994
  */
11973
11995
 
11996
+ JQLite.expando = 'ng339';
11997
+
11974
11998
  var jqCache = JQLite.cache = {},
11975
- jqName = JQLite.expando = 'ng' + new Date().getTime(),
11976
11999
  jqId = 1,
11977
12000
  addEventListenerFn = (window.document.addEventListener
11978
12001
  ? function(element, type, fn) {element.addEventListener(type, fn, false);}
@@ -12182,7 +12205,7 @@ function jqLiteOff(element, type, fn, unsupported) {
12182
12205
  }
12183
12206
 
12184
12207
  function jqLiteRemoveData(element, name) {
12185
- var expandoId = element[jqName],
12208
+ var expandoId = element.ng339,
12186
12209
  expandoStore = jqCache[expandoId];
12187
12210
 
12188
12211
  if (expandoStore) {
@@ -12196,17 +12219,17 @@ function jqLiteRemoveData(element, name) {
12196
12219
  jqLiteOff(element);
12197
12220
  }
12198
12221
  delete jqCache[expandoId];
12199
- element[jqName] = undefined; // ie does not allow deletion of attributes on elements.
12222
+ element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
12200
12223
  }
12201
12224
  }
12202
12225
 
12203
12226
  function jqLiteExpandoStore(element, key, value) {
12204
- var expandoId = element[jqName],
12227
+ var expandoId = element.ng339,
12205
12228
  expandoStore = jqCache[expandoId || -1];
12206
12229
 
12207
12230
  if (isDefined(value)) {
12208
12231
  if (!expandoStore) {
12209
- element[jqName] = expandoId = jqNextId();
12232
+ element.ng339 = expandoId = jqNextId();
12210
12233
  expandoStore = jqCache[expandoId] = {};
12211
12234
  }
12212
12235
  expandoStore[key] = value;
@@ -12291,25 +12314,22 @@ function jqLiteController(element, name) {
12291
12314
  }
12292
12315
 
12293
12316
  function jqLiteInheritedData(element, name, value) {
12294
- element = jqLite(element);
12295
-
12296
12317
  // if element is the document object work with the html element instead
12297
12318
  // this makes $(document).scope() possible
12298
- if(element[0].nodeType == 9) {
12299
- element = element.find('html');
12319
+ if(element.nodeType == 9) {
12320
+ element = element.documentElement;
12300
12321
  }
12301
12322
  var names = isArray(name) ? name : [name];
12302
12323
 
12303
- while (element.length) {
12304
- var node = element[0];
12324
+ while (element) {
12305
12325
  for (var i = 0, ii = names.length; i < ii; i++) {
12306
- if ((value = element.data(names[i])) !== undefined) return value;
12326
+ if ((value = jqLite.data(element, names[i])) !== undefined) return value;
12307
12327
  }
12308
12328
 
12309
12329
  // If dealing with a document fragment node with a host element, and no parent, use the host
12310
12330
  // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
12311
12331
  // to lookup parent controllers.
12312
- element = jqLite(node.parentNode || (node.nodeType === 11 && node.host));
12332
+ element = element.parentNode || (element.nodeType === 11 && element.host);
12313
12333
  }
12314
12334
  }
12315
12335
 
@@ -12384,18 +12404,25 @@ function getBooleanAttrName(element, name) {
12384
12404
  return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
12385
12405
  }
12386
12406
 
12407
+ forEach({
12408
+ data: jqLiteData,
12409
+ removeData: jqLiteRemoveData
12410
+ }, function(fn, name) {
12411
+ JQLite[name] = fn;
12412
+ });
12413
+
12387
12414
  forEach({
12388
12415
  data: jqLiteData,
12389
12416
  inheritedData: jqLiteInheritedData,
12390
12417
 
12391
12418
  scope: function(element) {
12392
12419
  // Can't use jqLiteData here directly so we stay compatible with jQuery!
12393
- return jqLite(element).data('$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
12420
+ return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
12394
12421
  },
12395
12422
 
12396
12423
  isolateScope: function(element) {
12397
12424
  // Can't use jqLiteData here directly so we stay compatible with jQuery!
12398
- return jqLite(element).data('$isolateScope') || jqLite(element).data('$isolateScopeNoTemplate');
12425
+ return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
12399
12426
  },
12400
12427
 
12401
12428
  controller: jqLiteController,
@@ -12823,7 +12850,9 @@ forEach({
12823
12850
  clone: jqLiteClone,
12824
12851
 
12825
12852
  triggerHandler: function(element, eventName, eventData) {
12826
- var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName];
12853
+ // Copy event handlers in case event handlers array is modified during execution.
12854
+ var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName],
12855
+ eventFnsCopy = shallowCopy(eventFns || []);
12827
12856
 
12828
12857
  eventData = eventData || [];
12829
12858
 
@@ -12832,7 +12861,7 @@ forEach({
12832
12861
  stopPropagation: noop
12833
12862
  }];
12834
12863
 
12835
- forEach(eventFns, function(fn) {
12864
+ forEach(eventFnsCopy, function(fn) {
12836
12865
  fn.apply(element, event.concat(eventData));
12837
12866
  });
12838
12867
  }
@@ -12873,16 +12902,16 @@ forEach({
12873
12902
  * @returns {string} hash string such that the same input will have the same hash string.
12874
12903
  * The resulting string key is in 'type:hashKey' format.
12875
12904
  */
12876
- function hashKey(obj) {
12905
+ function hashKey(obj, nextUidFn) {
12877
12906
  var objType = typeof obj,
12878
12907
  key;
12879
12908
 
12880
- if (objType == 'object' && obj !== null) {
12909
+ if (objType == 'function' || (objType == 'object' && obj !== null)) {
12881
12910
  if (typeof (key = obj.$$hashKey) == 'function') {
12882
12911
  // must invoke on object to keep the right this
12883
12912
  key = obj.$$hashKey();
12884
12913
  } else if (key === undefined) {
12885
- key = obj.$$hashKey = nextUid();
12914
+ key = obj.$$hashKey = (nextUidFn || nextUid)();
12886
12915
  }
12887
12916
  } else {
12888
12917
  key = obj;
@@ -12894,7 +12923,13 @@ function hashKey(obj) {
12894
12923
  /**
12895
12924
  * HashMap which can use objects as keys
12896
12925
  */
12897
- function HashMap(array){
12926
+ function HashMap(array, isolatedUid) {
12927
+ if (isolatedUid) {
12928
+ var uid = 0;
12929
+ this.nextUid = function() {
12930
+ return ++uid;
12931
+ };
12932
+ }
12898
12933
  forEach(array, this.put, this);
12899
12934
  }
12900
12935
  HashMap.prototype = {
@@ -12904,7 +12939,7 @@ HashMap.prototype = {
12904
12939
  * @param value value to store can be any type
12905
12940
  */
12906
12941
  put: function(key, value) {
12907
- this[hashKey(key)] = value;
12942
+ this[hashKey(key, this.nextUid)] = value;
12908
12943
  },
12909
12944
 
12910
12945
  /**
@@ -12912,7 +12947,7 @@ HashMap.prototype = {
12912
12947
  * @returns {Object} the value for the key
12913
12948
  */
12914
12949
  get: function(key) {
12915
- return this[hashKey(key)];
12950
+ return this[hashKey(key, this.nextUid)];
12916
12951
  },
12917
12952
 
12918
12953
  /**
@@ -12920,7 +12955,7 @@ HashMap.prototype = {
12920
12955
  * @param key
12921
12956
  */
12922
12957
  remove: function(key) {
12923
- var value = this[key = hashKey(key)];
12958
+ var value = this[key = hashKey(key, this.nextUid)];
12924
12959
  delete this[key];
12925
12960
  return value;
12926
12961
  }
@@ -12998,7 +13033,7 @@ function annotate(fn) {
12998
13033
  argDecl,
12999
13034
  last;
13000
13035
 
13001
- if (typeof fn == 'function') {
13036
+ if (typeof fn === 'function') {
13002
13037
  if (!($inject = fn.$inject)) {
13003
13038
  $inject = [];
13004
13039
  if (fn.length) {
@@ -13211,7 +13246,7 @@ function annotate(fn) {
13211
13246
 
13212
13247
 
13213
13248
  /**
13214
- * @ngdoc object
13249
+ * @ngdoc service
13215
13250
  * @name $provide
13216
13251
  *
13217
13252
  * @description
@@ -13517,7 +13552,7 @@ function createInjector(modulesToLoad) {
13517
13552
  var INSTANTIATING = {},
13518
13553
  providerSuffix = 'Provider',
13519
13554
  path = [],
13520
- loadedModules = new HashMap(),
13555
+ loadedModules = new HashMap([], true),
13521
13556
  providerCache = {
13522
13557
  $provide: {
13523
13558
  provider: supportObject(provider),
@@ -13688,8 +13723,7 @@ function createInjector(modulesToLoad) {
13688
13723
  : getService(key)
13689
13724
  );
13690
13725
  }
13691
- if (!fn.$inject) {
13692
- // this means that we must be an array.
13726
+ if (isArray(fn)) {
13693
13727
  fn = fn[length];
13694
13728
  }
13695
13729
 
@@ -15022,7 +15056,7 @@ function $TemplateCacheProvider() {
15022
15056
  * local name. Given `<widget my-attr="count = count + value">` and widget definition of
15023
15057
  * `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
15024
15058
  * a function wrapper for the `count = count + value` expression. Often it's desirable to
15025
- * pass data from the isolated scope via an expression and to the parent scope, this can be
15059
+ * pass data from the isolated scope via an expression to the parent scope, this can be
15026
15060
  * done by passing a map of local variable names and values into the expression wrapper fn.
15027
15061
  * For example, if the expression is `increment(amount)` then we can specify the amount value
15028
15062
  * by calling the `localFn` as `localFn({amount: 22})`.
@@ -15073,14 +15107,16 @@ function $TemplateCacheProvider() {
15073
15107
  *
15074
15108
  *
15075
15109
  * #### `template`
15076
- * replace the current element with the contents of the HTML. The replacement process
15077
- * migrates all of the attributes / classes from the old element to the new one. See the
15078
- * {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
15079
- * Directives Guide} for an example.
15110
+ * HTML markup that may:
15111
+ * * Replace the contents of the directive's element (defualt).
15112
+ * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
15113
+ * * Wrap the contents of the directive's element (if `transclude` is true).
15080
15114
  *
15081
- * You can specify `template` as a string representing the template or as a function which takes
15082
- * two arguments `tElement` and `tAttrs` (described in the `compile` function api below) and
15083
- * returns a string value representing the template.
15115
+ * Value may be:
15116
+ *
15117
+ * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
15118
+ * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
15119
+ * function api below) and returns a string value.
15084
15120
  *
15085
15121
  *
15086
15122
  * #### `templateUrl`
@@ -15095,11 +15131,14 @@ function $TemplateCacheProvider() {
15095
15131
  *
15096
15132
  *
15097
15133
  * #### `replace` ([*DEPRECATED*!], will be removed in next major release)
15098
- * specify where the template should be inserted. Defaults to `false`.
15134
+ * specify what the template should replace. Defaults to `false`.
15099
15135
  *
15100
- * * `true` - the template will replace the current element.
15101
- * * `false` - the template will replace the contents of the current element.
15136
+ * * `true` - the template will replace the directive's element.
15137
+ * * `false` - the template will replace the contents of the directive's element.
15102
15138
  *
15139
+ * The replacement process migrates all of the attributes / classes from the old element to the new
15140
+ * one. See the {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
15141
+ * Directives Guide} for an example.
15103
15142
  *
15104
15143
  * #### `transclude`
15105
15144
  * compile the content of the element and make it available to the directive.
@@ -15113,6 +15152,11 @@ function $TemplateCacheProvider() {
15113
15152
  * * `true` - transclude the content of the directive.
15114
15153
  * * `'element'` - transclude the whole element including any directives defined at lower priority.
15115
15154
  *
15155
+ * <div class="alert alert-warning">
15156
+ * **Note:** When testing an element transclude directive you must not place the directive at the root of the
15157
+ * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
15158
+ * Testing Transclusion Directives}.
15159
+ * </div>
15116
15160
  *
15117
15161
  * #### `compile`
15118
15162
  *
@@ -15249,10 +15293,10 @@ function $TemplateCacheProvider() {
15249
15293
  * to illustrate how `$compile` works.
15250
15294
  * </div>
15251
15295
  *
15252
- <example module="compile">
15296
+ <example module="compileExample">
15253
15297
  <file name="index.html">
15254
15298
  <script>
15255
- angular.module('compile', [], function($compileProvider) {
15299
+ angular.module('compileExample', [], function($compileProvider) {
15256
15300
  // configure new 'compile' directive by passing a directive
15257
15301
  // factory function. The factory function injects the '$compile'
15258
15302
  $compileProvider.directive('compile', function($compile) {
@@ -15276,15 +15320,14 @@ function $TemplateCacheProvider() {
15276
15320
  }
15277
15321
  );
15278
15322
  };
15279
- })
15280
- });
15281
-
15282
- function Ctrl($scope) {
15323
+ });
15324
+ })
15325
+ .controller('GreeterController', ['$scope', function($scope) {
15283
15326
  $scope.name = 'Angular';
15284
15327
  $scope.html = 'Hello {{name}}';
15285
- }
15328
+ }]);
15286
15329
  </script>
15287
- <div ng-controller="Ctrl">
15330
+ <div ng-controller="GreeterController">
15288
15331
  <input ng-model="name"> <br>
15289
15332
  <textarea ng-model="html"></textarea> <br>
15290
15333
  <div compile="html"></div>
@@ -15759,7 +15802,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15759
15802
  : null;
15760
15803
 
15761
15804
  if (nodeLinkFn && nodeLinkFn.scope) {
15762
- safeAddClass(jqLite(nodeList[i]), 'ng-scope');
15805
+ safeAddClass(attrs.$$element, 'ng-scope');
15763
15806
  }
15764
15807
 
15765
15808
  childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
@@ -15781,7 +15824,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15781
15824
  return linkFnFound ? compositeLinkFn : null;
15782
15825
 
15783
15826
  function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
15784
- var nodeLinkFn, childLinkFn, node, $node, childScope, i, ii, n, childBoundTranscludeFn;
15827
+ var nodeLinkFn, childLinkFn, node, childScope, i, ii, n, childBoundTranscludeFn;
15785
15828
 
15786
15829
  // copy nodeList so that linking doesn't break due to live list updates.
15787
15830
  var nodeListLength = nodeList.length,
@@ -15794,12 +15837,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15794
15837
  node = stableNodeList[n];
15795
15838
  nodeLinkFn = linkFns[i++];
15796
15839
  childLinkFn = linkFns[i++];
15797
- $node = jqLite(node);
15798
15840
 
15799
15841
  if (nodeLinkFn) {
15800
15842
  if (nodeLinkFn.scope) {
15801
15843
  childScope = scope.$new();
15802
- $node.data('$scope', childScope);
15844
+ jqLite.data(node, '$scope', childScope);
15803
15845
  } else {
15804
15846
  childScope = scope;
15805
15847
  }
@@ -15870,7 +15912,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15870
15912
  directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective);
15871
15913
 
15872
15914
  // iterate over the attributes
15873
- for (var attr, name, nName, ngAttrName, value, nAttrs = node.attributes,
15915
+ for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
15874
15916
  j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
15875
15917
  var attrStartName = false;
15876
15918
  var attrEndName = false;
@@ -15878,9 +15920,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15878
15920
  attr = nAttrs[j];
15879
15921
  if (!msie || msie >= 8 || attr.specified) {
15880
15922
  name = attr.name;
15923
+ value = trim(attr.value);
15924
+
15881
15925
  // support ngAttr attribute binding
15882
15926
  ngAttrName = directiveNormalize(name);
15883
- if (NG_ATTR_BINDING.test(ngAttrName)) {
15927
+ if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
15884
15928
  name = snake_case(ngAttrName.substr(6), '-');
15885
15929
  }
15886
15930
 
@@ -15893,9 +15937,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15893
15937
 
15894
15938
  nName = directiveNormalize(name.toLowerCase());
15895
15939
  attrsMap[nName] = name;
15896
- attrs[nName] = value = trim(attr.value);
15897
- if (getBooleanAttrName(node, nName)) {
15898
- attrs[nName] = true; // presence means true
15940
+ if (isNgAttr || !attrs.hasOwnProperty(nName)) {
15941
+ attrs[nName] = value;
15942
+ if (getBooleanAttrName(node, nName)) {
15943
+ attrs[nName] = true; // presence means true
15944
+ }
15899
15945
  }
15900
15946
  addAttrInterpolateDirective(node, directives, value, nName);
15901
15947
  addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
@@ -16087,12 +16133,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16087
16133
  if (directiveValue == 'element') {
16088
16134
  hasElementTranscludeDirective = true;
16089
16135
  terminalPriority = directive.priority;
16090
- $template = groupScan(compileNode, attrStart, attrEnd);
16136
+ $template = $compileNode;
16091
16137
  $compileNode = templateAttrs.$$element =
16092
16138
  jqLite(document.createComment(' ' + directiveName + ': ' +
16093
16139
  templateAttrs[directiveName] + ' '));
16094
16140
  compileNode = $compileNode[0];
16095
- replaceWith(jqCollection, jqLite(sliceArgs($template)), compileNode);
16141
+ replaceWith(jqCollection, sliceArgs($template), compileNode);
16096
16142
 
16097
16143
  childTranscludeFn = compile($template, transcludeFn, terminalPriority,
16098
16144
  replaceDirective && replaceDirective.name, {
@@ -16269,29 +16315,26 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16269
16315
  function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
16270
16316
  var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn;
16271
16317
 
16272
- if (compileNode === linkNode) {
16273
- attrs = templateAttrs;
16274
- } else {
16275
- attrs = shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
16276
- }
16318
+ attrs = (compileNode === linkNode)
16319
+ ? templateAttrs
16320
+ : shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
16277
16321
  $element = attrs.$$element;
16278
16322
 
16279
16323
  if (newIsolateScopeDirective) {
16280
16324
  var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
16281
- var $linkNode = jqLite(linkNode);
16282
16325
 
16283
16326
  isolateScope = scope.$new(true);
16284
16327
 
16285
16328
  if (templateDirective && (templateDirective === newIsolateScopeDirective ||
16286
16329
  templateDirective === newIsolateScopeDirective.$$originalDirective)) {
16287
- $linkNode.data('$isolateScope', isolateScope) ;
16330
+ $element.data('$isolateScope', isolateScope);
16288
16331
  } else {
16289
- $linkNode.data('$isolateScopeNoTemplate', isolateScope);
16332
+ $element.data('$isolateScopeNoTemplate', isolateScope);
16290
16333
  }
16291
16334
 
16292
16335
 
16293
16336
 
16294
- safeAddClass($linkNode, 'ng-isolate-scope');
16337
+ safeAddClass($element, 'ng-isolate-scope');
16295
16338
 
16296
16339
  forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
16297
16340
  var match = definition.match(LOCAL_REGEXP) || [],
@@ -16993,7 +17036,7 @@ function $ControllerProvider() {
16993
17036
  instance = $injector.instantiate(expression, locals);
16994
17037
 
16995
17038
  if (identifier) {
16996
- if (!(locals && typeof locals.$scope == 'object')) {
17039
+ if (!(locals && typeof locals.$scope === 'object')) {
16997
17040
  throw minErr('$controller')('noscp',
16998
17041
  "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
16999
17042
  constructor || expression.name, identifier);
@@ -17016,18 +17059,19 @@ function $ControllerProvider() {
17016
17059
  * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
17017
17060
  *
17018
17061
  * @example
17019
- <example>
17062
+ <example module="documentExample">
17020
17063
  <file name="index.html">
17021
- <div ng-controller="MainCtrl">
17064
+ <div ng-controller="ExampleController">
17022
17065
  <p>$document title: <b ng-bind="title"></b></p>
17023
17066
  <p>window.document title: <b ng-bind="windowTitle"></b></p>
17024
17067
  </div>
17025
17068
  </file>
17026
17069
  <file name="script.js">
17027
- function MainCtrl($scope, $document) {
17028
- $scope.title = $document[0].title;
17029
- $scope.windowTitle = angular.element(window.document)[0].title;
17030
- }
17070
+ angular.module('documentExample', [])
17071
+ .controller('ExampleController', ['$scope', '$document', function($scope, $document) {
17072
+ $scope.title = $document[0].title;
17073
+ $scope.windowTitle = angular.element(window.document)[0].title;
17074
+ }]);
17031
17075
  </file>
17032
17076
  </example>
17033
17077
  */
@@ -17094,11 +17138,7 @@ function parseHeaders(headers) {
17094
17138
  val = trim(line.substr(i + 1));
17095
17139
 
17096
17140
  if (key) {
17097
- if (parsed[key]) {
17098
- parsed[key] += ', ' + val;
17099
- } else {
17100
- parsed[key] = val;
17101
- }
17141
+ parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
17102
17142
  }
17103
17143
  });
17104
17144
 
@@ -17160,12 +17200,39 @@ function isSuccess(status) {
17160
17200
  }
17161
17201
 
17162
17202
 
17203
+ /**
17204
+ * @ngdoc provider
17205
+ * @name $httpProvider
17206
+ * @description
17207
+ * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
17208
+ * */
17163
17209
  function $HttpProvider() {
17164
17210
  var JSON_START = /^\s*(\[|\{[^\{])/,
17165
17211
  JSON_END = /[\}\]]\s*$/,
17166
17212
  PROTECTION_PREFIX = /^\)\]\}',?\n/,
17167
17213
  CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': 'application/json;charset=utf-8'};
17168
17214
 
17215
+ /**
17216
+ * @ngdoc property
17217
+ * @name $httpProvider#defaults
17218
+ * @description
17219
+ *
17220
+ * Object containing default values for all {@link ng.$http $http} requests.
17221
+ *
17222
+ * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
17223
+ * Defaults value is `'XSRF-TOKEN'`.
17224
+ *
17225
+ * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
17226
+ * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
17227
+ *
17228
+ * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
17229
+ * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
17230
+ * setting default headers.
17231
+ * - **`defaults.headers.common`**
17232
+ * - **`defaults.headers.post`**
17233
+ * - **`defaults.headers.put`**
17234
+ * - **`defaults.headers.patch`**
17235
+ **/
17169
17236
  var defaults = this.defaults = {
17170
17237
  // transform incoming response data
17171
17238
  transformResponse: [function(data) {
@@ -17655,9 +17722,9 @@ function $HttpProvider() {
17655
17722
  *
17656
17723
  *
17657
17724
  * @example
17658
- <example>
17725
+ <example module="httpExample">
17659
17726
  <file name="index.html">
17660
- <div ng-controller="FetchCtrl">
17727
+ <div ng-controller="FetchController">
17661
17728
  <select ng-model="method">
17662
17729
  <option>GET</option>
17663
17730
  <option>JSONP</option>
@@ -17679,30 +17746,32 @@ function $HttpProvider() {
17679
17746
  </div>
17680
17747
  </file>
17681
17748
  <file name="script.js">
17682
- function FetchCtrl($scope, $http, $templateCache) {
17683
- $scope.method = 'GET';
17684
- $scope.url = 'http-hello.html';
17685
-
17686
- $scope.fetch = function() {
17687
- $scope.code = null;
17688
- $scope.response = null;
17689
-
17690
- $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
17691
- success(function(data, status) {
17692
- $scope.status = status;
17693
- $scope.data = data;
17694
- }).
17695
- error(function(data, status) {
17696
- $scope.data = data || "Request failed";
17697
- $scope.status = status;
17698
- });
17699
- };
17749
+ angular.module('httpExample', [])
17750
+ .controller('FetchController', ['$scope', '$http', '$templateCache',
17751
+ function($scope, $http, $templateCache) {
17752
+ $scope.method = 'GET';
17753
+ $scope.url = 'http-hello.html';
17754
+
17755
+ $scope.fetch = function() {
17756
+ $scope.code = null;
17757
+ $scope.response = null;
17758
+
17759
+ $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
17760
+ success(function(data, status) {
17761
+ $scope.status = status;
17762
+ $scope.data = data;
17763
+ }).
17764
+ error(function(data, status) {
17765
+ $scope.data = data || "Request failed";
17766
+ $scope.status = status;
17767
+ });
17768
+ };
17700
17769
 
17701
- $scope.updateModel = function(method, url) {
17702
- $scope.method = method;
17703
- $scope.url = url;
17704
- };
17705
- }
17770
+ $scope.updateModel = function(method, url) {
17771
+ $scope.method = method;
17772
+ $scope.url = url;
17773
+ };
17774
+ }]);
17706
17775
  </file>
17707
17776
  <file name="http-hello.html">
17708
17777
  Hello, $http!
@@ -17756,7 +17825,7 @@ function $HttpProvider() {
17756
17825
  var reqData = transformData(config.data, headersGetter(headers), config.transformRequest);
17757
17826
 
17758
17827
  // strip content-type if data is undefined
17759
- if (isUndefined(config.data)) {
17828
+ if (isUndefined(reqData)) {
17760
17829
  forEach(headers, function(value, header) {
17761
17830
  if (lowercase(header) === 'content-type') {
17762
17831
  delete headers[header];
@@ -17825,10 +17894,6 @@ function $HttpProvider() {
17825
17894
 
17826
17895
  defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
17827
17896
 
17828
- // execute if header value is function
17829
- execHeaders(defHeaders);
17830
- execHeaders(reqHeaders);
17831
-
17832
17897
  // using for-in instead of forEach to avoid unecessary iteration after header has been found
17833
17898
  defaultHeadersIteration:
17834
17899
  for (defHeaderName in defHeaders) {
@@ -17843,6 +17908,8 @@ function $HttpProvider() {
17843
17908
  reqHeaders[defHeaderName] = defHeaders[defHeaderName];
17844
17909
  }
17845
17910
 
17911
+ // execute if header value is a function for merged headers
17912
+ execHeaders(reqHeaders);
17846
17913
  return reqHeaders;
17847
17914
 
17848
17915
  function execHeaders(headers) {
@@ -17908,7 +17975,7 @@ function $HttpProvider() {
17908
17975
  * Shortcut method to perform `JSONP` request.
17909
17976
  *
17910
17977
  * @param {string} url Relative or absolute URL specifying the destination of the request.
17911
- * Should contain `JSON_CALLBACK` string.
17978
+ * The name of the callback should be the string `JSON_CALLBACK`.
17912
17979
  * @param {Object=} config Optional configuration object
17913
17980
  * @returns {HttpPromise} Future object
17914
17981
  */
@@ -18008,7 +18075,7 @@ function $HttpProvider() {
18008
18075
  if (cache) {
18009
18076
  cachedResp = cache.get(url);
18010
18077
  if (isDefined(cachedResp)) {
18011
- if (cachedResp.then) {
18078
+ if (isPromiseLike(cachedResp)) {
18012
18079
  // cached request has already been sent, but there is no response yet
18013
18080
  cachedResp.then(removePendingReq, removePendingReq);
18014
18081
  return cachedResp;
@@ -18090,27 +18157,29 @@ function $HttpProvider() {
18090
18157
 
18091
18158
 
18092
18159
  function buildUrl(url, params) {
18093
- if (!params) return url;
18094
- var parts = [];
18095
- forEachSorted(params, function(value, key) {
18096
- if (value === null || isUndefined(value)) return;
18097
- if (!isArray(value)) value = [value];
18098
-
18099
- forEach(value, function(v) {
18100
- if (isObject(v)) {
18101
- v = toJson(v);
18102
- }
18103
- parts.push(encodeUriQuery(key) + '=' +
18104
- encodeUriQuery(v));
18105
- });
18106
- });
18107
- if(parts.length > 0) {
18108
- url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
18160
+ if (!params) return url;
18161
+ var parts = [];
18162
+ forEachSorted(params, function(value, key) {
18163
+ if (value === null || isUndefined(value)) return;
18164
+ if (!isArray(value)) value = [value];
18165
+
18166
+ forEach(value, function(v) {
18167
+ if (isObject(v)) {
18168
+ if (isDate(v)){
18169
+ v = v.toISOString();
18170
+ } else if (isObject(v)) {
18171
+ v = toJson(v);
18172
+ }
18109
18173
  }
18110
- return url;
18111
- }
18112
-
18113
-
18174
+ parts.push(encodeUriQuery(key) + '=' +
18175
+ encodeUriQuery(v));
18176
+ });
18177
+ });
18178
+ if(parts.length > 0) {
18179
+ url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
18180
+ }
18181
+ return url;
18182
+ }
18114
18183
  }];
18115
18184
  }
18116
18185
 
@@ -18195,7 +18264,8 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
18195
18264
  // Safari respectively.
18196
18265
  if (xhr && xhr.readyState == 4) {
18197
18266
  var responseHeaders = null,
18198
- response = null;
18267
+ response = null,
18268
+ statusText = '';
18199
18269
 
18200
18270
  if(status !== ABORTED) {
18201
18271
  responseHeaders = xhr.getAllResponseHeaders();
@@ -18205,11 +18275,17 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
18205
18275
  response = ('response' in xhr) ? xhr.response : xhr.responseText;
18206
18276
  }
18207
18277
 
18278
+ // Accessing statusText on an aborted xhr object will
18279
+ // throw an 'c00c023f error' in IE9 and lower, don't touch it.
18280
+ if (!(status === ABORTED && msie < 10)) {
18281
+ statusText = xhr.statusText;
18282
+ }
18283
+
18208
18284
  completeRequest(callback,
18209
18285
  status || xhr.status,
18210
18286
  response,
18211
18287
  responseHeaders,
18212
- xhr.statusText || '');
18288
+ statusText);
18213
18289
  }
18214
18290
  };
18215
18291
 
@@ -18239,7 +18315,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
18239
18315
 
18240
18316
  if (timeout > 0) {
18241
18317
  var timeoutId = $browserDefer(timeoutRequest, timeout);
18242
- } else if (timeout && timeout.then) {
18318
+ } else if (isPromiseLike(timeout)) {
18243
18319
  timeout.then(timeoutRequest);
18244
18320
  }
18245
18321
 
@@ -18611,25 +18687,27 @@ function $IntervalProvider() {
18611
18687
  * @returns {promise} A promise which will be notified on each iteration.
18612
18688
  *
18613
18689
  * @example
18614
- * <example module="time">
18615
- * <file name="index.html">
18616
- * <script>
18617
- * function Ctrl2($scope,$interval) {
18618
- * $scope.format = 'M/d/yy h:mm:ss a';
18619
- * $scope.blood_1 = 100;
18620
- * $scope.blood_2 = 120;
18690
+ * <example module="intervalExample">
18691
+ * <file name="index.html">
18692
+ * <script>
18693
+ * angular.module('intervalExample', [])
18694
+ * .controller('ExampleController', ['$scope', '$interval',
18695
+ * function($scope, $interval) {
18696
+ * $scope.format = 'M/d/yy h:mm:ss a';
18697
+ * $scope.blood_1 = 100;
18698
+ * $scope.blood_2 = 120;
18621
18699
  *
18622
- * var stop;
18623
- * $scope.fight = function() {
18624
- * // Don't start a new fight if we are already fighting
18625
- * if ( angular.isDefined(stop) ) return;
18700
+ * var stop;
18701
+ * $scope.fight = function() {
18702
+ * // Don't start a new fight if we are already fighting
18703
+ * if ( angular.isDefined(stop) ) return;
18626
18704
  *
18627
18705
  * stop = $interval(function() {
18628
18706
  * if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
18629
- * $scope.blood_1 = $scope.blood_1 - 3;
18630
- * $scope.blood_2 = $scope.blood_2 - 4;
18707
+ * $scope.blood_1 = $scope.blood_1 - 3;
18708
+ * $scope.blood_2 = $scope.blood_2 - 4;
18631
18709
  * } else {
18632
- * $scope.stopFight();
18710
+ * $scope.stopFight();
18633
18711
  * }
18634
18712
  * }, 100);
18635
18713
  * };
@@ -18644,22 +18722,21 @@ function $IntervalProvider() {
18644
18722
  * $scope.resetFight = function() {
18645
18723
  * $scope.blood_1 = 100;
18646
18724
  * $scope.blood_2 = 120;
18647
- * }
18725
+ * };
18648
18726
  *
18649
18727
  * $scope.$on('$destroy', function() {
18650
- * // Make sure that the interval is destroyed too
18728
+ * // Make sure that the interval nis destroyed too
18651
18729
  * $scope.stopFight();
18652
18730
  * });
18653
- * }
18654
- *
18655
- * angular.module('time', [])
18656
- * // Register the 'myCurrentTime' directive factory method.
18657
- * // We inject $interval and dateFilter service since the factory method is DI.
18658
- * .directive('myCurrentTime', function($interval, dateFilter) {
18731
+ * }])
18732
+ * // Register the 'myCurrentTime' directive factory method.
18733
+ * // We inject $interval and dateFilter service since the factory method is DI.
18734
+ * .directive('myCurrentTime', ['$interval', 'dateFilter',
18735
+ * function($interval, dateFilter) {
18659
18736
  * // return the directive link function. (compile function not needed)
18660
18737
  * return function(scope, element, attrs) {
18661
18738
  * var format, // date format
18662
- * stopTime; // so that we can cancel the time updates
18739
+ * stopTime; // so that we can cancel the time updates
18663
18740
  *
18664
18741
  * // used to update the UI
18665
18742
  * function updateTime() {
@@ -18675,28 +18752,28 @@ function $IntervalProvider() {
18675
18752
  * stopTime = $interval(updateTime, 1000);
18676
18753
  *
18677
18754
  * // listen on DOM destroy (removal) event, and cancel the next UI update
18678
- * // to prevent updating time ofter the DOM element was removed.
18755
+ * // to prevent updating time after the DOM element was removed.
18679
18756
  * element.bind('$destroy', function() {
18680
18757
  * $interval.cancel(stopTime);
18681
18758
  * });
18682
18759
  * }
18683
- * });
18684
- * </script>
18760
+ * }]);
18761
+ * </script>
18685
18762
  *
18686
- * <div>
18687
- * <div ng-controller="Ctrl2">
18688
- * Date format: <input ng-model="format"> <hr/>
18689
- * Current time is: <span my-current-time="format"></span>
18690
- * <hr/>
18691
- * Blood 1 : <font color='red'>{{blood_1}}</font>
18692
- * Blood 2 : <font color='red'>{{blood_2}}</font>
18693
- * <button type="button" data-ng-click="fight()">Fight</button>
18694
- * <button type="button" data-ng-click="stopFight()">StopFight</button>
18695
- * <button type="button" data-ng-click="resetFight()">resetFight</button>
18696
- * </div>
18763
+ * <div>
18764
+ * <div ng-controller="ExampleController">
18765
+ * Date format: <input ng-model="format"> <hr/>
18766
+ * Current time is: <span my-current-time="format"></span>
18767
+ * <hr/>
18768
+ * Blood 1 : <font color='red'>{{blood_1}}</font>
18769
+ * Blood 2 : <font color='red'>{{blood_2}}</font>
18770
+ * <button type="button" data-ng-click="fight()">Fight</button>
18771
+ * <button type="button" data-ng-click="stopFight()">StopFight</button>
18772
+ * <button type="button" data-ng-click="resetFight()">resetFight</button>
18697
18773
  * </div>
18774
+ * </div>
18698
18775
  *
18699
- * </file>
18776
+ * </file>
18700
18777
  * </example>
18701
18778
  */
18702
18779
  function interval(fn, delay, count, invokeApply) {
@@ -18743,7 +18820,7 @@ function $IntervalProvider() {
18743
18820
  interval.cancel = function(promise) {
18744
18821
  if (promise && promise.$$intervalId in intervals) {
18745
18822
  intervals[promise.$$intervalId].reject('canceled');
18746
- clearInterval(promise.$$intervalId);
18823
+ $window.clearInterval(promise.$$intervalId);
18747
18824
  delete intervals[promise.$$intervalId];
18748
18825
  return true;
18749
18826
  }
@@ -19253,14 +19330,17 @@ LocationHashbangInHtml5Url.prototype =
19253
19330
  * If the argument is a hash object containing an array of values, these values will be encoded
19254
19331
  * as duplicate search parameters in the url.
19255
19332
  *
19256
- * @param {(string|Array<string>)=} paramValue If `search` is a string, then `paramValue` will
19257
- * override only a single search property.
19333
+ * @param {(string|Array<string>|boolean)=} paramValue If `search` is a string, then `paramValue`
19334
+ * will override only a single search property.
19258
19335
  *
19259
19336
  * If `paramValue` is an array, it will override the property of the `search` component of
19260
19337
  * `$location` specified via the first argument.
19261
19338
  *
19262
19339
  * If `paramValue` is `null`, the property specified via the first argument will be deleted.
19263
19340
  *
19341
+ * If `paramValue` is `true`, the property specified via the first argument will be added with no
19342
+ * value nor trailing equal sign.
19343
+ *
19264
19344
  * @return {Object} If called with no arguments returns the parsed `search` object. If called with
19265
19345
  * one or more arguments returns `$location` object itself.
19266
19346
  */
@@ -19272,6 +19352,11 @@ LocationHashbangInHtml5Url.prototype =
19272
19352
  if (isString(search)) {
19273
19353
  this.$$search = parseKeyValue(search);
19274
19354
  } else if (isObject(search)) {
19355
+ // remove object undefined or null properties
19356
+ forEach(search, function(value, key) {
19357
+ if (value == null) delete search[key];
19358
+ });
19359
+
19275
19360
  this.$$search = search;
19276
19361
  } else {
19277
19362
  throw $locationMinErr('isrcharg',
@@ -19377,7 +19462,7 @@ function $LocationProvider(){
19377
19462
  html5Mode = false;
19378
19463
 
19379
19464
  /**
19380
- * @ngdoc property
19465
+ * @ngdoc method
19381
19466
  * @name $locationProvider#hashPrefix
19382
19467
  * @description
19383
19468
  * @param {string=} prefix Prefix for hash part (containing path and search)
@@ -19393,7 +19478,7 @@ function $LocationProvider(){
19393
19478
  };
19394
19479
 
19395
19480
  /**
19396
- * @ngdoc property
19481
+ * @ngdoc method
19397
19482
  * @name $locationProvider#html5Mode
19398
19483
  * @description
19399
19484
  * @param {boolean=} mode Use HTML5 strategy if available.
@@ -19593,15 +19678,16 @@ function $LocationProvider(){
19593
19678
  * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
19594
19679
  *
19595
19680
  * @example
19596
- <example>
19681
+ <example module="logExample">
19597
19682
  <file name="script.js">
19598
- function LogCtrl($scope, $log) {
19599
- $scope.$log = $log;
19600
- $scope.message = 'Hello World!';
19601
- }
19683
+ angular.module('logExample', [])
19684
+ .controller('LogController', ['$scope', '$log', function($scope, $log) {
19685
+ $scope.$log = $log;
19686
+ $scope.message = 'Hello World!';
19687
+ }]);
19602
19688
  </file>
19603
19689
  <file name="index.html">
19604
- <div ng-controller="LogCtrl">
19690
+ <div ng-controller="LogController">
19605
19691
  <p>Reload this page with open console, enter text and hit the log button...</p>
19606
19692
  Message:
19607
19693
  <input type="text" ng-model="message"/>
@@ -19625,7 +19711,7 @@ function $LogProvider(){
19625
19711
  self = this;
19626
19712
 
19627
19713
  /**
19628
- * @ngdoc property
19714
+ * @ngdoc method
19629
19715
  * @name $logProvider#debugEnabled
19630
19716
  * @description
19631
19717
  * @param {boolean=} flag enable or disable debug level messages
@@ -19751,14 +19837,7 @@ var promiseWarning;
19751
19837
  //
19752
19838
  // As an example, consider the following Angular expression:
19753
19839
  //
19754
- // {}.toString.constructor(alert("evil JS code"))
19755
- //
19756
- // We want to prevent this type of access. For the sake of performance, during the lexing phase we
19757
- // disallow any "dotted" access to any member named "constructor".
19758
- //
19759
- // For reflective calls (a[b]) we check that the value of the lookup is not the Function constructor
19760
- // while evaluating the expression, which is a stronger but more expensive test. Since reflective
19761
- // calls are expensive anyway, this is not such a big deal compared to static dereferencing.
19840
+ // {}.toString.constructor('alert("evil JS code")')
19762
19841
  //
19763
19842
  // This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
19764
19843
  // against the expression language, but not to prevent exploits that were enabled by exposing
@@ -19766,17 +19845,19 @@ var promiseWarning;
19766
19845
  // practice and therefore we are not even trying to protect against interaction with an object
19767
19846
  // explicitly exposed in this way.
19768
19847
  //
19769
- // A developer could foil the name check by aliasing the Function constructor under a different
19770
- // name on the scope.
19771
- //
19772
19848
  // In general, it is not possible to access a Window object from an angular expression unless a
19773
19849
  // window or some DOM object that has a reference to window is published onto a Scope.
19850
+ // Similarly we prevent invocations of function known to be dangerous, as well as assignments to
19851
+ // native objects.
19852
+
19774
19853
 
19775
19854
  function ensureSafeMemberName(name, fullExpression) {
19776
- if (name === "constructor") {
19855
+ if (name === "__defineGetter__" || name === "__defineSetter__"
19856
+ || name === "__lookupGetter__" || name === "__lookupSetter__"
19857
+ || name === "__proto__") {
19777
19858
  throw $parseMinErr('isecfld',
19778
- 'Referencing "constructor" field in Angular expressions is disallowed! Expression: {0}',
19779
- fullExpression);
19859
+ 'Attempting to access a disallowed field in Angular expressions! '
19860
+ +'Expression: {0}', fullExpression);
19780
19861
  }
19781
19862
  return name;
19782
19863
  }
@@ -19798,11 +19879,34 @@ function ensureSafeObject(obj, fullExpression) {
19798
19879
  throw $parseMinErr('isecdom',
19799
19880
  'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
19800
19881
  fullExpression);
19882
+ } else if (// block Object so that we can't get hold of dangerous Object.* methods
19883
+ obj === Object) {
19884
+ throw $parseMinErr('isecobj',
19885
+ 'Referencing Object in Angular expressions is disallowed! Expression: {0}',
19886
+ fullExpression);
19801
19887
  }
19802
19888
  }
19803
19889
  return obj;
19804
19890
  }
19805
19891
 
19892
+ var CALL = Function.prototype.call;
19893
+ var APPLY = Function.prototype.apply;
19894
+ var BIND = Function.prototype.bind;
19895
+
19896
+ function ensureSafeFunction(obj, fullExpression) {
19897
+ if (obj) {
19898
+ if (obj.constructor === obj) {
19899
+ throw $parseMinErr('isecfn',
19900
+ 'Referencing Function in Angular expressions is disallowed! Expression: {0}',
19901
+ fullExpression);
19902
+ } else if (obj === CALL || obj === APPLY || (BIND && obj === BIND)) {
19903
+ throw $parseMinErr('isecff',
19904
+ 'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
19905
+ fullExpression);
19906
+ }
19907
+ }
19908
+ }
19909
+
19806
19910
  var OPERATORS = {
19807
19911
  /* jshint bitwise : false */
19808
19912
  'null':function(){return null;},
@@ -20082,11 +20186,7 @@ Lexer.prototype = {
20082
20186
  string += String.fromCharCode(parseInt(hex, 16));
20083
20187
  } else {
20084
20188
  var rep = ESCAPE[ch];
20085
- if (rep) {
20086
- string += rep;
20087
- } else {
20088
- string += ch;
20089
- }
20189
+ string = string + (rep || ch);
20090
20190
  }
20091
20191
  escape = false;
20092
20192
  } else if (ch === '\\') {
@@ -20437,6 +20537,7 @@ Parser.prototype = {
20437
20537
  i = indexFn(self, locals),
20438
20538
  v, p;
20439
20539
 
20540
+ ensureSafeMemberName(i, parser.text);
20440
20541
  if (!o) return undefined;
20441
20542
  v = ensureSafeObject(o[i], parser.text);
20442
20543
  if (v && v.then && parser.options.unwrapPromises) {
@@ -20479,7 +20580,7 @@ Parser.prototype = {
20479
20580
  var fnPtr = fn(scope, locals, context) || noop;
20480
20581
 
20481
20582
  ensureSafeObject(context, parser.text);
20482
- ensureSafeObject(fnPtr, parser.text);
20583
+ ensureSafeFunction(fnPtr, parser.text);
20483
20584
 
20484
20585
  // IE stupidity! (IE doesn't have apply for some native functions)
20485
20586
  var v = fnPtr.apply
@@ -20588,6 +20689,8 @@ function setter(obj, path, setValue, fullExp, options) {
20588
20689
  }
20589
20690
  }
20590
20691
  key = ensureSafeMemberName(element.shift(), fullExp);
20692
+ ensureSafeObject(obj, fullExp);
20693
+ ensureSafeObject(obj[key], fullExp);
20591
20694
  obj[key] = setValue;
20592
20695
  return setValue;
20593
20696
  }
@@ -20703,26 +20806,6 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
20703
20806
  };
20704
20807
  }
20705
20808
 
20706
- function simpleGetterFn1(key0, fullExp) {
20707
- ensureSafeMemberName(key0, fullExp);
20708
-
20709
- return function simpleGetterFn1(scope, locals) {
20710
- if (scope == null) return undefined;
20711
- return ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
20712
- };
20713
- }
20714
-
20715
- function simpleGetterFn2(key0, key1, fullExp) {
20716
- ensureSafeMemberName(key0, fullExp);
20717
- ensureSafeMemberName(key1, fullExp);
20718
-
20719
- return function simpleGetterFn2(scope, locals) {
20720
- if (scope == null) return undefined;
20721
- scope = ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
20722
- return scope == null ? undefined : scope[key1];
20723
- };
20724
- }
20725
-
20726
20809
  function getterFn(path, options, fullExp) {
20727
20810
  // Check whether the cache has this getter already.
20728
20811
  // We can use hasOwnProperty directly on the cache because we ensure,
@@ -20735,13 +20818,8 @@ function getterFn(path, options, fullExp) {
20735
20818
  pathKeysLength = pathKeys.length,
20736
20819
  fn;
20737
20820
 
20738
- // When we have only 1 or 2 tokens, use optimized special case closures.
20739
20821
  // http://jsperf.com/angularjs-parse-getter/6
20740
- if (!options.unwrapPromises && pathKeysLength === 1) {
20741
- fn = simpleGetterFn1(pathKeys[0], fullExp);
20742
- } else if (!options.unwrapPromises && pathKeysLength === 2) {
20743
- fn = simpleGetterFn2(pathKeys[0], pathKeys[1], fullExp);
20744
- } else if (options.csp) {
20822
+ if (options.csp) {
20745
20823
  if (pathKeysLength < 6) {
20746
20824
  fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
20747
20825
  options);
@@ -21007,17 +21085,13 @@ function $ParseProvider() {
21007
21085
  * var deferred = $q.defer();
21008
21086
  *
21009
21087
  * setTimeout(function() {
21010
- * // since this fn executes async in a future turn of the event loop, we need to wrap
21011
- * // our code into an $apply call so that the model changes are properly observed.
21012
- * scope.$apply(function() {
21013
- * deferred.notify('About to greet ' + name + '.');
21014
- *
21015
- * if (okToGreet(name)) {
21016
- * deferred.resolve('Hello, ' + name + '!');
21017
- * } else {
21018
- * deferred.reject('Greeting ' + name + ' is not allowed.');
21019
- * }
21020
- * });
21088
+ * deferred.notify('About to greet ' + name + '.');
21089
+ *
21090
+ * if (okToGreet(name)) {
21091
+ * deferred.resolve('Hello, ' + name + '!');
21092
+ * } else {
21093
+ * deferred.reject('Greeting ' + name + ' is not allowed.');
21094
+ * }
21021
21095
  * }, 1000);
21022
21096
  *
21023
21097
  * return deferred.promise;
@@ -21291,7 +21365,7 @@ function qFactory(nextTick, exceptionHandler) {
21291
21365
  } catch(e) {
21292
21366
  return makePromise(e, false);
21293
21367
  }
21294
- if (callbackOutput && isFunction(callbackOutput.then)) {
21368
+ if (isPromiseLike(callbackOutput)) {
21295
21369
  return callbackOutput.then(function() {
21296
21370
  return makePromise(value, isResolved);
21297
21371
  }, function(error) {
@@ -21316,7 +21390,7 @@ function qFactory(nextTick, exceptionHandler) {
21316
21390
 
21317
21391
 
21318
21392
  var ref = function(value) {
21319
- if (value && isFunction(value.then)) return value;
21393
+ if (isPromiseLike(value)) return value;
21320
21394
  return {
21321
21395
  then: function(callback) {
21322
21396
  var result = defer();
@@ -21983,7 +22057,7 @@ function $RootScopeProvider(){
21983
22057
 
21984
22058
  function $watchCollectionWatch() {
21985
22059
  newValue = objGetter(self);
21986
- var newLength, key;
22060
+ var newLength, key, bothNaN;
21987
22061
 
21988
22062
  if (!isObject(newValue)) { // if primitive
21989
22063
  if (oldValue !== newValue) {
@@ -22007,7 +22081,7 @@ function $RootScopeProvider(){
22007
22081
  }
22008
22082
  // copy the items to oldValue and look for changes.
22009
22083
  for (var i = 0; i < newLength; i++) {
22010
- var bothNaN = (oldValue[i] !== oldValue[i]) &&
22084
+ bothNaN = (oldValue[i] !== oldValue[i]) &&
22011
22085
  (newValue[i] !== newValue[i]);
22012
22086
  if (!bothNaN && (oldValue[i] !== newValue[i])) {
22013
22087
  changeDetected++;
@@ -22027,7 +22101,9 @@ function $RootScopeProvider(){
22027
22101
  if (newValue.hasOwnProperty(key)) {
22028
22102
  newLength++;
22029
22103
  if (oldValue.hasOwnProperty(key)) {
22030
- if (oldValue[key] !== newValue[key]) {
22104
+ bothNaN = (oldValue[key] !== oldValue[key]) &&
22105
+ (newValue[key] !== newValue[key]);
22106
+ if (!bothNaN && (oldValue[key] !== newValue[key])) {
22031
22107
  changeDetected++;
22032
22108
  oldValue[key] = newValue[key];
22033
22109
  }
@@ -22179,7 +22255,7 @@ function $RootScopeProvider(){
22179
22255
  if ((value = watch.get(current)) !== (last = watch.last) &&
22180
22256
  !(watch.eq
22181
22257
  ? equals(value, last)
22182
- : (typeof value == 'number' && typeof last == 'number'
22258
+ : (typeof value === 'number' && typeof last === 'number'
22183
22259
  && isNaN(value) && isNaN(last)))) {
22184
22260
  dirty = true;
22185
22261
  lastDirtyWatch = watch;
@@ -22872,19 +22948,21 @@ function adjustMatchers(matchers) {
22872
22948
  *
22873
22949
  * Here is what a secure configuration for this scenario might look like:
22874
22950
  *
22875
- * <pre class="prettyprint">
22876
- * angular.module('myApp', []).config(function($sceDelegateProvider) {
22877
- * $sceDelegateProvider.resourceUrlWhitelist([
22878
- * // Allow same origin resource loads.
22879
- * 'self',
22880
- * // Allow loading from our assets domain. Notice the difference between * and **.
22881
- * 'http://srv*.assets.example.com/**']);
22882
- *
22883
- * // The blacklist overrides the whitelist so the open redirect here is blocked.
22884
- * $sceDelegateProvider.resourceUrlBlacklist([
22885
- * 'http://myapp.example.com/clickThru**']);
22886
- * });
22887
- * </pre>
22951
+ * ```
22952
+ * angular.module('myApp', []).config(function($sceDelegateProvider) {
22953
+ * $sceDelegateProvider.resourceUrlWhitelist([
22954
+ * // Allow same origin resource loads.
22955
+ * 'self',
22956
+ * // Allow loading from our assets domain. Notice the difference between * and **.
22957
+ * 'http://srv*.assets.example.com/**'
22958
+ * ]);
22959
+ *
22960
+ * // The blacklist overrides the whitelist so the open redirect here is blocked.
22961
+ * $sceDelegateProvider.resourceUrlBlacklist([
22962
+ * 'http://myapp.example.com/clickThru**'
22963
+ * ]);
22964
+ * });
22965
+ * ```
22888
22966
  */
22889
22967
 
22890
22968
  function $SceDelegateProvider() {
@@ -23179,10 +23257,10 @@ function $SceDelegateProvider() {
23179
23257
  *
23180
23258
  * Here's an example of a binding in a privileged context:
23181
23259
  *
23182
- * <pre class="prettyprint">
23183
- * <input ng-model="userHtml">
23184
- * <div ng-bind-html="userHtml">
23185
- * </pre>
23260
+ * ```
23261
+ * <input ng-model="userHtml">
23262
+ * <div ng-bind-html="userHtml"></div>
23263
+ * ```
23186
23264
  *
23187
23265
  * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user. With SCE
23188
23266
  * disabled, this application allows the user to render arbitrary HTML into the DIV.
@@ -23222,15 +23300,15 @@ function $SceDelegateProvider() {
23222
23300
  * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}. Here's the actual code (slightly
23223
23301
  * simplified):
23224
23302
  *
23225
- * <pre class="prettyprint">
23226
- * var ngBindHtmlDirective = ['$sce', function($sce) {
23227
- * return function(scope, element, attr) {
23228
- * scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
23229
- * element.html(value || '');
23230
- * });
23231
- * };
23232
- * }];
23233
- * </pre>
23303
+ * ```
23304
+ * var ngBindHtmlDirective = ['$sce', function($sce) {
23305
+ * return function(scope, element, attr) {
23306
+ * scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
23307
+ * element.html(value || '');
23308
+ * });
23309
+ * };
23310
+ * }];
23311
+ * ```
23234
23312
  *
23235
23313
  * ## Impact on loading templates
23236
23314
  *
@@ -23334,66 +23412,65 @@ function $SceDelegateProvider() {
23334
23412
  *
23335
23413
  * ## Show me an example using SCE.
23336
23414
  *
23337
- * @example
23338
- <example module="mySceApp" deps="angular-sanitize.js">
23339
- <file name="index.html">
23340
- <div ng-controller="myAppController as myCtrl">
23341
- <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
23342
- <b>User comments</b><br>
23343
- By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
23344
- $sanitize is available. If $sanitize isn't available, this results in an error instead of an
23345
- exploit.
23346
- <div class="well">
23347
- <div ng-repeat="userComment in myCtrl.userComments">
23348
- <b>{{userComment.name}}</b>:
23349
- <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
23350
- <br>
23351
- </div>
23352
- </div>
23353
- </div>
23354
- </file>
23355
-
23356
- <file name="script.js">
23357
- var mySceApp = angular.module('mySceApp', ['ngSanitize']);
23358
-
23359
- mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) {
23360
- var self = this;
23361
- $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
23362
- self.userComments = userComments;
23363
- });
23364
- self.explicitlyTrustedHtml = $sce.trustAsHtml(
23365
- '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
23366
- 'sanitization.&quot;">Hover over this text.</span>');
23367
- });
23368
- </file>
23369
-
23370
- <file name="test_data.json">
23371
- [
23372
- { "name": "Alice",
23373
- "htmlComment":
23374
- "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
23375
- },
23376
- { "name": "Bob",
23377
- "htmlComment": "<i>Yes!</i> Am I the only other one?"
23378
- }
23379
- ]
23380
- </file>
23381
-
23382
- <file name="protractor.js" type="protractor">
23383
- describe('SCE doc demo', function() {
23384
- it('should sanitize untrusted values', function() {
23385
- expect(element(by.css('.htmlComment')).getInnerHtml())
23386
- .toBe('<span>Is <i>anyone</i> reading this?</span>');
23387
- });
23388
-
23389
- it('should NOT sanitize explicitly trusted values', function() {
23390
- expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
23391
- '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
23392
- 'sanitization.&quot;">Hover over this text.</span>');
23393
- });
23394
- });
23395
- </file>
23396
- </example>
23415
+ * <example module="mySceApp" deps="angular-sanitize.js">
23416
+ * <file name="index.html">
23417
+ * <div ng-controller="myAppController as myCtrl">
23418
+ * <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
23419
+ * <b>User comments</b><br>
23420
+ * By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
23421
+ * $sanitize is available. If $sanitize isn't available, this results in an error instead of an
23422
+ * exploit.
23423
+ * <div class="well">
23424
+ * <div ng-repeat="userComment in myCtrl.userComments">
23425
+ * <b>{{userComment.name}}</b>:
23426
+ * <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
23427
+ * <br>
23428
+ * </div>
23429
+ * </div>
23430
+ * </div>
23431
+ * </file>
23432
+ *
23433
+ * <file name="script.js">
23434
+ * var mySceApp = angular.module('mySceApp', ['ngSanitize']);
23435
+ *
23436
+ * mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) {
23437
+ * var self = this;
23438
+ * $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
23439
+ * self.userComments = userComments;
23440
+ * });
23441
+ * self.explicitlyTrustedHtml = $sce.trustAsHtml(
23442
+ * '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
23443
+ * 'sanitization.&quot;">Hover over this text.</span>');
23444
+ * });
23445
+ * </file>
23446
+ *
23447
+ * <file name="test_data.json">
23448
+ * [
23449
+ * { "name": "Alice",
23450
+ * "htmlComment":
23451
+ * "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
23452
+ * },
23453
+ * { "name": "Bob",
23454
+ * "htmlComment": "<i>Yes!</i> Am I the only other one?"
23455
+ * }
23456
+ * ]
23457
+ * </file>
23458
+ *
23459
+ * <file name="protractor.js" type="protractor">
23460
+ * describe('SCE doc demo', function() {
23461
+ * it('should sanitize untrusted values', function() {
23462
+ * expect(element.all(by.css('.htmlComment')).first().getInnerHtml())
23463
+ * .toBe('<span>Is <i>anyone</i> reading this?</span>');
23464
+ * });
23465
+ *
23466
+ * it('should NOT sanitize explicitly trusted values', function() {
23467
+ * expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
23468
+ * '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
23469
+ * 'sanitization.&quot;">Hover over this text.</span>');
23470
+ * });
23471
+ * });
23472
+ * </file>
23473
+ * </example>
23397
23474
  *
23398
23475
  *
23399
23476
  *
@@ -23407,13 +23484,13 @@ function $SceDelegateProvider() {
23407
23484
  *
23408
23485
  * That said, here's how you can completely disable SCE:
23409
23486
  *
23410
- * <pre class="prettyprint">
23411
- * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
23412
- * // Completely disable SCE. For demonstration purposes only!
23413
- * // Do not use in new projects.
23414
- * $sceProvider.enabled(false);
23415
- * });
23416
- * </pre>
23487
+ * ```
23488
+ * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
23489
+ * // Completely disable SCE. For demonstration purposes only!
23490
+ * // Do not use in new projects.
23491
+ * $sceProvider.enabled(false);
23492
+ * });
23493
+ * ```
23417
23494
  *
23418
23495
  */
23419
23496
  /* jshint maxlen: 100 */
@@ -23524,7 +23601,7 @@ function $SceProvider() {
23524
23601
 
23525
23602
  /**
23526
23603
  * @ngdoc method
23527
- * @name $sce#parse
23604
+ * @name $sce#parseAs
23528
23605
  *
23529
23606
  * @description
23530
23607
  * Converts Angular {@link guide/expression expression} into a function. This is like {@link
@@ -24110,17 +24187,18 @@ function urlIsSameOrigin(requestUrl) {
24110
24187
  * expression.
24111
24188
  *
24112
24189
  * @example
24113
- <example>
24190
+ <example module="windowExample">
24114
24191
  <file name="index.html">
24115
24192
  <script>
24116
- function Ctrl($scope, $window) {
24117
- $scope.greeting = 'Hello, World!';
24118
- $scope.doGreeting = function(greeting) {
24193
+ angular.module('windowExample', [])
24194
+ .controller('ExampleController', ['$scope', '$window', function ($scope, $window) {
24195
+ $scope.greeting = 'Hello, World!';
24196
+ $scope.doGreeting = function(greeting) {
24119
24197
  $window.alert(greeting);
24120
- };
24121
- }
24198
+ };
24199
+ }]);
24122
24200
  </script>
24123
- <div ng-controller="Ctrl">
24201
+ <div ng-controller="ExampleController">
24124
24202
  <input type="text" ng-model="greeting" />
24125
24203
  <button ng-click="doGreeting(greeting)">ALERT</button>
24126
24204
  </div>
@@ -24138,6 +24216,17 @@ function $WindowProvider(){
24138
24216
  this.$get = valueFn(window);
24139
24217
  }
24140
24218
 
24219
+ /* global currencyFilter: true,
24220
+ dateFilter: true,
24221
+ filterFilter: true,
24222
+ jsonFilter: true,
24223
+ limitToFilter: true,
24224
+ lowercaseFilter: true,
24225
+ numberFilter: true,
24226
+ orderByFilter: true,
24227
+ uppercaseFilter: true,
24228
+ */
24229
+
24141
24230
  /**
24142
24231
  * @ngdoc provider
24143
24232
  * @name $filterProvider
@@ -24480,7 +24569,7 @@ function filterFilter() {
24480
24569
  // jshint +W086
24481
24570
  for (var key in expression) {
24482
24571
  (function(path) {
24483
- if (typeof expression[path] == 'undefined') return;
24572
+ if (typeof expression[path] === 'undefined') return;
24484
24573
  predicates.push(function(value) {
24485
24574
  return search(path == '$' ? value : (value && value[path]), expression[path]);
24486
24575
  });
@@ -24519,14 +24608,15 @@ function filterFilter() {
24519
24608
  *
24520
24609
  *
24521
24610
  * @example
24522
- <example>
24611
+ <example module="currencyExample">
24523
24612
  <file name="index.html">
24524
24613
  <script>
24525
- function Ctrl($scope) {
24526
- $scope.amount = 1234.56;
24527
- }
24614
+ angular.module('currencyExample', [])
24615
+ .controller('ExampleController', ['$scope', function($scope) {
24616
+ $scope.amount = 1234.56;
24617
+ }]);
24528
24618
  </script>
24529
- <div ng-controller="Ctrl">
24619
+ <div ng-controller="ExampleController">
24530
24620
  <input type="number" ng-model="amount"> <br>
24531
24621
  default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
24532
24622
  custom currency identifier (USD$): <span>{{amount | currency:"USD$"}}</span>
@@ -24578,14 +24668,15 @@ function currencyFilter($locale) {
24578
24668
  * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
24579
24669
  *
24580
24670
  * @example
24581
- <example>
24671
+ <example module="numberFilterExample">
24582
24672
  <file name="index.html">
24583
24673
  <script>
24584
- function Ctrl($scope) {
24585
- $scope.val = 1234.56789;
24586
- }
24674
+ angular.module('numberFilterExample', [])
24675
+ .controller('ExampleController', ['$scope', function($scope) {
24676
+ $scope.val = 1234.56789;
24677
+ }]);
24587
24678
  </script>
24588
- <div ng-controller="Ctrl">
24679
+ <div ng-controller="ExampleController">
24589
24680
  Enter number: <input ng-model='val'><br>
24590
24681
  Default formatting: <span id='number-default'>{{val | number}}</span><br>
24591
24682
  No fractions: <span>{{val | number:0}}</span><br>
@@ -24635,6 +24726,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
24635
24726
  var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
24636
24727
  if (match && match[2] == '-' && match[3] > fractionSize + 1) {
24637
24728
  numStr = '0';
24729
+ number = 0;
24638
24730
  } else {
24639
24731
  formatedText = numStr;
24640
24732
  hasExponent = true;
@@ -24649,8 +24741,11 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
24649
24741
  fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
24650
24742
  }
24651
24743
 
24652
- var pow = Math.pow(10, fractionSize + 1);
24653
- number = Math.floor(number * pow + 5) / pow;
24744
+ // safely round numbers in JS without hitting imprecisions of floating-point arithmetics
24745
+ // inspired by:
24746
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
24747
+ number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
24748
+
24654
24749
  var fraction = ('' + number).split(DECIMAL_SEP);
24655
24750
  var whole = fraction[0];
24656
24751
  fraction = fraction[1] || '';
@@ -24893,11 +24988,7 @@ function dateFilter($locale) {
24893
24988
  format = format || 'mediumDate';
24894
24989
  format = $locale.DATETIME_FORMATS[format] || format;
24895
24990
  if (isString(date)) {
24896
- if (NUMBER_STRING.test(date)) {
24897
- date = int(date);
24898
- } else {
24899
- date = jsonStringToDate(date);
24900
- }
24991
+ date = NUMBER_STRING.test(date) ? int(date) : jsonStringToDate(date);
24901
24992
  }
24902
24993
 
24903
24994
  if (isNumber(date)) {
@@ -25005,17 +25096,18 @@ var uppercaseFilter = valueFn(uppercase);
25005
25096
  * had less than `limit` elements.
25006
25097
  *
25007
25098
  * @example
25008
- <example>
25099
+ <example module="limitToExample">
25009
25100
  <file name="index.html">
25010
25101
  <script>
25011
- function Ctrl($scope) {
25012
- $scope.numbers = [1,2,3,4,5,6,7,8,9];
25013
- $scope.letters = "abcdefghi";
25014
- $scope.numLimit = 3;
25015
- $scope.letterLimit = 3;
25016
- }
25102
+ angular.module('limitToExample', [])
25103
+ .controller('ExampleController', ['$scope', function($scope) {
25104
+ $scope.numbers = [1,2,3,4,5,6,7,8,9];
25105
+ $scope.letters = "abcdefghi";
25106
+ $scope.numLimit = 3;
25107
+ $scope.letterLimit = 3;
25108
+ }]);
25017
25109
  </script>
25018
- <div ng-controller="Ctrl">
25110
+ <div ng-controller="ExampleController">
25019
25111
  Limit {{numbers}} to: <input type="integer" ng-model="numLimit">
25020
25112
  <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
25021
25113
  Limit {{letters}} to: <input type="integer" ng-model="letterLimit">
@@ -25127,20 +25219,21 @@ function limitToFilter(){
25127
25219
  * @returns {Array} Sorted copy of the source array.
25128
25220
  *
25129
25221
  * @example
25130
- <example>
25222
+ <example module="orderByExample">
25131
25223
  <file name="index.html">
25132
25224
  <script>
25133
- function Ctrl($scope) {
25134
- $scope.friends =
25135
- [{name:'John', phone:'555-1212', age:10},
25136
- {name:'Mary', phone:'555-9876', age:19},
25137
- {name:'Mike', phone:'555-4321', age:21},
25138
- {name:'Adam', phone:'555-5678', age:35},
25139
- {name:'Julie', phone:'555-8765', age:29}]
25140
- $scope.predicate = '-age';
25141
- }
25225
+ angular.module('orderByExample', [])
25226
+ .controller('ExampleController', ['$scope', function($scope) {
25227
+ $scope.friends =
25228
+ [{name:'John', phone:'555-1212', age:10},
25229
+ {name:'Mary', phone:'555-9876', age:19},
25230
+ {name:'Mike', phone:'555-4321', age:21},
25231
+ {name:'Adam', phone:'555-5678', age:35},
25232
+ {name:'Julie', phone:'555-8765', age:29}];
25233
+ $scope.predicate = '-age';
25234
+ }]);
25142
25235
  </script>
25143
- <div ng-controller="Ctrl">
25236
+ <div ng-controller="ExampleController">
25144
25237
  <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
25145
25238
  <hr/>
25146
25239
  [ <a href="" ng-click="predicate=''">unsorted</a> ]
@@ -25168,9 +25261,9 @@ function limitToFilter(){
25168
25261
  * Example:
25169
25262
  *
25170
25263
  * @example
25171
- <example>
25264
+ <example module="orderByExample">
25172
25265
  <file name="index.html">
25173
- <div ng-controller="Ctrl">
25266
+ <div ng-controller="ExampleController">
25174
25267
  <table class="friend">
25175
25268
  <tr>
25176
25269
  <th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
@@ -25188,21 +25281,21 @@ function limitToFilter(){
25188
25281
  </file>
25189
25282
 
25190
25283
  <file name="script.js">
25191
- function Ctrl($scope, $filter) {
25192
- var orderBy = $filter('orderBy');
25193
- $scope.friends = [
25194
- { name: 'John', phone: '555-1212', age: 10 },
25195
- { name: 'Mary', phone: '555-9876', age: 19 },
25196
- { name: 'Mike', phone: '555-4321', age: 21 },
25197
- { name: 'Adam', phone: '555-5678', age: 35 },
25198
- { name: 'Julie', phone: '555-8765', age: 29 }
25199
- ];
25200
-
25201
- $scope.order = function(predicate, reverse) {
25202
- $scope.friends = orderBy($scope.friends, predicate, reverse);
25203
- };
25204
- $scope.order('-age',false);
25205
- }
25284
+ angular.module('orderByExample', [])
25285
+ .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) {
25286
+ var orderBy = $filter('orderBy');
25287
+ $scope.friends = [
25288
+ { name: 'John', phone: '555-1212', age: 10 },
25289
+ { name: 'Mary', phone: '555-9876', age: 19 },
25290
+ { name: 'Mike', phone: '555-4321', age: 21 },
25291
+ { name: 'Adam', phone: '555-5678', age: 35 },
25292
+ { name: 'Julie', phone: '555-8765', age: 29 }
25293
+ ];
25294
+ $scope.order = function(predicate, reverse) {
25295
+ $scope.friends = orderBy($scope.friends, predicate, reverse);
25296
+ };
25297
+ $scope.order('-age',false);
25298
+ }]);
25206
25299
  </file>
25207
25300
  </example>
25208
25301
  */
@@ -25251,6 +25344,10 @@ function orderByFilter($parse){
25251
25344
  var t1 = typeof v1;
25252
25345
  var t2 = typeof v2;
25253
25346
  if (t1 == t2) {
25347
+ if (isDate(v1) && isDate(v2)) {
25348
+ v1 = v1.valueOf();
25349
+ v2 = v2.valueOf();
25350
+ }
25254
25351
  if (t1 == "string") {
25255
25352
  v1 = v1.toLowerCase();
25256
25353
  v2 = v2.toLowerCase();
@@ -25388,7 +25485,7 @@ var htmlAnchorDirective = valueFn({
25388
25485
  return browser.driver.getCurrentUrl().then(function(url) {
25389
25486
  return url.match(/\/123$/);
25390
25487
  });
25391
- }, 1000, 'page should navigate to /123');
25488
+ }, 5000, 'page should navigate to /123');
25392
25489
  });
25393
25490
 
25394
25491
  xit('should execute ng-click but not reload when href empty string and name specified', function() {
@@ -25416,7 +25513,7 @@ var htmlAnchorDirective = valueFn({
25416
25513
  return browser.driver.getCurrentUrl().then(function(url) {
25417
25514
  return url.match(/\/6$/);
25418
25515
  });
25419
- }, 1000, 'page should navigate to /6');
25516
+ }, 5000, 'page should navigate to /6');
25420
25517
  });
25421
25518
  </file>
25422
25519
  </example>
@@ -26032,12 +26129,13 @@ function FormController(element, attrs, $scope, $animate) {
26032
26129
  * </pre>
26033
26130
  *
26034
26131
  * @example
26035
- <example deps="angular-animate.js" animations="true" fixBase="true">
26132
+ <example deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
26036
26133
  <file name="index.html">
26037
26134
  <script>
26038
- function Ctrl($scope) {
26039
- $scope.userType = 'guest';
26040
- }
26135
+ angular.module('formExample', [])
26136
+ .controller('FormController', ['$scope', function($scope) {
26137
+ $scope.userType = 'guest';
26138
+ }]);
26041
26139
  </script>
26042
26140
  <style>
26043
26141
  .my-form {
@@ -26049,7 +26147,7 @@ function FormController(element, attrs, $scope, $animate) {
26049
26147
  background: red;
26050
26148
  }
26051
26149
  </style>
26052
- <form name="myForm" ng-controller="Ctrl" class="my-form">
26150
+ <form name="myForm" ng-controller="FormController" class="my-form">
26053
26151
  userType: <input name="input" ng-model="userType" required>
26054
26152
  <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
26055
26153
  <tt>userType = {{userType}}</tt><br>
@@ -26143,16 +26241,14 @@ var formDirectiveFactory = function(isNgForm) {
26143
26241
  var formDirective = formDirectiveFactory();
26144
26242
  var ngFormDirective = formDirectiveFactory(true);
26145
26243
 
26146
- /* global
26147
-
26148
- -VALID_CLASS,
26149
- -INVALID_CLASS,
26150
- -PRISTINE_CLASS,
26151
- -DIRTY_CLASS
26244
+ /* global VALID_CLASS: true,
26245
+ INVALID_CLASS: true,
26246
+ PRISTINE_CLASS: true,
26247
+ DIRTY_CLASS: true
26152
26248
  */
26153
26249
 
26154
26250
  var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
26155
- var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*$/i;
26251
+ var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
26156
26252
  var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
26157
26253
 
26158
26254
  var inputType = {
@@ -26182,15 +26278,16 @@ var inputType = {
26182
26278
  * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
26183
26279
  *
26184
26280
  * @example
26185
- <example name="text-input-directive">
26281
+ <example name="text-input-directive" module="textInputExample">
26186
26282
  <file name="index.html">
26187
26283
  <script>
26188
- function Ctrl($scope) {
26189
- $scope.text = 'guest';
26190
- $scope.word = /^\s*\w*\s*$/;
26191
- }
26284
+ angular.module('textInputExample', [])
26285
+ .controller('ExampleController', ['$scope', function($scope) {
26286
+ $scope.text = 'guest';
26287
+ $scope.word = /^\s*\w*\s*$/;
26288
+ }]);
26192
26289
  </script>
26193
- <form name="myForm" ng-controller="Ctrl">
26290
+ <form name="myForm" ng-controller="ExampleController">
26194
26291
  Single word: <input type="text" name="input" ng-model="text"
26195
26292
  ng-pattern="word" required ng-trim="false">
26196
26293
  <span class="error" ng-show="myForm.input.$error.required">
@@ -26262,14 +26359,15 @@ var inputType = {
26262
26359
  * interaction with the input element.
26263
26360
  *
26264
26361
  * @example
26265
- <example name="number-input-directive">
26362
+ <example name="number-input-directive" module="numberExample">
26266
26363
  <file name="index.html">
26267
26364
  <script>
26268
- function Ctrl($scope) {
26269
- $scope.value = 12;
26270
- }
26365
+ angular.module('numberExample', [])
26366
+ .controller('ExampleController', ['$scope', function($scope) {
26367
+ $scope.value = 12;
26368
+ }]);
26271
26369
  </script>
26272
- <form name="myForm" ng-controller="Ctrl">
26370
+ <form name="myForm" ng-controller="ExampleController">
26273
26371
  Number: <input type="number" name="input" ng-model="value"
26274
26372
  min="0" max="99" required>
26275
26373
  <span class="error" ng-show="myForm.input.$error.required">
@@ -26337,14 +26435,15 @@ var inputType = {
26337
26435
  * interaction with the input element.
26338
26436
  *
26339
26437
  * @example
26340
- <example name="url-input-directive">
26438
+ <example name="url-input-directive" module="urlExample">
26341
26439
  <file name="index.html">
26342
26440
  <script>
26343
- function Ctrl($scope) {
26344
- $scope.text = 'http://google.com';
26345
- }
26441
+ angular.module('urlExample', [])
26442
+ .controller('ExampleController', ['$scope', function($scope) {
26443
+ $scope.text = 'http://google.com';
26444
+ }]);
26346
26445
  </script>
26347
- <form name="myForm" ng-controller="Ctrl">
26446
+ <form name="myForm" ng-controller="ExampleController">
26348
26447
  URL: <input type="url" name="input" ng-model="text" required>
26349
26448
  <span class="error" ng-show="myForm.input.$error.required">
26350
26449
  Required!</span>
@@ -26413,14 +26512,15 @@ var inputType = {
26413
26512
  * interaction with the input element.
26414
26513
  *
26415
26514
  * @example
26416
- <example name="email-input-directive">
26515
+ <example name="email-input-directive" module="emailExample">
26417
26516
  <file name="index.html">
26418
26517
  <script>
26419
- function Ctrl($scope) {
26420
- $scope.text = 'me@example.com';
26421
- }
26518
+ angular.module('emailExample', [])
26519
+ .controller('ExampleController', ['$scope', function($scope) {
26520
+ $scope.text = 'me@example.com';
26521
+ }]);
26422
26522
  </script>
26423
- <form name="myForm" ng-controller="Ctrl">
26523
+ <form name="myForm" ng-controller="ExampleController">
26424
26524
  Email: <input type="email" name="input" ng-model="text" required>
26425
26525
  <span class="error" ng-show="myForm.input.$error.required">
26426
26526
  Required!</span>
@@ -26479,18 +26579,19 @@ var inputType = {
26479
26579
  * be set when selected.
26480
26580
  *
26481
26581
  * @example
26482
- <example name="radio-input-directive">
26582
+ <example name="radio-input-directive" module="radioExample">
26483
26583
  <file name="index.html">
26484
26584
  <script>
26485
- function Ctrl($scope) {
26486
- $scope.color = 'blue';
26487
- $scope.specialValue = {
26488
- "id": "12345",
26489
- "value": "green"
26490
- };
26491
- }
26585
+ angular.module('radioExample', [])
26586
+ .controller('ExampleController', ['$scope', function($scope) {
26587
+ $scope.color = 'blue';
26588
+ $scope.specialValue = {
26589
+ "id": "12345",
26590
+ "value": "green"
26591
+ };
26592
+ }]);
26492
26593
  </script>
26493
- <form name="myForm" ng-controller="Ctrl">
26594
+ <form name="myForm" ng-controller="ExampleController">
26494
26595
  <input type="radio" ng-model="color" value="red"> Red <br/>
26495
26596
  <input type="radio" ng-model="color" ng-value="specialValue"> Green <br/>
26496
26597
  <input type="radio" ng-model="color" value="blue"> Blue <br/>
@@ -26529,15 +26630,16 @@ var inputType = {
26529
26630
  * interaction with the input element.
26530
26631
  *
26531
26632
  * @example
26532
- <example name="checkbox-input-directive">
26633
+ <example name="checkbox-input-directive" module="checkboxExample">
26533
26634
  <file name="index.html">
26534
26635
  <script>
26535
- function Ctrl($scope) {
26536
- $scope.value1 = true;
26537
- $scope.value2 = 'YES'
26538
- }
26636
+ angular.module('checkboxExample', [])
26637
+ .controller('ExampleController', ['$scope', function($scope) {
26638
+ $scope.value1 = true;
26639
+ $scope.value2 = 'YES'
26640
+ }]);
26539
26641
  </script>
26540
- <form name="myForm" ng-controller="Ctrl">
26642
+ <form name="myForm" ng-controller="ExampleController">
26541
26643
  Value1: <input type="checkbox" ng-model="value1"> <br/>
26542
26644
  Value2: <input type="checkbox" ng-model="value2"
26543
26645
  ng-true-value="YES" ng-false-value="NO"> <br/>
@@ -26578,15 +26680,29 @@ function validate(ctrl, validatorName, validity, value){
26578
26680
  return validity ? value : undefined;
26579
26681
  }
26580
26682
 
26683
+ function testFlags(validity, flags) {
26684
+ var i, flag;
26685
+ if (flags) {
26686
+ for (i=0; i<flags.length; ++i) {
26687
+ flag = flags[i];
26688
+ if (validity[flag]) {
26689
+ return true;
26690
+ }
26691
+ }
26692
+ }
26693
+ return false;
26694
+ }
26581
26695
 
26582
- function addNativeHtml5Validators(ctrl, validatorName, element) {
26583
- var validity = element.prop('validity');
26696
+ // Pass validity so that behaviour can be mocked easier.
26697
+ function addNativeHtml5Validators(ctrl, validatorName, badFlags, ignoreFlags, validity) {
26584
26698
  if (isObject(validity)) {
26699
+ ctrl.$$hasNativeValidators = true;
26585
26700
  var validator = function(value) {
26586
26701
  // Don't overwrite previous validation, don't consider valueMissing to apply (ng-required can
26587
26702
  // perform the required validation)
26588
- if (!ctrl.$error[validatorName] && (validity.badInput || validity.customError ||
26589
- validity.typeMismatch) && !validity.valueMissing) {
26703
+ if (!ctrl.$error[validatorName] &&
26704
+ !testFlags(validity, ignoreFlags) &&
26705
+ testFlags(validity, badFlags)) {
26590
26706
  ctrl.$setValidity(validatorName, false);
26591
26707
  return;
26592
26708
  }
@@ -26597,8 +26713,9 @@ function addNativeHtml5Validators(ctrl, validatorName, element) {
26597
26713
  }
26598
26714
 
26599
26715
  function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
26600
- var validity = element.prop('validity');
26716
+ var validity = element.prop(VALIDITY_STATE_PROPERTY);
26601
26717
  var placeholder = element[0].placeholder, noevent = {};
26718
+ ctrl.$$validityState = validity;
26602
26719
 
26603
26720
  // In composition mode, users are still inputing intermediate text buffer,
26604
26721
  // hold the listener until composition is done.
@@ -26636,11 +26753,11 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
26636
26753
  value = trim(value);
26637
26754
  }
26638
26755
 
26639
- if (ctrl.$viewValue !== value ||
26640
- // If the value is still empty/falsy, and there is no `required` error, run validators
26641
- // again. This enables HTML5 constraint validation errors to affect Angular validation
26642
- // even when the first character entered causes an error.
26643
- (validity && value === '' && !validity.valueMissing)) {
26756
+ // If a control is suffering from bad input, browsers discard its value, so it may be
26757
+ // necessary to revalidate even if the control's value is the same empty value twice in
26758
+ // a row.
26759
+ var revalidate = validity && ctrl.$$hasNativeValidators;
26760
+ if (ctrl.$viewValue !== value || (value === '' && revalidate)) {
26644
26761
  if (scope.$$phase) {
26645
26762
  ctrl.$setViewValue(value);
26646
26763
  } else {
@@ -26746,6 +26863,8 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
26746
26863
  }
26747
26864
  }
26748
26865
 
26866
+ var numberBadFlags = ['badInput'];
26867
+
26749
26868
  function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
26750
26869
  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
26751
26870
 
@@ -26760,7 +26879,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
26760
26879
  }
26761
26880
  });
26762
26881
 
26763
- addNativeHtml5Validators(ctrl, 'number', element);
26882
+ addNativeHtml5Validators(ctrl, 'number', numberBadFlags, null, ctrl.$$validityState);
26764
26883
 
26765
26884
  ctrl.$formatters.push(function(value) {
26766
26885
  return ctrl.$isEmpty(value) ? '' : '' + value;
@@ -26920,14 +27039,15 @@ function checkboxInputType(scope, element, attr, ctrl) {
26920
27039
  * interaction with the input element.
26921
27040
  *
26922
27041
  * @example
26923
- <example name="input-directive">
27042
+ <example name="input-directive" module="inputExample">
26924
27043
  <file name="index.html">
26925
27044
  <script>
26926
- function Ctrl($scope) {
26927
- $scope.user = {name: 'guest', last: 'visitor'};
26928
- }
27045
+ angular.module('inputExample', [])
27046
+ .controller('ExampleController', ['$scope', function($scope) {
27047
+ $scope.user = {name: 'guest', last: 'visitor'};
27048
+ }]);
26929
27049
  </script>
26930
- <div ng-controller="Ctrl">
27050
+ <div ng-controller="ExampleController">
26931
27051
  <form name="myForm">
26932
27052
  User name: <input type="text" name="userName" ng-model="user.name" required>
26933
27053
  <span class="error" ng-show="myForm.userName.$error.required">
@@ -27242,7 +27362,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
27242
27362
  * This method should be called by validators - i.e. the parser or formatter functions.
27243
27363
  *
27244
27364
  * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign
27245
- * to `$error[validationErrorKey]=isValid` so that it is available for data-binding.
27365
+ * to `$error[validationErrorKey]=!isValid` so that it is available for data-binding.
27246
27366
  * The `validationErrorKey` should be in camelCase and will get converted into dash-case
27247
27367
  * for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
27248
27368
  * class and can be bound to as `{{someForm.someControl.$error.myError}}` .
@@ -27445,12 +27565,13 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
27445
27565
  * </pre>
27446
27566
  *
27447
27567
  * @example
27448
- * <example deps="angular-animate.js" animations="true" fixBase="true">
27568
+ * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
27449
27569
  <file name="index.html">
27450
27570
  <script>
27451
- function Ctrl($scope) {
27452
- $scope.val = '1';
27453
- }
27571
+ angular.module('inputExample', [])
27572
+ .controller('ExampleController', ['$scope', function($scope) {
27573
+ $scope.val = '1';
27574
+ }]);
27454
27575
  </script>
27455
27576
  <style>
27456
27577
  .my-input {
@@ -27465,7 +27586,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
27465
27586
  </style>
27466
27587
  Update input to see transitions when valid/invalid.
27467
27588
  Integer is a valid value.
27468
- <form name="testForm" ng-controller="Ctrl">
27589
+ <form name="testForm" ng-controller="ExampleController">
27469
27590
  <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input" />
27470
27591
  </form>
27471
27592
  </file>
@@ -27509,17 +27630,18 @@ var ngModelDirective = function() {
27509
27630
  * in input value.
27510
27631
  *
27511
27632
  * @example
27512
- * <example name="ngChange-directive">
27633
+ * <example name="ngChange-directive" module="changeExample">
27513
27634
  * <file name="index.html">
27514
27635
  * <script>
27515
- * function Controller($scope) {
27516
- * $scope.counter = 0;
27517
- * $scope.change = function() {
27518
- * $scope.counter++;
27519
- * };
27520
- * }
27636
+ * angular.module('changeExample', [])
27637
+ * .controller('ExampleController', ['$scope', function($scope) {
27638
+ * $scope.counter = 0;
27639
+ * $scope.change = function() {
27640
+ * $scope.counter++;
27641
+ * };
27642
+ * }]);
27521
27643
  * </script>
27522
- * <div ng-controller="Controller">
27644
+ * <div ng-controller="ExampleController">
27523
27645
  * <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
27524
27646
  * <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
27525
27647
  * <label for="ng-change-example2">Confirmed</label><br />
@@ -27600,14 +27722,15 @@ var requiredDirective = function() {
27600
27722
  * specified in form `/something/` then the value will be converted into a regular expression.
27601
27723
  *
27602
27724
  * @example
27603
- <example name="ngList-directive">
27725
+ <example name="ngList-directive" module="listExample">
27604
27726
  <file name="index.html">
27605
27727
  <script>
27606
- function Ctrl($scope) {
27607
- $scope.names = ['igor', 'misko', 'vojta'];
27608
- }
27728
+ angular.module('listExample', [])
27729
+ .controller('ExampleController', ['$scope', function($scope) {
27730
+ $scope.names = ['igor', 'misko', 'vojta'];
27731
+ }]);
27609
27732
  </script>
27610
- <form name="myForm" ng-controller="Ctrl">
27733
+ <form name="myForm" ng-controller="ExampleController">
27611
27734
  List: <input name="namesInput" ng-model="names" ng-list required>
27612
27735
  <span class="error" ng-show="myForm.namesInput.$error.required">
27613
27736
  Required!</span>
@@ -27699,15 +27822,16 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
27699
27822
  * of the `input` element
27700
27823
  *
27701
27824
  * @example
27702
- <example name="ngValue-directive">
27825
+ <example name="ngValue-directive" module="valueExample">
27703
27826
  <file name="index.html">
27704
27827
  <script>
27705
- function Ctrl($scope) {
27706
- $scope.names = ['pizza', 'unicorns', 'robots'];
27707
- $scope.my = { favorite: 'unicorns' };
27708
- }
27828
+ angular.module('valueExample', [])
27829
+ .controller('ExampleController', ['$scope', function($scope) {
27830
+ $scope.names = ['pizza', 'unicorns', 'robots'];
27831
+ $scope.my = { favorite: 'unicorns' };
27832
+ }]);
27709
27833
  </script>
27710
- <form ng-controller="Ctrl">
27834
+ <form ng-controller="ExampleController">
27711
27835
  <h2>Which is your favorite?</h2>
27712
27836
  <label ng-repeat="name in names" for="{{name}}">
27713
27837
  {{name}}
@@ -27765,7 +27889,7 @@ var ngValueDirective = function() {
27765
27889
  * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
27766
27890
  * `{{ expression }}` which is similar but less verbose.
27767
27891
  *
27768
- * It is preferable to use `ngBind` instead of `{{ expression }}` when a template is momentarily
27892
+ * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
27769
27893
  * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
27770
27894
  * element attribute, it makes the bindings invisible to the user while the page is loading.
27771
27895
  *
@@ -27778,14 +27902,15 @@ var ngValueDirective = function() {
27778
27902
  *
27779
27903
  * @example
27780
27904
  * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
27781
- <example>
27905
+ <example module="bindExample">
27782
27906
  <file name="index.html">
27783
27907
  <script>
27784
- function Ctrl($scope) {
27785
- $scope.name = 'Whirled';
27786
- }
27908
+ angular.module('bindExample', [])
27909
+ .controller('ExampleController', ['$scope', function($scope) {
27910
+ $scope.name = 'Whirled';
27911
+ }]);
27787
27912
  </script>
27788
- <div ng-controller="Ctrl">
27913
+ <div ng-controller="ExampleController">
27789
27914
  Enter name: <input type="text" ng-model="name"><br>
27790
27915
  Hello <span ng-bind="name"></span>!
27791
27916
  </div>
@@ -27836,15 +27961,16 @@ var ngBindDirective = ngDirective({
27836
27961
  *
27837
27962
  * @example
27838
27963
  * Try it here: enter text in text box and watch the greeting change.
27839
- <example>
27964
+ <example module="bindExample">
27840
27965
  <file name="index.html">
27841
27966
  <script>
27842
- function Ctrl($scope) {
27843
- $scope.salutation = 'Hello';
27844
- $scope.name = 'World';
27845
- }
27967
+ angular.module('bindExample', [])
27968
+ .controller('ExampleController', ['$scope', function ($scope) {
27969
+ $scope.salutation = 'Hello';
27970
+ $scope.name = 'World';
27971
+ }]);
27846
27972
  </script>
27847
- <div ng-controller="Ctrl">
27973
+ <div ng-controller="ExampleController">
27848
27974
  Salutation: <input type="text" ng-model="salutation"><br>
27849
27975
  Name: <input type="text" ng-model="name"><br>
27850
27976
  <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
@@ -27902,20 +28028,20 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
27902
28028
  * @example
27903
28029
  Try it here: enter text in text box and watch the greeting change.
27904
28030
 
27905
- <example module="ngBindHtmlExample" deps="angular-sanitize.js">
28031
+ <example module="bindHtmlExample" deps="angular-sanitize.js">
27906
28032
  <file name="index.html">
27907
- <div ng-controller="ngBindHtmlCtrl">
28033
+ <div ng-controller="ExampleController">
27908
28034
  <p ng-bind-html="myHTML"></p>
27909
28035
  </div>
27910
28036
  </file>
27911
28037
 
27912
28038
  <file name="script.js">
27913
- angular.module('ngBindHtmlExample', ['ngSanitize'])
27914
-
27915
- .controller('ngBindHtmlCtrl', ['$scope', function ngBindHtmlCtrl($scope) {
27916
- $scope.myHTML =
27917
- 'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>';
27918
- }]);
28039
+ angular.module('bindHtmlExample', ['ngSanitize'])
28040
+ .controller('ExampleController', ['$scope', function($scope) {
28041
+ $scope.myHTML =
28042
+ 'I am an <code>HTML</code>string with ' +
28043
+ '<a href="#">links!</a> and other <em>stuff</em>';
28044
+ }]);
27919
28045
  </file>
27920
28046
 
27921
28047
  <file name="protractor.js" type="protractor">
@@ -27927,15 +28053,24 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
27927
28053
  </example>
27928
28054
  */
27929
28055
  var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
27930
- return function(scope, element, attr) {
27931
- element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
28056
+ return {
28057
+ compile: function (tElement) {
28058
+ tElement.addClass('ng-binding');
27932
28059
 
27933
- var parsed = $parse(attr.ngBindHtml);
27934
- function getStringValue() { return (parsed(scope) || '').toString(); }
28060
+ return function (scope, element, attr) {
28061
+ element.data('$binding', attr.ngBindHtml);
27935
28062
 
27936
- scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
27937
- element.html($sce.getTrustedHtml(parsed(scope)) || '');
27938
- });
28063
+ var parsed = $parse(attr.ngBindHtml);
28064
+
28065
+ function getStringValue() {
28066
+ return (parsed(scope) || '').toString();
28067
+ }
28068
+
28069
+ scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
28070
+ element.html($sce.getTrustedHtml(parsed(scope)) || '');
28071
+ });
28072
+ };
28073
+ }
27939
28074
  };
27940
28075
  }];
27941
28076
 
@@ -28414,7 +28549,7 @@ var ngCloakDirective = ngDirective({
28414
28549
  *
28415
28550
  * This example demonstrates the `controller as` syntax.
28416
28551
  *
28417
- * <example name="ngControllerAs">
28552
+ * <example name="ngControllerAs" module="controllerAsExample">
28418
28553
  * <file name="index.html">
28419
28554
  * <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
28420
28555
  * Name: <input type="text" ng-model="settings.name"/>
@@ -28435,6 +28570,9 @@ var ngCloakDirective = ngDirective({
28435
28570
  * </div>
28436
28571
  * </file>
28437
28572
  * <file name="app.js">
28573
+ * angular.module('controllerAsExample', [])
28574
+ * .controller('SettingsController1', SettingsController1);
28575
+ *
28438
28576
  * function SettingsController1() {
28439
28577
  * this.name = "John Smith";
28440
28578
  * this.contacts = [
@@ -28463,29 +28601,29 @@ var ngCloakDirective = ngDirective({
28463
28601
  * <file name="protractor.js" type="protractor">
28464
28602
  * it('should check controller as', function() {
28465
28603
  * var container = element(by.id('ctrl-as-exmpl'));
28466
- * expect(container.findElement(by.model('settings.name'))
28604
+ * expect(container.element(by.model('settings.name'))
28467
28605
  * .getAttribute('value')).toBe('John Smith');
28468
28606
  *
28469
28607
  * var firstRepeat =
28470
- * container.findElement(by.repeater('contact in settings.contacts').row(0));
28608
+ * container.element(by.repeater('contact in settings.contacts').row(0));
28471
28609
  * var secondRepeat =
28472
- * container.findElement(by.repeater('contact in settings.contacts').row(1));
28610
+ * container.element(by.repeater('contact in settings.contacts').row(1));
28473
28611
  *
28474
- * expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
28612
+ * expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
28475
28613
  * .toBe('408 555 1212');
28476
28614
  *
28477
- * expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
28615
+ * expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
28478
28616
  * .toBe('john.smith@example.org');
28479
28617
  *
28480
- * firstRepeat.findElement(by.linkText('clear')).click();
28618
+ * firstRepeat.element(by.linkText('clear')).click();
28481
28619
  *
28482
- * expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
28620
+ * expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
28483
28621
  * .toBe('');
28484
28622
  *
28485
- * container.findElement(by.linkText('add')).click();
28623
+ * container.element(by.linkText('add')).click();
28486
28624
  *
28487
- * expect(container.findElement(by.repeater('contact in settings.contacts').row(2))
28488
- * .findElement(by.model('contact.value'))
28625
+ * expect(container.element(by.repeater('contact in settings.contacts').row(2))
28626
+ * .element(by.model('contact.value'))
28489
28627
  * .getAttribute('value'))
28490
28628
  * .toBe('yourname@example.org');
28491
28629
  * });
@@ -28494,7 +28632,7 @@ var ngCloakDirective = ngDirective({
28494
28632
  *
28495
28633
  * This example demonstrates the "attach to `$scope`" style of controller.
28496
28634
  *
28497
- * <example name="ngController">
28635
+ * <example name="ngController" module="controllerExample">
28498
28636
  * <file name="index.html">
28499
28637
  * <div id="ctrl-exmpl" ng-controller="SettingsController2">
28500
28638
  * Name: <input type="text" ng-model="name"/>
@@ -28515,6 +28653,9 @@ var ngCloakDirective = ngDirective({
28515
28653
  * </div>
28516
28654
  * </file>
28517
28655
  * <file name="app.js">
28656
+ * angular.module('controllerExample', [])
28657
+ * .controller('SettingsController2', ['$scope', SettingsController2]);
28658
+ *
28518
28659
  * function SettingsController2($scope) {
28519
28660
  * $scope.name = "John Smith";
28520
28661
  * $scope.contacts = [
@@ -28544,28 +28685,28 @@ var ngCloakDirective = ngDirective({
28544
28685
  * it('should check controller', function() {
28545
28686
  * var container = element(by.id('ctrl-exmpl'));
28546
28687
  *
28547
- * expect(container.findElement(by.model('name'))
28688
+ * expect(container.element(by.model('name'))
28548
28689
  * .getAttribute('value')).toBe('John Smith');
28549
28690
  *
28550
28691
  * var firstRepeat =
28551
- * container.findElement(by.repeater('contact in contacts').row(0));
28692
+ * container.element(by.repeater('contact in contacts').row(0));
28552
28693
  * var secondRepeat =
28553
- * container.findElement(by.repeater('contact in contacts').row(1));
28694
+ * container.element(by.repeater('contact in contacts').row(1));
28554
28695
  *
28555
- * expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
28696
+ * expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
28556
28697
  * .toBe('408 555 1212');
28557
- * expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
28698
+ * expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
28558
28699
  * .toBe('john.smith@example.org');
28559
28700
  *
28560
- * firstRepeat.findElement(by.linkText('clear')).click();
28701
+ * firstRepeat.element(by.linkText('clear')).click();
28561
28702
  *
28562
- * expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
28703
+ * expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
28563
28704
  * .toBe('');
28564
28705
  *
28565
- * container.findElement(by.linkText('add')).click();
28706
+ * container.element(by.linkText('add')).click();
28566
28707
  *
28567
- * expect(container.findElement(by.repeater('contact in contacts').row(2))
28568
- * .findElement(by.model('contact.value'))
28708
+ * expect(container.element(by.repeater('contact in contacts').row(2))
28709
+ * .element(by.model('contact.value'))
28569
28710
  * .getAttribute('value'))
28570
28711
  * .toBe('yourname@example.org');
28571
28712
  * });
@@ -28592,8 +28733,10 @@ var ngControllerDirective = [function() {
28592
28733
  * This is necessary when developing things like Google Chrome Extensions.
28593
28734
  *
28594
28735
  * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
28595
- * For us to be compatible, we just need to implement the "getterFn" in $parse without violating
28596
- * any of these restrictions.
28736
+ * For Angular to be CSP compatible there are only two things that we need to do differently:
28737
+ *
28738
+ * - don't use `Function` constructor to generate optimized value getters
28739
+ * - don't inject custom stylesheet into the document
28597
28740
  *
28598
28741
  * AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
28599
28742
  * directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
@@ -28604,7 +28747,18 @@ var ngControllerDirective = [function() {
28604
28747
  * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
28605
28748
  * To make those directives work in CSP mode, include the `angular-csp.css` manually.
28606
28749
  *
28607
- * In order to use this feature put the `ngCsp` directive on the root element of the application.
28750
+ * Angular tries to autodetect if CSP is active and automatically turn on the CSP-safe mode. This
28751
+ * autodetection however triggers a CSP error to be logged in the console:
28752
+ *
28753
+ * ```
28754
+ * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
28755
+ * script in the following Content Security Policy directive: "default-src 'self'". Note that
28756
+ * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
28757
+ * ```
28758
+ *
28759
+ * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
28760
+ * directive on the root element of the application or on the `angular.js` script tag, whichever
28761
+ * appears first in the html document.
28608
28762
  *
28609
28763
  * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
28610
28764
  *
@@ -28619,9 +28773,9 @@ var ngControllerDirective = [function() {
28619
28773
  ```
28620
28774
  */
28621
28775
 
28622
- // ngCsp is not implemented as a proper directive any more, because we need it be processed while we bootstrap
28623
- // the system (before $parse is instantiated), for this reason we just have a csp() fn that looks for ng-csp attribute
28624
- // anywhere in the current doc
28776
+ // ngCsp is not implemented as a proper directive any more, because we need it be processed while we
28777
+ // bootstrap the system (before $parse is instantiated), for this reason we just have
28778
+ // the csp.isActive() fn that looks for ng-csp attribute anywhere in the current doc
28625
28779
 
28626
28780
  /**
28627
28781
  * @ngdoc directive
@@ -28936,21 +29090,22 @@ forEach(
28936
29090
  * ({@link guide/expression#-event- Event object is available as `$event`})
28937
29091
  *
28938
29092
  * @example
28939
- <example>
29093
+ <example module="submitExample">
28940
29094
  <file name="index.html">
28941
29095
  <script>
28942
- function Ctrl($scope) {
28943
- $scope.list = [];
28944
- $scope.text = 'hello';
28945
- $scope.submit = function() {
28946
- if ($scope.text) {
28947
- $scope.list.push(this.text);
28948
- $scope.text = '';
28949
- }
28950
- };
28951
- }
29096
+ angular.module('submitExample', [])
29097
+ .controller('ExampleController', ['$scope', function($scope) {
29098
+ $scope.list = [];
29099
+ $scope.text = 'hello';
29100
+ $scope.submit = function() {
29101
+ if ($scope.text) {
29102
+ $scope.list.push(this.text);
29103
+ $scope.text = '';
29104
+ }
29105
+ };
29106
+ }]);
28952
29107
  </script>
28953
- <form ng-submit="submit()" ng-controller="Ctrl">
29108
+ <form ng-submit="submit()" ng-controller="ExampleController">
28954
29109
  Enter text and hit enter:
28955
29110
  <input type="text" ng-model="text" name="text" />
28956
29111
  <input type="submit" id="submit" value="Submit" />
@@ -28962,7 +29117,7 @@ forEach(
28962
29117
  expect(element(by.binding('list')).getText()).toBe('list=[]');
28963
29118
  element(by.css('#submit')).click();
28964
29119
  expect(element(by.binding('list')).getText()).toContain('hello');
28965
- expect(element(by.input('text')).getAttribute('value')).toBe('');
29120
+ expect(element(by.model('text')).getAttribute('value')).toBe('');
28966
29121
  });
28967
29122
  it('should ignore empty strings', function() {
28968
29123
  expect(element(by.binding('list')).getText()).toBe('list=[]');
@@ -29235,9 +29390,9 @@ var ngIfDirective = ['$animate', function($animate) {
29235
29390
  * - Otherwise enable scrolling only if the expression evaluates to truthy value.
29236
29391
  *
29237
29392
  * @example
29238
- <example module="ngAnimate" deps="angular-animate.js" animations="true">
29393
+ <example module="includeExample" deps="angular-animate.js" animations="true">
29239
29394
  <file name="index.html">
29240
- <div ng-controller="Ctrl">
29395
+ <div ng-controller="ExampleController">
29241
29396
  <select ng-model="template" ng-options="t.name for t in templates">
29242
29397
  <option value="">(blank)</option>
29243
29398
  </select>
@@ -29249,12 +29404,13 @@ var ngIfDirective = ['$animate', function($animate) {
29249
29404
  </div>
29250
29405
  </file>
29251
29406
  <file name="script.js">
29252
- function Ctrl($scope) {
29253
- $scope.templates =
29254
- [ { name: 'template1.html', url: 'template1.html'},
29255
- { name: 'template2.html', url: 'template2.html'} ];
29256
- $scope.template = $scope.templates[0];
29257
- }
29407
+ angular.module('includeExample', ['ngAnimate'])
29408
+ .controller('ExampleController', ['$scope', function($scope) {
29409
+ $scope.templates =
29410
+ [ { name: 'template1.html', url: 'template1.html'},
29411
+ { name: 'template2.html', url: 'template2.html'} ];
29412
+ $scope.template = $scope.templates[0];
29413
+ }]);
29258
29414
  </file>
29259
29415
  <file name="template1.html">
29260
29416
  Content of template1.html
@@ -29317,7 +29473,7 @@ var ngIfDirective = ['$animate', function($animate) {
29317
29473
  return;
29318
29474
  }
29319
29475
  templateSelect.click();
29320
- templateSelect.element.all(by.css('option')).get(2).click();
29476
+ templateSelect.all(by.css('option')).get(2).click();
29321
29477
  expect(includeElem.getText()).toMatch(/Content of template2.html/);
29322
29478
  });
29323
29479
 
@@ -29327,7 +29483,7 @@ var ngIfDirective = ['$animate', function($animate) {
29327
29483
  return;
29328
29484
  }
29329
29485
  templateSelect.click();
29330
- templateSelect.element.all(by.css('option')).get(0).click();
29486
+ templateSelect.all(by.css('option')).get(0).click();
29331
29487
  expect(includeElem.isPresent()).toBe(false);
29332
29488
  });
29333
29489
  </file>
@@ -29479,14 +29635,15 @@ var ngIncludeFillContentDirective = ['$compile',
29479
29635
  * @param {expression} ngInit {@link guide/expression Expression} to eval.
29480
29636
  *
29481
29637
  * @example
29482
- <example>
29638
+ <example module="initExample">
29483
29639
  <file name="index.html">
29484
29640
  <script>
29485
- function Ctrl($scope) {
29486
- $scope.list = [['a', 'b'], ['c', 'd']];
29487
- }
29641
+ angular.module('initExample', [])
29642
+ .controller('ExampleController', ['$scope', function($scope) {
29643
+ $scope.list = [['a', 'b'], ['c', 'd']];
29644
+ }]);
29488
29645
  </script>
29489
- <div ng-controller="Ctrl">
29646
+ <div ng-controller="ExampleController">
29490
29647
  <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
29491
29648
  <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
29492
29649
  <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
@@ -29626,7 +29783,7 @@ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
29626
29783
  * When one person, perhaps John, views the document, "John is viewing" will be shown.
29627
29784
  * When three people view the document, no explicit number rule is found, so
29628
29785
  * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
29629
- * In this case, plural category 'one' is matched and "John, Marry and one other person are viewing"
29786
+ * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
29630
29787
  * is shown.
29631
29788
  *
29632
29789
  * Note that when you specify offsets, you must provide explicit number rules for
@@ -29639,16 +29796,17 @@ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
29639
29796
  * @param {number=} offset Offset to deduct from the total number.
29640
29797
  *
29641
29798
  * @example
29642
- <example>
29799
+ <example module="pluralizeExample">
29643
29800
  <file name="index.html">
29644
29801
  <script>
29645
- function Ctrl($scope) {
29646
- $scope.person1 = 'Igor';
29647
- $scope.person2 = 'Misko';
29648
- $scope.personCount = 1;
29649
- }
29802
+ angular.module('pluralizeExample', [])
29803
+ .controller('ExampleController', ['$scope', function($scope) {
29804
+ $scope.person1 = 'Igor';
29805
+ $scope.person2 = 'Misko';
29806
+ $scope.personCount = 1;
29807
+ }]);
29650
29808
  </script>
29651
- <div ng-controller="Ctrl">
29809
+ <div ng-controller="ExampleController">
29652
29810
  Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
29653
29811
  Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
29654
29812
  Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
@@ -30508,7 +30666,7 @@ var ngHideDirective = ['$animate', function($animate) {
30508
30666
  <file name="protractor.js" type="protractor">
30509
30667
  var colorSpan = element(by.css('span'));
30510
30668
 
30511
- iit('should check ng-style', function() {
30669
+ it('should check ng-style', function() {
30512
30670
  expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
30513
30671
  element(by.css('input[value=\'set color\']')).click();
30514
30672
  expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
@@ -30582,9 +30740,9 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
30582
30740
  *
30583
30741
  *
30584
30742
  * @example
30585
- <example module="ngAnimate" deps="angular-animate.js" animations="true">
30743
+ <example module="switchExample" deps="angular-animate.js" animations="true">
30586
30744
  <file name="index.html">
30587
- <div ng-controller="Ctrl">
30745
+ <div ng-controller="ExampleController">
30588
30746
  <select ng-model="selection" ng-options="item for item in items">
30589
30747
  </select>
30590
30748
  <tt>selection={{selection}}</tt>
@@ -30598,10 +30756,11 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
30598
30756
  </div>
30599
30757
  </file>
30600
30758
  <file name="script.js">
30601
- function Ctrl($scope) {
30602
- $scope.items = ['settings', 'home', 'other'];
30603
- $scope.selection = $scope.items[0];
30604
- }
30759
+ angular.module('switchExample', ['ngAnimate'])
30760
+ .controller('ExampleController', ['$scope', function($scope) {
30761
+ $scope.items = ['settings', 'home', 'other'];
30762
+ $scope.selection = $scope.items[0];
30763
+ }]);
30605
30764
  </file>
30606
30765
  <file name="animations.css">
30607
30766
  .animate-switch-container {
@@ -30644,11 +30803,11 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
30644
30803
  expect(switchElem.getText()).toMatch(/Settings Div/);
30645
30804
  });
30646
30805
  it('should change to home', function() {
30647
- select.element.all(by.css('option')).get(1).click();
30806
+ select.all(by.css('option')).get(1).click();
30648
30807
  expect(switchElem.getText()).toMatch(/Home Span/);
30649
30808
  });
30650
30809
  it('should select default', function() {
30651
- select.element.all(by.css('option')).get(2).click();
30810
+ select.all(by.css('option')).get(2).click();
30652
30811
  expect(switchElem.getText()).toMatch(/default/);
30653
30812
  });
30654
30813
  </file>
@@ -30740,15 +30899,10 @@ var ngSwitchDefaultDirective = ngDirective({
30740
30899
  * @element ANY
30741
30900
  *
30742
30901
  * @example
30743
- <example module="transclude">
30902
+ <example module="transcludeExample">
30744
30903
  <file name="index.html">
30745
30904
  <script>
30746
- function Ctrl($scope) {
30747
- $scope.title = 'Lorem Ipsum';
30748
- $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
30749
- }
30750
-
30751
- angular.module('transclude', [])
30905
+ angular.module('transcludeExample', [])
30752
30906
  .directive('pane', function(){
30753
30907
  return {
30754
30908
  restrict: 'E',
@@ -30759,9 +30913,13 @@ var ngSwitchDefaultDirective = ngDirective({
30759
30913
  '<div ng-transclude></div>' +
30760
30914
  '</div>'
30761
30915
  };
30762
- });
30916
+ })
30917
+ .controller('ExampleController', ['$scope', function($scope) {
30918
+ $scope.title = 'Lorem Ipsum';
30919
+ $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
30920
+ }]);
30763
30921
  </script>
30764
- <div ng-controller="Ctrl">
30922
+ <div ng-controller="ExampleController">
30765
30923
  <input ng-model="title"><br>
30766
30924
  <textarea ng-model="text"></textarea> <br/>
30767
30925
  <pane title="{{title}}">{{text}}</pane>
@@ -30920,21 +31078,22 @@ var ngOptionsMinErr = minErr('ngOptions');
30920
31078
  * `value` variable (e.g. `value.propertyName`).
30921
31079
  *
30922
31080
  * @example
30923
- <example>
31081
+ <example module="selectExample">
30924
31082
  <file name="index.html">
30925
31083
  <script>
30926
- function MyCntrl($scope) {
30927
- $scope.colors = [
30928
- {name:'black', shade:'dark'},
30929
- {name:'white', shade:'light'},
30930
- {name:'red', shade:'dark'},
30931
- {name:'blue', shade:'dark'},
30932
- {name:'yellow', shade:'light'}
30933
- ];
30934
- $scope.myColor = $scope.colors[2]; // red
30935
- }
31084
+ angular.module('selectExample', [])
31085
+ .controller('ExampleController', ['$scope', function($scope) {
31086
+ $scope.colors = [
31087
+ {name:'black', shade:'dark'},
31088
+ {name:'white', shade:'light'},
31089
+ {name:'red', shade:'dark'},
31090
+ {name:'blue', shade:'dark'},
31091
+ {name:'yellow', shade:'light'}
31092
+ ];
31093
+ $scope.myColor = $scope.colors[2]; // red
31094
+ }]);
30936
31095
  </script>
30937
- <div ng-controller="MyCntrl">
31096
+ <div ng-controller="ExampleController">
30938
31097
  <ul>
30939
31098
  <li ng-repeat="color in colors">
30940
31099
  Name: <input ng-model="color.name">
@@ -30971,7 +31130,7 @@ var ngOptionsMinErr = minErr('ngOptions');
30971
31130
  <file name="protractor.js" type="protractor">
30972
31131
  it('should check ng-options', function() {
30973
31132
  expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
30974
- element.all(by.select('myColor')).first().click();
31133
+ element.all(by.model('myColor')).first().click();
30975
31134
  element.all(by.css('select[ng-model="myColor"] option')).first().click();
30976
31135
  expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
30977
31136
  element(by.css('.nullable select[ng-model="myColor"]')).click();
@@ -31387,6 +31546,12 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
31387
31546
  // lastElement.prop('selected') provided by jQuery has side-effects
31388
31547
  if (existingOption.selected !== option.selected) {
31389
31548
  lastElement.prop('selected', (existingOption.selected = option.selected));
31549
+ if (msie) {
31550
+ // See #7692
31551
+ // The selected item wouldn't visually update on IE without this.
31552
+ // Tested on Win7: IE9, IE10 and IE11. Future IEs should be tested as well
31553
+ lastElement.prop('selected', existingOption.selected);
31554
+ }
31390
31555
  }
31391
31556
  } else {
31392
31557
  // grow elements
@@ -31401,7 +31566,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
31401
31566
  // rather then the element.
31402
31567
  (element = optionTemplate.clone())
31403
31568
  .val(option.id)
31404
- .attr('selected', option.selected)
31569
+ .prop('selected', option.selected)
31405
31570
  .text(option.label);
31406
31571
  }
31407
31572
 
@@ -31782,7 +31947,7 @@ _jQuery.fn.bindings = function(windowJquery, bindExp) {
31782
31947
  function push(value) {
31783
31948
  if (value === undefined) {
31784
31949
  value = '';
31785
- } else if (typeof value != 'string') {
31950
+ } else if (typeof value !== 'string') {
31786
31951
  value = angular.toJson(value);
31787
31952
  }
31788
31953
  result.push('' + value);