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