angularjs-rails 1.2.26 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/angularjs-rails/version.rb +2 -2
- data/vendor/assets/javascripts/angular-animate.js +879 -456
- data/vendor/assets/javascripts/angular-aria.js +250 -0
- data/vendor/assets/javascripts/angular-cookies.js +1 -1
- data/vendor/assets/javascripts/angular-loader.js +17 -10
- data/vendor/assets/javascripts/angular-messages.js +400 -0
- data/vendor/assets/javascripts/angular-mocks.js +220 -110
- data/vendor/assets/javascripts/angular-resource.js +287 -247
- data/vendor/assets/javascripts/angular-route.js +111 -54
- data/vendor/assets/javascripts/angular-sanitize.js +1 -1
- data/vendor/assets/javascripts/angular-scenario.js +11579 -8665
- data/vendor/assets/javascripts/angular-touch.js +49 -11
- data/vendor/assets/javascripts/angular.js +6660 -3106
- data/vendor/assets/javascripts/unstable/angular-animate.js +240 -71
- data/vendor/assets/javascripts/unstable/angular-aria.js +12 -12
- data/vendor/assets/javascripts/unstable/angular-cookies.js +1 -1
- data/vendor/assets/javascripts/unstable/angular-loader.js +4 -4
- data/vendor/assets/javascripts/unstable/angular-messages.js +1 -1
- data/vendor/assets/javascripts/unstable/angular-mocks.js +21 -14
- data/vendor/assets/javascripts/unstable/angular-resource.js +2 -2
- data/vendor/assets/javascripts/unstable/angular-route.js +1 -1
- data/vendor/assets/javascripts/unstable/angular-sanitize.js +1 -1
- data/vendor/assets/javascripts/unstable/angular-scenario.js +562 -262
- data/vendor/assets/javascripts/unstable/angular-touch.js +1 -1
- data/vendor/assets/javascripts/unstable/angular.js +562 -262
- metadata +16 -14
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.3.0
|
2
|
+
* @license AngularJS v1.3.0
|
3
3
|
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -10,18 +10,18 @@
|
|
10
10
|
* @name ngAria
|
11
11
|
* @description
|
12
12
|
*
|
13
|
-
* The `ngAria` module provides support for adding
|
14
|
-
* about the application in order to allow assistive technologies
|
15
|
-
* persons with disabilities.
|
13
|
+
* The `ngAria` module provides support for adding <abbr title="Accessible Rich Internet Applications">ARIA</abbr>
|
14
|
+
* attributes that convey state or semantic information about the application in order to allow assistive technologies
|
15
|
+
* to convey appropriate information to persons with disabilities.
|
16
16
|
*
|
17
17
|
* <div doc-module-components="ngAria"></div>
|
18
18
|
*
|
19
19
|
* # Usage
|
20
|
-
* To enable the addition of the
|
20
|
+
* To enable the addition of the ARIA tags, just require the module into your application and the tags will
|
21
21
|
* hook into your ng-show/ng-hide, input, textarea, button, select and ng-required directives and adds the
|
22
|
-
* appropriate
|
22
|
+
* appropriate ARIA attributes.
|
23
23
|
*
|
24
|
-
* Currently, the following
|
24
|
+
* Currently, the following ARIA attributes are implemented:
|
25
25
|
*
|
26
26
|
* + aria-hidden
|
27
27
|
* + aria-checked
|
@@ -34,7 +34,7 @@
|
|
34
34
|
* + aria-valuemax
|
35
35
|
* + tabindex
|
36
36
|
*
|
37
|
-
* You can disable individual
|
37
|
+
* You can disable individual ARIA attributes by using the {@link ngAria.$ariaProvider#config config} method.
|
38
38
|
*/
|
39
39
|
|
40
40
|
/* global -ngAriaModule */
|
@@ -47,7 +47,7 @@ var ngAriaModule = angular.module('ngAria', ['ng']).
|
|
47
47
|
*
|
48
48
|
* @description
|
49
49
|
*
|
50
|
-
* Used for configuring
|
50
|
+
* Used for configuring ARIA attributes.
|
51
51
|
*
|
52
52
|
* ## Dependencies
|
53
53
|
* Requires the {@link ngAria} module to be installed.
|
@@ -68,7 +68,7 @@ function $AriaProvider() {
|
|
68
68
|
* @ngdoc method
|
69
69
|
* @name $ariaProvider#config
|
70
70
|
*
|
71
|
-
* @param {object} config object to enable/disable specific
|
71
|
+
* @param {object} config object to enable/disable specific ARIA attributes
|
72
72
|
*
|
73
73
|
* - **ariaHidden** – `{boolean}` – Enables/disables aria-hidden tags
|
74
74
|
* - **ariaChecked** – `{boolean}` – Enables/disables aria-checked tags
|
@@ -80,7 +80,7 @@ function $AriaProvider() {
|
|
80
80
|
* - **tabindex** – `{boolean}` – Enables/disables tabindex tags
|
81
81
|
*
|
82
82
|
* @description
|
83
|
-
* Enables/disables various
|
83
|
+
* Enables/disables various ARIA attributes
|
84
84
|
*/
|
85
85
|
this.config = function(newConfig) {
|
86
86
|
config = angular.extend(config, newConfig);
|
@@ -113,7 +113,7 @@ function $AriaProvider() {
|
|
113
113
|
*
|
114
114
|
* @description
|
115
115
|
*
|
116
|
-
* Contains helper methods for applying
|
116
|
+
* Contains helper methods for applying ARIA attributes to HTML
|
117
117
|
*
|
118
118
|
* ## Dependencies
|
119
119
|
* Requires the {@link ngAria} module to be installed.
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.3.0
|
2
|
+
* @license AngularJS v1.3.0
|
3
3
|
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -72,7 +72,7 @@ function minErr(module, ErrorConstructor) {
|
|
72
72
|
return match;
|
73
73
|
});
|
74
74
|
|
75
|
-
message = message + '\nhttp://errors.angularjs.org/1.3.0
|
75
|
+
message = message + '\nhttp://errors.angularjs.org/1.3.0/' +
|
76
76
|
(module ? module + '/' : '') + code;
|
77
77
|
for (i = 2; i < arguments.length; i++) {
|
78
78
|
message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
|
@@ -304,7 +304,7 @@ function setupModuleLoader(window) {
|
|
304
304
|
* })
|
305
305
|
* ```
|
306
306
|
*
|
307
|
-
* See {@link
|
307
|
+
* See {@link ng.$animateProvider#register $animateProvider.register()} and
|
308
308
|
* {@link ngAnimate ngAnimate module} for more information.
|
309
309
|
*/
|
310
310
|
animation: invokeLater('$animateProvider', 'register'),
|
@@ -354,7 +354,7 @@ function setupModuleLoader(window) {
|
|
354
354
|
* @description
|
355
355
|
* Use this method to register work which needs to be performed on module loading.
|
356
356
|
* For more about how to configure services, see
|
357
|
-
* {@link providers#
|
357
|
+
* {@link providers#provider-recipe Provider Recipe}.
|
358
358
|
*/
|
359
359
|
config: config,
|
360
360
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.3.0
|
2
|
+
* @license AngularJS v1.3.0
|
3
3
|
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -201,7 +201,7 @@ angular.mock.$Browser.prototype = {
|
|
201
201
|
*
|
202
202
|
* @description
|
203
203
|
* Configures the mock implementation of {@link ng.$exceptionHandler} to rethrow or to log errors
|
204
|
-
* passed
|
204
|
+
* passed to the `$exceptionHandler`.
|
205
205
|
*/
|
206
206
|
|
207
207
|
/**
|
@@ -210,7 +210,7 @@ angular.mock.$Browser.prototype = {
|
|
210
210
|
*
|
211
211
|
* @description
|
212
212
|
* Mock implementation of {@link ng.$exceptionHandler} that rethrows or logs errors passed
|
213
|
-
*
|
213
|
+
* to it. See {@link ngMock.$exceptionHandlerProvider $exceptionHandlerProvider} for configuration
|
214
214
|
* information.
|
215
215
|
*
|
216
216
|
*
|
@@ -250,9 +250,8 @@ angular.mock.$ExceptionHandlerProvider = function() {
|
|
250
250
|
*
|
251
251
|
* @param {string} mode Mode of operation, defaults to `rethrow`.
|
252
252
|
*
|
253
|
-
* - `rethrow`: If any errors are passed
|
254
|
-
*
|
255
|
-
* make these tests fail.
|
253
|
+
* - `rethrow`: If any errors are passed to the handler in tests, it typically means that there
|
254
|
+
* is a bug in the application or test, so this mock will make these tests fail.
|
256
255
|
* - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log`
|
257
256
|
* mode stores an array of errors in `$exceptionHandler.errors`, to allow later
|
258
257
|
* assertion of them. See {@link ngMock.$log#assertEmpty assertEmpty()} and
|
@@ -343,7 +342,7 @@ angular.mock.$LogProvider = function() {
|
|
343
342
|
* @name $log#log.logs
|
344
343
|
*
|
345
344
|
* @description
|
346
|
-
* Array of messages logged using {@link
|
345
|
+
* Array of messages logged using {@link ng.$log#log `log()`}.
|
347
346
|
*
|
348
347
|
* @example
|
349
348
|
* ```js
|
@@ -357,7 +356,7 @@ angular.mock.$LogProvider = function() {
|
|
357
356
|
* @name $log#info.logs
|
358
357
|
*
|
359
358
|
* @description
|
360
|
-
* Array of messages logged using {@link
|
359
|
+
* Array of messages logged using {@link ng.$log#info `info()`}.
|
361
360
|
*
|
362
361
|
* @example
|
363
362
|
* ```js
|
@@ -371,7 +370,7 @@ angular.mock.$LogProvider = function() {
|
|
371
370
|
* @name $log#warn.logs
|
372
371
|
*
|
373
372
|
* @description
|
374
|
-
* Array of messages logged using {@link
|
373
|
+
* Array of messages logged using {@link ng.$log#warn `warn()`}.
|
375
374
|
*
|
376
375
|
* @example
|
377
376
|
* ```js
|
@@ -385,7 +384,7 @@ angular.mock.$LogProvider = function() {
|
|
385
384
|
* @name $log#error.logs
|
386
385
|
*
|
387
386
|
* @description
|
388
|
-
* Array of messages logged using {@link
|
387
|
+
* Array of messages logged using {@link ng.$log#error `error()`}.
|
389
388
|
*
|
390
389
|
* @example
|
391
390
|
* ```js
|
@@ -399,7 +398,7 @@ angular.mock.$LogProvider = function() {
|
|
399
398
|
* @name $log#debug.logs
|
400
399
|
*
|
401
400
|
* @description
|
402
|
-
* Array of messages logged using {@link
|
401
|
+
* Array of messages logged using {@link ng.$log#debug `debug()`}.
|
403
402
|
*
|
404
403
|
* @example
|
405
404
|
* ```js
|
@@ -415,8 +414,8 @@ angular.mock.$LogProvider = function() {
|
|
415
414
|
* @name $log#assertEmpty
|
416
415
|
*
|
417
416
|
* @description
|
418
|
-
* Assert that
|
419
|
-
* exception is thrown.
|
417
|
+
* Assert that all of the logging methods have no logged messages. If any messages are present,
|
418
|
+
* an exception is thrown.
|
420
419
|
*/
|
421
420
|
$log.assertEmpty = function() {
|
422
421
|
var errors = [];
|
@@ -811,7 +810,7 @@ angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
|
|
811
810
|
};
|
812
811
|
|
813
812
|
angular.forEach(
|
814
|
-
['enter','leave','move','addClass','removeClass','setClass'], function(method) {
|
813
|
+
['animate','enter','leave','move','addClass','removeClass','setClass'], function(method) {
|
815
814
|
animate[method] = function() {
|
816
815
|
animate.queue.push({
|
817
816
|
event : method,
|
@@ -1002,6 +1001,11 @@ angular.mock.dump = function(object) {
|
|
1002
1001
|
* First we create the controller under test:
|
1003
1002
|
*
|
1004
1003
|
```js
|
1004
|
+
// The module code
|
1005
|
+
angular
|
1006
|
+
.module('MyApp', [])
|
1007
|
+
.controller('MyController', MyController);
|
1008
|
+
|
1005
1009
|
// The controller code
|
1006
1010
|
function MyController($scope, $http) {
|
1007
1011
|
var authToken;
|
@@ -1031,6 +1035,9 @@ angular.mock.dump = function(object) {
|
|
1031
1035
|
describe('MyController', function() {
|
1032
1036
|
var $httpBackend, $rootScope, createController, authRequestHandler;
|
1033
1037
|
|
1038
|
+
// Set up the module
|
1039
|
+
beforeEach(module('MyApp'));
|
1040
|
+
|
1034
1041
|
beforeEach(inject(function($injector) {
|
1035
1042
|
// Set up the mock http service responses
|
1036
1043
|
$httpBackend = $injector.get('$httpBackend');
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.3.0
|
2
|
+
* @license AngularJS v1.3.0
|
3
3
|
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -118,7 +118,7 @@ function shallowClearAndCopy(src, dst) {
|
|
118
118
|
*
|
119
119
|
* @param {Object.<Object>=} actions Hash with declaration of custom action that should extend
|
120
120
|
* the default set of resource actions. The declaration should be created in the format of {@link
|
121
|
-
* ng.$http#
|
121
|
+
* ng.$http#usage $http.config}:
|
122
122
|
*
|
123
123
|
* {action1: {method:?, params:?, isArray:?, headers:?, ...},
|
124
124
|
* action2: {method:?, params:?, isArray:?, headers:?, ...},
|
@@ -9190,7 +9190,7 @@ return jQuery;
|
|
9190
9190
|
}));
|
9191
9191
|
|
9192
9192
|
/**
|
9193
|
-
* @license AngularJS v1.3.0
|
9193
|
+
* @license AngularJS v1.3.0
|
9194
9194
|
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
9195
9195
|
* License: MIT
|
9196
9196
|
*/
|
@@ -9263,7 +9263,7 @@ function minErr(module, ErrorConstructor) {
|
|
9263
9263
|
return match;
|
9264
9264
|
});
|
9265
9265
|
|
9266
|
-
message = message + '\nhttp://errors.angularjs.org/1.3.0
|
9266
|
+
message = message + '\nhttp://errors.angularjs.org/1.3.0/' +
|
9267
9267
|
(module ? module + '/' : '') + code;
|
9268
9268
|
for (i = 2; i < arguments.length; i++) {
|
9269
9269
|
message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
|
@@ -9605,7 +9605,8 @@ function setHashKey(obj, h) {
|
|
9605
9605
|
*
|
9606
9606
|
* @description
|
9607
9607
|
* Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
|
9608
|
-
* to `dst`. You can specify multiple `src` objects.
|
9608
|
+
* to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
|
9609
|
+
* by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
|
9609
9610
|
*
|
9610
9611
|
* @param {Object} dst Destination object.
|
9611
9612
|
* @param {...Object} src Source object(s).
|
@@ -11116,7 +11117,7 @@ function setupModuleLoader(window) {
|
|
11116
11117
|
* })
|
11117
11118
|
* ```
|
11118
11119
|
*
|
11119
|
-
* See {@link
|
11120
|
+
* See {@link ng.$animateProvider#register $animateProvider.register()} and
|
11120
11121
|
* {@link ngAnimate ngAnimate module} for more information.
|
11121
11122
|
*/
|
11122
11123
|
animation: invokeLater('$animateProvider', 'register'),
|
@@ -11166,7 +11167,7 @@ function setupModuleLoader(window) {
|
|
11166
11167
|
* @description
|
11167
11168
|
* Use this method to register work which needs to be performed on module loading.
|
11168
11169
|
* For more about how to configure services, see
|
11169
|
-
* {@link providers#
|
11170
|
+
* {@link providers#provider-recipe Provider Recipe}.
|
11170
11171
|
*/
|
11171
11172
|
config: config,
|
11172
11173
|
|
@@ -11313,11 +11314,11 @@ function setupModuleLoader(window) {
|
|
11313
11314
|
* - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
|
11314
11315
|
*/
|
11315
11316
|
var version = {
|
11316
|
-
full: '1.3.0
|
11317
|
+
full: '1.3.0', // all of these placeholder strings will be replaced by grunt's
|
11317
11318
|
major: 1, // package task
|
11318
11319
|
minor: 3,
|
11319
11320
|
dot: 0,
|
11320
|
-
codeName: '
|
11321
|
+
codeName: 'superluminal-nudge'
|
11321
11322
|
};
|
11322
11323
|
|
11323
11324
|
|
@@ -11492,7 +11493,7 @@ function publishExternalAPI(angular){
|
|
11492
11493
|
* - [`addClass()`](http://api.jquery.com/addClass/)
|
11493
11494
|
* - [`after()`](http://api.jquery.com/after/)
|
11494
11495
|
* - [`append()`](http://api.jquery.com/append/)
|
11495
|
-
* - [`attr()`](http://api.jquery.com/attr/)
|
11496
|
+
* - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
|
11496
11497
|
* - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
|
11497
11498
|
* - [`children()`](http://api.jquery.com/children/) - Does not support selectors
|
11498
11499
|
* - [`clone()`](http://api.jquery.com/clone/)
|
@@ -11727,18 +11728,22 @@ function jqLiteOff(element, type, fn, unsupported) {
|
|
11727
11728
|
if (!type) {
|
11728
11729
|
for (type in events) {
|
11729
11730
|
if (type !== '$destroy') {
|
11730
|
-
removeEventListenerFn(element, type,
|
11731
|
+
removeEventListenerFn(element, type, handle);
|
11731
11732
|
}
|
11732
11733
|
delete events[type];
|
11733
11734
|
}
|
11734
11735
|
} else {
|
11735
11736
|
forEach(type.split(' '), function(type) {
|
11736
|
-
if (
|
11737
|
-
|
11738
|
-
|
11739
|
-
|
11740
|
-
|
11737
|
+
if (isDefined(fn)) {
|
11738
|
+
var listenerFns = events[type];
|
11739
|
+
arrayRemove(listenerFns || [], fn);
|
11740
|
+
if (listenerFns && listenerFns.length > 0) {
|
11741
|
+
return;
|
11742
|
+
}
|
11741
11743
|
}
|
11744
|
+
|
11745
|
+
removeEventListenerFn(element, type, handle);
|
11746
|
+
delete events[type];
|
11742
11747
|
});
|
11743
11748
|
}
|
11744
11749
|
}
|
@@ -11902,6 +11907,20 @@ function jqLiteRemove(element, keepData) {
|
|
11902
11907
|
if (parent) parent.removeChild(element);
|
11903
11908
|
}
|
11904
11909
|
|
11910
|
+
|
11911
|
+
function jqLiteDocumentLoaded(action, win) {
|
11912
|
+
win = win || window;
|
11913
|
+
if (win.document.readyState === 'complete') {
|
11914
|
+
// Force the action to be run async for consistent behaviour
|
11915
|
+
// from the action's point of view
|
11916
|
+
// i.e. it will definitely not be in a $apply
|
11917
|
+
win.setTimeout(action);
|
11918
|
+
} else {
|
11919
|
+
// No need to unbind this handler as load is only ever called once
|
11920
|
+
jqLite(win).on('load', action);
|
11921
|
+
}
|
11922
|
+
}
|
11923
|
+
|
11905
11924
|
//////////////////////////////////////////
|
11906
11925
|
// Functions which are declared directly.
|
11907
11926
|
//////////////////////////////////////////
|
@@ -12524,7 +12543,7 @@ HashMap.prototype = {
|
|
12524
12543
|
|
12525
12544
|
* @param {Array.<string|Function>} modules A list of module functions or their aliases. See
|
12526
12545
|
* {@link angular.module}. The `ng` module must be explicitly added.
|
12527
|
-
* @returns {
|
12546
|
+
* @returns {injector} Injector object. See {@link auto.$injector $injector}.
|
12528
12547
|
*
|
12529
12548
|
* @example
|
12530
12549
|
* Typical usage
|
@@ -13175,7 +13194,7 @@ function createInjector(modulesToLoad, strictDi) {
|
|
13175
13194
|
|
13176
13195
|
function enforceReturnValue(name, factory) {
|
13177
13196
|
return function enforcedReturnValue() {
|
13178
|
-
var result = instanceInjector.invoke(factory);
|
13197
|
+
var result = instanceInjector.invoke(factory, this, undefined, name);
|
13179
13198
|
if (isUndefined(result)) {
|
13180
13199
|
throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
|
13181
13200
|
}
|
@@ -13353,93 +13372,252 @@ function createInjector(modulesToLoad, strictDi) {
|
|
13353
13372
|
createInjector.$$annotate = annotate;
|
13354
13373
|
|
13355
13374
|
/**
|
13356
|
-
* @ngdoc
|
13357
|
-
* @name $
|
13358
|
-
* @kind function
|
13359
|
-
* @requires $window
|
13360
|
-
* @requires $location
|
13361
|
-
* @requires $rootScope
|
13375
|
+
* @ngdoc provider
|
13376
|
+
* @name $anchorScrollProvider
|
13362
13377
|
*
|
13363
13378
|
* @description
|
13364
|
-
*
|
13365
|
-
*
|
13366
|
-
* [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
|
13367
|
-
*
|
13368
|
-
* It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor.
|
13369
|
-
* This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
|
13370
|
-
*
|
13371
|
-
* @example
|
13372
|
-
<example module="anchorScrollExample">
|
13373
|
-
<file name="index.html">
|
13374
|
-
<div id="scrollArea" ng-controller="ScrollController">
|
13375
|
-
<a ng-click="gotoBottom()">Go to bottom</a>
|
13376
|
-
<a id="bottom"></a> You're at the bottom!
|
13377
|
-
</div>
|
13378
|
-
</file>
|
13379
|
-
<file name="script.js">
|
13380
|
-
angular.module('anchorScrollExample', [])
|
13381
|
-
.controller('ScrollController', ['$scope', '$location', '$anchorScroll',
|
13382
|
-
function ($scope, $location, $anchorScroll) {
|
13383
|
-
$scope.gotoBottom = function() {
|
13384
|
-
// set the location.hash to the id of
|
13385
|
-
// the element you wish to scroll to.
|
13386
|
-
$location.hash('bottom');
|
13387
|
-
|
13388
|
-
// call $anchorScroll()
|
13389
|
-
$anchorScroll();
|
13390
|
-
};
|
13391
|
-
}]);
|
13392
|
-
</file>
|
13393
|
-
<file name="style.css">
|
13394
|
-
#scrollArea {
|
13395
|
-
height: 350px;
|
13396
|
-
overflow: auto;
|
13397
|
-
}
|
13398
|
-
|
13399
|
-
#bottom {
|
13400
|
-
display: block;
|
13401
|
-
margin-top: 2000px;
|
13402
|
-
}
|
13403
|
-
</file>
|
13404
|
-
</example>
|
13379
|
+
* Use `$anchorScrollProvider` to disable automatic scrolling whenever
|
13380
|
+
* {@link ng.$location#hash $location.hash()} changes.
|
13405
13381
|
*/
|
13406
13382
|
function $AnchorScrollProvider() {
|
13407
13383
|
|
13408
13384
|
var autoScrollingEnabled = true;
|
13409
13385
|
|
13386
|
+
/**
|
13387
|
+
* @ngdoc method
|
13388
|
+
* @name $anchorScrollProvider#disableAutoScrolling
|
13389
|
+
*
|
13390
|
+
* @description
|
13391
|
+
* By default, {@link ng.$anchorScroll $anchorScroll()} will automatically will detect changes to
|
13392
|
+
* {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
|
13393
|
+
* Use this method to disable automatic scrolling.
|
13394
|
+
*
|
13395
|
+
* If automatic scrolling is disabled, one must explicitly call
|
13396
|
+
* {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
|
13397
|
+
* current hash.
|
13398
|
+
*/
|
13410
13399
|
this.disableAutoScrolling = function() {
|
13411
13400
|
autoScrollingEnabled = false;
|
13412
13401
|
};
|
13413
13402
|
|
13403
|
+
/**
|
13404
|
+
* @ngdoc service
|
13405
|
+
* @name $anchorScroll
|
13406
|
+
* @kind function
|
13407
|
+
* @requires $window
|
13408
|
+
* @requires $location
|
13409
|
+
* @requires $rootScope
|
13410
|
+
*
|
13411
|
+
* @description
|
13412
|
+
* When called, it checks the current value of {@link ng.$location#hash $location.hash()} and
|
13413
|
+
* scrolls to the related element, according to the rules specified in the
|
13414
|
+
* [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
|
13415
|
+
*
|
13416
|
+
* It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
|
13417
|
+
* match any anchor whenever it changes. This can be disabled by calling
|
13418
|
+
* {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
|
13419
|
+
*
|
13420
|
+
* Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
|
13421
|
+
* vertical scroll-offset (either fixed or dynamic).
|
13422
|
+
*
|
13423
|
+
* @property {(number|function|jqLite)} yOffset
|
13424
|
+
* If set, specifies a vertical scroll-offset. This is often useful when there are fixed
|
13425
|
+
* positioned elements at the top of the page, such as navbars, headers etc.
|
13426
|
+
*
|
13427
|
+
* `yOffset` can be specified in various ways:
|
13428
|
+
* - **number**: A fixed number of pixels to be used as offset.<br /><br />
|
13429
|
+
* - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
|
13430
|
+
* a number representing the offset (in pixels).<br /><br />
|
13431
|
+
* - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
|
13432
|
+
* the top of the page to the element's bottom will be used as offset.<br />
|
13433
|
+
* **Note**: The element will be taken into account only as long as its `position` is set to
|
13434
|
+
* `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust
|
13435
|
+
* their height and/or positioning according to the viewport's size.
|
13436
|
+
*
|
13437
|
+
* <br />
|
13438
|
+
* <div class="alert alert-warning">
|
13439
|
+
* In order for `yOffset` to work properly, scrolling should take place on the document's root and
|
13440
|
+
* not some child element.
|
13441
|
+
* </div>
|
13442
|
+
*
|
13443
|
+
* @example
|
13444
|
+
<example module="anchorScrollExample">
|
13445
|
+
<file name="index.html">
|
13446
|
+
<div id="scrollArea" ng-controller="ScrollController">
|
13447
|
+
<a ng-click="gotoBottom()">Go to bottom</a>
|
13448
|
+
<a id="bottom"></a> You're at the bottom!
|
13449
|
+
</div>
|
13450
|
+
</file>
|
13451
|
+
<file name="script.js">
|
13452
|
+
angular.module('anchorScrollExample', [])
|
13453
|
+
.controller('ScrollController', ['$scope', '$location', '$anchorScroll',
|
13454
|
+
function ($scope, $location, $anchorScroll) {
|
13455
|
+
$scope.gotoBottom = function() {
|
13456
|
+
// set the location.hash to the id of
|
13457
|
+
// the element you wish to scroll to.
|
13458
|
+
$location.hash('bottom');
|
13459
|
+
|
13460
|
+
// call $anchorScroll()
|
13461
|
+
$anchorScroll();
|
13462
|
+
};
|
13463
|
+
}]);
|
13464
|
+
</file>
|
13465
|
+
<file name="style.css">
|
13466
|
+
#scrollArea {
|
13467
|
+
height: 280px;
|
13468
|
+
overflow: auto;
|
13469
|
+
}
|
13470
|
+
|
13471
|
+
#bottom {
|
13472
|
+
display: block;
|
13473
|
+
margin-top: 2000px;
|
13474
|
+
}
|
13475
|
+
</file>
|
13476
|
+
</example>
|
13477
|
+
*
|
13478
|
+
* <hr />
|
13479
|
+
* The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).
|
13480
|
+
* See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details.
|
13481
|
+
*
|
13482
|
+
* @example
|
13483
|
+
<example module="anchorScrollOffsetExample">
|
13484
|
+
<file name="index.html">
|
13485
|
+
<div class="fixed-header" ng-controller="headerCtrl">
|
13486
|
+
<a href="" ng-click="gotoAnchor(x)" ng-repeat="x in [1,2,3,4,5]">
|
13487
|
+
Go to anchor {{x}}
|
13488
|
+
</a>
|
13489
|
+
</div>
|
13490
|
+
<div id="anchor{{x}}" class="anchor" ng-repeat="x in [1,2,3,4,5]">
|
13491
|
+
Anchor {{x}} of 5
|
13492
|
+
</div>
|
13493
|
+
</file>
|
13494
|
+
<file name="script.js">
|
13495
|
+
angular.module('anchorScrollOffsetExample', [])
|
13496
|
+
.run(['$anchorScroll', function($anchorScroll) {
|
13497
|
+
$anchorScroll.yOffset = 50; // always scroll by 50 extra pixels
|
13498
|
+
}])
|
13499
|
+
.controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
|
13500
|
+
function ($anchorScroll, $location, $scope) {
|
13501
|
+
$scope.gotoAnchor = function(x) {
|
13502
|
+
var newHash = 'anchor' + x;
|
13503
|
+
if ($location.hash() !== newHash) {
|
13504
|
+
// set the $location.hash to `newHash` and
|
13505
|
+
// $anchorScroll will automatically scroll to it
|
13506
|
+
$location.hash('anchor' + x);
|
13507
|
+
} else {
|
13508
|
+
// call $anchorScroll() explicitly,
|
13509
|
+
// since $location.hash hasn't changed
|
13510
|
+
$anchorScroll();
|
13511
|
+
}
|
13512
|
+
};
|
13513
|
+
}
|
13514
|
+
]);
|
13515
|
+
</file>
|
13516
|
+
<file name="style.css">
|
13517
|
+
body {
|
13518
|
+
padding-top: 50px;
|
13519
|
+
}
|
13520
|
+
|
13521
|
+
.anchor {
|
13522
|
+
border: 2px dashed DarkOrchid;
|
13523
|
+
padding: 10px 10px 200px 10px;
|
13524
|
+
}
|
13525
|
+
|
13526
|
+
.fixed-header {
|
13527
|
+
background-color: rgba(0, 0, 0, 0.2);
|
13528
|
+
height: 50px;
|
13529
|
+
position: fixed;
|
13530
|
+
top: 0; left: 0; right: 0;
|
13531
|
+
}
|
13532
|
+
|
13533
|
+
.fixed-header > a {
|
13534
|
+
display: inline-block;
|
13535
|
+
margin: 5px 15px;
|
13536
|
+
}
|
13537
|
+
</file>
|
13538
|
+
</example>
|
13539
|
+
*/
|
13414
13540
|
this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
|
13415
13541
|
var document = $window.document;
|
13542
|
+
var scrollScheduled = false;
|
13416
13543
|
|
13417
|
-
//
|
13418
|
-
//
|
13419
|
-
//
|
13420
|
-
// TODO(vojta): use filter if we change it to accept lists as well
|
13544
|
+
// Helper function to get first anchor from a NodeList
|
13545
|
+
// (using `Array#some()` instead of `angular#forEach()` since it's more performant
|
13546
|
+
// and working in all supported browsers.)
|
13421
13547
|
function getFirstAnchor(list) {
|
13422
13548
|
var result = null;
|
13423
|
-
|
13424
|
-
if (
|
13549
|
+
Array.prototype.some.call(list, function(element) {
|
13550
|
+
if (nodeName_(element) === 'a') {
|
13551
|
+
result = element;
|
13552
|
+
return true;
|
13553
|
+
}
|
13425
13554
|
});
|
13426
13555
|
return result;
|
13427
13556
|
}
|
13428
13557
|
|
13558
|
+
function getYOffset() {
|
13559
|
+
|
13560
|
+
var offset = scroll.yOffset;
|
13561
|
+
|
13562
|
+
if (isFunction(offset)) {
|
13563
|
+
offset = offset();
|
13564
|
+
} else if (isElement(offset)) {
|
13565
|
+
var elem = offset[0];
|
13566
|
+
var style = $window.getComputedStyle(elem);
|
13567
|
+
if (style.position !== 'fixed') {
|
13568
|
+
offset = 0;
|
13569
|
+
} else {
|
13570
|
+
offset = elem.getBoundingClientRect().bottom;
|
13571
|
+
}
|
13572
|
+
} else if (!isNumber(offset)) {
|
13573
|
+
offset = 0;
|
13574
|
+
}
|
13575
|
+
|
13576
|
+
return offset;
|
13577
|
+
}
|
13578
|
+
|
13579
|
+
function scrollTo(elem) {
|
13580
|
+
if (elem) {
|
13581
|
+
elem.scrollIntoView();
|
13582
|
+
|
13583
|
+
var offset = getYOffset();
|
13584
|
+
|
13585
|
+
if (offset) {
|
13586
|
+
// `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
|
13587
|
+
// This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
|
13588
|
+
// top of the viewport.
|
13589
|
+
//
|
13590
|
+
// IF the number of pixels from the top of `elem` to the end of the page's content is less
|
13591
|
+
// than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
|
13592
|
+
// way down the page.
|
13593
|
+
//
|
13594
|
+
// This is often the case for elements near the bottom of the page.
|
13595
|
+
//
|
13596
|
+
// In such cases we do not need to scroll the whole `offset` up, just the difference between
|
13597
|
+
// the top of the element and the offset, which is enough to align the top of `elem` at the
|
13598
|
+
// desired position.
|
13599
|
+
var elemTop = elem.getBoundingClientRect().top;
|
13600
|
+
$window.scrollBy(0, elemTop - offset);
|
13601
|
+
}
|
13602
|
+
} else {
|
13603
|
+
$window.scrollTo(0, 0);
|
13604
|
+
}
|
13605
|
+
}
|
13606
|
+
|
13429
13607
|
function scroll() {
|
13430
13608
|
var hash = $location.hash(), elm;
|
13431
13609
|
|
13432
13610
|
// empty hash, scroll to the top of the page
|
13433
|
-
if (!hash)
|
13611
|
+
if (!hash) scrollTo(null);
|
13434
13612
|
|
13435
13613
|
// element with given id
|
13436
|
-
else if ((elm = document.getElementById(hash))) elm
|
13614
|
+
else if ((elm = document.getElementById(hash))) scrollTo(elm);
|
13437
13615
|
|
13438
13616
|
// first anchor with given name :-D
|
13439
|
-
else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) elm
|
13617
|
+
else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
|
13440
13618
|
|
13441
13619
|
// no element and hash == 'top', scroll to the top of the page
|
13442
|
-
else if (hash === 'top')
|
13620
|
+
else if (hash === 'top') scrollTo(null);
|
13443
13621
|
}
|
13444
13622
|
|
13445
13623
|
// does not scroll when user clicks on anchor link that is currently on
|
@@ -13450,7 +13628,9 @@ function $AnchorScrollProvider() {
|
|
13450
13628
|
// skip the initial scroll if $location.hash is empty
|
13451
13629
|
if (newVal === oldVal && newVal === '') return;
|
13452
13630
|
|
13453
|
-
|
13631
|
+
jqLiteDocumentLoaded(function() {
|
13632
|
+
$rootScope.$evalAsync(scroll);
|
13633
|
+
});
|
13454
13634
|
});
|
13455
13635
|
}
|
13456
13636
|
|
@@ -13558,7 +13738,7 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
13558
13738
|
return defer.promise;
|
13559
13739
|
}
|
13560
13740
|
|
13561
|
-
function resolveElementClasses(element,
|
13741
|
+
function resolveElementClasses(element, classes) {
|
13562
13742
|
var toAdd = [], toRemove = [];
|
13563
13743
|
|
13564
13744
|
var hasClasses = createMap();
|
@@ -13566,7 +13746,7 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
13566
13746
|
hasClasses[className] = true;
|
13567
13747
|
});
|
13568
13748
|
|
13569
|
-
forEach(
|
13749
|
+
forEach(classes, function(status, className) {
|
13570
13750
|
var hasClass = hasClasses[className];
|
13571
13751
|
|
13572
13752
|
// If the most recent class manipulation (via $animate) was to remove the class, and the
|
@@ -13580,7 +13760,8 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
13580
13760
|
}
|
13581
13761
|
});
|
13582
13762
|
|
13583
|
-
return (toAdd.length + toRemove.length) > 0 &&
|
13763
|
+
return (toAdd.length + toRemove.length) > 0 &&
|
13764
|
+
[toAdd.length ? toAdd : null, toRemove.length ? toRemove : null];
|
13584
13765
|
}
|
13585
13766
|
|
13586
13767
|
function cachedClassManipulation(cache, classes, op) {
|
@@ -13602,6 +13783,13 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
13602
13783
|
return currentDefer.promise;
|
13603
13784
|
}
|
13604
13785
|
|
13786
|
+
function applyStyles(element, options) {
|
13787
|
+
if (angular.isObject(options)) {
|
13788
|
+
var styles = extend(options.from || {}, options.to || {});
|
13789
|
+
element.css(styles);
|
13790
|
+
}
|
13791
|
+
}
|
13792
|
+
|
13605
13793
|
/**
|
13606
13794
|
*
|
13607
13795
|
* @ngdoc service
|
@@ -13620,6 +13808,10 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
13620
13808
|
* page}.
|
13621
13809
|
*/
|
13622
13810
|
return {
|
13811
|
+
animate : function(element, from, to) {
|
13812
|
+
applyStyles(element, { from: from, to: to });
|
13813
|
+
return asyncPromise();
|
13814
|
+
},
|
13623
13815
|
|
13624
13816
|
/**
|
13625
13817
|
*
|
@@ -13634,9 +13826,11 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
13634
13826
|
* a child (if the after element is not present)
|
13635
13827
|
* @param {DOMElement} after the sibling element which will append the element
|
13636
13828
|
* after itself
|
13829
|
+
* @param {object=} options an optional collection of styles that will be applied to the element.
|
13637
13830
|
* @return {Promise} the animation callback promise
|
13638
13831
|
*/
|
13639
|
-
enter : function(element, parent, after) {
|
13832
|
+
enter : function(element, parent, after, options) {
|
13833
|
+
applyStyles(element, options);
|
13640
13834
|
after ? after.after(element)
|
13641
13835
|
: parent.prepend(element);
|
13642
13836
|
return asyncPromise();
|
@@ -13650,9 +13844,10 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
13650
13844
|
* @description Removes the element from the DOM. When the function is called a promise
|
13651
13845
|
* is returned that will be resolved at a later time.
|
13652
13846
|
* @param {DOMElement} element the element which will be removed from the DOM
|
13847
|
+
* @param {object=} options an optional collection of options that will be applied to the element.
|
13653
13848
|
* @return {Promise} the animation callback promise
|
13654
13849
|
*/
|
13655
|
-
leave : function(element) {
|
13850
|
+
leave : function(element, options) {
|
13656
13851
|
element.remove();
|
13657
13852
|
return asyncPromise();
|
13658
13853
|
},
|
@@ -13672,12 +13867,13 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
13672
13867
|
* inserted into (if the after element is not present)
|
13673
13868
|
* @param {DOMElement} after the sibling element where the element will be
|
13674
13869
|
* positioned next to
|
13870
|
+
* @param {object=} options an optional collection of options that will be applied to the element.
|
13675
13871
|
* @return {Promise} the animation callback promise
|
13676
13872
|
*/
|
13677
|
-
move : function(element, parent, after) {
|
13873
|
+
move : function(element, parent, after, options) {
|
13678
13874
|
// Do not remove element before insert. Removing will cause data associated with the
|
13679
13875
|
// element to be dropped. Insert will implicitly do the remove.
|
13680
|
-
return this.enter(element, parent, after);
|
13876
|
+
return this.enter(element, parent, after, options);
|
13681
13877
|
},
|
13682
13878
|
|
13683
13879
|
/**
|
@@ -13690,13 +13886,14 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
13690
13886
|
* @param {DOMElement} element the element which will have the className value
|
13691
13887
|
* added to it
|
13692
13888
|
* @param {string} className the CSS class which will be added to the element
|
13889
|
+
* @param {object=} options an optional collection of options that will be applied to the element.
|
13693
13890
|
* @return {Promise} the animation callback promise
|
13694
13891
|
*/
|
13695
|
-
addClass : function(element, className) {
|
13696
|
-
return this.setClass(element, className, []);
|
13892
|
+
addClass : function(element, className, options) {
|
13893
|
+
return this.setClass(element, className, [], options);
|
13697
13894
|
},
|
13698
13895
|
|
13699
|
-
$$addClassImmediately : function
|
13896
|
+
$$addClassImmediately : function(element, className, options) {
|
13700
13897
|
element = jqLite(element);
|
13701
13898
|
className = !isString(className)
|
13702
13899
|
? (isArray(className) ? className.join(' ') : '')
|
@@ -13704,6 +13901,8 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
13704
13901
|
forEach(element, function (element) {
|
13705
13902
|
jqLiteAddClass(element, className);
|
13706
13903
|
});
|
13904
|
+
applyStyles(element, options);
|
13905
|
+
return asyncPromise();
|
13707
13906
|
},
|
13708
13907
|
|
13709
13908
|
/**
|
@@ -13716,13 +13915,14 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
13716
13915
|
* @param {DOMElement} element the element which will have the className value
|
13717
13916
|
* removed from it
|
13718
13917
|
* @param {string} className the CSS class which will be removed from the element
|
13918
|
+
* @param {object=} options an optional collection of options that will be applied to the element.
|
13719
13919
|
* @return {Promise} the animation callback promise
|
13720
13920
|
*/
|
13721
|
-
removeClass : function(element, className) {
|
13722
|
-
return this.setClass(element, [], className);
|
13921
|
+
removeClass : function(element, className, options) {
|
13922
|
+
return this.setClass(element, [], className, options);
|
13723
13923
|
},
|
13724
13924
|
|
13725
|
-
$$removeClassImmediately : function
|
13925
|
+
$$removeClassImmediately : function(element, className, options) {
|
13726
13926
|
element = jqLite(element);
|
13727
13927
|
className = !isString(className)
|
13728
13928
|
? (isArray(className) ? className.join(' ') : '')
|
@@ -13730,6 +13930,7 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
13730
13930
|
forEach(element, function (element) {
|
13731
13931
|
jqLiteRemoveClass(element, className);
|
13732
13932
|
});
|
13933
|
+
applyStyles(element, options);
|
13733
13934
|
return asyncPromise();
|
13734
13935
|
},
|
13735
13936
|
|
@@ -13744,28 +13945,24 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
13744
13945
|
* removed from it
|
13745
13946
|
* @param {string} add the CSS classes which will be added to the element
|
13746
13947
|
* @param {string} remove the CSS class which will be removed from the element
|
13948
|
+
* @param {object=} options an optional collection of options that will be applied to the element.
|
13747
13949
|
* @return {Promise} the animation callback promise
|
13748
13950
|
*/
|
13749
|
-
setClass : function(element, add, remove,
|
13951
|
+
setClass : function(element, add, remove, options) {
|
13750
13952
|
var self = this;
|
13751
13953
|
var STORAGE_KEY = '$$animateClasses';
|
13752
13954
|
var createdCache = false;
|
13753
13955
|
element = jqLite(element);
|
13754
13956
|
|
13755
|
-
if (runSynchronously) {
|
13756
|
-
// TODO(@caitp/@matsko): Remove undocumented `runSynchronously` parameter, and always
|
13757
|
-
// perform DOM manipulation asynchronously or in postDigest.
|
13758
|
-
self.$$addClassImmediately(element, add);
|
13759
|
-
self.$$removeClassImmediately(element, remove);
|
13760
|
-
return asyncPromise();
|
13761
|
-
}
|
13762
|
-
|
13763
13957
|
var cache = element.data(STORAGE_KEY);
|
13764
13958
|
if (!cache) {
|
13765
13959
|
cache = {
|
13766
|
-
classes: {}
|
13960
|
+
classes: {},
|
13961
|
+
options : options
|
13767
13962
|
};
|
13768
13963
|
createdCache = true;
|
13964
|
+
} else if (options && cache.options) {
|
13965
|
+
cache.options = angular.extend(cache.options || {}, options);
|
13769
13966
|
}
|
13770
13967
|
|
13771
13968
|
var classes = cache.classes;
|
@@ -13780,11 +13977,14 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
13780
13977
|
var cache = element.data(STORAGE_KEY);
|
13781
13978
|
element.removeData(STORAGE_KEY);
|
13782
13979
|
|
13783
|
-
|
13784
|
-
|
13785
|
-
|
13786
|
-
|
13787
|
-
|
13980
|
+
// in the event that the element is removed before postDigest
|
13981
|
+
// is run then the cache will be undefined and there will be
|
13982
|
+
// no need anymore to add or remove and of the element classes
|
13983
|
+
if (cache) {
|
13984
|
+
var classes = resolveElementClasses(element, cache.classes);
|
13985
|
+
if (classes) {
|
13986
|
+
self.$$setClassImmediately(element, classes[0], classes[1], cache.options);
|
13987
|
+
}
|
13788
13988
|
}
|
13789
13989
|
|
13790
13990
|
done();
|
@@ -13795,6 +13995,13 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
13795
13995
|
return cache.promise;
|
13796
13996
|
},
|
13797
13997
|
|
13998
|
+
$$setClassImmediately : function(element, add, remove, options) {
|
13999
|
+
add && this.$$addClassImmediately(element, add);
|
14000
|
+
remove && this.$$removeClassImmediately(element, remove);
|
14001
|
+
applyStyles(element, options);
|
14002
|
+
return asyncPromise();
|
14003
|
+
},
|
14004
|
+
|
13798
14005
|
enabled : noop,
|
13799
14006
|
cancel : noop
|
13800
14007
|
};
|
@@ -13935,11 +14142,14 @@ function Browser(window, document, $log, $sniffer) {
|
|
13935
14142
|
// URL API
|
13936
14143
|
//////////////////////////////////////////////////////////////
|
13937
14144
|
|
13938
|
-
var
|
13939
|
-
|
14145
|
+
var cachedState, lastHistoryState,
|
14146
|
+
lastBrowserUrl = location.href,
|
13940
14147
|
baseElement = document.find('base'),
|
13941
14148
|
reloadLocation = null;
|
13942
14149
|
|
14150
|
+
cacheState();
|
14151
|
+
lastHistoryState = cachedState;
|
14152
|
+
|
13943
14153
|
/**
|
13944
14154
|
* @name $browser#url
|
13945
14155
|
*
|
@@ -13974,21 +14184,26 @@ function Browser(window, document, $log, $sniffer) {
|
|
13974
14184
|
|
13975
14185
|
// setter
|
13976
14186
|
if (url) {
|
14187
|
+
var sameState = lastHistoryState === state;
|
14188
|
+
|
13977
14189
|
// Don't change anything if previous and current URLs and states match. This also prevents
|
13978
14190
|
// IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
|
13979
14191
|
// See https://github.com/angular/angular.js/commit/ffb2701
|
13980
|
-
if (lastBrowserUrl === url && (!$sniffer.history ||
|
14192
|
+
if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
|
13981
14193
|
return;
|
13982
14194
|
}
|
13983
14195
|
var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
|
13984
14196
|
lastBrowserUrl = url;
|
14197
|
+
lastHistoryState = state;
|
13985
14198
|
// Don't use history API if only the hash changed
|
13986
14199
|
// due to a bug in IE10/IE11 which leads
|
13987
14200
|
// to not firing a `hashchange` nor `popstate` event
|
13988
14201
|
// in some cases (see #9143).
|
13989
|
-
if ($sniffer.history && (!sameBase ||
|
14202
|
+
if ($sniffer.history && (!sameBase || !sameState)) {
|
13990
14203
|
history[replace ? 'replaceState' : 'pushState'](state, '', url);
|
13991
|
-
|
14204
|
+
cacheState();
|
14205
|
+
// Do the assignment again so that those two variables are referentially identical.
|
14206
|
+
lastHistoryState = cachedState;
|
13992
14207
|
} else {
|
13993
14208
|
if (!sameBase) {
|
13994
14209
|
reloadLocation = url;
|
@@ -14020,20 +14235,40 @@ function Browser(window, document, $log, $sniffer) {
|
|
14020
14235
|
* @returns {object} state
|
14021
14236
|
*/
|
14022
14237
|
self.state = function() {
|
14023
|
-
return
|
14238
|
+
return cachedState;
|
14024
14239
|
};
|
14025
14240
|
|
14026
14241
|
var urlChangeListeners = [],
|
14027
14242
|
urlChangeInit = false;
|
14028
14243
|
|
14244
|
+
function cacheStateAndFireUrlChange() {
|
14245
|
+
cacheState();
|
14246
|
+
fireUrlChange();
|
14247
|
+
}
|
14248
|
+
|
14249
|
+
// This variable should be used *only* inside the cacheState function.
|
14250
|
+
var lastCachedState = null;
|
14251
|
+
function cacheState() {
|
14252
|
+
// This should be the only place in $browser where `history.state` is read.
|
14253
|
+
cachedState = window.history.state;
|
14254
|
+
cachedState = isUndefined(cachedState) ? null : cachedState;
|
14255
|
+
|
14256
|
+
// Prevent callbacks fo fire twice if both hashchange & popstate were fired.
|
14257
|
+
if (equals(cachedState, lastCachedState)) {
|
14258
|
+
cachedState = lastCachedState;
|
14259
|
+
}
|
14260
|
+
lastCachedState = cachedState;
|
14261
|
+
}
|
14262
|
+
|
14029
14263
|
function fireUrlChange() {
|
14030
|
-
if (lastBrowserUrl === self.url() && lastHistoryState ===
|
14264
|
+
if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
|
14031
14265
|
return;
|
14032
14266
|
}
|
14033
14267
|
|
14034
14268
|
lastBrowserUrl = self.url();
|
14269
|
+
lastHistoryState = cachedState;
|
14035
14270
|
forEach(urlChangeListeners, function(listener) {
|
14036
|
-
listener(self.url(),
|
14271
|
+
listener(self.url(), cachedState);
|
14037
14272
|
});
|
14038
14273
|
}
|
14039
14274
|
|
@@ -14066,9 +14301,9 @@ function Browser(window, document, $log, $sniffer) {
|
|
14066
14301
|
// changed by push/replaceState
|
14067
14302
|
|
14068
14303
|
// html5 history api - popstate event
|
14069
|
-
if ($sniffer.history) jqLite(window).on('popstate',
|
14304
|
+
if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
|
14070
14305
|
// hashchange event
|
14071
|
-
jqLite(window).on('hashchange',
|
14306
|
+
jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
|
14072
14307
|
|
14073
14308
|
urlChangeInit = true;
|
14074
14309
|
}
|
@@ -14109,6 +14344,14 @@ function Browser(window, document, $log, $sniffer) {
|
|
14109
14344
|
var lastCookieString = '';
|
14110
14345
|
var cookiePath = self.baseHref();
|
14111
14346
|
|
14347
|
+
function safeDecodeURIComponent(str) {
|
14348
|
+
try {
|
14349
|
+
return decodeURIComponent(str);
|
14350
|
+
} catch (e) {
|
14351
|
+
return str;
|
14352
|
+
}
|
14353
|
+
}
|
14354
|
+
|
14112
14355
|
/**
|
14113
14356
|
* @name $browser#cookies
|
14114
14357
|
*
|
@@ -14162,12 +14405,12 @@ function Browser(window, document, $log, $sniffer) {
|
|
14162
14405
|
cookie = cookieArray[i];
|
14163
14406
|
index = cookie.indexOf('=');
|
14164
14407
|
if (index > 0) { //ignore nameless cookies
|
14165
|
-
name =
|
14408
|
+
name = safeDecodeURIComponent(cookie.substring(0, index));
|
14166
14409
|
// the first value that is seen for a cookie is the most
|
14167
14410
|
// specific one. values for the same cookie name that
|
14168
14411
|
// follow are for less specific paths.
|
14169
14412
|
if (lastCookies[name] === undefined) {
|
14170
|
-
lastCookies[name] =
|
14413
|
+
lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
|
14171
14414
|
}
|
14172
14415
|
}
|
14173
14416
|
}
|
@@ -14692,6 +14935,7 @@ function $TemplateCacheProvider() {
|
|
14692
14935
|
* // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
|
14693
14936
|
* transclude: false,
|
14694
14937
|
* restrict: 'A',
|
14938
|
+
* templateNamespace: 'html',
|
14695
14939
|
* scope: false,
|
14696
14940
|
* controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
|
14697
14941
|
* controllerAs: 'stringAlias',
|
@@ -14746,8 +14990,8 @@ function $TemplateCacheProvider() {
|
|
14746
14990
|
* When this property is set to true, the HTML compiler will collect DOM nodes between
|
14747
14991
|
* nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
|
14748
14992
|
* together as the directive elements. It is recomended that this feature be used on directives
|
14749
|
-
* which are not strictly behavioural (such as {@link
|
14750
|
-
* do not manipulate or replace child nodes (such as {@link
|
14993
|
+
* which are not strictly behavioural (such as {@link ngClick}), and which
|
14994
|
+
* do not manipulate or replace child nodes (such as {@link ngInclude}).
|
14751
14995
|
*
|
14752
14996
|
* #### `priority`
|
14753
14997
|
* When there are multiple directives defined on a single DOM element, sometimes it
|
@@ -14760,7 +15004,8 @@ function $TemplateCacheProvider() {
|
|
14760
15004
|
* #### `terminal`
|
14761
15005
|
* If set to true then the current `priority` will be the last set of directives
|
14762
15006
|
* which will execute (any directives at the current priority will still execute
|
14763
|
-
* as the order of execution on same `priority` is undefined).
|
15007
|
+
* as the order of execution on same `priority` is undefined). Note that expressions
|
15008
|
+
* and other directives used in the directive's template will also be excluded from execution.
|
14764
15009
|
*
|
14765
15010
|
* #### `scope`
|
14766
15011
|
* **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the
|
@@ -14907,7 +15152,7 @@ function $TemplateCacheProvider() {
|
|
14907
15152
|
* You can specify `templateUrl` as a string representing the URL or as a function which takes two
|
14908
15153
|
* arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
|
14909
15154
|
* a string value representing the url. In either case, the template URL is passed through {@link
|
14910
|
-
*
|
15155
|
+
* $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
|
14911
15156
|
*
|
14912
15157
|
*
|
14913
15158
|
* #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0)
|
@@ -14917,7 +15162,7 @@ function $TemplateCacheProvider() {
|
|
14917
15162
|
* * `false` - the template will replace the contents of the directive's element.
|
14918
15163
|
*
|
14919
15164
|
* The replacement process migrates all of the attributes / classes from the old element to the new
|
14920
|
-
* one. See the {@link guide/directive#
|
15165
|
+
* one. See the {@link guide/directive#template-expanding-directive
|
14921
15166
|
* Directives Guide} for an example.
|
14922
15167
|
*
|
14923
15168
|
* There are very few scenarios where element replacement is required for the application function,
|
@@ -15072,7 +15317,7 @@ function $TemplateCacheProvider() {
|
|
15072
15317
|
* then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
|
15073
15318
|
* object that contains the compiled DOM, which is linked to the correct transclusion scope.
|
15074
15319
|
*
|
15075
|
-
* When you call a transclusion function you can pass in a **clone attach function**. This function
|
15320
|
+
* When you call a transclusion function you can pass in a **clone attach function**. This function accepts
|
15076
15321
|
* two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
|
15077
15322
|
* content and the `scope` is the newly created transclusion scope, to which the clone is bound.
|
15078
15323
|
*
|
@@ -15692,12 +15937,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15692
15937
|
* @param {string} key Normalized key. (ie ngAttribute) .
|
15693
15938
|
* @param {function(interpolatedValue)} fn Function that will be called whenever
|
15694
15939
|
the interpolated value of the attribute changes.
|
15695
|
-
* See {@link
|
15940
|
+
* See the {@link guide/directive#text-and-attribute-bindings Directives} guide for more info.
|
15696
15941
|
* @returns {function()} Returns a deregistration function for this observer.
|
15697
15942
|
*/
|
15698
15943
|
$observe: function(key, fn) {
|
15699
15944
|
var attrs = this,
|
15700
|
-
$$observers = (attrs.$$observers || (attrs.$$observers =
|
15945
|
+
$$observers = (attrs.$$observers || (attrs.$$observers = createMap())),
|
15701
15946
|
listeners = ($$observers[key] || ($$observers[key] = []));
|
15702
15947
|
|
15703
15948
|
listeners.push(fn);
|
@@ -17373,6 +17618,14 @@ function $DocumentProvider(){
|
|
17373
17618
|
* This example will override the normal action of `$exceptionHandler`, to make angular
|
17374
17619
|
* exceptions fail hard when they happen, instead of just logging to the console.
|
17375
17620
|
*
|
17621
|
+
* <hr />
|
17622
|
+
* Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`
|
17623
|
+
* methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler}
|
17624
|
+
* (unless executed during a digest).
|
17625
|
+
*
|
17626
|
+
* If you wish, you can manually delegate exceptions, e.g.
|
17627
|
+
* `try { ... } catch(e) { $exceptionHandler(e); }`
|
17628
|
+
*
|
17376
17629
|
* @param {Error} exception Exception associated with the error.
|
17377
17630
|
* @param {string=} cause optional information about the context in which
|
17378
17631
|
* the error was thrown.
|
@@ -17540,7 +17793,7 @@ function $HttpProvider() {
|
|
17540
17793
|
* @description
|
17541
17794
|
*
|
17542
17795
|
* Configure $http service to combine processing of multiple http responses received at around
|
17543
|
-
* the same time via {@link ng.$rootScope
|
17796
|
+
* the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in
|
17544
17797
|
* significant performance improvement for bigger applications that make many HTTP requests
|
17545
17798
|
* concurrently (common during application bootstrap).
|
17546
17799
|
*
|
@@ -17616,7 +17869,21 @@ function $HttpProvider() {
|
|
17616
17869
|
* with two $http specific methods: `success` and `error`.
|
17617
17870
|
*
|
17618
17871
|
* ```js
|
17619
|
-
*
|
17872
|
+
* // Simple GET request example :
|
17873
|
+
* $http.get('/someUrl').
|
17874
|
+
* success(function(data, status, headers, config) {
|
17875
|
+
* // this callback will be called asynchronously
|
17876
|
+
* // when the response is available
|
17877
|
+
* }).
|
17878
|
+
* error(function(data, status, headers, config) {
|
17879
|
+
* // called asynchronously if an error occurs
|
17880
|
+
* // or server returns response with an error status.
|
17881
|
+
* });
|
17882
|
+
* ```
|
17883
|
+
*
|
17884
|
+
* ```js
|
17885
|
+
* // Simple POST request example (passing data) :
|
17886
|
+
* $http.post('/someUrl', {msg:'hello word!'}).
|
17620
17887
|
* success(function(data, status, headers, config) {
|
17621
17888
|
* // this callback will be called asynchronously
|
17622
17889
|
* // when the response is available
|
@@ -17627,6 +17894,7 @@ function $HttpProvider() {
|
|
17627
17894
|
* });
|
17628
17895
|
* ```
|
17629
17896
|
*
|
17897
|
+
*
|
17630
17898
|
* Since the returned value of calling the $http function is a `promise`, you can also use
|
17631
17899
|
* the `then` method to register callbacks, and these callbacks will receive a single argument –
|
17632
17900
|
* an object representing the response. See the API signature and type info below for more
|
@@ -17779,7 +18047,7 @@ function $HttpProvider() {
|
|
17779
18047
|
*
|
17780
18048
|
* You can change the default cache to a new object (built with
|
17781
18049
|
* {@link ng.$cacheFactory `$cacheFactory`}) by updating the
|
17782
|
-
* {@link ng.$http#
|
18050
|
+
* {@link ng.$http#defaults `$http.defaults.cache`} property. All requests who set
|
17783
18051
|
* their `cache` property to `true` will now use this cache object.
|
17784
18052
|
*
|
17785
18053
|
* If you set the default cache to `false` then only requests that specify their own custom
|
@@ -18141,9 +18409,12 @@ function $HttpProvider() {
|
|
18141
18409
|
|
18142
18410
|
function transformResponse(response) {
|
18143
18411
|
// make a copy since the response must be cacheable
|
18144
|
-
var resp = extend({}, response
|
18145
|
-
|
18146
|
-
|
18412
|
+
var resp = extend({}, response);
|
18413
|
+
if (!response.data) {
|
18414
|
+
resp.data = response.data;
|
18415
|
+
} else {
|
18416
|
+
resp.data = transformData(response.data, response.headers, config.transformResponse);
|
18417
|
+
}
|
18147
18418
|
return (isSuccess(response.status))
|
18148
18419
|
? resp
|
18149
18420
|
: $q.reject(resp);
|
@@ -18886,16 +19157,13 @@ function $InterpolateProvider() {
|
|
18886
19157
|
return '';
|
18887
19158
|
}
|
18888
19159
|
switch (typeof value) {
|
18889
|
-
case 'string':
|
19160
|
+
case 'string':
|
18890
19161
|
break;
|
18891
|
-
|
18892
|
-
case 'number': {
|
19162
|
+
case 'number':
|
18893
19163
|
value = '' + value;
|
18894
19164
|
break;
|
18895
|
-
|
18896
|
-
default: {
|
19165
|
+
default:
|
18897
19166
|
value = toJson(value);
|
18898
|
-
}
|
18899
19167
|
}
|
18900
19168
|
|
18901
19169
|
return value;
|
@@ -19717,6 +19985,7 @@ var locationPrototype = {
|
|
19717
19985
|
search = search.toString();
|
19718
19986
|
this.$$search = parseKeyValue(search);
|
19719
19987
|
} else if (isObject(search)) {
|
19988
|
+
search = copy(search, {});
|
19720
19989
|
// remove object undefined or null properties
|
19721
19990
|
forEach(search, function(value, key) {
|
19722
19991
|
if (value == null) delete search[key];
|
@@ -19902,8 +20171,8 @@ function $LocationProvider(){
|
|
19902
20171
|
* whether or not a <base> tag is required to be present. If `enabled` and `requireBase` are
|
19903
20172
|
* true, and a base tag is not present, an error will be thrown when `$location` is injected.
|
19904
20173
|
* See the {@link guide/$location $location guide for more information}
|
19905
|
-
* - **rewriteLinks** - `{boolean}` - (default: `
|
19906
|
-
*
|
20174
|
+
* - **rewriteLinks** - `{boolean}` - (default: `true`) When html5Mode is enabled,
|
20175
|
+
* enables/disables url rewriting for relative links.
|
19907
20176
|
*
|
19908
20177
|
* @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
|
19909
20178
|
*/
|
@@ -19914,7 +20183,7 @@ function $LocationProvider(){
|
|
19914
20183
|
} else if (isObject(mode)) {
|
19915
20184
|
|
19916
20185
|
if (isBoolean(mode.enabled)) {
|
19917
|
-
html5Mode.enabled =
|
20186
|
+
html5Mode.enabled = mode.enabled;
|
19918
20187
|
}
|
19919
20188
|
|
19920
20189
|
if (isBoolean(mode.requireBase)) {
|
@@ -19922,7 +20191,7 @@ function $LocationProvider(){
|
|
19922
20191
|
}
|
19923
20192
|
|
19924
20193
|
if (isBoolean(mode.rewriteLinks)) {
|
19925
|
-
html5Mode.rewriteLinks =
|
20194
|
+
html5Mode.rewriteLinks = mode.rewriteLinks;
|
19926
20195
|
}
|
19927
20196
|
|
19928
20197
|
return this;
|
@@ -19941,7 +20210,7 @@ function $LocationProvider(){
|
|
19941
20210
|
* This change can be prevented by calling
|
19942
20211
|
* `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
|
19943
20212
|
* details about event object. Upon successful change
|
19944
|
-
* {@link ng.$location
|
20213
|
+
* {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
|
19945
20214
|
*
|
19946
20215
|
* The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
|
19947
20216
|
* the browser supports the HTML5 History API.
|
@@ -20093,9 +20362,10 @@ function $LocationProvider(){
|
|
20093
20362
|
var oldUrl = $browser.url();
|
20094
20363
|
var oldState = $browser.state();
|
20095
20364
|
var currentReplace = $location.$$replace;
|
20365
|
+
var urlOrStateChanged = oldUrl !== $location.absUrl() ||
|
20366
|
+
($location.$$html5 && $sniffer.history && oldState !== $location.$$state);
|
20096
20367
|
|
20097
|
-
if (initializing ||
|
20098
|
-
($location.$$html5 && $sniffer.history && oldState !== $location.$$state)) {
|
20368
|
+
if (initializing || urlOrStateChanged) {
|
20099
20369
|
initializing = false;
|
20100
20370
|
|
20101
20371
|
$rootScope.$evalAsync(function() {
|
@@ -20104,8 +20374,10 @@ function $LocationProvider(){
|
|
20104
20374
|
$location.$$parse(oldUrl);
|
20105
20375
|
$location.$$state = oldState;
|
20106
20376
|
} else {
|
20107
|
-
|
20108
|
-
|
20377
|
+
if (urlOrStateChanged) {
|
20378
|
+
setBrowserUrlWithFallback($location.absUrl(), currentReplace,
|
20379
|
+
oldState === $location.$$state ? null : $location.$$state);
|
20380
|
+
}
|
20109
20381
|
afterLocationChange(oldUrl, oldState);
|
20110
20382
|
}
|
20111
20383
|
});
|
@@ -20387,7 +20659,6 @@ CONSTANTS['this'].sharedGetter = true;
|
|
20387
20659
|
|
20388
20660
|
//Operators - will be wrapped by binaryFn/unaryFn/assignment/filter
|
20389
20661
|
var OPERATORS = extend(createMap(), {
|
20390
|
-
/* jshint bitwise : false */
|
20391
20662
|
'+':function(self, locals, a,b){
|
20392
20663
|
a=a(self, locals); b=b(self, locals);
|
20393
20664
|
if (isDefined(a)) {
|
@@ -20404,7 +20675,6 @@ var OPERATORS = extend(createMap(), {
|
|
20404
20675
|
'*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
|
20405
20676
|
'/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
|
20406
20677
|
'%':function(self, locals, a,b){return a(self, locals)%b(self, locals);},
|
20407
|
-
'^':function(self, locals, a,b){return a(self, locals)^b(self, locals);},
|
20408
20678
|
'===':function(self, locals, a, b){return a(self, locals)===b(self, locals);},
|
20409
20679
|
'!==':function(self, locals, a, b){return a(self, locals)!==b(self, locals);},
|
20410
20680
|
'==':function(self, locals, a,b){return a(self, locals)==b(self, locals);},
|
@@ -20415,14 +20685,12 @@ var OPERATORS = extend(createMap(), {
|
|
20415
20685
|
'>=':function(self, locals, a,b){return a(self, locals)>=b(self, locals);},
|
20416
20686
|
'&&':function(self, locals, a,b){return a(self, locals)&&b(self, locals);},
|
20417
20687
|
'||':function(self, locals, a,b){return a(self, locals)||b(self, locals);},
|
20418
|
-
'&':function(self, locals, a,b){return a(self, locals)&b(self, locals);},
|
20419
20688
|
'!':function(self, locals, a){return !a(self, locals);},
|
20420
20689
|
|
20421
20690
|
//Tokenized as operators but parsed as assignment/filters
|
20422
20691
|
'=':true,
|
20423
20692
|
'|':true
|
20424
20693
|
});
|
20425
|
-
/* jshint bitwise: true */
|
20426
20694
|
var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
|
20427
20695
|
|
20428
20696
|
|
@@ -21460,16 +21728,17 @@ function $ParseProvider() {
|
|
21460
21728
|
}
|
21461
21729
|
|
21462
21730
|
function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
|
21463
|
-
var unwatch;
|
21731
|
+
var unwatch, lastValue;
|
21464
21732
|
return unwatch = scope.$watch(function oneTimeWatch(scope) {
|
21465
21733
|
return parsedExpression(scope);
|
21466
21734
|
}, function oneTimeListener(value, old, scope) {
|
21735
|
+
lastValue = value;
|
21467
21736
|
if (isFunction(listener)) {
|
21468
21737
|
listener.call(this, value, old, scope);
|
21469
21738
|
}
|
21470
21739
|
if (isAllDefined(value)) {
|
21471
21740
|
scope.$$postDigest(function () {
|
21472
|
-
if(isAllDefined(
|
21741
|
+
if(isAllDefined(lastValue)) unwatch();
|
21473
21742
|
});
|
21474
21743
|
}
|
21475
21744
|
}, objectEquality);
|
@@ -21545,24 +21814,27 @@ function $ParseProvider() {
|
|
21545
21814
|
* It can be used like so:
|
21546
21815
|
*
|
21547
21816
|
* ```js
|
21548
|
-
*
|
21549
|
-
* //
|
21550
|
-
*
|
21551
|
-
*
|
21552
|
-
*
|
21553
|
-
*
|
21554
|
-
*
|
21555
|
-
*
|
21556
|
-
*
|
21557
|
-
*
|
21558
|
-
*
|
21559
|
-
*
|
21560
|
-
*
|
21561
|
-
*
|
21562
|
-
*
|
21563
|
-
*
|
21817
|
+
* // for the purpose of this example let's assume that variables `$q` and `okToGreet`
|
21818
|
+
* // are available in the current lexical scope (they could have been injected or passed in).
|
21819
|
+
*
|
21820
|
+
* function asyncGreet(name) {
|
21821
|
+
* // perform some asynchronous operation, resolve or reject the promise when appropriate.
|
21822
|
+
* return $q(function(resolve, reject) {
|
21823
|
+
* setTimeout(function() {
|
21824
|
+
* if (okToGreet(name)) {
|
21825
|
+
* resolve('Hello, ' + name + '!');
|
21826
|
+
* } else {
|
21827
|
+
* reject('Greeting ' + name + ' is not allowed.');
|
21828
|
+
* }
|
21829
|
+
* }, 1000);
|
21830
|
+
* });
|
21831
|
+
* }
|
21832
|
+
*
|
21833
|
+
* var promise = asyncGreet('Robin Hood');
|
21834
|
+
* promise.then(function(greeting) {
|
21835
|
+
* alert('Success: ' + greeting);
|
21564
21836
|
* }, function(reason) {
|
21565
|
-
*
|
21837
|
+
* alert('Failed: ' + reason);
|
21566
21838
|
* });
|
21567
21839
|
* ```
|
21568
21840
|
*
|
@@ -21578,7 +21850,7 @@ function $ParseProvider() {
|
|
21578
21850
|
* asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
|
21579
21851
|
*
|
21580
21852
|
* ```js
|
21581
|
-
* // for the purpose of this example let's assume that variables `$q
|
21853
|
+
* // for the purpose of this example let's assume that variables `$q` and `okToGreet`
|
21582
21854
|
* // are available in the current lexical scope (they could have been injected or passed in).
|
21583
21855
|
*
|
21584
21856
|
* function asyncGreet(name) {
|
@@ -23918,7 +24190,7 @@ function $SceDelegateProvider() {
|
|
23918
24190
|
*
|
23919
24191
|
* As of version 1.2, Angular ships with SCE enabled by default.
|
23920
24192
|
*
|
23921
|
-
* Note: When enabled (the default),
|
24193
|
+
* Note: When enabled (the default), IE<11 in quirks mode is not supported. In this mode, IE<11 allow
|
23922
24194
|
* one to execute arbitrary javascript by the use of the expression() syntax. Refer
|
23923
24195
|
* <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
|
23924
24196
|
* You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
|
@@ -23965,7 +24237,7 @@ function $SceDelegateProvider() {
|
|
23965
24237
|
*
|
23966
24238
|
* In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
|
23967
24239
|
* $sce.getTrusted(context, value)} rather than to the value directly. Directives use {@link
|
23968
|
-
* ng.$sce#
|
24240
|
+
* ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
|
23969
24241
|
* {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
|
23970
24242
|
*
|
23971
24243
|
* As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
|
@@ -24235,13 +24507,13 @@ function $SceProvider() {
|
|
24235
24507
|
* sce.js and sceSpecs.js would need to be aware of this detail.
|
24236
24508
|
*/
|
24237
24509
|
|
24238
|
-
this.$get = ['$
|
24239
|
-
$
|
24240
|
-
// Prereq: Ensure that we're not running in
|
24510
|
+
this.$get = ['$document', '$parse', '$sceDelegate', function(
|
24511
|
+
$document, $parse, $sceDelegate) {
|
24512
|
+
// Prereq: Ensure that we're not running in IE<11 quirks mode. In that mode, IE < 11 allow
|
24241
24513
|
// the "expression(javascript expression)" syntax which is insecure.
|
24242
|
-
if (enabled && $
|
24514
|
+
if (enabled && $document[0].documentMode < 8) {
|
24243
24515
|
throw $sceMinErr('iequirks',
|
24244
|
-
'Strict Contextual Escaping does not support Internet Explorer version <
|
24516
|
+
'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' +
|
24245
24517
|
'mode. You can fix this by adding the text <!doctype html> to the top of your HTML ' +
|
24246
24518
|
'document. See http://docs.angularjs.org/api/ng.$sce for more information.');
|
24247
24519
|
}
|
@@ -24464,7 +24736,7 @@ function $SceProvider() {
|
|
24464
24736
|
*
|
24465
24737
|
* @description
|
24466
24738
|
* Shorthand method. `$sce.parseAsHtml(expression string)` →
|
24467
|
-
* {@link ng.$sce#
|
24739
|
+
* {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`}
|
24468
24740
|
*
|
24469
24741
|
* @param {string} expression String expression to compile.
|
24470
24742
|
* @returns {function(context, locals)} a function which represents the compiled expression:
|
@@ -24481,7 +24753,7 @@ function $SceProvider() {
|
|
24481
24753
|
*
|
24482
24754
|
* @description
|
24483
24755
|
* Shorthand method. `$sce.parseAsCss(value)` →
|
24484
|
-
* {@link ng.$sce#
|
24756
|
+
* {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`}
|
24485
24757
|
*
|
24486
24758
|
* @param {string} expression String expression to compile.
|
24487
24759
|
* @returns {function(context, locals)} a function which represents the compiled expression:
|
@@ -24498,7 +24770,7 @@ function $SceProvider() {
|
|
24498
24770
|
*
|
24499
24771
|
* @description
|
24500
24772
|
* Shorthand method. `$sce.parseAsUrl(value)` →
|
24501
|
-
* {@link ng.$sce#
|
24773
|
+
* {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`}
|
24502
24774
|
*
|
24503
24775
|
* @param {string} expression String expression to compile.
|
24504
24776
|
* @returns {function(context, locals)} a function which represents the compiled expression:
|
@@ -24515,7 +24787,7 @@ function $SceProvider() {
|
|
24515
24787
|
*
|
24516
24788
|
* @description
|
24517
24789
|
* Shorthand method. `$sce.parseAsResourceUrl(value)` →
|
24518
|
-
* {@link ng.$sce#
|
24790
|
+
* {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`}
|
24519
24791
|
*
|
24520
24792
|
* @param {string} expression String expression to compile.
|
24521
24793
|
* @returns {function(context, locals)} a function which represents the compiled expression:
|
@@ -24532,7 +24804,7 @@ function $SceProvider() {
|
|
24532
24804
|
*
|
24533
24805
|
* @description
|
24534
24806
|
* Shorthand method. `$sce.parseAsJs(value)` →
|
24535
|
-
* {@link ng.$sce#
|
24807
|
+
* {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`}
|
24536
24808
|
*
|
24537
24809
|
* @param {string} expression String expression to compile.
|
24538
24810
|
* @returns {function(context, locals)} a function which represents the compiled expression:
|
@@ -24586,7 +24858,6 @@ function $SnifferProvider() {
|
|
24586
24858
|
int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
|
24587
24859
|
boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
|
24588
24860
|
document = $document[0] || {},
|
24589
|
-
documentMode = document.documentMode,
|
24590
24861
|
vendorPrefix,
|
24591
24862
|
vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/,
|
24592
24863
|
bodyStyle = document.body && document.body.style,
|
@@ -24646,9 +24917,7 @@ function $SnifferProvider() {
|
|
24646
24917
|
vendorPrefix: vendorPrefix,
|
24647
24918
|
transitions : transitions,
|
24648
24919
|
animations : animations,
|
24649
|
-
android: android
|
24650
|
-
msie : msie,
|
24651
|
-
msieDocumentMode: documentMode
|
24920
|
+
android: android
|
24652
24921
|
};
|
24653
24922
|
}];
|
24654
24923
|
}
|
@@ -25353,17 +25622,17 @@ function filterFilter() {
|
|
25353
25622
|
}
|
25354
25623
|
|
25355
25624
|
var search = function(obj, text){
|
25356
|
-
if (typeof text
|
25625
|
+
if (typeof text === 'string' && text.charAt(0) === '!') {
|
25357
25626
|
return !search(obj, text.substr(1));
|
25358
25627
|
}
|
25359
25628
|
switch (typeof obj) {
|
25360
|
-
case
|
25361
|
-
case
|
25362
|
-
case
|
25629
|
+
case 'boolean':
|
25630
|
+
case 'number':
|
25631
|
+
case 'string':
|
25363
25632
|
return comparator(obj, text);
|
25364
|
-
case
|
25633
|
+
case 'object':
|
25365
25634
|
switch (typeof text) {
|
25366
|
-
case
|
25635
|
+
case 'object':
|
25367
25636
|
return comparator(obj, text);
|
25368
25637
|
default:
|
25369
25638
|
for ( var objKey in obj) {
|
@@ -25374,7 +25643,7 @@ function filterFilter() {
|
|
25374
25643
|
break;
|
25375
25644
|
}
|
25376
25645
|
return false;
|
25377
|
-
case
|
25646
|
+
case 'array':
|
25378
25647
|
for ( var i = 0; i < obj.length; i++) {
|
25379
25648
|
if (search(obj[i], text)) {
|
25380
25649
|
return true;
|
@@ -25386,13 +25655,13 @@ function filterFilter() {
|
|
25386
25655
|
}
|
25387
25656
|
};
|
25388
25657
|
switch (typeof expression) {
|
25389
|
-
case
|
25390
|
-
case
|
25391
|
-
case
|
25658
|
+
case 'boolean':
|
25659
|
+
case 'number':
|
25660
|
+
case 'string':
|
25392
25661
|
// Set up expression object and fall through
|
25393
25662
|
expression = {$:expression};
|
25394
25663
|
// jshint -W086
|
25395
|
-
case
|
25664
|
+
case 'object':
|
25396
25665
|
// jshint +W086
|
25397
25666
|
for (var key in expression) {
|
25398
25667
|
(function(path) {
|
@@ -25431,6 +25700,7 @@ function filterFilter() {
|
|
25431
25700
|
*
|
25432
25701
|
* @param {number} amount Input to filter.
|
25433
25702
|
* @param {string=} symbol Currency symbol or identifier to be displayed.
|
25703
|
+
* @param {number=} fractionSize Number of decimal places to round the amount to.
|
25434
25704
|
* @returns {string} Formatted number.
|
25435
25705
|
*
|
25436
25706
|
*
|
@@ -25446,13 +25716,15 @@ function filterFilter() {
|
|
25446
25716
|
<div ng-controller="ExampleController">
|
25447
25717
|
<input type="number" ng-model="amount"> <br>
|
25448
25718
|
default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
|
25449
|
-
custom currency identifier (USD$): <span>{{amount | currency:"USD$"}}</span>
|
25719
|
+
custom currency identifier (USD$): <span id="currency-custom">{{amount | currency:"USD$"}}</span>
|
25720
|
+
no fractions (0): <span id="currency-no-fractions">{{amount | currency:"USD$":0}}</span>
|
25450
25721
|
</div>
|
25451
25722
|
</file>
|
25452
25723
|
<file name="protractor.js" type="protractor">
|
25453
25724
|
it('should init with 1234.56', function() {
|
25454
25725
|
expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
|
25455
|
-
expect(element(by.
|
25726
|
+
expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56');
|
25727
|
+
expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235');
|
25456
25728
|
});
|
25457
25729
|
it('should update', function() {
|
25458
25730
|
if (browser.params.browser == 'safari') {
|
@@ -25463,7 +25735,8 @@ function filterFilter() {
|
|
25463
25735
|
element(by.model('amount')).clear();
|
25464
25736
|
element(by.model('amount')).sendKeys('-1234');
|
25465
25737
|
expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)');
|
25466
|
-
expect(element(by.
|
25738
|
+
expect(element(by.id('currency-custom')).getText()).toBe('(USD$1,234.00)');
|
25739
|
+
expect(element(by.id('currency-no-fractions')).getText()).toBe('(USD$1,234)');
|
25467
25740
|
});
|
25468
25741
|
</file>
|
25469
25742
|
</example>
|
@@ -25471,13 +25744,20 @@ function filterFilter() {
|
|
25471
25744
|
currencyFilter.$inject = ['$locale'];
|
25472
25745
|
function currencyFilter($locale) {
|
25473
25746
|
var formats = $locale.NUMBER_FORMATS;
|
25474
|
-
return function(amount, currencySymbol){
|
25475
|
-
if (isUndefined(currencySymbol))
|
25747
|
+
return function(amount, currencySymbol, fractionSize){
|
25748
|
+
if (isUndefined(currencySymbol)) {
|
25749
|
+
currencySymbol = formats.CURRENCY_SYM;
|
25750
|
+
}
|
25751
|
+
|
25752
|
+
if (isUndefined(fractionSize)) {
|
25753
|
+
// TODO: read the default value from the locale file
|
25754
|
+
fractionSize = 2;
|
25755
|
+
}
|
25476
25756
|
|
25477
25757
|
// if null or undefined pass it through
|
25478
25758
|
return (amount == null)
|
25479
25759
|
? amount
|
25480
|
-
: formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP,
|
25760
|
+
: formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize).
|
25481
25761
|
replace(/\u00A4/g, currencySymbol);
|
25482
25762
|
};
|
25483
25763
|
}
|
@@ -25994,7 +26274,7 @@ var uppercaseFilter = valueFn(uppercase);
|
|
25994
26274
|
<p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
|
25995
26275
|
Limit {{letters}} to: <input type="number" step="1" ng-model="letterLimit">
|
25996
26276
|
<p>Output letters: {{ letters | limitTo:letterLimit }}</p>
|
25997
|
-
Limit {{longNumber}} to: <input type="
|
26277
|
+
Limit {{longNumber}} to: <input type="number" step="1" ng-model="longNumberLimit">
|
25998
26278
|
<p>Output long number: {{ longNumber | limitTo:longNumberLimit }}</p>
|
25999
26279
|
</div>
|
26000
26280
|
</file>
|
@@ -27231,15 +27511,13 @@ var formDirectiveFactory = function(isNgForm) {
|
|
27231
27511
|
parentFormCtrl.$$renameControl(controller, alias);
|
27232
27512
|
});
|
27233
27513
|
}
|
27234
|
-
|
27235
|
-
|
27236
|
-
|
27237
|
-
|
27238
|
-
|
27239
|
-
|
27240
|
-
|
27241
|
-
});
|
27242
|
-
}
|
27514
|
+
formElement.on('$destroy', function() {
|
27515
|
+
parentFormCtrl.$removeControl(controller);
|
27516
|
+
if (alias) {
|
27517
|
+
setter(scope, alias, undefined, alias);
|
27518
|
+
}
|
27519
|
+
extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
|
27520
|
+
});
|
27243
27521
|
}
|
27244
27522
|
};
|
27245
27523
|
}
|
@@ -30486,7 +30764,7 @@ var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate
|
|
30486
30764
|
*
|
30487
30765
|
* You may also bypass sanitization for values you know are safe. To do so, bind to
|
30488
30766
|
* an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}. See the example
|
30489
|
-
* under {@link ng.$sce#
|
30767
|
+
* under {@link ng.$sce#show-me-an-example-using-sce- Strict Contextual Escaping (SCE)}.
|
30490
30768
|
*
|
30491
30769
|
* Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
|
30492
30770
|
* will have an exception (instead of an exploit.)
|
@@ -30798,8 +31076,8 @@ function classDirective(name, selector) {
|
|
30798
31076
|
The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
|
30799
31077
|
Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
|
30800
31078
|
any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
|
30801
|
-
to view the step by step details of {@link
|
30802
|
-
{@link
|
31079
|
+
to view the step by step details of {@link ng.$animate#addClass $animate.addClass} and
|
31080
|
+
{@link ng.$animate#removeClass $animate.removeClass}.
|
30803
31081
|
*/
|
30804
31082
|
var ngClassDirective = classDirective('', true);
|
30805
31083
|
|
@@ -31205,7 +31483,7 @@ var ngControllerDirective = [function() {
|
|
31205
31483
|
* @description
|
31206
31484
|
* Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
|
31207
31485
|
*
|
31208
|
-
* This is necessary when developing things like Google Chrome Extensions.
|
31486
|
+
* This is necessary when developing things like Google Chrome Extensions or Universal Windows Apps.
|
31209
31487
|
*
|
31210
31488
|
* CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
|
31211
31489
|
* For Angular to be CSP compatible there are only two things that we need to do differently:
|
@@ -31901,7 +32179,7 @@ forEach(
|
|
31901
32179
|
Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>
|
31902
32180
|
Show when checked:
|
31903
32181
|
<span ng-if="checked" class="animate-if">
|
31904
|
-
|
32182
|
+
This is removed when the checkbox is unchecked.
|
31905
32183
|
</span>
|
31906
32184
|
</file>
|
31907
32185
|
<file name="animations.css">
|
@@ -31955,15 +32233,15 @@ var ngIfDirective = ['$animate', function($animate) {
|
|
31955
32233
|
});
|
31956
32234
|
}
|
31957
32235
|
} else {
|
31958
|
-
if(previousElements) {
|
32236
|
+
if (previousElements) {
|
31959
32237
|
previousElements.remove();
|
31960
32238
|
previousElements = null;
|
31961
32239
|
}
|
31962
|
-
if(childScope) {
|
32240
|
+
if (childScope) {
|
31963
32241
|
childScope.$destroy();
|
31964
32242
|
childScope = null;
|
31965
32243
|
}
|
31966
|
-
if(block) {
|
32244
|
+
if (block) {
|
31967
32245
|
previousElements = getBlockNodes(block.clone);
|
31968
32246
|
$animate.leave(previousElements).then(function() {
|
31969
32247
|
previousElements = null;
|
@@ -31985,10 +32263,10 @@ var ngIfDirective = ['$animate', function($animate) {
|
|
31985
32263
|
* Fetches, compiles and includes an external HTML fragment.
|
31986
32264
|
*
|
31987
32265
|
* By default, the template URL is restricted to the same domain and protocol as the
|
31988
|
-
* application document. This is done by calling {@link
|
32266
|
+
* application document. This is done by calling {@link $sce#getTrustedResourceUrl
|
31989
32267
|
* $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
|
31990
32268
|
* you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
|
31991
|
-
*
|
32269
|
+
* {@link $sce#trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
|
31992
32270
|
* ng.$sce Strict Contextual Escaping}.
|
31993
32271
|
*
|
31994
32272
|
* In addition, the browser's
|
@@ -32687,13 +32965,6 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
|
|
32687
32965
|
* For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
|
32688
32966
|
* will be associated by item identity in the array.
|
32689
32967
|
*
|
32690
|
-
* * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
|
32691
|
-
* intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
|
32692
|
-
* when a filter is active on the repeater, but the filtered result set is empty.
|
32693
|
-
*
|
32694
|
-
* For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
|
32695
|
-
* the items have been processed through the filter.
|
32696
|
-
*
|
32697
32968
|
* For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
|
32698
32969
|
* `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
|
32699
32970
|
* with the corresponding item in the array by identity. Moving the same object in array would move the DOM
|
@@ -32706,6 +32977,13 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
|
|
32706
32977
|
* For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
|
32707
32978
|
* to items in conjunction with a tracking expression.
|
32708
32979
|
*
|
32980
|
+
* * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
|
32981
|
+
* intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
|
32982
|
+
* when a filter is active on the repeater, but the filtered result set is empty.
|
32983
|
+
*
|
32984
|
+
* For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
|
32985
|
+
* the items have been processed through the filter.
|
32986
|
+
*
|
32709
32987
|
* @example
|
32710
32988
|
* This example initializes the scope to a list of names and
|
32711
32989
|
* then uses `ngRepeat` to display every person:
|
@@ -33193,7 +33471,9 @@ var ngShowDirective = ['$animate', function($animate) {
|
|
33193
33471
|
// we can control when the element is actually displayed on screen without having
|
33194
33472
|
// to have a global/greedy CSS selector that breaks when other animations are run.
|
33195
33473
|
// Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
|
33196
|
-
$animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS,
|
33474
|
+
$animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, {
|
33475
|
+
tempClasses : NG_HIDE_IN_PROGRESS_CLASS
|
33476
|
+
});
|
33197
33477
|
});
|
33198
33478
|
}
|
33199
33479
|
};
|
@@ -33350,7 +33630,9 @@ var ngHideDirective = ['$animate', function($animate) {
|
|
33350
33630
|
scope.$watch(attr.ngHide, function ngHideWatchAction(value){
|
33351
33631
|
// The comment inside of the ngShowDirective explains why we add and
|
33352
33632
|
// remove a temporary class for the show/hide animation
|
33353
|
-
$animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS,
|
33633
|
+
$animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, {
|
33634
|
+
tempClasses : NG_HIDE_IN_PROGRESS_CLASS
|
33635
|
+
});
|
33354
33636
|
});
|
33355
33637
|
}
|
33356
33638
|
};
|
@@ -33775,9 +34057,23 @@ var ngOptionsMinErr = minErr('ngOptions');
|
|
33775
34057
|
* <div class="alert alert-info">
|
33776
34058
|
* **Note:** Using `select as` will bind the result of the `select as` expression to the model, but
|
33777
34059
|
* the value of the `<select>` and `<option>` html elements will be either the index (for array data sources)
|
33778
|
-
* or property name (for object data sources) of the value
|
34060
|
+
* or property name (for object data sources) of the value within the collection.
|
33779
34061
|
* </div>
|
33780
34062
|
*
|
34063
|
+
* **Note:** Using `select as` together with `trackexpr` is not recommended.
|
34064
|
+
* Reasoning:
|
34065
|
+
* - Example: <select ng-options="item.subItem as item.label for item in values track by item.id" ng-model="selected">
|
34066
|
+
* values: [{id: 1, label: 'aLabel', subItem: {name: 'aSubItem'}}, {id: 2, label: 'bLabel', subItem: {name: 'bSubItem'}}],
|
34067
|
+
* $scope.selected = {name: 'aSubItem'};
|
34068
|
+
* - track by is always applied to `value`, with the purpose of preserving the selection,
|
34069
|
+
* (to `item` in this case)
|
34070
|
+
* - to calculate whether an item is selected we do the following:
|
34071
|
+
* 1. apply `track by` to the values in the array, e.g.
|
34072
|
+
* In the example: [1,2]
|
34073
|
+
* 2. apply `track by` to the already selected value in `ngModel`:
|
34074
|
+
* In the example: this is not possible, as `track by` refers to `item.id`, but the selected
|
34075
|
+
* value from `ngModel` is `{name: aSubItem}`.
|
34076
|
+
*
|
33781
34077
|
* @param {string} ngModel Assignable angular expression to data-bind to.
|
33782
34078
|
* @param {string=} name Property name of the form under which the control is published.
|
33783
34079
|
* @param {string=} required The control is considered valid only if value is entered.
|
@@ -33814,23 +34110,6 @@ var ngOptionsMinErr = minErr('ngOptions');
|
|
33814
34110
|
* used to identify the objects in the array. The `trackexpr` will most likely refer to the
|
33815
34111
|
* `value` variable (e.g. `value.propertyName`). With this the selection is preserved
|
33816
34112
|
* even when the options are recreated (e.g. reloaded from the server).
|
33817
|
-
|
33818
|
-
* <div class="alert alert-info">
|
33819
|
-
* **Note:** Using `select as` together with `trackexpr` is not possible (and will throw).
|
33820
|
-
* Reasoning:
|
33821
|
-
* - Example: <select ng-options="item.subItem as item.label for item in values track by item.id" ng-model="selected">
|
33822
|
-
* values: [{id: 1, label: 'aLabel', subItem: {name: 'aSubItem'}}, {id: 2, label: 'bLabel', subItem: {name: 'bSubItemß'}}],
|
33823
|
-
* $scope.selected = {name: 'aSubItem'};
|
33824
|
-
* - track by is always applied to `value`, with purpose to preserve the selection,
|
33825
|
-
* (to `item` in this case)
|
33826
|
-
* - to calculate whether an item is selected we do the following:
|
33827
|
-
* 1. apply `track by` to the values in the array, e.g.
|
33828
|
-
* In the example: [1,2]
|
33829
|
-
* 2. apply `track by` to the already selected value in `ngModel`:
|
33830
|
-
* In the example: this is not possible, as `track by` refers to `item.id`, but the selected
|
33831
|
-
* value from `ngModel` is `{name: aSubItem}`.
|
33832
|
-
*
|
33833
|
-
* </div>
|
33834
34113
|
*
|
33835
34114
|
* @example
|
33836
34115
|
<example module="selectExample">
|
@@ -33940,7 +34219,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
33940
34219
|
// Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
|
33941
34220
|
// Adding an <option selected="selected"> element to a <select required="required"> should
|
33942
34221
|
// automatically select the new element
|
33943
|
-
if (element[0].hasAttribute('selected')) {
|
34222
|
+
if (element && element[0].hasAttribute('selected')) {
|
33944
34223
|
element[0].selected = true;
|
33945
34224
|
}
|
33946
34225
|
};
|
@@ -34103,13 +34382,6 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
34103
34382
|
//re-usable object to represent option's locals
|
34104
34383
|
locals = {};
|
34105
34384
|
|
34106
|
-
if (trackFn && selectAsFn) {
|
34107
|
-
throw ngOptionsMinErr('trkslct',
|
34108
|
-
"Comprehension expression cannot contain both selectAs '{0}' " +
|
34109
|
-
"and trackBy '{1}' expressions.",
|
34110
|
-
selectAs, track);
|
34111
|
-
}
|
34112
|
-
|
34113
34385
|
if (nullOption) {
|
34114
34386
|
// compile the element since there might be bindings in it
|
34115
34387
|
$compile(nullOption)(scope);
|
@@ -34200,7 +34472,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
34200
34472
|
function createIsSelectedFn(viewValue) {
|
34201
34473
|
var selectedSet;
|
34202
34474
|
if (multiple) {
|
34203
|
-
if (
|
34475
|
+
if (trackFn && isArray(viewValue)) {
|
34204
34476
|
|
34205
34477
|
selectedSet = new HashMap([]);
|
34206
34478
|
for (var trackIndex = 0; trackIndex < viewValue.length; trackIndex++) {
|
@@ -34210,15 +34482,16 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
34210
34482
|
} else {
|
34211
34483
|
selectedSet = new HashMap(viewValue);
|
34212
34484
|
}
|
34213
|
-
} else if (
|
34485
|
+
} else if (trackFn) {
|
34214
34486
|
viewValue = callExpression(trackFn, null, viewValue);
|
34215
34487
|
}
|
34488
|
+
|
34216
34489
|
return function isSelected(key, value) {
|
34217
34490
|
var compareValueFn;
|
34218
|
-
if (
|
34219
|
-
compareValueFn = selectAsFn;
|
34220
|
-
} else if (trackFn) {
|
34491
|
+
if (trackFn) {
|
34221
34492
|
compareValueFn = trackFn;
|
34493
|
+
} else if (selectAsFn) {
|
34494
|
+
compareValueFn = selectAsFn;
|
34222
34495
|
} else {
|
34223
34496
|
compareValueFn = valueFn;
|
34224
34497
|
}
|
@@ -34238,6 +34511,23 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
34238
34511
|
}
|
34239
34512
|
}
|
34240
34513
|
|
34514
|
+
/**
|
34515
|
+
* A new labelMap is created with each render.
|
34516
|
+
* This function is called for each existing option with added=false,
|
34517
|
+
* and each new option with added=true.
|
34518
|
+
* - Labels that are passed to this method twice,
|
34519
|
+
* (once with added=true and once with added=false) will end up with a value of 0, and
|
34520
|
+
* will cause no change to happen to the corresponding option.
|
34521
|
+
* - Labels that are passed to this method only once with added=false will end up with a
|
34522
|
+
* value of -1 and will eventually be passed to selectCtrl.removeOption()
|
34523
|
+
* - Labels that are passed to this method only once with added=true will end up with a
|
34524
|
+
* value of 1 and will eventually be passed to selectCtrl.addOption()
|
34525
|
+
*/
|
34526
|
+
function updateLabelMap(labelMap, label, added) {
|
34527
|
+
labelMap[label] = labelMap[label] || 0;
|
34528
|
+
labelMap[label] += (added ? 1 : -1);
|
34529
|
+
}
|
34530
|
+
|
34241
34531
|
function render() {
|
34242
34532
|
renderScheduled = false;
|
34243
34533
|
|
@@ -34255,6 +34545,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
34255
34545
|
value,
|
34256
34546
|
groupLength, length,
|
34257
34547
|
groupIndex, index,
|
34548
|
+
labelMap = {},
|
34258
34549
|
selected,
|
34259
34550
|
isSelected = createIsSelectedFn(viewValue),
|
34260
34551
|
anySelected = false,
|
@@ -34337,6 +34628,8 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
34337
34628
|
// reuse elements
|
34338
34629
|
lastElement = existingOption.element;
|
34339
34630
|
if (existingOption.label !== option.label) {
|
34631
|
+
updateLabelMap(labelMap, existingOption.label, false);
|
34632
|
+
updateLabelMap(labelMap, option.label, true);
|
34340
34633
|
lastElement.text(existingOption.label = option.label);
|
34341
34634
|
}
|
34342
34635
|
if (existingOption.id !== option.id) {
|
@@ -34376,7 +34669,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
34376
34669
|
id: option.id,
|
34377
34670
|
selected: option.selected
|
34378
34671
|
});
|
34379
|
-
|
34672
|
+
updateLabelMap(labelMap, option.label, true);
|
34380
34673
|
if (lastElement) {
|
34381
34674
|
lastElement.after(element);
|
34382
34675
|
} else {
|
@@ -34389,9 +34682,16 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
34389
34682
|
index++; // increment since the existingOptions[0] is parent element not OPTION
|
34390
34683
|
while(existingOptions.length > index) {
|
34391
34684
|
option = existingOptions.pop();
|
34392
|
-
|
34685
|
+
updateLabelMap(labelMap, option.label, false);
|
34393
34686
|
option.element.remove();
|
34394
34687
|
}
|
34688
|
+
forEach(labelMap, function (count, label) {
|
34689
|
+
if (count > 0) {
|
34690
|
+
selectCtrl.addOption(label);
|
34691
|
+
} else if (count < 0) {
|
34692
|
+
selectCtrl.removeOption(label);
|
34693
|
+
}
|
34694
|
+
});
|
34395
34695
|
}
|
34396
34696
|
// remove any excessive OPTGROUPs from select
|
34397
34697
|
while(optionGroupsCache.length > groupIndex) {
|