angularjs-rails 1.5.6 → 1.5.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/angularjs-rails/version.rb +1 -1
- data/vendor/assets/javascripts/angular-animate.js +40 -49
- data/vendor/assets/javascripts/angular-aria.js +1 -1
- data/vendor/assets/javascripts/angular-cookies.js +1 -1
- data/vendor/assets/javascripts/angular-loader.js +3 -3
- data/vendor/assets/javascripts/angular-message-format.js +136 -32
- data/vendor/assets/javascripts/angular-messages.js +394 -379
- data/vendor/assets/javascripts/angular-mocks.js +30 -16
- data/vendor/assets/javascripts/angular-parse-ext.js +1 -1
- data/vendor/assets/javascripts/angular-resource.js +104 -9
- data/vendor/assets/javascripts/angular-route.js +39 -2
- data/vendor/assets/javascripts/angular-sanitize.js +319 -298
- data/vendor/assets/javascripts/angular-scenario.js +2639 -1602
- data/vendor/assets/javascripts/angular-touch.js +15 -9
- data/vendor/assets/javascripts/angular.js +1167 -422
- metadata +11 -11
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.5.
|
2
|
+
* @license AngularJS v1.5.8
|
3
3
|
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -167,6 +167,12 @@ ngTouch.factory('$swipe', [function() {
|
|
167
167
|
move: 'touchmove',
|
168
168
|
end: 'touchend',
|
169
169
|
cancel: 'touchcancel'
|
170
|
+
},
|
171
|
+
'pointer': {
|
172
|
+
start: 'pointerdown',
|
173
|
+
move: 'pointermove',
|
174
|
+
end: 'pointerup',
|
175
|
+
cancel: 'pointercancel'
|
170
176
|
}
|
171
177
|
};
|
172
178
|
|
@@ -201,15 +207,15 @@ ngTouch.factory('$swipe', [function() {
|
|
201
207
|
* The main method of `$swipe`. It takes an element to be watched for swipe motions, and an
|
202
208
|
* object containing event handlers.
|
203
209
|
* The pointer types that should be used can be specified via the optional
|
204
|
-
* third argument, which is an array of strings `'mouse'` and `'
|
205
|
-
* `$swipe` will listen for `mouse` and `
|
210
|
+
* third argument, which is an array of strings `'mouse'`, `'touch'` and `'pointer'`. By default,
|
211
|
+
* `$swipe` will listen for `mouse`, `touch` and `pointer` events.
|
206
212
|
*
|
207
213
|
* The four events are `start`, `move`, `end`, and `cancel`. `start`, `move`, and `end`
|
208
214
|
* receive as a parameter a coordinates object of the form `{ x: 150, y: 310 }` and the raw
|
209
215
|
* `event`. `cancel` receives the raw `event` as its single parameter.
|
210
216
|
*
|
211
|
-
* `start` is called on either `mousedown` or `
|
212
|
-
* watching for `touchmove` or `
|
217
|
+
* `start` is called on either `mousedown`, `touchstart` or `pointerdown`. After this event, `$swipe` is
|
218
|
+
* watching for `touchmove`, `mousemove` or `pointermove` events. These events are ignored until the total
|
213
219
|
* distance moved in either dimension exceeds a small threshold.
|
214
220
|
*
|
215
221
|
* Once this threshold is exceeded, either the horizontal or vertical delta is greater.
|
@@ -217,12 +223,12 @@ ngTouch.factory('$swipe', [function() {
|
|
217
223
|
* - If the vertical distance is greater, this is a scroll, and we let the browser take over.
|
218
224
|
* A `cancel` event is sent.
|
219
225
|
*
|
220
|
-
* `move` is called on `mousemove` and `
|
226
|
+
* `move` is called on `mousemove`, `touchmove` and `pointermove` after the above logic has determined that
|
221
227
|
* a swipe is in progress.
|
222
228
|
*
|
223
|
-
* `end` is called when a swipe is successfully completed with a `touchend` or `
|
229
|
+
* `end` is called when a swipe is successfully completed with a `touchend`, `mouseup` or `pointerup`.
|
224
230
|
*
|
225
|
-
* `cancel` is called either on a `touchcancel` from the browser, or when we begin scrolling
|
231
|
+
* `cancel` is called either on a `touchcancel` or `pointercancel` from the browser, or when we begin scrolling
|
226
232
|
* as described above.
|
227
233
|
*
|
228
234
|
*/
|
@@ -236,7 +242,7 @@ ngTouch.factory('$swipe', [function() {
|
|
236
242
|
// Whether a swipe is active.
|
237
243
|
var active = false;
|
238
244
|
|
239
|
-
pointerTypes = pointerTypes || ['mouse', 'touch'];
|
245
|
+
pointerTypes = pointerTypes || ['mouse', 'touch', 'pointer'];
|
240
246
|
element.on(getEvents(pointerTypes, 'start'), function(event) {
|
241
247
|
startCoords = getCoordinates(event);
|
242
248
|
active = true;
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.5.
|
2
|
+
* @license AngularJS v1.5.8
|
3
3
|
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -57,7 +57,7 @@ function minErr(module, ErrorConstructor) {
|
|
57
57
|
return match;
|
58
58
|
});
|
59
59
|
|
60
|
-
message += '\nhttp://errors.angularjs.org/1.5.
|
60
|
+
message += '\nhttp://errors.angularjs.org/1.5.8/' +
|
61
61
|
(module ? module + '/' : '') + code;
|
62
62
|
|
63
63
|
for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
|
@@ -126,7 +126,6 @@ function minErr(module, ErrorConstructor) {
|
|
126
126
|
includes: true,
|
127
127
|
arrayRemove: true,
|
128
128
|
copy: true,
|
129
|
-
shallowCopy: true,
|
130
129
|
equals: true,
|
131
130
|
csp: true,
|
132
131
|
jq: true,
|
@@ -822,7 +821,13 @@ function arrayRemove(array, value) {
|
|
822
821
|
* * If a destination is provided, all of its elements (for arrays) or properties (for objects)
|
823
822
|
* are deleted and then all elements/properties from the source are copied to it.
|
824
823
|
* * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
|
825
|
-
* * If `source` is identical to
|
824
|
+
* * If `source` is identical to `destination` an exception will be thrown.
|
825
|
+
*
|
826
|
+
* <br />
|
827
|
+
* <div class="alert alert-warning">
|
828
|
+
* Only enumerable properties are taken into account. Non-enumerable properties (both on `source`
|
829
|
+
* and on `destination`) will be ignored.
|
830
|
+
* </div>
|
826
831
|
*
|
827
832
|
* @param {*} source The source that will be used to make a copy.
|
828
833
|
* Can be any type, including primitives, `null`, and `undefined`.
|
@@ -831,41 +836,42 @@ function arrayRemove(array, value) {
|
|
831
836
|
* @returns {*} The copy or updated `destination`, if `destination` was specified.
|
832
837
|
*
|
833
838
|
* @example
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
839
|
+
<example module="copyExample">
|
840
|
+
<file name="index.html">
|
841
|
+
<div ng-controller="ExampleController">
|
842
|
+
<form novalidate class="simple-form">
|
843
|
+
<label>Name: <input type="text" ng-model="user.name" /></label><br />
|
844
|
+
<label>Age: <input type="number" ng-model="user.age" /></label><br />
|
845
|
+
Gender: <label><input type="radio" ng-model="user.gender" value="male" />male</label>
|
846
|
+
<label><input type="radio" ng-model="user.gender" value="female" />female</label><br />
|
847
|
+
<button ng-click="reset()">RESET</button>
|
848
|
+
<button ng-click="update(user)">SAVE</button>
|
849
|
+
</form>
|
850
|
+
<pre>form = {{user | json}}</pre>
|
851
|
+
<pre>master = {{master | json}}</pre>
|
852
|
+
</div>
|
853
|
+
</file>
|
854
|
+
<file name="script.js">
|
855
|
+
// Module: copyExample
|
856
|
+
angular.
|
857
|
+
module('copyExample', []).
|
858
|
+
controller('ExampleController', ['$scope', function($scope) {
|
859
|
+
$scope.master = {};
|
860
|
+
|
861
|
+
$scope.reset = function() {
|
862
|
+
// Example with 1 argument
|
863
|
+
$scope.user = angular.copy($scope.master);
|
864
|
+
};
|
858
865
|
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
866
|
+
$scope.update = function(user) {
|
867
|
+
// Example with 2 arguments
|
868
|
+
angular.copy(user, $scope.master);
|
869
|
+
};
|
863
870
|
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
</example>
|
871
|
+
$scope.reset();
|
872
|
+
}]);
|
873
|
+
</file>
|
874
|
+
</example>
|
869
875
|
*/
|
870
876
|
function copy(source, destination) {
|
871
877
|
var stackSource = [];
|
@@ -972,7 +978,7 @@ function copy(source, destination) {
|
|
972
978
|
case '[object Uint8ClampedArray]':
|
973
979
|
case '[object Uint16Array]':
|
974
980
|
case '[object Uint32Array]':
|
975
|
-
return new source.constructor(copyElement(source.buffer));
|
981
|
+
return new source.constructor(copyElement(source.buffer), source.byteOffset, source.length);
|
976
982
|
|
977
983
|
case '[object ArrayBuffer]':
|
978
984
|
//Support: IE10
|
@@ -1004,31 +1010,6 @@ function copy(source, destination) {
|
|
1004
1010
|
}
|
1005
1011
|
}
|
1006
1012
|
|
1007
|
-
/**
|
1008
|
-
* Creates a shallow copy of an object, an array or a primitive.
|
1009
|
-
*
|
1010
|
-
* Assumes that there are no proto properties for objects.
|
1011
|
-
*/
|
1012
|
-
function shallowCopy(src, dst) {
|
1013
|
-
if (isArray(src)) {
|
1014
|
-
dst = dst || [];
|
1015
|
-
|
1016
|
-
for (var i = 0, ii = src.length; i < ii; i++) {
|
1017
|
-
dst[i] = src[i];
|
1018
|
-
}
|
1019
|
-
} else if (isObject(src)) {
|
1020
|
-
dst = dst || {};
|
1021
|
-
|
1022
|
-
for (var key in src) {
|
1023
|
-
if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
|
1024
|
-
dst[key] = src[key];
|
1025
|
-
}
|
1026
|
-
}
|
1027
|
-
}
|
1028
|
-
|
1029
|
-
return dst || src;
|
1030
|
-
}
|
1031
|
-
|
1032
1013
|
|
1033
1014
|
/**
|
1034
1015
|
* @ngdoc function
|
@@ -2369,7 +2350,34 @@ function setupModuleLoader(window) {
|
|
2369
2350
|
|
2370
2351
|
}
|
2371
2352
|
|
2372
|
-
/* global
|
2353
|
+
/* global shallowCopy: true */
|
2354
|
+
|
2355
|
+
/**
|
2356
|
+
* Creates a shallow copy of an object, an array or a primitive.
|
2357
|
+
*
|
2358
|
+
* Assumes that there are no proto properties for objects.
|
2359
|
+
*/
|
2360
|
+
function shallowCopy(src, dst) {
|
2361
|
+
if (isArray(src)) {
|
2362
|
+
dst = dst || [];
|
2363
|
+
|
2364
|
+
for (var i = 0, ii = src.length; i < ii; i++) {
|
2365
|
+
dst[i] = src[i];
|
2366
|
+
}
|
2367
|
+
} else if (isObject(src)) {
|
2368
|
+
dst = dst || {};
|
2369
|
+
|
2370
|
+
for (var key in src) {
|
2371
|
+
if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
|
2372
|
+
dst[key] = src[key];
|
2373
|
+
}
|
2374
|
+
}
|
2375
|
+
}
|
2376
|
+
|
2377
|
+
return dst || src;
|
2378
|
+
}
|
2379
|
+
|
2380
|
+
/* global toDebugString: true */
|
2373
2381
|
|
2374
2382
|
function serializeObject(obj) {
|
2375
2383
|
var seen = [];
|
@@ -2473,6 +2481,7 @@ function toDebugString(obj) {
|
|
2473
2481
|
$HttpParamSerializerJQLikeProvider,
|
2474
2482
|
$HttpBackendProvider,
|
2475
2483
|
$xhrFactoryProvider,
|
2484
|
+
$jsonpCallbacksProvider,
|
2476
2485
|
$LocationProvider,
|
2477
2486
|
$LogProvider,
|
2478
2487
|
$ParseProvider,
|
@@ -2510,11 +2519,11 @@ function toDebugString(obj) {
|
|
2510
2519
|
* - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
|
2511
2520
|
*/
|
2512
2521
|
var version = {
|
2513
|
-
full: '1.5.
|
2522
|
+
full: '1.5.8', // all of these placeholder strings will be replaced by grunt's
|
2514
2523
|
major: 1, // package task
|
2515
2524
|
minor: 5,
|
2516
|
-
dot:
|
2517
|
-
codeName: '
|
2525
|
+
dot: 8,
|
2526
|
+
codeName: 'arbitrary-fallbacks'
|
2518
2527
|
};
|
2519
2528
|
|
2520
2529
|
|
@@ -2545,7 +2554,7 @@ function publishExternalAPI(angular) {
|
|
2545
2554
|
'isDate': isDate,
|
2546
2555
|
'lowercase': lowercase,
|
2547
2556
|
'uppercase': uppercase,
|
2548
|
-
'callbacks': {counter: 0},
|
2557
|
+
'callbacks': {$$counter: 0},
|
2549
2558
|
'getTestability': getTestability,
|
2550
2559
|
'$$minErr': minErr,
|
2551
2560
|
'$$csp': csp,
|
@@ -2634,6 +2643,7 @@ function publishExternalAPI(angular) {
|
|
2634
2643
|
$httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,
|
2635
2644
|
$httpBackend: $HttpBackendProvider,
|
2636
2645
|
$xhrFactory: $xhrFactoryProvider,
|
2646
|
+
$jsonpCallbacks: $jsonpCallbacksProvider,
|
2637
2647
|
$location: $LocationProvider,
|
2638
2648
|
$log: $LogProvider,
|
2639
2649
|
$parse: $ParseProvider,
|
@@ -2710,7 +2720,7 @@ function publishExternalAPI(angular) {
|
|
2710
2720
|
* ## Angular's jqLite
|
2711
2721
|
* jqLite provides only the following jQuery methods:
|
2712
2722
|
*
|
2713
|
-
* - [`addClass()`](http://api.jquery.com/addClass/)
|
2723
|
+
* - [`addClass()`](http://api.jquery.com/addClass/) - Does not support a function as first argument
|
2714
2724
|
* - [`after()`](http://api.jquery.com/after/)
|
2715
2725
|
* - [`append()`](http://api.jquery.com/append/)
|
2716
2726
|
* - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
|
@@ -2737,7 +2747,7 @@ function publishExternalAPI(angular) {
|
|
2737
2747
|
* - [`ready()`](http://api.jquery.com/ready/)
|
2738
2748
|
* - [`remove()`](http://api.jquery.com/remove/)
|
2739
2749
|
* - [`removeAttr()`](http://api.jquery.com/removeAttr/)
|
2740
|
-
* - [`removeClass()`](http://api.jquery.com/removeClass/)
|
2750
|
+
* - [`removeClass()`](http://api.jquery.com/removeClass/) - Does not support a function as first argument
|
2741
2751
|
* - [`removeData()`](http://api.jquery.com/removeData/)
|
2742
2752
|
* - [`replaceWith()`](http://api.jquery.com/replaceWith/)
|
2743
2753
|
* - [`text()`](http://api.jquery.com/text/)
|
@@ -2872,7 +2882,7 @@ function jqLiteBuildFragment(html, context) {
|
|
2872
2882
|
nodes.push(context.createTextNode(html));
|
2873
2883
|
} else {
|
2874
2884
|
// Convert html into DOM nodes
|
2875
|
-
tmp =
|
2885
|
+
tmp = fragment.appendChild(context.createElement("div"));
|
2876
2886
|
tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
|
2877
2887
|
wrap = wrapMap[tag] || wrapMap._default;
|
2878
2888
|
tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
|
@@ -4685,10 +4695,10 @@ function createInjector(modulesToLoad, strictDi) {
|
|
4685
4695
|
if (msie <= 11) {
|
4686
4696
|
return false;
|
4687
4697
|
}
|
4688
|
-
//
|
4689
|
-
//
|
4698
|
+
// Support: Edge 12-13 only
|
4699
|
+
// See: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6156135/
|
4690
4700
|
return typeof func === 'function'
|
4691
|
-
&& /^(?:class\
|
4701
|
+
&& /^(?:class\b|constructor\()/.test(stringifyFn(func));
|
4692
4702
|
}
|
4693
4703
|
|
4694
4704
|
function invoke(fn, self, locals, serviceName) {
|
@@ -5429,7 +5439,13 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
5429
5439
|
* @param {DOMElement} parent the parent element which will append the element as
|
5430
5440
|
* a child (so long as the after element is not present)
|
5431
5441
|
* @param {DOMElement=} after the sibling element after which the element will be appended
|
5432
|
-
* @param {object=} options an optional collection of options/styles that will be applied to the element
|
5442
|
+
* @param {object=} options an optional collection of options/styles that will be applied to the element.
|
5443
|
+
* The object can have the following properties:
|
5444
|
+
*
|
5445
|
+
* - **addClass** - `{string}` - space-separated CSS classes to add to element
|
5446
|
+
* - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
|
5447
|
+
* - **removeClass** - `{string}` - space-separated CSS classes to remove from element
|
5448
|
+
* - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
|
5433
5449
|
*
|
5434
5450
|
* @return {Promise} the animation callback promise
|
5435
5451
|
*/
|
@@ -5455,7 +5471,13 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
5455
5471
|
* @param {DOMElement} parent the parent element which will append the element as
|
5456
5472
|
* a child (so long as the after element is not present)
|
5457
5473
|
* @param {DOMElement=} after the sibling element after which the element will be appended
|
5458
|
-
* @param {object=} options an optional collection of options/styles that will be applied to the element
|
5474
|
+
* @param {object=} options an optional collection of options/styles that will be applied to the element.
|
5475
|
+
* The object can have the following properties:
|
5476
|
+
*
|
5477
|
+
* - **addClass** - `{string}` - space-separated CSS classes to add to element
|
5478
|
+
* - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
|
5479
|
+
* - **removeClass** - `{string}` - space-separated CSS classes to remove from element
|
5480
|
+
* - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
|
5459
5481
|
*
|
5460
5482
|
* @return {Promise} the animation callback promise
|
5461
5483
|
*/
|
@@ -5476,7 +5498,13 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
5476
5498
|
* digest once the animation has completed.
|
5477
5499
|
*
|
5478
5500
|
* @param {DOMElement} element the element which will be removed from the DOM
|
5479
|
-
* @param {object=} options an optional collection of options/styles that will be applied to the element
|
5501
|
+
* @param {object=} options an optional collection of options/styles that will be applied to the element.
|
5502
|
+
* The object can have the following properties:
|
5503
|
+
*
|
5504
|
+
* - **addClass** - `{string}` - space-separated CSS classes to add to element
|
5505
|
+
* - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
|
5506
|
+
* - **removeClass** - `{string}` - space-separated CSS classes to remove from element
|
5507
|
+
* - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
|
5480
5508
|
*
|
5481
5509
|
* @return {Promise} the animation callback promise
|
5482
5510
|
*/
|
@@ -5500,7 +5528,13 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
5500
5528
|
*
|
5501
5529
|
* @param {DOMElement} element the element which the CSS classes will be applied to
|
5502
5530
|
* @param {string} className the CSS class(es) that will be added (multiple classes are separated via spaces)
|
5503
|
-
* @param {object=} options an optional collection of options/styles that will be applied to the element
|
5531
|
+
* @param {object=} options an optional collection of options/styles that will be applied to the element.
|
5532
|
+
* The object can have the following properties:
|
5533
|
+
*
|
5534
|
+
* - **addClass** - `{string}` - space-separated CSS classes to add to element
|
5535
|
+
* - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
|
5536
|
+
* - **removeClass** - `{string}` - space-separated CSS classes to remove from element
|
5537
|
+
* - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
|
5504
5538
|
*
|
5505
5539
|
* @return {Promise} the animation callback promise
|
5506
5540
|
*/
|
@@ -5524,7 +5558,13 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
5524
5558
|
*
|
5525
5559
|
* @param {DOMElement} element the element which the CSS classes will be applied to
|
5526
5560
|
* @param {string} className the CSS class(es) that will be removed (multiple classes are separated via spaces)
|
5527
|
-
* @param {object=} options an optional collection of options/styles that will be applied to the element
|
5561
|
+
* @param {object=} options an optional collection of options/styles that will be applied to the element.
|
5562
|
+
* The object can have the following properties:
|
5563
|
+
*
|
5564
|
+
* - **addClass** - `{string}` - space-separated CSS classes to add to element
|
5565
|
+
* - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
|
5566
|
+
* - **removeClass** - `{string}` - space-separated CSS classes to remove from element
|
5567
|
+
* - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
|
5528
5568
|
*
|
5529
5569
|
* @return {Promise} the animation callback promise
|
5530
5570
|
*/
|
@@ -5549,7 +5589,13 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
5549
5589
|
* @param {DOMElement} element the element which the CSS classes will be applied to
|
5550
5590
|
* @param {string} add the CSS class(es) that will be added (multiple classes are separated via spaces)
|
5551
5591
|
* @param {string} remove the CSS class(es) that will be removed (multiple classes are separated via spaces)
|
5552
|
-
* @param {object=} options an optional collection of options/styles that will be applied to the element
|
5592
|
+
* @param {object=} options an optional collection of options/styles that will be applied to the element.
|
5593
|
+
* The object can have the following properties:
|
5594
|
+
*
|
5595
|
+
* - **addClass** - `{string}` - space-separated CSS classes to add to element
|
5596
|
+
* - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
|
5597
|
+
* - **removeClass** - `{string}` - space-separated CSS classes to remove from element
|
5598
|
+
* - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
|
5553
5599
|
*
|
5554
5600
|
* @return {Promise} the animation callback promise
|
5555
5601
|
*/
|
@@ -5590,7 +5636,13 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
5590
5636
|
* @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
|
5591
5637
|
* this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
|
5592
5638
|
* (Note that if no animation is detected then this value will not be applied to the element.)
|
5593
|
-
* @param {object=} options an optional collection of options/styles that will be applied to the element
|
5639
|
+
* @param {object=} options an optional collection of options/styles that will be applied to the element.
|
5640
|
+
* The object can have the following properties:
|
5641
|
+
*
|
5642
|
+
* - **addClass** - `{string}` - space-separated CSS classes to add to element
|
5643
|
+
* - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
|
5644
|
+
* - **removeClass** - `{string}` - space-separated CSS classes to remove from element
|
5645
|
+
* - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
|
5594
5646
|
*
|
5595
5647
|
* @return {Promise} the animation callback promise
|
5596
5648
|
*/
|
@@ -6678,8 +6730,9 @@ function $TemplateCacheProvider() {
|
|
6678
6730
|
* There are many different options for a directive.
|
6679
6731
|
*
|
6680
6732
|
* The difference resides in the return value of the factory function.
|
6681
|
-
* You can either return a
|
6682
|
-
* or just the `postLink` function (all other properties will have
|
6733
|
+
* You can either return a {@link $compile#directive-definition-object Directive Definition Object (see below)}
|
6734
|
+
* that defines the directive properties, or just the `postLink` function (all other properties will have
|
6735
|
+
* the default values).
|
6683
6736
|
*
|
6684
6737
|
* <div class="alert alert-success">
|
6685
6738
|
* **Best Practice:** It's recommended to use the "directive definition object" form.
|
@@ -6743,6 +6796,125 @@ function $TemplateCacheProvider() {
|
|
6743
6796
|
* });
|
6744
6797
|
* ```
|
6745
6798
|
*
|
6799
|
+
* ### Life-cycle hooks
|
6800
|
+
* Directive controllers can provide the following methods that are called by Angular at points in the life-cycle of the
|
6801
|
+
* directive:
|
6802
|
+
* * `$onInit()` - Called on each controller after all the controllers on an element have been constructed and
|
6803
|
+
* had their bindings initialized (and before the pre & post linking functions for the directives on
|
6804
|
+
* this element). This is a good place to put initialization code for your controller.
|
6805
|
+
* * `$onChanges(changesObj)` - Called whenever one-way (`<`) or interpolation (`@`) bindings are updated. The
|
6806
|
+
* `changesObj` is a hash whose keys are the names of the bound properties that have changed, and the values are an
|
6807
|
+
* object of the form `{ currentValue, previousValue, isFirstChange() }`. Use this hook to trigger updates within a
|
6808
|
+
* component such as cloning the bound value to prevent accidental mutation of the outer value.
|
6809
|
+
* * `$doCheck()` - Called on each turn of the digest cycle. Provides an opportunity to detect and act on
|
6810
|
+
* changes. Any actions that you wish to take in response to the changes that you detect must be
|
6811
|
+
* invoked from this hook; implementing this has no effect on when `$onChanges` is called. For example, this hook
|
6812
|
+
* could be useful if you wish to perform a deep equality check, or to check a Date object, changes to which would not
|
6813
|
+
* be detected by Angular's change detector and thus not trigger `$onChanges`. This hook is invoked with no arguments;
|
6814
|
+
* if detecting changes, you must store the previous value(s) for comparison to the current values.
|
6815
|
+
* * `$onDestroy()` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
|
6816
|
+
* external resources, watches and event handlers. Note that components have their `$onDestroy()` hooks called in
|
6817
|
+
* the same order as the `$scope.$broadcast` events are triggered, which is top down. This means that parent
|
6818
|
+
* components will have their `$onDestroy()` hook called before child components.
|
6819
|
+
* * `$postLink()` - Called after this controller's element and its children have been linked. Similar to the post-link
|
6820
|
+
* function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
|
6821
|
+
* Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
|
6822
|
+
* they are waiting for their template to load asynchronously and their own compilation and linking has been
|
6823
|
+
* suspended until that occurs.
|
6824
|
+
*
|
6825
|
+
* #### Comparison with Angular 2 life-cycle hooks
|
6826
|
+
* Angular 2 also uses life-cycle hooks for its components. While the Angular 1 life-cycle hooks are similar there are
|
6827
|
+
* some differences that you should be aware of, especially when it comes to moving your code from Angular 1 to Angular 2:
|
6828
|
+
*
|
6829
|
+
* * Angular 1 hooks are prefixed with `$`, such as `$onInit`. Angular 2 hooks are prefixed with `ng`, such as `ngOnInit`.
|
6830
|
+
* * Angular 1 hooks can be defined on the controller prototype or added to the controller inside its constructor.
|
6831
|
+
* In Angular 2 you can only define hooks on the prototype of the Component class.
|
6832
|
+
* * Due to the differences in change-detection, you may get many more calls to `$doCheck` in Angular 1 than you would to
|
6833
|
+
* `ngDoCheck` in Angular 2
|
6834
|
+
* * Changes to the model inside `$doCheck` will trigger new turns of the digest loop, which will cause the changes to be
|
6835
|
+
* propagated throughout the application.
|
6836
|
+
* Angular 2 does not allow the `ngDoCheck` hook to trigger a change outside of the component. It will either throw an
|
6837
|
+
* error or do nothing depending upon the state of `enableProdMode()`.
|
6838
|
+
*
|
6839
|
+
* #### Life-cycle hook examples
|
6840
|
+
*
|
6841
|
+
* This example shows how you can check for mutations to a Date object even though the identity of the object
|
6842
|
+
* has not changed.
|
6843
|
+
*
|
6844
|
+
* <example name="doCheckDateExample" module="do-check-module">
|
6845
|
+
* <file name="app.js">
|
6846
|
+
* angular.module('do-check-module', [])
|
6847
|
+
* .component('app', {
|
6848
|
+
* template:
|
6849
|
+
* 'Month: <input ng-model="$ctrl.month" ng-change="$ctrl.updateDate()">' +
|
6850
|
+
* 'Date: {{ $ctrl.date }}' +
|
6851
|
+
* '<test date="$ctrl.date"></test>',
|
6852
|
+
* controller: function() {
|
6853
|
+
* this.date = new Date();
|
6854
|
+
* this.month = this.date.getMonth();
|
6855
|
+
* this.updateDate = function() {
|
6856
|
+
* this.date.setMonth(this.month);
|
6857
|
+
* };
|
6858
|
+
* }
|
6859
|
+
* })
|
6860
|
+
* .component('test', {
|
6861
|
+
* bindings: { date: '<' },
|
6862
|
+
* template:
|
6863
|
+
* '<pre>{{ $ctrl.log | json }}</pre>',
|
6864
|
+
* controller: function() {
|
6865
|
+
* var previousValue;
|
6866
|
+
* this.log = [];
|
6867
|
+
* this.$doCheck = function() {
|
6868
|
+
* var currentValue = this.date && this.date.valueOf();
|
6869
|
+
* if (previousValue !== currentValue) {
|
6870
|
+
* this.log.push('doCheck: date mutated: ' + this.date);
|
6871
|
+
* previousValue = currentValue;
|
6872
|
+
* }
|
6873
|
+
* };
|
6874
|
+
* }
|
6875
|
+
* });
|
6876
|
+
* </file>
|
6877
|
+
* <file name="index.html">
|
6878
|
+
* <app></app>
|
6879
|
+
* </file>
|
6880
|
+
* </example>
|
6881
|
+
*
|
6882
|
+
* This example show how you might use `$doCheck` to trigger changes in your component's inputs even if the
|
6883
|
+
* actual identity of the component doesn't change. (Be aware that cloning and deep equality checks on large
|
6884
|
+
* arrays or objects can have a negative impact on your application performance)
|
6885
|
+
*
|
6886
|
+
* <example name="doCheckArrayExample" module="do-check-module">
|
6887
|
+
* <file name="index.html">
|
6888
|
+
* <div ng-init="items = []">
|
6889
|
+
* <button ng-click="items.push(items.length)">Add Item</button>
|
6890
|
+
* <button ng-click="items = []">Reset Items</button>
|
6891
|
+
* <pre>{{ items }}</pre>
|
6892
|
+
* <test items="items"></test>
|
6893
|
+
* </div>
|
6894
|
+
* </file>
|
6895
|
+
* <file name="app.js">
|
6896
|
+
* angular.module('do-check-module', [])
|
6897
|
+
* .component('test', {
|
6898
|
+
* bindings: { items: '<' },
|
6899
|
+
* template:
|
6900
|
+
* '<pre>{{ $ctrl.log | json }}</pre>',
|
6901
|
+
* controller: function() {
|
6902
|
+
* this.log = [];
|
6903
|
+
*
|
6904
|
+
* this.$doCheck = function() {
|
6905
|
+
* if (this.items_ref !== this.items) {
|
6906
|
+
* this.log.push('doCheck: items changed');
|
6907
|
+
* this.items_ref = this.items;
|
6908
|
+
* }
|
6909
|
+
* if (!angular.equals(this.items_clone, this.items)) {
|
6910
|
+
* this.log.push('doCheck: items mutated');
|
6911
|
+
* this.items_clone = angular.copy(this.items);
|
6912
|
+
* }
|
6913
|
+
* };
|
6914
|
+
* }
|
6915
|
+
* });
|
6916
|
+
* </file>
|
6917
|
+
* </example>
|
6746
6918
|
*
|
6747
6919
|
*
|
6748
6920
|
* ### Directive Definition Object
|
@@ -6918,25 +7090,6 @@ function $TemplateCacheProvider() {
|
|
6918
7090
|
* The `$transclude` function also has a method on it, `$transclude.isSlotFilled(slotName)`, which returns
|
6919
7091
|
* `true` if the specified slot contains content (i.e. one or more DOM nodes).
|
6920
7092
|
*
|
6921
|
-
* The controller can provide the following methods that act as life-cycle hooks:
|
6922
|
-
* * `$onInit()` - Called on each controller after all the controllers on an element have been constructed and
|
6923
|
-
* had their bindings initialized (and before the pre & post linking functions for the directives on
|
6924
|
-
* this element). This is a good place to put initialization code for your controller.
|
6925
|
-
* * `$onChanges(changesObj)` - Called whenever one-way (`<`) or interpolation (`@`) bindings are updated. The
|
6926
|
-
* `changesObj` is a hash whose keys are the names of the bound properties that have changed, and the values are an
|
6927
|
-
* object of the form `{ currentValue, previousValue, isFirstChange() }`. Use this hook to trigger updates within a
|
6928
|
-
* component such as cloning the bound value to prevent accidental mutation of the outer value.
|
6929
|
-
* * `$onDestroy()` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
|
6930
|
-
* external resources, watches and event handlers. Note that components have their `$onDestroy()` hooks called in
|
6931
|
-
* the same order as the `$scope.$broadcast` events are triggered, which is top down. This means that parent
|
6932
|
-
* components will have their `$onDestroy()` hook called before child components.
|
6933
|
-
* * `$postLink()` - Called after this controller's element and its children have been linked. Similar to the post-link
|
6934
|
-
* function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
|
6935
|
-
* Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
|
6936
|
-
* they are waiting for their template to load asynchronously and their own compilation and linking has been
|
6937
|
-
* suspended until that occurs.
|
6938
|
-
*
|
6939
|
-
*
|
6940
7093
|
* #### `require`
|
6941
7094
|
* Require another directive and inject its controller as the fourth argument to the linking function. The
|
6942
7095
|
* `require` property can be a string, an array or an object:
|
@@ -7134,8 +7287,8 @@ function $TemplateCacheProvider() {
|
|
7134
7287
|
* any other controller.
|
7135
7288
|
*
|
7136
7289
|
* * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
|
7137
|
-
* This is the same as the `$transclude`
|
7138
|
-
*
|
7290
|
+
* This is the same as the `$transclude` parameter of directive controllers,
|
7291
|
+
* see {@link ng.$compile#-controller- the controller section for details}.
|
7139
7292
|
* `function([scope], cloneLinkingFn, futureParentElement)`.
|
7140
7293
|
*
|
7141
7294
|
* #### Pre-linking function
|
@@ -7937,11 +8090,19 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
7937
8090
|
}
|
7938
8091
|
// We must run this hook in an apply since the $$postDigest runs outside apply
|
7939
8092
|
$rootScope.$apply(function() {
|
8093
|
+
var errors = [];
|
7940
8094
|
for (var i = 0, ii = onChangesQueue.length; i < ii; ++i) {
|
7941
|
-
|
8095
|
+
try {
|
8096
|
+
onChangesQueue[i]();
|
8097
|
+
} catch (e) {
|
8098
|
+
errors.push(e);
|
8099
|
+
}
|
7942
8100
|
}
|
7943
8101
|
// Reset the queue to trigger a new schedule next time there is a change
|
7944
8102
|
onChangesQueue = undefined;
|
8103
|
+
if (errors.length) {
|
8104
|
+
throw errors;
|
8105
|
+
}
|
7945
8106
|
});
|
7946
8107
|
} finally {
|
7947
8108
|
onChangesTtl++;
|
@@ -8582,19 +8743,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
8582
8743
|
addTextInterpolateDirective(directives, node.nodeValue);
|
8583
8744
|
break;
|
8584
8745
|
case NODE_TYPE_COMMENT: /* Comment */
|
8585
|
-
|
8586
|
-
match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
|
8587
|
-
if (match) {
|
8588
|
-
nName = directiveNormalize(match[1]);
|
8589
|
-
if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
|
8590
|
-
attrs[nName] = trim(match[2]);
|
8591
|
-
}
|
8592
|
-
}
|
8593
|
-
} catch (e) {
|
8594
|
-
// turns out that under some circumstances IE9 throws errors when one attempts to read
|
8595
|
-
// comment's node value.
|
8596
|
-
// Just ignore it and continue. (Can't seem to reproduce in test case.)
|
8597
|
-
}
|
8746
|
+
collectCommentDirectives(node, directives, attrs, maxPriority, ignoreDirective);
|
8598
8747
|
break;
|
8599
8748
|
}
|
8600
8749
|
|
@@ -8602,6 +8751,24 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
8602
8751
|
return directives;
|
8603
8752
|
}
|
8604
8753
|
|
8754
|
+
function collectCommentDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
|
8755
|
+
// function created because of performance, try/catch disables
|
8756
|
+
// the optimization of the whole function #14848
|
8757
|
+
try {
|
8758
|
+
var match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
|
8759
|
+
if (match) {
|
8760
|
+
var nName = directiveNormalize(match[1]);
|
8761
|
+
if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
|
8762
|
+
attrs[nName] = trim(match[2]);
|
8763
|
+
}
|
8764
|
+
}
|
8765
|
+
} catch (e) {
|
8766
|
+
// turns out that under some circumstances IE9 throws errors when one attempts to read
|
8767
|
+
// comment's node value.
|
8768
|
+
// Just ignore it and continue. (Can't seem to reproduce in test case.)
|
8769
|
+
}
|
8770
|
+
}
|
8771
|
+
|
8605
8772
|
/**
|
8606
8773
|
* Given a node with an directive-start it collects all of the siblings until it finds
|
8607
8774
|
* directive-end.
|
@@ -9117,10 +9284,22 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
9117
9284
|
forEach(elementControllers, function(controller) {
|
9118
9285
|
var controllerInstance = controller.instance;
|
9119
9286
|
if (isFunction(controllerInstance.$onChanges)) {
|
9120
|
-
|
9287
|
+
try {
|
9288
|
+
controllerInstance.$onChanges(controller.bindingInfo.initialChanges);
|
9289
|
+
} catch (e) {
|
9290
|
+
$exceptionHandler(e);
|
9291
|
+
}
|
9121
9292
|
}
|
9122
9293
|
if (isFunction(controllerInstance.$onInit)) {
|
9123
|
-
|
9294
|
+
try {
|
9295
|
+
controllerInstance.$onInit();
|
9296
|
+
} catch (e) {
|
9297
|
+
$exceptionHandler(e);
|
9298
|
+
}
|
9299
|
+
}
|
9300
|
+
if (isFunction(controllerInstance.$doCheck)) {
|
9301
|
+
controllerScope.$watch(function() { controllerInstance.$doCheck(); });
|
9302
|
+
controllerInstance.$doCheck();
|
9124
9303
|
}
|
9125
9304
|
if (isFunction(controllerInstance.$onDestroy)) {
|
9126
9305
|
controllerScope.$on('$destroy', function callOnDestroyHook() {
|
@@ -9384,18 +9563,16 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
9384
9563
|
|
9385
9564
|
// copy the new attributes on the old attrs object
|
9386
9565
|
forEach(src, function(value, key) {
|
9387
|
-
if
|
9388
|
-
|
9389
|
-
|
9390
|
-
|
9391
|
-
|
9392
|
-
dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
|
9393
|
-
// `dst` will never contain hasOwnProperty as DOM parser won't let it.
|
9394
|
-
// You will get an "InvalidCharacterError: DOM Exception 5" error if you
|
9395
|
-
// have an attribute like "has-own-property" or "data-has-own-property", etc.
|
9396
|
-
} else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
|
9566
|
+
// Check if we already set this attribute in the loop above.
|
9567
|
+
// `dst` will never contain hasOwnProperty as DOM parser won't let it.
|
9568
|
+
// You will get an "InvalidCharacterError: DOM Exception 5" error if you
|
9569
|
+
// have an attribute like "has-own-property" or "data-has-own-property", etc.
|
9570
|
+
if (!dst.hasOwnProperty(key) && key.charAt(0) !== '$') {
|
9397
9571
|
dst[key] = value;
|
9398
|
-
|
9572
|
+
|
9573
|
+
if (key !== 'class' && key !== 'style') {
|
9574
|
+
dstAttr[key] = srcAttr[key];
|
9575
|
+
}
|
9399
9576
|
}
|
9400
9577
|
});
|
9401
9578
|
}
|
@@ -9770,7 +9947,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
9770
9947
|
forEach(bindings, function initializeBinding(definition, scopeName) {
|
9771
9948
|
var attrName = definition.attrName,
|
9772
9949
|
optional = definition.optional,
|
9773
|
-
mode = definition.mode, // @, =, or &
|
9950
|
+
mode = definition.mode, // @, =, <, or &
|
9774
9951
|
lastValue,
|
9775
9952
|
parentGet, parentSet, compare, removeWatch;
|
9776
9953
|
|
@@ -10256,18 +10433,21 @@ function $DocumentProvider() {
|
|
10256
10433
|
*
|
10257
10434
|
* ## Example:
|
10258
10435
|
*
|
10436
|
+
* The example below will overwrite the default `$exceptionHandler` in order to (a) log uncaught
|
10437
|
+
* errors to the backend for later inspection by the developers and (b) to use `$log.warn()` instead
|
10438
|
+
* of `$log.error()`.
|
10439
|
+
*
|
10259
10440
|
* ```js
|
10260
|
-
* angular.
|
10261
|
-
*
|
10262
|
-
*
|
10263
|
-
*
|
10264
|
-
*
|
10265
|
-
*
|
10441
|
+
* angular.
|
10442
|
+
* module('exceptionOverwrite', []).
|
10443
|
+
* factory('$exceptionHandler', ['$log', 'logErrorsToBackend', function($log, logErrorsToBackend) {
|
10444
|
+
* return function myExceptionHandler(exception, cause) {
|
10445
|
+
* logErrorsToBackend(exception, cause);
|
10446
|
+
* $log.warn(exception, cause);
|
10447
|
+
* };
|
10448
|
+
* }]);
|
10266
10449
|
* ```
|
10267
10450
|
*
|
10268
|
-
* This example will override the normal action of `$exceptionHandler`, to make angular
|
10269
|
-
* exceptions fail hard when they happen, instead of just logging to the console.
|
10270
|
-
*
|
10271
10451
|
* <hr />
|
10272
10452
|
* Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`
|
10273
10453
|
* methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler}
|
@@ -10277,7 +10457,7 @@ function $DocumentProvider() {
|
|
10277
10457
|
* `try { ... } catch(e) { $exceptionHandler(e); }`
|
10278
10458
|
*
|
10279
10459
|
* @param {Error} exception Exception associated with the error.
|
10280
|
-
* @param {string=} cause
|
10460
|
+
* @param {string=} cause Optional information about the context in which
|
10281
10461
|
* the error was thrown.
|
10282
10462
|
*
|
10283
10463
|
*/
|
@@ -10347,7 +10527,7 @@ function $HttpParamSerializerProvider() {
|
|
10347
10527
|
* * `{'foo': 'bar'}` results in `foo=bar`
|
10348
10528
|
* * `{'foo': Date.now()}` results in `foo=2015-04-01T09%3A50%3A49.262Z` (`toISOString()` and encoded representation of a Date object)
|
10349
10529
|
* * `{'foo': ['bar', 'baz']}` results in `foo=bar&foo=baz` (repeated key for each array element)
|
10350
|
-
* * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D
|
10530
|
+
* * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D` (stringified and encoded representation of an object)
|
10351
10531
|
*
|
10352
10532
|
* Note that serializer will sort the request parameters alphabetically.
|
10353
10533
|
* */
|
@@ -10898,7 +11078,7 @@ function $HttpProvider() {
|
|
10898
11078
|
*
|
10899
11079
|
* ### Overriding the Default Transformations Per Request
|
10900
11080
|
*
|
10901
|
-
* If you wish override the request/response transformations only for a single request then provide
|
11081
|
+
* If you wish to override the request/response transformations only for a single request then provide
|
10902
11082
|
* `transformRequest` and/or `transformResponse` properties on the configuration object passed
|
10903
11083
|
* into `$http`.
|
10904
11084
|
*
|
@@ -10941,7 +11121,7 @@ function $HttpProvider() {
|
|
10941
11121
|
* * cache a specific response - set config.cache value to TRUE or to a cache object
|
10942
11122
|
*
|
10943
11123
|
* If caching is enabled, but neither the default cache nor config.cache are set to a cache object,
|
10944
|
-
* then the default `$cacheFactory($http)` object is used.
|
11124
|
+
* then the default `$cacheFactory("$http")` object is used.
|
10945
11125
|
*
|
10946
11126
|
* The default cache value can be set by updating the
|
10947
11127
|
* {@link ng.$http#defaults `$http.defaults.cache`} property or the
|
@@ -11269,48 +11449,25 @@ function $HttpProvider() {
|
|
11269
11449
|
config.headers = mergeHeaders(requestConfig);
|
11270
11450
|
config.method = uppercase(config.method);
|
11271
11451
|
config.paramSerializer = isString(config.paramSerializer) ?
|
11272
|
-
|
11273
|
-
|
11274
|
-
var serverRequest = function(config) {
|
11275
|
-
var headers = config.headers;
|
11276
|
-
var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);
|
11452
|
+
$injector.get(config.paramSerializer) : config.paramSerializer;
|
11277
11453
|
|
11278
|
-
|
11279
|
-
|
11280
|
-
forEach(headers, function(value, header) {
|
11281
|
-
if (lowercase(header) === 'content-type') {
|
11282
|
-
delete headers[header];
|
11283
|
-
}
|
11284
|
-
});
|
11285
|
-
}
|
11286
|
-
|
11287
|
-
if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
|
11288
|
-
config.withCredentials = defaults.withCredentials;
|
11289
|
-
}
|
11290
|
-
|
11291
|
-
// send request
|
11292
|
-
return sendReq(config, reqData).then(transformResponse, transformResponse);
|
11293
|
-
};
|
11294
|
-
|
11295
|
-
var chain = [serverRequest, undefined];
|
11454
|
+
var requestInterceptors = [];
|
11455
|
+
var responseInterceptors = [];
|
11296
11456
|
var promise = $q.when(config);
|
11297
11457
|
|
11298
11458
|
// apply interceptors
|
11299
11459
|
forEach(reversedInterceptors, function(interceptor) {
|
11300
11460
|
if (interceptor.request || interceptor.requestError) {
|
11301
|
-
|
11461
|
+
requestInterceptors.unshift(interceptor.request, interceptor.requestError);
|
11302
11462
|
}
|
11303
11463
|
if (interceptor.response || interceptor.responseError) {
|
11304
|
-
|
11464
|
+
responseInterceptors.push(interceptor.response, interceptor.responseError);
|
11305
11465
|
}
|
11306
11466
|
});
|
11307
11467
|
|
11308
|
-
|
11309
|
-
|
11310
|
-
|
11311
|
-
|
11312
|
-
promise = promise.then(thenFn, rejectFn);
|
11313
|
-
}
|
11468
|
+
promise = chainInterceptors(promise, requestInterceptors);
|
11469
|
+
promise = promise.then(serverRequest);
|
11470
|
+
promise = chainInterceptors(promise, responseInterceptors);
|
11314
11471
|
|
11315
11472
|
if (useLegacyPromise) {
|
11316
11473
|
promise.success = function(fn) {
|
@@ -11337,14 +11494,18 @@ function $HttpProvider() {
|
|
11337
11494
|
|
11338
11495
|
return promise;
|
11339
11496
|
|
11340
|
-
|
11341
|
-
|
11342
|
-
var
|
11343
|
-
|
11344
|
-
|
11345
|
-
|
11346
|
-
|
11347
|
-
|
11497
|
+
|
11498
|
+
function chainInterceptors(promise, interceptors) {
|
11499
|
+
for (var i = 0, ii = interceptors.length; i < ii;) {
|
11500
|
+
var thenFn = interceptors[i++];
|
11501
|
+
var rejectFn = interceptors[i++];
|
11502
|
+
|
11503
|
+
promise = promise.then(thenFn, rejectFn);
|
11504
|
+
}
|
11505
|
+
|
11506
|
+
interceptors.length = 0;
|
11507
|
+
|
11508
|
+
return promise;
|
11348
11509
|
}
|
11349
11510
|
|
11350
11511
|
function executeHeaderFns(headers, config) {
|
@@ -11388,6 +11549,37 @@ function $HttpProvider() {
|
|
11388
11549
|
// execute if header value is a function for merged headers
|
11389
11550
|
return executeHeaderFns(reqHeaders, shallowCopy(config));
|
11390
11551
|
}
|
11552
|
+
|
11553
|
+
function serverRequest(config) {
|
11554
|
+
var headers = config.headers;
|
11555
|
+
var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);
|
11556
|
+
|
11557
|
+
// strip content-type if data is undefined
|
11558
|
+
if (isUndefined(reqData)) {
|
11559
|
+
forEach(headers, function(value, header) {
|
11560
|
+
if (lowercase(header) === 'content-type') {
|
11561
|
+
delete headers[header];
|
11562
|
+
}
|
11563
|
+
});
|
11564
|
+
}
|
11565
|
+
|
11566
|
+
if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
|
11567
|
+
config.withCredentials = defaults.withCredentials;
|
11568
|
+
}
|
11569
|
+
|
11570
|
+
// send request
|
11571
|
+
return sendReq(config, reqData).then(transformResponse, transformResponse);
|
11572
|
+
}
|
11573
|
+
|
11574
|
+
function transformResponse(response) {
|
11575
|
+
// make a copy since the response must be cacheable
|
11576
|
+
var resp = extend({}, response);
|
11577
|
+
resp.data = transformData(response.data, response.headers, response.status,
|
11578
|
+
config.transformResponse);
|
11579
|
+
return (isSuccess(response.status))
|
11580
|
+
? resp
|
11581
|
+
: $q.reject(resp);
|
11582
|
+
}
|
11391
11583
|
}
|
11392
11584
|
|
11393
11585
|
$http.pendingRequests = [];
|
@@ -11434,6 +11626,8 @@ function $HttpProvider() {
|
|
11434
11626
|
*
|
11435
11627
|
* @description
|
11436
11628
|
* Shortcut method to perform `JSONP` request.
|
11629
|
+
* If you would like to customise where and how the callbacks are stored then try overriding
|
11630
|
+
* or decorating the {@link $jsonpCallbacks} service.
|
11437
11631
|
*
|
11438
11632
|
* @param {string} url Relative or absolute URL specifying the destination of the request.
|
11439
11633
|
* The name of the callback should be the string `JSON_CALLBACK`.
|
@@ -11707,7 +11901,7 @@ function $xhrFactoryProvider() {
|
|
11707
11901
|
/**
|
11708
11902
|
* @ngdoc service
|
11709
11903
|
* @name $httpBackend
|
11710
|
-
* @requires $
|
11904
|
+
* @requires $jsonpCallbacks
|
11711
11905
|
* @requires $document
|
11712
11906
|
* @requires $xhrFactory
|
11713
11907
|
*
|
@@ -11722,8 +11916,8 @@ function $xhrFactoryProvider() {
|
|
11722
11916
|
* $httpBackend} which can be trained with responses.
|
11723
11917
|
*/
|
11724
11918
|
function $HttpBackendProvider() {
|
11725
|
-
this.$get = ['$browser', '$
|
11726
|
-
return createHttpBackend($browser, $xhrFactory, $browser.defer, $
|
11919
|
+
this.$get = ['$browser', '$jsonpCallbacks', '$document', '$xhrFactory', function($browser, $jsonpCallbacks, $document, $xhrFactory) {
|
11920
|
+
return createHttpBackend($browser, $xhrFactory, $browser.defer, $jsonpCallbacks, $document[0]);
|
11727
11921
|
}];
|
11728
11922
|
}
|
11729
11923
|
|
@@ -11733,17 +11927,13 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
|
|
11733
11927
|
$browser.$$incOutstandingRequestCount();
|
11734
11928
|
url = url || $browser.url();
|
11735
11929
|
|
11736
|
-
if (lowercase(method)
|
11737
|
-
var
|
11738
|
-
|
11739
|
-
|
11740
|
-
|
11741
|
-
|
11742
|
-
|
11743
|
-
var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
|
11744
|
-
callbackId, function(status, text) {
|
11745
|
-
completeRequest(callback, status, callbacks[callbackId].data, "", text);
|
11746
|
-
callbacks[callbackId] = noop;
|
11930
|
+
if (lowercase(method) === 'jsonp') {
|
11931
|
+
var callbackPath = callbacks.createCallback(url);
|
11932
|
+
var jsonpDone = jsonpReq(url, callbackPath, function(status, text) {
|
11933
|
+
// jsonpReq only ever sets status to 200 (OK), 404 (ERROR) or -1 (WAITING)
|
11934
|
+
var response = (status === 200) && callbacks.getResponse(callbackPath);
|
11935
|
+
completeRequest(callback, status, response, "", text);
|
11936
|
+
callbacks.removeCallback(callbackPath);
|
11747
11937
|
});
|
11748
11938
|
} else {
|
11749
11939
|
|
@@ -11845,7 +12035,8 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
|
|
11845
12035
|
}
|
11846
12036
|
};
|
11847
12037
|
|
11848
|
-
function jsonpReq(url,
|
12038
|
+
function jsonpReq(url, callbackPath, done) {
|
12039
|
+
url = url.replace('JSON_CALLBACK', callbackPath);
|
11849
12040
|
// we can't use jQuery/jqLite here because jQuery does crazy stuff with script elements, e.g.:
|
11850
12041
|
// - fetches local scripts via XHR and evals them
|
11851
12042
|
// - adds and immediately removes script elements from the document
|
@@ -11863,7 +12054,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
|
|
11863
12054
|
var text = "unknown";
|
11864
12055
|
|
11865
12056
|
if (event) {
|
11866
|
-
if (event.type === "load" && !callbacks
|
12057
|
+
if (event.type === "load" && !callbacks.wasCalled(callbackPath)) {
|
11867
12058
|
event = { type: "error" };
|
11868
12059
|
}
|
11869
12060
|
text = event.type;
|
@@ -12062,7 +12253,7 @@ function $InterpolateProvider() {
|
|
12062
12253
|
*
|
12063
12254
|
* `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
|
12064
12255
|
*
|
12065
|
-
* ####Escaped Interpolation
|
12256
|
+
* #### Escaped Interpolation
|
12066
12257
|
* $interpolate provides a mechanism for escaping interpolation markers. Start and end markers
|
12067
12258
|
* can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).
|
12068
12259
|
* It will be rendered as a regular start/end marker, and will not be interpreted as an expression
|
@@ -12485,6 +12676,87 @@ function $IntervalProvider() {
|
|
12485
12676
|
}];
|
12486
12677
|
}
|
12487
12678
|
|
12679
|
+
/**
|
12680
|
+
* @ngdoc service
|
12681
|
+
* @name $jsonpCallbacks
|
12682
|
+
* @requires $window
|
12683
|
+
* @description
|
12684
|
+
* This service handles the lifecycle of callbacks to handle JSONP requests.
|
12685
|
+
* Override this service if you wish to customise where the callbacks are stored and
|
12686
|
+
* how they vary compared to the requested url.
|
12687
|
+
*/
|
12688
|
+
var $jsonpCallbacksProvider = function() {
|
12689
|
+
this.$get = ['$window', function($window) {
|
12690
|
+
var callbacks = $window.angular.callbacks;
|
12691
|
+
var callbackMap = {};
|
12692
|
+
|
12693
|
+
function createCallback(callbackId) {
|
12694
|
+
var callback = function(data) {
|
12695
|
+
callback.data = data;
|
12696
|
+
callback.called = true;
|
12697
|
+
};
|
12698
|
+
callback.id = callbackId;
|
12699
|
+
return callback;
|
12700
|
+
}
|
12701
|
+
|
12702
|
+
return {
|
12703
|
+
/**
|
12704
|
+
* @ngdoc method
|
12705
|
+
* @name $jsonpCallbacks#createCallback
|
12706
|
+
* @param {string} url the url of the JSONP request
|
12707
|
+
* @returns {string} the callback path to send to the server as part of the JSONP request
|
12708
|
+
* @description
|
12709
|
+
* {@link $httpBackend} calls this method to create a callback and get hold of the path to the callback
|
12710
|
+
* to pass to the server, which will be used to call the callback with its payload in the JSONP response.
|
12711
|
+
*/
|
12712
|
+
createCallback: function(url) {
|
12713
|
+
var callbackId = '_' + (callbacks.$$counter++).toString(36);
|
12714
|
+
var callbackPath = 'angular.callbacks.' + callbackId;
|
12715
|
+
var callback = createCallback(callbackId);
|
12716
|
+
callbackMap[callbackPath] = callbacks[callbackId] = callback;
|
12717
|
+
return callbackPath;
|
12718
|
+
},
|
12719
|
+
/**
|
12720
|
+
* @ngdoc method
|
12721
|
+
* @name $jsonpCallbacks#wasCalled
|
12722
|
+
* @param {string} callbackPath the path to the callback that was sent in the JSONP request
|
12723
|
+
* @returns {boolean} whether the callback has been called, as a result of the JSONP response
|
12724
|
+
* @description
|
12725
|
+
* {@link $httpBackend} calls this method to find out whether the JSONP response actually called the
|
12726
|
+
* callback that was passed in the request.
|
12727
|
+
*/
|
12728
|
+
wasCalled: function(callbackPath) {
|
12729
|
+
return callbackMap[callbackPath].called;
|
12730
|
+
},
|
12731
|
+
/**
|
12732
|
+
* @ngdoc method
|
12733
|
+
* @name $jsonpCallbacks#getResponse
|
12734
|
+
* @param {string} callbackPath the path to the callback that was sent in the JSONP request
|
12735
|
+
* @returns {*} the data received from the response via the registered callback
|
12736
|
+
* @description
|
12737
|
+
* {@link $httpBackend} calls this method to get hold of the data that was provided to the callback
|
12738
|
+
* in the JSONP response.
|
12739
|
+
*/
|
12740
|
+
getResponse: function(callbackPath) {
|
12741
|
+
return callbackMap[callbackPath].data;
|
12742
|
+
},
|
12743
|
+
/**
|
12744
|
+
* @ngdoc method
|
12745
|
+
* @name $jsonpCallbacks#removeCallback
|
12746
|
+
* @param {string} callbackPath the path to the callback that was sent in the JSONP request
|
12747
|
+
* @description
|
12748
|
+
* {@link $httpBackend} calls this method to remove the callback after the JSONP request has
|
12749
|
+
* completed or timed-out.
|
12750
|
+
*/
|
12751
|
+
removeCallback: function(callbackPath) {
|
12752
|
+
var callback = callbackMap[callbackPath];
|
12753
|
+
delete callbacks[callback.id];
|
12754
|
+
delete callbackMap[callbackPath];
|
12755
|
+
}
|
12756
|
+
};
|
12757
|
+
}];
|
12758
|
+
};
|
12759
|
+
|
12488
12760
|
/**
|
12489
12761
|
* @ngdoc service
|
12490
12762
|
* @name $locale
|
@@ -12824,6 +13096,12 @@ function LocationHashbangInHtml5Url(appBase, appBaseNoFile, hashPrefix) {
|
|
12824
13096
|
|
12825
13097
|
var locationPrototype = {
|
12826
13098
|
|
13099
|
+
/**
|
13100
|
+
* Ensure absolute url is initialized.
|
13101
|
+
* @private
|
13102
|
+
*/
|
13103
|
+
$$absUrl:'',
|
13104
|
+
|
12827
13105
|
/**
|
12828
13106
|
* Are we in html5 mode?
|
12829
13107
|
* @private
|
@@ -14197,7 +14475,7 @@ AST.prototype = {
|
|
14197
14475
|
var args = [];
|
14198
14476
|
if (this.peekToken().text !== ')') {
|
14199
14477
|
do {
|
14200
|
-
args.push(this.
|
14478
|
+
args.push(this.filterChain());
|
14201
14479
|
} while (this.expect(','));
|
14202
14480
|
}
|
14203
14481
|
return args;
|
@@ -15924,7 +16202,7 @@ function $ParseProvider() {
|
|
15924
16202
|
*
|
15925
16203
|
* **Methods**
|
15926
16204
|
*
|
15927
|
-
* - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
|
16205
|
+
* - `then(successCallback, [errorCallback], [notifyCallback])` – regardless of when the promise was or
|
15928
16206
|
* will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
|
15929
16207
|
* as soon as the result is available. The callbacks are called with a single argument: the result
|
15930
16208
|
* or rejection reason. Additionally, the notify callback may be called zero or more times to
|
@@ -15935,7 +16213,8 @@ function $ParseProvider() {
|
|
15935
16213
|
* with the value which is resolved in that promise using
|
15936
16214
|
* [promise chaining](http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promises-queues)).
|
15937
16215
|
* It also notifies via the return value of the `notifyCallback` method. The promise cannot be
|
15938
|
-
* resolved or rejected from the notifyCallback method.
|
16216
|
+
* resolved or rejected from the notifyCallback method. The errorCallback and notifyCallback
|
16217
|
+
* arguments are optional.
|
15939
16218
|
*
|
15940
16219
|
* - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
|
15941
16220
|
*
|
@@ -16350,6 +16629,30 @@ function qFactory(nextTick, exceptionHandler) {
|
|
16350
16629
|
return deferred.promise;
|
16351
16630
|
}
|
16352
16631
|
|
16632
|
+
/**
|
16633
|
+
* @ngdoc method
|
16634
|
+
* @name $q#race
|
16635
|
+
* @kind function
|
16636
|
+
*
|
16637
|
+
* @description
|
16638
|
+
* Returns a promise that resolves or rejects as soon as one of those promises
|
16639
|
+
* resolves or rejects, with the value or reason from that promise.
|
16640
|
+
*
|
16641
|
+
* @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
|
16642
|
+
* @returns {Promise} a promise that resolves or rejects as soon as one of the `promises`
|
16643
|
+
* resolves or rejects, with the value or reason from that promise.
|
16644
|
+
*/
|
16645
|
+
|
16646
|
+
function race(promises) {
|
16647
|
+
var deferred = defer();
|
16648
|
+
|
16649
|
+
forEach(promises, function(promise) {
|
16650
|
+
when(promise).then(deferred.resolve, deferred.reject);
|
16651
|
+
});
|
16652
|
+
|
16653
|
+
return deferred.promise;
|
16654
|
+
}
|
16655
|
+
|
16353
16656
|
var $Q = function Q(resolver) {
|
16354
16657
|
if (!isFunction(resolver)) {
|
16355
16658
|
throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
|
@@ -16379,6 +16682,7 @@ function qFactory(nextTick, exceptionHandler) {
|
|
16379
16682
|
$Q.when = when;
|
16380
16683
|
$Q.resolve = resolve;
|
16381
16684
|
$Q.all = all;
|
16685
|
+
$Q.race = race;
|
16382
16686
|
|
16383
16687
|
return $Q;
|
16384
16688
|
}
|
@@ -19730,10 +20034,11 @@ function $FilterProvider($provide) {
|
|
19730
20034
|
* - `Object`: A pattern object can be used to filter specific properties on objects contained
|
19731
20035
|
* by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
|
19732
20036
|
* which have property `name` containing "M" and property `phone` containing "1". A special
|
19733
|
-
* property name `$` can be used (as in `{$:"text"}`) to accept a match
|
19734
|
-
* property of the object or its nested object properties. That's equivalent to the
|
19735
|
-
* substring match with a `string` as described above. The
|
19736
|
-
* the
|
20037
|
+
* property name (`$` by default) can be used (e.g. as in `{$: "text"}`) to accept a match
|
20038
|
+
* against any property of the object or its nested object properties. That's equivalent to the
|
20039
|
+
* simple substring match with a `string` as described above. The special property name can be
|
20040
|
+
* overwritten, using the `anyPropertyKey` parameter.
|
20041
|
+
* The predicate can be negated by prefixing the string with `!`.
|
19737
20042
|
* For example `{name: "!M"}` predicate will return an array of items which have property `name`
|
19738
20043
|
* not containing "M".
|
19739
20044
|
*
|
@@ -19767,6 +20072,9 @@ function $FilterProvider($provide) {
|
|
19767
20072
|
* Primitive values are converted to strings. Objects are not compared against primitives,
|
19768
20073
|
* unless they have a custom `toString` method (e.g. `Date` objects).
|
19769
20074
|
*
|
20075
|
+
* @param {string=} anyPropertyKey The special property name that matches against any property.
|
20076
|
+
* By default `$`.
|
20077
|
+
*
|
19770
20078
|
* @example
|
19771
20079
|
<example>
|
19772
20080
|
<file name="index.html">
|
@@ -19835,8 +20143,9 @@ function $FilterProvider($provide) {
|
|
19835
20143
|
</file>
|
19836
20144
|
</example>
|
19837
20145
|
*/
|
20146
|
+
|
19838
20147
|
function filterFilter() {
|
19839
|
-
return function(array, expression, comparator) {
|
20148
|
+
return function(array, expression, comparator, anyPropertyKey) {
|
19840
20149
|
if (!isArrayLike(array)) {
|
19841
20150
|
if (array == null) {
|
19842
20151
|
return array;
|
@@ -19845,6 +20154,7 @@ function filterFilter() {
|
|
19845
20154
|
}
|
19846
20155
|
}
|
19847
20156
|
|
20157
|
+
anyPropertyKey = anyPropertyKey || '$';
|
19848
20158
|
var expressionType = getTypeForFilter(expression);
|
19849
20159
|
var predicateFn;
|
19850
20160
|
var matchAgainstAnyProp;
|
@@ -19861,7 +20171,7 @@ function filterFilter() {
|
|
19861
20171
|
//jshint -W086
|
19862
20172
|
case 'object':
|
19863
20173
|
//jshint +W086
|
19864
|
-
predicateFn = createPredicateFn(expression, comparator, matchAgainstAnyProp);
|
20174
|
+
predicateFn = createPredicateFn(expression, comparator, anyPropertyKey, matchAgainstAnyProp);
|
19865
20175
|
break;
|
19866
20176
|
default:
|
19867
20177
|
return array;
|
@@ -19872,8 +20182,8 @@ function filterFilter() {
|
|
19872
20182
|
}
|
19873
20183
|
|
19874
20184
|
// Helper functions for `filterFilter`
|
19875
|
-
function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
|
19876
|
-
var shouldMatchPrimitives = isObject(expression) && (
|
20185
|
+
function createPredicateFn(expression, comparator, anyPropertyKey, matchAgainstAnyProp) {
|
20186
|
+
var shouldMatchPrimitives = isObject(expression) && (anyPropertyKey in expression);
|
19877
20187
|
var predicateFn;
|
19878
20188
|
|
19879
20189
|
if (comparator === true) {
|
@@ -19901,25 +20211,25 @@ function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
|
|
19901
20211
|
|
19902
20212
|
predicateFn = function(item) {
|
19903
20213
|
if (shouldMatchPrimitives && !isObject(item)) {
|
19904
|
-
return deepCompare(item, expression
|
20214
|
+
return deepCompare(item, expression[anyPropertyKey], comparator, anyPropertyKey, false);
|
19905
20215
|
}
|
19906
|
-
return deepCompare(item, expression, comparator, matchAgainstAnyProp);
|
20216
|
+
return deepCompare(item, expression, comparator, anyPropertyKey, matchAgainstAnyProp);
|
19907
20217
|
};
|
19908
20218
|
|
19909
20219
|
return predicateFn;
|
19910
20220
|
}
|
19911
20221
|
|
19912
|
-
function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatchWholeObject) {
|
20222
|
+
function deepCompare(actual, expected, comparator, anyPropertyKey, matchAgainstAnyProp, dontMatchWholeObject) {
|
19913
20223
|
var actualType = getTypeForFilter(actual);
|
19914
20224
|
var expectedType = getTypeForFilter(expected);
|
19915
20225
|
|
19916
20226
|
if ((expectedType === 'string') && (expected.charAt(0) === '!')) {
|
19917
|
-
return !deepCompare(actual, expected.substring(1), comparator, matchAgainstAnyProp);
|
20227
|
+
return !deepCompare(actual, expected.substring(1), comparator, anyPropertyKey, matchAgainstAnyProp);
|
19918
20228
|
} else if (isArray(actual)) {
|
19919
20229
|
// In case `actual` is an array, consider it a match
|
19920
20230
|
// if ANY of it's items matches `expected`
|
19921
20231
|
return actual.some(function(item) {
|
19922
|
-
return deepCompare(item, expected, comparator, matchAgainstAnyProp);
|
20232
|
+
return deepCompare(item, expected, comparator, anyPropertyKey, matchAgainstAnyProp);
|
19923
20233
|
});
|
19924
20234
|
}
|
19925
20235
|
|
@@ -19928,11 +20238,11 @@ function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatc
|
|
19928
20238
|
var key;
|
19929
20239
|
if (matchAgainstAnyProp) {
|
19930
20240
|
for (key in actual) {
|
19931
|
-
if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, true)) {
|
20241
|
+
if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, anyPropertyKey, true)) {
|
19932
20242
|
return true;
|
19933
20243
|
}
|
19934
20244
|
}
|
19935
|
-
return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, false);
|
20245
|
+
return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, anyPropertyKey, false);
|
19936
20246
|
} else if (expectedType === 'object') {
|
19937
20247
|
for (key in expected) {
|
19938
20248
|
var expectedVal = expected[key];
|
@@ -19940,9 +20250,9 @@ function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatc
|
|
19940
20250
|
continue;
|
19941
20251
|
}
|
19942
20252
|
|
19943
|
-
var matchAnyProperty = key ===
|
20253
|
+
var matchAnyProperty = key === anyPropertyKey;
|
19944
20254
|
var actualVal = matchAnyProperty ? actual : actual[key];
|
19945
|
-
if (!deepCompare(actualVal, expectedVal, comparator, matchAnyProperty, matchAnyProperty)) {
|
20255
|
+
if (!deepCompare(actualVal, expectedVal, comparator, anyPropertyKey, matchAnyProperty, matchAnyProperty)) {
|
19946
20256
|
return false;
|
19947
20257
|
}
|
19948
20258
|
}
|
@@ -20680,21 +20990,22 @@ var uppercaseFilter = valueFn(uppercase);
|
|
20680
20990
|
* @kind function
|
20681
20991
|
*
|
20682
20992
|
* @description
|
20683
|
-
* Creates a new array or string containing only a specified number of elements. The elements
|
20684
|
-
*
|
20685
|
-
* the value and sign (positive or negative) of `limit`.
|
20686
|
-
*
|
20687
|
-
*
|
20688
|
-
*
|
20689
|
-
* @param {string|number}
|
20993
|
+
* Creates a new array or string containing only a specified number of elements. The elements are
|
20994
|
+
* taken from either the beginning or the end of the source array, string or number, as specified by
|
20995
|
+
* the value and sign (positive or negative) of `limit`. Other array-like objects are also supported
|
20996
|
+
* (e.g. array subclasses, NodeLists, jqLite/jQuery collections etc). If a number is used as input,
|
20997
|
+
* it is converted to a string.
|
20998
|
+
*
|
20999
|
+
* @param {Array|ArrayLike|string|number} input - Array/array-like, string or number to be limited.
|
21000
|
+
* @param {string|number} limit - The length of the returned array or string. If the `limit` number
|
20690
21001
|
* is positive, `limit` number of items from the beginning of the source array/string are copied.
|
20691
21002
|
* If the number is negative, `limit` number of items from the end of the source array/string
|
20692
21003
|
* are copied. The `limit` will be trimmed if it exceeds `array.length`. If `limit` is undefined,
|
20693
21004
|
* the input will be returned unchanged.
|
20694
|
-
* @param {(string|number)=} begin Index at which to begin limitation. As a negative index,
|
20695
|
-
* indicates an offset from the end of `input`. Defaults to `0`.
|
20696
|
-
* @returns {Array|string} A new sub-array or substring of length `limit` or less if input
|
20697
|
-
*
|
21005
|
+
* @param {(string|number)=} begin - Index at which to begin limitation. As a negative index,
|
21006
|
+
* `begin` indicates an offset from the end of `input`. Defaults to `0`.
|
21007
|
+
* @returns {Array|string} A new sub-array or substring of length `limit` or less if the input had
|
21008
|
+
* less than `limit` elements.
|
20698
21009
|
*
|
20699
21010
|
* @example
|
20700
21011
|
<example module="limitToExample">
|
@@ -20782,67 +21093,157 @@ function limitToFilter() {
|
|
20782
21093
|
if (isNaN(limit)) return input;
|
20783
21094
|
|
20784
21095
|
if (isNumber(input)) input = input.toString();
|
20785
|
-
if (!
|
21096
|
+
if (!isArrayLike(input)) return input;
|
20786
21097
|
|
20787
21098
|
begin = (!begin || isNaN(begin)) ? 0 : toInt(begin);
|
20788
21099
|
begin = (begin < 0) ? Math.max(0, input.length + begin) : begin;
|
20789
21100
|
|
20790
21101
|
if (limit >= 0) {
|
20791
|
-
return input
|
21102
|
+
return sliceFn(input, begin, begin + limit);
|
20792
21103
|
} else {
|
20793
21104
|
if (begin === 0) {
|
20794
|
-
return input
|
21105
|
+
return sliceFn(input, limit, input.length);
|
20795
21106
|
} else {
|
20796
|
-
return input
|
21107
|
+
return sliceFn(input, Math.max(0, begin + limit), begin);
|
20797
21108
|
}
|
20798
21109
|
}
|
20799
21110
|
};
|
20800
21111
|
}
|
20801
21112
|
|
21113
|
+
function sliceFn(input, begin, end) {
|
21114
|
+
if (isString(input)) return input.slice(begin, end);
|
21115
|
+
|
21116
|
+
return slice.call(input, begin, end);
|
21117
|
+
}
|
21118
|
+
|
20802
21119
|
/**
|
20803
21120
|
* @ngdoc filter
|
20804
21121
|
* @name orderBy
|
20805
21122
|
* @kind function
|
20806
21123
|
*
|
20807
21124
|
* @description
|
20808
|
-
*
|
20809
|
-
*
|
20810
|
-
*
|
20811
|
-
*
|
21125
|
+
* Returns an array containing the items from the specified `collection`, ordered by a `comparator`
|
21126
|
+
* function based on the values computed using the `expression` predicate.
|
21127
|
+
*
|
21128
|
+
* For example, `[{id: 'foo'}, {id: 'bar'}] | orderBy:'id'` would result in
|
21129
|
+
* `[{id: 'bar'}, {id: 'foo'}]`.
|
21130
|
+
*
|
21131
|
+
* The `collection` can be an Array or array-like object (e.g. NodeList, jQuery object, TypedArray,
|
21132
|
+
* String, etc).
|
21133
|
+
*
|
21134
|
+
* The `expression` can be a single predicate, or a list of predicates each serving as a tie-breaker
|
21135
|
+
* for the preceeding one. The `expression` is evaluated against each item and the output is used
|
21136
|
+
* for comparing with other items.
|
21137
|
+
*
|
21138
|
+
* You can change the sorting order by setting `reverse` to `true`. By default, items are sorted in
|
21139
|
+
* ascending order.
|
21140
|
+
*
|
21141
|
+
* The comparison is done using the `comparator` function. If none is specified, a default, built-in
|
21142
|
+
* comparator is used (see below for details - in a nutshell, it compares numbers numerically and
|
21143
|
+
* strings alphabetically).
|
21144
|
+
*
|
21145
|
+
* ### Under the hood
|
20812
21146
|
*
|
20813
|
-
*
|
20814
|
-
*
|
20815
|
-
*
|
21147
|
+
* Ordering the specified `collection` happens in two phases:
|
21148
|
+
*
|
21149
|
+
* 1. All items are passed through the predicate (or predicates), and the returned values are saved
|
21150
|
+
* along with their type (`string`, `number` etc). For example, an item `{label: 'foo'}`, passed
|
21151
|
+
* through a predicate that extracts the value of the `label` property, would be transformed to:
|
21152
|
+
* ```
|
21153
|
+
* {
|
21154
|
+
* value: 'foo',
|
21155
|
+
* type: 'string',
|
21156
|
+
* index: ...
|
21157
|
+
* }
|
21158
|
+
* ```
|
21159
|
+
* 2. The comparator function is used to sort the items, based on the derived values, types and
|
21160
|
+
* indices.
|
21161
|
+
*
|
21162
|
+
* If you use a custom comparator, it will be called with pairs of objects of the form
|
21163
|
+
* `{value: ..., type: '...', index: ...}` and is expected to return `0` if the objects are equal
|
21164
|
+
* (as far as the comparator is concerned), `-1` if the 1st one should be ranked higher than the
|
21165
|
+
* second, or `1` otherwise.
|
21166
|
+
*
|
21167
|
+
* In order to ensure that the sorting will be deterministic across platforms, if none of the
|
21168
|
+
* specified predicates can distinguish between two items, `orderBy` will automatically introduce a
|
21169
|
+
* dummy predicate that returns the item's index as `value`.
|
21170
|
+
* (If you are using a custom comparator, make sure it can handle this predicate as well.)
|
21171
|
+
*
|
21172
|
+
* Finally, in an attempt to simplify things, if a predicate returns an object as the extracted
|
21173
|
+
* value for an item, `orderBy` will try to convert that object to a primitive value, before passing
|
21174
|
+
* it to the comparator. The following rules govern the conversion:
|
21175
|
+
*
|
21176
|
+
* 1. If the object has a `valueOf()` method that returns a primitive, its return value will be
|
21177
|
+
* used instead.<br />
|
21178
|
+
* (If the object has a `valueOf()` method that returns another object, then the returned object
|
21179
|
+
* will be used in subsequent steps.)
|
21180
|
+
* 2. If the object has a custom `toString()` method (i.e. not the one inherited from `Object`) that
|
21181
|
+
* returns a primitive, its return value will be used instead.<br />
|
21182
|
+
* (If the object has a `toString()` method that returns another object, then the returned object
|
21183
|
+
* will be used in subsequent steps.)
|
21184
|
+
* 3. No conversion; the object itself is used.
|
21185
|
+
*
|
21186
|
+
* ### The default comparator
|
21187
|
+
*
|
21188
|
+
* The default, built-in comparator should be sufficient for most usecases. In short, it compares
|
21189
|
+
* numbers numerically, strings alphabetically (and case-insensitively), for objects falls back to
|
21190
|
+
* using their index in the original collection, and sorts values of different types by type.
|
21191
|
+
*
|
21192
|
+
* More specifically, it follows these steps to determine the relative order of items:
|
21193
|
+
*
|
21194
|
+
* 1. If the compared values are of different types, compare the types themselves alphabetically.
|
21195
|
+
* 2. If both values are of type `string`, compare them alphabetically in a case- and
|
21196
|
+
* locale-insensitive way.
|
21197
|
+
* 3. If both values are objects, compare their indices instead.
|
21198
|
+
* 4. Otherwise, return:
|
21199
|
+
* - `0`, if the values are equal (by strict equality comparison, i.e. using `===`).
|
21200
|
+
* - `-1`, if the 1st value is "less than" the 2nd value (compared using the `<` operator).
|
21201
|
+
* - `1`, otherwise.
|
21202
|
+
*
|
21203
|
+
* **Note:** If you notice numbers not being sorted as expected, make sure they are actually being
|
21204
|
+
* saved as numbers and not strings.
|
21205
|
+
*
|
21206
|
+
* @param {Array|ArrayLike} collection - The collection (array or array-like object) to sort.
|
21207
|
+
* @param {(Function|string|Array.<Function|string>)=} expression - A predicate (or list of
|
21208
|
+
* predicates) to be used by the comparator to determine the order of elements.
|
20816
21209
|
*
|
20817
21210
|
* Can be one of:
|
20818
21211
|
*
|
20819
|
-
* - `
|
20820
|
-
*
|
20821
|
-
* - `string`: An Angular expression.
|
20822
|
-
*
|
20823
|
-
*
|
20824
|
-
*
|
20825
|
-
*
|
20826
|
-
*
|
20827
|
-
*
|
20828
|
-
*
|
20829
|
-
*
|
20830
|
-
*
|
21212
|
+
* - `Function`: A getter function. This function will be called with each item as argument and
|
21213
|
+
* the return value will be used for sorting.
|
21214
|
+
* - `string`: An Angular expression. This expression will be evaluated against each item and the
|
21215
|
+
* result will be used for sorting. For example, use `'label'` to sort by a property called
|
21216
|
+
* `label` or `'label.substring(0, 3)'` to sort by the first 3 characters of the `label`
|
21217
|
+
* property.<br />
|
21218
|
+
* (The result of a constant expression is interpreted as a property name to be used for
|
21219
|
+
* comparison. For example, use `'"special name"'` (note the extra pair of quotes) to sort by a
|
21220
|
+
* property called `special name`.)<br />
|
21221
|
+
* An expression can be optionally prefixed with `+` or `-` to control the sorting direction,
|
21222
|
+
* ascending or descending. For example, `'+label'` or `'-label'`. If no property is provided,
|
21223
|
+
* (e.g. `'+'` or `'-'`), the collection element itself is used in comparisons.
|
21224
|
+
* - `Array`: An array of function and/or string predicates. If a predicate cannot determine the
|
21225
|
+
* relative order of two items, the next predicate is used as a tie-breaker.
|
20831
21226
|
*
|
20832
|
-
*
|
21227
|
+
* **Note:** If the predicate is missing or empty then it defaults to `'+'`.
|
20833
21228
|
*
|
20834
|
-
* @param {boolean=} reverse
|
20835
|
-
* @
|
21229
|
+
* @param {boolean=} reverse - If `true`, reverse the sorting order.
|
21230
|
+
* @param {(Function)=} comparator - The comparator function used to determine the relative order of
|
21231
|
+
* value pairs. If omitted, the built-in comparator will be used.
|
21232
|
+
*
|
21233
|
+
* @returns {Array} - The sorted array.
|
20836
21234
|
*
|
20837
21235
|
*
|
20838
21236
|
* @example
|
20839
|
-
*
|
20840
|
-
*
|
20841
|
-
*
|
20842
|
-
|
21237
|
+
* ### Ordering a table with `ngRepeat`
|
21238
|
+
*
|
21239
|
+
* The example below demonstrates a simple {@link ngRepeat ngRepeat}, where the data is sorted by
|
21240
|
+
* age in descending order (expression is set to `'-age'`). The `comparator` is not set, which means
|
21241
|
+
* it defaults to the built-in comparator.
|
21242
|
+
*
|
21243
|
+
<example name="orderBy-static" module="orderByExample1">
|
20843
21244
|
<file name="index.html">
|
20844
21245
|
<div ng-controller="ExampleController">
|
20845
|
-
<table class="
|
21246
|
+
<table class="friends">
|
20846
21247
|
<tr>
|
20847
21248
|
<th>Name</th>
|
20848
21249
|
<th>Phone Number</th>
|
@@ -20857,43 +21258,77 @@ function limitToFilter() {
|
|
20857
21258
|
</div>
|
20858
21259
|
</file>
|
20859
21260
|
<file name="script.js">
|
20860
|
-
angular.module('
|
21261
|
+
angular.module('orderByExample1', [])
|
20861
21262
|
.controller('ExampleController', ['$scope', function($scope) {
|
20862
|
-
$scope.friends =
|
20863
|
-
|
20864
|
-
|
20865
|
-
|
20866
|
-
|
20867
|
-
|
21263
|
+
$scope.friends = [
|
21264
|
+
{name: 'John', phone: '555-1212', age: 10},
|
21265
|
+
{name: 'Mary', phone: '555-9876', age: 19},
|
21266
|
+
{name: 'Mike', phone: '555-4321', age: 21},
|
21267
|
+
{name: 'Adam', phone: '555-5678', age: 35},
|
21268
|
+
{name: 'Julie', phone: '555-8765', age: 29}
|
21269
|
+
];
|
20868
21270
|
}]);
|
20869
21271
|
</file>
|
21272
|
+
<file name="style.css">
|
21273
|
+
.friends {
|
21274
|
+
border-collapse: collapse;
|
21275
|
+
}
|
21276
|
+
|
21277
|
+
.friends th {
|
21278
|
+
border-bottom: 1px solid;
|
21279
|
+
}
|
21280
|
+
.friends td, .friends th {
|
21281
|
+
border-left: 1px solid;
|
21282
|
+
padding: 5px 10px;
|
21283
|
+
}
|
21284
|
+
.friends td:first-child, .friends th:first-child {
|
21285
|
+
border-left: none;
|
21286
|
+
}
|
21287
|
+
</file>
|
21288
|
+
<file name="protractor.js" type="protractor">
|
21289
|
+
// Element locators
|
21290
|
+
var names = element.all(by.repeater('friends').column('friend.name'));
|
21291
|
+
|
21292
|
+
it('should sort friends by age in reverse order', function() {
|
21293
|
+
expect(names.get(0).getText()).toBe('Adam');
|
21294
|
+
expect(names.get(1).getText()).toBe('Julie');
|
21295
|
+
expect(names.get(2).getText()).toBe('Mike');
|
21296
|
+
expect(names.get(3).getText()).toBe('Mary');
|
21297
|
+
expect(names.get(4).getText()).toBe('John');
|
21298
|
+
});
|
21299
|
+
</file>
|
20870
21300
|
</example>
|
21301
|
+
* <hr />
|
20871
21302
|
*
|
20872
|
-
* The predicate and reverse parameters can be controlled dynamically through scope properties,
|
20873
|
-
* as shown in the next example.
|
20874
21303
|
* @example
|
20875
|
-
|
21304
|
+
* ### Changing parameters dynamically
|
21305
|
+
*
|
21306
|
+
* All parameters can be changed dynamically. The next example shows how you can make the columns of
|
21307
|
+
* a table sortable, by binding the `expression` and `reverse` parameters to scope properties.
|
21308
|
+
*
|
21309
|
+
<example name="orderBy-dynamic" module="orderByExample2">
|
20876
21310
|
<file name="index.html">
|
20877
21311
|
<div ng-controller="ExampleController">
|
20878
|
-
<pre>
|
21312
|
+
<pre>Sort by = {{propertyName}}; reverse = {{reverse}}</pre>
|
20879
21313
|
<hr/>
|
20880
|
-
<button ng-click="
|
20881
|
-
<
|
21314
|
+
<button ng-click="propertyName = null; reverse = false">Set to unsorted</button>
|
21315
|
+
<hr/>
|
21316
|
+
<table class="friends">
|
20882
21317
|
<tr>
|
20883
|
-
|
20884
|
-
|
20885
|
-
|
20886
|
-
|
20887
|
-
|
20888
|
-
|
20889
|
-
|
20890
|
-
|
20891
|
-
|
20892
|
-
|
20893
|
-
|
20894
|
-
|
21318
|
+
<th>
|
21319
|
+
<button ng-click="sortBy('name')">Name</button>
|
21320
|
+
<span class="sortorder" ng-show="propertyName === 'name'" ng-class="{reverse: reverse}"></span>
|
21321
|
+
</th>
|
21322
|
+
<th>
|
21323
|
+
<button ng-click="sortBy('phone')">Phone Number</button>
|
21324
|
+
<span class="sortorder" ng-show="propertyName === 'phone'" ng-class="{reverse: reverse}"></span>
|
21325
|
+
</th>
|
21326
|
+
<th>
|
21327
|
+
<button ng-click="sortBy('age')">Age</button>
|
21328
|
+
<span class="sortorder" ng-show="propertyName === 'age'" ng-class="{reverse: reverse}"></span>
|
21329
|
+
</th>
|
20895
21330
|
</tr>
|
20896
|
-
<tr ng-repeat="friend in friends | orderBy:
|
21331
|
+
<tr ng-repeat="friend in friends | orderBy:propertyName:reverse">
|
20897
21332
|
<td>{{friend.name}}</td>
|
20898
21333
|
<td>{{friend.phone}}</td>
|
20899
21334
|
<td>{{friend.age}}</td>
|
@@ -20902,100 +21337,335 @@ function limitToFilter() {
|
|
20902
21337
|
</div>
|
20903
21338
|
</file>
|
20904
21339
|
<file name="script.js">
|
20905
|
-
angular.module('
|
21340
|
+
angular.module('orderByExample2', [])
|
20906
21341
|
.controller('ExampleController', ['$scope', function($scope) {
|
20907
|
-
|
20908
|
-
|
20909
|
-
|
20910
|
-
|
20911
|
-
|
20912
|
-
|
20913
|
-
|
21342
|
+
var friends = [
|
21343
|
+
{name: 'John', phone: '555-1212', age: 10},
|
21344
|
+
{name: 'Mary', phone: '555-9876', age: 19},
|
21345
|
+
{name: 'Mike', phone: '555-4321', age: 21},
|
21346
|
+
{name: 'Adam', phone: '555-5678', age: 35},
|
21347
|
+
{name: 'Julie', phone: '555-8765', age: 29}
|
21348
|
+
];
|
21349
|
+
|
21350
|
+
$scope.propertyName = 'age';
|
20914
21351
|
$scope.reverse = true;
|
20915
|
-
$scope.
|
20916
|
-
|
20917
|
-
|
21352
|
+
$scope.friends = friends;
|
21353
|
+
|
21354
|
+
$scope.sortBy = function(propertyName) {
|
21355
|
+
$scope.reverse = ($scope.propertyName === propertyName) ? !$scope.reverse : false;
|
21356
|
+
$scope.propertyName = propertyName;
|
20918
21357
|
};
|
20919
21358
|
}]);
|
20920
|
-
|
21359
|
+
</file>
|
20921
21360
|
<file name="style.css">
|
21361
|
+
.friends {
|
21362
|
+
border-collapse: collapse;
|
21363
|
+
}
|
21364
|
+
|
21365
|
+
.friends th {
|
21366
|
+
border-bottom: 1px solid;
|
21367
|
+
}
|
21368
|
+
.friends td, .friends th {
|
21369
|
+
border-left: 1px solid;
|
21370
|
+
padding: 5px 10px;
|
21371
|
+
}
|
21372
|
+
.friends td:first-child, .friends th:first-child {
|
21373
|
+
border-left: none;
|
21374
|
+
}
|
21375
|
+
|
20922
21376
|
.sortorder:after {
|
20923
|
-
content: '\25b2';
|
21377
|
+
content: '\25b2'; // BLACK UP-POINTING TRIANGLE
|
20924
21378
|
}
|
20925
21379
|
.sortorder.reverse:after {
|
20926
|
-
content: '\25bc';
|
21380
|
+
content: '\25bc'; // BLACK DOWN-POINTING TRIANGLE
|
20927
21381
|
}
|
20928
21382
|
</file>
|
21383
|
+
<file name="protractor.js" type="protractor">
|
21384
|
+
// Element locators
|
21385
|
+
var unsortButton = element(by.partialButtonText('unsorted'));
|
21386
|
+
var nameHeader = element(by.partialButtonText('Name'));
|
21387
|
+
var phoneHeader = element(by.partialButtonText('Phone'));
|
21388
|
+
var ageHeader = element(by.partialButtonText('Age'));
|
21389
|
+
var firstName = element(by.repeater('friends').column('friend.name').row(0));
|
21390
|
+
var lastName = element(by.repeater('friends').column('friend.name').row(4));
|
21391
|
+
|
21392
|
+
it('should sort friends by some property, when clicking on the column header', function() {
|
21393
|
+
expect(firstName.getText()).toBe('Adam');
|
21394
|
+
expect(lastName.getText()).toBe('John');
|
21395
|
+
|
21396
|
+
phoneHeader.click();
|
21397
|
+
expect(firstName.getText()).toBe('John');
|
21398
|
+
expect(lastName.getText()).toBe('Mary');
|
21399
|
+
|
21400
|
+
nameHeader.click();
|
21401
|
+
expect(firstName.getText()).toBe('Adam');
|
21402
|
+
expect(lastName.getText()).toBe('Mike');
|
21403
|
+
|
21404
|
+
ageHeader.click();
|
21405
|
+
expect(firstName.getText()).toBe('John');
|
21406
|
+
expect(lastName.getText()).toBe('Adam');
|
21407
|
+
});
|
21408
|
+
|
21409
|
+
it('should sort friends in reverse order, when clicking on the same column', function() {
|
21410
|
+
expect(firstName.getText()).toBe('Adam');
|
21411
|
+
expect(lastName.getText()).toBe('John');
|
21412
|
+
|
21413
|
+
ageHeader.click();
|
21414
|
+
expect(firstName.getText()).toBe('John');
|
21415
|
+
expect(lastName.getText()).toBe('Adam');
|
21416
|
+
|
21417
|
+
ageHeader.click();
|
21418
|
+
expect(firstName.getText()).toBe('Adam');
|
21419
|
+
expect(lastName.getText()).toBe('John');
|
21420
|
+
});
|
21421
|
+
|
21422
|
+
it('should restore the original order, when clicking "Set to unsorted"', function() {
|
21423
|
+
expect(firstName.getText()).toBe('Adam');
|
21424
|
+
expect(lastName.getText()).toBe('John');
|
21425
|
+
|
21426
|
+
unsortButton.click();
|
21427
|
+
expect(firstName.getText()).toBe('John');
|
21428
|
+
expect(lastName.getText()).toBe('Julie');
|
21429
|
+
});
|
21430
|
+
</file>
|
20929
21431
|
</example>
|
21432
|
+
* <hr />
|
20930
21433
|
*
|
20931
|
-
*
|
20932
|
-
*
|
20933
|
-
* desired parameters.
|
21434
|
+
* @example
|
21435
|
+
* ### Using `orderBy` inside a controller
|
20934
21436
|
*
|
20935
|
-
*
|
21437
|
+
* It is also possible to call the `orderBy` filter manually, by injecting `orderByFilter`, and
|
21438
|
+
* calling it with the desired parameters. (Alternatively, you could inject the `$filter` factory
|
21439
|
+
* and retrieve the `orderBy` filter with `$filter('orderBy')`.)
|
20936
21440
|
*
|
20937
|
-
|
20938
|
-
|
20939
|
-
|
20940
|
-
|
20941
|
-
|
20942
|
-
|
20943
|
-
|
20944
|
-
|
20945
|
-
|
20946
|
-
|
20947
|
-
|
20948
|
-
|
20949
|
-
|
20950
|
-
|
20951
|
-
|
20952
|
-
|
20953
|
-
|
20954
|
-
|
20955
|
-
|
20956
|
-
|
20957
|
-
|
20958
|
-
|
20959
|
-
|
20960
|
-
|
20961
|
-
|
20962
|
-
|
20963
|
-
|
20964
|
-
|
21441
|
+
<example name="orderBy-call-manually" module="orderByExample3">
|
21442
|
+
<file name="index.html">
|
21443
|
+
<div ng-controller="ExampleController">
|
21444
|
+
<pre>Sort by = {{propertyName}}; reverse = {{reverse}}</pre>
|
21445
|
+
<hr/>
|
21446
|
+
<button ng-click="sortBy(null)">Set to unsorted</button>
|
21447
|
+
<hr/>
|
21448
|
+
<table class="friends">
|
21449
|
+
<tr>
|
21450
|
+
<th>
|
21451
|
+
<button ng-click="sortBy('name')">Name</button>
|
21452
|
+
<span class="sortorder" ng-show="propertyName === 'name'" ng-class="{reverse: reverse}"></span>
|
21453
|
+
</th>
|
21454
|
+
<th>
|
21455
|
+
<button ng-click="sortBy('phone')">Phone Number</button>
|
21456
|
+
<span class="sortorder" ng-show="propertyName === 'phone'" ng-class="{reverse: reverse}"></span>
|
21457
|
+
</th>
|
21458
|
+
<th>
|
21459
|
+
<button ng-click="sortBy('age')">Age</button>
|
21460
|
+
<span class="sortorder" ng-show="propertyName === 'age'" ng-class="{reverse: reverse}"></span>
|
21461
|
+
</th>
|
21462
|
+
</tr>
|
21463
|
+
<tr ng-repeat="friend in friends">
|
21464
|
+
<td>{{friend.name}}</td>
|
21465
|
+
<td>{{friend.phone}}</td>
|
21466
|
+
<td>{{friend.age}}</td>
|
21467
|
+
</tr>
|
21468
|
+
</table>
|
21469
|
+
</div>
|
21470
|
+
</file>
|
21471
|
+
<file name="script.js">
|
21472
|
+
angular.module('orderByExample3', [])
|
21473
|
+
.controller('ExampleController', ['$scope', 'orderByFilter', function($scope, orderBy) {
|
21474
|
+
var friends = [
|
21475
|
+
{name: 'John', phone: '555-1212', age: 10},
|
21476
|
+
{name: 'Mary', phone: '555-9876', age: 19},
|
21477
|
+
{name: 'Mike', phone: '555-4321', age: 21},
|
21478
|
+
{name: 'Adam', phone: '555-5678', age: 35},
|
21479
|
+
{name: 'Julie', phone: '555-8765', age: 29}
|
21480
|
+
];
|
21481
|
+
|
21482
|
+
$scope.propertyName = 'age';
|
21483
|
+
$scope.reverse = true;
|
21484
|
+
$scope.friends = orderBy(friends, $scope.propertyName, $scope.reverse);
|
20965
21485
|
|
20966
|
-
|
20967
|
-
|
20968
|
-
|
20969
|
-
|
20970
|
-
|
20971
|
-
|
20972
|
-
|
20973
|
-
|
20974
|
-
|
20975
|
-
|
20976
|
-
|
20977
|
-
|
20978
|
-
|
20979
|
-
|
20980
|
-
|
20981
|
-
|
20982
|
-
|
20983
|
-
|
20984
|
-
|
21486
|
+
$scope.sortBy = function(propertyName) {
|
21487
|
+
$scope.reverse = (propertyName !== null && $scope.propertyName === propertyName)
|
21488
|
+
? !$scope.reverse : false;
|
21489
|
+
$scope.propertyName = propertyName;
|
21490
|
+
$scope.friends = orderBy(friends, $scope.propertyName, $scope.reverse);
|
21491
|
+
};
|
21492
|
+
}]);
|
21493
|
+
</file>
|
21494
|
+
<file name="style.css">
|
21495
|
+
.friends {
|
21496
|
+
border-collapse: collapse;
|
21497
|
+
}
|
21498
|
+
|
21499
|
+
.friends th {
|
21500
|
+
border-bottom: 1px solid;
|
21501
|
+
}
|
21502
|
+
.friends td, .friends th {
|
21503
|
+
border-left: 1px solid;
|
21504
|
+
padding: 5px 10px;
|
21505
|
+
}
|
21506
|
+
.friends td:first-child, .friends th:first-child {
|
21507
|
+
border-left: none;
|
21508
|
+
}
|
20985
21509
|
|
20986
|
-
<file name="style.css">
|
20987
21510
|
.sortorder:after {
|
20988
|
-
content: '\25b2';
|
21511
|
+
content: '\25b2'; // BLACK UP-POINTING TRIANGLE
|
20989
21512
|
}
|
20990
21513
|
.sortorder.reverse:after {
|
20991
|
-
content: '\25bc';
|
21514
|
+
content: '\25bc'; // BLACK DOWN-POINTING TRIANGLE
|
20992
21515
|
}
|
20993
|
-
|
20994
|
-
|
21516
|
+
</file>
|
21517
|
+
<file name="protractor.js" type="protractor">
|
21518
|
+
// Element locators
|
21519
|
+
var unsortButton = element(by.partialButtonText('unsorted'));
|
21520
|
+
var nameHeader = element(by.partialButtonText('Name'));
|
21521
|
+
var phoneHeader = element(by.partialButtonText('Phone'));
|
21522
|
+
var ageHeader = element(by.partialButtonText('Age'));
|
21523
|
+
var firstName = element(by.repeater('friends').column('friend.name').row(0));
|
21524
|
+
var lastName = element(by.repeater('friends').column('friend.name').row(4));
|
21525
|
+
|
21526
|
+
it('should sort friends by some property, when clicking on the column header', function() {
|
21527
|
+
expect(firstName.getText()).toBe('Adam');
|
21528
|
+
expect(lastName.getText()).toBe('John');
|
21529
|
+
|
21530
|
+
phoneHeader.click();
|
21531
|
+
expect(firstName.getText()).toBe('John');
|
21532
|
+
expect(lastName.getText()).toBe('Mary');
|
21533
|
+
|
21534
|
+
nameHeader.click();
|
21535
|
+
expect(firstName.getText()).toBe('Adam');
|
21536
|
+
expect(lastName.getText()).toBe('Mike');
|
21537
|
+
|
21538
|
+
ageHeader.click();
|
21539
|
+
expect(firstName.getText()).toBe('John');
|
21540
|
+
expect(lastName.getText()).toBe('Adam');
|
21541
|
+
});
|
21542
|
+
|
21543
|
+
it('should sort friends in reverse order, when clicking on the same column', function() {
|
21544
|
+
expect(firstName.getText()).toBe('Adam');
|
21545
|
+
expect(lastName.getText()).toBe('John');
|
21546
|
+
|
21547
|
+
ageHeader.click();
|
21548
|
+
expect(firstName.getText()).toBe('John');
|
21549
|
+
expect(lastName.getText()).toBe('Adam');
|
21550
|
+
|
21551
|
+
ageHeader.click();
|
21552
|
+
expect(firstName.getText()).toBe('Adam');
|
21553
|
+
expect(lastName.getText()).toBe('John');
|
21554
|
+
});
|
21555
|
+
|
21556
|
+
it('should restore the original order, when clicking "Set to unsorted"', function() {
|
21557
|
+
expect(firstName.getText()).toBe('Adam');
|
21558
|
+
expect(lastName.getText()).toBe('John');
|
21559
|
+
|
21560
|
+
unsortButton.click();
|
21561
|
+
expect(firstName.getText()).toBe('John');
|
21562
|
+
expect(lastName.getText()).toBe('Julie');
|
21563
|
+
});
|
21564
|
+
</file>
|
21565
|
+
</example>
|
21566
|
+
* <hr />
|
21567
|
+
*
|
21568
|
+
* @example
|
21569
|
+
* ### Using a custom comparator
|
21570
|
+
*
|
21571
|
+
* If you have very specific requirements about the way items are sorted, you can pass your own
|
21572
|
+
* comparator function. For example, you might need to compare some strings in a locale-sensitive
|
21573
|
+
* way. (When specifying a custom comparator, you also need to pass a value for the `reverse`
|
21574
|
+
* argument - passing `false` retains the default sorting order, i.e. ascending.)
|
21575
|
+
*
|
21576
|
+
<example name="orderBy-custom-comparator" module="orderByExample4">
|
21577
|
+
<file name="index.html">
|
21578
|
+
<div ng-controller="ExampleController">
|
21579
|
+
<div class="friends-container custom-comparator">
|
21580
|
+
<h3>Locale-sensitive Comparator</h3>
|
21581
|
+
<table class="friends">
|
21582
|
+
<tr>
|
21583
|
+
<th>Name</th>
|
21584
|
+
<th>Favorite Letter</th>
|
21585
|
+
</tr>
|
21586
|
+
<tr ng-repeat="friend in friends | orderBy:'favoriteLetter':false:localeSensitiveComparator">
|
21587
|
+
<td>{{friend.name}}</td>
|
21588
|
+
<td>{{friend.favoriteLetter}}</td>
|
21589
|
+
</tr>
|
21590
|
+
</table>
|
21591
|
+
</div>
|
21592
|
+
<div class="friends-container default-comparator">
|
21593
|
+
<h3>Default Comparator</h3>
|
21594
|
+
<table class="friends">
|
21595
|
+
<tr>
|
21596
|
+
<th>Name</th>
|
21597
|
+
<th>Favorite Letter</th>
|
21598
|
+
</tr>
|
21599
|
+
<tr ng-repeat="friend in friends | orderBy:'favoriteLetter'">
|
21600
|
+
<td>{{friend.name}}</td>
|
21601
|
+
<td>{{friend.favoriteLetter}}</td>
|
21602
|
+
</tr>
|
21603
|
+
</table>
|
21604
|
+
</div>
|
21605
|
+
</div>
|
21606
|
+
</file>
|
21607
|
+
<file name="script.js">
|
21608
|
+
angular.module('orderByExample4', [])
|
21609
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
21610
|
+
$scope.friends = [
|
21611
|
+
{name: 'John', favoriteLetter: 'Ä'},
|
21612
|
+
{name: 'Mary', favoriteLetter: 'Ü'},
|
21613
|
+
{name: 'Mike', favoriteLetter: 'Ö'},
|
21614
|
+
{name: 'Adam', favoriteLetter: 'H'},
|
21615
|
+
{name: 'Julie', favoriteLetter: 'Z'}
|
21616
|
+
];
|
21617
|
+
|
21618
|
+
$scope.localeSensitiveComparator = function(v1, v2) {
|
21619
|
+
// If we don't get strings, just compare by index
|
21620
|
+
if (v1.type !== 'string' || v2.type !== 'string') {
|
21621
|
+
return (v1.index < v2.index) ? -1 : 1;
|
21622
|
+
}
|
21623
|
+
|
21624
|
+
// Compare strings alphabetically, taking locale into account
|
21625
|
+
return v1.value.localeCompare(v2.value);
|
21626
|
+
};
|
21627
|
+
}]);
|
21628
|
+
</file>
|
21629
|
+
<file name="style.css">
|
21630
|
+
.friends-container {
|
21631
|
+
display: inline-block;
|
21632
|
+
margin: 0 30px;
|
21633
|
+
}
|
21634
|
+
|
21635
|
+
.friends {
|
21636
|
+
border-collapse: collapse;
|
21637
|
+
}
|
21638
|
+
|
21639
|
+
.friends th {
|
21640
|
+
border-bottom: 1px solid;
|
21641
|
+
}
|
21642
|
+
.friends td, .friends th {
|
21643
|
+
border-left: 1px solid;
|
21644
|
+
padding: 5px 10px;
|
21645
|
+
}
|
21646
|
+
.friends td:first-child, .friends th:first-child {
|
21647
|
+
border-left: none;
|
21648
|
+
}
|
21649
|
+
</file>
|
21650
|
+
<file name="protractor.js" type="protractor">
|
21651
|
+
// Element locators
|
21652
|
+
var container = element(by.css('.custom-comparator'));
|
21653
|
+
var names = container.all(by.repeater('friends').column('friend.name'));
|
21654
|
+
|
21655
|
+
it('should sort friends by favorite letter (in correct alphabetical order)', function() {
|
21656
|
+
expect(names.get(0).getText()).toBe('John');
|
21657
|
+
expect(names.get(1).getText()).toBe('Adam');
|
21658
|
+
expect(names.get(2).getText()).toBe('Mike');
|
21659
|
+
expect(names.get(3).getText()).toBe('Mary');
|
21660
|
+
expect(names.get(4).getText()).toBe('Julie');
|
21661
|
+
});
|
21662
|
+
</file>
|
21663
|
+
</example>
|
21664
|
+
*
|
20995
21665
|
*/
|
20996
21666
|
orderByFilter.$inject = ['$parse'];
|
20997
21667
|
function orderByFilter($parse) {
|
20998
|
-
return function(array, sortPredicate, reverseOrder) {
|
21668
|
+
return function(array, sortPredicate, reverseOrder, compareFn) {
|
20999
21669
|
|
21000
21670
|
if (array == null) return array;
|
21001
21671
|
if (!isArrayLike(array)) {
|
@@ -21005,11 +21675,12 @@ function orderByFilter($parse) {
|
|
21005
21675
|
if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }
|
21006
21676
|
if (sortPredicate.length === 0) { sortPredicate = ['+']; }
|
21007
21677
|
|
21008
|
-
var predicates = processPredicates(sortPredicate
|
21009
|
-
|
21010
|
-
|
21011
|
-
|
21012
|
-
|
21678
|
+
var predicates = processPredicates(sortPredicate);
|
21679
|
+
|
21680
|
+
var descending = reverseOrder ? -1 : 1;
|
21681
|
+
|
21682
|
+
// Define the `compare()` function. Use a default comparator if none is specified.
|
21683
|
+
var compare = isFunction(compareFn) ? compareFn : defaultCompare;
|
21013
21684
|
|
21014
21685
|
// The next three lines are a version of a Swartzian Transform idiom from Perl
|
21015
21686
|
// (sometimes called the Decorate-Sort-Undecorate idiom)
|
@@ -21021,8 +21692,12 @@ function orderByFilter($parse) {
|
|
21021
21692
|
return array;
|
21022
21693
|
|
21023
21694
|
function getComparisonObject(value, index) {
|
21695
|
+
// NOTE: We are adding an extra `tieBreaker` value based on the element's index.
|
21696
|
+
// This will be used to keep the sort stable when none of the input predicates can
|
21697
|
+
// distinguish between two elements.
|
21024
21698
|
return {
|
21025
21699
|
value: value,
|
21700
|
+
tieBreaker: {value: index, type: 'number', index: index},
|
21026
21701
|
predicateValues: predicates.map(function(predicate) {
|
21027
21702
|
return getPredicateValue(predicate.get(value), index);
|
21028
21703
|
})
|
@@ -21030,18 +21705,19 @@ function orderByFilter($parse) {
|
|
21030
21705
|
}
|
21031
21706
|
|
21032
21707
|
function doComparison(v1, v2) {
|
21033
|
-
var
|
21034
|
-
|
21035
|
-
|
21036
|
-
|
21708
|
+
for (var i = 0, ii = predicates.length; i < ii; i++) {
|
21709
|
+
var result = compare(v1.predicateValues[i], v2.predicateValues[i]);
|
21710
|
+
if (result) {
|
21711
|
+
return result * predicates[i].descending * descending;
|
21712
|
+
}
|
21037
21713
|
}
|
21038
|
-
|
21714
|
+
|
21715
|
+
return compare(v1.tieBreaker, v2.tieBreaker) * descending;
|
21039
21716
|
}
|
21040
21717
|
};
|
21041
21718
|
|
21042
|
-
function processPredicates(
|
21043
|
-
|
21044
|
-
return sortPredicate.map(function(predicate) {
|
21719
|
+
function processPredicates(sortPredicates) {
|
21720
|
+
return sortPredicates.map(function(predicate) {
|
21045
21721
|
var descending = 1, get = identity;
|
21046
21722
|
|
21047
21723
|
if (isFunction(predicate)) {
|
@@ -21059,7 +21735,7 @@ function orderByFilter($parse) {
|
|
21059
21735
|
}
|
21060
21736
|
}
|
21061
21737
|
}
|
21062
|
-
return {
|
21738
|
+
return {get: get, descending: descending};
|
21063
21739
|
});
|
21064
21740
|
}
|
21065
21741
|
|
@@ -21074,9 +21750,9 @@ function orderByFilter($parse) {
|
|
21074
21750
|
}
|
21075
21751
|
}
|
21076
21752
|
|
21077
|
-
function objectValue(value
|
21753
|
+
function objectValue(value) {
|
21078
21754
|
// If `valueOf` is a valid function use that
|
21079
|
-
if (
|
21755
|
+
if (isFunction(value.valueOf)) {
|
21080
21756
|
value = value.valueOf();
|
21081
21757
|
if (isPrimitive(value)) return value;
|
21082
21758
|
}
|
@@ -21085,8 +21761,8 @@ function orderByFilter($parse) {
|
|
21085
21761
|
value = value.toString();
|
21086
21762
|
if (isPrimitive(value)) return value;
|
21087
21763
|
}
|
21088
|
-
|
21089
|
-
return
|
21764
|
+
|
21765
|
+
return value;
|
21090
21766
|
}
|
21091
21767
|
|
21092
21768
|
function getPredicateValue(value, index) {
|
@@ -21094,23 +21770,39 @@ function orderByFilter($parse) {
|
|
21094
21770
|
if (value === null) {
|
21095
21771
|
type = 'string';
|
21096
21772
|
value = 'null';
|
21097
|
-
} else if (type === 'string') {
|
21098
|
-
value = value.toLowerCase();
|
21099
21773
|
} else if (type === 'object') {
|
21100
|
-
value = objectValue(value
|
21774
|
+
value = objectValue(value);
|
21101
21775
|
}
|
21102
|
-
return {
|
21776
|
+
return {value: value, type: type, index: index};
|
21103
21777
|
}
|
21104
21778
|
|
21105
|
-
function
|
21779
|
+
function defaultCompare(v1, v2) {
|
21106
21780
|
var result = 0;
|
21107
|
-
|
21108
|
-
|
21109
|
-
|
21781
|
+
var type1 = v1.type;
|
21782
|
+
var type2 = v2.type;
|
21783
|
+
|
21784
|
+
if (type1 === type2) {
|
21785
|
+
var value1 = v1.value;
|
21786
|
+
var value2 = v2.value;
|
21787
|
+
|
21788
|
+
if (type1 === 'string') {
|
21789
|
+
// Compare strings case-insensitively
|
21790
|
+
value1 = value1.toLowerCase();
|
21791
|
+
value2 = value2.toLowerCase();
|
21792
|
+
} else if (type1 === 'object') {
|
21793
|
+
// For basic objects, use the position of the object
|
21794
|
+
// in the collection instead of the value
|
21795
|
+
if (isObject(value1)) value1 = v1.index;
|
21796
|
+
if (isObject(value2)) value2 = v2.index;
|
21797
|
+
}
|
21798
|
+
|
21799
|
+
if (value1 !== value2) {
|
21800
|
+
result = value1 < value2 ? -1 : 1;
|
21110
21801
|
}
|
21111
21802
|
} else {
|
21112
|
-
result =
|
21803
|
+
result = type1 < type2 ? -1 : 1;
|
21113
21804
|
}
|
21805
|
+
|
21114
21806
|
return result;
|
21115
21807
|
}
|
21116
21808
|
}
|
@@ -21390,9 +22082,11 @@ var htmlAnchorDirective = valueFn({
|
|
21390
22082
|
*
|
21391
22083
|
* @description
|
21392
22084
|
*
|
21393
|
-
* Sets the `
|
22085
|
+
* Sets the `readonly` attribute on the element, if the expression inside `ngReadonly` is truthy.
|
22086
|
+
* Note that `readonly` applies only to `input` elements with specific types. [See the input docs on
|
22087
|
+
* MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-readonly) for more information.
|
21394
22088
|
*
|
21395
|
-
* A special directive is necessary because we cannot use interpolation inside the `
|
22089
|
+
* A special directive is necessary because we cannot use interpolation inside the `readonly`
|
21396
22090
|
* attribute. See the {@link guide/interpolation interpolation guide} for more info.
|
21397
22091
|
*
|
21398
22092
|
* @example
|
@@ -21429,6 +22123,13 @@ var htmlAnchorDirective = valueFn({
|
|
21429
22123
|
* A special directive is necessary because we cannot use interpolation inside the `selected`
|
21430
22124
|
* attribute. See the {@link guide/interpolation interpolation guide} for more info.
|
21431
22125
|
*
|
22126
|
+
* <div class="alert alert-warning">
|
22127
|
+
* **Note:** `ngSelected` does not interact with the `select` and `ngModel` directives, it only
|
22128
|
+
* sets the `selected` attribute on the element. If you are using `ngModel` on the select, you
|
22129
|
+
* should not use `ngSelected` on the options, as `ngModel` will set the select value and
|
22130
|
+
* selected options.
|
22131
|
+
* </div>
|
22132
|
+
*
|
21432
22133
|
* @example
|
21433
22134
|
<example>
|
21434
22135
|
<file name="index.html">
|
@@ -21465,6 +22166,11 @@ var htmlAnchorDirective = valueFn({
|
|
21465
22166
|
* A special directive is necessary because we cannot use interpolation inside the `open`
|
21466
22167
|
* attribute. See the {@link guide/interpolation interpolation guide} for more info.
|
21467
22168
|
*
|
22169
|
+
* ## A note about browser compatibility
|
22170
|
+
*
|
22171
|
+
* Edge, Firefox, and Internet Explorer do not support the `details` element, it is
|
22172
|
+
* recommended to use {@link ng.ngShow} and {@link ng.ngHide} instead.
|
22173
|
+
*
|
21468
22174
|
* @example
|
21469
22175
|
<example>
|
21470
22176
|
<file name="index.html">
|
@@ -22155,7 +22861,9 @@ var ISO_DATE_REGEXP = /^\d{4,}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-
|
|
22155
22861
|
// 9. Fragment
|
22156
22862
|
// 1111111111111111 222 333333 44444 555555555555555555555555 666 77777777 8888888 999
|
22157
22863
|
var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+\])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
|
22158
|
-
|
22864
|
+
/* jshint maxlen:220 */
|
22865
|
+
var EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+\/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+\/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/;
|
22866
|
+
/* jshint maxlen:200 */
|
22159
22867
|
var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
|
22160
22868
|
var DATE_REGEXP = /^(\d{4,})-(\d{2})-(\d{2})$/;
|
22161
22869
|
var DATETIMELOCAL_REGEXP = /^(\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
|
@@ -23540,7 +24248,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
23540
24248
|
|
23541
24249
|
attr.$observe('min', function(val) {
|
23542
24250
|
if (isDefined(val) && !isNumber(val)) {
|
23543
|
-
val = parseFloat(val
|
24251
|
+
val = parseFloat(val);
|
23544
24252
|
}
|
23545
24253
|
minVal = isNumber(val) && !isNaN(val) ? val : undefined;
|
23546
24254
|
// TODO(matsko): implement validateLater to reduce number of validations
|
@@ -23556,7 +24264,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
23556
24264
|
|
23557
24265
|
attr.$observe('max', function(val) {
|
23558
24266
|
if (isDefined(val) && !isNumber(val)) {
|
23559
|
-
val = parseFloat(val
|
24267
|
+
val = parseFloat(val);
|
23560
24268
|
}
|
23561
24269
|
maxVal = isNumber(val) && !isNaN(val) ? val : undefined;
|
23562
24270
|
// TODO(matsko): implement validateLater to reduce number of validations
|
@@ -24363,6 +25071,11 @@ function classDirective(name, selector) {
|
|
24363
25071
|
* When the expression changes, the previously added classes are removed and only then are the
|
24364
25072
|
* new classes added.
|
24365
25073
|
*
|
25074
|
+
* @knownIssue
|
25075
|
+
* You should not use {@link guide/interpolation interpolation} in the value of the `class`
|
25076
|
+
* attribute, when using the `ngClass` directive on the same element.
|
25077
|
+
* See {@link guide/interpolation#known-issues here} for more info.
|
25078
|
+
*
|
24366
25079
|
* @animations
|
24367
25080
|
* | Animation | Occurs |
|
24368
25081
|
* |----------------------------------|-------------------------------------|
|
@@ -28308,7 +29021,7 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
|
|
28308
29021
|
|
28309
29022
|
for (var i = options.items.length - 1; i >= 0; i--) {
|
28310
29023
|
var option = options.items[i];
|
28311
|
-
if (option.group) {
|
29024
|
+
if (isDefined(option.group)) {
|
28312
29025
|
jqLiteRemove(option.element.parentNode);
|
28313
29026
|
} else {
|
28314
29027
|
jqLiteRemove(option.element);
|
@@ -28340,7 +29053,8 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
|
|
28340
29053
|
listFragment.appendChild(groupElement);
|
28341
29054
|
|
28342
29055
|
// Update the label on the group element
|
28343
|
-
|
29056
|
+
// "null" is special cased because of Safari
|
29057
|
+
groupElement.label = option.group === null ? 'null' : option.group;
|
28344
29058
|
|
28345
29059
|
// Store it for use later
|
28346
29060
|
groupElementMap[option.group] = groupElement;
|
@@ -28676,7 +29390,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
|
|
28676
29390
|
* it's a prefix used by Angular for public (`$`) and private (`$$`) properties.
|
28677
29391
|
*
|
28678
29392
|
* - The built-in filters {@link ng.orderBy orderBy} and {@link ng.filter filter} do not work with
|
28679
|
-
* objects, and will throw if used with one.
|
29393
|
+
* objects, and will throw an error if used with one.
|
28680
29394
|
*
|
28681
29395
|
* If you are hitting any of these limitations, the recommended workaround is to convert your object into an array
|
28682
29396
|
* that is sorted into the order that you prefer before providing it to `ngRepeat`. You could
|
@@ -29525,6 +30239,11 @@ var ngHideDirective = ['$animate', function($animate) {
|
|
29525
30239
|
* @description
|
29526
30240
|
* The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
|
29527
30241
|
*
|
30242
|
+
* @knownIssue
|
30243
|
+
* You should not use {@link guide/interpolation interpolation} in the value of the `style`
|
30244
|
+
* attribute, when using the `ngStyle` directive on the same element.
|
30245
|
+
* See {@link guide/interpolation#known-issues here} for more info.
|
30246
|
+
*
|
29528
30247
|
* @element ANY
|
29529
30248
|
* @param {expression} ngStyle
|
29530
30249
|
*
|
@@ -29936,37 +30655,63 @@ var ngSwitchDefaultDirective = ngDirective({
|
|
29936
30655
|
* </example>
|
29937
30656
|
*/
|
29938
30657
|
var ngTranscludeMinErr = minErr('ngTransclude');
|
29939
|
-
var ngTranscludeDirective =
|
29940
|
-
|
29941
|
-
|
30658
|
+
var ngTranscludeDirective = ['$compile', function($compile) {
|
30659
|
+
return {
|
30660
|
+
restrict: 'EAC',
|
30661
|
+
terminal: true,
|
30662
|
+
compile: function ngTranscludeCompile(tElement) {
|
29942
30663
|
|
29943
|
-
|
29944
|
-
|
29945
|
-
|
29946
|
-
$attrs.ngTransclude = '';
|
29947
|
-
}
|
30664
|
+
// Remove and cache any original content to act as a fallback
|
30665
|
+
var fallbackLinkFn = $compile(tElement.contents());
|
30666
|
+
tElement.empty();
|
29948
30667
|
|
29949
|
-
|
29950
|
-
if (clone.length) {
|
29951
|
-
$element.empty();
|
29952
|
-
$element.append(clone);
|
29953
|
-
}
|
29954
|
-
}
|
30668
|
+
return function ngTranscludePostLink($scope, $element, $attrs, controller, $transclude) {
|
29955
30669
|
|
29956
|
-
|
29957
|
-
|
29958
|
-
|
29959
|
-
|
29960
|
-
|
29961
|
-
|
29962
|
-
|
30670
|
+
if (!$transclude) {
|
30671
|
+
throw ngTranscludeMinErr('orphan',
|
30672
|
+
'Illegal use of ngTransclude directive in the template! ' +
|
30673
|
+
'No parent directive that requires a transclusion found. ' +
|
30674
|
+
'Element: {0}',
|
30675
|
+
startingTag($element));
|
30676
|
+
}
|
29963
30677
|
|
29964
|
-
|
29965
|
-
|
29966
|
-
|
29967
|
-
|
29968
|
-
|
29969
|
-
|
30678
|
+
|
30679
|
+
// If the attribute is of the form: `ng-transclude="ng-transclude"` then treat it like the default
|
30680
|
+
if ($attrs.ngTransclude === $attrs.$attr.ngTransclude) {
|
30681
|
+
$attrs.ngTransclude = '';
|
30682
|
+
}
|
30683
|
+
var slotName = $attrs.ngTransclude || $attrs.ngTranscludeSlot;
|
30684
|
+
|
30685
|
+
// If the slot is required and no transclusion content is provided then this call will throw an error
|
30686
|
+
$transclude(ngTranscludeCloneAttachFn, null, slotName);
|
30687
|
+
|
30688
|
+
// If the slot is optional and no transclusion content is provided then use the fallback content
|
30689
|
+
if (slotName && !$transclude.isSlotFilled(slotName)) {
|
30690
|
+
useFallbackContent();
|
30691
|
+
}
|
30692
|
+
|
30693
|
+
function ngTranscludeCloneAttachFn(clone, transcludedScope) {
|
30694
|
+
if (clone.length) {
|
30695
|
+
$element.append(clone);
|
30696
|
+
} else {
|
30697
|
+
useFallbackContent();
|
30698
|
+
// There is nothing linked against the transcluded scope since no content was available,
|
30699
|
+
// so it should be safe to clean up the generated scope.
|
30700
|
+
transcludedScope.$destroy();
|
30701
|
+
}
|
30702
|
+
}
|
30703
|
+
|
30704
|
+
function useFallbackContent() {
|
30705
|
+
// Since this is the fallback content rather than the transcluded content,
|
30706
|
+
// we link against the scope of this directive rather than the transcluded scope
|
30707
|
+
fallbackLinkFn($scope, function(clone) {
|
30708
|
+
$element.append(clone);
|
30709
|
+
});
|
30710
|
+
}
|
30711
|
+
};
|
30712
|
+
}
|
30713
|
+
};
|
30714
|
+
}];
|
29970
30715
|
|
29971
30716
|
/**
|
29972
30717
|
* @ngdoc directive
|