angularjs-rails 1.4.8 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/angularjs-rails/version.rb +2 -2
- data/vendor/assets/javascripts/angular-animate.js +477 -286
- data/vendor/assets/javascripts/angular-aria.js +51 -51
- data/vendor/assets/javascripts/angular-cookies.js +9 -8
- data/vendor/assets/javascripts/angular-loader.js +45 -4
- data/vendor/assets/javascripts/angular-message-format.js +2 -2
- data/vendor/assets/javascripts/angular-messages.js +7 -5
- data/vendor/assets/javascripts/angular-mocks.js +406 -35
- data/vendor/assets/javascripts/angular-resource.js +121 -37
- data/vendor/assets/javascripts/angular-route.js +36 -11
- data/vendor/assets/javascripts/angular-sanitize.js +280 -246
- data/vendor/assets/javascripts/angular-scenario.js +2183 -773
- data/vendor/assets/javascripts/angular-touch.js +115 -14
- data/vendor/assets/javascripts/angular.js +2183 -773
- data/vendor/assets/javascripts/unstable/angular2-polyfills.js +3316 -0
- data/vendor/assets/javascripts/unstable/angular2.js +19327 -25066
- metadata +15 -14
@@ -1,10 +1,13 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.
|
3
|
-
* (c) 2010-
|
2
|
+
* @license AngularJS v1.5.0
|
3
|
+
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
6
6
|
(function(window, angular, undefined) {'use strict';
|
7
7
|
|
8
|
+
/* global ngTouchClickDirectiveFactory: false,
|
9
|
+
*/
|
10
|
+
|
8
11
|
/**
|
9
12
|
* @ngdoc module
|
10
13
|
* @name ngTouch
|
@@ -27,10 +30,108 @@
|
|
27
30
|
/* global -ngTouch */
|
28
31
|
var ngTouch = angular.module('ngTouch', []);
|
29
32
|
|
33
|
+
ngTouch.provider('$touch', $TouchProvider);
|
34
|
+
|
30
35
|
function nodeName_(element) {
|
31
36
|
return angular.lowercase(element.nodeName || (element[0] && element[0].nodeName));
|
32
37
|
}
|
33
38
|
|
39
|
+
/**
|
40
|
+
* @ngdoc provider
|
41
|
+
* @name $touchProvider
|
42
|
+
*
|
43
|
+
* @description
|
44
|
+
* The `$touchProvider` allows enabling / disabling {@link ngTouch.ngClick ngTouch's ngClick directive}.
|
45
|
+
*/
|
46
|
+
$TouchProvider.$inject = ['$provide', '$compileProvider'];
|
47
|
+
function $TouchProvider($provide, $compileProvider) {
|
48
|
+
|
49
|
+
/**
|
50
|
+
* @ngdoc method
|
51
|
+
* @name $touchProvider#ngClickOverrideEnabled
|
52
|
+
*
|
53
|
+
* @param {boolean=} enabled update the ngClickOverrideEnabled state if provided, otherwise just return the
|
54
|
+
* current ngClickOverrideEnabled state
|
55
|
+
* @returns {*} current value if used as getter or itself (chaining) if used as setter
|
56
|
+
*
|
57
|
+
* @kind function
|
58
|
+
*
|
59
|
+
* @description
|
60
|
+
* Call this method to enable/disable {@link ngTouch.ngClick ngTouch's ngClick directive}. If enabled,
|
61
|
+
* the default ngClick directive will be replaced by a version that eliminates the 300ms delay for
|
62
|
+
* click events on browser for touch-devices.
|
63
|
+
*
|
64
|
+
* The default is `false`.
|
65
|
+
*
|
66
|
+
*/
|
67
|
+
var ngClickOverrideEnabled = false;
|
68
|
+
var ngClickDirectiveAdded = false;
|
69
|
+
this.ngClickOverrideEnabled = function(enabled) {
|
70
|
+
if (angular.isDefined(enabled)) {
|
71
|
+
|
72
|
+
if (enabled && !ngClickDirectiveAdded) {
|
73
|
+
ngClickDirectiveAdded = true;
|
74
|
+
|
75
|
+
// Use this to identify the correct directive in the delegate
|
76
|
+
ngTouchClickDirectiveFactory.$$moduleName = 'ngTouch';
|
77
|
+
$compileProvider.directive('ngClick', ngTouchClickDirectiveFactory);
|
78
|
+
|
79
|
+
$provide.decorator('ngClickDirective', ['$delegate', function($delegate) {
|
80
|
+
if (ngClickOverrideEnabled) {
|
81
|
+
// drop the default ngClick directive
|
82
|
+
$delegate.shift();
|
83
|
+
} else {
|
84
|
+
// drop the ngTouch ngClick directive if the override has been re-disabled (because
|
85
|
+
// we cannot de-register added directives)
|
86
|
+
var i = $delegate.length - 1;
|
87
|
+
while (i >= 0) {
|
88
|
+
if ($delegate[i].$$moduleName === 'ngTouch') {
|
89
|
+
$delegate.splice(i, 1);
|
90
|
+
break;
|
91
|
+
}
|
92
|
+
i--;
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
return $delegate;
|
97
|
+
}]);
|
98
|
+
}
|
99
|
+
|
100
|
+
ngClickOverrideEnabled = enabled;
|
101
|
+
return this;
|
102
|
+
}
|
103
|
+
|
104
|
+
return ngClickOverrideEnabled;
|
105
|
+
};
|
106
|
+
|
107
|
+
/**
|
108
|
+
* @ngdoc service
|
109
|
+
* @name $touch
|
110
|
+
* @kind object
|
111
|
+
*
|
112
|
+
* @description
|
113
|
+
* Provides the {@link ngTouch.$touch#ngClickOverrideEnabled `ngClickOverrideEnabled`} method.
|
114
|
+
*
|
115
|
+
*/
|
116
|
+
this.$get = function() {
|
117
|
+
return {
|
118
|
+
/**
|
119
|
+
* @ngdoc method
|
120
|
+
* @name $touch#ngClickOverrideEnabled
|
121
|
+
*
|
122
|
+
* @returns {*} current value of `ngClickOverrideEnabled` set in the {@link ngTouch.$touchProvider $touchProvider},
|
123
|
+
* i.e. if {@link ngTouch.ngClick ngTouch's ngClick} directive is enabled.
|
124
|
+
*
|
125
|
+
* @kind function
|
126
|
+
*/
|
127
|
+
ngClickOverrideEnabled: function() {
|
128
|
+
return ngClickOverrideEnabled;
|
129
|
+
}
|
130
|
+
};
|
131
|
+
};
|
132
|
+
|
133
|
+
}
|
134
|
+
|
34
135
|
/* global ngTouch: false */
|
35
136
|
|
36
137
|
/**
|
@@ -43,8 +144,7 @@ function nodeName_(element) {
|
|
43
144
|
*
|
44
145
|
* Requires the {@link ngTouch `ngTouch`} module to be installed.
|
45
146
|
*
|
46
|
-
* `$swipe` is used by the `ngSwipeLeft` and `ngSwipeRight` directives in `ngTouch
|
47
|
-
* `ngCarousel` in a separate component.
|
147
|
+
* `$swipe` is used by the `ngSwipeLeft` and `ngSwipeRight` directives in `ngTouch`.
|
48
148
|
*
|
49
149
|
* # Usage
|
50
150
|
* The `$swipe` service is an object with a single method: `bind`. `bind` takes an element
|
@@ -203,8 +303,17 @@ ngTouch.factory('$swipe', [function() {
|
|
203
303
|
/**
|
204
304
|
* @ngdoc directive
|
205
305
|
* @name ngClick
|
306
|
+
* @deprecated
|
206
307
|
*
|
207
308
|
* @description
|
309
|
+
* <div class="alert alert-danger">
|
310
|
+
* **DEPRECATION NOTICE**: Beginning with Angular 1.5, this directive is deprecated and by default **disabled**.
|
311
|
+
* The directive will receive no further support and might be removed from future releases.
|
312
|
+
* If you need the directive, you can enable it with the {@link ngTouch.$touchProvider $touchProvider#ngClickOverrideEnabled}
|
313
|
+
* function. We also recommend that you migrate to [FastClick](https://github.com/ftlabs/fastclick).
|
314
|
+
* To learn more about the 300ms delay, this [Telerik article](http://developer.telerik.com/featured/300-ms-click-delay-ios-8/)
|
315
|
+
* gives a good overview.
|
316
|
+
* </div>
|
208
317
|
* A more powerful replacement for the default ngClick designed to be used on touchscreen
|
209
318
|
* devices. Most mobile browsers wait about 300ms after a tap-and-release before sending
|
210
319
|
* the click event. This version handles them immediately, and then prevents the
|
@@ -236,15 +345,7 @@ ngTouch.factory('$swipe', [function() {
|
|
236
345
|
</example>
|
237
346
|
*/
|
238
347
|
|
239
|
-
|
240
|
-
$provide.decorator('ngClickDirective', ['$delegate', function($delegate) {
|
241
|
-
// drop the default ngClick directive
|
242
|
-
$delegate.shift();
|
243
|
-
return $delegate;
|
244
|
-
}]);
|
245
|
-
}]);
|
246
|
-
|
247
|
-
ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
|
348
|
+
var ngTouchClickDirectiveFactory = ['$parse', '$timeout', '$rootElement',
|
248
349
|
function($parse, $timeout, $rootElement) {
|
249
350
|
var TAP_DURATION = 750; // Shorter than 750ms is a tap, longer is a taphold or drag.
|
250
351
|
var MOVE_TOLERANCE = 12; // 12px seems to work in most mobile browsers.
|
@@ -488,7 +589,7 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
|
|
488
589
|
});
|
489
590
|
|
490
591
|
};
|
491
|
-
}]
|
592
|
+
}];
|
492
593
|
|
493
594
|
/* global ngTouch: false */
|
494
595
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.
|
3
|
-
* (c) 2010-
|
2
|
+
* @license AngularJS v1.5.0
|
3
|
+
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
6
6
|
(function(window, document, undefined) {'use strict';
|
@@ -57,7 +57,7 @@ function minErr(module, ErrorConstructor) {
|
|
57
57
|
return match;
|
58
58
|
});
|
59
59
|
|
60
|
-
message += '\nhttp://errors.angularjs.org/1.
|
60
|
+
message += '\nhttp://errors.angularjs.org/1.5.0/' +
|
61
61
|
(module ? module + '/' : '') + code;
|
62
62
|
|
63
63
|
for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
|
@@ -188,29 +188,9 @@ var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
|
|
188
188
|
// This is used so that it's possible for internal tests to create mock ValidityStates.
|
189
189
|
var VALIDITY_STATE_PROPERTY = 'validity';
|
190
190
|
|
191
|
-
/**
|
192
|
-
* @ngdoc function
|
193
|
-
* @name angular.lowercase
|
194
|
-
* @module ng
|
195
|
-
* @kind function
|
196
|
-
*
|
197
|
-
* @description Converts the specified string to lowercase.
|
198
|
-
* @param {string} string String to be converted to lowercase.
|
199
|
-
* @returns {string} Lowercased string.
|
200
|
-
*/
|
201
|
-
var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
|
202
191
|
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
203
192
|
|
204
|
-
|
205
|
-
* @ngdoc function
|
206
|
-
* @name angular.uppercase
|
207
|
-
* @module ng
|
208
|
-
* @kind function
|
209
|
-
*
|
210
|
-
* @description Converts the specified string to uppercase.
|
211
|
-
* @param {string} string String to be converted to uppercase.
|
212
|
-
* @returns {string} Uppercased string.
|
213
|
-
*/
|
193
|
+
var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
|
214
194
|
var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
|
215
195
|
|
216
196
|
|
@@ -230,7 +210,7 @@ var manualUppercase = function(s) {
|
|
230
210
|
|
231
211
|
// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
|
232
212
|
// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
|
233
|
-
// with correct but slower alternatives.
|
213
|
+
// with correct but slower alternatives. See https://github.com/angular/angular.js/issues/11387
|
234
214
|
if ('i' !== 'I'.toLowerCase()) {
|
235
215
|
lowercase = manualLowercase;
|
236
216
|
uppercase = manualUppercase;
|
@@ -273,7 +253,7 @@ function isArrayLike(obj) {
|
|
273
253
|
|
274
254
|
// arrays, strings and jQuery/jqLite objects are array like
|
275
255
|
// * jqLite is either the jQuery or jqLite constructor function
|
276
|
-
// * we have to check the
|
256
|
+
// * we have to check the existence of jqLite first as this method is called
|
277
257
|
// via the forEach method when constructing the jqLite object in the first place
|
278
258
|
if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;
|
279
259
|
|
@@ -284,7 +264,8 @@ function isArrayLike(obj) {
|
|
284
264
|
// NodeList objects (with `item` method) and
|
285
265
|
// other objects with suitable length characteristics are array-like
|
286
266
|
return isNumber(length) &&
|
287
|
-
(length >= 0 && (length - 1) in obj || typeof obj.item == 'function');
|
267
|
+
(length >= 0 && ((length - 1) in obj || obj instanceof Array) || typeof obj.item == 'function');
|
268
|
+
|
288
269
|
}
|
289
270
|
|
290
271
|
/**
|
@@ -381,7 +362,7 @@ function forEachSorted(obj, iterator, context) {
|
|
381
362
|
* @returns {function(*, string)}
|
382
363
|
*/
|
383
364
|
function reverseParams(iteratorFn) {
|
384
|
-
return function(value, key) {
|
365
|
+
return function(value, key) {iteratorFn(key, value);};
|
385
366
|
}
|
386
367
|
|
387
368
|
/**
|
@@ -752,6 +733,10 @@ function isTypedArray(value) {
|
|
752
733
|
return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
|
753
734
|
}
|
754
735
|
|
736
|
+
function isArrayBuffer(obj) {
|
737
|
+
return toString.call(obj) === '[object ArrayBuffer]';
|
738
|
+
}
|
739
|
+
|
755
740
|
|
756
741
|
var trim = function(value) {
|
757
742
|
return isString(value) ? value.trim() : value;
|
@@ -789,7 +774,7 @@ function isElement(node) {
|
|
789
774
|
* @returns {object} in the form of {key1:true, key2:true, ...}
|
790
775
|
*/
|
791
776
|
function makeMap(str) {
|
792
|
-
var obj = {}, items = str.split(
|
777
|
+
var obj = {}, items = str.split(','), i;
|
793
778
|
for (i = 0; i < items.length; i++) {
|
794
779
|
obj[items[i]] = true;
|
795
780
|
}
|
@@ -876,7 +861,7 @@ function copy(source, destination) {
|
|
876
861
|
var stackDest = [];
|
877
862
|
|
878
863
|
if (destination) {
|
879
|
-
if (isTypedArray(destination)) {
|
864
|
+
if (isTypedArray(destination) || isArrayBuffer(destination)) {
|
880
865
|
throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated.");
|
881
866
|
}
|
882
867
|
if (source === destination) {
|
@@ -950,22 +935,10 @@ function copy(source, destination) {
|
|
950
935
|
}
|
951
936
|
|
952
937
|
var needsRecurse = false;
|
953
|
-
var destination;
|
938
|
+
var destination = copyType(source);
|
954
939
|
|
955
|
-
if (
|
956
|
-
destination = [];
|
957
|
-
needsRecurse = true;
|
958
|
-
} else if (isTypedArray(source)) {
|
959
|
-
destination = new source.constructor(source);
|
960
|
-
} else if (isDate(source)) {
|
961
|
-
destination = new Date(source.getTime());
|
962
|
-
} else if (isRegExp(source)) {
|
963
|
-
destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
|
964
|
-
destination.lastIndex = source.lastIndex;
|
965
|
-
} else if (isFunction(source.cloneNode)) {
|
966
|
-
destination = source.cloneNode(true);
|
967
|
-
} else {
|
968
|
-
destination = Object.create(getPrototypeOf(source));
|
940
|
+
if (destination === undefined) {
|
941
|
+
destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
|
969
942
|
needsRecurse = true;
|
970
943
|
}
|
971
944
|
|
@@ -976,6 +949,45 @@ function copy(source, destination) {
|
|
976
949
|
? copyRecurse(source, destination)
|
977
950
|
: destination;
|
978
951
|
}
|
952
|
+
|
953
|
+
function copyType(source) {
|
954
|
+
switch (toString.call(source)) {
|
955
|
+
case '[object Int8Array]':
|
956
|
+
case '[object Int16Array]':
|
957
|
+
case '[object Int32Array]':
|
958
|
+
case '[object Float32Array]':
|
959
|
+
case '[object Float64Array]':
|
960
|
+
case '[object Uint8Array]':
|
961
|
+
case '[object Uint8ClampedArray]':
|
962
|
+
case '[object Uint16Array]':
|
963
|
+
case '[object Uint32Array]':
|
964
|
+
return new source.constructor(copyElement(source.buffer));
|
965
|
+
|
966
|
+
case '[object ArrayBuffer]':
|
967
|
+
//Support: IE10
|
968
|
+
if (!source.slice) {
|
969
|
+
var copied = new ArrayBuffer(source.byteLength);
|
970
|
+
new Uint8Array(copied).set(new Uint8Array(source));
|
971
|
+
return copied;
|
972
|
+
}
|
973
|
+
return source.slice(0);
|
974
|
+
|
975
|
+
case '[object Boolean]':
|
976
|
+
case '[object Number]':
|
977
|
+
case '[object String]':
|
978
|
+
case '[object Date]':
|
979
|
+
return new source.constructor(source.valueOf());
|
980
|
+
|
981
|
+
case '[object RegExp]':
|
982
|
+
var re = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
|
983
|
+
re.lastIndex = source.lastIndex;
|
984
|
+
return re;
|
985
|
+
}
|
986
|
+
|
987
|
+
if (isFunction(source.cloneNode)) {
|
988
|
+
return source.cloneNode(true);
|
989
|
+
}
|
990
|
+
}
|
979
991
|
}
|
980
992
|
|
981
993
|
/**
|
@@ -1038,38 +1050,37 @@ function equals(o1, o2) {
|
|
1038
1050
|
if (o1 === null || o2 === null) return false;
|
1039
1051
|
if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
|
1040
1052
|
var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
|
1041
|
-
if (t1 == t2) {
|
1042
|
-
if (
|
1043
|
-
if (isArray(
|
1044
|
-
|
1045
|
-
|
1046
|
-
for (key = 0; key < length; key++) {
|
1047
|
-
if (!equals(o1[key], o2[key])) return false;
|
1048
|
-
}
|
1049
|
-
return true;
|
1050
|
-
}
|
1051
|
-
} else if (isDate(o1)) {
|
1052
|
-
if (!isDate(o2)) return false;
|
1053
|
-
return equals(o1.getTime(), o2.getTime());
|
1054
|
-
} else if (isRegExp(o1)) {
|
1055
|
-
return isRegExp(o2) ? o1.toString() == o2.toString() : false;
|
1056
|
-
} else {
|
1057
|
-
if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
|
1058
|
-
isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
|
1059
|
-
keySet = createMap();
|
1060
|
-
for (key in o1) {
|
1061
|
-
if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
|
1053
|
+
if (t1 == t2 && t1 == 'object') {
|
1054
|
+
if (isArray(o1)) {
|
1055
|
+
if (!isArray(o2)) return false;
|
1056
|
+
if ((length = o1.length) == o2.length) {
|
1057
|
+
for (key = 0; key < length; key++) {
|
1062
1058
|
if (!equals(o1[key], o2[key])) return false;
|
1063
|
-
keySet[key] = true;
|
1064
|
-
}
|
1065
|
-
for (key in o2) {
|
1066
|
-
if (!(key in keySet) &&
|
1067
|
-
key.charAt(0) !== '$' &&
|
1068
|
-
isDefined(o2[key]) &&
|
1069
|
-
!isFunction(o2[key])) return false;
|
1070
1059
|
}
|
1071
1060
|
return true;
|
1072
1061
|
}
|
1062
|
+
} else if (isDate(o1)) {
|
1063
|
+
if (!isDate(o2)) return false;
|
1064
|
+
return equals(o1.getTime(), o2.getTime());
|
1065
|
+
} else if (isRegExp(o1)) {
|
1066
|
+
if (!isRegExp(o2)) return false;
|
1067
|
+
return o1.toString() == o2.toString();
|
1068
|
+
} else {
|
1069
|
+
if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
|
1070
|
+
isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
|
1071
|
+
keySet = createMap();
|
1072
|
+
for (key in o1) {
|
1073
|
+
if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
|
1074
|
+
if (!equals(o1[key], o2[key])) return false;
|
1075
|
+
keySet[key] = true;
|
1076
|
+
}
|
1077
|
+
for (key in o2) {
|
1078
|
+
if (!(key in keySet) &&
|
1079
|
+
key.charAt(0) !== '$' &&
|
1080
|
+
isDefined(o2[key]) &&
|
1081
|
+
!isFunction(o2[key])) return false;
|
1082
|
+
}
|
1083
|
+
return true;
|
1073
1084
|
}
|
1074
1085
|
}
|
1075
1086
|
return false;
|
@@ -1246,7 +1257,7 @@ function toJsonReplacer(key, value) {
|
|
1246
1257
|
* @returns {string|undefined} JSON-ified string representing `obj`.
|
1247
1258
|
*/
|
1248
1259
|
function toJson(obj, pretty) {
|
1249
|
-
if (
|
1260
|
+
if (isUndefined(obj)) return undefined;
|
1250
1261
|
if (!isNumber(pretty)) {
|
1251
1262
|
pretty = pretty ? 2 : null;
|
1252
1263
|
}
|
@@ -1273,7 +1284,10 @@ function fromJson(json) {
|
|
1273
1284
|
}
|
1274
1285
|
|
1275
1286
|
|
1287
|
+
var ALL_COLONS = /:/g;
|
1276
1288
|
function timezoneToOffset(timezone, fallback) {
|
1289
|
+
// IE/Edge do not "understand" colon (`:`) in timezone
|
1290
|
+
timezone = timezone.replace(ALL_COLONS, '');
|
1277
1291
|
var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
|
1278
1292
|
return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
|
1279
1293
|
}
|
@@ -1288,8 +1302,9 @@ function addDateMinutes(date, minutes) {
|
|
1288
1302
|
|
1289
1303
|
function convertTimezoneToLocal(date, timezone, reverse) {
|
1290
1304
|
reverse = reverse ? -1 : 1;
|
1291
|
-
var
|
1292
|
-
|
1305
|
+
var dateTimezoneOffset = date.getTimezoneOffset();
|
1306
|
+
var timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
|
1307
|
+
return addDateMinutes(date, reverse * (timezoneOffset - dateTimezoneOffset));
|
1293
1308
|
}
|
1294
1309
|
|
1295
1310
|
|
@@ -1308,7 +1323,7 @@ function startingTag(element) {
|
|
1308
1323
|
return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
|
1309
1324
|
elemHtml.
|
1310
1325
|
match(/^(<[^>]+>)/)[1].
|
1311
|
-
replace(/^<([\w\-]+)/, function(match, nodeName) {
|
1326
|
+
replace(/^<([\w\-]+)/, function(match, nodeName) {return '<' + lowercase(nodeName);});
|
1312
1327
|
} catch (e) {
|
1313
1328
|
return lowercase(elemHtml);
|
1314
1329
|
}
|
@@ -1751,7 +1766,6 @@ function snake_case(name, separator) {
|
|
1751
1766
|
}
|
1752
1767
|
|
1753
1768
|
var bindJQueryFired = false;
|
1754
|
-
var skipDestroyOnNextJQueryCleanData;
|
1755
1769
|
function bindJQuery() {
|
1756
1770
|
var originalCleanData;
|
1757
1771
|
|
@@ -1785,15 +1799,11 @@ function bindJQuery() {
|
|
1785
1799
|
originalCleanData = jQuery.cleanData;
|
1786
1800
|
jQuery.cleanData = function(elems) {
|
1787
1801
|
var events;
|
1788
|
-
|
1789
|
-
|
1790
|
-
|
1791
|
-
|
1792
|
-
jQuery(elem).triggerHandler('$destroy');
|
1793
|
-
}
|
1802
|
+
for (var i = 0, elem; (elem = elems[i]) != null; i++) {
|
1803
|
+
events = jQuery._data(elem, "events");
|
1804
|
+
if (events && events.$destroy) {
|
1805
|
+
jQuery(elem).triggerHandler('$destroy');
|
1794
1806
|
}
|
1795
|
-
} else {
|
1796
|
-
skipDestroyOnNextJQueryCleanData = false;
|
1797
1807
|
}
|
1798
1808
|
originalCleanData(elems);
|
1799
1809
|
};
|
@@ -1987,7 +1997,7 @@ function setupModuleLoader(window) {
|
|
1987
1997
|
* unspecified then the module is being retrieved for further configuration.
|
1988
1998
|
* @param {Function=} configFn Optional configuration function for the module. Same as
|
1989
1999
|
* {@link angular.Module#config Module#config()}.
|
1990
|
-
* @returns {
|
2000
|
+
* @returns {angular.Module} new module with the {@link angular.Module} api.
|
1991
2001
|
*/
|
1992
2002
|
return function module(name, requires, configFn) {
|
1993
2003
|
var assertNotHasOwnProperty = function(name, context) {
|
@@ -2193,6 +2203,19 @@ function setupModuleLoader(window) {
|
|
2193
2203
|
*/
|
2194
2204
|
directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
|
2195
2205
|
|
2206
|
+
/**
|
2207
|
+
* @ngdoc method
|
2208
|
+
* @name angular.Module#component
|
2209
|
+
* @module ng
|
2210
|
+
* @param {string} name Name of the component in camel-case (i.e. myComp which will match as my-comp)
|
2211
|
+
* @param {Object} options Component definition object (a simplified
|
2212
|
+
* {@link ng.$compile#directive-definition-object directive definition object})
|
2213
|
+
*
|
2214
|
+
* @description
|
2215
|
+
* See {@link ng.$compileProvider#component $compileProvider.component()}.
|
2216
|
+
*/
|
2217
|
+
component: invokeLaterAndSetModuleName('$compileProvider', 'component'),
|
2218
|
+
|
2196
2219
|
/**
|
2197
2220
|
* @ngdoc method
|
2198
2221
|
* @name angular.Module#config
|
@@ -2344,11 +2367,14 @@ function toDebugString(obj) {
|
|
2344
2367
|
$AnchorScrollProvider,
|
2345
2368
|
$AnimateProvider,
|
2346
2369
|
$CoreAnimateCssProvider,
|
2370
|
+
$$CoreAnimateJsProvider,
|
2347
2371
|
$$CoreAnimateQueueProvider,
|
2348
|
-
$$
|
2372
|
+
$$AnimateRunnerFactoryProvider,
|
2373
|
+
$$AnimateAsyncRunFactoryProvider,
|
2349
2374
|
$BrowserProvider,
|
2350
2375
|
$CacheFactoryProvider,
|
2351
2376
|
$ControllerProvider,
|
2377
|
+
$DateProvider,
|
2352
2378
|
$DocumentProvider,
|
2353
2379
|
$ExceptionHandlerProvider,
|
2354
2380
|
$FilterProvider,
|
@@ -2398,11 +2424,11 @@ function toDebugString(obj) {
|
|
2398
2424
|
* - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
|
2399
2425
|
*/
|
2400
2426
|
var version = {
|
2401
|
-
full: '1.
|
2427
|
+
full: '1.5.0', // all of these placeholder strings will be replaced by grunt's
|
2402
2428
|
major: 1, // package task
|
2403
|
-
minor:
|
2404
|
-
dot:
|
2405
|
-
codeName: '
|
2429
|
+
minor: 5,
|
2430
|
+
dot: 0,
|
2431
|
+
codeName: 'ennoblement-facilitation'
|
2406
2432
|
};
|
2407
2433
|
|
2408
2434
|
|
@@ -2504,8 +2530,10 @@ function publishExternalAPI(angular) {
|
|
2504
2530
|
$anchorScroll: $AnchorScrollProvider,
|
2505
2531
|
$animate: $AnimateProvider,
|
2506
2532
|
$animateCss: $CoreAnimateCssProvider,
|
2533
|
+
$$animateJs: $$CoreAnimateJsProvider,
|
2507
2534
|
$$animateQueue: $$CoreAnimateQueueProvider,
|
2508
|
-
$$AnimateRunner: $$
|
2535
|
+
$$AnimateRunner: $$AnimateRunnerFactoryProvider,
|
2536
|
+
$$animateAsyncRun: $$AnimateAsyncRunFactoryProvider,
|
2509
2537
|
$browser: $BrowserProvider,
|
2510
2538
|
$cacheFactory: $CacheFactoryProvider,
|
2511
2539
|
$controller: $ControllerProvider,
|
@@ -2576,16 +2604,22 @@ function publishExternalAPI(angular) {
|
|
2576
2604
|
*
|
2577
2605
|
* If jQuery is available, `angular.element` is an alias for the
|
2578
2606
|
* [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
|
2579
|
-
* delegates to Angular's built-in subset of jQuery, called "jQuery lite" or
|
2607
|
+
* delegates to Angular's built-in subset of jQuery, called "jQuery lite" or **jqLite**.
|
2580
2608
|
*
|
2581
|
-
*
|
2582
|
-
* Angular to manipulate the DOM in a cross-browser compatible way.
|
2583
|
-
* commonly needed functionality with the goal of having a very small footprint
|
2609
|
+
* jqLite is a tiny, API-compatible subset of jQuery that allows
|
2610
|
+
* Angular to manipulate the DOM in a cross-browser compatible way. jqLite implements only the most
|
2611
|
+
* commonly needed functionality with the goal of having a very small footprint.
|
2584
2612
|
*
|
2585
|
-
* To use `jQuery`, simply ensure it is loaded before the `angular.js` file.
|
2613
|
+
* To use `jQuery`, simply ensure it is loaded before the `angular.js` file. You can also use the
|
2614
|
+
* {@link ngJq `ngJq`} directive to specify that jqlite should be used over jQuery, or to use a
|
2615
|
+
* specific version of jQuery if multiple versions exist on the page.
|
2586
2616
|
*
|
2587
|
-
* <div class="alert">**Note:**
|
2588
|
-
* jqLite
|
2617
|
+
* <div class="alert alert-info">**Note:** All element references in Angular are always wrapped with jQuery or
|
2618
|
+
* jqLite (such as the element argument in a directive's compile / link function). They are never raw DOM references.</div>
|
2619
|
+
*
|
2620
|
+
* <div class="alert alert-warning">**Note:** Keep in mind that this function will not find elements
|
2621
|
+
* by tag name / CSS selector. For lookups by tag name, try instead `angular.element(document).find(...)`
|
2622
|
+
* or `$document.find()`, or use the standard DOM APIs, e.g. `document.querySelectorAll()`.</div>
|
2589
2623
|
*
|
2590
2624
|
* ## Angular's jqLite
|
2591
2625
|
* jqLite provides only the following jQuery methods:
|
@@ -2598,7 +2632,8 @@ function publishExternalAPI(angular) {
|
|
2598
2632
|
* - [`children()`](http://api.jquery.com/children/) - Does not support selectors
|
2599
2633
|
* - [`clone()`](http://api.jquery.com/clone/)
|
2600
2634
|
* - [`contents()`](http://api.jquery.com/contents/)
|
2601
|
-
* - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`.
|
2635
|
+
* - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`.
|
2636
|
+
* As a setter, does not convert numbers to strings or append 'px', and also does not have automatic property prefixing.
|
2602
2637
|
* - [`data()`](http://api.jquery.com/data/)
|
2603
2638
|
* - [`detach()`](http://api.jquery.com/detach/)
|
2604
2639
|
* - [`empty()`](http://api.jquery.com/empty/)
|
@@ -2732,6 +2767,12 @@ function jqLiteHasData(node) {
|
|
2732
2767
|
return false;
|
2733
2768
|
}
|
2734
2769
|
|
2770
|
+
function jqLiteCleanData(nodes) {
|
2771
|
+
for (var i = 0, ii = nodes.length; i < ii; i++) {
|
2772
|
+
jqLiteRemoveData(nodes[i]);
|
2773
|
+
}
|
2774
|
+
}
|
2775
|
+
|
2735
2776
|
function jqLiteBuildFragment(html, context) {
|
2736
2777
|
var tmp, tag, wrap,
|
2737
2778
|
fragment = context.createDocumentFragment(),
|
@@ -2784,6 +2825,16 @@ function jqLiteParseHTML(html, context) {
|
|
2784
2825
|
return [];
|
2785
2826
|
}
|
2786
2827
|
|
2828
|
+
function jqLiteWrapNode(node, wrapper) {
|
2829
|
+
var parent = node.parentNode;
|
2830
|
+
|
2831
|
+
if (parent) {
|
2832
|
+
parent.replaceChild(wrapper, node);
|
2833
|
+
}
|
2834
|
+
|
2835
|
+
wrapper.appendChild(node);
|
2836
|
+
}
|
2837
|
+
|
2787
2838
|
|
2788
2839
|
// IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
|
2789
2840
|
var jqLiteContains = Node.prototype.contains || function(arg) {
|
@@ -3034,7 +3085,7 @@ function jqLiteRemove(element, keepData) {
|
|
3034
3085
|
function jqLiteDocumentLoaded(action, win) {
|
3035
3086
|
win = win || window;
|
3036
3087
|
if (win.document.readyState === 'complete') {
|
3037
|
-
// Force the action to be run async for consistent
|
3088
|
+
// Force the action to be run async for consistent behavior
|
3038
3089
|
// from the action's point of view
|
3039
3090
|
// i.e. it will definitely not be in a $apply
|
3040
3091
|
win.setTimeout(action);
|
@@ -3120,7 +3171,8 @@ function getAliasedAttrName(name) {
|
|
3120
3171
|
forEach({
|
3121
3172
|
data: jqLiteData,
|
3122
3173
|
removeData: jqLiteRemoveData,
|
3123
|
-
hasData: jqLiteHasData
|
3174
|
+
hasData: jqLiteHasData,
|
3175
|
+
cleanData: jqLiteCleanData
|
3124
3176
|
}, function(fn, name) {
|
3125
3177
|
JQLite[name] = fn;
|
3126
3178
|
});
|
@@ -3475,12 +3527,7 @@ forEach({
|
|
3475
3527
|
},
|
3476
3528
|
|
3477
3529
|
wrap: function(element, wrapNode) {
|
3478
|
-
|
3479
|
-
var parent = element.parentNode;
|
3480
|
-
if (parent) {
|
3481
|
-
parent.replaceChild(wrapNode, element);
|
3482
|
-
}
|
3483
|
-
wrapNode.appendChild(element);
|
3530
|
+
jqLiteWrapNode(element, jqLite(wrapNode).eq(0).clone()[0]);
|
3484
3531
|
},
|
3485
3532
|
|
3486
3533
|
remove: jqLiteRemove,
|
@@ -3758,17 +3805,23 @@ var $$HashMapProvider = [function() {
|
|
3758
3805
|
* Implicit module which gets automatically added to each {@link auto.$injector $injector}.
|
3759
3806
|
*/
|
3760
3807
|
|
3808
|
+
var ARROW_ARG = /^([^\(]+?)=>/;
|
3761
3809
|
var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m;
|
3762
3810
|
var FN_ARG_SPLIT = /,/;
|
3763
3811
|
var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
|
3764
3812
|
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
|
3765
3813
|
var $injectorMinErr = minErr('$injector');
|
3766
3814
|
|
3815
|
+
function extractArgs(fn) {
|
3816
|
+
var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
|
3817
|
+
args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS);
|
3818
|
+
return args;
|
3819
|
+
}
|
3820
|
+
|
3767
3821
|
function anonFn(fn) {
|
3768
3822
|
// For anonymous functions, showing at the very least the function signature can help in
|
3769
3823
|
// debugging.
|
3770
|
-
var
|
3771
|
-
args = fnText.match(FN_ARGS);
|
3824
|
+
var args = extractArgs(fn);
|
3772
3825
|
if (args) {
|
3773
3826
|
return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
|
3774
3827
|
}
|
@@ -3777,7 +3830,6 @@ function anonFn(fn) {
|
|
3777
3830
|
|
3778
3831
|
function annotate(fn, strictDi, name) {
|
3779
3832
|
var $inject,
|
3780
|
-
fnText,
|
3781
3833
|
argDecl,
|
3782
3834
|
last;
|
3783
3835
|
|
@@ -3792,8 +3844,7 @@ function annotate(fn, strictDi, name) {
|
|
3792
3844
|
throw $injectorMinErr('strictdi',
|
3793
3845
|
'{0} is not using explicit annotation and cannot be invoked in strict mode', name);
|
3794
3846
|
}
|
3795
|
-
|
3796
|
-
argDecl = fnText.match(FN_ARGS);
|
3847
|
+
argDecl = extractArgs(fn);
|
3797
3848
|
forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
|
3798
3849
|
arg.replace(FN_ARG, function(all, underscore, name) {
|
3799
3850
|
$inject.push(name);
|
@@ -4183,8 +4234,20 @@ function annotate(fn, strictDi, name) {
|
|
4183
4234
|
*
|
4184
4235
|
* Register a **service constructor**, which will be invoked with `new` to create the service
|
4185
4236
|
* instance.
|
4186
|
-
* This is short for registering a service where its provider's `$get` property is
|
4187
|
-
*
|
4237
|
+
* This is short for registering a service where its provider's `$get` property is a factory
|
4238
|
+
* function that returns an instance instantiated by the injector from the service constructor
|
4239
|
+
* function.
|
4240
|
+
*
|
4241
|
+
* Internally it looks a bit like this:
|
4242
|
+
*
|
4243
|
+
* ```
|
4244
|
+
* {
|
4245
|
+
* $get: function() {
|
4246
|
+
* return $injector.instantiate(constructor);
|
4247
|
+
* }
|
4248
|
+
* }
|
4249
|
+
* ```
|
4250
|
+
*
|
4188
4251
|
*
|
4189
4252
|
* You should use {@link auto.$provide#service $provide.service(class)} if you define your service
|
4190
4253
|
* as a type/class.
|
@@ -4285,7 +4348,7 @@ function annotate(fn, strictDi, name) {
|
|
4285
4348
|
* @description
|
4286
4349
|
*
|
4287
4350
|
* Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
|
4288
|
-
* intercepts the creation of a service, allowing it to override or modify the
|
4351
|
+
* intercepts the creation of a service, allowing it to override or modify the behavior of the
|
4289
4352
|
* service. The object returned by the decorator may be the original service, or a new service
|
4290
4353
|
* object which replaces or wraps and delegates to the original service.
|
4291
4354
|
*
|
@@ -4334,14 +4397,19 @@ function createInjector(modulesToLoad, strictDi) {
|
|
4334
4397
|
throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
|
4335
4398
|
})),
|
4336
4399
|
instanceCache = {},
|
4337
|
-
|
4400
|
+
protoInstanceInjector =
|
4338
4401
|
createInternalInjector(instanceCache, function(serviceName, caller) {
|
4339
4402
|
var provider = providerInjector.get(serviceName + providerSuffix, caller);
|
4340
|
-
return instanceInjector.invoke(
|
4341
|
-
|
4342
|
-
|
4403
|
+
return instanceInjector.invoke(
|
4404
|
+
provider.$get, provider, undefined, serviceName);
|
4405
|
+
}),
|
4406
|
+
instanceInjector = protoInstanceInjector;
|
4343
4407
|
|
4344
|
-
|
4408
|
+
providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) };
|
4409
|
+
var runBlocks = loadModules(modulesToLoad);
|
4410
|
+
instanceInjector = protoInstanceInjector.get('$injector');
|
4411
|
+
instanceInjector.strictDi = strictDi;
|
4412
|
+
forEach(runBlocks, function(fn) { if (fn) instanceInjector.invoke(fn); });
|
4345
4413
|
|
4346
4414
|
return instanceInjector;
|
4347
4415
|
|
@@ -4491,48 +4559,67 @@ function createInjector(modulesToLoad, strictDi) {
|
|
4491
4559
|
}
|
4492
4560
|
}
|
4493
4561
|
|
4494
|
-
function invoke(fn, self, locals, serviceName) {
|
4495
|
-
if (typeof locals === 'string') {
|
4496
|
-
serviceName = locals;
|
4497
|
-
locals = null;
|
4498
|
-
}
|
4499
4562
|
|
4563
|
+
function injectionArgs(fn, locals, serviceName) {
|
4500
4564
|
var args = [],
|
4501
|
-
$inject = createInjector.$$annotate(fn, strictDi, serviceName)
|
4502
|
-
length, i,
|
4503
|
-
key;
|
4565
|
+
$inject = createInjector.$$annotate(fn, strictDi, serviceName);
|
4504
4566
|
|
4505
|
-
for (i = 0, length = $inject.length; i < length; i++) {
|
4506
|
-
key = $inject[i];
|
4567
|
+
for (var i = 0, length = $inject.length; i < length; i++) {
|
4568
|
+
var key = $inject[i];
|
4507
4569
|
if (typeof key !== 'string') {
|
4508
4570
|
throw $injectorMinErr('itkn',
|
4509
4571
|
'Incorrect injection token! Expected service name as string, got {0}', key);
|
4510
4572
|
}
|
4511
|
-
args.push(
|
4512
|
-
|
4513
|
-
|
4514
|
-
|
4515
|
-
|
4573
|
+
args.push(locals && locals.hasOwnProperty(key) ? locals[key] :
|
4574
|
+
getService(key, serviceName));
|
4575
|
+
}
|
4576
|
+
return args;
|
4577
|
+
}
|
4578
|
+
|
4579
|
+
function isClass(func) {
|
4580
|
+
// IE 9-11 do not support classes and IE9 leaks with the code below.
|
4581
|
+
if (msie <= 11) {
|
4582
|
+
return false;
|
4516
4583
|
}
|
4584
|
+
// Workaround for MS Edge.
|
4585
|
+
// Check https://connect.microsoft.com/IE/Feedback/Details/2211653
|
4586
|
+
return typeof func === 'function'
|
4587
|
+
&& /^(?:class\s|constructor\()/.test(Function.prototype.toString.call(func));
|
4588
|
+
}
|
4589
|
+
|
4590
|
+
function invoke(fn, self, locals, serviceName) {
|
4591
|
+
if (typeof locals === 'string') {
|
4592
|
+
serviceName = locals;
|
4593
|
+
locals = null;
|
4594
|
+
}
|
4595
|
+
|
4596
|
+
var args = injectionArgs(fn, locals, serviceName);
|
4517
4597
|
if (isArray(fn)) {
|
4518
|
-
fn = fn[length];
|
4598
|
+
fn = fn[fn.length - 1];
|
4519
4599
|
}
|
4520
4600
|
|
4521
|
-
|
4522
|
-
|
4523
|
-
|
4601
|
+
if (!isClass(fn)) {
|
4602
|
+
// http://jsperf.com/angularjs-invoke-apply-vs-switch
|
4603
|
+
// #5388
|
4604
|
+
return fn.apply(self, args);
|
4605
|
+
} else {
|
4606
|
+
args.unshift(null);
|
4607
|
+
return new (Function.prototype.bind.apply(fn, args))();
|
4608
|
+
}
|
4524
4609
|
}
|
4525
4610
|
|
4611
|
+
|
4526
4612
|
function instantiate(Type, locals, serviceName) {
|
4527
4613
|
// Check if Type is annotated and use just the given function at n-1 as parameter
|
4528
4614
|
// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
|
4529
|
-
|
4530
|
-
var
|
4531
|
-
|
4532
|
-
|
4533
|
-
return
|
4615
|
+
var ctor = (isArray(Type) ? Type[Type.length - 1] : Type);
|
4616
|
+
var args = injectionArgs(Type, locals, serviceName);
|
4617
|
+
// Empty object at position 0 is ignored for invocation with `new`, but required.
|
4618
|
+
args.unshift(null);
|
4619
|
+
return new (Function.prototype.bind.apply(ctor, args))();
|
4534
4620
|
}
|
4535
4621
|
|
4622
|
+
|
4536
4623
|
return {
|
4537
4624
|
invoke: invoke,
|
4538
4625
|
instantiate: instantiate,
|
@@ -4871,27 +4958,8 @@ function prepareAnimateOptions(options) {
|
|
4871
4958
|
: {};
|
4872
4959
|
}
|
4873
4960
|
|
4874
|
-
var $$
|
4875
|
-
this.$get =
|
4876
|
-
function AnimateRunner() {}
|
4877
|
-
AnimateRunner.all = noop;
|
4878
|
-
AnimateRunner.chain = noop;
|
4879
|
-
AnimateRunner.prototype = {
|
4880
|
-
end: noop,
|
4881
|
-
cancel: noop,
|
4882
|
-
resume: noop,
|
4883
|
-
pause: noop,
|
4884
|
-
complete: noop,
|
4885
|
-
then: function(pass, fail) {
|
4886
|
-
return $q(function(resolve) {
|
4887
|
-
$$rAF(function() {
|
4888
|
-
resolve();
|
4889
|
-
});
|
4890
|
-
}).then(pass, fail);
|
4891
|
-
}
|
4892
|
-
};
|
4893
|
-
return AnimateRunner;
|
4894
|
-
}];
|
4961
|
+
var $$CoreAnimateJsProvider = function() {
|
4962
|
+
this.$get = function() {};
|
4895
4963
|
};
|
4896
4964
|
|
4897
4965
|
// this is prefixed with Core since it conflicts with
|
@@ -4919,7 +4987,12 @@ var $$CoreAnimateQueueProvider = function() {
|
|
4919
4987
|
addRemoveClassesPostDigest(element, options.addClass, options.removeClass);
|
4920
4988
|
}
|
4921
4989
|
|
4922
|
-
|
4990
|
+
var runner = new $$AnimateRunner(); // jshint ignore:line
|
4991
|
+
|
4992
|
+
// since there are no animations to run the runner needs to be
|
4993
|
+
// notified that the animation call is complete.
|
4994
|
+
runner.complete();
|
4995
|
+
return runner;
|
4923
4996
|
}
|
4924
4997
|
};
|
4925
4998
|
|
@@ -5161,8 +5234,8 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
5161
5234
|
* // remove all the animation event listeners listening for `enter` on the given element and its children
|
5162
5235
|
* $animate.off('enter', container);
|
5163
5236
|
*
|
5164
|
-
* // remove the event listener function provided by `
|
5165
|
-
* // to listen for `enter` on the given `
|
5237
|
+
* // remove the event listener function provided by `callback` that is set
|
5238
|
+
* // to listen for `enter` on the given `container` as well as its children
|
5166
5239
|
* $animate.off('enter', container, callback);
|
5167
5240
|
* ```
|
5168
5241
|
*
|
@@ -5384,17 +5457,30 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
5384
5457
|
* @kind function
|
5385
5458
|
*
|
5386
5459
|
* @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.
|
5387
|
-
* If any detected CSS transition, keyframe or JavaScript matches the provided className value then the animation will take
|
5388
|
-
* on the provided styles. For example, if a transition animation is set for the given
|
5389
|
-
* to styles will be applied alongside the given transition. If
|
5390
|
-
*
|
5460
|
+
* If any detected CSS transition, keyframe or JavaScript matches the provided className value, then the animation will take
|
5461
|
+
* on the provided styles. For example, if a transition animation is set for the given classNamem, then the provided `from` and
|
5462
|
+
* `to` styles will be applied alongside the given transition. If the CSS style provided in `from` does not have a corresponding
|
5463
|
+
* style in `to`, the style in `from` is applied immediately, and no animation is run.
|
5464
|
+
* If a JavaScript animation is detected then the provided styles will be given in as function parameters into the `animate`
|
5465
|
+
* method (or as part of the `options` parameter):
|
5466
|
+
*
|
5467
|
+
* ```js
|
5468
|
+
* ngModule.animation('.my-inline-animation', function() {
|
5469
|
+
* return {
|
5470
|
+
* animate : function(element, from, to, done, options) {
|
5471
|
+
* //animation
|
5472
|
+
* done();
|
5473
|
+
* }
|
5474
|
+
* }
|
5475
|
+
* });
|
5476
|
+
* ```
|
5391
5477
|
*
|
5392
5478
|
* @param {DOMElement} element the element which the CSS styles will be applied to
|
5393
5479
|
* @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation.
|
5394
5480
|
* @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.
|
5395
5481
|
* @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
|
5396
5482
|
* this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
|
5397
|
-
* (Note that if no animation is detected then this value will not be
|
5483
|
+
* (Note that if no animation is detected then this value will not be applied to the element.)
|
5398
5484
|
* @param {object=} options an optional collection of options/styles that will be applied to the element
|
5399
5485
|
*
|
5400
5486
|
* @return {Promise} the animation callback promise
|
@@ -5412,6 +5498,190 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
5412
5498
|
}];
|
5413
5499
|
}];
|
5414
5500
|
|
5501
|
+
var $$AnimateAsyncRunFactoryProvider = function() {
|
5502
|
+
this.$get = ['$$rAF', function($$rAF) {
|
5503
|
+
var waitQueue = [];
|
5504
|
+
|
5505
|
+
function waitForTick(fn) {
|
5506
|
+
waitQueue.push(fn);
|
5507
|
+
if (waitQueue.length > 1) return;
|
5508
|
+
$$rAF(function() {
|
5509
|
+
for (var i = 0; i < waitQueue.length; i++) {
|
5510
|
+
waitQueue[i]();
|
5511
|
+
}
|
5512
|
+
waitQueue = [];
|
5513
|
+
});
|
5514
|
+
}
|
5515
|
+
|
5516
|
+
return function() {
|
5517
|
+
var passed = false;
|
5518
|
+
waitForTick(function() {
|
5519
|
+
passed = true;
|
5520
|
+
});
|
5521
|
+
return function(callback) {
|
5522
|
+
passed ? callback() : waitForTick(callback);
|
5523
|
+
};
|
5524
|
+
};
|
5525
|
+
}];
|
5526
|
+
};
|
5527
|
+
|
5528
|
+
var $$AnimateRunnerFactoryProvider = function() {
|
5529
|
+
this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$document', '$timeout',
|
5530
|
+
function($q, $sniffer, $$animateAsyncRun, $document, $timeout) {
|
5531
|
+
|
5532
|
+
var INITIAL_STATE = 0;
|
5533
|
+
var DONE_PENDING_STATE = 1;
|
5534
|
+
var DONE_COMPLETE_STATE = 2;
|
5535
|
+
|
5536
|
+
AnimateRunner.chain = function(chain, callback) {
|
5537
|
+
var index = 0;
|
5538
|
+
|
5539
|
+
next();
|
5540
|
+
function next() {
|
5541
|
+
if (index === chain.length) {
|
5542
|
+
callback(true);
|
5543
|
+
return;
|
5544
|
+
}
|
5545
|
+
|
5546
|
+
chain[index](function(response) {
|
5547
|
+
if (response === false) {
|
5548
|
+
callback(false);
|
5549
|
+
return;
|
5550
|
+
}
|
5551
|
+
index++;
|
5552
|
+
next();
|
5553
|
+
});
|
5554
|
+
}
|
5555
|
+
};
|
5556
|
+
|
5557
|
+
AnimateRunner.all = function(runners, callback) {
|
5558
|
+
var count = 0;
|
5559
|
+
var status = true;
|
5560
|
+
forEach(runners, function(runner) {
|
5561
|
+
runner.done(onProgress);
|
5562
|
+
});
|
5563
|
+
|
5564
|
+
function onProgress(response) {
|
5565
|
+
status = status && response;
|
5566
|
+
if (++count === runners.length) {
|
5567
|
+
callback(status);
|
5568
|
+
}
|
5569
|
+
}
|
5570
|
+
};
|
5571
|
+
|
5572
|
+
function AnimateRunner(host) {
|
5573
|
+
this.setHost(host);
|
5574
|
+
|
5575
|
+
var rafTick = $$animateAsyncRun();
|
5576
|
+
var timeoutTick = function(fn) {
|
5577
|
+
$timeout(fn, 0, false);
|
5578
|
+
};
|
5579
|
+
|
5580
|
+
this._doneCallbacks = [];
|
5581
|
+
this._tick = function(fn) {
|
5582
|
+
var doc = $document[0];
|
5583
|
+
|
5584
|
+
// the document may not be ready or attached
|
5585
|
+
// to the module for some internal tests
|
5586
|
+
if (doc && doc.hidden) {
|
5587
|
+
timeoutTick(fn);
|
5588
|
+
} else {
|
5589
|
+
rafTick(fn);
|
5590
|
+
}
|
5591
|
+
};
|
5592
|
+
this._state = 0;
|
5593
|
+
}
|
5594
|
+
|
5595
|
+
AnimateRunner.prototype = {
|
5596
|
+
setHost: function(host) {
|
5597
|
+
this.host = host || {};
|
5598
|
+
},
|
5599
|
+
|
5600
|
+
done: function(fn) {
|
5601
|
+
if (this._state === DONE_COMPLETE_STATE) {
|
5602
|
+
fn();
|
5603
|
+
} else {
|
5604
|
+
this._doneCallbacks.push(fn);
|
5605
|
+
}
|
5606
|
+
},
|
5607
|
+
|
5608
|
+
progress: noop,
|
5609
|
+
|
5610
|
+
getPromise: function() {
|
5611
|
+
if (!this.promise) {
|
5612
|
+
var self = this;
|
5613
|
+
this.promise = $q(function(resolve, reject) {
|
5614
|
+
self.done(function(status) {
|
5615
|
+
status === false ? reject() : resolve();
|
5616
|
+
});
|
5617
|
+
});
|
5618
|
+
}
|
5619
|
+
return this.promise;
|
5620
|
+
},
|
5621
|
+
|
5622
|
+
then: function(resolveHandler, rejectHandler) {
|
5623
|
+
return this.getPromise().then(resolveHandler, rejectHandler);
|
5624
|
+
},
|
5625
|
+
|
5626
|
+
'catch': function(handler) {
|
5627
|
+
return this.getPromise()['catch'](handler);
|
5628
|
+
},
|
5629
|
+
|
5630
|
+
'finally': function(handler) {
|
5631
|
+
return this.getPromise()['finally'](handler);
|
5632
|
+
},
|
5633
|
+
|
5634
|
+
pause: function() {
|
5635
|
+
if (this.host.pause) {
|
5636
|
+
this.host.pause();
|
5637
|
+
}
|
5638
|
+
},
|
5639
|
+
|
5640
|
+
resume: function() {
|
5641
|
+
if (this.host.resume) {
|
5642
|
+
this.host.resume();
|
5643
|
+
}
|
5644
|
+
},
|
5645
|
+
|
5646
|
+
end: function() {
|
5647
|
+
if (this.host.end) {
|
5648
|
+
this.host.end();
|
5649
|
+
}
|
5650
|
+
this._resolve(true);
|
5651
|
+
},
|
5652
|
+
|
5653
|
+
cancel: function() {
|
5654
|
+
if (this.host.cancel) {
|
5655
|
+
this.host.cancel();
|
5656
|
+
}
|
5657
|
+
this._resolve(false);
|
5658
|
+
},
|
5659
|
+
|
5660
|
+
complete: function(response) {
|
5661
|
+
var self = this;
|
5662
|
+
if (self._state === INITIAL_STATE) {
|
5663
|
+
self._state = DONE_PENDING_STATE;
|
5664
|
+
self._tick(function() {
|
5665
|
+
self._resolve(response);
|
5666
|
+
});
|
5667
|
+
}
|
5668
|
+
},
|
5669
|
+
|
5670
|
+
_resolve: function(response) {
|
5671
|
+
if (this._state !== DONE_COMPLETE_STATE) {
|
5672
|
+
forEach(this._doneCallbacks, function(fn) {
|
5673
|
+
fn(response);
|
5674
|
+
});
|
5675
|
+
this._doneCallbacks.length = 0;
|
5676
|
+
this._state = DONE_COMPLETE_STATE;
|
5677
|
+
}
|
5678
|
+
}
|
5679
|
+
};
|
5680
|
+
|
5681
|
+
return AnimateRunner;
|
5682
|
+
}];
|
5683
|
+
};
|
5684
|
+
|
5415
5685
|
/**
|
5416
5686
|
* @ngdoc service
|
5417
5687
|
* @name $animateCss
|
@@ -5424,37 +5694,18 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
5424
5694
|
* Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}.
|
5425
5695
|
*/
|
5426
5696
|
var $CoreAnimateCssProvider = function() {
|
5427
|
-
this.$get = ['$$rAF', '$q', function($$rAF, $q) {
|
5697
|
+
this.$get = ['$$rAF', '$q', '$$AnimateRunner', function($$rAF, $q, $$AnimateRunner) {
|
5428
5698
|
|
5429
|
-
|
5430
|
-
|
5431
|
-
|
5432
|
-
|
5433
|
-
|
5434
|
-
|
5435
|
-
|
5436
|
-
|
5437
|
-
cancel: function() {
|
5438
|
-
this.done(true);
|
5439
|
-
},
|
5440
|
-
getPromise: function() {
|
5441
|
-
if (!this.defer) {
|
5442
|
-
this.defer = $q.defer();
|
5443
|
-
}
|
5444
|
-
return this.defer.promise;
|
5445
|
-
},
|
5446
|
-
then: function(f1,f2) {
|
5447
|
-
return this.getPromise().then(f1,f2);
|
5448
|
-
},
|
5449
|
-
'catch': function(f1) {
|
5450
|
-
return this.getPromise()['catch'](f1);
|
5451
|
-
},
|
5452
|
-
'finally': function(f1) {
|
5453
|
-
return this.getPromise()['finally'](f1);
|
5699
|
+
return function(element, initialOptions) {
|
5700
|
+
// all of the animation functions should create
|
5701
|
+
// a copy of the options data, however, if a
|
5702
|
+
// parent service has already created a copy then
|
5703
|
+
// we should stick to using that
|
5704
|
+
var options = initialOptions || {};
|
5705
|
+
if (!options.$$prepared) {
|
5706
|
+
options = copy(options);
|
5454
5707
|
}
|
5455
|
-
};
|
5456
5708
|
|
5457
|
-
return function(element, options) {
|
5458
5709
|
// there is no point in applying the styles since
|
5459
5710
|
// there is no animation that goes on at all in
|
5460
5711
|
// this version of $animateCss.
|
@@ -5467,7 +5718,8 @@ var $CoreAnimateCssProvider = function() {
|
|
5467
5718
|
options.from = null;
|
5468
5719
|
}
|
5469
5720
|
|
5470
|
-
|
5721
|
+
/* jshint newcap: false */
|
5722
|
+
var closed, runner = new $$AnimateRunner();
|
5471
5723
|
return {
|
5472
5724
|
start: run,
|
5473
5725
|
end: run
|
@@ -5475,16 +5727,16 @@ var $CoreAnimateCssProvider = function() {
|
|
5475
5727
|
|
5476
5728
|
function run() {
|
5477
5729
|
$$rAF(function() {
|
5478
|
-
|
5730
|
+
applyAnimationContents();
|
5479
5731
|
if (!closed) {
|
5480
|
-
runner.
|
5732
|
+
runner.complete();
|
5481
5733
|
}
|
5482
5734
|
closed = true;
|
5483
5735
|
});
|
5484
5736
|
return runner;
|
5485
5737
|
}
|
5486
5738
|
|
5487
|
-
function
|
5739
|
+
function applyAnimationContents() {
|
5488
5740
|
if (options.addClass) {
|
5489
5741
|
element.addClass(options.addClass);
|
5490
5742
|
options.addClass = null;
|
@@ -6392,7 +6644,7 @@ function $TemplateCacheProvider() {
|
|
6392
6644
|
* When this property is set to true, the HTML compiler will collect DOM nodes between
|
6393
6645
|
* nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
|
6394
6646
|
* together as the directive elements. It is recommended that this feature be used on directives
|
6395
|
-
* which are not strictly
|
6647
|
+
* which are not strictly behavioral (such as {@link ngClick}), and which
|
6396
6648
|
* do not manipulate or replace child nodes (such as {@link ngInclude}).
|
6397
6649
|
*
|
6398
6650
|
* #### `priority`
|
@@ -6430,35 +6682,62 @@ function $TemplateCacheProvider() {
|
|
6430
6682
|
* is bound to the parent scope, via matching attributes on the directive's element:
|
6431
6683
|
*
|
6432
6684
|
* * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
|
6433
|
-
* always a string since DOM attributes are strings. If no `attr` name is specified
|
6434
|
-
* attribute name is assumed to be the same as the local name.
|
6435
|
-
*
|
6436
|
-
*
|
6437
|
-
*
|
6438
|
-
*
|
6439
|
-
*
|
6440
|
-
*
|
6441
|
-
*
|
6442
|
-
*
|
6443
|
-
* name
|
6444
|
-
*
|
6445
|
-
*
|
6685
|
+
* always a string since DOM attributes are strings. If no `attr` name is specified then the
|
6686
|
+
* attribute name is assumed to be the same as the local name. Given `<my-component
|
6687
|
+
* my-attr="hello {{name}}">` and the isolate scope definition `scope: { localName:'@myAttr' }`,
|
6688
|
+
* the directive's scope property `localName` will reflect the interpolated value of `hello
|
6689
|
+
* {{name}}`. As the `name` attribute changes so will the `localName` property on the directive's
|
6690
|
+
* scope. The `name` is read from the parent scope (not the directive's scope).
|
6691
|
+
*
|
6692
|
+
* * `=` or `=attr` - set up a bidirectional binding between a local scope property and an expression
|
6693
|
+
* passed via the attribute `attr`. The expression is evaluated in the context of the parent scope.
|
6694
|
+
* If no `attr` name is specified then the attribute name is assumed to be the same as the local
|
6695
|
+
* name. Given `<my-component my-attr="parentModel">` and the isolate scope definition `scope: {
|
6696
|
+
* localModel: '=myAttr' }`, the property `localModel` on the directive's scope will reflect the
|
6697
|
+
* value of `parentModel` on the parent scope. Changes to `parentModel` will be reflected in
|
6698
|
+
* `localModel` and vice versa. Optional attributes should be marked as such with a question mark:
|
6699
|
+
* `=?` or `=?attr`. If the binding expression is non-assignable, or if the attribute isn't
|
6700
|
+
* optional and doesn't exist, an exception ({@link error/$compile/nonassign `$compile:nonassign`})
|
6701
|
+
* will be thrown upon discovering changes to the local value, since it will be impossible to sync
|
6702
|
+
* them back to the parent scope. By default, the {@link ng.$rootScope.Scope#$watch `$watch`}
|
6703
|
+
* method is used for tracking changes, and the equality check is based on object identity.
|
6704
|
+
* However, if an object literal or an array literal is passed as the binding expression, the
|
6705
|
+
* equality check is done by value (using the {@link angular.equals} function). It's also possible
|
6706
|
+
* to watch the evaluated value shallowly with {@link ng.$rootScope.Scope#$watchCollection
|
6707
|
+
* `$watchCollection`}: use `=*` or `=*attr` (`=*?` or `=*?attr` if the attribute is optional).
|
6708
|
+
*
|
6709
|
+
* * `<` or `<attr` - set up a one-way (one-directional) binding between a local scope property and an
|
6710
|
+
* expression passed via the attribute `attr`. The expression is evaluated in the context of the
|
6711
|
+
* parent scope. If no `attr` name is specified then the attribute name is assumed to be the same as the
|
6712
|
+
* local name. You can also make the binding optional by adding `?`: `<?` or `<?attr`.
|
6713
|
+
*
|
6714
|
+
* For example, given `<my-component my-attr="parentModel">` and directive definition of
|
6715
|
+
* `scope: { localModel:'<myAttr' }`, then the isolated scope property `localModel` will reflect the
|
6446
6716
|
* value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
|
6447
|
-
* in `localModel
|
6448
|
-
*
|
6449
|
-
*
|
6450
|
-
*
|
6451
|
-
*
|
6452
|
-
*
|
6453
|
-
*
|
6454
|
-
*
|
6455
|
-
*
|
6456
|
-
*
|
6457
|
-
*
|
6458
|
-
*
|
6459
|
-
*
|
6460
|
-
*
|
6461
|
-
*
|
6717
|
+
* in `localModel`, but changes in `localModel` will not reflect in `parentModel`. There are however
|
6718
|
+
* two caveats:
|
6719
|
+
* 1. one-way binding does not copy the value from the parent to the isolate scope, it simply
|
6720
|
+
* sets the same value. That means if your bound value is an object, changes to its properties
|
6721
|
+
* in the isolated scope will be reflected in the parent scope (because both reference the same object).
|
6722
|
+
* 2. one-way binding watches changes to the **identity** of the parent value. That means the
|
6723
|
+
* {@link ng.$rootScope.Scope#$watch `$watch`} on the parent value only fires if the reference
|
6724
|
+
* to the value has changed. In most cases, this should not be of concern, but can be important
|
6725
|
+
* to know if you one-way bind to an object, and then replace that object in the isolated scope.
|
6726
|
+
* If you now change a property of the object in your parent scope, the change will not be
|
6727
|
+
* propagated to the isolated scope, because the identity of the object on the parent scope
|
6728
|
+
* has not changed. Instead you must assign a new object.
|
6729
|
+
*
|
6730
|
+
* One-way binding is useful if you do not plan to propagate changes to your isolated scope bindings
|
6731
|
+
* back to the parent. However, it does not make this completely impossible.
|
6732
|
+
*
|
6733
|
+
* * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope. If
|
6734
|
+
* no `attr` name is specified then the attribute name is assumed to be the same as the local name.
|
6735
|
+
* Given `<my-component my-attr="count = count + value">` and the isolate scope definition `scope: {
|
6736
|
+
* localFn:'&myAttr' }`, the isolate scope property `localFn` will point to a function wrapper for
|
6737
|
+
* the `count = count + value` expression. Often it's desirable to pass data from the isolated scope
|
6738
|
+
* via an expression to the parent scope. This can be done by passing a map of local variable names
|
6739
|
+
* and values into the expression wrapper fn. For example, if the expression is `increment(amount)`
|
6740
|
+
* then we can specify the amount value by calling the `localFn` as `localFn({amount: 22})`.
|
6462
6741
|
*
|
6463
6742
|
* In general it's possible to apply more than one directive to one element, but there might be limitations
|
6464
6743
|
* depending on the type of scope required by the directives. The following points will help explain these limitations.
|
@@ -6476,9 +6755,32 @@ function $TemplateCacheProvider() {
|
|
6476
6755
|
*
|
6477
6756
|
*
|
6478
6757
|
* #### `bindToController`
|
6479
|
-
*
|
6480
|
-
*
|
6481
|
-
*
|
6758
|
+
* This property is used to bind scope properties directly to the controller. It can be either
|
6759
|
+
* `true` or an object hash with the same format as the `scope` property. Additionally, a controller
|
6760
|
+
* alias must be set, either by using `controllerAs: 'myAlias'` or by specifying the alias in the controller
|
6761
|
+
* definition: `controller: 'myCtrl as myAlias'`.
|
6762
|
+
*
|
6763
|
+
* When an isolate scope is used for a directive (see above), `bindToController: true` will
|
6764
|
+
* allow a component to have its properties bound to the controller, rather than to scope.
|
6765
|
+
*
|
6766
|
+
* After the controller is instantiated, the initial values of the isolate scope bindings will be bound to the controller
|
6767
|
+
* properties. You can access these bindings once they have been initialized by providing a controller method called
|
6768
|
+
* `$onInit`, which is called after all the controllers on an element have been constructed and had their bindings
|
6769
|
+
* initialized.
|
6770
|
+
*
|
6771
|
+
* <div class="alert alert-warning">
|
6772
|
+
* **Deprecation warning:** although bindings for non-ES6 class controllers are currently
|
6773
|
+
* bound to `this` before the controller constructor is called, this use is now deprecated. Please place initialization
|
6774
|
+
* code that relies upon bindings inside a `$onInit` method on the controller, instead.
|
6775
|
+
* </div>
|
6776
|
+
*
|
6777
|
+
* It is also possible to set `bindToController` to an object hash with the same format as the `scope` property.
|
6778
|
+
* This will set up the scope bindings to the controller directly. Note that `scope` can still be used
|
6779
|
+
* to define which kind of scope is created. By default, no scope is created. Use `scope: {}` to create an isolate
|
6780
|
+
* scope (useful for component directives).
|
6781
|
+
*
|
6782
|
+
* If both `bindToController` and `scope` are defined and have object hashes, `bindToController` overrides `scope`.
|
6783
|
+
*
|
6482
6784
|
*
|
6483
6785
|
* #### `controller`
|
6484
6786
|
* Controller constructor function. The controller is instantiated before the
|
@@ -6490,10 +6792,10 @@ function $TemplateCacheProvider() {
|
|
6490
6792
|
* * `$element` - Current element
|
6491
6793
|
* * `$attrs` - Current attributes object for the element
|
6492
6794
|
* * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
|
6493
|
-
* `function([scope], cloneLinkingFn, futureParentElement)
|
6494
|
-
* * `scope`: optional
|
6495
|
-
* * `cloneLinkingFn`: optional argument to create clones of the original transcluded content.
|
6496
|
-
* * `futureParentElement
|
6795
|
+
* `function([scope], cloneLinkingFn, futureParentElement, slotName)`:
|
6796
|
+
* * `scope`: (optional) override the scope.
|
6797
|
+
* * `cloneLinkingFn`: (optional) argument to create clones of the original transcluded content.
|
6798
|
+
* * `futureParentElement` (optional):
|
6497
6799
|
* * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
|
6498
6800
|
* * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
|
6499
6801
|
* * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
|
@@ -6501,14 +6803,34 @@ function $TemplateCacheProvider() {
|
|
6501
6803
|
* as those elements need to created and cloned in a special way when they are defined outside their
|
6502
6804
|
* usual containers (e.g. like `<svg>`).
|
6503
6805
|
* * See also the `directive.templateNamespace` property.
|
6806
|
+
* * `slotName`: (optional) the name of the slot to transclude. If falsy (e.g. `null`, `undefined` or `''`)
|
6807
|
+
* then the default translusion is provided.
|
6808
|
+
* The `$transclude` function also has a method on it, `$transclude.isSlotFilled(slotName)`, which returns
|
6809
|
+
* `true` if the specified slot contains content (i.e. one or more DOM nodes).
|
6504
6810
|
*
|
6811
|
+
* The controller can provide the following methods that act as life-cycle hooks:
|
6812
|
+
* * `$onInit` - Called on each controller after all the controllers on an element have been constructed and
|
6813
|
+
* had their bindings initialized (and before the pre & post linking functions for the directives on
|
6814
|
+
* this element). This is a good place to put initialization code for your controller.
|
6505
6815
|
*
|
6506
6816
|
* #### `require`
|
6507
6817
|
* Require another directive and inject its controller as the fourth argument to the linking function. The
|
6508
|
-
* `require`
|
6509
|
-
*
|
6510
|
-
*
|
6511
|
-
*
|
6818
|
+
* `require` property can be a string, an array or an object:
|
6819
|
+
* * a **string** containing the name of the directive to pass to the linking function
|
6820
|
+
* * an **array** containing the names of directives to pass to the linking function. The argument passed to the
|
6821
|
+
* linking function will be an array of controllers in the same order as the names in the `require` property
|
6822
|
+
* * an **object** whose property values are the names of the directives to pass to the linking function. The argument
|
6823
|
+
* passed to the linking function will also be an object with matching keys, whose values will hold the corresponding
|
6824
|
+
* controllers.
|
6825
|
+
*
|
6826
|
+
* If the `require` property is an object and `bindToController` is truthy, then the required controllers are
|
6827
|
+
* bound to the controller using the keys of the `require` property. This binding occurs after all the controllers
|
6828
|
+
* have been constructed but before `$onInit` is called.
|
6829
|
+
* See the {@link $compileProvider#component} helper for an example of how this can be used.
|
6830
|
+
*
|
6831
|
+
* If no such required directive(s) can be found, or if the directive does not have a controller, then an error is
|
6832
|
+
* raised (unless no link function is specified and the required controllers are not being bound to the directive
|
6833
|
+
* controller, in which case error checking is skipped). The name can be prefixed with:
|
6512
6834
|
*
|
6513
6835
|
* * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
|
6514
6836
|
* * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
|
@@ -6601,14 +6923,6 @@ function $TemplateCacheProvider() {
|
|
6601
6923
|
* The contents are compiled and provided to the directive as a **transclusion function**. See the
|
6602
6924
|
* {@link $compile#transclusion Transclusion} section below.
|
6603
6925
|
*
|
6604
|
-
* There are two kinds of transclusion depending upon whether you want to transclude just the contents of the
|
6605
|
-
* directive's element or the entire element:
|
6606
|
-
*
|
6607
|
-
* * `true` - transclude the content (i.e. the child nodes) of the directive's element.
|
6608
|
-
* * `'element'` - transclude the whole of the directive's element including any directives on this
|
6609
|
-
* element that defined at a lower priority than this directive. When used, the `template`
|
6610
|
-
* property is ignored.
|
6611
|
-
*
|
6612
6926
|
*
|
6613
6927
|
* #### `compile`
|
6614
6928
|
*
|
@@ -6636,7 +6950,7 @@ function $TemplateCacheProvider() {
|
|
6636
6950
|
|
6637
6951
|
* <div class="alert alert-warning">
|
6638
6952
|
* **Note:** The compile function cannot handle directives that recursively use themselves in their
|
6639
|
-
* own templates or compile functions. Compiling these directives results in an infinite loop and
|
6953
|
+
* own templates or compile functions. Compiling these directives results in an infinite loop and
|
6640
6954
|
* stack overflow errors.
|
6641
6955
|
*
|
6642
6956
|
* This can be avoided by manually using $compile in the postLink function to imperatively compile
|
@@ -6738,6 +7052,34 @@ function $TemplateCacheProvider() {
|
|
6738
7052
|
* Testing Transclusion Directives}.
|
6739
7053
|
* </div>
|
6740
7054
|
*
|
7055
|
+
* There are three kinds of transclusion depending upon whether you want to transclude just the contents of the
|
7056
|
+
* directive's element, the entire element or multiple parts of the element contents:
|
7057
|
+
*
|
7058
|
+
* * `true` - transclude the content (i.e. the child nodes) of the directive's element.
|
7059
|
+
* * `'element'` - transclude the whole of the directive's element including any directives on this
|
7060
|
+
* element that defined at a lower priority than this directive. When used, the `template`
|
7061
|
+
* property is ignored.
|
7062
|
+
* * **`{...}` (an object hash):** - map elements of the content onto transclusion "slots" in the template.
|
7063
|
+
*
|
7064
|
+
* **Mult-slot transclusion** is declared by providing an object for the `transclude` property.
|
7065
|
+
*
|
7066
|
+
* This object is a map where the keys are the name of the slot to fill and the value is an element selector
|
7067
|
+
* used to match the HTML to the slot. The element selector should be in normalized form (e.g. `myElement`)
|
7068
|
+
* and will match the standard element variants (e.g. `my-element`, `my:element`, `data-my-element`, etc).
|
7069
|
+
*
|
7070
|
+
* For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
|
7071
|
+
*
|
7072
|
+
* If the element selector is prefixed with a `?` then that slot is optional.
|
7073
|
+
*
|
7074
|
+
* For example, the transclude object `{ slotA: '?myCustomElement' }` maps `<my-custom-element>` elements to
|
7075
|
+
* the `slotA` slot, which can be accessed via the `$transclude` function or via the {@link ngTransclude} directive.
|
7076
|
+
*
|
7077
|
+
* Slots that are not marked as optional (`?`) will trigger a compile time error if there are no matching elements
|
7078
|
+
* in the transclude content. If you wish to know if an optional slot was filled with content, then you can call
|
7079
|
+
* `$transclude.isSlotFilled(slotName)` on the transclude function passed to the directive's link function and
|
7080
|
+
* injectable into the directive's controller.
|
7081
|
+
*
|
7082
|
+
*
|
6741
7083
|
* #### Transclusion Functions
|
6742
7084
|
*
|
6743
7085
|
* When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
|
@@ -6758,7 +7100,7 @@ function $TemplateCacheProvider() {
|
|
6758
7100
|
* content and the `scope` is the newly created transclusion scope, to which the clone is bound.
|
6759
7101
|
*
|
6760
7102
|
* <div class="alert alert-info">
|
6761
|
-
* **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a
|
7103
|
+
* **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a transclude function
|
6762
7104
|
* since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
|
6763
7105
|
* </div>
|
6764
7106
|
*
|
@@ -6790,7 +7132,7 @@ function $TemplateCacheProvider() {
|
|
6790
7132
|
* </div>
|
6791
7133
|
*
|
6792
7134
|
* The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
|
6793
|
-
* automatically destroy their
|
7135
|
+
* automatically destroy their transcluded clones as necessary so you do not need to worry about this if
|
6794
7136
|
* you are simply using {@link ngTransclude} to inject the transclusion into your directive.
|
6795
7137
|
*
|
6796
7138
|
*
|
@@ -6815,19 +7157,19 @@ function $TemplateCacheProvider() {
|
|
6815
7157
|
*
|
6816
7158
|
* The `$parent` scope hierarchy will look like this:
|
6817
7159
|
*
|
6818
|
-
|
6819
|
-
|
6820
|
-
|
6821
|
-
|
6822
|
-
|
7160
|
+
```
|
7161
|
+
- $rootScope
|
7162
|
+
- isolate
|
7163
|
+
- transclusion
|
7164
|
+
```
|
6823
7165
|
*
|
6824
7166
|
* but the scopes will inherit prototypically from different scopes to their `$parent`.
|
6825
7167
|
*
|
6826
|
-
|
6827
|
-
|
6828
|
-
|
6829
|
-
|
6830
|
-
|
7168
|
+
```
|
7169
|
+
- $rootScope
|
7170
|
+
- transclusion
|
7171
|
+
- isolate
|
7172
|
+
```
|
6831
7173
|
*
|
6832
7174
|
*
|
6833
7175
|
* ### Attributes
|
@@ -6835,10 +7177,9 @@ function $TemplateCacheProvider() {
|
|
6835
7177
|
* The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
|
6836
7178
|
* `link()` or `compile()` functions. It has a variety of uses.
|
6837
7179
|
*
|
6838
|
-
*
|
6839
|
-
*
|
6840
|
-
* the attributes
|
6841
|
-
* the attributes.
|
7180
|
+
* * *Accessing normalized attribute names:* Directives like 'ngBind' can be expressed in many ways:
|
7181
|
+
* 'ng:bind', `data-ng-bind`, or 'x-ng-bind'. The attributes object allows for normalized access
|
7182
|
+
* to the attributes.
|
6842
7183
|
*
|
6843
7184
|
* * *Directive inter-communication:* All directives share the same instance of the attributes
|
6844
7185
|
* object which allows the directives to use the attributes object as inter directive
|
@@ -6959,8 +7300,15 @@ function $TemplateCacheProvider() {
|
|
6959
7300
|
* directives; if given, it will be passed through to the link functions of
|
6960
7301
|
* directives found in `element` during compilation.
|
6961
7302
|
* * `transcludeControllers` - an object hash with keys that map controller names
|
6962
|
-
* to
|
6963
|
-
* available to directives
|
7303
|
+
* to a hash with the key `instance`, which maps to the controller instance;
|
7304
|
+
* if given, it will make the controllers available to directives on the compileNode:
|
7305
|
+
* ```
|
7306
|
+
* {
|
7307
|
+
* parent: {
|
7308
|
+
* instance: parentControllerInstance
|
7309
|
+
* }
|
7310
|
+
* }
|
7311
|
+
* ```
|
6964
7312
|
* * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
|
6965
7313
|
* the cloned elements; only needed for transcludes that are allowed to contain non html
|
6966
7314
|
* elements (e.g. SVG elements). See also the directive.controller property.
|
@@ -7021,7 +7369,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
7021
7369
|
var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
|
7022
7370
|
|
7023
7371
|
function parseIsolateBindings(scope, directiveName, isController) {
|
7024
|
-
var LOCAL_REGEXP = /^\s*([
|
7372
|
+
var LOCAL_REGEXP = /^\s*([@&<]|=(\*?))(\??)\s*(\w*)\s*$/;
|
7025
7373
|
|
7026
7374
|
var bindings = {};
|
7027
7375
|
|
@@ -7108,8 +7456,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
7108
7456
|
* @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
|
7109
7457
|
* will match as <code>ng-bind</code>), or an object map of directives where the keys are the
|
7110
7458
|
* names and the values are the factories.
|
7111
|
-
* @param {Function|Array} directiveFactory An injectable directive factory function. See
|
7112
|
-
* {@link guide/directive} for more info.
|
7459
|
+
* @param {Function|Array} directiveFactory An injectable directive factory function. See the
|
7460
|
+
* {@link guide/directive directive guide} and the {@link $compile compile API} for more info.
|
7113
7461
|
* @returns {ng.$compileProvider} Self for chaining.
|
7114
7462
|
*/
|
7115
7463
|
this.directive = function registerDirective(name, directiveFactory) {
|
@@ -7156,6 +7504,128 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
7156
7504
|
return this;
|
7157
7505
|
};
|
7158
7506
|
|
7507
|
+
/**
|
7508
|
+
* @ngdoc method
|
7509
|
+
* @name $compileProvider#component
|
7510
|
+
* @module ng
|
7511
|
+
* @param {string} name Name of the component in camelCase (i.e. `myComp` which will match `<my-comp>`)
|
7512
|
+
* @param {Object} options Component definition object (a simplified
|
7513
|
+
* {@link ng.$compile#directive-definition-object directive definition object}),
|
7514
|
+
* with the following properties (all optional):
|
7515
|
+
*
|
7516
|
+
* - `controller` – `{(string|function()=}` – controller constructor function that should be
|
7517
|
+
* associated with newly created scope or the name of a {@link ng.$compile#-controller-
|
7518
|
+
* registered controller} if passed as a string. An empty `noop` function by default.
|
7519
|
+
* - `controllerAs` – `{string=}` – identifier name for to reference the controller in the component's scope.
|
7520
|
+
* If present, the controller will be published to scope under the `controllerAs` name.
|
7521
|
+
* If not present, this will default to be `$ctrl`.
|
7522
|
+
* - `template` – `{string=|function()=}` – html template as a string or a function that
|
7523
|
+
* returns an html template as a string which should be used as the contents of this component.
|
7524
|
+
* Empty string by default.
|
7525
|
+
*
|
7526
|
+
* If `template` is a function, then it is {@link auto.$injector#invoke injected} with
|
7527
|
+
* the following locals:
|
7528
|
+
*
|
7529
|
+
* - `$element` - Current element
|
7530
|
+
* - `$attrs` - Current attributes object for the element
|
7531
|
+
*
|
7532
|
+
* - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
|
7533
|
+
* template that should be used as the contents of this component.
|
7534
|
+
*
|
7535
|
+
* If `templateUrl` is a function, then it is {@link auto.$injector#invoke injected} with
|
7536
|
+
* the following locals:
|
7537
|
+
*
|
7538
|
+
* - `$element` - Current element
|
7539
|
+
* - `$attrs` - Current attributes object for the element
|
7540
|
+
*
|
7541
|
+
* - `bindings` – `{object=}` – defines bindings between DOM attributes and component properties.
|
7542
|
+
* Component properties are always bound to the component controller and not to the scope.
|
7543
|
+
* See {@link ng.$compile#-bindtocontroller- `bindToController`}.
|
7544
|
+
* - `transclude` – `{boolean=}` – whether {@link $compile#transclusion content transclusion} is enabled.
|
7545
|
+
* Disabled by default.
|
7546
|
+
* - `$...` – `{function()=}` – additional annotations to provide to the directive factory function.
|
7547
|
+
*
|
7548
|
+
* @returns {ng.$compileProvider} the compile provider itself, for chaining of function calls.
|
7549
|
+
* @description
|
7550
|
+
* Register a **component definition** with the compiler. This is a shorthand for registering a special
|
7551
|
+
* type of directive, which represents a self-contained UI component in your application. Such components
|
7552
|
+
* are always isolated (i.e. `scope: {}`) and are always restricted to elements (i.e. `restrict: 'E'`).
|
7553
|
+
*
|
7554
|
+
* Component definitions are very simple and do not require as much configuration as defining general
|
7555
|
+
* directives. Component definitions usually consist only of a template and a controller backing it.
|
7556
|
+
*
|
7557
|
+
* In order to make the definition easier, components enforce best practices like use of `controllerAs`,
|
7558
|
+
* `bindToController`. They always have **isolate scope** and are restricted to elements.
|
7559
|
+
*
|
7560
|
+
* Here are a few examples of how you would usually define components:
|
7561
|
+
*
|
7562
|
+
* ```js
|
7563
|
+
* var myMod = angular.module(...);
|
7564
|
+
* myMod.component('myComp', {
|
7565
|
+
* template: '<div>My name is {{$ctrl.name}}</div>',
|
7566
|
+
* controller: function() {
|
7567
|
+
* this.name = 'shahar';
|
7568
|
+
* }
|
7569
|
+
* });
|
7570
|
+
*
|
7571
|
+
* myMod.component('myComp', {
|
7572
|
+
* template: '<div>My name is {{$ctrl.name}}</div>',
|
7573
|
+
* bindings: {name: '@'}
|
7574
|
+
* });
|
7575
|
+
*
|
7576
|
+
* myMod.component('myComp', {
|
7577
|
+
* templateUrl: 'views/my-comp.html',
|
7578
|
+
* controller: 'MyCtrl as ctrl',
|
7579
|
+
* bindings: {name: '@'}
|
7580
|
+
* });
|
7581
|
+
*
|
7582
|
+
* ```
|
7583
|
+
* For more examples, and an in-depth guide, see the {@link guide/component component guide}.
|
7584
|
+
*
|
7585
|
+
* <br />
|
7586
|
+
* See also {@link ng.$compileProvider#directive $compileProvider.directive()}.
|
7587
|
+
*/
|
7588
|
+
this.component = function registerComponent(name, options) {
|
7589
|
+
var controller = options.controller || function() {};
|
7590
|
+
|
7591
|
+
function factory($injector) {
|
7592
|
+
function makeInjectable(fn) {
|
7593
|
+
if (isFunction(fn) || isArray(fn)) {
|
7594
|
+
return function(tElement, tAttrs) {
|
7595
|
+
return $injector.invoke(fn, this, {$element: tElement, $attrs: tAttrs});
|
7596
|
+
};
|
7597
|
+
} else {
|
7598
|
+
return fn;
|
7599
|
+
}
|
7600
|
+
}
|
7601
|
+
|
7602
|
+
var template = (!options.template && !options.templateUrl ? '' : options.template);
|
7603
|
+
return {
|
7604
|
+
controller: controller,
|
7605
|
+
controllerAs: identifierForController(options.controller) || options.controllerAs || '$ctrl',
|
7606
|
+
template: makeInjectable(template),
|
7607
|
+
templateUrl: makeInjectable(options.templateUrl),
|
7608
|
+
transclude: options.transclude,
|
7609
|
+
scope: {},
|
7610
|
+
bindToController: options.bindings || {},
|
7611
|
+
restrict: 'E',
|
7612
|
+
require: options.require
|
7613
|
+
};
|
7614
|
+
}
|
7615
|
+
|
7616
|
+
// Copy any annotation properties (starting with $) over to the factory function
|
7617
|
+
// These could be used by libraries such as the new component router
|
7618
|
+
forEach(options, function(val, key) {
|
7619
|
+
if (key.charAt(0) === '$') {
|
7620
|
+
factory[key] = val;
|
7621
|
+
}
|
7622
|
+
});
|
7623
|
+
|
7624
|
+
factory.$inject = ['$injector'];
|
7625
|
+
|
7626
|
+
return this.directive(name, factory);
|
7627
|
+
};
|
7628
|
+
|
7159
7629
|
|
7160
7630
|
/**
|
7161
7631
|
* @ngdoc method
|
@@ -7249,10 +7719,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
7249
7719
|
|
7250
7720
|
this.$get = [
|
7251
7721
|
'$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
|
7252
|
-
'$controller', '$rootScope', '$
|
7722
|
+
'$controller', '$rootScope', '$sce', '$animate', '$$sanitizeUri',
|
7253
7723
|
function($injector, $interpolate, $exceptionHandler, $templateRequest, $parse,
|
7254
|
-
$controller, $rootScope, $
|
7724
|
+
$controller, $rootScope, $sce, $animate, $$sanitizeUri) {
|
7255
7725
|
|
7726
|
+
var SIMPLE_ATTR_NAME = /^\w/;
|
7727
|
+
var specialAttrHolder = document.createElement('div');
|
7256
7728
|
var Attributes = function(element, attributesToCopy) {
|
7257
7729
|
if (attributesToCopy) {
|
7258
7730
|
var keys = Object.keys(attributesToCopy);
|
@@ -7388,7 +7860,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
7388
7860
|
|
7389
7861
|
nodeName = nodeName_(this.$$element);
|
7390
7862
|
|
7391
|
-
if ((nodeName === 'a' && key === 'href') ||
|
7863
|
+
if ((nodeName === 'a' && (key === 'href' || key === 'xlinkHref')) ||
|
7392
7864
|
(nodeName === 'img' && key === 'src')) {
|
7393
7865
|
// sanitize a[href] and img[src] values
|
7394
7866
|
this[key] = value = $$sanitizeUri(value, key === 'src');
|
@@ -7432,7 +7904,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
7432
7904
|
if (value === null || isUndefined(value)) {
|
7433
7905
|
this.$$element.removeAttr(attrName);
|
7434
7906
|
} else {
|
7435
|
-
|
7907
|
+
if (SIMPLE_ATTR_NAME.test(attrName)) {
|
7908
|
+
this.$$element.attr(attrName, value);
|
7909
|
+
} else {
|
7910
|
+
setSpecialAttr(this.$$element[0], attrName, value);
|
7911
|
+
}
|
7436
7912
|
}
|
7437
7913
|
}
|
7438
7914
|
|
@@ -7463,7 +7939,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
7463
7939
|
* @param {string} key Normalized key. (ie ngAttribute) .
|
7464
7940
|
* @param {function(interpolatedValue)} fn Function that will be called whenever
|
7465
7941
|
the interpolated value of the attribute changes.
|
7466
|
-
* See the {@link guide/
|
7942
|
+
* See the {@link guide/interpolation#how-text-and-attribute-bindings-work Interpolation
|
7943
|
+
* guide} for more info.
|
7467
7944
|
* @returns {function()} Returns a deregistration function for this observer.
|
7468
7945
|
*/
|
7469
7946
|
$observe: function(key, fn) {
|
@@ -7485,6 +7962,18 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
7485
7962
|
}
|
7486
7963
|
};
|
7487
7964
|
|
7965
|
+
function setSpecialAttr(element, attrName, value) {
|
7966
|
+
// Attributes names that do not start with letters (such as `(click)`) cannot be set using `setAttribute`
|
7967
|
+
// so we have to jump through some hoops to get such an attribute
|
7968
|
+
// https://github.com/angular/angular.js/pull/13318
|
7969
|
+
specialAttrHolder.innerHTML = "<span " + attrName + ">";
|
7970
|
+
var attributes = specialAttrHolder.firstChild.attributes;
|
7971
|
+
var attribute = attributes[0];
|
7972
|
+
// We have to remove the attribute from its container element before we can add it to the destination element
|
7973
|
+
attributes.removeNamedItem(attribute.name);
|
7974
|
+
attribute.value = value;
|
7975
|
+
element.attributes.setNamedItem(attribute);
|
7976
|
+
}
|
7488
7977
|
|
7489
7978
|
function safeAddClass($element, className) {
|
7490
7979
|
try {
|
@@ -7498,7 +7987,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
7498
7987
|
|
7499
7988
|
var startSymbol = $interpolate.startSymbol(),
|
7500
7989
|
endSymbol = $interpolate.endSymbol(),
|
7501
|
-
denormalizeTemplate = (startSymbol == '{{'
|
7990
|
+
denormalizeTemplate = (startSymbol == '{{' && endSymbol == '}}')
|
7502
7991
|
? identity
|
7503
7992
|
: function denormalizeTemplate(template) {
|
7504
7993
|
return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
|
@@ -7542,13 +8031,19 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
7542
8031
|
// modify it.
|
7543
8032
|
$compileNodes = jqLite($compileNodes);
|
7544
8033
|
}
|
8034
|
+
|
8035
|
+
var NOT_EMPTY = /\S+/;
|
8036
|
+
|
7545
8037
|
// We can not compile top level text elements since text nodes can be merged and we will
|
7546
8038
|
// not be able to attach scope data to them, so we will wrap them in <span>
|
7547
|
-
|
7548
|
-
|
7549
|
-
|
8039
|
+
for (var i = 0, len = $compileNodes.length; i < len; i++) {
|
8040
|
+
var domNode = $compileNodes[i];
|
8041
|
+
|
8042
|
+
if (domNode.nodeType === NODE_TYPE_TEXT && domNode.nodeValue.match(NOT_EMPTY) /* non-empty */) {
|
8043
|
+
jqLiteWrapNode(domNode, $compileNodes[i] = document.createElement('span'));
|
7550
8044
|
}
|
7551
|
-
}
|
8045
|
+
}
|
8046
|
+
|
7552
8047
|
var compositeLinkFn =
|
7553
8048
|
compileNodes($compileNodes, transcludeFn, $compileNodes,
|
7554
8049
|
maxPriority, ignoreDirective, previousCompileContext);
|
@@ -7619,7 +8114,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
7619
8114
|
if (!node) {
|
7620
8115
|
return 'html';
|
7621
8116
|
} else {
|
7622
|
-
return nodeName_(node) !== 'foreignobject' &&
|
8117
|
+
return nodeName_(node) !== 'foreignobject' && toString.call(node).match(/SVG/) ? 'svg' : 'html';
|
7623
8118
|
}
|
7624
8119
|
}
|
7625
8120
|
|
@@ -7753,6 +8248,17 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
7753
8248
|
});
|
7754
8249
|
};
|
7755
8250
|
|
8251
|
+
// We need to attach the transclusion slots onto the `boundTranscludeFn`
|
8252
|
+
// so that they are available inside the `controllersBoundTransclude` function
|
8253
|
+
var boundSlots = boundTranscludeFn.$$slots = createMap();
|
8254
|
+
for (var slotName in transcludeFn.$$slots) {
|
8255
|
+
if (transcludeFn.$$slots[slotName]) {
|
8256
|
+
boundSlots[slotName] = createBoundTranscludeFn(scope, transcludeFn.$$slots[slotName], previousBoundTranscludeFn);
|
8257
|
+
} else {
|
8258
|
+
boundSlots[slotName] = null;
|
8259
|
+
}
|
8260
|
+
}
|
8261
|
+
|
7756
8262
|
return boundTranscludeFn;
|
7757
8263
|
}
|
7758
8264
|
|
@@ -7911,6 +8417,37 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
7911
8417
|
};
|
7912
8418
|
}
|
7913
8419
|
|
8420
|
+
/**
|
8421
|
+
* A function generator that is used to support both eager and lazy compilation
|
8422
|
+
* linking function.
|
8423
|
+
* @param eager
|
8424
|
+
* @param $compileNodes
|
8425
|
+
* @param transcludeFn
|
8426
|
+
* @param maxPriority
|
8427
|
+
* @param ignoreDirective
|
8428
|
+
* @param previousCompileContext
|
8429
|
+
* @returns {Function}
|
8430
|
+
*/
|
8431
|
+
function compilationGenerator(eager, $compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext) {
|
8432
|
+
if (eager) {
|
8433
|
+
return compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
|
8434
|
+
}
|
8435
|
+
|
8436
|
+
var compiled;
|
8437
|
+
|
8438
|
+
return function() {
|
8439
|
+
if (!compiled) {
|
8440
|
+
compiled = compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
|
8441
|
+
|
8442
|
+
// Null out all of these references in order to make them eligible for garbage collection
|
8443
|
+
// since this is a potentially long lived closure
|
8444
|
+
$compileNodes = transcludeFn = previousCompileContext = null;
|
8445
|
+
}
|
8446
|
+
|
8447
|
+
return compiled.apply(this, arguments);
|
8448
|
+
};
|
8449
|
+
}
|
8450
|
+
|
7914
8451
|
/**
|
7915
8452
|
* Once the directives have been collected, their compile functions are executed. This method
|
7916
8453
|
* is responsible for inlining directive templates as well as terminating the application
|
@@ -7955,6 +8492,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
7955
8492
|
replaceDirective = originalReplaceDirective,
|
7956
8493
|
childTranscludeFn = transcludeFn,
|
7957
8494
|
linkFn,
|
8495
|
+
didScanForMultipleTransclusion = false,
|
8496
|
+
mightHaveMultipleTransclusionError = false,
|
7958
8497
|
directiveValue;
|
7959
8498
|
|
7960
8499
|
// executes all directives on the current element
|
@@ -7997,6 +8536,27 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
7997
8536
|
|
7998
8537
|
directiveName = directive.name;
|
7999
8538
|
|
8539
|
+
// If we encounter a condition that can result in transclusion on the directive,
|
8540
|
+
// then scan ahead in the remaining directives for others that may cause a multiple
|
8541
|
+
// transclusion error to be thrown during the compilation process. If a matching directive
|
8542
|
+
// is found, then we know that when we encounter a transcluded directive, we need to eagerly
|
8543
|
+
// compile the `transclude` function rather than doing it lazily in order to throw
|
8544
|
+
// exceptions at the correct time
|
8545
|
+
if (!didScanForMultipleTransclusion && ((directive.replace && (directive.templateUrl || directive.template))
|
8546
|
+
|| (directive.transclude && !directive.$$tlb))) {
|
8547
|
+
var candidateDirective;
|
8548
|
+
|
8549
|
+
for (var scanningIndex = i + 1; candidateDirective = directives[scanningIndex++];) {
|
8550
|
+
if ((candidateDirective.transclude && !candidateDirective.$$tlb)
|
8551
|
+
|| (candidateDirective.replace && (candidateDirective.templateUrl || candidateDirective.template))) {
|
8552
|
+
mightHaveMultipleTransclusionError = true;
|
8553
|
+
break;
|
8554
|
+
}
|
8555
|
+
}
|
8556
|
+
|
8557
|
+
didScanForMultipleTransclusion = true;
|
8558
|
+
}
|
8559
|
+
|
8000
8560
|
if (!directive.templateUrl && directive.controller) {
|
8001
8561
|
directiveValue = directive.controller;
|
8002
8562
|
controllerDirectives = controllerDirectives || createMap();
|
@@ -8026,7 +8586,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
8026
8586
|
compileNode = $compileNode[0];
|
8027
8587
|
replaceWith(jqCollection, sliceArgs($template), compileNode);
|
8028
8588
|
|
8029
|
-
childTranscludeFn =
|
8589
|
+
childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, terminalPriority,
|
8030
8590
|
replaceDirective && replaceDirective.name, {
|
8031
8591
|
// Don't pass in:
|
8032
8592
|
// - controllerDirectives - otherwise we'll create duplicates controllers
|
@@ -8038,10 +8598,69 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
8038
8598
|
nonTlbTranscludeDirective: nonTlbTranscludeDirective
|
8039
8599
|
});
|
8040
8600
|
} else {
|
8601
|
+
|
8602
|
+
var slots = createMap();
|
8603
|
+
|
8041
8604
|
$template = jqLite(jqLiteClone(compileNode)).contents();
|
8605
|
+
|
8606
|
+
if (isObject(directiveValue)) {
|
8607
|
+
|
8608
|
+
// We have transclusion slots,
|
8609
|
+
// collect them up, compile them and store their transclusion functions
|
8610
|
+
$template = [];
|
8611
|
+
|
8612
|
+
var slotMap = createMap();
|
8613
|
+
var filledSlots = createMap();
|
8614
|
+
|
8615
|
+
// Parse the element selectors
|
8616
|
+
forEach(directiveValue, function(elementSelector, slotName) {
|
8617
|
+
// If an element selector starts with a ? then it is optional
|
8618
|
+
var optional = (elementSelector.charAt(0) === '?');
|
8619
|
+
elementSelector = optional ? elementSelector.substring(1) : elementSelector;
|
8620
|
+
|
8621
|
+
slotMap[elementSelector] = slotName;
|
8622
|
+
|
8623
|
+
// We explicitly assign `null` since this implies that a slot was defined but not filled.
|
8624
|
+
// Later when calling boundTransclusion functions with a slot name we only error if the
|
8625
|
+
// slot is `undefined`
|
8626
|
+
slots[slotName] = null;
|
8627
|
+
|
8628
|
+
// filledSlots contains `true` for all slots that are either optional or have been
|
8629
|
+
// filled. This is used to check that we have not missed any required slots
|
8630
|
+
filledSlots[slotName] = optional;
|
8631
|
+
});
|
8632
|
+
|
8633
|
+
// Add the matching elements into their slot
|
8634
|
+
forEach($compileNode.contents(), function(node) {
|
8635
|
+
var slotName = slotMap[directiveNormalize(nodeName_(node))];
|
8636
|
+
if (slotName) {
|
8637
|
+
filledSlots[slotName] = true;
|
8638
|
+
slots[slotName] = slots[slotName] || [];
|
8639
|
+
slots[slotName].push(node);
|
8640
|
+
} else {
|
8641
|
+
$template.push(node);
|
8642
|
+
}
|
8643
|
+
});
|
8644
|
+
|
8645
|
+
// Check for required slots that were not filled
|
8646
|
+
forEach(filledSlots, function(filled, slotName) {
|
8647
|
+
if (!filled) {
|
8648
|
+
throw $compileMinErr('reqslot', 'Required transclusion slot `{0}` was not filled.', slotName);
|
8649
|
+
}
|
8650
|
+
});
|
8651
|
+
|
8652
|
+
for (var slotName in slots) {
|
8653
|
+
if (slots[slotName]) {
|
8654
|
+
// Only define a transclusion function if the slot was filled
|
8655
|
+
slots[slotName] = compilationGenerator(mightHaveMultipleTransclusionError, slots[slotName], transcludeFn);
|
8656
|
+
}
|
8657
|
+
}
|
8658
|
+
}
|
8659
|
+
|
8042
8660
|
$compileNode.empty(); // clear contents
|
8043
|
-
childTranscludeFn =
|
8661
|
+
childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, undefined,
|
8044
8662
|
undefined, { needsNewScope: directive.$$isolateScope || directive.$$newScope});
|
8663
|
+
childTranscludeFn.$$slots = slots;
|
8045
8664
|
}
|
8046
8665
|
}
|
8047
8666
|
|
@@ -8204,6 +8823,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
8204
8823
|
for (var i = 0, ii = require.length; i < ii; i++) {
|
8205
8824
|
value[i] = getControllers(directiveName, require[i], $element, elementControllers);
|
8206
8825
|
}
|
8826
|
+
} else if (isObject(require)) {
|
8827
|
+
value = {};
|
8828
|
+
forEach(require, function(controller, property) {
|
8829
|
+
value[property] = getControllers(directiveName, controller, $element, elementControllers);
|
8830
|
+
});
|
8207
8831
|
}
|
8208
8832
|
|
8209
8833
|
return value || null;
|
@@ -8241,7 +8865,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
8241
8865
|
}
|
8242
8866
|
|
8243
8867
|
function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
|
8244
|
-
var linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
|
8868
|
+
var i, ii, linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
|
8245
8869
|
attrs, removeScopeBindingWatches, removeControllerBindingWatches;
|
8246
8870
|
|
8247
8871
|
if (compileNode === linkNode) {
|
@@ -8264,6 +8888,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
8264
8888
|
// is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
|
8265
8889
|
transcludeFn = controllersBoundTransclude;
|
8266
8890
|
transcludeFn.$$boundTransclude = boundTranscludeFn;
|
8891
|
+
// expose the slots on the `$transclude` function
|
8892
|
+
transcludeFn.isSlotFilled = function(slotName) {
|
8893
|
+
return !!boundTranscludeFn.$$slots[slotName];
|
8894
|
+
};
|
8267
8895
|
}
|
8268
8896
|
|
8269
8897
|
if (controllerDirectives) {
|
@@ -8308,6 +8936,21 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
8308
8936
|
}
|
8309
8937
|
}
|
8310
8938
|
|
8939
|
+
// Bind the required controllers to the controller, if `require` is an object and `bindToController` is truthy
|
8940
|
+
forEach(controllerDirectives, function(controllerDirective, name) {
|
8941
|
+
var require = controllerDirective.require;
|
8942
|
+
if (controllerDirective.bindToController && !isArray(require) && isObject(require)) {
|
8943
|
+
extend(elementControllers[name].instance, getControllers(name, require, $element, elementControllers));
|
8944
|
+
}
|
8945
|
+
});
|
8946
|
+
|
8947
|
+
// Trigger the `$onInit` method on all controllers that have one
|
8948
|
+
forEach(elementControllers, function(controller) {
|
8949
|
+
if (isFunction(controller.instance.$onInit)) {
|
8950
|
+
controller.instance.$onInit();
|
8951
|
+
}
|
8952
|
+
});
|
8953
|
+
|
8311
8954
|
// PRELINKING
|
8312
8955
|
for (i = 0, ii = preLinkFns.length; i < ii; i++) {
|
8313
8956
|
linkFn = preLinkFns[i];
|
@@ -8343,11 +8986,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
8343
8986
|
|
8344
8987
|
// This is the function that is injected as `$transclude`.
|
8345
8988
|
// Note: all arguments are optional!
|
8346
|
-
function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement) {
|
8989
|
+
function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement, slotName) {
|
8347
8990
|
var transcludeControllers;
|
8348
|
-
|
8349
8991
|
// No scope passed in:
|
8350
8992
|
if (!isScope(scope)) {
|
8993
|
+
slotName = futureParentElement;
|
8351
8994
|
futureParentElement = cloneAttachFn;
|
8352
8995
|
cloneAttachFn = scope;
|
8353
8996
|
scope = undefined;
|
@@ -8359,7 +9002,23 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
8359
9002
|
if (!futureParentElement) {
|
8360
9003
|
futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
|
8361
9004
|
}
|
8362
|
-
|
9005
|
+
if (slotName) {
|
9006
|
+
// slotTranscludeFn can be one of three things:
|
9007
|
+
// * a transclude function - a filled slot
|
9008
|
+
// * `null` - an optional slot that was not filled
|
9009
|
+
// * `undefined` - a slot that was not declared (i.e. invalid)
|
9010
|
+
var slotTranscludeFn = boundTranscludeFn.$$slots[slotName];
|
9011
|
+
if (slotTranscludeFn) {
|
9012
|
+
return slotTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
|
9013
|
+
} else if (isUndefined(slotTranscludeFn)) {
|
9014
|
+
throw $compileMinErr('noslot',
|
9015
|
+
'No parent directive that requires a transclusion with slot name "{0}". ' +
|
9016
|
+
'Element: {1}',
|
9017
|
+
slotName, startingTag($element));
|
9018
|
+
}
|
9019
|
+
} else {
|
9020
|
+
return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
|
9021
|
+
}
|
8363
9022
|
}
|
8364
9023
|
}
|
8365
9024
|
}
|
@@ -8791,9 +9450,14 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
8791
9450
|
parent.replaceChild(newNode, firstElementToRemove);
|
8792
9451
|
}
|
8793
9452
|
|
8794
|
-
//
|
9453
|
+
// Append all the `elementsToRemove` to a fragment. This will...
|
9454
|
+
// - remove them from the DOM
|
9455
|
+
// - allow them to still be traversed with .nextSibling
|
9456
|
+
// - allow a single fragment.qSA to fetch all elements being removed
|
8795
9457
|
var fragment = document.createDocumentFragment();
|
8796
|
-
|
9458
|
+
for (i = 0; i < removeCount; i++) {
|
9459
|
+
fragment.appendChild(elementsToRemove[i]);
|
9460
|
+
}
|
8797
9461
|
|
8798
9462
|
if (jqLite.hasData(firstElementToRemove)) {
|
8799
9463
|
// Copy over user data (that includes Angular's $scope etc.). Don't copy private
|
@@ -8801,31 +9465,18 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
8801
9465
|
// event listeners (which is the main use of private data) wouldn't work anyway.
|
8802
9466
|
jqLite.data(newNode, jqLite.data(firstElementToRemove));
|
8803
9467
|
|
8804
|
-
// Remove
|
8805
|
-
|
8806
|
-
// for the new node. Instead, remove the data "manually".
|
8807
|
-
if (!jQuery) {
|
8808
|
-
delete jqLite.cache[firstElementToRemove[jqLite.expando]];
|
8809
|
-
} else {
|
8810
|
-
// jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after
|
8811
|
-
// the replaced element. The cleanData version monkey-patched by Angular would cause
|
8812
|
-
// the scope to be trashed and we do need the very same scope to work with the new
|
8813
|
-
// element. However, we cannot just cache the non-patched version and use it here as
|
8814
|
-
// that would break if another library patches the method after Angular does (one
|
8815
|
-
// example is jQuery UI). Instead, set a flag indicating scope destroying should be
|
8816
|
-
// skipped this one time.
|
8817
|
-
skipDestroyOnNextJQueryCleanData = true;
|
8818
|
-
jQuery.cleanData([firstElementToRemove]);
|
8819
|
-
}
|
9468
|
+
// Remove $destroy event listeners from `firstElementToRemove`
|
9469
|
+
jqLite(firstElementToRemove).off('$destroy');
|
8820
9470
|
}
|
8821
9471
|
|
8822
|
-
|
8823
|
-
|
8824
|
-
|
8825
|
-
fragment.appendChild(element);
|
8826
|
-
delete elementsToRemove[k];
|
8827
|
-
}
|
9472
|
+
// Cleanup any data/listeners on the elements and children.
|
9473
|
+
// This includes invoking the $destroy event on any elements with listeners.
|
9474
|
+
jqLite.cleanData(fragment.querySelectorAll('*'));
|
8828
9475
|
|
9476
|
+
// Update the jqLite collection to only contain the `newNode`
|
9477
|
+
for (i = 1; i < removeCount; i++) {
|
9478
|
+
delete elementsToRemove[i];
|
9479
|
+
}
|
8829
9480
|
elementsToRemove[0] = newNode;
|
8830
9481
|
elementsToRemove.length = 1;
|
8831
9482
|
}
|
@@ -8854,7 +9505,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
8854
9505
|
optional = definition.optional,
|
8855
9506
|
mode = definition.mode, // @, =, or &
|
8856
9507
|
lastValue,
|
8857
|
-
parentGet, parentSet, compare;
|
9508
|
+
parentGet, parentSet, compare, removeWatch;
|
8858
9509
|
|
8859
9510
|
switch (mode) {
|
8860
9511
|
|
@@ -8868,10 +9519,15 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
8868
9519
|
}
|
8869
9520
|
});
|
8870
9521
|
attrs.$$observers[attrName].$$scope = scope;
|
8871
|
-
|
9522
|
+
lastValue = attrs[attrName];
|
9523
|
+
if (isString(lastValue)) {
|
8872
9524
|
// If the attribute has been provided then we trigger an interpolation to ensure
|
8873
9525
|
// the value is there for use in the link fn
|
8874
|
-
destination[scopeName] = $interpolate(
|
9526
|
+
destination[scopeName] = $interpolate(lastValue)(scope);
|
9527
|
+
} else if (isBoolean(lastValue)) {
|
9528
|
+
// If the attributes is one of the BOOLEAN_ATTR then Angular will have converted
|
9529
|
+
// the value to boolean rather than a string, so we special case this situation
|
9530
|
+
destination[scopeName] = lastValue;
|
8875
9531
|
}
|
8876
9532
|
break;
|
8877
9533
|
|
@@ -8892,8 +9548,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
8892
9548
|
// reset the change, or we will throw this exception on every $digest
|
8893
9549
|
lastValue = destination[scopeName] = parentGet(scope);
|
8894
9550
|
throw $compileMinErr('nonassign',
|
8895
|
-
"Expression '{0}' used with directive '{
|
8896
|
-
attrs[attrName], directive.name);
|
9551
|
+
"Expression '{0}' in attribute '{1}' used with directive '{2}' is non-assignable!",
|
9552
|
+
attrs[attrName], attrName, directive.name);
|
8897
9553
|
};
|
8898
9554
|
lastValue = destination[scopeName] = parentGet(scope);
|
8899
9555
|
var parentValueWatch = function parentValueWatch(parentValue) {
|
@@ -8910,7 +9566,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
8910
9566
|
return lastValue = parentValue;
|
8911
9567
|
};
|
8912
9568
|
parentValueWatch.$stateful = true;
|
8913
|
-
var removeWatch;
|
8914
9569
|
if (definition.collection) {
|
8915
9570
|
removeWatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
|
8916
9571
|
} else {
|
@@ -8919,6 +9574,24 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
8919
9574
|
removeWatchCollection.push(removeWatch);
|
8920
9575
|
break;
|
8921
9576
|
|
9577
|
+
case '<':
|
9578
|
+
if (!hasOwnProperty.call(attrs, attrName)) {
|
9579
|
+
if (optional) break;
|
9580
|
+
attrs[attrName] = void 0;
|
9581
|
+
}
|
9582
|
+
if (optional && !attrs[attrName]) break;
|
9583
|
+
|
9584
|
+
parentGet = $parse(attrs[attrName]);
|
9585
|
+
|
9586
|
+
destination[scopeName] = parentGet(scope);
|
9587
|
+
|
9588
|
+
removeWatch = scope.$watch(parentGet, function parentValueWatchAction(newParentValue) {
|
9589
|
+
destination[scopeName] = newParentValue;
|
9590
|
+
}, parentGet.literal);
|
9591
|
+
|
9592
|
+
removeWatchCollection.push(removeWatch);
|
9593
|
+
break;
|
9594
|
+
|
8922
9595
|
case '&':
|
8923
9596
|
// Don't assign Object.prototype method to scope
|
8924
9597
|
parentGet = attrs.hasOwnProperty(attrName) ? $parse(attrs[attrName]) : noop;
|
@@ -9047,7 +9720,7 @@ function removeComments(jqNodes) {
|
|
9047
9720
|
var $controllerMinErr = minErr('$controller');
|
9048
9721
|
|
9049
9722
|
|
9050
|
-
var CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
|
9723
|
+
var CNTRL_REG = /^(\S+)(\s+as\s+([\w$]+))?$/;
|
9051
9724
|
function identifierForController(controller, ident) {
|
9052
9725
|
if (ident && isString(ident)) return ident;
|
9053
9726
|
if (isString(controller)) {
|
@@ -9838,7 +10511,7 @@ function $HttpProvider() {
|
|
9838
10511
|
*
|
9839
10512
|
* ```
|
9840
10513
|
* module.run(function($http) {
|
9841
|
-
* $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
|
10514
|
+
* $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w';
|
9842
10515
|
* });
|
9843
10516
|
* ```
|
9844
10517
|
*
|
@@ -10066,13 +10739,13 @@ function $HttpProvider() {
|
|
10066
10739
|
*
|
10067
10740
|
* ### Cross Site Request Forgery (XSRF) Protection
|
10068
10741
|
*
|
10069
|
-
* [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is
|
10070
|
-
*
|
10071
|
-
* to counter XSRF. When performing XHR requests, the
|
10072
|
-
* (by default, `XSRF-TOKEN`) and sets it as an HTTP
|
10073
|
-
* JavaScript that runs on your domain could read the
|
10074
|
-
* the XHR came from JavaScript running on your domain.
|
10075
|
-
* cross-domain requests.
|
10742
|
+
* [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is an attack technique by
|
10743
|
+
* which the attacker can trick an authenticated user into unknowingly executing actions on your
|
10744
|
+
* website. Angular provides a mechanism to counter XSRF. When performing XHR requests, the
|
10745
|
+
* $http service reads a token from a cookie (by default, `XSRF-TOKEN`) and sets it as an HTTP
|
10746
|
+
* header (`X-XSRF-TOKEN`). Since only JavaScript that runs on your domain could read the
|
10747
|
+
* cookie, your server can be assured that the XHR came from JavaScript running on your domain.
|
10748
|
+
* The header will not be set for cross-domain requests.
|
10076
10749
|
*
|
10077
10750
|
* To take advantage of this, your server needs to set a token in a JavaScript readable session
|
10078
10751
|
* cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
|
@@ -10231,10 +10904,14 @@ function $HttpProvider() {
|
|
10231
10904
|
*/
|
10232
10905
|
function $http(requestConfig) {
|
10233
10906
|
|
10234
|
-
if (!
|
10907
|
+
if (!isObject(requestConfig)) {
|
10235
10908
|
throw minErr('$http')('badreq', 'Http request configuration must be an object. Received: {0}', requestConfig);
|
10236
10909
|
}
|
10237
10910
|
|
10911
|
+
if (!isString(requestConfig.url)) {
|
10912
|
+
throw minErr('$http')('badreq', 'Http request configuration url must be a string. Received: {0}', requestConfig.url);
|
10913
|
+
}
|
10914
|
+
|
10238
10915
|
var config = extend({
|
10239
10916
|
method: 'get',
|
10240
10917
|
transformRequest: defaults.transformRequest,
|
@@ -10347,7 +11024,7 @@ function $HttpProvider() {
|
|
10347
11024
|
|
10348
11025
|
defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
|
10349
11026
|
|
10350
|
-
// using for-in instead of forEach to avoid
|
11027
|
+
// using for-in instead of forEach to avoid unnecessary iteration after header has been found
|
10351
11028
|
defaultHeadersIteration:
|
10352
11029
|
for (defHeaderName in defHeaders) {
|
10353
11030
|
lowercaseDefHeaderName = lowercase(defHeaderName);
|
@@ -10846,8 +11523,16 @@ $interpolateMinErr.interr = function(text, err) {
|
|
10846
11523
|
*
|
10847
11524
|
* Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
|
10848
11525
|
*
|
11526
|
+
* <div class="alert alert-danger">
|
11527
|
+
* This feature is sometimes used to mix different markup languages, e.g. to wrap an Angular
|
11528
|
+
* template within a Python Jinja template (or any other template language). Mixing templating
|
11529
|
+
* languages is **very dangerous**. The embedding template language will not safely escape Angular
|
11530
|
+
* expressions, so any user-controlled values in the template will cause Cross Site Scripting (XSS)
|
11531
|
+
* security bugs!
|
11532
|
+
* </div>
|
11533
|
+
*
|
10849
11534
|
* @example
|
10850
|
-
<example module="customInterpolationApp">
|
11535
|
+
<example name="custom-interpolation-markup" module="customInterpolationApp">
|
10851
11536
|
<file name="index.html">
|
10852
11537
|
<script>
|
10853
11538
|
var customInterpolationApp = angular.module('customInterpolationApp', []);
|
@@ -10862,7 +11547,7 @@ $interpolateMinErr.interr = function(text, err) {
|
|
10862
11547
|
this.label = "This binding is brought you by // interpolation symbols.";
|
10863
11548
|
});
|
10864
11549
|
</script>
|
10865
|
-
<div ng-
|
11550
|
+
<div ng-controller="DemoController as demo">
|
10866
11551
|
//demo.label//
|
10867
11552
|
</div>
|
10868
11553
|
</file>
|
@@ -10946,6 +11631,15 @@ function $InterpolateProvider() {
|
|
10946
11631
|
return value;
|
10947
11632
|
}
|
10948
11633
|
|
11634
|
+
//TODO: this is the same as the constantWatchDelegate in parse.js
|
11635
|
+
function constantWatchDelegate(scope, listener, objectEquality, constantInterp) {
|
11636
|
+
var unwatch;
|
11637
|
+
return unwatch = scope.$watch(function constantInterpolateWatch(scope) {
|
11638
|
+
unwatch();
|
11639
|
+
return constantInterp(scope);
|
11640
|
+
}, listener, objectEquality);
|
11641
|
+
}
|
11642
|
+
|
10949
11643
|
/**
|
10950
11644
|
* @ngdoc service
|
10951
11645
|
* @name $interpolate
|
@@ -11041,6 +11735,19 @@ function $InterpolateProvider() {
|
|
11041
11735
|
* - `context`: evaluation context for all expressions embedded in the interpolated text
|
11042
11736
|
*/
|
11043
11737
|
function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
|
11738
|
+
// Provide a quick exit and simplified result function for text with no interpolation
|
11739
|
+
if (!text.length || text.indexOf(startSymbol) === -1) {
|
11740
|
+
var constantInterp;
|
11741
|
+
if (!mustHaveExpression) {
|
11742
|
+
var unescapedText = unescapeText(text);
|
11743
|
+
constantInterp = valueFn(unescapedText);
|
11744
|
+
constantInterp.exp = text;
|
11745
|
+
constantInterp.expressions = [];
|
11746
|
+
constantInterp.$$watchDelegate = constantWatchDelegate;
|
11747
|
+
}
|
11748
|
+
return constantInterp;
|
11749
|
+
}
|
11750
|
+
|
11044
11751
|
allOrNothing = !!allOrNothing;
|
11045
11752
|
var startIndex,
|
11046
11753
|
endIndex,
|
@@ -11177,8 +11884,8 @@ function $InterpolateProvider() {
|
|
11177
11884
|
}
|
11178
11885
|
|
11179
11886
|
function $IntervalProvider() {
|
11180
|
-
this.$get = ['$rootScope', '$window', '$q', '$$q',
|
11181
|
-
function($rootScope, $window, $q, $$q) {
|
11887
|
+
this.$get = ['$rootScope', '$window', '$q', '$$q', '$browser',
|
11888
|
+
function($rootScope, $window, $q, $$q, $browser) {
|
11182
11889
|
var intervals = {};
|
11183
11890
|
|
11184
11891
|
|
@@ -11319,11 +12026,12 @@ function $IntervalProvider() {
|
|
11319
12026
|
|
11320
12027
|
count = isDefined(count) ? count : 0;
|
11321
12028
|
|
11322
|
-
promise.then(null, null, (!hasParams) ? fn : function() {
|
11323
|
-
fn.apply(null, args);
|
11324
|
-
});
|
11325
|
-
|
11326
12029
|
promise.$$intervalId = setInterval(function tick() {
|
12030
|
+
if (skipApply) {
|
12031
|
+
$browser.defer(callback);
|
12032
|
+
} else {
|
12033
|
+
$rootScope.$evalAsync(callback);
|
12034
|
+
}
|
11327
12035
|
deferred.notify(iteration++);
|
11328
12036
|
|
11329
12037
|
if (count > 0 && iteration >= count) {
|
@@ -11339,6 +12047,14 @@ function $IntervalProvider() {
|
|
11339
12047
|
intervals[promise.$$intervalId] = deferred;
|
11340
12048
|
|
11341
12049
|
return promise;
|
12050
|
+
|
12051
|
+
function callback() {
|
12052
|
+
if (!hasParams) {
|
12053
|
+
fn(iteration);
|
12054
|
+
} else {
|
12055
|
+
fn.apply(null, args);
|
12056
|
+
}
|
12057
|
+
}
|
11342
12058
|
}
|
11343
12059
|
|
11344
12060
|
|
@@ -12578,23 +13294,22 @@ function ensureSafeMemberName(name, fullExpression) {
|
|
12578
13294
|
return name;
|
12579
13295
|
}
|
12580
13296
|
|
12581
|
-
function getStringValue(name
|
12582
|
-
// From the JavaScript docs:
|
13297
|
+
function getStringValue(name) {
|
12583
13298
|
// Property names must be strings. This means that non-string objects cannot be used
|
12584
13299
|
// as keys in an object. Any non-string object, including a number, is typecasted
|
12585
13300
|
// into a string via the toString method.
|
13301
|
+
// -- MDN, https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Property_accessors#Property_names
|
12586
13302
|
//
|
12587
|
-
// So, to ensure that we are checking the same `name` that JavaScript would use,
|
12588
|
-
//
|
12589
|
-
//
|
12590
|
-
//
|
12591
|
-
|
12592
|
-
|
12593
|
-
|
12594
|
-
|
12595
|
-
|
12596
|
-
|
12597
|
-
return name;
|
13303
|
+
// So, to ensure that we are checking the same `name` that JavaScript would use, we cast it
|
13304
|
+
// to a string. It's not always possible. If `name` is an object and its `toString` method is
|
13305
|
+
// 'broken' (doesn't return a string, isn't a function, etc.), an error will be thrown:
|
13306
|
+
//
|
13307
|
+
// TypeError: Cannot convert object to primitive value
|
13308
|
+
//
|
13309
|
+
// For performance reasons, we don't catch this error here and allow it to propagate up the call
|
13310
|
+
// stack. Note that you'll get the same error in JavaScript if you try to access a property using
|
13311
|
+
// such a 'broken' object as a key.
|
13312
|
+
return name + '';
|
12598
13313
|
}
|
12599
13314
|
|
12600
13315
|
function ensureSafeObject(obj, fullExpression) {
|
@@ -12855,6 +13570,7 @@ AST.ArrayExpression = 'ArrayExpression';
|
|
12855
13570
|
AST.Property = 'Property';
|
12856
13571
|
AST.ObjectExpression = 'ObjectExpression';
|
12857
13572
|
AST.ThisExpression = 'ThisExpression';
|
13573
|
+
AST.LocalsExpression = 'LocalsExpression';
|
12858
13574
|
|
12859
13575
|
// Internal use only
|
12860
13576
|
AST.NGValueParameter = 'NGValueParameter';
|
@@ -13155,7 +13871,8 @@ AST.prototype = {
|
|
13155
13871
|
'false': { type: AST.Literal, value: false },
|
13156
13872
|
'null': { type: AST.Literal, value: null },
|
13157
13873
|
'undefined': {type: AST.Literal, value: undefined },
|
13158
|
-
'this': {type: AST.ThisExpression }
|
13874
|
+
'this': {type: AST.ThisExpression },
|
13875
|
+
'$locals': {type: AST.LocalsExpression }
|
13159
13876
|
}
|
13160
13877
|
};
|
13161
13878
|
|
@@ -13275,6 +13992,10 @@ function findConstantAndWatchExpressions(ast, $filter) {
|
|
13275
13992
|
ast.constant = false;
|
13276
13993
|
ast.toWatch = [];
|
13277
13994
|
break;
|
13995
|
+
case AST.LocalsExpression:
|
13996
|
+
ast.constant = false;
|
13997
|
+
ast.toWatch = [];
|
13998
|
+
break;
|
13278
13999
|
}
|
13279
14000
|
}
|
13280
14001
|
|
@@ -13518,6 +14239,9 @@ ASTCompiler.prototype = {
|
|
13518
14239
|
intoId = intoId || this.nextId();
|
13519
14240
|
self.recurse(ast.object, left, undefined, function() {
|
13520
14241
|
self.if_(self.notNull(left), function() {
|
14242
|
+
if (create && create !== 1) {
|
14243
|
+
self.addEnsureSafeAssignContext(left);
|
14244
|
+
}
|
13521
14245
|
if (ast.computed) {
|
13522
14246
|
right = self.nextId();
|
13523
14247
|
self.recurse(ast.property, right);
|
@@ -13599,7 +14323,7 @@ ASTCompiler.prototype = {
|
|
13599
14323
|
right = this.nextId();
|
13600
14324
|
left = {};
|
13601
14325
|
if (!isAssignable(ast.left)) {
|
13602
|
-
throw $parseMinErr('lval', 'Trying to
|
14326
|
+
throw $parseMinErr('lval', 'Trying to assign a value to a non l-value');
|
13603
14327
|
}
|
13604
14328
|
this.recurse(ast.left, undefined, left, function() {
|
13605
14329
|
self.if_(self.notNull(left.context), function() {
|
@@ -13641,6 +14365,10 @@ ASTCompiler.prototype = {
|
|
13641
14365
|
this.assign(intoId, 's');
|
13642
14366
|
recursionFn('s');
|
13643
14367
|
break;
|
14368
|
+
case AST.LocalsExpression:
|
14369
|
+
this.assign(intoId, 'l');
|
14370
|
+
recursionFn('l');
|
14371
|
+
break;
|
13644
14372
|
case AST.NGValueParameter:
|
13645
14373
|
this.assign(intoId, 'v');
|
13646
14374
|
recursionFn('v');
|
@@ -13748,7 +14476,7 @@ ASTCompiler.prototype = {
|
|
13748
14476
|
},
|
13749
14477
|
|
13750
14478
|
getStringValue: function(item) {
|
13751
|
-
this.assign(item, 'getStringValue(' + item + '
|
14479
|
+
this.assign(item, 'getStringValue(' + item + ')');
|
13752
14480
|
},
|
13753
14481
|
|
13754
14482
|
ensureSafeAssignContext: function(item) {
|
@@ -13968,6 +14696,10 @@ ASTInterpreter.prototype = {
|
|
13968
14696
|
return function(scope) {
|
13969
14697
|
return context ? {value: scope} : scope;
|
13970
14698
|
};
|
14699
|
+
case AST.LocalsExpression:
|
14700
|
+
return function(scope, locals) {
|
14701
|
+
return context ? {value: locals} : locals;
|
14702
|
+
};
|
13971
14703
|
case AST.NGValueParameter:
|
13972
14704
|
return function(scope, locals, assign, inputs) {
|
13973
14705
|
return context ? {value: assign} : assign;
|
@@ -14132,8 +14864,11 @@ ASTInterpreter.prototype = {
|
|
14132
14864
|
rhs = right(scope, locals, assign, inputs);
|
14133
14865
|
rhs = getStringValue(rhs);
|
14134
14866
|
ensureSafeMemberName(rhs, expression);
|
14135
|
-
if (create && create !== 1
|
14136
|
-
lhs
|
14867
|
+
if (create && create !== 1) {
|
14868
|
+
ensureSafeAssignContext(lhs);
|
14869
|
+
if (lhs && !(lhs[rhs])) {
|
14870
|
+
lhs[rhs] = {};
|
14871
|
+
}
|
14137
14872
|
}
|
14138
14873
|
value = lhs[rhs];
|
14139
14874
|
ensureSafeObject(value, expression);
|
@@ -14148,8 +14883,11 @@ ASTInterpreter.prototype = {
|
|
14148
14883
|
nonComputedMember: function(left, right, expensiveChecks, context, create, expression) {
|
14149
14884
|
return function(scope, locals, assign, inputs) {
|
14150
14885
|
var lhs = left(scope, locals, assign, inputs);
|
14151
|
-
if (create && create !== 1
|
14152
|
-
lhs
|
14886
|
+
if (create && create !== 1) {
|
14887
|
+
ensureSafeAssignContext(lhs);
|
14888
|
+
if (lhs && !(lhs[right])) {
|
14889
|
+
lhs[right] = {};
|
14890
|
+
}
|
14153
14891
|
}
|
14154
14892
|
var value = lhs != null ? lhs[right] : undefined;
|
14155
14893
|
if (expensiveChecks || isPossiblyDangerousMemberName(right)) {
|
@@ -14190,9 +14928,6 @@ Parser.prototype = {
|
|
14190
14928
|
}
|
14191
14929
|
};
|
14192
14930
|
|
14193
|
-
var getterFnCacheDefault = createMap();
|
14194
|
-
var getterFnCacheExpensive = createMap();
|
14195
|
-
|
14196
14931
|
function isPossiblyDangerousMemberName(name) {
|
14197
14932
|
return name == 'constructor';
|
14198
14933
|
}
|
@@ -14268,10 +15003,19 @@ function $ParseProvider() {
|
|
14268
15003
|
csp: noUnsafeEval,
|
14269
15004
|
expensiveChecks: true
|
14270
15005
|
};
|
15006
|
+
var runningChecksEnabled = false;
|
15007
|
+
|
15008
|
+
$parse.$$runningExpensiveChecks = function() {
|
15009
|
+
return runningChecksEnabled;
|
15010
|
+
};
|
15011
|
+
|
15012
|
+
return $parse;
|
14271
15013
|
|
14272
|
-
|
15014
|
+
function $parse(exp, interceptorFn, expensiveChecks) {
|
14273
15015
|
var parsedExpression, oneTime, cacheKey;
|
14274
15016
|
|
15017
|
+
expensiveChecks = expensiveChecks || runningChecksEnabled;
|
15018
|
+
|
14275
15019
|
switch (typeof exp) {
|
14276
15020
|
case 'string':
|
14277
15021
|
exp = exp.trim();
|
@@ -14297,6 +15041,9 @@ function $ParseProvider() {
|
|
14297
15041
|
} else if (parsedExpression.inputs) {
|
14298
15042
|
parsedExpression.$$watchDelegate = inputsWatchDelegate;
|
14299
15043
|
}
|
15044
|
+
if (expensiveChecks) {
|
15045
|
+
parsedExpression = expensiveChecksInterceptor(parsedExpression);
|
15046
|
+
}
|
14300
15047
|
cache[cacheKey] = parsedExpression;
|
14301
15048
|
}
|
14302
15049
|
return addInterceptor(parsedExpression, interceptorFn);
|
@@ -14305,9 +15052,33 @@ function $ParseProvider() {
|
|
14305
15052
|
return addInterceptor(exp, interceptorFn);
|
14306
15053
|
|
14307
15054
|
default:
|
14308
|
-
return noop;
|
15055
|
+
return addInterceptor(noop, interceptorFn);
|
14309
15056
|
}
|
14310
|
-
}
|
15057
|
+
}
|
15058
|
+
|
15059
|
+
function expensiveChecksInterceptor(fn) {
|
15060
|
+
if (!fn) return fn;
|
15061
|
+
expensiveCheckFn.$$watchDelegate = fn.$$watchDelegate;
|
15062
|
+
expensiveCheckFn.assign = expensiveChecksInterceptor(fn.assign);
|
15063
|
+
expensiveCheckFn.constant = fn.constant;
|
15064
|
+
expensiveCheckFn.literal = fn.literal;
|
15065
|
+
for (var i = 0; fn.inputs && i < fn.inputs.length; ++i) {
|
15066
|
+
fn.inputs[i] = expensiveChecksInterceptor(fn.inputs[i]);
|
15067
|
+
}
|
15068
|
+
expensiveCheckFn.inputs = fn.inputs;
|
15069
|
+
|
15070
|
+
return expensiveCheckFn;
|
15071
|
+
|
15072
|
+
function expensiveCheckFn(scope, locals, assign, inputs) {
|
15073
|
+
var expensiveCheckOldValue = runningChecksEnabled;
|
15074
|
+
runningChecksEnabled = true;
|
15075
|
+
try {
|
15076
|
+
return fn(scope, locals, assign, inputs);
|
15077
|
+
} finally {
|
15078
|
+
runningChecksEnabled = expensiveCheckOldValue;
|
15079
|
+
}
|
15080
|
+
}
|
15081
|
+
}
|
14311
15082
|
|
14312
15083
|
function expressionInputDirtyCheck(newValue, oldValueOfValue) {
|
14313
15084
|
|
@@ -14424,13 +15195,9 @@ function $ParseProvider() {
|
|
14424
15195
|
function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
|
14425
15196
|
var unwatch;
|
14426
15197
|
return unwatch = scope.$watch(function constantWatch(scope) {
|
14427
|
-
return parsedExpression(scope);
|
14428
|
-
}, function constantListener(value, old, scope) {
|
14429
|
-
if (isFunction(listener)) {
|
14430
|
-
listener.apply(this, arguments);
|
14431
|
-
}
|
14432
15198
|
unwatch();
|
14433
|
-
|
15199
|
+
return parsedExpression(scope);
|
15200
|
+
}, listener, objectEquality);
|
14434
15201
|
}
|
14435
15202
|
|
14436
15203
|
function addInterceptor(parsedExpression, interceptorFn) {
|
@@ -14523,7 +15290,7 @@ function $ParseProvider() {
|
|
14523
15290
|
*
|
14524
15291
|
* Note: progress/notify callbacks are not currently supported via the ES6-style interface.
|
14525
15292
|
*
|
14526
|
-
* Note: unlike ES6
|
15293
|
+
* Note: unlike ES6 behavior, an exception thrown in the constructor function will NOT implicitly reject the promise.
|
14527
15294
|
*
|
14528
15295
|
* However, the more traditional CommonJS-style usage is still available, and documented below.
|
14529
15296
|
*
|
@@ -14713,18 +15480,6 @@ function $$QProvider() {
|
|
14713
15480
|
*/
|
14714
15481
|
function qFactory(nextTick, exceptionHandler) {
|
14715
15482
|
var $qMinErr = minErr('$q', TypeError);
|
14716
|
-
function callOnce(self, resolveFn, rejectFn) {
|
14717
|
-
var called = false;
|
14718
|
-
function wrap(fn) {
|
14719
|
-
return function(value) {
|
14720
|
-
if (called) return;
|
14721
|
-
called = true;
|
14722
|
-
fn.call(self, value);
|
14723
|
-
};
|
14724
|
-
}
|
14725
|
-
|
14726
|
-
return [wrap(resolveFn), wrap(rejectFn)];
|
14727
|
-
}
|
14728
15483
|
|
14729
15484
|
/**
|
14730
15485
|
* @ngdoc method
|
@@ -14737,7 +15492,12 @@ function qFactory(nextTick, exceptionHandler) {
|
|
14737
15492
|
* @returns {Deferred} Returns a new instance of deferred.
|
14738
15493
|
*/
|
14739
15494
|
var defer = function() {
|
14740
|
-
|
15495
|
+
var d = new Deferred();
|
15496
|
+
//Necessary to support unbound execution :/
|
15497
|
+
d.resolve = simpleBind(d, d.resolve);
|
15498
|
+
d.reject = simpleBind(d, d.reject);
|
15499
|
+
d.notify = simpleBind(d, d.notify);
|
15500
|
+
return d;
|
14741
15501
|
};
|
14742
15502
|
|
14743
15503
|
function Promise() {
|
@@ -14810,10 +15570,6 @@ function qFactory(nextTick, exceptionHandler) {
|
|
14810
15570
|
|
14811
15571
|
function Deferred() {
|
14812
15572
|
this.promise = new Promise();
|
14813
|
-
//Necessary to support unbound execution :/
|
14814
|
-
this.resolve = simpleBind(this, this.resolve);
|
14815
|
-
this.reject = simpleBind(this, this.reject);
|
14816
|
-
this.notify = simpleBind(this, this.notify);
|
14817
15573
|
}
|
14818
15574
|
|
14819
15575
|
extend(Deferred.prototype, {
|
@@ -14831,23 +15587,34 @@ function qFactory(nextTick, exceptionHandler) {
|
|
14831
15587
|
},
|
14832
15588
|
|
14833
15589
|
$$resolve: function(val) {
|
14834
|
-
var then
|
14835
|
-
|
14836
|
-
|
15590
|
+
var then;
|
15591
|
+
var that = this;
|
15592
|
+
var done = false;
|
14837
15593
|
try {
|
14838
15594
|
if ((isObject(val) || isFunction(val))) then = val && val.then;
|
14839
15595
|
if (isFunction(then)) {
|
14840
15596
|
this.promise.$$state.status = -1;
|
14841
|
-
then.call(val,
|
15597
|
+
then.call(val, resolvePromise, rejectPromise, simpleBind(this, this.notify));
|
14842
15598
|
} else {
|
14843
15599
|
this.promise.$$state.value = val;
|
14844
15600
|
this.promise.$$state.status = 1;
|
14845
15601
|
scheduleProcessQueue(this.promise.$$state);
|
14846
15602
|
}
|
14847
15603
|
} catch (e) {
|
14848
|
-
|
15604
|
+
rejectPromise(e);
|
14849
15605
|
exceptionHandler(e);
|
14850
15606
|
}
|
15607
|
+
|
15608
|
+
function resolvePromise(val) {
|
15609
|
+
if (done) return;
|
15610
|
+
done = true;
|
15611
|
+
that.$$resolve(val);
|
15612
|
+
}
|
15613
|
+
function rejectPromise(val) {
|
15614
|
+
if (done) return;
|
15615
|
+
done = true;
|
15616
|
+
that.$$reject(val);
|
15617
|
+
}
|
14851
15618
|
},
|
14852
15619
|
|
14853
15620
|
reject: function(reason) {
|
@@ -15036,11 +15803,6 @@ function qFactory(nextTick, exceptionHandler) {
|
|
15036
15803
|
throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
|
15037
15804
|
}
|
15038
15805
|
|
15039
|
-
if (!(this instanceof Q)) {
|
15040
|
-
// More useful when $Q is the Promise itself.
|
15041
|
-
return new Q(resolver);
|
15042
|
-
}
|
15043
|
-
|
15044
15806
|
var deferred = new Deferred();
|
15045
15807
|
|
15046
15808
|
function resolveFn(value) {
|
@@ -15056,6 +15818,10 @@ function qFactory(nextTick, exceptionHandler) {
|
|
15056
15818
|
return deferred.promise;
|
15057
15819
|
};
|
15058
15820
|
|
15821
|
+
// Let's make the instanceof operator work for promises, so that
|
15822
|
+
// `new $q(fn) instanceof $q` would evaluate to true.
|
15823
|
+
$Q.prototype = Promise.prototype;
|
15824
|
+
|
15059
15825
|
$Q.defer = defer;
|
15060
15826
|
$Q.reject = reject;
|
15061
15827
|
$Q.when = when;
|
@@ -15189,8 +15955,8 @@ function $RootScopeProvider() {
|
|
15189
15955
|
return ChildScope;
|
15190
15956
|
}
|
15191
15957
|
|
15192
|
-
this.$get = ['$
|
15193
|
-
function($
|
15958
|
+
this.$get = ['$exceptionHandler', '$parse', '$browser',
|
15959
|
+
function($exceptionHandler, $parse, $browser) {
|
15194
15960
|
|
15195
15961
|
function destroyChildScope($event) {
|
15196
15962
|
$event.currentScope.$$destroyed = true;
|
@@ -15474,7 +16240,7 @@ function $RootScopeProvider() {
|
|
15474
16240
|
* - `newVal` contains the current value of the `watchExpression`
|
15475
16241
|
* - `oldVal` contains the previous value of the `watchExpression`
|
15476
16242
|
* - `scope` refers to the current scope
|
15477
|
-
* @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
|
16243
|
+
* @param {boolean=} [objectEquality=false] Compare for object equality using {@link angular.equals} instead of
|
15478
16244
|
* comparing for reference equality.
|
15479
16245
|
* @returns {function()} Returns a deregistration function for this listener.
|
15480
16246
|
*/
|
@@ -15839,7 +16605,7 @@ function $RootScopeProvider() {
|
|
15839
16605
|
*
|
15840
16606
|
*/
|
15841
16607
|
$digest: function() {
|
15842
|
-
var watch, value, last,
|
16608
|
+
var watch, value, last, fn, get,
|
15843
16609
|
watchers,
|
15844
16610
|
length,
|
15845
16611
|
dirty, ttl = TTL,
|
@@ -15885,7 +16651,8 @@ function $RootScopeProvider() {
|
|
15885
16651
|
// Most common watches are on primitives, in which case we can short
|
15886
16652
|
// circuit it with === operator, only when === fails do we use .equals
|
15887
16653
|
if (watch) {
|
15888
|
-
|
16654
|
+
get = watch.get;
|
16655
|
+
if ((value = get(current)) !== (last = watch.last) &&
|
15889
16656
|
!(watch.eq
|
15890
16657
|
? equals(value, last)
|
15891
16658
|
: (typeof value === 'number' && typeof last === 'number'
|
@@ -15893,7 +16660,8 @@ function $RootScopeProvider() {
|
|
15893
16660
|
dirty = true;
|
15894
16661
|
lastDirtyWatch = watch;
|
15895
16662
|
watch.last = watch.eq ? copy(value, null) : value;
|
15896
|
-
watch.fn
|
16663
|
+
fn = watch.fn;
|
16664
|
+
fn(value, ((last === initWatchVal) ? value : last), current);
|
15897
16665
|
if (ttl < 5) {
|
15898
16666
|
logIdx = 4 - ttl;
|
15899
16667
|
if (!watchLog[logIdx]) watchLog[logIdx] = [];
|
@@ -16093,7 +16861,7 @@ function $RootScopeProvider() {
|
|
16093
16861
|
});
|
16094
16862
|
}
|
16095
16863
|
|
16096
|
-
asyncQueue.push({scope: this, expression: expr, locals: locals});
|
16864
|
+
asyncQueue.push({scope: this, expression: $parse(expr), locals: locals});
|
16097
16865
|
},
|
16098
16866
|
|
16099
16867
|
$$postDigest: function(fn) {
|
@@ -16185,6 +16953,7 @@ function $RootScopeProvider() {
|
|
16185
16953
|
$applyAsync: function(expr) {
|
16186
16954
|
var scope = this;
|
16187
16955
|
expr && applyAsyncQueue.push($applyAsyncExpression);
|
16956
|
+
expr = $parse(expr);
|
16188
16957
|
scheduleApplyAsync();
|
16189
16958
|
|
16190
16959
|
function $applyAsyncExpression() {
|
@@ -16459,6 +17228,21 @@ function $RootScopeProvider() {
|
|
16459
17228
|
}];
|
16460
17229
|
}
|
16461
17230
|
|
17231
|
+
/**
|
17232
|
+
* @ngdoc service
|
17233
|
+
* @name $rootElement
|
17234
|
+
*
|
17235
|
+
* @description
|
17236
|
+
* The root element of Angular application. This is either the element where {@link
|
17237
|
+
* ng.directive:ngApp ngApp} was declared or the element passed into
|
17238
|
+
* {@link angular.bootstrap}. The element represents the root element of application. It is also the
|
17239
|
+
* location where the application's {@link auto.$injector $injector} service gets
|
17240
|
+
* published, and can be retrieved using `$rootElement.injector()`.
|
17241
|
+
*/
|
17242
|
+
|
17243
|
+
|
17244
|
+
// the implementation is in angular.bootstrap
|
17245
|
+
|
16462
17246
|
/**
|
16463
17247
|
* @description
|
16464
17248
|
* Private service to sanitize uris for links and images. Used by $compile and $sanitize.
|
@@ -16673,13 +17457,15 @@ function $SceDelegateProvider() {
|
|
16673
17457
|
* @kind function
|
16674
17458
|
*
|
16675
17459
|
* @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
|
16676
|
-
*
|
16677
|
-
*
|
17460
|
+
* provided. This must be an array or null. A snapshot of this array is used so further
|
17461
|
+
* changes to the array are ignored.
|
16678
17462
|
*
|
16679
|
-
*
|
16680
|
-
*
|
17463
|
+
* Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
|
17464
|
+
* allowed in this array.
|
16681
17465
|
*
|
16682
|
-
*
|
17466
|
+
* <div class="alert alert-warning">
|
17467
|
+
* **Note:** an empty whitelist array will block all URLs!
|
17468
|
+
* </div>
|
16683
17469
|
*
|
16684
17470
|
* @return {Array} the currently set whitelist array.
|
16685
17471
|
*
|
@@ -16702,17 +17488,17 @@ function $SceDelegateProvider() {
|
|
16702
17488
|
* @kind function
|
16703
17489
|
*
|
16704
17490
|
* @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
|
16705
|
-
*
|
16706
|
-
*
|
17491
|
+
* provided. This must be an array or null. A snapshot of this array is used so further
|
17492
|
+
* changes to the array are ignored.
|
16707
17493
|
*
|
16708
|
-
*
|
16709
|
-
*
|
17494
|
+
* Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
|
17495
|
+
* allowed in this array.
|
16710
17496
|
*
|
16711
|
-
*
|
16712
|
-
*
|
16713
|
-
*
|
17497
|
+
* The typical usage for the blacklist is to **block
|
17498
|
+
* [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
|
17499
|
+
* these would otherwise be trusted but actually return content from the redirected domain.
|
16714
17500
|
*
|
16715
|
-
*
|
17501
|
+
* Finally, **the blacklist overrides the whitelist** and has the final say.
|
16716
17502
|
*
|
16717
17503
|
* @return {Array} the currently set blacklist array.
|
16718
17504
|
*
|
@@ -16871,6 +17657,11 @@ function $SceDelegateProvider() {
|
|
16871
17657
|
* returns the originally supplied value if the queried context type is a supertype of the
|
16872
17658
|
* created type. If this condition isn't satisfied, throws an exception.
|
16873
17659
|
*
|
17660
|
+
* <div class="alert alert-danger">
|
17661
|
+
* Disabling auto-escaping is extremely dangerous, it usually creates a Cross Site Scripting
|
17662
|
+
* (XSS) vulnerability in your application.
|
17663
|
+
* </div>
|
17664
|
+
*
|
16874
17665
|
* @param {string} type The kind of context in which this value is to be used.
|
16875
17666
|
* @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
|
16876
17667
|
* `$sceDelegate.trustAs`} call.
|
@@ -17678,26 +18469,63 @@ function $SnifferProvider() {
|
|
17678
18469
|
var $compileMinErr = minErr('$compile');
|
17679
18470
|
|
17680
18471
|
/**
|
17681
|
-
* @ngdoc
|
17682
|
-
* @name $
|
17683
|
-
*
|
18472
|
+
* @ngdoc provider
|
18473
|
+
* @name $templateRequestProvider
|
17684
18474
|
* @description
|
17685
|
-
*
|
17686
|
-
* `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
|
17687
|
-
* fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
|
17688
|
-
* exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
|
17689
|
-
* contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
|
17690
|
-
* when `tpl` is of type string and `$templateCache` has the matching entry.
|
17691
|
-
*
|
17692
|
-
* @param {string|TrustedResourceUrl} tpl The HTTP request template URL
|
17693
|
-
* @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
|
18475
|
+
* Used to configure the options passed to the {@link $http} service when making a template request.
|
17694
18476
|
*
|
17695
|
-
*
|
17696
|
-
*
|
17697
|
-
* @property {number} totalPendingRequests total amount of pending template requests being downloaded.
|
18477
|
+
* For example, it can be used for specifying the "Accept" header that is sent to the server, when
|
18478
|
+
* requesting a template.
|
17698
18479
|
*/
|
17699
18480
|
function $TemplateRequestProvider() {
|
18481
|
+
|
18482
|
+
var httpOptions;
|
18483
|
+
|
18484
|
+
/**
|
18485
|
+
* @ngdoc method
|
18486
|
+
* @name $templateRequestProvider#httpOptions
|
18487
|
+
* @description
|
18488
|
+
* The options to be passed to the {@link $http} service when making the request.
|
18489
|
+
* You can use this to override options such as the "Accept" header for template requests.
|
18490
|
+
*
|
18491
|
+
* The {@link $templateRequest} will set the `cache` and the `transformResponse` properties of the
|
18492
|
+
* options if not overridden here.
|
18493
|
+
*
|
18494
|
+
* @param {string=} value new value for the {@link $http} options.
|
18495
|
+
* @returns {string|self} Returns the {@link $http} options when used as getter and self if used as setter.
|
18496
|
+
*/
|
18497
|
+
this.httpOptions = function(val) {
|
18498
|
+
if (val) {
|
18499
|
+
httpOptions = val;
|
18500
|
+
return this;
|
18501
|
+
}
|
18502
|
+
return httpOptions;
|
18503
|
+
};
|
18504
|
+
|
18505
|
+
/**
|
18506
|
+
* @ngdoc service
|
18507
|
+
* @name $templateRequest
|
18508
|
+
*
|
18509
|
+
* @description
|
18510
|
+
* The `$templateRequest` service runs security checks then downloads the provided template using
|
18511
|
+
* `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
|
18512
|
+
* fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
|
18513
|
+
* exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
|
18514
|
+
* contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
|
18515
|
+
* when `tpl` is of type string and `$templateCache` has the matching entry.
|
18516
|
+
*
|
18517
|
+
* If you want to pass custom options to the `$http` service, such as setting the Accept header you
|
18518
|
+
* can configure this via {@link $templateRequestProvider#httpOptions}.
|
18519
|
+
*
|
18520
|
+
* @param {string|TrustedResourceUrl} tpl The HTTP request template URL
|
18521
|
+
* @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
|
18522
|
+
*
|
18523
|
+
* @return {Promise} a promise for the HTTP response data of the given URL.
|
18524
|
+
*
|
18525
|
+
* @property {number} totalPendingRequests total amount of pending template requests being downloaded.
|
18526
|
+
*/
|
17700
18527
|
this.$get = ['$templateCache', '$http', '$q', '$sce', function($templateCache, $http, $q, $sce) {
|
18528
|
+
|
17701
18529
|
function handleRequestFn(tpl, ignoreRequestError) {
|
17702
18530
|
handleRequestFn.totalPendingRequests++;
|
17703
18531
|
|
@@ -17720,12 +18548,10 @@ function $TemplateRequestProvider() {
|
|
17720
18548
|
transformResponse = null;
|
17721
18549
|
}
|
17722
18550
|
|
17723
|
-
|
17724
|
-
|
17725
|
-
|
17726
|
-
|
17727
|
-
|
17728
|
-
return $http.get(tpl, httpOptions)
|
18551
|
+
return $http.get(tpl, extend({
|
18552
|
+
cache: $templateCache,
|
18553
|
+
transformResponse: transformResponse
|
18554
|
+
}, httpOptions))
|
17729
18555
|
['finally'](function() {
|
17730
18556
|
handleRequestFn.totalPendingRequests--;
|
17731
18557
|
})
|
@@ -17896,8 +18722,8 @@ function $TimeoutProvider() {
|
|
17896
18722
|
* @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
|
17897
18723
|
* will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
|
17898
18724
|
* @param {...*=} Pass additional parameters to the executed function.
|
17899
|
-
* @returns {Promise} Promise that will be resolved when the timeout is reached. The
|
17900
|
-
*
|
18725
|
+
* @returns {Promise} Promise that will be resolved when the timeout is reached. The promise
|
18726
|
+
* will be resolved with the return value of the `fn` function.
|
17901
18727
|
*
|
17902
18728
|
*/
|
17903
18729
|
function timeout(fn, delay, invokeApply) {
|
@@ -18573,6 +19399,10 @@ function getTypeForFilter(val) {
|
|
18573
19399
|
return (val === null) ? 'null' : typeof val;
|
18574
19400
|
}
|
18575
19401
|
|
19402
|
+
var MAX_DIGITS = 22;
|
19403
|
+
var DECIMAL_SEP = '.';
|
19404
|
+
var ZERO_CHAR = '0';
|
19405
|
+
|
18576
19406
|
/**
|
18577
19407
|
* @ngdoc filter
|
18578
19408
|
* @name currency
|
@@ -18662,7 +19492,7 @@ function currencyFilter($locale) {
|
|
18662
19492
|
* @param {(number|string)=} fractionSize Number of decimal places to round the number to.
|
18663
19493
|
* If this is not provided then the fraction size is computed from the current locale's number
|
18664
19494
|
* formatting pattern. In the case of the default locale, it will be 3.
|
18665
|
-
* @returns {string} Number rounded to
|
19495
|
+
* @returns {string} Number rounded to fractionSize and places a “,” after each third digit.
|
18666
19496
|
*
|
18667
19497
|
* @example
|
18668
19498
|
<example module="numberFilterExample">
|
@@ -18697,8 +19527,6 @@ function currencyFilter($locale) {
|
|
18697
19527
|
</file>
|
18698
19528
|
</example>
|
18699
19529
|
*/
|
18700
|
-
|
18701
|
-
|
18702
19530
|
numberFilter.$inject = ['$locale'];
|
18703
19531
|
function numberFilter($locale) {
|
18704
19532
|
var formats = $locale.NUMBER_FORMATS;
|
@@ -18712,93 +19540,194 @@ function numberFilter($locale) {
|
|
18712
19540
|
};
|
18713
19541
|
}
|
18714
19542
|
|
18715
|
-
|
18716
|
-
|
18717
|
-
|
19543
|
+
/**
|
19544
|
+
* Parse a number (as a string) into three components that can be used
|
19545
|
+
* for formatting the number.
|
19546
|
+
*
|
19547
|
+
* (Significant bits of this parse algorithm came from https://github.com/MikeMcl/big.js/)
|
19548
|
+
*
|
19549
|
+
* @param {string} numStr The number to parse
|
19550
|
+
* @return {object} An object describing this number, containing the following keys:
|
19551
|
+
* - d : an array of digits containing leading zeros as necessary
|
19552
|
+
* - i : the number of the digits in `d` that are to the left of the decimal point
|
19553
|
+
* - e : the exponent for numbers that would need more than `MAX_DIGITS` digits in `d`
|
19554
|
+
*
|
19555
|
+
*/
|
19556
|
+
function parse(numStr) {
|
19557
|
+
var exponent = 0, digits, numberOfIntegerDigits;
|
19558
|
+
var i, j, zeros;
|
18718
19559
|
|
18719
|
-
|
18720
|
-
|
19560
|
+
// Decimal point?
|
19561
|
+
if ((numberOfIntegerDigits = numStr.indexOf(DECIMAL_SEP)) > -1) {
|
19562
|
+
numStr = numStr.replace(DECIMAL_SEP, '');
|
19563
|
+
}
|
18721
19564
|
|
18722
|
-
|
18723
|
-
if (
|
19565
|
+
// Exponential form?
|
19566
|
+
if ((i = numStr.search(/e/i)) > 0) {
|
19567
|
+
// Work out the exponent.
|
19568
|
+
if (numberOfIntegerDigits < 0) numberOfIntegerDigits = i;
|
19569
|
+
numberOfIntegerDigits += +numStr.slice(i + 1);
|
19570
|
+
numStr = numStr.substring(0, i);
|
19571
|
+
} else if (numberOfIntegerDigits < 0) {
|
19572
|
+
// There was no decimal point or exponent so it is an integer.
|
19573
|
+
numberOfIntegerDigits = numStr.length;
|
19574
|
+
}
|
18724
19575
|
|
18725
|
-
|
18726
|
-
|
18727
|
-
hasExponent = false,
|
18728
|
-
parts = [];
|
19576
|
+
// Count the number of leading zeros.
|
19577
|
+
for (i = 0; numStr.charAt(i) == ZERO_CHAR; i++);
|
18729
19578
|
|
18730
|
-
if (
|
19579
|
+
if (i == (zeros = numStr.length)) {
|
19580
|
+
// The digits are all zero.
|
19581
|
+
digits = [0];
|
19582
|
+
numberOfIntegerDigits = 1;
|
19583
|
+
} else {
|
19584
|
+
// Count the number of trailing zeros
|
19585
|
+
zeros--;
|
19586
|
+
while (numStr.charAt(zeros) == ZERO_CHAR) zeros--;
|
18731
19587
|
|
18732
|
-
|
18733
|
-
|
18734
|
-
|
18735
|
-
|
18736
|
-
|
18737
|
-
|
18738
|
-
hasExponent = true;
|
19588
|
+
// Trailing zeros are insignificant so ignore them
|
19589
|
+
numberOfIntegerDigits -= i;
|
19590
|
+
digits = [];
|
19591
|
+
// Convert string to array of digits without leading/trailing zeros.
|
19592
|
+
for (j = 0; i <= zeros; i++, j++) {
|
19593
|
+
digits[j] = +numStr.charAt(i);
|
18739
19594
|
}
|
18740
19595
|
}
|
18741
19596
|
|
18742
|
-
|
18743
|
-
|
19597
|
+
// If the number overflows the maximum allowed digits then use an exponent.
|
19598
|
+
if (numberOfIntegerDigits > MAX_DIGITS) {
|
19599
|
+
digits = digits.splice(0, MAX_DIGITS - 1);
|
19600
|
+
exponent = numberOfIntegerDigits - 1;
|
19601
|
+
numberOfIntegerDigits = 1;
|
19602
|
+
}
|
18744
19603
|
|
18745
|
-
|
18746
|
-
|
18747
|
-
|
19604
|
+
return { d: digits, e: exponent, i: numberOfIntegerDigits };
|
19605
|
+
}
|
19606
|
+
|
19607
|
+
/**
|
19608
|
+
* Round the parsed number to the specified number of decimal places
|
19609
|
+
* This function changed the parsedNumber in-place
|
19610
|
+
*/
|
19611
|
+
function roundNumber(parsedNumber, fractionSize, minFrac, maxFrac) {
|
19612
|
+
var digits = parsedNumber.d;
|
19613
|
+
var fractionLen = digits.length - parsedNumber.i;
|
19614
|
+
|
19615
|
+
// determine fractionSize if it is not specified; `+fractionSize` converts it to a number
|
19616
|
+
fractionSize = (isUndefined(fractionSize)) ? Math.min(Math.max(minFrac, fractionLen), maxFrac) : +fractionSize;
|
19617
|
+
|
19618
|
+
// The index of the digit to where rounding is to occur
|
19619
|
+
var roundAt = fractionSize + parsedNumber.i;
|
19620
|
+
var digit = digits[roundAt];
|
19621
|
+
|
19622
|
+
if (roundAt > 0) {
|
19623
|
+
digits.splice(roundAt);
|
19624
|
+
} else {
|
19625
|
+
// We rounded to zero so reset the parsedNumber
|
19626
|
+
parsedNumber.i = 1;
|
19627
|
+
digits.length = roundAt = fractionSize + 1;
|
19628
|
+
for (var i=0; i < roundAt; i++) digits[i] = 0;
|
18748
19629
|
}
|
18749
19630
|
|
18750
|
-
|
18751
|
-
// inspired by:
|
18752
|
-
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
|
18753
|
-
number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
|
19631
|
+
if (digit >= 5) digits[roundAt - 1]++;
|
18754
19632
|
|
18755
|
-
|
18756
|
-
|
18757
|
-
fraction = fraction[1] || '';
|
19633
|
+
// Pad out with zeros to get the required fraction length
|
19634
|
+
for (; fractionLen < fractionSize; fractionLen++) digits.push(0);
|
18758
19635
|
|
18759
|
-
var i, pos = 0,
|
18760
|
-
lgroup = pattern.lgSize,
|
18761
|
-
group = pattern.gSize;
|
18762
19636
|
|
18763
|
-
|
18764
|
-
|
18765
|
-
|
18766
|
-
|
18767
|
-
|
18768
|
-
|
18769
|
-
|
18770
|
-
|
19637
|
+
// Do any carrying, e.g. a digit was rounded up to 10
|
19638
|
+
var carry = digits.reduceRight(function(carry, d, i, digits) {
|
19639
|
+
d = d + carry;
|
19640
|
+
digits[i] = d % 10;
|
19641
|
+
return Math.floor(d / 10);
|
19642
|
+
}, 0);
|
19643
|
+
if (carry) {
|
19644
|
+
digits.unshift(carry);
|
19645
|
+
parsedNumber.i++;
|
18771
19646
|
}
|
19647
|
+
}
|
18772
19648
|
|
18773
|
-
|
18774
|
-
|
18775
|
-
|
18776
|
-
|
18777
|
-
|
19649
|
+
/**
|
19650
|
+
* Format a number into a string
|
19651
|
+
* @param {number} number The number to format
|
19652
|
+
* @param {{
|
19653
|
+
* minFrac, // the minimum number of digits required in the fraction part of the number
|
19654
|
+
* maxFrac, // the maximum number of digits required in the fraction part of the number
|
19655
|
+
* gSize, // number of digits in each group of separated digits
|
19656
|
+
* lgSize, // number of digits in the last group of digits before the decimal separator
|
19657
|
+
* negPre, // the string to go in front of a negative number (e.g. `-` or `(`))
|
19658
|
+
* posPre, // the string to go in front of a positive number
|
19659
|
+
* negSuf, // the string to go after a negative number (e.g. `)`)
|
19660
|
+
* posSuf // the string to go after a positive number
|
19661
|
+
* }} pattern
|
19662
|
+
* @param {string} groupSep The string to separate groups of number (e.g. `,`)
|
19663
|
+
* @param {string} decimalSep The string to act as the decimal separator (e.g. `.`)
|
19664
|
+
* @param {[type]} fractionSize The size of the fractional part of the number
|
19665
|
+
* @return {string} The number formatted as a string
|
19666
|
+
*/
|
19667
|
+
function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
|
19668
|
+
|
19669
|
+
if (!(isString(number) || isNumber(number)) || isNaN(number)) return '';
|
19670
|
+
|
19671
|
+
var isInfinity = !isFinite(number);
|
19672
|
+
var isZero = false;
|
19673
|
+
var numStr = Math.abs(number) + '',
|
19674
|
+
formattedText = '',
|
19675
|
+
parsedNumber;
|
19676
|
+
|
19677
|
+
if (isInfinity) {
|
19678
|
+
formattedText = '\u221e';
|
19679
|
+
} else {
|
19680
|
+
parsedNumber = parse(numStr);
|
19681
|
+
|
19682
|
+
roundNumber(parsedNumber, fractionSize, pattern.minFrac, pattern.maxFrac);
|
19683
|
+
|
19684
|
+
var digits = parsedNumber.d;
|
19685
|
+
var integerLen = parsedNumber.i;
|
19686
|
+
var exponent = parsedNumber.e;
|
19687
|
+
var decimals = [];
|
19688
|
+
isZero = digits.reduce(function(isZero, d) { return isZero && !d; }, true);
|
19689
|
+
|
19690
|
+
// pad zeros for small numbers
|
19691
|
+
while (integerLen < 0) {
|
19692
|
+
digits.unshift(0);
|
19693
|
+
integerLen++;
|
18778
19694
|
}
|
18779
19695
|
|
18780
|
-
//
|
18781
|
-
|
18782
|
-
|
19696
|
+
// extract decimals digits
|
19697
|
+
if (integerLen > 0) {
|
19698
|
+
decimals = digits.splice(integerLen);
|
19699
|
+
} else {
|
19700
|
+
decimals = digits;
|
19701
|
+
digits = [0];
|
18783
19702
|
}
|
18784
19703
|
|
18785
|
-
|
18786
|
-
|
18787
|
-
if (
|
18788
|
-
|
18789
|
-
number = parseFloat(formatedText);
|
18790
|
-
formatedText = formatedText.replace(DECIMAL_SEP, decimalSep);
|
19704
|
+
// format the integer digits with grouping separators
|
19705
|
+
var groups = [];
|
19706
|
+
if (digits.length > pattern.lgSize) {
|
19707
|
+
groups.unshift(digits.splice(-pattern.lgSize).join(''));
|
18791
19708
|
}
|
18792
|
-
|
19709
|
+
while (digits.length > pattern.gSize) {
|
19710
|
+
groups.unshift(digits.splice(-pattern.gSize).join(''));
|
19711
|
+
}
|
19712
|
+
if (digits.length) {
|
19713
|
+
groups.unshift(digits.join(''));
|
19714
|
+
}
|
19715
|
+
formattedText = groups.join(groupSep);
|
18793
19716
|
|
18794
|
-
|
18795
|
-
|
18796
|
-
|
19717
|
+
// append the decimal digits
|
19718
|
+
if (decimals.length) {
|
19719
|
+
formattedText += decimalSep + decimals.join('');
|
19720
|
+
}
|
18797
19721
|
|
18798
|
-
|
18799
|
-
|
18800
|
-
|
18801
|
-
|
19722
|
+
if (exponent) {
|
19723
|
+
formattedText += 'e+' + exponent;
|
19724
|
+
}
|
19725
|
+
}
|
19726
|
+
if (number < 0 && !isZero) {
|
19727
|
+
return pattern.negPre + formattedText + pattern.negSuf;
|
19728
|
+
} else {
|
19729
|
+
return pattern.posPre + formattedText + pattern.posSuf;
|
19730
|
+
}
|
18802
19731
|
}
|
18803
19732
|
|
18804
19733
|
function padNumber(num, digits, trim) {
|
@@ -18808,7 +19737,7 @@ function padNumber(num, digits, trim) {
|
|
18808
19737
|
num = -num;
|
18809
19738
|
}
|
18810
19739
|
num = '' + num;
|
18811
|
-
while (num.length < digits) num =
|
19740
|
+
while (num.length < digits) num = ZERO_CHAR + num;
|
18812
19741
|
if (trim) {
|
18813
19742
|
num = num.substr(num.length - digits);
|
18814
19743
|
}
|
@@ -19077,13 +20006,13 @@ function dateFilter($locale) {
|
|
19077
20006
|
|
19078
20007
|
var dateTimezoneOffset = date.getTimezoneOffset();
|
19079
20008
|
if (timezone) {
|
19080
|
-
dateTimezoneOffset = timezoneToOffset(timezone,
|
20009
|
+
dateTimezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
|
19081
20010
|
date = convertTimezoneToLocal(date, timezone, true);
|
19082
20011
|
}
|
19083
20012
|
forEach(parts, function(value) {
|
19084
20013
|
fn = DATE_FORMATS[value];
|
19085
20014
|
text += fn ? fn(date, $locale.DATETIME_FORMATS, dateTimezoneOffset)
|
19086
|
-
: value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
|
20015
|
+
: value === "''" ? "'" : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
|
19087
20016
|
});
|
19088
20017
|
|
19089
20018
|
return text;
|
@@ -19287,8 +20216,9 @@ function limitToFilter() {
|
|
19287
20216
|
* Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
|
19288
20217
|
* for strings and numerically for numbers. Note: if you notice numbers are not being sorted
|
19289
20218
|
* as expected, make sure they are actually being saved as numbers and not strings.
|
20219
|
+
* Array-like values (e.g. NodeLists, jQuery objects, TypedArrays, Strings, etc) are also supported.
|
19290
20220
|
*
|
19291
|
-
* @param {Array} array The array to sort.
|
20221
|
+
* @param {Array} array The array (or array-like object) to sort.
|
19292
20222
|
* @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
|
19293
20223
|
* used by the comparator to determine the order of elements.
|
19294
20224
|
*
|
@@ -19319,17 +20249,6 @@ function limitToFilter() {
|
|
19319
20249
|
* `reverse` is not set, which means it defaults to `false`.
|
19320
20250
|
<example module="orderByExample">
|
19321
20251
|
<file name="index.html">
|
19322
|
-
<script>
|
19323
|
-
angular.module('orderByExample', [])
|
19324
|
-
.controller('ExampleController', ['$scope', function($scope) {
|
19325
|
-
$scope.friends =
|
19326
|
-
[{name:'John', phone:'555-1212', age:10},
|
19327
|
-
{name:'Mary', phone:'555-9876', age:19},
|
19328
|
-
{name:'Mike', phone:'555-4321', age:21},
|
19329
|
-
{name:'Adam', phone:'555-5678', age:35},
|
19330
|
-
{name:'Julie', phone:'555-8765', age:29}];
|
19331
|
-
}]);
|
19332
|
-
</script>
|
19333
20252
|
<div ng-controller="ExampleController">
|
19334
20253
|
<table class="friend">
|
19335
20254
|
<tr>
|
@@ -19345,6 +20264,17 @@ function limitToFilter() {
|
|
19345
20264
|
</table>
|
19346
20265
|
</div>
|
19347
20266
|
</file>
|
20267
|
+
<file name="script.js">
|
20268
|
+
angular.module('orderByExample', [])
|
20269
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
20270
|
+
$scope.friends =
|
20271
|
+
[{name:'John', phone:'555-1212', age:10},
|
20272
|
+
{name:'Mary', phone:'555-9876', age:19},
|
20273
|
+
{name:'Mike', phone:'555-4321', age:21},
|
20274
|
+
{name:'Adam', phone:'555-5678', age:35},
|
20275
|
+
{name:'Julie', phone:'555-8765', age:29}];
|
20276
|
+
}]);
|
20277
|
+
</file>
|
19348
20278
|
</example>
|
19349
20279
|
*
|
19350
20280
|
* The predicate and reverse parameters can be controlled dynamically through scope properties,
|
@@ -19352,49 +20282,24 @@ function limitToFilter() {
|
|
19352
20282
|
* @example
|
19353
20283
|
<example module="orderByExample">
|
19354
20284
|
<file name="index.html">
|
19355
|
-
<script>
|
19356
|
-
angular.module('orderByExample', [])
|
19357
|
-
.controller('ExampleController', ['$scope', function($scope) {
|
19358
|
-
$scope.friends =
|
19359
|
-
[{name:'John', phone:'555-1212', age:10},
|
19360
|
-
{name:'Mary', phone:'555-9876', age:19},
|
19361
|
-
{name:'Mike', phone:'555-4321', age:21},
|
19362
|
-
{name:'Adam', phone:'555-5678', age:35},
|
19363
|
-
{name:'Julie', phone:'555-8765', age:29}];
|
19364
|
-
$scope.predicate = 'age';
|
19365
|
-
$scope.reverse = true;
|
19366
|
-
$scope.order = function(predicate) {
|
19367
|
-
$scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
|
19368
|
-
$scope.predicate = predicate;
|
19369
|
-
};
|
19370
|
-
}]);
|
19371
|
-
</script>
|
19372
|
-
<style type="text/css">
|
19373
|
-
.sortorder:after {
|
19374
|
-
content: '\25b2';
|
19375
|
-
}
|
19376
|
-
.sortorder.reverse:after {
|
19377
|
-
content: '\25bc';
|
19378
|
-
}
|
19379
|
-
</style>
|
19380
20285
|
<div ng-controller="ExampleController">
|
19381
20286
|
<pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
|
19382
20287
|
<hr/>
|
19383
|
-
|
20288
|
+
<button ng-click="predicate=''">Set to unsorted</button>
|
19384
20289
|
<table class="friend">
|
19385
20290
|
<tr>
|
19386
|
-
|
19387
|
-
|
19388
|
-
|
19389
|
-
|
19390
|
-
|
19391
|
-
|
19392
|
-
|
19393
|
-
|
19394
|
-
|
19395
|
-
|
19396
|
-
|
19397
|
-
|
20291
|
+
<th>
|
20292
|
+
<button ng-click="order('name')">Name</button>
|
20293
|
+
<span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
|
20294
|
+
</th>
|
20295
|
+
<th>
|
20296
|
+
<button ng-click="order('phone')">Phone Number</button>
|
20297
|
+
<span class="sortorder" ng-show="predicate === 'phone'" ng-class="{reverse:reverse}"></span>
|
20298
|
+
</th>
|
20299
|
+
<th>
|
20300
|
+
<button ng-click="order('age')">Age</button>
|
20301
|
+
<span class="sortorder" ng-show="predicate === 'age'" ng-class="{reverse:reverse}"></span>
|
20302
|
+
</th>
|
19398
20303
|
</tr>
|
19399
20304
|
<tr ng-repeat="friend in friends | orderBy:predicate:reverse">
|
19400
20305
|
<td>{{friend.name}}</td>
|
@@ -19404,6 +20309,31 @@ function limitToFilter() {
|
|
19404
20309
|
</table>
|
19405
20310
|
</div>
|
19406
20311
|
</file>
|
20312
|
+
<file name="script.js">
|
20313
|
+
angular.module('orderByExample', [])
|
20314
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
20315
|
+
$scope.friends =
|
20316
|
+
[{name:'John', phone:'555-1212', age:10},
|
20317
|
+
{name:'Mary', phone:'555-9876', age:19},
|
20318
|
+
{name:'Mike', phone:'555-4321', age:21},
|
20319
|
+
{name:'Adam', phone:'555-5678', age:35},
|
20320
|
+
{name:'Julie', phone:'555-8765', age:29}];
|
20321
|
+
$scope.predicate = 'age';
|
20322
|
+
$scope.reverse = true;
|
20323
|
+
$scope.order = function(predicate) {
|
20324
|
+
$scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
|
20325
|
+
$scope.predicate = predicate;
|
20326
|
+
};
|
20327
|
+
}]);
|
20328
|
+
</file>
|
20329
|
+
<file name="style.css">
|
20330
|
+
.sortorder:after {
|
20331
|
+
content: '\25b2';
|
20332
|
+
}
|
20333
|
+
.sortorder.reverse:after {
|
20334
|
+
content: '\25bc';
|
20335
|
+
}
|
20336
|
+
</file>
|
19407
20337
|
</example>
|
19408
20338
|
*
|
19409
20339
|
* It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
|
@@ -19415,21 +20345,30 @@ function limitToFilter() {
|
|
19415
20345
|
* @example
|
19416
20346
|
<example module="orderByExample">
|
19417
20347
|
<file name="index.html">
|
19418
|
-
|
19419
|
-
|
19420
|
-
|
19421
|
-
|
19422
|
-
|
19423
|
-
|
19424
|
-
|
19425
|
-
</
|
19426
|
-
<
|
19427
|
-
|
19428
|
-
|
19429
|
-
|
19430
|
-
|
19431
|
-
|
19432
|
-
|
20348
|
+
<div ng-controller="ExampleController">
|
20349
|
+
<pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
|
20350
|
+
<table class="friend">
|
20351
|
+
<tr>
|
20352
|
+
<th>
|
20353
|
+
<button ng-click="order('name')">Name</button>
|
20354
|
+
<span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
|
20355
|
+
</th>
|
20356
|
+
<th>
|
20357
|
+
<button ng-click="order('phone')">Phone Number</button>
|
20358
|
+
<span class="sortorder" ng-show="predicate === 'phone'" ng-class="{reverse:reverse}"></span>
|
20359
|
+
</th>
|
20360
|
+
<th>
|
20361
|
+
<button ng-click="order('age')">Age</button>
|
20362
|
+
<span class="sortorder" ng-show="predicate === 'age'" ng-class="{reverse:reverse}"></span>
|
20363
|
+
</th>
|
20364
|
+
</tr>
|
20365
|
+
<tr ng-repeat="friend in friends">
|
20366
|
+
<td>{{friend.name}}</td>
|
20367
|
+
<td>{{friend.phone}}</td>
|
20368
|
+
<td>{{friend.age}}</td>
|
20369
|
+
</tr>
|
20370
|
+
</table>
|
20371
|
+
</div>
|
19433
20372
|
</file>
|
19434
20373
|
|
19435
20374
|
<file name="script.js">
|
@@ -19443,19 +20382,33 @@ function limitToFilter() {
|
|
19443
20382
|
{ name: 'Adam', phone: '555-5678', age: 35 },
|
19444
20383
|
{ name: 'Julie', phone: '555-8765', age: 29 }
|
19445
20384
|
];
|
19446
|
-
$scope.order = function(predicate
|
19447
|
-
$scope.
|
20385
|
+
$scope.order = function(predicate) {
|
20386
|
+
$scope.predicate = predicate;
|
20387
|
+
$scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
|
20388
|
+
$scope.friends = orderBy($scope.friends, predicate, $scope.reverse);
|
19448
20389
|
};
|
19449
|
-
$scope.order('
|
20390
|
+
$scope.order('age', true);
|
19450
20391
|
}]);
|
19451
20392
|
</file>
|
20393
|
+
|
20394
|
+
<file name="style.css">
|
20395
|
+
.sortorder:after {
|
20396
|
+
content: '\25b2';
|
20397
|
+
}
|
20398
|
+
.sortorder.reverse:after {
|
20399
|
+
content: '\25bc';
|
20400
|
+
}
|
20401
|
+
</file>
|
19452
20402
|
</example>
|
19453
20403
|
*/
|
19454
20404
|
orderByFilter.$inject = ['$parse'];
|
19455
20405
|
function orderByFilter($parse) {
|
19456
20406
|
return function(array, sortPredicate, reverseOrder) {
|
19457
20407
|
|
19458
|
-
if (
|
20408
|
+
if (array == null) return array;
|
20409
|
+
if (!isArrayLike(array)) {
|
20410
|
+
throw minErr('orderBy')('notarray', 'Expected array but received: {0}', array);
|
20411
|
+
}
|
19459
20412
|
|
19460
20413
|
if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }
|
19461
20414
|
if (sortPredicate.length === 0) { sortPredicate = ['+']; }
|
@@ -19778,20 +20731,7 @@ var htmlAnchorDirective = valueFn({
|
|
19778
20731
|
* {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
|
19779
20732
|
*
|
19780
20733
|
* A special directive is necessary because we cannot use interpolation inside the `disabled`
|
19781
|
-
* attribute.
|
19782
|
-
* but not on older IEs:
|
19783
|
-
*
|
19784
|
-
* ```html
|
19785
|
-
* <!-- See below for an example of ng-disabled being used correctly -->
|
19786
|
-
* <div ng-init="isDisabled = false">
|
19787
|
-
* <button disabled="{{isDisabled}}">Disabled</button>
|
19788
|
-
* </div>
|
19789
|
-
* ```
|
19790
|
-
*
|
19791
|
-
* This is because the HTML specification does not require browsers to preserve the values of
|
19792
|
-
* boolean attributes such as `disabled` (Their presence means true and their absence means false.)
|
19793
|
-
* If we put an Angular interpolation expression into such an attribute then the
|
19794
|
-
* binding information would be lost when the browser removes the attribute.
|
20734
|
+
* attribute. See the {@link guide/interpolation interpolation guide} for more info.
|
19795
20735
|
*
|
19796
20736
|
* @example
|
19797
20737
|
<example>
|
@@ -19826,15 +20766,9 @@ var htmlAnchorDirective = valueFn({
|
|
19826
20766
|
* Note that this directive should not be used together with {@link ngModel `ngModel`},
|
19827
20767
|
* as this can lead to unexpected behavior.
|
19828
20768
|
*
|
19829
|
-
*
|
20769
|
+
* A special directive is necessary because we cannot use interpolation inside the `checked`
|
20770
|
+
* attribute. See the {@link guide/interpolation interpolation guide} for more info.
|
19830
20771
|
*
|
19831
|
-
* The HTML specification does not require browsers to preserve the values of boolean attributes
|
19832
|
-
* such as checked. (Their presence means true and their absence means false.)
|
19833
|
-
* If we put an Angular interpolation expression into such an attribute then the
|
19834
|
-
* binding information would be lost when the browser removes the attribute.
|
19835
|
-
* The `ngChecked` directive solves this problem for the `checked` attribute.
|
19836
|
-
* This complementary directive is not removed by the browser and so provides
|
19837
|
-
* a permanent reliable place to store the binding information.
|
19838
20772
|
* @example
|
19839
20773
|
<example>
|
19840
20774
|
<file name="index.html">
|
@@ -19863,13 +20797,12 @@ var htmlAnchorDirective = valueFn({
|
|
19863
20797
|
* @priority 100
|
19864
20798
|
*
|
19865
20799
|
* @description
|
19866
|
-
*
|
19867
|
-
*
|
19868
|
-
*
|
19869
|
-
*
|
19870
|
-
*
|
19871
|
-
*
|
19872
|
-
* a permanent reliable place to store the binding information.
|
20800
|
+
*
|
20801
|
+
* Sets the `readOnly` attribute on the element, if the expression inside `ngReadonly` is truthy.
|
20802
|
+
*
|
20803
|
+
* A special directive is necessary because we cannot use interpolation inside the `readOnly`
|
20804
|
+
* attribute. See the {@link guide/interpolation interpolation guide} for more info.
|
20805
|
+
*
|
19873
20806
|
* @example
|
19874
20807
|
<example>
|
19875
20808
|
<file name="index.html">
|
@@ -19898,13 +20831,11 @@ var htmlAnchorDirective = valueFn({
|
|
19898
20831
|
* @priority 100
|
19899
20832
|
*
|
19900
20833
|
* @description
|
19901
|
-
*
|
19902
|
-
*
|
19903
|
-
*
|
19904
|
-
*
|
19905
|
-
*
|
19906
|
-
* This complementary directive is not removed by the browser and so provides
|
19907
|
-
* a permanent reliable place to store the binding information.
|
20834
|
+
*
|
20835
|
+
* Sets the `selected` attribute on the element, if the expression inside `ngSelected` is truthy.
|
20836
|
+
*
|
20837
|
+
* A special directive is necessary because we cannot use interpolation inside the `selected`
|
20838
|
+
* attribute. See the {@link guide/interpolation interpolation guide} for more info.
|
19908
20839
|
*
|
19909
20840
|
* @example
|
19910
20841
|
<example>
|
@@ -19936,13 +20867,12 @@ var htmlAnchorDirective = valueFn({
|
|
19936
20867
|
* @priority 100
|
19937
20868
|
*
|
19938
20869
|
* @description
|
19939
|
-
*
|
19940
|
-
*
|
19941
|
-
*
|
19942
|
-
*
|
19943
|
-
*
|
19944
|
-
*
|
19945
|
-
* a permanent reliable place to store the binding information.
|
20870
|
+
*
|
20871
|
+
* Sets the `open` attribute on the element, if the expression inside `ngOpen` is truthy.
|
20872
|
+
*
|
20873
|
+
* A special directive is necessary because we cannot use interpolation inside the `open`
|
20874
|
+
* attribute. See the {@link guide/interpolation interpolation guide} for more info.
|
20875
|
+
*
|
19946
20876
|
* @example
|
19947
20877
|
<example>
|
19948
20878
|
<file name="index.html">
|
@@ -20188,7 +21118,7 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
|
|
20188
21118
|
*
|
20189
21119
|
* However, if the method is used programmatically, for example by adding dynamically created controls,
|
20190
21120
|
* or controls that have been previously removed without destroying their corresponding DOM element,
|
20191
|
-
* it's the developers
|
21121
|
+
* it's the developers responsibility to make sure the current state propagates to the parent form.
|
20192
21122
|
*
|
20193
21123
|
* For example, if an input control is added that is already `$dirty` and has `$error` properties,
|
20194
21124
|
* calling `$setDirty()` and `$validate()` afterwards will propagate the state to the parent form.
|
@@ -20398,13 +21328,9 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
|
|
20398
21328
|
*
|
20399
21329
|
* In Angular, forms can be nested. This means that the outer form is valid when all of the child
|
20400
21330
|
* forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
|
20401
|
-
* Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
|
20402
|
-
*
|
20403
|
-
*
|
20404
|
-
* {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
|
20405
|
-
* attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
|
20406
|
-
* `ngForm` directive and nest these in an outer `form` element.
|
20407
|
-
*
|
21331
|
+
* Angular provides the {@link ng.directive:ngForm `ngForm`} directive, which behaves identically to
|
21332
|
+
* `form` but can be nested. Nested forms can be useful, for example, if the validity of a sub-group
|
21333
|
+
* of controls needs to be determined.
|
20408
21334
|
*
|
20409
21335
|
* # CSS classes
|
20410
21336
|
* - `ng-valid` is set if the form is valid.
|
@@ -20625,7 +21551,18 @@ var ngFormDirective = formDirectiveFactory(true);
|
|
20625
21551
|
// Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
|
20626
21552
|
var ISO_DATE_REGEXP = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/;
|
20627
21553
|
// See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987)
|
20628
|
-
|
21554
|
+
// Note: We are being more lenient, because browsers are too.
|
21555
|
+
// 1. Scheme
|
21556
|
+
// 2. Slashes
|
21557
|
+
// 3. Username
|
21558
|
+
// 4. Password
|
21559
|
+
// 5. Hostname
|
21560
|
+
// 6. Port
|
21561
|
+
// 7. Path
|
21562
|
+
// 8. Query
|
21563
|
+
// 9. Fragment
|
21564
|
+
// 1111111111111111 222 333333 44444 555555555555555555555555 666 77777777 8888888 999
|
21565
|
+
var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+\])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
|
20629
21566
|
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
|
20630
21567
|
var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
|
20631
21568
|
var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
|
@@ -20658,8 +21595,8 @@ var inputType = {
|
|
20658
21595
|
* @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
|
20659
21596
|
* that contains the regular expression body that will be converted to a regular expression
|
20660
21597
|
* as in the ngPattern directive.
|
20661
|
-
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel
|
20662
|
-
* a RegExp found by evaluating the Angular expression given in the attribute value.
|
21598
|
+
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
|
21599
|
+
* does not match a RegExp found by evaluating the Angular expression given in the attribute value.
|
20663
21600
|
* If the expression evaluates to a RegExp object, then this is used directly.
|
20664
21601
|
* If the expression evaluates to a string, then it will be converted to a RegExp
|
20665
21602
|
* after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
|
@@ -20946,7 +21883,7 @@ var inputType = {
|
|
20946
21883
|
*
|
20947
21884
|
* @description
|
20948
21885
|
* Input with time validation and transformation. In browsers that do not yet support
|
20949
|
-
* the HTML5
|
21886
|
+
* the HTML5 time input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
|
20950
21887
|
* local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
|
20951
21888
|
* Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
|
20952
21889
|
*
|
@@ -21293,8 +22230,8 @@ var inputType = {
|
|
21293
22230
|
* @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
|
21294
22231
|
* that contains the regular expression body that will be converted to a regular expression
|
21295
22232
|
* as in the ngPattern directive.
|
21296
|
-
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel
|
21297
|
-
* a RegExp found by evaluating the Angular expression given in the attribute value.
|
22233
|
+
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
|
22234
|
+
* does not match a RegExp found by evaluating the Angular expression given in the attribute value.
|
21298
22235
|
* If the expression evaluates to a RegExp object, then this is used directly.
|
21299
22236
|
* If the expression evaluates to a string, then it will be converted to a RegExp
|
21300
22237
|
* after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
|
@@ -21391,8 +22328,8 @@ var inputType = {
|
|
21391
22328
|
* @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
|
21392
22329
|
* that contains the regular expression body that will be converted to a regular expression
|
21393
22330
|
* as in the ngPattern directive.
|
21394
|
-
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel
|
21395
|
-
* a RegExp found by evaluating the Angular expression given in the attribute value.
|
22331
|
+
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
|
22332
|
+
* does not match a RegExp found by evaluating the Angular expression given in the attribute value.
|
21396
22333
|
* If the expression evaluates to a RegExp object, then this is used directly.
|
21397
22334
|
* If the expression evaluates to a string, then it will be converted to a RegExp
|
21398
22335
|
* after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
|
@@ -21490,8 +22427,8 @@ var inputType = {
|
|
21490
22427
|
* @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
|
21491
22428
|
* that contains the regular expression body that will be converted to a regular expression
|
21492
22429
|
* as in the ngPattern directive.
|
21493
|
-
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel
|
21494
|
-
* a RegExp found by evaluating the Angular expression given in the attribute value.
|
22430
|
+
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
|
22431
|
+
* does not match a RegExp found by evaluating the Angular expression given in the attribute value.
|
21495
22432
|
* If the expression evaluates to a RegExp object, then this is used directly.
|
21496
22433
|
* If the expression evaluates to a string, then it will be converted to a RegExp
|
21497
22434
|
* after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
|
@@ -21951,11 +22888,7 @@ function badInputChecker(scope, element, attr, ctrl) {
|
|
21951
22888
|
if (nativeValidation) {
|
21952
22889
|
ctrl.$parsers.push(function(value) {
|
21953
22890
|
var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
|
21954
|
-
|
21955
|
-
// - also sets validity.badInput (should only be validity.typeMismatch).
|
21956
|
-
// - see http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-mail-state-(type=email)
|
21957
|
-
// - can ignore this case as we can still read out the erroneous email...
|
21958
|
-
return validity.badInput && !validity.typeMismatch ? undefined : value;
|
22891
|
+
return validity.badInput || validity.typeMismatch ? undefined : value;
|
21959
22892
|
});
|
21960
22893
|
}
|
21961
22894
|
}
|
@@ -22127,8 +23060,8 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt
|
|
22127
23060
|
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
|
22128
23061
|
* maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
|
22129
23062
|
* length.
|
22130
|
-
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel
|
22131
|
-
* a RegExp found by evaluating the Angular expression given in the attribute value.
|
23063
|
+
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
|
23064
|
+
* does not match a RegExp found by evaluating the Angular expression given in the attribute value.
|
22132
23065
|
* If the expression evaluates to a RegExp object, then this is used directly.
|
22133
23066
|
* If the expression evaluates to a string, then it will be converted to a RegExp
|
22134
23067
|
* after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
|
@@ -22166,8 +23099,8 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt
|
|
22166
23099
|
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
|
22167
23100
|
* maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
|
22168
23101
|
* length.
|
22169
|
-
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel
|
22170
|
-
* a RegExp found by evaluating the Angular expression given in the attribute value.
|
23102
|
+
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
|
23103
|
+
* value does not match a RegExp found by evaluating the Angular expression given in the attribute value.
|
22171
23104
|
* If the expression evaluates to a RegExp object, then this is used directly.
|
22172
23105
|
* If the expression evaluates to a string, then it will be converted to a RegExp
|
22173
23106
|
* after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
|
@@ -23393,7 +24326,7 @@ var ngControllerDirective = [function() {
|
|
23393
24326
|
*
|
23394
24327
|
* * no-inline-style: this stops Angular from injecting CSS styles into the DOM
|
23395
24328
|
*
|
23396
|
-
* * no-unsafe-eval: this stops Angular from
|
24329
|
+
* * no-unsafe-eval: this stops Angular from optimizing $parse with unsafe eval of strings
|
23397
24330
|
*
|
23398
24331
|
* You can use these values in the following combinations:
|
23399
24332
|
*
|
@@ -23410,7 +24343,7 @@ var ngControllerDirective = [function() {
|
|
23410
24343
|
* inline styles. E.g. `<body ng-csp="no-unsafe-eval">`.
|
23411
24344
|
*
|
23412
24345
|
* * Specifying only `no-inline-style` tells Angular that we must not inject styles, but that we can
|
23413
|
-
* run eval - no
|
24346
|
+
* run eval - no automatic check for unsafe eval will occur. E.g. `<body ng-csp="no-inline-style">`
|
23414
24347
|
*
|
23415
24348
|
* * Specifying both `no-unsafe-eval` and `no-inline-style` tells Angular that we must not inject
|
23416
24349
|
* styles nor use eval, which is the same as an empty: ng-csp.
|
@@ -24389,6 +25322,8 @@ var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
|
|
24389
25322
|
//set the 2nd param to true to ignore the template request error so that the inner
|
24390
25323
|
//contents and scope can be cleaned up.
|
24391
25324
|
$templateRequest(src, true).then(function(response) {
|
25325
|
+
if (scope.$$destroyed) return;
|
25326
|
+
|
24392
25327
|
if (thisChangeId !== changeCounter) return;
|
24393
25328
|
var newScope = scope.$new();
|
24394
25329
|
ctrl.template = response;
|
@@ -24410,6 +25345,8 @@ var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
|
|
24410
25345
|
currentScope.$emit('$includeContentLoaded', src);
|
24411
25346
|
scope.$eval(onloadExp);
|
24412
25347
|
}, function() {
|
25348
|
+
if (scope.$$destroyed) return;
|
25349
|
+
|
24413
25350
|
if (thisChangeId === changeCounter) {
|
24414
25351
|
cleanupLastIncludeContent();
|
24415
25352
|
scope.$emit('$includeContentError', src);
|
@@ -24438,7 +25375,7 @@ var ngIncludeFillContentDirective = ['$compile',
|
|
24438
25375
|
priority: -400,
|
24439
25376
|
require: 'ngInclude',
|
24440
25377
|
link: function(scope, $element, $attr, ctrl) {
|
24441
|
-
if (
|
25378
|
+
if (toString.call($element[0]).match(/SVG/)) {
|
24442
25379
|
// WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
|
24443
25380
|
// support innerHTML, so detect this here and try to generate the contents
|
24444
25381
|
// specially.
|
@@ -24667,7 +25604,9 @@ var VALID_CLASS = 'ng-valid',
|
|
24667
25604
|
DIRTY_CLASS = 'ng-dirty',
|
24668
25605
|
UNTOUCHED_CLASS = 'ng-untouched',
|
24669
25606
|
TOUCHED_CLASS = 'ng-touched',
|
24670
|
-
PENDING_CLASS = 'ng-pending'
|
25607
|
+
PENDING_CLASS = 'ng-pending',
|
25608
|
+
EMPTY_CLASS = 'ng-empty',
|
25609
|
+
NOT_EMPTY_CLASS = 'ng-not-empty';
|
24671
25610
|
|
24672
25611
|
var ngModelMinErr = minErr('ngModel');
|
24673
25612
|
|
@@ -24971,6 +25910,17 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
24971
25910
|
return isUndefined(value) || value === '' || value === null || value !== value;
|
24972
25911
|
};
|
24973
25912
|
|
25913
|
+
this.$$updateEmptyClasses = function(value) {
|
25914
|
+
if (ctrl.$isEmpty(value)) {
|
25915
|
+
$animate.removeClass($element, NOT_EMPTY_CLASS);
|
25916
|
+
$animate.addClass($element, EMPTY_CLASS);
|
25917
|
+
} else {
|
25918
|
+
$animate.removeClass($element, EMPTY_CLASS);
|
25919
|
+
$animate.addClass($element, NOT_EMPTY_CLASS);
|
25920
|
+
}
|
25921
|
+
};
|
25922
|
+
|
25923
|
+
|
24974
25924
|
var currentValidationRunId = 0;
|
24975
25925
|
|
24976
25926
|
/**
|
@@ -25088,11 +26038,14 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
25088
26038
|
* which may be caused by a pending debounced event or because the input is waiting for a some
|
25089
26039
|
* future event.
|
25090
26040
|
*
|
25091
|
-
* If you have an input that uses `ng-model-options` to set up debounced
|
25092
|
-
* as blur you can have a situation where there is a period when
|
25093
|
-
* is out of
|
26041
|
+
* If you have an input that uses `ng-model-options` to set up debounced updates or updates that
|
26042
|
+
* depend on special events such as blur, you can have a situation where there is a period when
|
26043
|
+
* the `$viewValue` is out of sync with the ngModel's `$modelValue`.
|
26044
|
+
*
|
26045
|
+
* In this case, you can use `$rollbackViewValue()` to manually cancel the debounced / future update
|
26046
|
+
* and reset the input to the last committed view value.
|
25094
26047
|
*
|
25095
|
-
*
|
26048
|
+
* It is also possible that you run into difficulties if you try to update the ngModel's `$modelValue`
|
25096
26049
|
* programmatically before these debounced/future events have resolved/occurred, because Angular's
|
25097
26050
|
* dirty checking mechanism is not able to tell whether the model has actually changed or not.
|
25098
26051
|
*
|
@@ -25105,39 +26058,63 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
25105
26058
|
* angular.module('cancel-update-example', [])
|
25106
26059
|
*
|
25107
26060
|
* .controller('CancelUpdateController', ['$scope', function($scope) {
|
25108
|
-
* $scope.
|
25109
|
-
*
|
25110
|
-
*
|
25111
|
-
* $scope.myValue = '';
|
25112
|
-
* }
|
25113
|
-
* };
|
25114
|
-
* $scope.resetWithoutCancel = function(e) {
|
26061
|
+
* $scope.model = {};
|
26062
|
+
*
|
26063
|
+
* $scope.setEmpty = function(e, value, rollback) {
|
25115
26064
|
* if (e.keyCode == 27) {
|
25116
|
-
*
|
26065
|
+
* e.preventDefault();
|
26066
|
+
* if (rollback) {
|
26067
|
+
* $scope.myForm[value].$rollbackViewValue();
|
26068
|
+
* }
|
26069
|
+
* $scope.model[value] = '';
|
25117
26070
|
* }
|
25118
26071
|
* };
|
25119
26072
|
* }]);
|
25120
26073
|
* </file>
|
25121
26074
|
* <file name="index.html">
|
25122
26075
|
* <div ng-controller="CancelUpdateController">
|
25123
|
-
*
|
25124
|
-
*
|
25125
|
-
*
|
25126
|
-
*
|
26076
|
+
* <p>Both of these inputs are only updated if they are blurred. Hitting escape should
|
26077
|
+
* empty them. Follow these steps and observe the difference:</p>
|
26078
|
+
* <ol>
|
26079
|
+
* <li>Type something in the input. You will see that the model is not yet updated</li>
|
26080
|
+
* <li>Press the Escape key.
|
26081
|
+
* <ol>
|
26082
|
+
* <li> In the first example, nothing happens, because the model is already '', and no
|
26083
|
+
* update is detected. If you blur the input, the model will be set to the current view.
|
26084
|
+
* </li>
|
26085
|
+
* <li> In the second example, the pending update is cancelled, and the input is set back
|
26086
|
+
* to the last committed view value (''). Blurring the input does nothing.
|
26087
|
+
* </li>
|
26088
|
+
* </ol>
|
26089
|
+
* </li>
|
26090
|
+
* </ol>
|
25127
26091
|
*
|
25128
26092
|
* <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
|
25129
|
-
* <
|
25130
|
-
*
|
25131
|
-
*
|
25132
|
-
*
|
25133
|
-
*
|
25134
|
-
*
|
25135
|
-
*
|
25136
|
-
*
|
25137
|
-
*
|
26093
|
+
* <div>
|
26094
|
+
* <p id="inputDescription1">Without $rollbackViewValue():</p>
|
26095
|
+
* <input name="value1" aria-describedby="inputDescription1" ng-model="model.value1"
|
26096
|
+
* ng-keydown="setEmpty($event, 'value1')">
|
26097
|
+
* value1: "{{ model.value1 }}"
|
26098
|
+
* </div>
|
26099
|
+
*
|
26100
|
+
* <div>
|
26101
|
+
* <p id="inputDescription2">With $rollbackViewValue():</p>
|
26102
|
+
* <input name="value2" aria-describedby="inputDescription2" ng-model="model.value2"
|
26103
|
+
* ng-keydown="setEmpty($event, 'value2', true)">
|
26104
|
+
* value2: "{{ model.value2 }}"
|
26105
|
+
* </div>
|
25138
26106
|
* </form>
|
25139
26107
|
* </div>
|
25140
26108
|
* </file>
|
26109
|
+
<file name="style.css">
|
26110
|
+
div {
|
26111
|
+
display: table-cell;
|
26112
|
+
}
|
26113
|
+
div:nth-child(1) {
|
26114
|
+
padding-right: 30px;
|
26115
|
+
}
|
26116
|
+
|
26117
|
+
</file>
|
25141
26118
|
* </example>
|
25142
26119
|
*/
|
25143
26120
|
this.$rollbackViewValue = function() {
|
@@ -25251,7 +26228,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
25251
26228
|
forEach(ctrl.$asyncValidators, function(validator, name) {
|
25252
26229
|
var promise = validator(modelValue, viewValue);
|
25253
26230
|
if (!isPromiseLike(promise)) {
|
25254
|
-
throw ngModelMinErr(
|
26231
|
+
throw ngModelMinErr('nopromise',
|
25255
26232
|
"Expected asynchronous validator to return a promise but got '{0}' instead.", promise);
|
25256
26233
|
}
|
25257
26234
|
setValidity(name, undefined);
|
@@ -25307,6 +26284,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
25307
26284
|
if (ctrl.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !ctrl.$$hasNativeValidators)) {
|
25308
26285
|
return;
|
25309
26286
|
}
|
26287
|
+
ctrl.$$updateEmptyClasses(viewValue);
|
25310
26288
|
ctrl.$$lastCommittedViewValue = viewValue;
|
25311
26289
|
|
25312
26290
|
// change to dirty
|
@@ -25405,7 +26383,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
25405
26383
|
* However, custom controls might also pass objects to this method. In this case, we should make
|
25406
26384
|
* a copy of the object before passing it to `$setViewValue`. This is because `ngModel` does not
|
25407
26385
|
* perform a deep watch of objects, it only looks for a change of identity. If you only change
|
25408
|
-
* the property of the object then ngModel will not
|
26386
|
+
* the property of the object then ngModel will not realize that the object has changed and
|
25409
26387
|
* will not invoke the `$parsers` and `$validators` pipelines. For this reason, you should
|
25410
26388
|
* not change properties of the copy once it has been passed to `$setViewValue`.
|
25411
26389
|
* Otherwise you may cause the model value on the scope to change incorrectly.
|
@@ -25489,6 +26467,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
25489
26467
|
viewValue = formatters[idx](viewValue);
|
25490
26468
|
}
|
25491
26469
|
if (ctrl.$viewValue !== viewValue) {
|
26470
|
+
ctrl.$$updateEmptyClasses(viewValue);
|
25492
26471
|
ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
|
25493
26472
|
ctrl.$render();
|
25494
26473
|
|
@@ -25519,7 +26498,8 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
25519
26498
|
* require.
|
25520
26499
|
* - Providing validation behavior (i.e. required, number, email, url).
|
25521
26500
|
* - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
|
25522
|
-
* - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`,
|
26501
|
+
* - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`,
|
26502
|
+
* `ng-untouched`, `ng-empty`, `ng-not-empty`) including animations.
|
25523
26503
|
* - Registering the control with its parent {@link ng.directive:form form}.
|
25524
26504
|
*
|
25525
26505
|
* Note: `ngModel` will try to bind to the property given by evaluating the expression on the
|
@@ -25547,6 +26527,22 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
25547
26527
|
* - {@link ng.directive:select select}
|
25548
26528
|
* - {@link ng.directive:textarea textarea}
|
25549
26529
|
*
|
26530
|
+
* # Complex Models (objects or collections)
|
26531
|
+
*
|
26532
|
+
* By default, `ngModel` watches the model by reference, not value. This is important to know when
|
26533
|
+
* binding inputs to models that are objects (e.g. `Date`) or collections (e.g. arrays). If only properties of the
|
26534
|
+
* object or collection change, `ngModel` will not be notified and so the input will not be re-rendered.
|
26535
|
+
*
|
26536
|
+
* The model must be assigned an entirely new object or collection before a re-rendering will occur.
|
26537
|
+
*
|
26538
|
+
* Some directives have options that will cause them to use a custom `$watchCollection` on the model expression
|
26539
|
+
* - for example, `ngOptions` will do so when a `track by` clause is included in the comprehension expression or
|
26540
|
+
* if the select is given the `multiple` attribute.
|
26541
|
+
*
|
26542
|
+
* The `$watchCollection()` method only does a shallow comparison, meaning that changing properties deeper than the
|
26543
|
+
* first level of the object (or only changing the properties of an item in the collection if it's an array) will still
|
26544
|
+
* not trigger a re-rendering of the model.
|
26545
|
+
*
|
25550
26546
|
* # CSS classes
|
25551
26547
|
* The following CSS classes are added and removed on the associated input/select/textarea element
|
25552
26548
|
* depending on the validity of the model.
|
@@ -25560,13 +26556,16 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
25560
26556
|
* - `ng-touched`: the control has been blurred
|
25561
26557
|
* - `ng-untouched`: the control hasn't been blurred
|
25562
26558
|
* - `ng-pending`: any `$asyncValidators` are unfulfilled
|
26559
|
+
* - `ng-empty`: the view does not contain a value or the value is deemed "empty", as defined
|
26560
|
+
* by the {@link ngModel.NgModelController#$isEmpty} method
|
26561
|
+
* - `ng-not-empty`: the view contains a non-empty value
|
25563
26562
|
*
|
25564
26563
|
* Keep in mind that ngAnimate can detect each of these classes when added and removed.
|
25565
26564
|
*
|
25566
26565
|
* ## Animation Hooks
|
25567
26566
|
*
|
25568
26567
|
* Animations within models are triggered when any of the associated CSS classes are added and removed
|
25569
|
-
* on the input element which is attached to the model. These classes
|
26568
|
+
* on the input element which is attached to the model. These classes include: `.ng-pristine`, `.ng-dirty`,
|
25570
26569
|
* `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
|
25571
26570
|
* The animations that are triggered within ngModel are similar to how they work in ngClass and
|
25572
26571
|
* animations can be hooked into using CSS transitions, keyframes as well as JS animations.
|
@@ -26459,14 +27458,10 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
26459
27458
|
var optionTemplate = document.createElement('option'),
|
26460
27459
|
optGroupTemplate = document.createElement('optgroup');
|
26461
27460
|
|
26462
|
-
|
26463
27461
|
function ngOptionsPostLink(scope, selectElement, attr, ctrls) {
|
26464
27462
|
|
26465
|
-
// if ngModel is not defined, we don't need to do anything
|
26466
|
-
var ngModelCtrl = ctrls[1];
|
26467
|
-
if (!ngModelCtrl) return;
|
26468
|
-
|
26469
27463
|
var selectCtrl = ctrls[0];
|
27464
|
+
var ngModelCtrl = ctrls[1];
|
26470
27465
|
var multiple = attr.multiple;
|
26471
27466
|
|
26472
27467
|
// The emptyOption allows the application developer to provide their own custom "empty"
|
@@ -26697,7 +27692,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
26697
27692
|
(current === emptyOption_ ||
|
26698
27693
|
current === unknownOption_ ||
|
26699
27694
|
current.nodeType === NODE_TYPE_COMMENT ||
|
26700
|
-
current.value === '')) {
|
27695
|
+
(nodeName_(current) === 'option' && current.value === ''))) {
|
26701
27696
|
current = current.nextSibling;
|
26702
27697
|
}
|
26703
27698
|
}
|
@@ -26726,7 +27721,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
26726
27721
|
var groupElement;
|
26727
27722
|
var optionElement;
|
26728
27723
|
|
26729
|
-
if (option.group) {
|
27724
|
+
if (isDefined(option.group)) {
|
26730
27725
|
|
26731
27726
|
// This option is to live in a group
|
26732
27727
|
// See if we have already created this group
|
@@ -26787,7 +27782,8 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
26787
27782
|
// Check to see if the value has changed due to the update to the options
|
26788
27783
|
if (!ngModelCtrl.$isEmpty(previousValue)) {
|
26789
27784
|
var nextValue = selectCtrl.readValue();
|
26790
|
-
|
27785
|
+
var isNotPrimitive = ngOptions.trackBy || multiple;
|
27786
|
+
if (isNotPrimitive ? !equals(previousValue, nextValue) : previousValue !== nextValue) {
|
26791
27787
|
ngModelCtrl.$setViewValue(nextValue);
|
26792
27788
|
ngModelCtrl.$render();
|
26793
27789
|
}
|
@@ -26799,7 +27795,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
26799
27795
|
return {
|
26800
27796
|
restrict: 'A',
|
26801
27797
|
terminal: true,
|
26802
|
-
require: ['select', '
|
27798
|
+
require: ['select', 'ngModel'],
|
26803
27799
|
link: {
|
26804
27800
|
pre: function ngOptionsPreLink(scope, selectElement, attr, ctrls) {
|
26805
27801
|
// Deactivate the SelectController.register method to prevent
|
@@ -27027,7 +28023,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
|
|
27027
28023
|
}
|
27028
28024
|
|
27029
28025
|
// If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
|
27030
|
-
// In JS `NaN !== NaN`, so we have to
|
28026
|
+
// In JS `NaN !== NaN`, so we have to explicitly check.
|
27031
28027
|
if ((count !== lastCount) && !(countIsNaN && isNumber(lastCount) && isNaN(lastCount))) {
|
27032
28028
|
watchRemover();
|
27033
28029
|
var whenExpFn = whensExpFns[count];
|
@@ -27144,7 +28140,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
|
|
27144
28140
|
* by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`
|
27145
28141
|
* will not have to rebuild the DOM elements for items it has already rendered, even if the
|
27146
28142
|
* JavaScript objects in the collection have been substituted for new ones. For large collections,
|
27147
|
-
* this
|
28143
|
+
* this significantly improves rendering performance. If you don't have a unique identifier,
|
27148
28144
|
* `track by $index` can also provide a performance boost.
|
27149
28145
|
* </div>
|
27150
28146
|
* ```html
|
@@ -27221,6 +28217,8 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
|
|
27221
28217
|
*
|
27222
28218
|
* **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
|
27223
28219
|
*
|
28220
|
+
* See the example below for defining CSS animations with ngRepeat.
|
28221
|
+
*
|
27224
28222
|
* @element ANY
|
27225
28223
|
* @scope
|
27226
28224
|
* @priority 1000
|
@@ -27273,22 +28271,11 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
|
|
27273
28271
|
* For example: `item in items | filter : x | orderBy : order | limitTo : limit as results` .
|
27274
28272
|
*
|
27275
28273
|
* @example
|
27276
|
-
* This example
|
27277
|
-
*
|
27278
|
-
<example module="
|
28274
|
+
* This example uses `ngRepeat` to display a list of people. A filter is used to restrict the displayed
|
28275
|
+
* results by name. New (entering) and removed (leaving) items are animated.
|
28276
|
+
<example module="ngRepeat" name="ngRepeat" deps="angular-animate.js" animations="true">
|
27279
28277
|
<file name="index.html">
|
27280
|
-
<div ng-
|
27281
|
-
{name:'John', age:25, gender:'boy'},
|
27282
|
-
{name:'Jessie', age:30, gender:'girl'},
|
27283
|
-
{name:'Johanna', age:28, gender:'girl'},
|
27284
|
-
{name:'Joy', age:15, gender:'girl'},
|
27285
|
-
{name:'Mary', age:28, gender:'girl'},
|
27286
|
-
{name:'Peter', age:95, gender:'boy'},
|
27287
|
-
{name:'Sebastian', age:50, gender:'boy'},
|
27288
|
-
{name:'Erika', age:27, gender:'girl'},
|
27289
|
-
{name:'Patrick', age:40, gender:'boy'},
|
27290
|
-
{name:'Samantha', age:60, gender:'girl'}
|
27291
|
-
]">
|
28278
|
+
<div ng-controller="repeatController">
|
27292
28279
|
I have {{friends.length}} friends. They are:
|
27293
28280
|
<input type="search" ng-model="q" placeholder="filter friends..." aria-label="filter friends" />
|
27294
28281
|
<ul class="example-animate-container">
|
@@ -27301,6 +28288,22 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
|
|
27301
28288
|
</ul>
|
27302
28289
|
</div>
|
27303
28290
|
</file>
|
28291
|
+
<file name="script.js">
|
28292
|
+
angular.module('ngRepeat', ['ngAnimate']).controller('repeatController', function($scope) {
|
28293
|
+
$scope.friends = [
|
28294
|
+
{name:'John', age:25, gender:'boy'},
|
28295
|
+
{name:'Jessie', age:30, gender:'girl'},
|
28296
|
+
{name:'Johanna', age:28, gender:'girl'},
|
28297
|
+
{name:'Joy', age:15, gender:'girl'},
|
28298
|
+
{name:'Mary', age:28, gender:'girl'},
|
28299
|
+
{name:'Peter', age:95, gender:'boy'},
|
28300
|
+
{name:'Sebastian', age:50, gender:'boy'},
|
28301
|
+
{name:'Erika', age:27, gender:'girl'},
|
28302
|
+
{name:'Patrick', age:40, gender:'boy'},
|
28303
|
+
{name:'Samantha', age:60, gender:'girl'}
|
28304
|
+
];
|
28305
|
+
});
|
28306
|
+
</file>
|
27304
28307
|
<file name="animations.css">
|
27305
28308
|
.example-animate-container {
|
27306
28309
|
background:white;
|
@@ -27311,7 +28314,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
|
|
27311
28314
|
}
|
27312
28315
|
|
27313
28316
|
.animate-repeat {
|
27314
|
-
line-height:
|
28317
|
+
line-height:30px;
|
27315
28318
|
list-style:none;
|
27316
28319
|
box-sizing:border-box;
|
27317
28320
|
}
|
@@ -27333,7 +28336,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
|
|
27333
28336
|
.animate-repeat.ng-move.ng-move-active,
|
27334
28337
|
.animate-repeat.ng-enter.ng-enter-active {
|
27335
28338
|
opacity:1;
|
27336
|
-
max-height:
|
28339
|
+
max-height:30px;
|
27337
28340
|
}
|
27338
28341
|
</file>
|
27339
28342
|
<file name="protractor.js" type="protractor">
|
@@ -28190,67 +29193,186 @@ var ngSwitchDefaultDirective = ngDirective({
|
|
28190
29193
|
* @description
|
28191
29194
|
* Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
|
28192
29195
|
*
|
28193
|
-
*
|
29196
|
+
* You can specify that you want to insert a named transclusion slot, instead of the default slot, by providing the slot name
|
29197
|
+
* as the value of the `ng-transclude` or `ng-transclude-slot` attribute.
|
29198
|
+
*
|
29199
|
+
* If the transcluded content is not empty (i.e. contains one or more DOM nodes, including whitespace text nodes), any existing
|
29200
|
+
* content of this element will be removed before the transcluded content is inserted.
|
29201
|
+
* If the transcluded content is empty, the existing content is left intact. This lets you provide fallback content in the case
|
29202
|
+
* that no transcluded content is provided.
|
28194
29203
|
*
|
28195
29204
|
* @element ANY
|
28196
29205
|
*
|
29206
|
+
* @param {string} ngTransclude|ngTranscludeSlot the name of the slot to insert at this point. If this is not provided, is empty
|
29207
|
+
* or its value is the same as the name of the attribute then the default slot is used.
|
29208
|
+
*
|
28197
29209
|
* @example
|
28198
|
-
|
28199
|
-
|
28200
|
-
|
28201
|
-
|
28202
|
-
|
28203
|
-
|
28204
|
-
|
28205
|
-
|
28206
|
-
|
28207
|
-
|
28208
|
-
|
28209
|
-
|
28210
|
-
'</div>'
|
28211
|
-
|
28212
|
-
|
28213
|
-
|
28214
|
-
|
28215
|
-
|
28216
|
-
|
28217
|
-
|
28218
|
-
|
28219
|
-
|
28220
|
-
|
28221
|
-
|
28222
|
-
|
28223
|
-
|
28224
|
-
|
28225
|
-
|
28226
|
-
|
28227
|
-
|
28228
|
-
|
28229
|
-
|
28230
|
-
|
28231
|
-
|
28232
|
-
|
28233
|
-
|
28234
|
-
|
28235
|
-
|
28236
|
-
|
29210
|
+
* ### Basic transclusion
|
29211
|
+
* This example demonstrates basic transclusion of content into a component directive.
|
29212
|
+
* <example name="simpleTranscludeExample" module="transcludeExample">
|
29213
|
+
* <file name="index.html">
|
29214
|
+
* <script>
|
29215
|
+
* angular.module('transcludeExample', [])
|
29216
|
+
* .directive('pane', function(){
|
29217
|
+
* return {
|
29218
|
+
* restrict: 'E',
|
29219
|
+
* transclude: true,
|
29220
|
+
* scope: { title:'@' },
|
29221
|
+
* template: '<div style="border: 1px solid black;">' +
|
29222
|
+
* '<div style="background-color: gray">{{title}}</div>' +
|
29223
|
+
* '<ng-transclude></ng-transclude>' +
|
29224
|
+
* '</div>'
|
29225
|
+
* };
|
29226
|
+
* })
|
29227
|
+
* .controller('ExampleController', ['$scope', function($scope) {
|
29228
|
+
* $scope.title = 'Lorem Ipsum';
|
29229
|
+
* $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
|
29230
|
+
* }]);
|
29231
|
+
* </script>
|
29232
|
+
* <div ng-controller="ExampleController">
|
29233
|
+
* <input ng-model="title" aria-label="title"> <br/>
|
29234
|
+
* <textarea ng-model="text" aria-label="text"></textarea> <br/>
|
29235
|
+
* <pane title="{{title}}">{{text}}</pane>
|
29236
|
+
* </div>
|
29237
|
+
* </file>
|
29238
|
+
* <file name="protractor.js" type="protractor">
|
29239
|
+
* it('should have transcluded', function() {
|
29240
|
+
* var titleElement = element(by.model('title'));
|
29241
|
+
* titleElement.clear();
|
29242
|
+
* titleElement.sendKeys('TITLE');
|
29243
|
+
* var textElement = element(by.model('text'));
|
29244
|
+
* textElement.clear();
|
29245
|
+
* textElement.sendKeys('TEXT');
|
29246
|
+
* expect(element(by.binding('title')).getText()).toEqual('TITLE');
|
29247
|
+
* expect(element(by.binding('text')).getText()).toEqual('TEXT');
|
29248
|
+
* });
|
29249
|
+
* </file>
|
29250
|
+
* </example>
|
29251
|
+
*
|
29252
|
+
* @example
|
29253
|
+
* ### Transclude fallback content
|
29254
|
+
* This example shows how to use `NgTransclude` with fallback content, that
|
29255
|
+
* is displayed if no transcluded content is provided.
|
29256
|
+
*
|
29257
|
+
* <example module="transcludeFallbackContentExample">
|
29258
|
+
* <file name="index.html">
|
29259
|
+
* <script>
|
29260
|
+
* angular.module('transcludeFallbackContentExample', [])
|
29261
|
+
* .directive('myButton', function(){
|
29262
|
+
* return {
|
29263
|
+
* restrict: 'E',
|
29264
|
+
* transclude: true,
|
29265
|
+
* scope: true,
|
29266
|
+
* template: '<button style="cursor: pointer;">' +
|
29267
|
+
* '<ng-transclude>' +
|
29268
|
+
* '<b style="color: red;">Button1</b>' +
|
29269
|
+
* '</ng-transclude>' +
|
29270
|
+
* '</button>'
|
29271
|
+
* };
|
29272
|
+
* });
|
29273
|
+
* </script>
|
29274
|
+
* <!-- fallback button content -->
|
29275
|
+
* <my-button id="fallback"></my-button>
|
29276
|
+
* <!-- modified button content -->
|
29277
|
+
* <my-button id="modified">
|
29278
|
+
* <i style="color: green;">Button2</i>
|
29279
|
+
* </my-button>
|
29280
|
+
* </file>
|
29281
|
+
* <file name="protractor.js" type="protractor">
|
29282
|
+
* it('should have different transclude element content', function() {
|
29283
|
+
* expect(element(by.id('fallback')).getText()).toBe('Button1');
|
29284
|
+
* expect(element(by.id('modified')).getText()).toBe('Button2');
|
29285
|
+
* });
|
29286
|
+
* </file>
|
29287
|
+
* </example>
|
28237
29288
|
*
|
29289
|
+
* @example
|
29290
|
+
* ### Multi-slot transclusion
|
29291
|
+
* This example demonstrates using multi-slot transclusion in a component directive.
|
29292
|
+
* <example name="multiSlotTranscludeExample" module="multiSlotTranscludeExample">
|
29293
|
+
* <file name="index.html">
|
29294
|
+
* <style>
|
29295
|
+
* .title, .footer {
|
29296
|
+
* background-color: gray
|
29297
|
+
* }
|
29298
|
+
* </style>
|
29299
|
+
* <div ng-controller="ExampleController">
|
29300
|
+
* <input ng-model="title" aria-label="title"> <br/>
|
29301
|
+
* <textarea ng-model="text" aria-label="text"></textarea> <br/>
|
29302
|
+
* <pane>
|
29303
|
+
* <pane-title><a ng-href="{{link}}">{{title}}</a></pane-title>
|
29304
|
+
* <pane-body><p>{{text}}</p></pane-body>
|
29305
|
+
* </pane>
|
29306
|
+
* </div>
|
29307
|
+
* </file>
|
29308
|
+
* <file name="app.js">
|
29309
|
+
* angular.module('multiSlotTranscludeExample', [])
|
29310
|
+
* .directive('pane', function(){
|
29311
|
+
* return {
|
29312
|
+
* restrict: 'E',
|
29313
|
+
* transclude: {
|
29314
|
+
* 'title': '?paneTitle',
|
29315
|
+
* 'body': 'paneBody',
|
29316
|
+
* 'footer': '?paneFooter'
|
29317
|
+
* },
|
29318
|
+
* template: '<div style="border: 1px solid black;">' +
|
29319
|
+
* '<div class="title" ng-transclude="title">Fallback Title</div>' +
|
29320
|
+
* '<div ng-transclude="body"></div>' +
|
29321
|
+
* '<div class="footer" ng-transclude="footer">Fallback Footer</div>' +
|
29322
|
+
* '</div>'
|
29323
|
+
* };
|
29324
|
+
* })
|
29325
|
+
* .controller('ExampleController', ['$scope', function($scope) {
|
29326
|
+
* $scope.title = 'Lorem Ipsum';
|
29327
|
+
* $scope.link = "https://google.com";
|
29328
|
+
* $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
|
29329
|
+
* }]);
|
29330
|
+
* </file>
|
29331
|
+
* <file name="protractor.js" type="protractor">
|
29332
|
+
* it('should have transcluded the title and the body', function() {
|
29333
|
+
* var titleElement = element(by.model('title'));
|
29334
|
+
* titleElement.clear();
|
29335
|
+
* titleElement.sendKeys('TITLE');
|
29336
|
+
* var textElement = element(by.model('text'));
|
29337
|
+
* textElement.clear();
|
29338
|
+
* textElement.sendKeys('TEXT');
|
29339
|
+
* expect(element(by.css('.title')).getText()).toEqual('TITLE');
|
29340
|
+
* expect(element(by.binding('text')).getText()).toEqual('TEXT');
|
29341
|
+
* expect(element(by.css('.footer')).getText()).toEqual('Fallback Footer');
|
29342
|
+
* });
|
29343
|
+
* </file>
|
29344
|
+
* </example>
|
28238
29345
|
*/
|
29346
|
+
var ngTranscludeMinErr = minErr('ngTransclude');
|
28239
29347
|
var ngTranscludeDirective = ngDirective({
|
28240
29348
|
restrict: 'EAC',
|
28241
29349
|
link: function($scope, $element, $attrs, controller, $transclude) {
|
29350
|
+
|
29351
|
+
if ($attrs.ngTransclude === $attrs.$attr.ngTransclude) {
|
29352
|
+
// If the attribute is of the form: `ng-transclude="ng-transclude"`
|
29353
|
+
// then treat it like the default
|
29354
|
+
$attrs.ngTransclude = '';
|
29355
|
+
}
|
29356
|
+
|
29357
|
+
function ngTranscludeCloneAttachFn(clone) {
|
29358
|
+
if (clone.length) {
|
29359
|
+
$element.empty();
|
29360
|
+
$element.append(clone);
|
29361
|
+
}
|
29362
|
+
}
|
29363
|
+
|
28242
29364
|
if (!$transclude) {
|
28243
|
-
throw
|
29365
|
+
throw ngTranscludeMinErr('orphan',
|
28244
29366
|
'Illegal use of ngTransclude directive in the template! ' +
|
28245
29367
|
'No parent directive that requires a transclusion found. ' +
|
28246
29368
|
'Element: {0}',
|
28247
29369
|
startingTag($element));
|
28248
29370
|
}
|
28249
29371
|
|
28250
|
-
|
28251
|
-
|
28252
|
-
|
28253
|
-
|
29372
|
+
// If there is no slot name defined or the slot name is not optional
|
29373
|
+
// then transclude the slot
|
29374
|
+
var slotName = $attrs.ngTransclude || $attrs.ngTranscludeSlot;
|
29375
|
+
$transclude(ngTranscludeCloneAttachFn, null, slotName);
|
28254
29376
|
}
|
28255
29377
|
});
|
28256
29378
|
|
@@ -28382,6 +29504,9 @@ var SelectController =
|
|
28382
29504
|
|
28383
29505
|
// Tell the select control that an option, with the given value, has been added
|
28384
29506
|
self.addOption = function(value, element) {
|
29507
|
+
// Skip comment nodes, as they only pollute the `optionsMap`
|
29508
|
+
if (element[0].nodeType === NODE_TYPE_COMMENT) return;
|
29509
|
+
|
28385
29510
|
assertNotHasOwnProperty(value, '"option value"');
|
28386
29511
|
if (value === '') {
|
28387
29512
|
self.emptyOption = element;
|
@@ -28456,7 +29581,7 @@ var SelectController =
|
|
28456
29581
|
*
|
28457
29582
|
* The `select` directive is used together with {@link ngModel `ngModel`} to provide data-binding
|
28458
29583
|
* between the scope and the `<select>` control (including setting default values).
|
28459
|
-
*
|
29584
|
+
* It also handles dynamic `<option>` elements, which can be added using the {@link ngRepeat `ngRepeat}` or
|
28460
29585
|
* {@link ngOptions `ngOptions`} directives.
|
28461
29586
|
*
|
28462
29587
|
* When an item in the `<select>` menu is selected, the value of the selected option will be bound
|
@@ -28466,7 +29591,7 @@ var SelectController =
|
|
28466
29591
|
*
|
28467
29592
|
* <div class="alert alert-warning">
|
28468
29593
|
* Note that the value of a `select` directive used without `ngOptions` is always a string.
|
28469
|
-
* When the model needs to be bound to a non-string value, you must either
|
29594
|
+
* When the model needs to be bound to a non-string value, you must either explicitly convert it
|
28470
29595
|
* using a directive (see example below) or use `ngOptions` to specify the set of options.
|
28471
29596
|
* This is because an option element can only be bound to string values at present.
|
28472
29597
|
* </div>
|
@@ -28658,7 +29783,8 @@ var selectDirective = function() {
|
|
28658
29783
|
controller: SelectController,
|
28659
29784
|
priority: 1,
|
28660
29785
|
link: {
|
28661
|
-
pre: selectPreLink
|
29786
|
+
pre: selectPreLink,
|
29787
|
+
post: selectPostLink
|
28662
29788
|
}
|
28663
29789
|
};
|
28664
29790
|
|
@@ -28672,13 +29798,6 @@ var selectDirective = function() {
|
|
28672
29798
|
|
28673
29799
|
selectCtrl.ngModelCtrl = ngModelCtrl;
|
28674
29800
|
|
28675
|
-
// We delegate rendering to the `writeValue` method, which can be changed
|
28676
|
-
// if the select can have multiple selected values or if the options are being
|
28677
|
-
// generated by `ngOptions`
|
28678
|
-
ngModelCtrl.$render = function() {
|
28679
|
-
selectCtrl.writeValue(ngModelCtrl.$viewValue);
|
28680
|
-
};
|
28681
|
-
|
28682
29801
|
// When the selected item(s) changes we delegate getting the value of the select control
|
28683
29802
|
// to the `readValue` method, which can be changed if the select can have multiple
|
28684
29803
|
// selected values or if the options are being generated by `ngOptions`
|
@@ -28732,6 +29851,23 @@ var selectDirective = function() {
|
|
28732
29851
|
|
28733
29852
|
}
|
28734
29853
|
}
|
29854
|
+
|
29855
|
+
function selectPostLink(scope, element, attrs, ctrls) {
|
29856
|
+
// if ngModel is not defined, we don't need to do anything
|
29857
|
+
var ngModelCtrl = ctrls[1];
|
29858
|
+
if (!ngModelCtrl) return;
|
29859
|
+
|
29860
|
+
var selectCtrl = ctrls[0];
|
29861
|
+
|
29862
|
+
// We delegate rendering to the `writeValue` method, which can be changed
|
29863
|
+
// if the select can have multiple selected values or if the options are being
|
29864
|
+
// generated by `ngOptions`.
|
29865
|
+
// This must be done in the postLink fn to prevent $render to be called before
|
29866
|
+
// all nodes have been linked correctly.
|
29867
|
+
ngModelCtrl.$render = function() {
|
29868
|
+
selectCtrl.writeValue(ngModelCtrl.$viewValue);
|
29869
|
+
};
|
29870
|
+
}
|
28735
29871
|
};
|
28736
29872
|
|
28737
29873
|
|
@@ -28743,7 +29879,6 @@ var optionDirective = ['$interpolate', function($interpolate) {
|
|
28743
29879
|
restrict: 'E',
|
28744
29880
|
priority: 100,
|
28745
29881
|
compile: function(element, attr) {
|
28746
|
-
|
28747
29882
|
if (isDefined(attr.value)) {
|
28748
29883
|
// If the value attribute is defined, check if it contains an interpolation
|
28749
29884
|
var interpolateValueFn = $interpolate(attr.value, true);
|
@@ -28757,7 +29892,6 @@ var optionDirective = ['$interpolate', function($interpolate) {
|
|
28757
29892
|
}
|
28758
29893
|
|
28759
29894
|
return function(scope, element, attr) {
|
28760
|
-
|
28761
29895
|
// This is an optimization over using ^^ since we don't want to have to search
|
28762
29896
|
// all the way to the root of the DOM for every single option element
|
28763
29897
|
var selectCtrlName = '$selectController',
|
@@ -28778,6 +29912,64 @@ var styleDirective = valueFn({
|
|
28778
29912
|
terminal: false
|
28779
29913
|
});
|
28780
29914
|
|
29915
|
+
/**
|
29916
|
+
* @ngdoc directive
|
29917
|
+
* @name ngRequired
|
29918
|
+
*
|
29919
|
+
* @description
|
29920
|
+
*
|
29921
|
+
* ngRequired adds the required {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
|
29922
|
+
* It is most often used for {@link input `input`} and {@link select `select`} controls, but can also be
|
29923
|
+
* applied to custom controls.
|
29924
|
+
*
|
29925
|
+
* The directive sets the `required` attribute on the element if the Angular expression inside
|
29926
|
+
* `ngRequired` evaluates to true. A special directive for setting `required` is necessary because we
|
29927
|
+
* cannot use interpolation inside `required`. See the {@link guide/interpolation interpolation guide}
|
29928
|
+
* for more info.
|
29929
|
+
*
|
29930
|
+
* The validator will set the `required` error key to true if the `required` attribute is set and
|
29931
|
+
* calling {@link ngModel.NgModelController#$isEmpty `NgModelController.$isEmpty`} with the
|
29932
|
+
* {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`} returns `true`. For example, the
|
29933
|
+
* `$isEmpty()` implementation for `input[text]` checks the length of the `$viewValue`. When developing
|
29934
|
+
* custom controls, `$isEmpty()` can be overwritten to account for a $viewValue that is not string-based.
|
29935
|
+
*
|
29936
|
+
* @example
|
29937
|
+
* <example name="ngRequiredDirective" module="ngRequiredExample">
|
29938
|
+
* <file name="index.html">
|
29939
|
+
* <script>
|
29940
|
+
* angular.module('ngRequiredExample', [])
|
29941
|
+
* .controller('ExampleController', ['$scope', function($scope) {
|
29942
|
+
* $scope.required = true;
|
29943
|
+
* }]);
|
29944
|
+
* </script>
|
29945
|
+
* <div ng-controller="ExampleController">
|
29946
|
+
* <form name="form">
|
29947
|
+
* <label for="required">Toggle required: </label>
|
29948
|
+
* <input type="checkbox" ng-model="required" id="required" />
|
29949
|
+
* <br>
|
29950
|
+
* <label for="input">This input must be filled if `required` is true: </label>
|
29951
|
+
* <input type="text" ng-model="model" id="input" name="input" ng-required="required" /><br>
|
29952
|
+
* <hr>
|
29953
|
+
* required error set? = <code>{{form.input.$error.required}}</code><br>
|
29954
|
+
* model = <code>{{model}}</code>
|
29955
|
+
* </form>
|
29956
|
+
* </div>
|
29957
|
+
* </file>
|
29958
|
+
* <file name="protractor.js" type="protractor">
|
29959
|
+
var required = element(by.binding('form.input.$error.required'));
|
29960
|
+
var model = element(by.binding('model'));
|
29961
|
+
var input = element(by.id('input'));
|
29962
|
+
|
29963
|
+
it('should set the required error', function() {
|
29964
|
+
expect(required.getText()).toContain('true');
|
29965
|
+
|
29966
|
+
input.sendKeys('123');
|
29967
|
+
expect(required.getText()).not.toContain('true');
|
29968
|
+
expect(model.getText()).toContain('123');
|
29969
|
+
});
|
29970
|
+
* </file>
|
29971
|
+
* </example>
|
29972
|
+
*/
|
28781
29973
|
var requiredDirective = function() {
|
28782
29974
|
return {
|
28783
29975
|
restrict: 'A',
|
@@ -28797,7 +29989,81 @@ var requiredDirective = function() {
|
|
28797
29989
|
};
|
28798
29990
|
};
|
28799
29991
|
|
29992
|
+
/**
|
29993
|
+
* @ngdoc directive
|
29994
|
+
* @name ngPattern
|
29995
|
+
*
|
29996
|
+
* @description
|
29997
|
+
*
|
29998
|
+
* ngPattern adds the pattern {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
|
29999
|
+
* It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
|
30000
|
+
*
|
30001
|
+
* The validator sets the `pattern` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
|
30002
|
+
* does not match a RegExp which is obtained by evaluating the Angular expression given in the
|
30003
|
+
* `ngPattern` attribute value:
|
30004
|
+
* * If the expression evaluates to a RegExp object, then this is used directly.
|
30005
|
+
* * If the expression evaluates to a string, then it will be converted to a RegExp after wrapping it
|
30006
|
+
* in `^` and `$` characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
|
30007
|
+
*
|
30008
|
+
* <div class="alert alert-info">
|
30009
|
+
* **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
|
30010
|
+
* start at the index of the last search's match, thus not taking the whole input value into
|
30011
|
+
* account.
|
30012
|
+
* </div>
|
30013
|
+
*
|
30014
|
+
* <div class="alert alert-info">
|
30015
|
+
* **Note:** This directive is also added when the plain `pattern` attribute is used, with two
|
30016
|
+
* differences:
|
30017
|
+
* <ol>
|
30018
|
+
* <li>
|
30019
|
+
* `ngPattern` does not set the `pattern` attribute and therefore HTML5 constraint validation is
|
30020
|
+
* not available.
|
30021
|
+
* </li>
|
30022
|
+
* <li>
|
30023
|
+
* The `ngPattern` attribute must be an expression, while the `pattern` value must be
|
30024
|
+
* interpolated.
|
30025
|
+
* </li>
|
30026
|
+
* </ol>
|
30027
|
+
* </div>
|
30028
|
+
*
|
30029
|
+
* @example
|
30030
|
+
* <example name="ngPatternDirective" module="ngPatternExample">
|
30031
|
+
* <file name="index.html">
|
30032
|
+
* <script>
|
30033
|
+
* angular.module('ngPatternExample', [])
|
30034
|
+
* .controller('ExampleController', ['$scope', function($scope) {
|
30035
|
+
* $scope.regex = '\\d+';
|
30036
|
+
* }]);
|
30037
|
+
* </script>
|
30038
|
+
* <div ng-controller="ExampleController">
|
30039
|
+
* <form name="form">
|
30040
|
+
* <label for="regex">Set a pattern (regex string): </label>
|
30041
|
+
* <input type="text" ng-model="regex" id="regex" />
|
30042
|
+
* <br>
|
30043
|
+
* <label for="input">This input is restricted by the current pattern: </label>
|
30044
|
+
* <input type="text" ng-model="model" id="input" name="input" ng-pattern="regex" /><br>
|
30045
|
+
* <hr>
|
30046
|
+
* input valid? = <code>{{form.input.$valid}}</code><br>
|
30047
|
+
* model = <code>{{model}}</code>
|
30048
|
+
* </form>
|
30049
|
+
* </div>
|
30050
|
+
* </file>
|
30051
|
+
* <file name="protractor.js" type="protractor">
|
30052
|
+
var model = element(by.binding('model'));
|
30053
|
+
var input = element(by.id('input'));
|
30054
|
+
|
30055
|
+
it('should validate the input with the default pattern', function() {
|
30056
|
+
input.sendKeys('aaa');
|
30057
|
+
expect(model.getText()).not.toContain('aaa');
|
28800
30058
|
|
30059
|
+
input.clear().then(function() {
|
30060
|
+
input.sendKeys('123');
|
30061
|
+
expect(model.getText()).toContain('123');
|
30062
|
+
});
|
30063
|
+
});
|
30064
|
+
* </file>
|
30065
|
+
* </example>
|
30066
|
+
*/
|
28801
30067
|
var patternDirective = function() {
|
28802
30068
|
return {
|
28803
30069
|
restrict: 'A',
|
@@ -28829,7 +30095,72 @@ var patternDirective = function() {
|
|
28829
30095
|
};
|
28830
30096
|
};
|
28831
30097
|
|
30098
|
+
/**
|
30099
|
+
* @ngdoc directive
|
30100
|
+
* @name ngMaxlength
|
30101
|
+
*
|
30102
|
+
* @description
|
30103
|
+
*
|
30104
|
+
* ngMaxlength adds the maxlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
|
30105
|
+
* It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
|
30106
|
+
*
|
30107
|
+
* The validator sets the `maxlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
|
30108
|
+
* is longer than the integer obtained by evaluating the Angular expression given in the
|
30109
|
+
* `ngMaxlength` attribute value.
|
30110
|
+
*
|
30111
|
+
* <div class="alert alert-info">
|
30112
|
+
* **Note:** This directive is also added when the plain `maxlength` attribute is used, with two
|
30113
|
+
* differences:
|
30114
|
+
* <ol>
|
30115
|
+
* <li>
|
30116
|
+
* `ngMaxlength` does not set the `maxlength` attribute and therefore HTML5 constraint
|
30117
|
+
* validation is not available.
|
30118
|
+
* </li>
|
30119
|
+
* <li>
|
30120
|
+
* The `ngMaxlength` attribute must be an expression, while the `maxlength` value must be
|
30121
|
+
* interpolated.
|
30122
|
+
* </li>
|
30123
|
+
* </ol>
|
30124
|
+
* </div>
|
30125
|
+
*
|
30126
|
+
* @example
|
30127
|
+
* <example name="ngMaxlengthDirective" module="ngMaxlengthExample">
|
30128
|
+
* <file name="index.html">
|
30129
|
+
* <script>
|
30130
|
+
* angular.module('ngMaxlengthExample', [])
|
30131
|
+
* .controller('ExampleController', ['$scope', function($scope) {
|
30132
|
+
* $scope.maxlength = 5;
|
30133
|
+
* }]);
|
30134
|
+
* </script>
|
30135
|
+
* <div ng-controller="ExampleController">
|
30136
|
+
* <form name="form">
|
30137
|
+
* <label for="maxlength">Set a maxlength: </label>
|
30138
|
+
* <input type="number" ng-model="maxlength" id="maxlength" />
|
30139
|
+
* <br>
|
30140
|
+
* <label for="input">This input is restricted by the current maxlength: </label>
|
30141
|
+
* <input type="text" ng-model="model" id="input" name="input" ng-maxlength="maxlength" /><br>
|
30142
|
+
* <hr>
|
30143
|
+
* input valid? = <code>{{form.input.$valid}}</code><br>
|
30144
|
+
* model = <code>{{model}}</code>
|
30145
|
+
* </form>
|
30146
|
+
* </div>
|
30147
|
+
* </file>
|
30148
|
+
* <file name="protractor.js" type="protractor">
|
30149
|
+
var model = element(by.binding('model'));
|
30150
|
+
var input = element(by.id('input'));
|
30151
|
+
|
30152
|
+
it('should validate the input with the default maxlength', function() {
|
30153
|
+
input.sendKeys('abcdef');
|
30154
|
+
expect(model.getText()).not.toContain('abcdef');
|
28832
30155
|
|
30156
|
+
input.clear().then(function() {
|
30157
|
+
input.sendKeys('abcde');
|
30158
|
+
expect(model.getText()).toContain('abcde');
|
30159
|
+
});
|
30160
|
+
});
|
30161
|
+
* </file>
|
30162
|
+
* </example>
|
30163
|
+
*/
|
28833
30164
|
var maxlengthDirective = function() {
|
28834
30165
|
return {
|
28835
30166
|
restrict: 'A',
|
@@ -28850,6 +30181,70 @@ var maxlengthDirective = function() {
|
|
28850
30181
|
};
|
28851
30182
|
};
|
28852
30183
|
|
30184
|
+
/**
|
30185
|
+
* @ngdoc directive
|
30186
|
+
* @name ngMinlength
|
30187
|
+
*
|
30188
|
+
* @description
|
30189
|
+
*
|
30190
|
+
* ngMinlength adds the minlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
|
30191
|
+
* It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
|
30192
|
+
*
|
30193
|
+
* The validator sets the `minlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
|
30194
|
+
* is shorter than the integer obtained by evaluating the Angular expression given in the
|
30195
|
+
* `ngMinlength` attribute value.
|
30196
|
+
*
|
30197
|
+
* <div class="alert alert-info">
|
30198
|
+
* **Note:** This directive is also added when the plain `minlength` attribute is used, with two
|
30199
|
+
* differences:
|
30200
|
+
* <ol>
|
30201
|
+
* <li>
|
30202
|
+
* `ngMinlength` does not set the `minlength` attribute and therefore HTML5 constraint
|
30203
|
+
* validation is not available.
|
30204
|
+
* </li>
|
30205
|
+
* <li>
|
30206
|
+
* The `ngMinlength` value must be an expression, while the `minlength` value must be
|
30207
|
+
* interpolated.
|
30208
|
+
* </li>
|
30209
|
+
* </ol>
|
30210
|
+
* </div>
|
30211
|
+
*
|
30212
|
+
* @example
|
30213
|
+
* <example name="ngMinlengthDirective" module="ngMinlengthExample">
|
30214
|
+
* <file name="index.html">
|
30215
|
+
* <script>
|
30216
|
+
* angular.module('ngMinlengthExample', [])
|
30217
|
+
* .controller('ExampleController', ['$scope', function($scope) {
|
30218
|
+
* $scope.minlength = 3;
|
30219
|
+
* }]);
|
30220
|
+
* </script>
|
30221
|
+
* <div ng-controller="ExampleController">
|
30222
|
+
* <form name="form">
|
30223
|
+
* <label for="minlength">Set a minlength: </label>
|
30224
|
+
* <input type="number" ng-model="minlength" id="minlength" />
|
30225
|
+
* <br>
|
30226
|
+
* <label for="input">This input is restricted by the current minlength: </label>
|
30227
|
+
* <input type="text" ng-model="model" id="input" name="input" ng-minlength="minlength" /><br>
|
30228
|
+
* <hr>
|
30229
|
+
* input valid? = <code>{{form.input.$valid}}</code><br>
|
30230
|
+
* model = <code>{{model}}</code>
|
30231
|
+
* </form>
|
30232
|
+
* </div>
|
30233
|
+
* </file>
|
30234
|
+
* <file name="protractor.js" type="protractor">
|
30235
|
+
var model = element(by.binding('model'));
|
30236
|
+
var input = element(by.id('input'));
|
30237
|
+
|
30238
|
+
it('should validate the input with the default minlength', function() {
|
30239
|
+
input.sendKeys('ab');
|
30240
|
+
expect(model.getText()).not.toContain('ab');
|
30241
|
+
|
30242
|
+
input.sendKeys('abc');
|
30243
|
+
expect(model.getText()).toContain('abc');
|
30244
|
+
});
|
30245
|
+
* </file>
|
30246
|
+
* </example>
|
30247
|
+
*/
|
28853
30248
|
var minlengthDirective = function() {
|
28854
30249
|
return {
|
28855
30250
|
restrict: 'A',
|
@@ -28962,6 +30357,20 @@ $provide.value("$locale", {
|
|
28962
30357
|
"Nov",
|
28963
30358
|
"Dec"
|
28964
30359
|
],
|
30360
|
+
"STANDALONEMONTH": [
|
30361
|
+
"January",
|
30362
|
+
"February",
|
30363
|
+
"March",
|
30364
|
+
"April",
|
30365
|
+
"May",
|
30366
|
+
"June",
|
30367
|
+
"July",
|
30368
|
+
"August",
|
30369
|
+
"September",
|
30370
|
+
"October",
|
30371
|
+
"November",
|
30372
|
+
"December"
|
30373
|
+
],
|
28965
30374
|
"WEEKENDRANGE": [
|
28966
30375
|
5,
|
28967
30376
|
6
|
@@ -29005,6 +30414,7 @@ $provide.value("$locale", {
|
|
29005
30414
|
]
|
29006
30415
|
},
|
29007
30416
|
"id": "en-us",
|
30417
|
+
"localeID": "en_US",
|
29008
30418
|
"pluralCat": function(n, opt_precision) { var i = n | 0; var vf = getVF(n, opt_precision); if (i == 1 && vf.v == 0) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
|
29009
30419
|
});
|
29010
30420
|
}]);
|