angularjs-rails 1.5.6 → 1.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/angularjs-rails/version.rb +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
|