angularjs-on-rails 0.1.1 → 0.1.2

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