angular_velocity 0.0.6alpha → 1.0.0
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.
- data/Gemfile +1 -1
- data/lib/angular_velocity/version.rb +1 -1
- data/lib/generators/angular_velocity/install/templates/angular-cookies.js +16 -3
- data/lib/generators/angular_velocity/install/templates/angular-mocks.js +144 -103
- data/lib/generators/angular_velocity/install/templates/angular-resource.js +19 -7
- data/lib/generators/angular_velocity/install/templates/angular-sanitize.js +27 -6
- data/lib/generators/angular_velocity/install/templates/angular-scenario.js +885 -459
- data/lib/generators/angular_velocity/install/templates/angular.js +754 -356
- data/lib/generators/angular_velocity/install/templates/templates_controller.rb +2 -1
- metadata +6 -6
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.0.
|
2
|
+
* @license AngularJS v1.0.8
|
3
3
|
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -67,6 +67,29 @@ var /** holds major version number for IE or NaN for real browsers */
|
|
67
67
|
nodeName_,
|
68
68
|
uid = ['0', '0', '0'];
|
69
69
|
|
70
|
+
|
71
|
+
/**
|
72
|
+
* @private
|
73
|
+
* @param {*} obj
|
74
|
+
* @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...)
|
75
|
+
*/
|
76
|
+
function isArrayLike(obj) {
|
77
|
+
if (!obj || (typeof obj.length !== 'number')) return false;
|
78
|
+
|
79
|
+
// We have on object which has length property. Should we treat it as array?
|
80
|
+
if (typeof obj.hasOwnProperty != 'function' &&
|
81
|
+
typeof obj.constructor != 'function') {
|
82
|
+
// This is here for IE8: it is a bogus object treat it as array;
|
83
|
+
return true;
|
84
|
+
} else {
|
85
|
+
return obj instanceof JQLite || // JQLite
|
86
|
+
(jQuery && obj instanceof jQuery) || // jQuery
|
87
|
+
toString.call(obj) !== '[object Object]' || // some browser native object
|
88
|
+
typeof obj.callee === 'function'; // arguments (on IE8 looks like regular obj)
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
|
70
93
|
/**
|
71
94
|
* @ngdoc function
|
72
95
|
* @name angular.forEach
|
@@ -94,30 +117,6 @@ var /** holds major version number for IE or NaN for real browsers */
|
|
94
117
|
* @param {Object=} context Object to become context (`this`) for the iterator function.
|
95
118
|
* @returns {Object|Array} Reference to `obj`.
|
96
119
|
*/
|
97
|
-
|
98
|
-
|
99
|
-
/**
|
100
|
-
* @private
|
101
|
-
* @param {*} obj
|
102
|
-
* @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...)
|
103
|
-
*/
|
104
|
-
function isArrayLike(obj) {
|
105
|
-
if (!obj || (typeof obj.length !== 'number')) return false;
|
106
|
-
|
107
|
-
// We have on object which has length property. Should we treat it as array?
|
108
|
-
if (typeof obj.hasOwnProperty != 'function' &&
|
109
|
-
typeof obj.constructor != 'function') {
|
110
|
-
// This is here for IE8: it is a bogus object treat it as array;
|
111
|
-
return true;
|
112
|
-
} else {
|
113
|
-
return obj instanceof JQLite || // JQLite
|
114
|
-
(jQuery && obj instanceof jQuery) || // jQuery
|
115
|
-
toString.call(obj) !== '[object Object]' || // some browser native object
|
116
|
-
typeof obj.callee === 'function'; // arguments (on IE8 looks like regular obj)
|
117
|
-
}
|
118
|
-
}
|
119
|
-
|
120
|
-
|
121
120
|
function forEach(obj, iterator, context) {
|
122
121
|
var key;
|
123
122
|
if (obj) {
|
@@ -201,6 +200,21 @@ function nextUid() {
|
|
201
200
|
return uid.join('');
|
202
201
|
}
|
203
202
|
|
203
|
+
|
204
|
+
/**
|
205
|
+
* Set or clear the hashkey for an object.
|
206
|
+
* @param obj object
|
207
|
+
* @param h the hashkey (!truthy to delete the hashkey)
|
208
|
+
*/
|
209
|
+
function setHashKey(obj, h) {
|
210
|
+
if (h) {
|
211
|
+
obj.$$hashKey = h;
|
212
|
+
}
|
213
|
+
else {
|
214
|
+
delete obj.$$hashKey;
|
215
|
+
}
|
216
|
+
}
|
217
|
+
|
204
218
|
/**
|
205
219
|
* @ngdoc function
|
206
220
|
* @name angular.extend
|
@@ -212,8 +226,10 @@ function nextUid() {
|
|
212
226
|
*
|
213
227
|
* @param {Object} dst Destination object.
|
214
228
|
* @param {...Object} src Source object(s).
|
229
|
+
* @returns {Object} Reference to `dst`.
|
215
230
|
*/
|
216
231
|
function extend(dst) {
|
232
|
+
var h = dst.$$hashKey;
|
217
233
|
forEach(arguments, function(obj){
|
218
234
|
if (obj !== dst) {
|
219
235
|
forEach(obj, function(value, key){
|
@@ -221,6 +237,8 @@ function extend(dst) {
|
|
221
237
|
});
|
222
238
|
}
|
223
239
|
});
|
240
|
+
|
241
|
+
setHashKey(dst,h);
|
224
242
|
return dst;
|
225
243
|
}
|
226
244
|
|
@@ -264,7 +282,7 @@ noop.$inject = [];
|
|
264
282
|
*
|
265
283
|
<pre>
|
266
284
|
function transformer(transformationFn, value) {
|
267
|
-
return (transformationFn || identity)(value);
|
285
|
+
return (transformationFn || angular.identity)(value);
|
268
286
|
};
|
269
287
|
</pre>
|
270
288
|
*/
|
@@ -391,6 +409,18 @@ function isArray(value) {
|
|
391
409
|
function isFunction(value){return typeof value == 'function';}
|
392
410
|
|
393
411
|
|
412
|
+
/**
|
413
|
+
* Determines if a value is a regular expression object.
|
414
|
+
*
|
415
|
+
* @private
|
416
|
+
* @param {*} value Reference to check.
|
417
|
+
* @returns {boolean} True if `value` is a `RegExp`.
|
418
|
+
*/
|
419
|
+
function isRegExp(value) {
|
420
|
+
return toString.apply(value) == '[object RegExp]';
|
421
|
+
}
|
422
|
+
|
423
|
+
|
394
424
|
/**
|
395
425
|
* Checks if `obj` is a window object.
|
396
426
|
*
|
@@ -418,9 +448,20 @@ function isBoolean(value) {
|
|
418
448
|
}
|
419
449
|
|
420
450
|
|
421
|
-
|
422
|
-
|
423
|
-
|
451
|
+
var trim = (function() {
|
452
|
+
// native trim is way faster: http://jsperf.com/angular-trim-test
|
453
|
+
// but IE doesn't have it... :-(
|
454
|
+
// TODO: we should move this into IE/ES5 polyfill
|
455
|
+
if (!String.prototype.trim) {
|
456
|
+
return function(value) {
|
457
|
+
return isString(value) ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value;
|
458
|
+
};
|
459
|
+
}
|
460
|
+
return function(value) {
|
461
|
+
return isString(value) ? value.trim() : value;
|
462
|
+
};
|
463
|
+
})();
|
464
|
+
|
424
465
|
|
425
466
|
/**
|
426
467
|
* @ngdoc function
|
@@ -563,6 +604,8 @@ function copy(source, destination){
|
|
563
604
|
destination = copy(source, []);
|
564
605
|
} else if (isDate(source)) {
|
565
606
|
destination = new Date(source.getTime());
|
607
|
+
} else if (isRegExp(source)) {
|
608
|
+
destination = new RegExp(source.source);
|
566
609
|
} else if (isObject(source)) {
|
567
610
|
destination = copy(source, {});
|
568
611
|
}
|
@@ -575,12 +618,14 @@ function copy(source, destination){
|
|
575
618
|
destination.push(copy(source[i]));
|
576
619
|
}
|
577
620
|
} else {
|
621
|
+
var h = destination.$$hashKey;
|
578
622
|
forEach(destination, function(value, key){
|
579
623
|
delete destination[key];
|
580
624
|
});
|
581
625
|
for ( var key in source) {
|
582
626
|
destination[key] = copy(source[key]);
|
583
627
|
}
|
628
|
+
setHashKey(destination,h);
|
584
629
|
}
|
585
630
|
}
|
586
631
|
return destination;
|
@@ -608,7 +653,7 @@ function shallowCopy(src, dst) {
|
|
608
653
|
* @function
|
609
654
|
*
|
610
655
|
* @description
|
611
|
-
* Determines if two objects or two values are equivalent. Supports value types, arrays and
|
656
|
+
* Determines if two objects or two values are equivalent. Supports value types, regular expressions, arrays and
|
612
657
|
* objects.
|
613
658
|
*
|
614
659
|
* Two objects or values are considered equivalent if at least one of the following is true:
|
@@ -616,11 +661,14 @@ function shallowCopy(src, dst) {
|
|
616
661
|
* * Both objects or values pass `===` comparison.
|
617
662
|
* * Both objects or values are of the same type and all of their properties pass `===` comparison.
|
618
663
|
* * Both values are NaN. (In JavasScript, NaN == NaN => false. But we consider two NaN as equal)
|
664
|
+
* * Both values represent the same regular expression (In JavasScript,
|
665
|
+
* /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
|
666
|
+
* representation matches).
|
619
667
|
*
|
620
668
|
* During a property comparision, properties of `function` type and properties with names
|
621
669
|
* that begin with `$` are ignored.
|
622
670
|
*
|
623
|
-
* Scope and DOMWindow objects are being compared only
|
671
|
+
* Scope and DOMWindow objects are being compared only by identify (`===`).
|
624
672
|
*
|
625
673
|
* @param {*} o1 Object or value to compare.
|
626
674
|
* @param {*} o2 Object or value to compare.
|
@@ -634,6 +682,7 @@ function equals(o1, o2) {
|
|
634
682
|
if (t1 == t2) {
|
635
683
|
if (t1 == 'object') {
|
636
684
|
if (isArray(o1)) {
|
685
|
+
if (!isArray(o2)) return false;
|
637
686
|
if ((length = o1.length) == o2.length) {
|
638
687
|
for(key=0; key<length; key++) {
|
639
688
|
if (!equals(o1[key], o2[key])) return false;
|
@@ -642,8 +691,10 @@ function equals(o1, o2) {
|
|
642
691
|
}
|
643
692
|
} else if (isDate(o1)) {
|
644
693
|
return isDate(o2) && o1.getTime() == o2.getTime();
|
694
|
+
} else if (isRegExp(o1) && isRegExp(o2)) {
|
695
|
+
return o1.toString() == o2.toString();
|
645
696
|
} else {
|
646
|
-
if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2)) return false;
|
697
|
+
if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false;
|
647
698
|
keySet = {};
|
648
699
|
for(key in o1) {
|
649
700
|
if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
|
@@ -680,7 +731,7 @@ function sliceArgs(args, startIndex) {
|
|
680
731
|
*
|
681
732
|
* @description
|
682
733
|
* Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
|
683
|
-
* `fn`). You can supply optional `args` that are
|
734
|
+
* `fn`). You can supply optional `args` that are prebound to the function. This feature is also
|
684
735
|
* known as [function currying](http://en.wikipedia.org/wiki/Currying).
|
685
736
|
*
|
686
737
|
* @param {Object} self Context which `fn` should be evaluated in.
|
@@ -732,13 +783,15 @@ function toJsonReplacer(key, value) {
|
|
732
783
|
* @function
|
733
784
|
*
|
734
785
|
* @description
|
735
|
-
* Serializes input into a JSON-formatted string.
|
786
|
+
* Serializes input into a JSON-formatted string. Properties with leading $ characters will be
|
787
|
+
* stripped since angular uses this notation internally.
|
736
788
|
*
|
737
789
|
* @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
|
738
790
|
* @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace.
|
739
|
-
* @returns {string} Jsonified string representing `obj`.
|
791
|
+
* @returns {string|undefined} Jsonified string representing `obj`.
|
740
792
|
*/
|
741
793
|
function toJson(obj, pretty) {
|
794
|
+
if (typeof obj === 'undefined') return undefined;
|
742
795
|
return JSON.stringify(obj, toJsonReplacer, pretty ? ' ' : null);
|
743
796
|
}
|
744
797
|
|
@@ -798,6 +851,23 @@ function startingTag(element) {
|
|
798
851
|
|
799
852
|
/////////////////////////////////////////////////
|
800
853
|
|
854
|
+
/**
|
855
|
+
* Tries to decode the URI component without throwing an exception.
|
856
|
+
*
|
857
|
+
* @private
|
858
|
+
* @param str value potential URI component to check.
|
859
|
+
* @returns {boolean} True if `value` can be decoded
|
860
|
+
* with the decodeURIComponent function.
|
861
|
+
*/
|
862
|
+
function tryDecodeURIComponent(value) {
|
863
|
+
try {
|
864
|
+
return decodeURIComponent(value);
|
865
|
+
} catch(e) {
|
866
|
+
// Ignore any invalid uri component
|
867
|
+
}
|
868
|
+
}
|
869
|
+
|
870
|
+
|
801
871
|
/**
|
802
872
|
* Parses an escaped url query string into key-value pairs.
|
803
873
|
* @returns Object.<(string|boolean)>
|
@@ -805,10 +875,12 @@ function startingTag(element) {
|
|
805
875
|
function parseKeyValue(/**string*/keyValue) {
|
806
876
|
var obj = {}, key_value, key;
|
807
877
|
forEach((keyValue || "").split('&'), function(keyValue){
|
808
|
-
if (keyValue) {
|
878
|
+
if ( keyValue ) {
|
809
879
|
key_value = keyValue.split('=');
|
810
|
-
key =
|
811
|
-
|
880
|
+
key = tryDecodeURIComponent(key_value[0]);
|
881
|
+
if ( isDefined(key) ) {
|
882
|
+
obj[key] = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
|
883
|
+
}
|
812
884
|
}
|
813
885
|
});
|
814
886
|
return obj;
|
@@ -873,11 +945,15 @@ function encodeUriQuery(val, pctEncodeSpaces) {
|
|
873
945
|
*
|
874
946
|
* @description
|
875
947
|
*
|
876
|
-
* Use this directive to auto-bootstrap
|
877
|
-
* one directive can be used per HTML document. The directive
|
948
|
+
* Use this directive to auto-bootstrap an application. Only
|
949
|
+
* one ngApp directive can be used per HTML document. The directive
|
878
950
|
* designates the root of the application and is typically placed
|
879
951
|
* at the root of the page.
|
880
952
|
*
|
953
|
+
* The first ngApp found in the document will be auto-bootstrapped. To use multiple applications in an
|
954
|
+
* HTML document you must manually bootstrap them using {@link angular.bootstrap}.
|
955
|
+
* Applications cannot be nested.
|
956
|
+
*
|
881
957
|
* In the example below if the `ngApp` directive would not be placed
|
882
958
|
* on the `html` element then the document would not be compiled
|
883
959
|
* and the `{{ 1+2 }}` would not be resolved to `3`.
|
@@ -943,12 +1019,15 @@ function angularInit(element, bootstrap) {
|
|
943
1019
|
*
|
944
1020
|
* See: {@link guide/bootstrap Bootstrap}
|
945
1021
|
*
|
1022
|
+
* Note that ngScenario-based end-to-end tests cannot use this function to bootstrap manually.
|
1023
|
+
* They must use {@link api/ng.directive:ngApp ngApp}.
|
1024
|
+
*
|
946
1025
|
* @param {Element} element DOM element which is the root of angular application.
|
947
1026
|
* @param {Array<String|Function>=} modules an array of module declarations. See: {@link angular.module modules}
|
948
1027
|
* @returns {AUTO.$injector} Returns the newly created injector for this app.
|
949
1028
|
*/
|
950
1029
|
function bootstrap(element, modules) {
|
951
|
-
var
|
1030
|
+
var doBootstrap = function() {
|
952
1031
|
element = jqLite(element);
|
953
1032
|
modules = modules || [];
|
954
1033
|
modules.unshift(['$provide', function($provide) {
|
@@ -970,7 +1049,7 @@ function bootstrap(element, modules) {
|
|
970
1049
|
var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
|
971
1050
|
|
972
1051
|
if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
|
973
|
-
return
|
1052
|
+
return doBootstrap();
|
974
1053
|
}
|
975
1054
|
|
976
1055
|
window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
|
@@ -978,7 +1057,7 @@ function bootstrap(element, modules) {
|
|
978
1057
|
forEach(extraModules, function(module) {
|
979
1058
|
modules.push(module);
|
980
1059
|
});
|
981
|
-
|
1060
|
+
doBootstrap();
|
982
1061
|
};
|
983
1062
|
}
|
984
1063
|
|
@@ -1002,9 +1081,10 @@ function bindJQuery() {
|
|
1002
1081
|
injector: JQLitePrototype.injector,
|
1003
1082
|
inheritedData: JQLitePrototype.inheritedData
|
1004
1083
|
});
|
1005
|
-
JQLitePatchJQueryRemove(
|
1006
|
-
JQLitePatchJQueryRemove('
|
1007
|
-
JQLitePatchJQueryRemove('
|
1084
|
+
// Method signature: JQLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments)
|
1085
|
+
JQLitePatchJQueryRemove('remove', true, true, false);
|
1086
|
+
JQLitePatchJQueryRemove('empty', false, false, false);
|
1087
|
+
JQLitePatchJQueryRemove('html', false, false, true);
|
1008
1088
|
} else {
|
1009
1089
|
jqLite = JQLite;
|
1010
1090
|
}
|
@@ -1012,7 +1092,7 @@ function bindJQuery() {
|
|
1012
1092
|
}
|
1013
1093
|
|
1014
1094
|
/**
|
1015
|
-
* throw error
|
1095
|
+
* throw error if the argument is falsy.
|
1016
1096
|
*/
|
1017
1097
|
function assertArg(arg, name, reason) {
|
1018
1098
|
if (!arg) {
|
@@ -1031,6 +1111,33 @@ function assertArgFn(arg, name, acceptArrayAnnotation) {
|
|
1031
1111
|
return arg;
|
1032
1112
|
}
|
1033
1113
|
|
1114
|
+
/**
|
1115
|
+
* Return the value accessible from the object by path. Any undefined traversals are ignored
|
1116
|
+
* @param {Object} obj starting object
|
1117
|
+
* @param {string} path path to traverse
|
1118
|
+
* @param {boolean=true} bindFnToScope
|
1119
|
+
* @returns value as accessible by path
|
1120
|
+
*/
|
1121
|
+
//TODO(misko): this function needs to be removed
|
1122
|
+
function getter(obj, path, bindFnToScope) {
|
1123
|
+
if (!path) return obj;
|
1124
|
+
var keys = path.split('.');
|
1125
|
+
var key;
|
1126
|
+
var lastInstance = obj;
|
1127
|
+
var len = keys.length;
|
1128
|
+
|
1129
|
+
for (var i = 0; i < len; i++) {
|
1130
|
+
key = keys[i];
|
1131
|
+
if (obj) {
|
1132
|
+
obj = (lastInstance = obj)[key];
|
1133
|
+
}
|
1134
|
+
}
|
1135
|
+
if (!bindFnToScope && isFunction(obj)) {
|
1136
|
+
return bind(lastInstance, obj);
|
1137
|
+
}
|
1138
|
+
return obj;
|
1139
|
+
}
|
1140
|
+
|
1034
1141
|
/**
|
1035
1142
|
* @ngdoc interface
|
1036
1143
|
* @name angular.Module
|
@@ -1061,8 +1168,8 @@ function setupModuleLoader(window) {
|
|
1061
1168
|
*
|
1062
1169
|
* # Module
|
1063
1170
|
*
|
1064
|
-
* A module is a
|
1065
|
-
* is used to configure the {@link AUTO.$injector $injector}.
|
1171
|
+
* A module is a collection of services, directives, filters, and configuration information.
|
1172
|
+
* `angular.module` is used to configure the {@link AUTO.$injector $injector}.
|
1066
1173
|
*
|
1067
1174
|
* <pre>
|
1068
1175
|
* // Create a new module
|
@@ -1293,11 +1400,11 @@ function setupModuleLoader(window) {
|
|
1293
1400
|
* - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
|
1294
1401
|
*/
|
1295
1402
|
var version = {
|
1296
|
-
full: '1.0.
|
1403
|
+
full: '1.0.8', // all of these placeholder strings will be replaced by grunt's
|
1297
1404
|
major: 1, // package task
|
1298
1405
|
minor: 0,
|
1299
|
-
dot:
|
1300
|
-
codeName: '
|
1406
|
+
dot: 8,
|
1407
|
+
codeName: 'bubble-burst'
|
1301
1408
|
};
|
1302
1409
|
|
1303
1410
|
|
@@ -1366,7 +1473,6 @@ function publishExternalAPI(angular){
|
|
1366
1473
|
ngPluralize: ngPluralizeDirective,
|
1367
1474
|
ngRepeat: ngRepeatDirective,
|
1368
1475
|
ngShow: ngShowDirective,
|
1369
|
-
ngSubmit: ngSubmitDirective,
|
1370
1476
|
ngStyle: ngStyleDirective,
|
1371
1477
|
ngSwitch: ngSwitchDirective,
|
1372
1478
|
ngSwitchWhen: ngSwitchWhenDirective,
|
@@ -1436,24 +1542,25 @@ function publishExternalAPI(angular){
|
|
1436
1542
|
* Note: All element references in Angular are always wrapped with jQuery or jqLite; they are never
|
1437
1543
|
* raw DOM references.
|
1438
1544
|
*
|
1439
|
-
* ## Angular's
|
1545
|
+
* ## Angular's jqLite
|
1546
|
+
* Angular's lite version of jQuery provides only the following jQuery methods:
|
1440
1547
|
*
|
1441
1548
|
* - [addClass()](http://api.jquery.com/addClass/)
|
1442
1549
|
* - [after()](http://api.jquery.com/after/)
|
1443
1550
|
* - [append()](http://api.jquery.com/append/)
|
1444
1551
|
* - [attr()](http://api.jquery.com/attr/)
|
1445
|
-
* - [bind()](http://api.jquery.com/bind/)
|
1446
|
-
* - [children()](http://api.jquery.com/children/)
|
1552
|
+
* - [bind()](http://api.jquery.com/bind/) - Does not support namespaces
|
1553
|
+
* - [children()](http://api.jquery.com/children/) - Does not support selectors
|
1447
1554
|
* - [clone()](http://api.jquery.com/clone/)
|
1448
1555
|
* - [contents()](http://api.jquery.com/contents/)
|
1449
1556
|
* - [css()](http://api.jquery.com/css/)
|
1450
1557
|
* - [data()](http://api.jquery.com/data/)
|
1451
1558
|
* - [eq()](http://api.jquery.com/eq/)
|
1452
|
-
* - [find()](http://api.jquery.com/find/) - Limited to lookups by tag name
|
1559
|
+
* - [find()](http://api.jquery.com/find/) - Limited to lookups by tag name
|
1453
1560
|
* - [hasClass()](http://api.jquery.com/hasClass/)
|
1454
1561
|
* - [html()](http://api.jquery.com/html/)
|
1455
|
-
* - [next()](http://api.jquery.com/next/)
|
1456
|
-
* - [parent()](http://api.jquery.com/parent/)
|
1562
|
+
* - [next()](http://api.jquery.com/next/) - Does not support selectors
|
1563
|
+
* - [parent()](http://api.jquery.com/parent/) - Does not support selectors
|
1457
1564
|
* - [prepend()](http://api.jquery.com/prepend/)
|
1458
1565
|
* - [prop()](http://api.jquery.com/prop/)
|
1459
1566
|
* - [ready()](http://api.jquery.com/ready/)
|
@@ -1465,12 +1572,18 @@ function publishExternalAPI(angular){
|
|
1465
1572
|
* - [text()](http://api.jquery.com/text/)
|
1466
1573
|
* - [toggleClass()](http://api.jquery.com/toggleClass/)
|
1467
1574
|
* - [triggerHandler()](http://api.jquery.com/triggerHandler/) - Doesn't pass native event objects to handlers.
|
1468
|
-
* - [unbind()](http://api.jquery.com/unbind/)
|
1575
|
+
* - [unbind()](http://api.jquery.com/unbind/) - Does not support namespaces
|
1469
1576
|
* - [val()](http://api.jquery.com/val/)
|
1470
1577
|
* - [wrap()](http://api.jquery.com/wrap/)
|
1471
1578
|
*
|
1472
|
-
* ##
|
1579
|
+
* ## jQuery/jqLite Extras
|
1580
|
+
* Angular also provides the following additional methods and events to both jQuery and jqLite:
|
1473
1581
|
*
|
1582
|
+
* ### Events
|
1583
|
+
* - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
|
1584
|
+
* on all DOM nodes being removed. This can be used to clean up and 3rd party bindings to the DOM
|
1585
|
+
* element before it is removed.
|
1586
|
+
* ### Methods
|
1474
1587
|
* - `controller(name)` - retrieves the controller of the current element or its parent. By default
|
1475
1588
|
* retrieves controller associated with the `ngController` directive. If `name` is provided as
|
1476
1589
|
* camelCase directive name, then the controller for this directive will be retrieved (e.g.
|
@@ -1517,37 +1630,38 @@ function camelCase(name) {
|
|
1517
1630
|
/////////////////////////////////////////////
|
1518
1631
|
// jQuery mutation patch
|
1519
1632
|
//
|
1520
|
-
//
|
1633
|
+
// In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a
|
1521
1634
|
// $destroy event on all DOM nodes being removed.
|
1522
1635
|
//
|
1523
1636
|
/////////////////////////////////////////////
|
1524
1637
|
|
1525
|
-
function JQLitePatchJQueryRemove(name, dispatchThis) {
|
1638
|
+
function JQLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) {
|
1526
1639
|
var originalJqFn = jQuery.fn[name];
|
1527
1640
|
originalJqFn = originalJqFn.$original || originalJqFn;
|
1528
1641
|
removePatch.$original = originalJqFn;
|
1529
1642
|
jQuery.fn[name] = removePatch;
|
1530
1643
|
|
1531
|
-
function removePatch() {
|
1532
|
-
var list = [this],
|
1644
|
+
function removePatch(param) {
|
1645
|
+
var list = filterElems && param ? [this.filter(param)] : [this],
|
1533
1646
|
fireEvent = dispatchThis,
|
1534
1647
|
set, setIndex, setLength,
|
1535
|
-
element, childIndex, childLength, children
|
1536
|
-
|
1537
|
-
|
1538
|
-
|
1539
|
-
|
1540
|
-
|
1541
|
-
|
1542
|
-
|
1543
|
-
|
1544
|
-
|
1545
|
-
|
1546
|
-
|
1547
|
-
|
1548
|
-
|
1549
|
-
|
1550
|
-
|
1648
|
+
element, childIndex, childLength, children;
|
1649
|
+
|
1650
|
+
if (!getterIfNoArguments || param != null) {
|
1651
|
+
while(list.length) {
|
1652
|
+
set = list.shift();
|
1653
|
+
for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
|
1654
|
+
element = jqLite(set[setIndex]);
|
1655
|
+
if (fireEvent) {
|
1656
|
+
element.triggerHandler('$destroy');
|
1657
|
+
} else {
|
1658
|
+
fireEvent = !fireEvent;
|
1659
|
+
}
|
1660
|
+
for(childIndex = 0, childLength = (children = element.children()).length;
|
1661
|
+
childIndex < childLength;
|
1662
|
+
childIndex++) {
|
1663
|
+
list.push(jQuery(children[childIndex]));
|
1664
|
+
}
|
1551
1665
|
}
|
1552
1666
|
}
|
1553
1667
|
}
|
@@ -1607,7 +1721,7 @@ function JQLiteUnbind(element, type, fn) {
|
|
1607
1721
|
removeEventListenerFn(element, type, events[type]);
|
1608
1722
|
delete events[type];
|
1609
1723
|
} else {
|
1610
|
-
arrayRemove(events[type], fn);
|
1724
|
+
arrayRemove(events[type] || [], fn);
|
1611
1725
|
}
|
1612
1726
|
}
|
1613
1727
|
}
|
@@ -1881,6 +1995,15 @@ forEach({
|
|
1881
1995
|
|
1882
1996
|
val: function(element, value) {
|
1883
1997
|
if (isUndefined(value)) {
|
1998
|
+
if (nodeName_(element) === 'SELECT' && element.multiple) {
|
1999
|
+
var result = [];
|
2000
|
+
forEach(element.options, function (option) {
|
2001
|
+
if (option.selected) {
|
2002
|
+
result.push(option.value || option.text);
|
2003
|
+
}
|
2004
|
+
});
|
2005
|
+
return result.length === 0 ? null : result;
|
2006
|
+
}
|
1884
2007
|
return element.value;
|
1885
2008
|
}
|
1886
2009
|
element.value = value;
|
@@ -2012,23 +2135,43 @@ forEach({
|
|
2012
2135
|
|
2013
2136
|
if (!eventFns) {
|
2014
2137
|
if (type == 'mouseenter' || type == 'mouseleave') {
|
2015
|
-
var
|
2138
|
+
var contains = document.body.contains || document.body.compareDocumentPosition ?
|
2139
|
+
function( a, b ) {
|
2140
|
+
var adown = a.nodeType === 9 ? a.documentElement : a,
|
2141
|
+
bup = b && b.parentNode;
|
2142
|
+
return a === bup || !!( bup && bup.nodeType === 1 && (
|
2143
|
+
adown.contains ?
|
2144
|
+
adown.contains( bup ) :
|
2145
|
+
a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
|
2146
|
+
));
|
2147
|
+
} :
|
2148
|
+
function( a, b ) {
|
2149
|
+
if ( b ) {
|
2150
|
+
while ( (b = b.parentNode) ) {
|
2151
|
+
if ( b === a ) {
|
2152
|
+
return true;
|
2153
|
+
}
|
2154
|
+
}
|
2155
|
+
}
|
2156
|
+
return false;
|
2157
|
+
};
|
2016
2158
|
|
2017
|
-
events
|
2018
|
-
|
2159
|
+
events[type] = [];
|
2160
|
+
|
2161
|
+
// Refer to jQuery's implementation of mouseenter & mouseleave
|
2162
|
+
// Read about mouseenter and mouseleave:
|
2163
|
+
// http://www.quirksmode.org/js/events_mouse.html#link8
|
2164
|
+
var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"}
|
2165
|
+
bindFn(element, eventmap[type], function(event) {
|
2166
|
+
var ret, target = this, related = event.relatedTarget;
|
2167
|
+
// For mousenter/leave call the handler if related is outside the target.
|
2168
|
+
// NB: No relatedTarget if the mouse left/entered the browser window
|
2169
|
+
if ( !related || (related !== target && !contains(target, related)) ){
|
2170
|
+
handle(event, type);
|
2171
|
+
}
|
2019
2172
|
|
2020
|
-
bindFn(element, 'mouseover', function(event) {
|
2021
|
-
counter++;
|
2022
|
-
if (counter == 1) {
|
2023
|
-
handle(event, 'mouseenter');
|
2024
|
-
}
|
2025
|
-
});
|
2026
|
-
bindFn(element, 'mouseout', function(event) {
|
2027
|
-
counter --;
|
2028
|
-
if (counter == 0) {
|
2029
|
-
handle(event, 'mouseleave');
|
2030
|
-
}
|
2031
2173
|
});
|
2174
|
+
|
2032
2175
|
} else {
|
2033
2176
|
addEventListenerFn(element, type, handle);
|
2034
2177
|
events[type] = [];
|
@@ -2078,12 +2221,7 @@ forEach({
|
|
2078
2221
|
if (element.nodeType === 1) {
|
2079
2222
|
var index = element.firstChild;
|
2080
2223
|
forEach(new JQLite(node), function(child){
|
2081
|
-
|
2082
|
-
element.insertBefore(child, index);
|
2083
|
-
} else {
|
2084
|
-
element.appendChild(child);
|
2085
|
-
index = child;
|
2086
|
-
}
|
2224
|
+
element.insertBefore(child, index);
|
2087
2225
|
});
|
2088
2226
|
}
|
2089
2227
|
},
|
@@ -2344,7 +2482,7 @@ function annotate(fn) {
|
|
2344
2482
|
}
|
2345
2483
|
} else if (isArray(fn)) {
|
2346
2484
|
last = fn.length - 1;
|
2347
|
-
assertArgFn(fn[last], 'fn')
|
2485
|
+
assertArgFn(fn[last], 'fn');
|
2348
2486
|
$inject = fn.slice(0, last);
|
2349
2487
|
} else {
|
2350
2488
|
assertArgFn(fn, 'fn', true);
|
@@ -2378,7 +2516,7 @@ function annotate(fn) {
|
|
2378
2516
|
* # Injection Function Annotation
|
2379
2517
|
*
|
2380
2518
|
* JavaScript does not have annotations, and annotations are needed for dependency injection. The
|
2381
|
-
* following
|
2519
|
+
* following are all valid ways of annotating function with injection arguments and are equivalent.
|
2382
2520
|
*
|
2383
2521
|
* <pre>
|
2384
2522
|
* // inferred (only works if code not minified/obfuscated)
|
@@ -2507,7 +2645,7 @@ function annotate(fn) {
|
|
2507
2645
|
* // ...
|
2508
2646
|
* };
|
2509
2647
|
* tmpFn.$inject = ['$compile', '$rootScope'];
|
2510
|
-
* injector.invoke(
|
2648
|
+
* injector.invoke(tmpFn);
|
2511
2649
|
*
|
2512
2650
|
* // To better support inline function the inline annotation is supported
|
2513
2651
|
* injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
|
@@ -2560,7 +2698,7 @@ function annotate(fn) {
|
|
2560
2698
|
*
|
2561
2699
|
* beforeEach(module(function($provide) {
|
2562
2700
|
* $provide.provider('greet', GreetProvider);
|
2563
|
-
* });
|
2701
|
+
* }));
|
2564
2702
|
*
|
2565
2703
|
* it('should greet', inject(function(greet) {
|
2566
2704
|
* expect(greet('angular')).toEqual('Hello angular!');
|
@@ -2573,9 +2711,7 @@ function annotate(fn) {
|
|
2573
2711
|
* inject(function(greet) {
|
2574
2712
|
* expect(greet('angular')).toEqual('Ahoj angular!');
|
2575
2713
|
* });
|
2576
|
-
* )
|
2577
|
-
*
|
2578
|
-
* });
|
2714
|
+
* });
|
2579
2715
|
* </pre>
|
2580
2716
|
*/
|
2581
2717
|
|
@@ -2669,7 +2805,7 @@ function annotate(fn) {
|
|
2669
2805
|
*
|
2670
2806
|
* @param {string} name The name of the service to decorate.
|
2671
2807
|
* @param {function()} decorator This function will be invoked when the service needs to be
|
2672
|
-
*
|
2808
|
+
* instantiated. The function is called using the {@link AUTO.$injector#invoke
|
2673
2809
|
* injector.invoke} method and is therefore fully injectable. Local injection arguments:
|
2674
2810
|
*
|
2675
2811
|
* * `$delegate` - The original service instance, which can be monkey patched, configured,
|
@@ -2869,6 +3005,8 @@ function createInjector(modulesToLoad) {
|
|
2869
3005
|
var Constructor = function() {},
|
2870
3006
|
instance, returnedValue;
|
2871
3007
|
|
3008
|
+
// Check if Type is annotated and use just the given function at n-1 as parameter
|
3009
|
+
// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
|
2872
3010
|
Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
|
2873
3011
|
instance = new Constructor();
|
2874
3012
|
returnedValue = invoke(Type, instance, locals);
|
@@ -3076,7 +3214,8 @@ function Browser(window, document, $log, $sniffer) {
|
|
3076
3214
|
//////////////////////////////////////////////////////////////
|
3077
3215
|
|
3078
3216
|
var lastBrowserUrl = location.href,
|
3079
|
-
baseElement = document.find('base')
|
3217
|
+
baseElement = document.find('base'),
|
3218
|
+
replacedUrl = null;
|
3080
3219
|
|
3081
3220
|
/**
|
3082
3221
|
* @name ng.$browser#url
|
@@ -3111,14 +3250,21 @@ function Browser(window, document, $log, $sniffer) {
|
|
3111
3250
|
baseElement.attr('href', baseElement.attr('href'));
|
3112
3251
|
}
|
3113
3252
|
} else {
|
3114
|
-
if (replace)
|
3115
|
-
|
3253
|
+
if (replace) {
|
3254
|
+
location.replace(url);
|
3255
|
+
replacedUrl = url;
|
3256
|
+
} else {
|
3257
|
+
location.href = url;
|
3258
|
+
replacedUrl = null;
|
3259
|
+
}
|
3116
3260
|
}
|
3117
3261
|
return self;
|
3118
3262
|
// getter
|
3119
3263
|
} else {
|
3120
|
-
// the
|
3121
|
-
|
3264
|
+
// - the replacedUrl is a workaround for an IE8-9 issue with location.replace method that doesn't update
|
3265
|
+
// location.href synchronously
|
3266
|
+
// - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
|
3267
|
+
return replacedUrl || location.href.replace(/%27/g,"'");
|
3122
3268
|
}
|
3123
3269
|
};
|
3124
3270
|
|
@@ -3249,7 +3395,13 @@ function Browser(window, document, $log, $sniffer) {
|
|
3249
3395
|
cookie = cookieArray[i];
|
3250
3396
|
index = cookie.indexOf('=');
|
3251
3397
|
if (index > 0) { //ignore nameless cookies
|
3252
|
-
|
3398
|
+
var name = unescape(cookie.substring(0, index));
|
3399
|
+
// the first value that is seen for a cookie is the most
|
3400
|
+
// specific one. values for the same cookie name that
|
3401
|
+
// follow are for less specific paths.
|
3402
|
+
if (lastCookies[name] === undefined) {
|
3403
|
+
lastCookies[name] = unescape(cookie.substring(index + 1));
|
3404
|
+
}
|
3253
3405
|
}
|
3254
3406
|
}
|
3255
3407
|
}
|
@@ -3319,7 +3471,20 @@ function $BrowserProvider(){
|
|
3319
3471
|
* @name ng.$cacheFactory
|
3320
3472
|
*
|
3321
3473
|
* @description
|
3322
|
-
* Factory that constructs cache objects.
|
3474
|
+
* Factory that constructs cache objects and gives access to them.
|
3475
|
+
*
|
3476
|
+
* <pre>
|
3477
|
+
*
|
3478
|
+
* var cache = $cacheFactory('cacheId');
|
3479
|
+
* expect($cacheFactory.get('cacheId')).toBe(cache);
|
3480
|
+
* expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
|
3481
|
+
*
|
3482
|
+
* cache.put("key", "value");
|
3483
|
+
* cache.put("another key", "another value");
|
3484
|
+
*
|
3485
|
+
* expect(cache.info()).toEqual({id: 'cacheId', size: 2}); // Since we've specified no options on creation
|
3486
|
+
*
|
3487
|
+
* </pre>
|
3323
3488
|
*
|
3324
3489
|
*
|
3325
3490
|
* @param {string} cacheId Name or id of the newly created cache.
|
@@ -3451,6 +3616,16 @@ function $CacheFactoryProvider() {
|
|
3451
3616
|
}
|
3452
3617
|
|
3453
3618
|
|
3619
|
+
/**
|
3620
|
+
* @ngdoc method
|
3621
|
+
* @name ng.$cacheFactory#info
|
3622
|
+
* @methodOf ng.$cacheFactory
|
3623
|
+
*
|
3624
|
+
* @description
|
3625
|
+
* Get information about all the of the caches that have been created
|
3626
|
+
*
|
3627
|
+
* @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
|
3628
|
+
*/
|
3454
3629
|
cacheFactory.info = function() {
|
3455
3630
|
var info = {};
|
3456
3631
|
forEach(caches, function(cache, cacheId) {
|
@@ -3460,6 +3635,17 @@ function $CacheFactoryProvider() {
|
|
3460
3635
|
};
|
3461
3636
|
|
3462
3637
|
|
3638
|
+
/**
|
3639
|
+
* @ngdoc method
|
3640
|
+
* @name ng.$cacheFactory#get
|
3641
|
+
* @methodOf ng.$cacheFactory
|
3642
|
+
*
|
3643
|
+
* @description
|
3644
|
+
* Get access to a cache object by the `cacheId` used when it was created.
|
3645
|
+
*
|
3646
|
+
* @param {string} cacheId Name or id of a cache to access.
|
3647
|
+
* @returns {object} Cache object identified by the cacheId or undefined if no such cache.
|
3648
|
+
*/
|
3463
3649
|
cacheFactory.get = function(cacheId) {
|
3464
3650
|
return caches[cacheId];
|
3465
3651
|
};
|
@@ -3474,8 +3660,44 @@ function $CacheFactoryProvider() {
|
|
3474
3660
|
* @name ng.$templateCache
|
3475
3661
|
*
|
3476
3662
|
* @description
|
3477
|
-
*
|
3478
|
-
*
|
3663
|
+
* The first time a template is used, it is loaded in the template cache for quick retrieval. You can
|
3664
|
+
* load templates directly into the cache in a `script` tag, or by consuming the `$templateCache`
|
3665
|
+
* service directly.
|
3666
|
+
*
|
3667
|
+
* Adding via the `script` tag:
|
3668
|
+
* <pre>
|
3669
|
+
* <html ng-app>
|
3670
|
+
* <head>
|
3671
|
+
* <script type="text/ng-template" id="templateId.html">
|
3672
|
+
* This is the content of the template
|
3673
|
+
* </script>
|
3674
|
+
* </head>
|
3675
|
+
* ...
|
3676
|
+
* </html>
|
3677
|
+
* </pre>
|
3678
|
+
*
|
3679
|
+
* **Note:** the `script` tag containing the template does not need to be included in the `head` of the document, but
|
3680
|
+
* it must be below the `ng-app` definition.
|
3681
|
+
*
|
3682
|
+
* Adding via the $templateCache service:
|
3683
|
+
*
|
3684
|
+
* <pre>
|
3685
|
+
* var myApp = angular.module('myApp', []);
|
3686
|
+
* myApp.run(function($templateCache) {
|
3687
|
+
* $templateCache.put('templateId.html', 'This is the content of the template');
|
3688
|
+
* });
|
3689
|
+
* </pre>
|
3690
|
+
*
|
3691
|
+
* To retrieve the template later, simply use it in your HTML:
|
3692
|
+
* <pre>
|
3693
|
+
* <div ng-include=" 'templateId.html' "></div>
|
3694
|
+
* </pre>
|
3695
|
+
*
|
3696
|
+
* or get it via Javascript:
|
3697
|
+
* <pre>
|
3698
|
+
* $templateCache.get('templateId.html')
|
3699
|
+
* </pre>
|
3700
|
+
*
|
3479
3701
|
* See {@link ng.$cacheFactory $cacheFactory}.
|
3480
3702
|
*
|
3481
3703
|
*/
|
@@ -3651,11 +3873,11 @@ function $CompileProvider($provide) {
|
|
3651
3873
|
* @function
|
3652
3874
|
*
|
3653
3875
|
* @description
|
3654
|
-
* Register a new
|
3876
|
+
* Register a new directive with the compiler.
|
3655
3877
|
*
|
3656
3878
|
* @param {string} name Name of the directive in camel-case. (ie <code>ngBind</code> which will match as
|
3657
3879
|
* <code>ng-bind</code>).
|
3658
|
-
* @param {function} directiveFactory An injectable directive
|
3880
|
+
* @param {function|Array} directiveFactory An injectable directive factory function. See {@link guide/directive} for more
|
3659
3881
|
* info.
|
3660
3882
|
* @returns {ng.$compileProvider} Self for chaining.
|
3661
3883
|
*/
|
@@ -3778,7 +4000,7 @@ function $CompileProvider($provide) {
|
|
3778
4000
|
|
3779
4001
|
// href property always returns normalized absolute url, so we can match against that
|
3780
4002
|
normalizedVal = urlSanitizationNode.href;
|
3781
|
-
if (!normalizedVal.match(urlSanitizationWhitelist)) {
|
4003
|
+
if (normalizedVal !== '' && !normalizedVal.match(urlSanitizationWhitelist)) {
|
3782
4004
|
this[key] = value = 'unsafe:' + normalizedVal;
|
3783
4005
|
}
|
3784
4006
|
}
|
@@ -4002,7 +4224,7 @@ function $CompileProvider($provide) {
|
|
4002
4224
|
for (var attr, name, nName, value, nAttrs = node.attributes,
|
4003
4225
|
j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
|
4004
4226
|
attr = nAttrs[j];
|
4005
|
-
if (attr.specified) {
|
4227
|
+
if (!msie || msie >= 8 || attr.specified) {
|
4006
4228
|
name = attr.name;
|
4007
4229
|
nName = directiveNormalize(name.toLowerCase());
|
4008
4230
|
attrsMap[nName] = name;
|
@@ -4054,9 +4276,9 @@ function $CompileProvider($provide) {
|
|
4054
4276
|
|
4055
4277
|
|
4056
4278
|
/**
|
4057
|
-
* Once the directives have been collected their compile functions
|
4279
|
+
* Once the directives have been collected, their compile functions are executed. This method
|
4058
4280
|
* is responsible for inlining directive templates as well as terminating the application
|
4059
|
-
* of the directives if the terminal directive has been reached
|
4281
|
+
* of the directives if the terminal directive has been reached.
|
4060
4282
|
*
|
4061
4283
|
* @param {Array} directives Array of collected directives to execute their compile function.
|
4062
4284
|
* this needs to be pre-sorted by priority order.
|
@@ -4064,11 +4286,11 @@ function $CompileProvider($provide) {
|
|
4064
4286
|
* @param {Object} templateAttrs The shared attribute function
|
4065
4287
|
* @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
|
4066
4288
|
* scope argument is auto-generated to the new child of the transcluded parent scope.
|
4067
|
-
* @param {
|
4068
|
-
* argument has the root jqLite array so that we can replace
|
4289
|
+
* @param {JQLite} jqCollection If we are working on the root of the compile tree then this
|
4290
|
+
* argument has the root jqLite array so that we can replace nodes on it.
|
4069
4291
|
* @returns linkFn
|
4070
4292
|
*/
|
4071
|
-
function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
|
4293
|
+
function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, jqCollection) {
|
4072
4294
|
var terminalPriority = -Number.MAX_VALUE,
|
4073
4295
|
preLinkFns = [],
|
4074
4296
|
postLinkFns = [],
|
@@ -4122,7 +4344,7 @@ function $CompileProvider($provide) {
|
|
4122
4344
|
$compileNode = templateAttrs.$$element =
|
4123
4345
|
jqLite(document.createComment(' ' + directiveName + ': ' + templateAttrs[directiveName] + ' '));
|
4124
4346
|
compileNode = $compileNode[0];
|
4125
|
-
replaceWith(
|
4347
|
+
replaceWith(jqCollection, jqLite($template[0]), compileNode);
|
4126
4348
|
childTranscludeFn = compile($template, transcludeFn, terminalPriority);
|
4127
4349
|
} else {
|
4128
4350
|
$template = jqLite(JQLiteClone(compileNode)).contents();
|
@@ -4146,7 +4368,7 @@ function $CompileProvider($provide) {
|
|
4146
4368
|
throw new Error(MULTI_ROOT_TEMPLATE_ERROR + directiveValue);
|
4147
4369
|
}
|
4148
4370
|
|
4149
|
-
replaceWith(
|
4371
|
+
replaceWith(jqCollection, $compileNode, compileNode);
|
4150
4372
|
|
4151
4373
|
var newTemplateAttrs = {$attr: {}};
|
4152
4374
|
|
@@ -4174,7 +4396,7 @@ function $CompileProvider($provide) {
|
|
4174
4396
|
assertNoDuplicate('template', templateDirective, directive, $compileNode);
|
4175
4397
|
templateDirective = directive;
|
4176
4398
|
nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i),
|
4177
|
-
nodeLinkFn, $compileNode, templateAttrs,
|
4399
|
+
nodeLinkFn, $compileNode, templateAttrs, jqCollection, directive.replace,
|
4178
4400
|
childTranscludeFn);
|
4179
4401
|
ii = directives.length;
|
4180
4402
|
} else if (directive.compile) {
|
@@ -4307,7 +4529,7 @@ function $CompileProvider($provide) {
|
|
4307
4529
|
parentGet = $parse(attrs[attrName]);
|
4308
4530
|
scope[scopeName] = function(locals) {
|
4309
4531
|
return parentGet(parentScope, locals);
|
4310
|
-
}
|
4532
|
+
};
|
4311
4533
|
break;
|
4312
4534
|
}
|
4313
4535
|
|
@@ -4795,7 +5017,7 @@ function $DocumentProvider(){
|
|
4795
5017
|
*
|
4796
5018
|
*/
|
4797
5019
|
function $ExceptionHandlerProvider() {
|
4798
|
-
this.$get = ['$log', function($log){
|
5020
|
+
this.$get = ['$log', function($log) {
|
4799
5021
|
return function(exception, cause) {
|
4800
5022
|
$log.error.apply($log, arguments);
|
4801
5023
|
};
|
@@ -5560,6 +5782,10 @@ function $LocationProvider(){
|
|
5560
5782
|
// update $location when $browser url changes
|
5561
5783
|
$browser.onUrlChange(function(newUrl) {
|
5562
5784
|
if ($location.absUrl() != newUrl) {
|
5785
|
+
if ($rootScope.$broadcast('$locationChangeStart', newUrl, $location.absUrl()).defaultPrevented) {
|
5786
|
+
$browser.url($location.absUrl());
|
5787
|
+
return;
|
5788
|
+
}
|
5563
5789
|
$rootScope.$evalAsync(function() {
|
5564
5790
|
var oldUrl = $location.absUrl();
|
5565
5791
|
|
@@ -5868,10 +6094,10 @@ function lex(text, csp){
|
|
5868
6094
|
function readIdent() {
|
5869
6095
|
var ident = "",
|
5870
6096
|
start = index,
|
5871
|
-
lastDot, peekIndex, methodName;
|
6097
|
+
lastDot, peekIndex, methodName, ch;
|
5872
6098
|
|
5873
6099
|
while (index < text.length) {
|
5874
|
-
|
6100
|
+
ch = text.charAt(index);
|
5875
6101
|
if (ch == '.' || isIdent(ch) || isNumber(ch)) {
|
5876
6102
|
if (ch == '.') lastDot = index;
|
5877
6103
|
ident += ch;
|
@@ -5885,7 +6111,7 @@ function lex(text, csp){
|
|
5885
6111
|
if (lastDot) {
|
5886
6112
|
peekIndex = index;
|
5887
6113
|
while(peekIndex < text.length) {
|
5888
|
-
|
6114
|
+
ch = text.charAt(peekIndex);
|
5889
6115
|
if (ch == '(') {
|
5890
6116
|
methodName = ident.substr(lastDot - start + 1);
|
5891
6117
|
ident = ident.substr(0, lastDot - start);
|
@@ -6138,8 +6364,8 @@ function parser(text, json, $filter, csp){
|
|
6138
6364
|
text.substring(0, token.index) + "] can not be assigned to", token);
|
6139
6365
|
}
|
6140
6366
|
right = logicalOR();
|
6141
|
-
return function(
|
6142
|
-
return left.assign(
|
6367
|
+
return function(scope, locals){
|
6368
|
+
return left.assign(scope, right(scope, locals), locals);
|
6143
6369
|
};
|
6144
6370
|
} else {
|
6145
6371
|
return left;
|
@@ -6256,12 +6482,12 @@ function parser(text, json, $filter, csp){
|
|
6256
6482
|
var field = expect().text;
|
6257
6483
|
var getter = getterFn(field, csp);
|
6258
6484
|
return extend(
|
6259
|
-
function(
|
6260
|
-
return getter(object(
|
6485
|
+
function(scope, locals, self) {
|
6486
|
+
return getter(self || object(scope, locals), locals);
|
6261
6487
|
},
|
6262
6488
|
{
|
6263
|
-
assign:function(
|
6264
|
-
return setter(object(
|
6489
|
+
assign:function(scope, value, locals) {
|
6490
|
+
return setter(object(scope, locals), field, value);
|
6265
6491
|
}
|
6266
6492
|
}
|
6267
6493
|
);
|
@@ -6302,14 +6528,14 @@ function parser(text, json, $filter, csp){
|
|
6302
6528
|
} while (expect(','));
|
6303
6529
|
}
|
6304
6530
|
consume(')');
|
6305
|
-
return function(
|
6531
|
+
return function(scope, locals){
|
6306
6532
|
var args = [],
|
6307
|
-
context = contextGetter ? contextGetter(
|
6533
|
+
context = contextGetter ? contextGetter(scope, locals) : scope;
|
6308
6534
|
|
6309
6535
|
for ( var i = 0; i < argsFn.length; i++) {
|
6310
|
-
args.push(argsFn[i](
|
6536
|
+
args.push(argsFn[i](scope, locals));
|
6311
6537
|
}
|
6312
|
-
var fnPtr = fn(
|
6538
|
+
var fnPtr = fn(scope, locals, context) || noop;
|
6313
6539
|
// IE stupidity!
|
6314
6540
|
return fnPtr.apply
|
6315
6541
|
? fnPtr.apply(context, args)
|
@@ -6351,8 +6577,7 @@ function parser(text, json, $filter, csp){
|
|
6351
6577
|
var object = {};
|
6352
6578
|
for ( var i = 0; i < keyValues.length; i++) {
|
6353
6579
|
var keyValue = keyValues[i];
|
6354
|
-
|
6355
|
-
object[keyValue.key] = value;
|
6580
|
+
object[keyValue.key] = keyValue.value(self, locals);
|
6356
6581
|
}
|
6357
6582
|
return object;
|
6358
6583
|
};
|
@@ -6378,33 +6603,6 @@ function setter(obj, path, setValue) {
|
|
6378
6603
|
return setValue;
|
6379
6604
|
}
|
6380
6605
|
|
6381
|
-
/**
|
6382
|
-
* Return the value accesible from the object by path. Any undefined traversals are ignored
|
6383
|
-
* @param {Object} obj starting object
|
6384
|
-
* @param {string} path path to traverse
|
6385
|
-
* @param {boolean=true} bindFnToScope
|
6386
|
-
* @returns value as accesbile by path
|
6387
|
-
*/
|
6388
|
-
//TODO(misko): this function needs to be removed
|
6389
|
-
function getter(obj, path, bindFnToScope) {
|
6390
|
-
if (!path) return obj;
|
6391
|
-
var keys = path.split('.');
|
6392
|
-
var key;
|
6393
|
-
var lastInstance = obj;
|
6394
|
-
var len = keys.length;
|
6395
|
-
|
6396
|
-
for (var i = 0; i < len; i++) {
|
6397
|
-
key = keys[i];
|
6398
|
-
if (obj) {
|
6399
|
-
obj = (lastInstance = obj)[key];
|
6400
|
-
}
|
6401
|
-
}
|
6402
|
-
if (!bindFnToScope && isFunction(obj)) {
|
6403
|
-
return bind(lastInstance, obj);
|
6404
|
-
}
|
6405
|
-
return obj;
|
6406
|
-
}
|
6407
|
-
|
6408
6606
|
var getterFnCache = {};
|
6409
6607
|
|
6410
6608
|
/**
|
@@ -6474,7 +6672,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4) {
|
|
6474
6672
|
}
|
6475
6673
|
return pathVal;
|
6476
6674
|
};
|
6477
|
-
}
|
6675
|
+
}
|
6478
6676
|
|
6479
6677
|
function getterFn(path, csp) {
|
6480
6678
|
if (getterFnCache.hasOwnProperty(path)) {
|
@@ -6489,7 +6687,7 @@ function getterFn(path, csp) {
|
|
6489
6687
|
fn = (pathKeysLength < 6)
|
6490
6688
|
? cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4])
|
6491
6689
|
: function(scope, locals) {
|
6492
|
-
var i = 0, val
|
6690
|
+
var i = 0, val;
|
6493
6691
|
do {
|
6494
6692
|
val = cspSafeGetterFn(
|
6495
6693
|
pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++]
|
@@ -6666,8 +6864,8 @@ function $ParseProvider() {
|
|
6666
6864
|
* **Methods**
|
6667
6865
|
*
|
6668
6866
|
* - `then(successCallback, errorCallback)` – regardless of when the promise was or will be resolved
|
6669
|
-
* or rejected calls one of the success or error callbacks asynchronously as soon as the result
|
6670
|
-
* is available. The callbacks are called with a single argument the result or rejection reason.
|
6867
|
+
* or rejected, `then` calls one of the success or error callbacks asynchronously as soon as the result
|
6868
|
+
* is available. The callbacks are called with a single argument: the result or rejection reason.
|
6671
6869
|
*
|
6672
6870
|
* This method *returns a new promise* which is resolved or rejected via the return value of the
|
6673
6871
|
* `successCallback` or `errorCallback`.
|
@@ -6675,7 +6873,7 @@ function $ParseProvider() {
|
|
6675
6873
|
*
|
6676
6874
|
* # Chaining promises
|
6677
6875
|
*
|
6678
|
-
* Because calling `then`
|
6876
|
+
* Because calling the `then` method of a promise returns a new derived promise, it is easily possible
|
6679
6877
|
* to create a chain of promises:
|
6680
6878
|
*
|
6681
6879
|
* <pre>
|
@@ -6683,13 +6881,13 @@ function $ParseProvider() {
|
|
6683
6881
|
* return result + 1;
|
6684
6882
|
* });
|
6685
6883
|
*
|
6686
|
-
* // promiseB will be resolved immediately after promiseA is resolved and its value
|
6687
|
-
* // the result of promiseA incremented by 1
|
6884
|
+
* // promiseB will be resolved immediately after promiseA is resolved and its value
|
6885
|
+
* // will be the result of promiseA incremented by 1
|
6688
6886
|
* </pre>
|
6689
6887
|
*
|
6690
6888
|
* It is possible to create chains of any length and since a promise can be resolved with another
|
6691
6889
|
* promise (which will defer its resolution further), it is possible to pause/defer resolution of
|
6692
|
-
* the promises at any point in the chain. This makes it possible to implement powerful
|
6890
|
+
* the promises at any point in the chain. This makes it possible to implement powerful APIs like
|
6693
6891
|
* $http's response interceptors.
|
6694
6892
|
*
|
6695
6893
|
*
|
@@ -6702,7 +6900,7 @@ function $ParseProvider() {
|
|
6702
6900
|
* models and avoiding unnecessary browser repaints, which would result in flickering UI.
|
6703
6901
|
* - $q promises are recognized by the templating engine in angular, which means that in templates
|
6704
6902
|
* you can treat promises attached to a scope as if they were the resulting values.
|
6705
|
-
* - Q has many more features
|
6903
|
+
* - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
|
6706
6904
|
* all the important functionality needed for common async tasks.
|
6707
6905
|
*
|
6708
6906
|
* # Testing
|
@@ -6796,8 +6994,8 @@ function qFactory(nextTick, exceptionHandler) {
|
|
6796
6994
|
try {
|
6797
6995
|
result.resolve((callback || defaultCallback)(value));
|
6798
6996
|
} catch(e) {
|
6799
|
-
exceptionHandler(e);
|
6800
6997
|
result.reject(e);
|
6998
|
+
exceptionHandler(e);
|
6801
6999
|
}
|
6802
7000
|
};
|
6803
7001
|
|
@@ -6805,8 +7003,8 @@ function qFactory(nextTick, exceptionHandler) {
|
|
6805
7003
|
try {
|
6806
7004
|
result.resolve((errback || defaultErrback)(reason));
|
6807
7005
|
} catch(e) {
|
6808
|
-
exceptionHandler(e);
|
6809
7006
|
result.reject(e);
|
7007
|
+
exceptionHandler(e);
|
6810
7008
|
}
|
6811
7009
|
};
|
6812
7010
|
|
@@ -6897,10 +7095,7 @@ function qFactory(nextTick, exceptionHandler) {
|
|
6897
7095
|
* the promise comes from a source that can't be trusted.
|
6898
7096
|
*
|
6899
7097
|
* @param {*} value Value or a promise
|
6900
|
-
* @returns {Promise} Returns a
|
6901
|
-
* each value corresponding to the promise at the same index in the `promises` array. If any of
|
6902
|
-
* the promises is resolved with a rejection, this resulting promise will be resolved with the
|
6903
|
-
* same rejection.
|
7098
|
+
* @returns {Promise} Returns a promise of the passed value or promise
|
6904
7099
|
*/
|
6905
7100
|
var when = function(value, callback, errback) {
|
6906
7101
|
var result = defer(),
|
@@ -7018,8 +7213,8 @@ function $RouteProvider(){
|
|
7018
7213
|
* route definition.
|
7019
7214
|
*
|
7020
7215
|
* `path` can contain named groups starting with a colon (`:name`). All characters up to the
|
7021
|
-
* next slash are matched and stored in `$routeParams` under the given `name`
|
7022
|
-
*
|
7216
|
+
* next slash are matched and stored in `$routeParams` under the given `name` after the route
|
7217
|
+
* is resolved.
|
7023
7218
|
*
|
7024
7219
|
* @param {Object} route Mapping information to be assigned to `$route.current` on route
|
7025
7220
|
* match.
|
@@ -7044,7 +7239,9 @@ function $RouteProvider(){
|
|
7044
7239
|
* - `factory` - `{string|function}`: If `string` then it is an alias for a service.
|
7045
7240
|
* Otherwise if function, then it is {@link api/AUTO.$injector#invoke injected}
|
7046
7241
|
* and the return value is treated as the dependency. If the result is a promise, it is resolved
|
7047
|
-
* before its value is injected into the controller.
|
7242
|
+
* before its value is injected into the controller. Be aware that `ngRoute.$routeParams` will
|
7243
|
+
* still refer to the previous route within these resolve functions. Use `$route.current.params`
|
7244
|
+
* to access the new route parameters, instead.
|
7048
7245
|
*
|
7049
7246
|
* - `redirectTo` – {(string|function())=} – value to update
|
7050
7247
|
* {@link ng.$location $location} path with and trigger route redirection.
|
@@ -7479,6 +7676,10 @@ function $RouteProvider(){
|
|
7479
7676
|
* The service guarantees that the identity of the `$routeParams` object will remain unchanged
|
7480
7677
|
* (but its properties will likely change) even when a route change occurs.
|
7481
7678
|
*
|
7679
|
+
* Note that the `$routeParams` are only updated *after* a route change completes successfully.
|
7680
|
+
* This means that you cannot rely on `$routeParams` being correct in route resolve functions.
|
7681
|
+
* Instead you can use `$route.current.params` to access the new route's parameters.
|
7682
|
+
*
|
7482
7683
|
* @example
|
7483
7684
|
* <pre>
|
7484
7685
|
* // Given:
|
@@ -7496,22 +7697,22 @@ function $RouteParamsProvider() {
|
|
7496
7697
|
/**
|
7497
7698
|
* DESIGN NOTES
|
7498
7699
|
*
|
7499
|
-
* The design decisions behind the scope
|
7700
|
+
* The design decisions behind the scope are heavily favored for speed and memory consumption.
|
7500
7701
|
*
|
7501
7702
|
* The typical use of scope is to watch the expressions, which most of the time return the same
|
7502
7703
|
* value as last time so we optimize the operation.
|
7503
7704
|
*
|
7504
|
-
* Closures construction is expensive
|
7505
|
-
* -
|
7705
|
+
* Closures construction is expensive in terms of speed as well as memory:
|
7706
|
+
* - No closures, instead use prototypical inheritance for API
|
7506
7707
|
* - Internal state needs to be stored on scope directly, which means that private state is
|
7507
7708
|
* exposed as $$____ properties
|
7508
7709
|
*
|
7509
7710
|
* Loop operations are optimized by using while(count--) { ... }
|
7510
7711
|
* - this means that in order to keep the same order of execution as addition we have to add
|
7511
|
-
* items to the array at the
|
7712
|
+
* items to the array at the beginning (shift) instead of at the end (push)
|
7512
7713
|
*
|
7513
7714
|
* Child scopes are created and removed often
|
7514
|
-
* - Using array would be slow since inserts in
|
7715
|
+
* - Using an array would be slow since inserts in middle are expensive so we use linked list
|
7515
7716
|
*
|
7516
7717
|
* There are few watches then a lot of observers. This is why you don't want the observer to be
|
7517
7718
|
* implemented in the same way as watch. Watch requires return of initialization function which
|
@@ -7533,7 +7734,7 @@ function $RouteParamsProvider() {
|
|
7533
7734
|
* @methodOf ng.$rootScopeProvider
|
7534
7735
|
* @description
|
7535
7736
|
*
|
7536
|
-
* Sets the number of digest
|
7737
|
+
* Sets the number of digest iterations the scope should attempt to execute before giving up and
|
7537
7738
|
* assuming that the model is unstable.
|
7538
7739
|
*
|
7539
7740
|
* The current default is 10 iterations.
|
@@ -7813,7 +8014,7 @@ function $RootScopeProvider(){
|
|
7813
8014
|
* @function
|
7814
8015
|
*
|
7815
8016
|
* @description
|
7816
|
-
*
|
8017
|
+
* Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and its children.
|
7817
8018
|
* Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change the model, the
|
7818
8019
|
* `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers} until no more listeners are
|
7819
8020
|
* firing. This means that it is possible to get into an infinite loop. This function will throw
|
@@ -7886,7 +8087,7 @@ function $RootScopeProvider(){
|
|
7886
8087
|
watch = watchers[length];
|
7887
8088
|
// Most common watches are on primitives, in which case we can short
|
7888
8089
|
// circuit it with === operator, only when === fails do we use .equals
|
7889
|
-
if ((value = watch.get(current)) !== (last = watch.last) &&
|
8090
|
+
if (watch && (value = watch.get(current)) !== (last = watch.last) &&
|
7890
8091
|
!(watch.eq
|
7891
8092
|
? equals(value, last)
|
7892
8093
|
: (typeof value == 'number' && typeof last == 'number'
|
@@ -7939,6 +8140,9 @@ function $RootScopeProvider(){
|
|
7939
8140
|
*
|
7940
8141
|
* @description
|
7941
8142
|
* Broadcasted when a scope and its children are being destroyed.
|
8143
|
+
*
|
8144
|
+
* Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
|
8145
|
+
* clean up DOM bindings before an element is removed from the DOM.
|
7942
8146
|
*/
|
7943
8147
|
|
7944
8148
|
/**
|
@@ -7960,6 +8164,9 @@ function $RootScopeProvider(){
|
|
7960
8164
|
* Just before a scope is destroyed a `$destroy` event is broadcasted on this scope.
|
7961
8165
|
* Application code can register a `$destroy` event handler that will give it chance to
|
7962
8166
|
* perform any necessary cleanup.
|
8167
|
+
*
|
8168
|
+
* Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
|
8169
|
+
* clean up DOM bindings before an element is removed from the DOM.
|
7963
8170
|
*/
|
7964
8171
|
$destroy: function() {
|
7965
8172
|
// we can't destroy the root scope or a scope that has been already destroyed
|
@@ -8155,7 +8362,7 @@ function $RootScopeProvider(){
|
|
8155
8362
|
* Afterwards, the event traverses upwards toward the root scope and calls all registered
|
8156
8363
|
* listeners along the way. The event will stop propagating if one of the listeners cancels it.
|
8157
8364
|
*
|
8158
|
-
* Any exception
|
8365
|
+
* Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
|
8159
8366
|
* onto the {@link ng.$exceptionHandler $exceptionHandler} service.
|
8160
8367
|
*
|
8161
8368
|
* @param {string} name Event name to emit.
|
@@ -8224,7 +8431,7 @@ function $RootScopeProvider(){
|
|
8224
8431
|
* Any exception emmited from the {@link ng.$rootScope.Scope#$on listeners} will be passed
|
8225
8432
|
* onto the {@link ng.$exceptionHandler $exceptionHandler} service.
|
8226
8433
|
*
|
8227
|
-
* @param {string} name Event name to
|
8434
|
+
* @param {string} name Event name to broadcast.
|
8228
8435
|
* @param {...*} args Optional set of arguments which will be passed onto the event listeners.
|
8229
8436
|
* @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
|
8230
8437
|
*/
|
@@ -8364,16 +8571,31 @@ function $SnifferProvider() {
|
|
8364
8571
|
* it is a global variable. In angular we always refer to it through the
|
8365
8572
|
* `$window` service, so it may be overriden, removed or mocked for testing.
|
8366
8573
|
*
|
8367
|
-
*
|
8368
|
-
*
|
8574
|
+
* Expressions, like the one defined for the `ngClick` directive in the example
|
8575
|
+
* below, are evaluated with respect to the current scope. Therefore, there is
|
8576
|
+
* no risk of inadvertently coding in a dependency on a global value in such an
|
8577
|
+
* expression.
|
8369
8578
|
*
|
8370
8579
|
* @example
|
8371
8580
|
<doc:example>
|
8372
8581
|
<doc:source>
|
8373
|
-
<
|
8374
|
-
|
8582
|
+
<script>
|
8583
|
+
function Ctrl($scope, $window) {
|
8584
|
+
$scope.$window = $window;
|
8585
|
+
$scope.greeting = 'Hello, World!';
|
8586
|
+
}
|
8587
|
+
</script>
|
8588
|
+
<div ng-controller="Ctrl">
|
8589
|
+
<input type="text" ng-model="greeting" />
|
8590
|
+
<button ng-click="$window.alert(greeting)">ALERT</button>
|
8591
|
+
</div>
|
8375
8592
|
</doc:source>
|
8376
8593
|
<doc:scenario>
|
8594
|
+
it('should display the greeting in the input box', function() {
|
8595
|
+
input('greeting').enter('Hello, E2E Tests');
|
8596
|
+
// If we click the button it will block the test runner
|
8597
|
+
// element(':button').click();
|
8598
|
+
});
|
8377
8599
|
</doc:scenario>
|
8378
8600
|
</doc:example>
|
8379
8601
|
*/
|
@@ -8526,7 +8748,7 @@ function $HttpProvider() {
|
|
8526
8748
|
*
|
8527
8749
|
* @description
|
8528
8750
|
* The `$http` service is a core Angular service that facilitates communication with the remote
|
8529
|
-
* HTTP servers via browser's {@link https://developer.mozilla.org/en/xmlhttprequest
|
8751
|
+
* HTTP servers via the browser's {@link https://developer.mozilla.org/en/xmlhttprequest
|
8530
8752
|
* XMLHttpRequest} object or via {@link http://en.wikipedia.org/wiki/JSONP JSONP}.
|
8531
8753
|
*
|
8532
8754
|
* For unit testing applications that use `$http` service, see
|
@@ -8536,13 +8758,13 @@ function $HttpProvider() {
|
|
8536
8758
|
* $resource} service.
|
8537
8759
|
*
|
8538
8760
|
* The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
|
8539
|
-
* the $q service. While for simple usage
|
8540
|
-
* it is important to familiarize yourself with these
|
8761
|
+
* the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
|
8762
|
+
* it is important to familiarize yourself with these APIs and the guarantees they provide.
|
8541
8763
|
*
|
8542
8764
|
*
|
8543
8765
|
* # General usage
|
8544
8766
|
* The `$http` service is a function which takes a single argument — a configuration object —
|
8545
|
-
* that is used to generate an
|
8767
|
+
* that is used to generate an HTTP request and returns a {@link ng.$q promise}
|
8546
8768
|
* with two $http specific methods: `success` and `error`.
|
8547
8769
|
*
|
8548
8770
|
* <pre>
|
@@ -8557,21 +8779,21 @@ function $HttpProvider() {
|
|
8557
8779
|
* });
|
8558
8780
|
* </pre>
|
8559
8781
|
*
|
8560
|
-
* Since the returned value of calling the $http function is a
|
8782
|
+
* Since the returned value of calling the $http function is a `promise`, you can also use
|
8561
8783
|
* the `then` method to register callbacks, and these callbacks will receive a single argument –
|
8562
|
-
* an object representing the response. See the
|
8784
|
+
* an object representing the response. See the API signature and type info below for more
|
8563
8785
|
* details.
|
8564
8786
|
*
|
8565
|
-
* A response status code
|
8787
|
+
* A response status code between 200 and 299 is considered a success status and
|
8566
8788
|
* will result in the success callback being called. Note that if the response is a redirect,
|
8567
8789
|
* XMLHttpRequest will transparently follow it, meaning that the error callback will not be
|
8568
8790
|
* called for such responses.
|
8569
8791
|
*
|
8570
8792
|
* # Shortcut methods
|
8571
8793
|
*
|
8572
|
-
* Since all
|
8573
|
-
* POST
|
8574
|
-
* were created
|
8794
|
+
* Since all invocations of the $http service require passing in an HTTP method and URL, and
|
8795
|
+
* POST/PUT requests require request data to be provided as well, shortcut methods
|
8796
|
+
* were created:
|
8575
8797
|
*
|
8576
8798
|
* <pre>
|
8577
8799
|
* $http.get('/someUrl').success(successCallback);
|
@@ -8590,25 +8812,25 @@ function $HttpProvider() {
|
|
8590
8812
|
*
|
8591
8813
|
* # Setting HTTP Headers
|
8592
8814
|
*
|
8593
|
-
* The $http service will automatically add certain
|
8815
|
+
* The $http service will automatically add certain HTTP headers to all requests. These defaults
|
8594
8816
|
* can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
|
8595
8817
|
* object, which currently contains this default configuration:
|
8596
8818
|
*
|
8597
8819
|
* - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
|
8598
8820
|
* - `Accept: application/json, text/plain, * / *`
|
8599
8821
|
* - `X-Requested-With: XMLHttpRequest`
|
8600
|
-
* - `$httpProvider.defaults.headers.post`: (header defaults for
|
8822
|
+
* - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
|
8601
8823
|
* - `Content-Type: application/json`
|
8602
|
-
* - `$httpProvider.defaults.headers.put` (header defaults for
|
8824
|
+
* - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
|
8603
8825
|
* - `Content-Type: application/json`
|
8604
8826
|
*
|
8605
|
-
* To add or overwrite these defaults, simply add or remove a property from
|
8827
|
+
* To add or overwrite these defaults, simply add or remove a property from these configuration
|
8606
8828
|
* objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
|
8607
|
-
* with
|
8829
|
+
* with the lowercased HTTP method name as the key, e.g.
|
8608
8830
|
* `$httpProvider.defaults.headers.get['My-Header']='value'`.
|
8609
8831
|
*
|
8610
|
-
* Additionally, the defaults can be set at runtime via the `$http.defaults` object in
|
8611
|
-
*
|
8832
|
+
* Additionally, the defaults can be set at runtime via the `$http.defaults` object in the same
|
8833
|
+
* fashion.
|
8612
8834
|
*
|
8613
8835
|
*
|
8614
8836
|
* # Transforming Requests and Responses
|
@@ -8618,36 +8840,36 @@ function $HttpProvider() {
|
|
8618
8840
|
*
|
8619
8841
|
* Request transformations:
|
8620
8842
|
*
|
8621
|
-
* -
|
8843
|
+
* - If the `data` property of the request configuration object contains an object, serialize it into
|
8622
8844
|
* JSON format.
|
8623
8845
|
*
|
8624
8846
|
* Response transformations:
|
8625
8847
|
*
|
8626
|
-
* -
|
8627
|
-
* -
|
8848
|
+
* - If XSRF prefix is detected, strip it (see Security Considerations section below).
|
8849
|
+
* - If JSON response is detected, deserialize it using a JSON parser.
|
8628
8850
|
*
|
8629
8851
|
* To globally augment or override the default transforms, modify the `$httpProvider.defaults.transformRequest` and
|
8630
|
-
* `$httpProvider.defaults.transformResponse` properties
|
8852
|
+
* `$httpProvider.defaults.transformResponse` properties. These properties are by default an
|
8631
8853
|
* array of transform functions, which allows you to `push` or `unshift` a new transformation function into the
|
8632
8854
|
* transformation chain. You can also decide to completely override any default transformations by assigning your
|
8633
8855
|
* transformation functions to these properties directly without the array wrapper.
|
8634
8856
|
*
|
8635
8857
|
* Similarly, to locally override the request/response transforms, augment the `transformRequest` and/or
|
8636
|
-
* `transformResponse` properties of the
|
8858
|
+
* `transformResponse` properties of the configuration object passed into `$http`.
|
8637
8859
|
*
|
8638
8860
|
*
|
8639
8861
|
* # Caching
|
8640
8862
|
*
|
8641
|
-
* To enable caching set the configuration property `cache` to `true`. When the cache is
|
8863
|
+
* To enable caching, set the configuration property `cache` to `true`. When the cache is
|
8642
8864
|
* enabled, `$http` stores the response from the server in local cache. Next time the
|
8643
8865
|
* response is served from the cache without sending a request to the server.
|
8644
8866
|
*
|
8645
8867
|
* Note that even if the response is served from cache, delivery of the data is asynchronous in
|
8646
8868
|
* the same way that real requests are.
|
8647
8869
|
*
|
8648
|
-
* If there are multiple GET requests for the same
|
8870
|
+
* If there are multiple GET requests for the same URL that should be cached using the same
|
8649
8871
|
* cache, but the cache is not populated yet, only one request to the server will be made and
|
8650
|
-
* the remaining requests will be fulfilled using the response
|
8872
|
+
* the remaining requests will be fulfilled using the response from the first request.
|
8651
8873
|
*
|
8652
8874
|
*
|
8653
8875
|
* # Response interceptors
|
@@ -8672,6 +8894,7 @@ function $HttpProvider() {
|
|
8672
8894
|
* return function(promise) {
|
8673
8895
|
* return promise.then(function(response) {
|
8674
8896
|
* // do something on success
|
8897
|
+
* return response;
|
8675
8898
|
* }, function(response) {
|
8676
8899
|
* // do something on error
|
8677
8900
|
* if (canRecover(response)) {
|
@@ -8699,7 +8922,7 @@ function $HttpProvider() {
|
|
8699
8922
|
* When designing web applications, consider security threats from:
|
8700
8923
|
*
|
8701
8924
|
* - {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
|
8702
|
-
* JSON
|
8925
|
+
* JSON vulnerability}
|
8703
8926
|
* - {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF}
|
8704
8927
|
*
|
8705
8928
|
* Both server and the client must cooperate in order to eliminate these threats. Angular comes
|
@@ -8709,8 +8932,8 @@ function $HttpProvider() {
|
|
8709
8932
|
* ## JSON Vulnerability Protection
|
8710
8933
|
*
|
8711
8934
|
* A {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
|
8712
|
-
* JSON
|
8713
|
-
* {@link http://en.wikipedia.org/wiki/
|
8935
|
+
* JSON vulnerability} allows third party website to turn your JSON resource URL into
|
8936
|
+
* {@link http://en.wikipedia.org/wiki/JSONP JSONP} request under some conditions. To
|
8714
8937
|
* counter this your server can prefix all JSON requests with following string `")]}',\n"`.
|
8715
8938
|
* Angular will automatically strip the prefix before processing it as JSON.
|
8716
8939
|
*
|
@@ -8731,19 +8954,19 @@ function $HttpProvider() {
|
|
8731
8954
|
* ## Cross Site Request Forgery (XSRF) Protection
|
8732
8955
|
*
|
8733
8956
|
* {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} is a technique by which
|
8734
|
-
* an unauthorized site can gain your user's private data. Angular provides
|
8957
|
+
* an unauthorized site can gain your user's private data. Angular provides a mechanism
|
8735
8958
|
* to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
|
8736
8959
|
* called `XSRF-TOKEN` and sets it as the HTTP header `X-XSRF-TOKEN`. Since only JavaScript that
|
8737
8960
|
* runs on your domain could read the cookie, your server can be assured that the XHR came from
|
8738
8961
|
* JavaScript running on your domain.
|
8739
8962
|
*
|
8740
8963
|
* To take advantage of this, your server needs to set a token in a JavaScript readable session
|
8741
|
-
* cookie called `XSRF-TOKEN` on first HTTP GET request. On subsequent
|
8964
|
+
* cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
|
8742
8965
|
* server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
|
8743
|
-
* that only JavaScript running on your domain could have
|
8744
|
-
* unique for each user and must be verifiable by the server (to prevent the JavaScript making
|
8966
|
+
* that only JavaScript running on your domain could have sent the request. The token must be
|
8967
|
+
* unique for each user and must be verifiable by the server (to prevent the JavaScript from making
|
8745
8968
|
* up its own tokens). We recommend that the token is a digest of your site's authentication
|
8746
|
-
* cookie with {@link
|
8969
|
+
* cookie with a {@link https://en.wikipedia.org/wiki/Salt_(cryptography) salt} for added security.
|
8747
8970
|
*
|
8748
8971
|
*
|
8749
8972
|
* @param {object} config Object describing the request to be made and how it should be
|
@@ -8863,17 +9086,40 @@ function $HttpProvider() {
|
|
8863
9086
|
|
8864
9087
|
var reqTransformFn = config.transformRequest || $config.transformRequest,
|
8865
9088
|
respTransformFn = config.transformResponse || $config.transformResponse,
|
8866
|
-
|
8867
|
-
|
8868
|
-
|
8869
|
-
|
9089
|
+
reqHeaders = extend({}, config.headers),
|
9090
|
+
defHeaders = extend(
|
9091
|
+
{'X-XSRF-TOKEN': $browser.cookies()['XSRF-TOKEN']},
|
9092
|
+
$config.headers.common,
|
9093
|
+
$config.headers[lowercase(config.method)]
|
9094
|
+
),
|
9095
|
+
reqData,
|
9096
|
+
defHeaderName, lowercaseDefHeaderName, headerName,
|
8870
9097
|
promise;
|
8871
9098
|
|
9099
|
+
// using for-in instead of forEach to avoid unecessary iteration after header has been found
|
9100
|
+
defaultHeadersIteration:
|
9101
|
+
for(defHeaderName in defHeaders) {
|
9102
|
+
lowercaseDefHeaderName = lowercase(defHeaderName);
|
9103
|
+
for(headerName in config.headers) {
|
9104
|
+
if (lowercase(headerName) === lowercaseDefHeaderName) {
|
9105
|
+
continue defaultHeadersIteration;
|
9106
|
+
}
|
9107
|
+
}
|
9108
|
+
reqHeaders[defHeaderName] = defHeaders[defHeaderName];
|
9109
|
+
}
|
9110
|
+
|
8872
9111
|
// strip content-type if data is undefined
|
8873
9112
|
if (isUndefined(config.data)) {
|
8874
|
-
|
9113
|
+
for(var header in reqHeaders) {
|
9114
|
+
if (lowercase(header) === 'content-type') {
|
9115
|
+
delete reqHeaders[header];
|
9116
|
+
break;
|
9117
|
+
}
|
9118
|
+
}
|
8875
9119
|
}
|
8876
9120
|
|
9121
|
+
reqData = transformData(config.data, headersGetter(reqHeaders), reqTransformFn);
|
9122
|
+
|
8877
9123
|
// send request
|
8878
9124
|
promise = sendReq(config, reqData, reqHeaders);
|
8879
9125
|
|
@@ -8921,7 +9167,7 @@ function $HttpProvider() {
|
|
8921
9167
|
* @methodOf ng.$http
|
8922
9168
|
*
|
8923
9169
|
* @description
|
8924
|
-
* Shortcut method to perform `GET` request
|
9170
|
+
* Shortcut method to perform `GET` request.
|
8925
9171
|
*
|
8926
9172
|
* @param {string} url Relative or absolute URL specifying the destination of the request
|
8927
9173
|
* @param {Object=} config Optional configuration object
|
@@ -8934,7 +9180,7 @@ function $HttpProvider() {
|
|
8934
9180
|
* @methodOf ng.$http
|
8935
9181
|
*
|
8936
9182
|
* @description
|
8937
|
-
* Shortcut method to perform `DELETE` request
|
9183
|
+
* Shortcut method to perform `DELETE` request.
|
8938
9184
|
*
|
8939
9185
|
* @param {string} url Relative or absolute URL specifying the destination of the request
|
8940
9186
|
* @param {Object=} config Optional configuration object
|
@@ -8947,7 +9193,7 @@ function $HttpProvider() {
|
|
8947
9193
|
* @methodOf ng.$http
|
8948
9194
|
*
|
8949
9195
|
* @description
|
8950
|
-
* Shortcut method to perform `HEAD` request
|
9196
|
+
* Shortcut method to perform `HEAD` request.
|
8951
9197
|
*
|
8952
9198
|
* @param {string} url Relative or absolute URL specifying the destination of the request
|
8953
9199
|
* @param {Object=} config Optional configuration object
|
@@ -8960,7 +9206,7 @@ function $HttpProvider() {
|
|
8960
9206
|
* @methodOf ng.$http
|
8961
9207
|
*
|
8962
9208
|
* @description
|
8963
|
-
* Shortcut method to perform `JSONP` request
|
9209
|
+
* Shortcut method to perform `JSONP` request.
|
8964
9210
|
*
|
8965
9211
|
* @param {string} url Relative or absolute URL specifying the destination of the request.
|
8966
9212
|
* Should contain `JSON_CALLBACK` string.
|
@@ -8975,7 +9221,7 @@ function $HttpProvider() {
|
|
8975
9221
|
* @methodOf ng.$http
|
8976
9222
|
*
|
8977
9223
|
* @description
|
8978
|
-
* Shortcut method to perform `POST` request
|
9224
|
+
* Shortcut method to perform `POST` request.
|
8979
9225
|
*
|
8980
9226
|
* @param {string} url Relative or absolute URL specifying the destination of the request
|
8981
9227
|
* @param {*} data Request content
|
@@ -8989,7 +9235,7 @@ function $HttpProvider() {
|
|
8989
9235
|
* @methodOf ng.$http
|
8990
9236
|
*
|
8991
9237
|
* @description
|
8992
|
-
* Shortcut method to perform `PUT` request
|
9238
|
+
* Shortcut method to perform `PUT` request.
|
8993
9239
|
*
|
8994
9240
|
* @param {string} url Relative or absolute URL specifying the destination of the request
|
8995
9241
|
* @param {*} data Request content
|
@@ -9041,7 +9287,7 @@ function $HttpProvider() {
|
|
9041
9287
|
|
9042
9288
|
|
9043
9289
|
/**
|
9044
|
-
* Makes the request
|
9290
|
+
* Makes the request.
|
9045
9291
|
*
|
9046
9292
|
* !!! ACCESSES CLOSURE VARS:
|
9047
9293
|
* $httpBackend, $config, $log, $rootScope, defaultCache, $http.pendingRequests
|
@@ -9388,17 +9634,17 @@ function $TimeoutProvider() {
|
|
9388
9634
|
* block and delegates any exceptions to
|
9389
9635
|
* {@link ng.$exceptionHandler $exceptionHandler} service.
|
9390
9636
|
*
|
9391
|
-
* The return value of registering a timeout function is a promise which will be resolved when
|
9637
|
+
* The return value of registering a timeout function is a promise, which will be resolved when
|
9392
9638
|
* the timeout is reached and the timeout function is executed.
|
9393
9639
|
*
|
9394
|
-
* To cancel a
|
9640
|
+
* To cancel a timeout request, call `$timeout.cancel(promise)`.
|
9395
9641
|
*
|
9396
9642
|
* In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
|
9397
9643
|
* synchronously flush the queue of deferred functions.
|
9398
9644
|
*
|
9399
|
-
* @param {function()} fn A function,
|
9645
|
+
* @param {function()} fn A function, whose execution should be delayed.
|
9400
9646
|
* @param {number=} [delay=0] Delay in milliseconds.
|
9401
|
-
* @param {boolean=} [invokeApply=true] If set to false skips model dirty checking, otherwise
|
9647
|
+
* @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
|
9402
9648
|
* will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
|
9403
9649
|
* @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
|
9404
9650
|
* promise will be resolved with is the return value of the `fn` function.
|
@@ -9416,17 +9662,15 @@ function $TimeoutProvider() {
|
|
9416
9662
|
deferred.reject(e);
|
9417
9663
|
$exceptionHandler(e);
|
9418
9664
|
}
|
9665
|
+
finally {
|
9666
|
+
delete deferreds[promise.$$timeoutId];
|
9667
|
+
}
|
9419
9668
|
|
9420
9669
|
if (!skipApply) $rootScope.$apply();
|
9421
9670
|
}, delay);
|
9422
9671
|
|
9423
|
-
cleanup = function() {
|
9424
|
-
delete deferreds[promise.$$timeoutId];
|
9425
|
-
};
|
9426
|
-
|
9427
9672
|
promise.$$timeoutId = timeoutId;
|
9428
9673
|
deferreds[timeoutId] = deferred;
|
9429
|
-
promise.then(cleanup, cleanup);
|
9430
9674
|
|
9431
9675
|
return promise;
|
9432
9676
|
}
|
@@ -9438,7 +9682,7 @@ function $TimeoutProvider() {
|
|
9438
9682
|
* @methodOf ng.$timeout
|
9439
9683
|
*
|
9440
9684
|
* @description
|
9441
|
-
* Cancels a task associated with the `promise`. As a result of this the promise will be
|
9685
|
+
* Cancels a task associated with the `promise`. As a result of this, the promise will be
|
9442
9686
|
* resolved with a rejection.
|
9443
9687
|
*
|
9444
9688
|
* @param {Promise=} promise Promise returned by the `$timeout` function.
|
@@ -9448,6 +9692,7 @@ function $TimeoutProvider() {
|
|
9448
9692
|
timeout.cancel = function(promise) {
|
9449
9693
|
if (promise && promise.$$timeoutId in deferreds) {
|
9450
9694
|
deferreds[promise.$$timeoutId].reject('canceled');
|
9695
|
+
delete deferreds[promise.$$timeoutId];
|
9451
9696
|
return $browser.defer.cancel(promise.$$timeoutId);
|
9452
9697
|
}
|
9453
9698
|
return false;
|
@@ -9526,7 +9771,7 @@ function $TimeoutProvider() {
|
|
9526
9771
|
*
|
9527
9772
|
* The general syntax in templates is as follows:
|
9528
9773
|
*
|
9529
|
-
* {{ expression | [
|
9774
|
+
* {{ expression [| filter_name[:parameter_value] ... ] }}
|
9530
9775
|
*
|
9531
9776
|
* @param {String} name Name of the filter function to retrieve
|
9532
9777
|
* @return {Function} the filter function
|
@@ -9611,7 +9856,7 @@ function $FilterProvider($provide) {
|
|
9611
9856
|
<hr>
|
9612
9857
|
Any: <input ng-model="search.$"> <br>
|
9613
9858
|
Name only <input ng-model="search.name"><br>
|
9614
|
-
Phone only <input ng-model="search.phone"
|
9859
|
+
Phone only <input ng-model="search.phone"><br>
|
9615
9860
|
<table id="searchObjResults">
|
9616
9861
|
<tr><th>Name</th><th>Phone</th></tr>
|
9617
9862
|
<tr ng-repeat="friend in friends | filter:search">
|
@@ -9784,7 +10029,9 @@ function currencyFilter($locale) {
|
|
9784
10029
|
* If the input is not a number an empty string is returned.
|
9785
10030
|
*
|
9786
10031
|
* @param {number|string} number Number to format.
|
9787
|
-
* @param {(number|string)=}
|
10032
|
+
* @param {(number|string)=} fractionSize Number of decimal places to round the number to.
|
10033
|
+
* If this is not provided then the fraction size is computed from the current locale's number
|
10034
|
+
* formatting pattern. In the case of the default locale, it will be 3.
|
9788
10035
|
* @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
|
9789
10036
|
*
|
9790
10037
|
* @example
|
@@ -9891,6 +10138,11 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
|
|
9891
10138
|
}
|
9892
10139
|
|
9893
10140
|
if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
|
10141
|
+
} else {
|
10142
|
+
|
10143
|
+
if (fractionSize > 0 && number > -1 && number < 1) {
|
10144
|
+
formatedText = number.toFixed(fractionSize);
|
10145
|
+
}
|
9894
10146
|
}
|
9895
10147
|
|
9896
10148
|
parts.push(isNegative ? pattern.negPre : pattern.posPre);
|
@@ -9914,6 +10166,7 @@ function padNumber(num, digits, trim) {
|
|
9914
10166
|
|
9915
10167
|
|
9916
10168
|
function dateGetter(name, size, offset, trim) {
|
10169
|
+
offset = offset || 0;
|
9917
10170
|
return function(date) {
|
9918
10171
|
var value = date['get' + name]();
|
9919
10172
|
if (offset > 0 || value > -offset)
|
@@ -10013,7 +10266,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
|
|
10013
10266
|
* * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US locale (e.g. 9/3/10 12:05 pm)
|
10014
10267
|
* * `'fullDate'`: equivalent to `'EEEE, MMMM d,y'` for en_US locale
|
10015
10268
|
* (e.g. Friday, September 3, 2010)
|
10016
|
-
* * `'longDate'`: equivalent to `'MMMM d, y'` for en_US locale (e.g. September 3, 2010
|
10269
|
+
* * `'longDate'`: equivalent to `'MMMM d, y'` for en_US locale (e.g. September 3, 2010)
|
10017
10270
|
* * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US locale (e.g. Sep 3, 2010)
|
10018
10271
|
* * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
|
10019
10272
|
* * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm)
|
@@ -10021,10 +10274,10 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
|
|
10021
10274
|
*
|
10022
10275
|
* `format` string can contain literal values. These need to be quoted with single quotes (e.g.
|
10023
10276
|
* `"h 'in the morning'"`). In order to output single quote, use two single quotes in a sequence
|
10024
|
-
* (e.g. `"h o''clock"`).
|
10277
|
+
* (e.g. `"h 'o''clock'"`).
|
10025
10278
|
*
|
10026
10279
|
* @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
|
10027
|
-
* number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and
|
10280
|
+
* number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and its
|
10028
10281
|
* shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
|
10029
10282
|
* specified in the string input, the time is considered to be in the local timezone.
|
10030
10283
|
* @param {string=} format Formatting rules (see Description). If not specified,
|
@@ -10388,8 +10641,10 @@ function orderByFilter($parse){
|
|
10388
10641
|
var t1 = typeof v1;
|
10389
10642
|
var t2 = typeof v2;
|
10390
10643
|
if (t1 == t2) {
|
10391
|
-
if (t1 == "string")
|
10392
|
-
|
10644
|
+
if (t1 == "string") {
|
10645
|
+
v1 = v1.toLowerCase();
|
10646
|
+
v2 = v2.toLowerCase();
|
10647
|
+
}
|
10393
10648
|
if (v1 === v2) return 0;
|
10394
10649
|
return v1 < v2 ? -1 : 1;
|
10395
10650
|
} else {
|
@@ -10809,7 +11064,7 @@ function FormController(element, attrs) {
|
|
10809
11064
|
errors = form.$error = {};
|
10810
11065
|
|
10811
11066
|
// init state
|
10812
|
-
form.$name = attrs.name;
|
11067
|
+
form.$name = attrs.name || attrs.ngForm;
|
10813
11068
|
form.$dirty = false;
|
10814
11069
|
form.$pristine = true;
|
10815
11070
|
form.$valid = true;
|
@@ -10829,12 +11084,32 @@ function FormController(element, attrs) {
|
|
10829
11084
|
addClass((isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
|
10830
11085
|
}
|
10831
11086
|
|
11087
|
+
/**
|
11088
|
+
* @ngdoc function
|
11089
|
+
* @name ng.directive:form.FormController#$addControl
|
11090
|
+
* @methodOf ng.directive:form.FormController
|
11091
|
+
*
|
11092
|
+
* @description
|
11093
|
+
* Register a control with the form.
|
11094
|
+
*
|
11095
|
+
* Input elements using ngModelController do this automatically when they are linked.
|
11096
|
+
*/
|
10832
11097
|
form.$addControl = function(control) {
|
10833
11098
|
if (control.$name && !form.hasOwnProperty(control.$name)) {
|
10834
11099
|
form[control.$name] = control;
|
10835
11100
|
}
|
10836
11101
|
};
|
10837
11102
|
|
11103
|
+
/**
|
11104
|
+
* @ngdoc function
|
11105
|
+
* @name ng.directive:form.FormController#$removeControl
|
11106
|
+
* @methodOf ng.directive:form.FormController
|
11107
|
+
*
|
11108
|
+
* @description
|
11109
|
+
* Deregister a control from the form.
|
11110
|
+
*
|
11111
|
+
* Input elements using ngModelController do this automatically when they are destroyed.
|
11112
|
+
*/
|
10838
11113
|
form.$removeControl = function(control) {
|
10839
11114
|
if (control.$name && form[control.$name] === control) {
|
10840
11115
|
delete form[control.$name];
|
@@ -10844,6 +11119,16 @@ function FormController(element, attrs) {
|
|
10844
11119
|
});
|
10845
11120
|
};
|
10846
11121
|
|
11122
|
+
/**
|
11123
|
+
* @ngdoc function
|
11124
|
+
* @name ng.directive:form.FormController#$setValidity
|
11125
|
+
* @methodOf ng.directive:form.FormController
|
11126
|
+
*
|
11127
|
+
* @description
|
11128
|
+
* Sets the validity of a form control.
|
11129
|
+
*
|
11130
|
+
* This method will also propagate to parent forms.
|
11131
|
+
*/
|
10847
11132
|
form.$setValidity = function(validationToken, isValid, control) {
|
10848
11133
|
var queue = errors[validationToken];
|
10849
11134
|
|
@@ -10882,6 +11167,17 @@ function FormController(element, attrs) {
|
|
10882
11167
|
}
|
10883
11168
|
};
|
10884
11169
|
|
11170
|
+
/**
|
11171
|
+
* @ngdoc function
|
11172
|
+
* @name ng.directive:form.FormController#$setDirty
|
11173
|
+
* @methodOf ng.directive:form.FormController
|
11174
|
+
*
|
11175
|
+
* @description
|
11176
|
+
* Sets the form to a dirty state.
|
11177
|
+
*
|
11178
|
+
* This method can be called to add the 'ng-dirty' class and set the form to a dirty
|
11179
|
+
* state (ng-dirty class). This method will also propagate to parent forms.
|
11180
|
+
*/
|
10885
11181
|
form.$setDirty = function() {
|
10886
11182
|
element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
|
10887
11183
|
form.$dirty = true;
|
@@ -11058,7 +11354,7 @@ var formDirective = formDirectiveFactory();
|
|
11058
11354
|
var ngFormDirective = formDirectiveFactory(true);
|
11059
11355
|
|
11060
11356
|
var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
|
11061
|
-
var EMAIL_REGEXP = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,
|
11357
|
+
var EMAIL_REGEXP = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}$/;
|
11062
11358
|
var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
|
11063
11359
|
|
11064
11360
|
var inputType = {
|
@@ -11142,8 +11438,8 @@ var inputType = {
|
|
11142
11438
|
*
|
11143
11439
|
* @param {string} ngModel Assignable angular expression to data-bind to.
|
11144
11440
|
* @param {string=} name Property name of the form under which the control is published.
|
11145
|
-
* @param {string=} min Sets the `min` validation error key if the value entered is less
|
11146
|
-
* @param {string=} max Sets the `max` validation error key if the value entered is greater
|
11441
|
+
* @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
|
11442
|
+
* @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
|
11147
11443
|
* @param {string=} required Sets `required` validation error key if the value is not entered.
|
11148
11444
|
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
|
11149
11445
|
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
|
@@ -11169,9 +11465,9 @@ var inputType = {
|
|
11169
11465
|
<form name="myForm" ng-controller="Ctrl">
|
11170
11466
|
Number: <input type="number" name="input" ng-model="value"
|
11171
11467
|
min="0" max="99" required>
|
11172
|
-
<span class="error" ng-show="myForm.
|
11468
|
+
<span class="error" ng-show="myForm.input.$error.required">
|
11173
11469
|
Required!</span>
|
11174
|
-
<span class="error" ng-show="myForm.
|
11470
|
+
<span class="error" ng-show="myForm.input.$error.number">
|
11175
11471
|
Not valid number!</span>
|
11176
11472
|
<tt>value = {{value}}</tt><br/>
|
11177
11473
|
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
|
@@ -11292,6 +11588,8 @@ var inputType = {
|
|
11292
11588
|
* @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
|
11293
11589
|
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
|
11294
11590
|
* patterns defined as scope expressions.
|
11591
|
+
* @param {string=} ngChange Angular expression to be executed when input changes due to user
|
11592
|
+
* interaction with the input element.
|
11295
11593
|
*
|
11296
11594
|
* @example
|
11297
11595
|
<doc:example>
|
@@ -11455,6 +11753,15 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
11455
11753
|
} else {
|
11456
11754
|
var timeout;
|
11457
11755
|
|
11756
|
+
var deferListener = function() {
|
11757
|
+
if (!timeout) {
|
11758
|
+
timeout = $browser.defer(function() {
|
11759
|
+
listener();
|
11760
|
+
timeout = null;
|
11761
|
+
});
|
11762
|
+
}
|
11763
|
+
};
|
11764
|
+
|
11458
11765
|
element.bind('keydown', function(event) {
|
11459
11766
|
var key = event.keyCode;
|
11460
11767
|
|
@@ -11462,16 +11769,16 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
11462
11769
|
// command modifiers arrows
|
11463
11770
|
if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
|
11464
11771
|
|
11465
|
-
|
11466
|
-
timeout = $browser.defer(function() {
|
11467
|
-
listener();
|
11468
|
-
timeout = null;
|
11469
|
-
});
|
11470
|
-
}
|
11772
|
+
deferListener();
|
11471
11773
|
});
|
11472
11774
|
|
11473
11775
|
// if user paste into input using mouse, we need "change" event to catch it
|
11474
11776
|
element.bind('change', listener);
|
11777
|
+
|
11778
|
+
// if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
|
11779
|
+
if ($sniffer.hasEvent('paste')) {
|
11780
|
+
element.bind('paste cut', deferListener);
|
11781
|
+
}
|
11475
11782
|
}
|
11476
11783
|
|
11477
11784
|
|
@@ -11770,7 +12077,7 @@ function checkboxInputType(scope, element, attr, ctrl) {
|
|
11770
12077
|
<tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
|
11771
12078
|
<tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
|
11772
12079
|
<tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
|
11773
|
-
<tt>myForm.
|
12080
|
+
<tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
|
11774
12081
|
<tt>myForm.$valid = {{myForm.$valid}}</tt><br>
|
11775
12082
|
<tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
|
11776
12083
|
<tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
|
@@ -11841,12 +12148,25 @@ var VALID_CLASS = 'ng-valid',
|
|
11841
12148
|
*
|
11842
12149
|
* @property {string} $viewValue Actual string value in the view.
|
11843
12150
|
* @property {*} $modelValue The value in the model, that the control is bound to.
|
11844
|
-
* @property {Array.<Function>} $parsers
|
11845
|
-
|
11846
|
-
|
11847
|
-
|
11848
|
-
|
11849
|
-
|
12151
|
+
* @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
|
12152
|
+
the control reads value from the DOM. Each function is called, in turn, passing the value
|
12153
|
+
through to the next. Used to sanitize / convert the value as well as validation.
|
12154
|
+
|
12155
|
+
For validation, the parsers should update the validity state using
|
12156
|
+
{@link ng.directive:ngModel.NgModelController#$setValidity $setValidity()},
|
12157
|
+
and return `undefined` for invalid values.
|
12158
|
+
*
|
12159
|
+
* @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
|
12160
|
+
* the model value changes. Each function is called, in turn, passing the value through to the
|
12161
|
+
* next. Used to format / convert values for display in the control and validation.
|
12162
|
+
* <pre>
|
12163
|
+
* function formatter(value) {
|
12164
|
+
* if (value) {
|
12165
|
+
* return value.toUpperCase();
|
12166
|
+
* }
|
12167
|
+
* }
|
12168
|
+
* ngModel.$formatters.push(formatter);
|
12169
|
+
* </pre>
|
11850
12170
|
* @property {Object} $error An bject hash with all errors as keys.
|
11851
12171
|
*
|
11852
12172
|
* @property {boolean} $pristine True if user has not interacted with the control yet.
|
@@ -11861,6 +12181,10 @@ var VALID_CLASS = 'ng-valid',
|
|
11861
12181
|
* specifically does not contain any logic which deals with DOM rendering or listening to
|
11862
12182
|
* DOM events. The `NgModelController` is meant to be extended by other directives where, the
|
11863
12183
|
* directive provides DOM manipulation and the `NgModelController` provides the data-binding.
|
12184
|
+
* Note that you cannot use `NgModelController` in a directive with an isolated scope,
|
12185
|
+
* as, in that case, the `ng-model` value gets put into the isolated scope and does not get
|
12186
|
+
* propogated to the parent scope.
|
12187
|
+
*
|
11864
12188
|
*
|
11865
12189
|
* This example shows how to use `NgModelController` with a custom control to achieve
|
11866
12190
|
* data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
|
@@ -11901,7 +12225,13 @@ var VALID_CLASS = 'ng-valid',
|
|
11901
12225
|
|
11902
12226
|
// Write data to the model
|
11903
12227
|
function read() {
|
11904
|
-
|
12228
|
+
var html = element.html();
|
12229
|
+
// When we clear the content editable the browser leaves a <br> behind
|
12230
|
+
// If strip-br attribute is provided then we strip this out
|
12231
|
+
if( attrs.stripBr && html == '<br>' ) {
|
12232
|
+
html = '';
|
12233
|
+
}
|
12234
|
+
ngModel.$setViewValue(html);
|
11905
12235
|
}
|
11906
12236
|
}
|
11907
12237
|
};
|
@@ -11911,6 +12241,7 @@ var VALID_CLASS = 'ng-valid',
|
|
11911
12241
|
<form name="myForm">
|
11912
12242
|
<div contenteditable
|
11913
12243
|
name="myWidget" ng-model="userContent"
|
12244
|
+
strip-br="true"
|
11914
12245
|
required>Change me!</div>
|
11915
12246
|
<span ng-show="myForm.myWidget.$error.required">Required!</span>
|
11916
12247
|
<hr>
|
@@ -12033,8 +12364,8 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
12033
12364
|
* For example {@link ng.directive:input input} or
|
12034
12365
|
* {@link ng.directive:select select} directives call it.
|
12035
12366
|
*
|
12036
|
-
* It internally calls all `
|
12037
|
-
* calls all registered change listeners.
|
12367
|
+
* It internally calls all `$parsers` (including validators) and updates the `$modelValue` and the actual model path.
|
12368
|
+
* Lastly it calls all registered change listeners.
|
12038
12369
|
*
|
12039
12370
|
* @param {string} value Value from the view.
|
12040
12371
|
*/
|
@@ -12099,7 +12430,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
12099
12430
|
* @element input
|
12100
12431
|
*
|
12101
12432
|
* @description
|
12102
|
-
* Is directive that tells Angular to do two-way data binding. It works together with `input`,
|
12433
|
+
* Is a directive that tells Angular to do two-way data binding. It works together with `input`,
|
12103
12434
|
* `select`, `textarea`. You can easily write your own directives to use `ngModel` as well.
|
12104
12435
|
*
|
12105
12436
|
* `ngModel` is responsible for:
|
@@ -12111,6 +12442,10 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
12111
12442
|
* - setting related css class onto the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`),
|
12112
12443
|
* - register the control with parent {@link ng.directive:form form}.
|
12113
12444
|
*
|
12445
|
+
* Note: `ngModel` will try to bind to the property given by evaluating the expression on the
|
12446
|
+
* current scope. If the property doesn't already exist on this scope, it will be created
|
12447
|
+
* implicitly and added to the scope.
|
12448
|
+
*
|
12114
12449
|
* For basic examples, how to use `ngModel`, see:
|
12115
12450
|
*
|
12116
12451
|
* - {@link ng.directive:input input}
|
@@ -12251,8 +12586,9 @@ var requiredDirective = function() {
|
|
12251
12586
|
</script>
|
12252
12587
|
<form name="myForm" ng-controller="Ctrl">
|
12253
12588
|
List: <input name="namesInput" ng-model="names" ng-list required>
|
12254
|
-
<span class="error" ng-show="myForm.
|
12589
|
+
<span class="error" ng-show="myForm.namesInput.$error.required">
|
12255
12590
|
Required!</span>
|
12591
|
+
<br>
|
12256
12592
|
<tt>names = {{names}}</tt><br/>
|
12257
12593
|
<tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
|
12258
12594
|
<tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
|
@@ -12264,12 +12600,14 @@ var requiredDirective = function() {
|
|
12264
12600
|
it('should initialize to model', function() {
|
12265
12601
|
expect(binding('names')).toEqual('["igor","misko","vojta"]');
|
12266
12602
|
expect(binding('myForm.namesInput.$valid')).toEqual('true');
|
12603
|
+
expect(element('span.error').css('display')).toBe('none');
|
12267
12604
|
});
|
12268
12605
|
|
12269
12606
|
it('should be invalid if empty', function() {
|
12270
12607
|
input('names').enter('');
|
12271
12608
|
expect(binding('names')).toEqual('[]');
|
12272
12609
|
expect(binding('myForm.namesInput.$valid')).toEqual('false');
|
12610
|
+
expect(element('span.error').css('display')).not().toBe('none');
|
12273
12611
|
});
|
12274
12612
|
</doc:scenario>
|
12275
12613
|
</doc:example>
|
@@ -12319,7 +12657,7 @@ var ngValueDirective = function() {
|
|
12319
12657
|
} else {
|
12320
12658
|
return function(scope, elm, attr) {
|
12321
12659
|
scope.$watch(attr.ngValue, function valueWatchAction(value) {
|
12322
|
-
attr.$set('value', value
|
12660
|
+
attr.$set('value', value);
|
12323
12661
|
});
|
12324
12662
|
};
|
12325
12663
|
}
|
@@ -12339,10 +12677,9 @@ var ngValueDirective = function() {
|
|
12339
12677
|
* Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
|
12340
12678
|
* `{{ expression }}` which is similar but less verbose.
|
12341
12679
|
*
|
12342
|
-
*
|
12343
|
-
*
|
12344
|
-
*
|
12345
|
-
* bindings invisible to the user while the page is loading.
|
12680
|
+
* It is preferrable to use `ngBind` instead of `{{ expression }}` when a template is momentarily
|
12681
|
+
* displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
|
12682
|
+
* element attribute, it makes the bindings invisible to the user while the page is loading.
|
12346
12683
|
*
|
12347
12684
|
* An alternative solution to this problem would be using the
|
12348
12685
|
* {@link ng.directive:ngCloak ngCloak} directive.
|
@@ -12388,10 +12725,11 @@ var ngBindDirective = ngDirective(function(scope, element, attr) {
|
|
12388
12725
|
*
|
12389
12726
|
* @description
|
12390
12727
|
* The `ngBindTemplate` directive specifies that the element
|
12391
|
-
* text should be replaced with the
|
12392
|
-
*
|
12393
|
-
*
|
12394
|
-
*
|
12728
|
+
* text content should be replaced with the interpolation of the template
|
12729
|
+
* in the `ngBindTemplate` attribute.
|
12730
|
+
* Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
|
12731
|
+
* expressions. This directive is needed since some HTML elements
|
12732
|
+
* (such as TITLE and OPTION) cannot contain SPAN elements.
|
12395
12733
|
*
|
12396
12734
|
* @element ANY
|
12397
12735
|
* @param {string} ngBindTemplate template of form
|
@@ -12480,9 +12818,9 @@ function classDirective(name, selector) {
|
|
12480
12818
|
|
12481
12819
|
if (name !== 'ngClass') {
|
12482
12820
|
scope.$watch('$index', function($index, old$index) {
|
12483
|
-
var mod = $index
|
12484
|
-
if (mod !== old$index
|
12485
|
-
if (mod
|
12821
|
+
var mod = $index & 1;
|
12822
|
+
if (mod !== old$index & 1) {
|
12823
|
+
if (mod === selector) {
|
12486
12824
|
addClass(scope.$eval(attr[name]));
|
12487
12825
|
} else {
|
12488
12826
|
removeClass(scope.$eval(attr[name]));
|
@@ -12494,12 +12832,12 @@ function classDirective(name, selector) {
|
|
12494
12832
|
|
12495
12833
|
function ngClassWatchAction(newVal) {
|
12496
12834
|
if (selector === true || scope.$index % 2 === selector) {
|
12497
|
-
if (oldVal && (newVal
|
12835
|
+
if (oldVal && !equals(newVal,oldVal)) {
|
12498
12836
|
removeClass(oldVal);
|
12499
12837
|
}
|
12500
12838
|
addClass(newVal);
|
12501
12839
|
}
|
12502
|
-
oldVal = newVal;
|
12840
|
+
oldVal = copy(newVal);
|
12503
12841
|
}
|
12504
12842
|
|
12505
12843
|
|
@@ -12527,8 +12865,8 @@ function classDirective(name, selector) {
|
|
12527
12865
|
* @name ng.directive:ngClass
|
12528
12866
|
*
|
12529
12867
|
* @description
|
12530
|
-
* The `ngClass` allows you to set CSS
|
12531
|
-
* expression that represents all classes to be added.
|
12868
|
+
* The `ngClass` allows you to set CSS classes on HTML an element, dynamically, by databinding
|
12869
|
+
* an expression that represents all classes to be added.
|
12532
12870
|
*
|
12533
12871
|
* The directive won't add duplicate classes if a particular class was already set.
|
12534
12872
|
*
|
@@ -12538,7 +12876,9 @@ function classDirective(name, selector) {
|
|
12538
12876
|
* @element ANY
|
12539
12877
|
* @param {expression} ngClass {@link guide/expression Expression} to eval. The result
|
12540
12878
|
* of the evaluation can be a string representing space delimited class
|
12541
|
-
* names, an array, or a map of class names to boolean values.
|
12879
|
+
* names, an array, or a map of class names to boolean values. In the case of a map, the
|
12880
|
+
* names of the properties whose values are truthy will be added as css classes to the
|
12881
|
+
* element.
|
12542
12882
|
*
|
12543
12883
|
* @example
|
12544
12884
|
<example>
|
@@ -12625,7 +12965,7 @@ var ngClassOddDirective = classDirective('Odd', 0);
|
|
12625
12965
|
* @name ng.directive:ngClassEven
|
12626
12966
|
*
|
12627
12967
|
* @description
|
12628
|
-
* The `ngClassOdd` and `ngClassEven`
|
12968
|
+
* The `ngClassOdd` and `ngClassEven` directives work exactly as
|
12629
12969
|
* {@link ng.directive:ngClass ngClass}, except it works in
|
12630
12970
|
* conjunction with `ngRepeat` and takes affect only on odd (even) rows.
|
12631
12971
|
*
|
@@ -12684,7 +13024,7 @@ var ngClassEvenDirective = classDirective('Even', 1);
|
|
12684
13024
|
*
|
12685
13025
|
* <pre>
|
12686
13026
|
* [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
|
12687
|
-
* display: none;
|
13027
|
+
* display: none !important;
|
12688
13028
|
* }
|
12689
13029
|
* </pre>
|
12690
13030
|
*
|
@@ -12742,8 +13082,7 @@ var ngCloakDirective = ngDirective({
|
|
12742
13082
|
* * Controller — The `ngController` directive specifies a Controller class; the class has
|
12743
13083
|
* methods that typically express the business logic behind the application.
|
12744
13084
|
*
|
12745
|
-
* Note that an alternative way to define controllers is via the
|
12746
|
-
* service.
|
13085
|
+
* Note that an alternative way to define controllers is via the {@link ng.$route $route} service.
|
12747
13086
|
*
|
12748
13087
|
* @element ANY
|
12749
13088
|
* @scope
|
@@ -12753,11 +13092,9 @@ var ngCloakDirective = ngDirective({
|
|
12753
13092
|
*
|
12754
13093
|
* @example
|
12755
13094
|
* Here is a simple form for editing user contact information. Adding, removing, clearing, and
|
12756
|
-
* greeting are methods declared on the controller (see source tab). These methods can
|
12757
|
-
* easily be called from the angular markup. Notice that
|
12758
|
-
*
|
12759
|
-
* notice that any changes to the data are automatically reflected in the View without the need
|
12760
|
-
* for a manual update.
|
13095
|
+
* greeting are methods declared on the $scope by the controller (see source tab). These methods can
|
13096
|
+
* easily be called from the angular markup. Notice that any changes to the data are automatically
|
13097
|
+
* reflected in the View without the need for a manual update.
|
12761
13098
|
<doc:example>
|
12762
13099
|
<doc:source>
|
12763
13100
|
<script>
|
@@ -12834,16 +13171,32 @@ var ngControllerDirective = [function() {
|
|
12834
13171
|
* @name ng.directive:ngCsp
|
12835
13172
|
* @priority 1000
|
12836
13173
|
*
|
13174
|
+
* @element html
|
12837
13175
|
* @description
|
12838
13176
|
* Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
|
12839
|
-
*
|
12840
|
-
*
|
12841
|
-
*
|
12842
|
-
*
|
12843
|
-
*
|
12844
|
-
*
|
12845
|
-
*
|
12846
|
-
*
|
13177
|
+
*
|
13178
|
+
* This is necessary when developing things like Google Chrome Extensions.
|
13179
|
+
*
|
13180
|
+
* CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
|
13181
|
+
* For us to be compatible, we just need to implement the "getterFn" in $parse without violating
|
13182
|
+
* any of these restrictions.
|
13183
|
+
*
|
13184
|
+
* AngularJS uses `Function(string)` generated functions as a speed optimization. By applying `ngCsp`
|
13185
|
+
* it is be possible to opt into the CSP compatible mode. When this mode is on AngularJS will
|
13186
|
+
* evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
|
13187
|
+
* be raised.
|
13188
|
+
*
|
13189
|
+
* In order to use this feature put `ngCsp` directive on the root element of the application.
|
13190
|
+
*
|
13191
|
+
* @example
|
13192
|
+
* This example shows how to apply the `ngCsp` directive to the `html` tag.
|
13193
|
+
<pre>
|
13194
|
+
<!doctype html>
|
13195
|
+
<html ng-app ng-csp>
|
13196
|
+
...
|
13197
|
+
...
|
13198
|
+
</html>
|
13199
|
+
</pre>
|
12847
13200
|
*/
|
12848
13201
|
|
12849
13202
|
var ngCspDirective = ['$sniffer', function($sniffer) {
|
@@ -12892,7 +13245,7 @@ var ngCspDirective = ['$sniffer', function($sniffer) {
|
|
12892
13245
|
*/
|
12893
13246
|
var ngEventDirectives = {};
|
12894
13247
|
forEach(
|
12895
|
-
'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave'.split(' '),
|
13248
|
+
'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave submit'.split(' '),
|
12896
13249
|
function(name) {
|
12897
13250
|
var directiveName = directiveNormalize('ng-' + name);
|
12898
13251
|
ngEventDirectives[directiveName] = ['$parse', function($parse) {
|
@@ -13019,6 +13372,54 @@ forEach(
|
|
13019
13372
|
*/
|
13020
13373
|
|
13021
13374
|
|
13375
|
+
/**
|
13376
|
+
* @ngdoc directive
|
13377
|
+
* @name ng.directive:ngKeydown
|
13378
|
+
*
|
13379
|
+
* @description
|
13380
|
+
* Specify custom behavior on keydown event.
|
13381
|
+
*
|
13382
|
+
* @element ANY
|
13383
|
+
* @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
|
13384
|
+
* keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
|
13385
|
+
*
|
13386
|
+
* @example
|
13387
|
+
* See {@link ng.directive:ngClick ngClick}
|
13388
|
+
*/
|
13389
|
+
|
13390
|
+
|
13391
|
+
/**
|
13392
|
+
* @ngdoc directive
|
13393
|
+
* @name ng.directive:ngKeyup
|
13394
|
+
*
|
13395
|
+
* @description
|
13396
|
+
* Specify custom behavior on keyup event.
|
13397
|
+
*
|
13398
|
+
* @element ANY
|
13399
|
+
* @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
|
13400
|
+
* keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
|
13401
|
+
*
|
13402
|
+
* @example
|
13403
|
+
* See {@link ng.directive:ngClick ngClick}
|
13404
|
+
*/
|
13405
|
+
|
13406
|
+
|
13407
|
+
/**
|
13408
|
+
* @ngdoc directive
|
13409
|
+
* @name ng.directive:ngKeypress
|
13410
|
+
*
|
13411
|
+
* @description
|
13412
|
+
* Specify custom behavior on keypress event.
|
13413
|
+
*
|
13414
|
+
* @element ANY
|
13415
|
+
* @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
|
13416
|
+
* keypress. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
|
13417
|
+
*
|
13418
|
+
* @example
|
13419
|
+
* See {@link ng.directive:ngClick ngClick}
|
13420
|
+
*/
|
13421
|
+
|
13422
|
+
|
13022
13423
|
/**
|
13023
13424
|
* @ngdoc directive
|
13024
13425
|
* @name ng.directive:ngSubmit
|
@@ -13027,10 +13428,11 @@ forEach(
|
|
13027
13428
|
* Enables binding angular expressions to onsubmit events.
|
13028
13429
|
*
|
13029
13430
|
* Additionally it prevents the default action (which for form means sending the request to the
|
13030
|
-
* server and reloading the current page)
|
13431
|
+
* server and reloading the current page) **but only if the form does not contain an `action`
|
13432
|
+
* attribute**.
|
13031
13433
|
*
|
13032
13434
|
* @element form
|
13033
|
-
* @param {expression} ngSubmit {@link guide/expression Expression} to eval.
|
13435
|
+
* @param {expression} ngSubmit {@link guide/expression Expression} to eval. (Event object is available as `$event`)
|
13034
13436
|
*
|
13035
13437
|
* @example
|
13036
13438
|
<doc:example>
|
@@ -13070,11 +13472,6 @@ forEach(
|
|
13070
13472
|
</doc:scenario>
|
13071
13473
|
</doc:example>
|
13072
13474
|
*/
|
13073
|
-
var ngSubmitDirective = ngDirective(function(scope, element, attrs) {
|
13074
|
-
element.bind('submit', function() {
|
13075
|
-
scope.$apply(attrs.ngSubmit);
|
13076
|
-
});
|
13077
|
-
});
|
13078
13475
|
|
13079
13476
|
/**
|
13080
13477
|
* @ngdoc directive
|
@@ -13282,7 +13679,7 @@ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
|
|
13282
13679
|
* @description
|
13283
13680
|
* # Overview
|
13284
13681
|
* `ngPluralize` is a directive that displays messages according to en-US localization rules.
|
13285
|
-
* These rules are bundled with angular.js
|
13682
|
+
* These rules are bundled with angular.js, but can be overridden
|
13286
13683
|
* (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
|
13287
13684
|
* by specifying the mappings between
|
13288
13685
|
* {@link http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
|
@@ -13295,8 +13692,8 @@ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
|
|
13295
13692
|
*
|
13296
13693
|
* While a pural category may match many numbers (for example, in en-US locale, "other" can match
|
13297
13694
|
* any number that is not 1), an explicit number rule can only match one number. For example, the
|
13298
|
-
* explicit number rule for "3" matches the number 3.
|
13299
|
-
* and explicit number rules throughout
|
13695
|
+
* explicit number rule for "3" matches the number 3. There are examples of plural categories
|
13696
|
+
* and explicit number rules throughout the rest of this documentation.
|
13300
13697
|
*
|
13301
13698
|
* # Configuring ngPluralize
|
13302
13699
|
* You configure ngPluralize by providing 2 attributes: `count` and `when`.
|
@@ -13306,8 +13703,7 @@ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
|
|
13306
13703
|
* Angular expression}; these are evaluated on the current scope for its bound value.
|
13307
13704
|
*
|
13308
13705
|
* The `when` attribute specifies the mappings between plural categories and the actual
|
13309
|
-
* string to be displayed. The value of the attribute should be a JSON object
|
13310
|
-
* can interpret it correctly.
|
13706
|
+
* string to be displayed. The value of the attribute should be a JSON object.
|
13311
13707
|
*
|
13312
13708
|
* The following example shows how to configure ngPluralize:
|
13313
13709
|
*
|
@@ -13468,7 +13864,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
|
|
13468
13864
|
if (!isNaN(value)) {
|
13469
13865
|
//if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
|
13470
13866
|
//check it against pluralization rules in $locale service
|
13471
|
-
if (!whens
|
13867
|
+
if (!(value in whens)) value = $locale.pluralCat(value - offset);
|
13472
13868
|
return whensExpFns[value](scope, element, true);
|
13473
13869
|
} else {
|
13474
13870
|
return '';
|
@@ -13931,8 +14327,7 @@ var ngSwitchDefaultDirective = ngDirective({
|
|
13931
14327
|
return {
|
13932
14328
|
restrict: 'E',
|
13933
14329
|
transclude: true,
|
13934
|
-
scope: '
|
13935
|
-
locals: { title:'bind' },
|
14330
|
+
scope: { title:'@' },
|
13936
14331
|
template: '<div style="border: 1px solid black;">' +
|
13937
14332
|
'<div style="background-color: gray">{{title}}</div>' +
|
13938
14333
|
'<div ng-transclude></div>' +
|
@@ -14187,8 +14582,8 @@ var scriptDirective = ['$templateCache', function($templateCache) {
|
|
14187
14582
|
* Optionally `ngOptions` attribute can be used to dynamically generate a list of `<option>`
|
14188
14583
|
* elements for a `<select>` element using an array or an object obtained by evaluating the
|
14189
14584
|
* `ngOptions` expression.
|
14190
|
-
|
14191
|
-
* When an item in the select menu is
|
14585
|
+
*
|
14586
|
+
* When an item in the `<select>` menu is selected, the value of array element or object property
|
14192
14587
|
* represented by the selected option will be bound to the model identified by the `ngModel`
|
14193
14588
|
* directive of the parent select element.
|
14194
14589
|
*
|
@@ -14201,7 +14596,8 @@ var scriptDirective = ['$templateCache', function($templateCache) {
|
|
14201
14596
|
* `select` model to be bound to a non-string value. This is because an option element can currently
|
14202
14597
|
* be bound to string values only.
|
14203
14598
|
*
|
14204
|
-
* @param {string}
|
14599
|
+
* @param {string} ngModel Assignable angular expression to data-bind to.
|
14600
|
+
* @param {string=} name Property name of the form under which the control is published.
|
14205
14601
|
* @param {string=} required The control is considered valid only if value is entered.
|
14206
14602
|
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
|
14207
14603
|
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
|
@@ -14568,10 +14964,6 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
14568
14964
|
|
14569
14965
|
if (multiple) {
|
14570
14966
|
selectedSet = new HashMap(modelValue);
|
14571
|
-
} else if (modelValue === null || nullOption) {
|
14572
|
-
// if we are not multiselect, and we are null then we have to add the nullOption
|
14573
|
-
optionGroups[''].push({selected:modelValue === null, id:'', label:''});
|
14574
|
-
selectedSet = true;
|
14575
14967
|
}
|
14576
14968
|
|
14577
14969
|
// We now build up the list of options we need (we merge later)
|
@@ -14596,9 +14988,14 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
14596
14988
|
selected: selected // determine if we should be selected
|
14597
14989
|
});
|
14598
14990
|
}
|
14599
|
-
if (!multiple
|
14600
|
-
|
14601
|
-
|
14991
|
+
if (!multiple) {
|
14992
|
+
if (nullOption || modelValue === null) {
|
14993
|
+
// insert null option if we have a placeholder, or the model is null
|
14994
|
+
optionGroups[''].unshift({id:'', label:'', selected:!selectedSet});
|
14995
|
+
} else if (!selectedSet) {
|
14996
|
+
// option could not be found, we have to insert the undefined item
|
14997
|
+
optionGroups[''].unshift({id:'?', label:'', selected:true});
|
14998
|
+
}
|
14602
14999
|
}
|
14603
15000
|
|
14604
15001
|
// Now we need to update the list of DOM nodes to match the optionGroups we computed above
|
@@ -14642,7 +15039,8 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
14642
15039
|
if (existingOption.id !== option.id) {
|
14643
15040
|
lastElement.val(existingOption.id = option.id);
|
14644
15041
|
}
|
14645
|
-
|
15042
|
+
// lastElement.prop('selected') provided by jQuery has side-effects
|
15043
|
+
if (lastElement[0].selected !== option.selected) {
|
14646
15044
|
lastElement.prop('selected', (existingOption.selected = option.selected));
|
14647
15045
|
}
|
14648
15046
|
} else {
|
@@ -14757,4 +15155,4 @@ var styleDirective = valueFn({
|
|
14757
15155
|
});
|
14758
15156
|
|
14759
15157
|
})(window, document);
|
14760
|
-
angular.element(document).find('head').append('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none;}ng\\:form{display:block;}</style>');
|
15158
|
+
angular.element(document).find('head').append('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none !important;}ng\\:form{display:block;}</style>');
|