angularjs-rails 1.2.26 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/angularjs-rails/version.rb +2 -2
- data/vendor/assets/javascripts/angular-animate.js +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) {
|