angular-gem 1.1.3 → 1.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +13 -0
- data/lib/angular-gem/version.rb +1 -1
- data/test/dummy/log/test.log +1 -1
- data/test/dummy/tmp/cache/assets/D65/250/sprockets%2F54a960d46bb0b354e8bd46fa03f5e0e4 +0 -0
- data/test/dummy/tmp/cache/assets/D6A/FB0/sprockets%2F92721e9941b77adcfdfba3d060622de2 +0 -0
- data/test/dummy/tmp/cache/assets/E07/040/sprockets%2Ff55b8ce9d0f28ce36b768a1c7aeb2ef3 +0 -0
- data/vendor/assets/javascripts/1.0.6/angular-1.0.6.js +14760 -0
- data/vendor/assets/javascripts/1.0.6/angular-resource-1.0.6.js +457 -0
- data/vendor/assets/javascripts/1.0.6/angular-sanitize-1.0.6.js +537 -0
- data/vendor/assets/javascripts/1.1.4/angular-1.1.4.js +16314 -0
- data/vendor/assets/javascripts/1.1.4/angular-resource-1.1.4.js +521 -0
- data/vendor/assets/javascripts/1.1.4/angular-sanitize-1.1.4.js +558 -0
- data/vendor/assets/javascripts/angular-resource-unstable.js +33 -19
- data/vendor/assets/javascripts/angular-resource.js +14 -2
- data/vendor/assets/javascripts/angular-sanitize-unstable.js +3 -1
- data/vendor/assets/javascripts/angular-sanitize.js +3 -1
- data/vendor/assets/javascripts/angular-unstable.js +1693 -543
- data/vendor/assets/javascripts/angular.js +88 -61
- metadata +9 -2
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.1.
|
2
|
+
* @license AngularJS v1.1.4
|
3
3
|
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -24,14 +24,23 @@
|
|
24
24
|
* The returned resource object has action methods which provide high-level behaviors without
|
25
25
|
* the need to interact with the low level {@link ng.$http $http} service.
|
26
26
|
*
|
27
|
-
*
|
27
|
+
* # Installation
|
28
|
+
* To use $resource make sure you have included the `angular-resource.js` that comes in Angular
|
29
|
+
* package. You also can find this stuff in {@link http://code.angularjs.org/ code.angularjs.org}.
|
30
|
+
* Finally load the module in your application:
|
31
|
+
*
|
32
|
+
* angular.module('app', ['ngResource']);
|
33
|
+
*
|
34
|
+
* and you ready to get started!
|
35
|
+
*
|
36
|
+
* @param {string} url A parametrized URL template with parameters prefixed by `:` as in
|
28
37
|
* `/user/:username`. If you are using a URL with a port number (e.g.
|
29
38
|
* `http://example.com:8080/api`), you'll need to escape the colon character before the port
|
30
39
|
* number, like this: `$resource('http://example.com\\:8080/api')`.
|
31
40
|
*
|
32
41
|
* @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
|
33
42
|
* `actions` methods. If any of the parameter value is a function, it will be executed every time
|
34
|
-
* when a param value needs to be obtained for a request (unless the param was
|
43
|
+
* when a param value needs to be obtained for a request (unless the param was overridden).
|
35
44
|
*
|
36
45
|
* Each key value in the parameter object is first bound to url template if present and then any
|
37
46
|
* excess keys are appended to the url search query after the `?`.
|
@@ -58,7 +67,9 @@
|
|
58
67
|
* and `JSONP`.
|
59
68
|
* - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of the
|
60
69
|
* parameter value is a function, it will be executed every time when a param value needs to be
|
61
|
-
* obtained for a request (unless the param was
|
70
|
+
* obtained for a request (unless the param was overridden).
|
71
|
+
* - **`url`** – {string} – action specific `url` override. The url templating is supported just like
|
72
|
+
* for the resource-level urls.
|
62
73
|
* - **`isArray`** – {boolean=} – If true then the returned object for this action is an array, see
|
63
74
|
* `returns` section.
|
64
75
|
* - **`transformRequest`** – `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
|
@@ -291,7 +302,7 @@ angular.module('ngResource', ['ng']).
|
|
291
302
|
|
292
303
|
/**
|
293
304
|
* This method is intended for encoding *key* or *value* parts of query component. We need a custom
|
294
|
-
* method
|
305
|
+
* method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
|
295
306
|
* encoded per http://tools.ietf.org/html/rfc3986:
|
296
307
|
* query = *( pchar / "/" / "?" )
|
297
308
|
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
@@ -306,36 +317,38 @@ angular.module('ngResource', ['ng']).
|
|
306
317
|
replace(/%3A/gi, ':').
|
307
318
|
replace(/%24/g, '$').
|
308
319
|
replace(/%2C/gi, ',').
|
309
|
-
replace((pctEncodeSpaces ?
|
320
|
+
replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
|
310
321
|
}
|
311
322
|
|
312
323
|
function Route(template, defaults) {
|
313
324
|
this.template = template = template + '#';
|
314
325
|
this.defaults = defaults || {};
|
315
|
-
|
316
|
-
forEach(template.split(/\W/), function(param){
|
317
|
-
if (param && (new RegExp("(^|[^\\\\]):" + param + "\\W").test(template))) {
|
318
|
-
urlParams[param] = true;
|
319
|
-
}
|
320
|
-
});
|
321
|
-
this.template = template.replace(/\\:/g, ':');
|
326
|
+
this.urlParams = {};
|
322
327
|
}
|
323
328
|
|
324
329
|
Route.prototype = {
|
325
|
-
setUrlParams: function(config, params) {
|
330
|
+
setUrlParams: function(config, params, actionUrl) {
|
326
331
|
var self = this,
|
327
|
-
url =
|
332
|
+
url = actionUrl || self.template,
|
328
333
|
val,
|
329
334
|
encodedVal;
|
330
335
|
|
336
|
+
var urlParams = self.urlParams = {};
|
337
|
+
forEach(url.split(/\W/), function(param){
|
338
|
+
if (param && (new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
|
339
|
+
urlParams[param] = true;
|
340
|
+
}
|
341
|
+
});
|
342
|
+
url = url.replace(/\\:/g, ':');
|
343
|
+
|
331
344
|
params = params || {};
|
332
|
-
forEach(
|
345
|
+
forEach(self.urlParams, function(_, urlParam){
|
333
346
|
val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
|
334
347
|
if (angular.isDefined(val) && val !== null) {
|
335
348
|
encodedVal = encodeUriSegment(val);
|
336
|
-
url = url.replace(new RegExp(":" + urlParam + "(\\W)", "g"), encodedVal + "$1");
|
349
|
+
url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), encodedVal + "$1");
|
337
350
|
} else {
|
338
|
-
url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W)", "g"), function(match,
|
351
|
+
url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match,
|
339
352
|
leadingSlashes, tail) {
|
340
353
|
if (tail.charAt(0) == '/') {
|
341
354
|
return tail;
|
@@ -433,7 +446,7 @@ angular.module('ngResource', ['ng']).
|
|
433
446
|
}
|
434
447
|
});
|
435
448
|
httpConfig.data = data;
|
436
|
-
route.setUrlParams(httpConfig, extend({}, extractParams(data, action.params || {}), params));
|
449
|
+
route.setUrlParams(httpConfig, extend({}, extractParams(data, action.params || {}), params), action.url);
|
437
450
|
|
438
451
|
function markResolved() { value.$resolved = true; }
|
439
452
|
|
@@ -504,4 +517,5 @@ angular.module('ngResource', ['ng']).
|
|
504
517
|
return ResourceFactory;
|
505
518
|
}]);
|
506
519
|
|
520
|
+
|
507
521
|
})(window, window.angular);
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.0.
|
2
|
+
* @license AngularJS v1.0.6
|
3
3
|
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -24,6 +24,17 @@
|
|
24
24
|
* The returned resource object has action methods which provide high-level behaviors without
|
25
25
|
* the need to interact with the low level {@link ng.$http $http} service.
|
26
26
|
*
|
27
|
+
* # Installation
|
28
|
+
* To use $resource make sure you have included the `angular-resource.js` that comes in Angular
|
29
|
+
* package. You can also find this file on Google CDN, bower as well as at
|
30
|
+
* {@link http://code.angularjs.org/ code.angularjs.org}.
|
31
|
+
*
|
32
|
+
* Finally load the module in your application:
|
33
|
+
*
|
34
|
+
* angular.module('app', ['ngResource']);
|
35
|
+
*
|
36
|
+
* and you are ready to get started!
|
37
|
+
*
|
27
38
|
* @param {string} url A parameterized URL template with parameters prefixed by `:` as in
|
28
39
|
* `/user/:username`. If you are using a URL with a port number (e.g.
|
29
40
|
* `http://example.com:8080/api`), you'll need to escape the colon character before the port
|
@@ -268,7 +279,7 @@ angular.module('ngResource', ['ng']).
|
|
268
279
|
replace(/%3A/gi, ':').
|
269
280
|
replace(/%24/g, '$').
|
270
281
|
replace(/%2C/gi, ',').
|
271
|
-
replace((pctEncodeSpaces ?
|
282
|
+
replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
|
272
283
|
}
|
273
284
|
|
274
285
|
function Route(template, defaults) {
|
@@ -442,4 +453,5 @@ angular.module('ngResource', ['ng']).
|
|
442
453
|
return ResourceFactory;
|
443
454
|
}]);
|
444
455
|
|
456
|
+
|
445
457
|
})(window, window.angular);
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.1.
|
2
|
+
* @license AngularJS v1.1.4
|
3
3
|
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -422,6 +422,7 @@ angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($san
|
|
422
422
|
});
|
423
423
|
};
|
424
424
|
}]);
|
425
|
+
|
425
426
|
/**
|
426
427
|
* @ngdoc filter
|
427
428
|
* @name ngSanitize.filter:linky
|
@@ -553,4 +554,5 @@ angular.module('ngSanitize').filter('linky', function() {
|
|
553
554
|
};
|
554
555
|
});
|
555
556
|
|
557
|
+
|
556
558
|
})(window, window.angular);
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.0.
|
2
|
+
* @license AngularJS v1.0.6
|
3
3
|
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -422,6 +422,7 @@ angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($san
|
|
422
422
|
});
|
423
423
|
};
|
424
424
|
}]);
|
425
|
+
|
425
426
|
/**
|
426
427
|
* @ngdoc filter
|
427
428
|
* @name ngSanitize.filter:linky
|
@@ -532,4 +533,5 @@ angular.module('ngSanitize').filter('linky', function() {
|
|
532
533
|
};
|
533
534
|
});
|
534
535
|
|
536
|
+
|
535
537
|
})(window, window.angular);
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.1.
|
2
|
+
* @license AngularJS v1.1.4
|
3
3
|
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -34,12 +34,12 @@ var uppercase = function(string){return isString(string) ? string.toUpperCase()
|
|
34
34
|
|
35
35
|
var manualLowercase = function(s) {
|
36
36
|
return isString(s)
|
37
|
-
? s.replace(/[A-Z]/g, function(ch) {return fromCharCode(ch.charCodeAt(0) | 32);})
|
37
|
+
? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
|
38
38
|
: s;
|
39
39
|
};
|
40
40
|
var manualUppercase = function(s) {
|
41
41
|
return isString(s)
|
42
|
-
? s.replace(/[a-z]/g, function(ch) {return fromCharCode(ch.charCodeAt(0) & ~32);})
|
42
|
+
? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
|
43
43
|
: s;
|
44
44
|
};
|
45
45
|
|
@@ -52,8 +52,6 @@ if ('i' !== 'I'.toLowerCase()) {
|
|
52
52
|
uppercase = manualUppercase;
|
53
53
|
}
|
54
54
|
|
55
|
-
function fromCharCode(code) {return String.fromCharCode(code);}
|
56
|
-
|
57
55
|
|
58
56
|
var /** holds major version number for IE or NaN for real browsers */
|
59
57
|
msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]),
|
@@ -64,7 +62,7 @@ var /** holds major version number for IE or NaN for real browsers */
|
|
64
62
|
toString = Object.prototype.toString,
|
65
63
|
|
66
64
|
|
67
|
-
_angular = window.angular,
|
65
|
+
_angular = window.angular,
|
68
66
|
/** @name angular */
|
69
67
|
angular = window.angular || (window.angular = {}),
|
70
68
|
angularModule,
|
@@ -255,6 +253,11 @@ function inherit(parent, extra) {
|
|
255
253
|
return extend(new (extend(function() {}, {prototype:parent}))(), extra);
|
256
254
|
}
|
257
255
|
|
256
|
+
var START_SPACE = /^\s*/;
|
257
|
+
var END_SPACE = /\s*$/;
|
258
|
+
function stripWhitespace(str) {
|
259
|
+
return isString(str) ? str.replace(START_SPACE, '').replace(END_SPACE, '') : str;
|
260
|
+
}
|
258
261
|
|
259
262
|
/**
|
260
263
|
* @ngdoc function
|
@@ -639,7 +642,7 @@ function shallowCopy(src, dst) {
|
|
639
642
|
* * Both objects or values are of the same type and all of their properties pass `===` comparison.
|
640
643
|
* * Both values are NaN. (In JavasScript, NaN == NaN => false. But we consider two NaN as equal)
|
641
644
|
*
|
642
|
-
* During a property
|
645
|
+
* During a property comparison, properties of `function` type and properties with names
|
643
646
|
* that begin with `$` are ignored.
|
644
647
|
*
|
645
648
|
* Scope and DOMWindow objects are being compared only be identify (`===`).
|
@@ -846,7 +849,7 @@ function toKeyValue(obj) {
|
|
846
849
|
|
847
850
|
|
848
851
|
/**
|
849
|
-
* We need our custom method because encodeURIComponent is too
|
852
|
+
* We need our custom method because encodeURIComponent is too aggressive and doesn't follow
|
850
853
|
* http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
|
851
854
|
* segments:
|
852
855
|
* segment = *pchar
|
@@ -866,7 +869,7 @@ function encodeUriSegment(val) {
|
|
866
869
|
|
867
870
|
/**
|
868
871
|
* This method is intended for encoding *key* or *value* parts of query component. We need a custom
|
869
|
-
* method
|
872
|
+
* method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
|
870
873
|
* encoded per http://tools.ietf.org/html/rfc3986:
|
871
874
|
* query = *( pchar / "/" / "?" )
|
872
875
|
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
@@ -881,7 +884,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
|
|
881
884
|
replace(/%3A/gi, ':').
|
882
885
|
replace(/%24/g, '$').
|
883
886
|
replace(/%2C/gi, ',').
|
884
|
-
replace((pctEncodeSpaces ?
|
887
|
+
replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
|
885
888
|
}
|
886
889
|
|
887
890
|
|
@@ -970,22 +973,38 @@ function angularInit(element, bootstrap) {
|
|
970
973
|
* @returns {AUTO.$injector} Returns the newly created injector for this app.
|
971
974
|
*/
|
972
975
|
function bootstrap(element, modules) {
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
['$rootScope', '$rootElement', '$compile', '$injector',
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
976
|
+
var resumeBootstrapInternal = function() {
|
977
|
+
element = jqLite(element);
|
978
|
+
modules = modules || [];
|
979
|
+
modules.unshift(['$provide', function($provide) {
|
980
|
+
$provide.value('$rootElement', element);
|
981
|
+
}]);
|
982
|
+
modules.unshift('ng');
|
983
|
+
var injector = createInjector(modules);
|
984
|
+
injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
|
985
|
+
function(scope, element, compile, injector) {
|
986
|
+
scope.$apply(function() {
|
987
|
+
element.data('$injector', injector);
|
988
|
+
compile(element)(scope);
|
989
|
+
});
|
990
|
+
}]
|
991
|
+
);
|
992
|
+
return injector;
|
993
|
+
};
|
994
|
+
|
995
|
+
var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
|
996
|
+
|
997
|
+
if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
|
998
|
+
return resumeBootstrapInternal();
|
999
|
+
}
|
1000
|
+
|
1001
|
+
window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
|
1002
|
+
angular.resumeBootstrap = function(extraModules) {
|
1003
|
+
forEach(extraModules, function(module) {
|
1004
|
+
modules.push(module);
|
1005
|
+
});
|
1006
|
+
resumeBootstrapInternal();
|
1007
|
+
};
|
989
1008
|
}
|
990
1009
|
|
991
1010
|
var SNAKE_CASE_REGEXP = /[A-Z]/g;
|
@@ -1200,6 +1219,33 @@ function setupModuleLoader(window) {
|
|
1200
1219
|
*/
|
1201
1220
|
constant: invokeLater('$provide', 'constant', 'unshift'),
|
1202
1221
|
|
1222
|
+
/**
|
1223
|
+
* @ngdoc method
|
1224
|
+
* @name angular.Module#animation
|
1225
|
+
* @methodOf angular.Module
|
1226
|
+
* @param {string} name animation name
|
1227
|
+
* @param {Function} animationFactory Factory function for creating new instance of an animation.
|
1228
|
+
* @description
|
1229
|
+
*
|
1230
|
+
* Defines an animation hook that can be later used with {@link ng.directive:ngAnimate ngAnimate}
|
1231
|
+
* alongside {@link ng.directive:ngAnimate#Description common ng directives} as well as custom directives.
|
1232
|
+
* <pre>
|
1233
|
+
* module.animation('animation-name', function($inject1, $inject2) {
|
1234
|
+
* return {
|
1235
|
+
* //this gets called in preparation to setup an animation
|
1236
|
+
* setup : function(element) { ... },
|
1237
|
+
*
|
1238
|
+
* //this gets called once the animation is run
|
1239
|
+
* start : function(element, done, memo) { ... }
|
1240
|
+
* }
|
1241
|
+
* })
|
1242
|
+
* </pre>
|
1243
|
+
*
|
1244
|
+
* See {@link ng.$animationProvider#register $animationProvider.register()} and
|
1245
|
+
* {@link ng.directive:ngAnimate ngAnimate} for more information.
|
1246
|
+
*/
|
1247
|
+
animation: invokeLater('$animationProvider', 'register'),
|
1248
|
+
|
1203
1249
|
/**
|
1204
1250
|
* @ngdoc method
|
1205
1251
|
* @name angular.Module#filter
|
@@ -1299,11 +1345,11 @@ function setupModuleLoader(window) {
|
|
1299
1345
|
* - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
|
1300
1346
|
*/
|
1301
1347
|
var version = {
|
1302
|
-
full: '1.1.
|
1303
|
-
major: 1, //
|
1348
|
+
full: '1.1.4', // all of these placeholder strings will be replaced by grunt's
|
1349
|
+
major: 1, // package task
|
1304
1350
|
minor: 1,
|
1305
|
-
dot:
|
1306
|
-
codeName: '
|
1351
|
+
dot: 4,
|
1352
|
+
codeName: 'quantum-manipulation'
|
1307
1353
|
};
|
1308
1354
|
|
1309
1355
|
|
@@ -1392,6 +1438,8 @@ function publishExternalAPI(angular){
|
|
1392
1438
|
directive(ngEventDirectives);
|
1393
1439
|
$provide.provider({
|
1394
1440
|
$anchorScroll: $AnchorScrollProvider,
|
1441
|
+
$animation: $AnimationProvider,
|
1442
|
+
$animator: $AnimatorProvider,
|
1395
1443
|
$browser: $BrowserProvider,
|
1396
1444
|
$cacheFactory: $CacheFactoryProvider,
|
1397
1445
|
$controller: $ControllerProvider,
|
@@ -1476,7 +1524,7 @@ function publishExternalAPI(angular){
|
|
1476
1524
|
* - [val()](http://api.jquery.com/val/)
|
1477
1525
|
* - [wrap()](http://api.jquery.com/wrap/)
|
1478
1526
|
*
|
1479
|
-
* ## In
|
1527
|
+
* ## In addition to the above, Angular provides additional methods to both jQuery and jQuery lite:
|
1480
1528
|
*
|
1481
1529
|
* - `controller(name)` - retrieves the controller of the current element or its parent. By default
|
1482
1530
|
* retrieves controller associated with the `ngController` directive. If `name` is provided as
|
@@ -1744,9 +1792,14 @@ var JQLitePrototype = JQLite.prototype = {
|
|
1744
1792
|
fn();
|
1745
1793
|
}
|
1746
1794
|
|
1747
|
-
|
1748
|
-
|
1749
|
-
|
1795
|
+
// check if document already is loaded
|
1796
|
+
if (document.readyState === 'complete'){
|
1797
|
+
setTimeout(trigger);
|
1798
|
+
} else {
|
1799
|
+
this.bind('DOMContentLoaded', trigger); // works for modern browsers and IE9
|
1800
|
+
// we can not use jqLite since we are not done loading and jQuery could be loaded later.
|
1801
|
+
JQLite(window).bind('load', trigger); // fallback to window.onload for others
|
1802
|
+
}
|
1750
1803
|
},
|
1751
1804
|
toString: function() {
|
1752
1805
|
var value = [];
|
@@ -2246,50 +2299,6 @@ HashMap.prototype = {
|
|
2246
2299
|
}
|
2247
2300
|
};
|
2248
2301
|
|
2249
|
-
/**
|
2250
|
-
* A map where multiple values can be added to the same key such that they form a queue.
|
2251
|
-
* @returns {HashQueueMap}
|
2252
|
-
*/
|
2253
|
-
function HashQueueMap() {}
|
2254
|
-
HashQueueMap.prototype = {
|
2255
|
-
/**
|
2256
|
-
* Same as array push, but using an array as the value for the hash
|
2257
|
-
*/
|
2258
|
-
push: function(key, value) {
|
2259
|
-
var array = this[key = hashKey(key)];
|
2260
|
-
if (!array) {
|
2261
|
-
this[key] = [value];
|
2262
|
-
} else {
|
2263
|
-
array.push(value);
|
2264
|
-
}
|
2265
|
-
},
|
2266
|
-
|
2267
|
-
/**
|
2268
|
-
* Same as array shift, but using an array as the value for the hash
|
2269
|
-
*/
|
2270
|
-
shift: function(key) {
|
2271
|
-
var array = this[key = hashKey(key)];
|
2272
|
-
if (array) {
|
2273
|
-
if (array.length == 1) {
|
2274
|
-
delete this[key];
|
2275
|
-
return array[0];
|
2276
|
-
} else {
|
2277
|
-
return array.shift();
|
2278
|
-
}
|
2279
|
-
}
|
2280
|
-
},
|
2281
|
-
|
2282
|
-
/**
|
2283
|
-
* return the first item without deleting it
|
2284
|
-
*/
|
2285
|
-
peek: function(key) {
|
2286
|
-
var array = this[hashKey(key)];
|
2287
|
-
if (array) {
|
2288
|
-
return array[0];
|
2289
|
-
}
|
2290
|
-
}
|
2291
|
-
};
|
2292
|
-
|
2293
2302
|
/**
|
2294
2303
|
* @ngdoc function
|
2295
2304
|
* @name angular.injector
|
@@ -2390,15 +2399,15 @@ function annotate(fn) {
|
|
2390
2399
|
*
|
2391
2400
|
* <pre>
|
2392
2401
|
* // inferred (only works if code not minified/obfuscated)
|
2393
|
-
* $
|
2402
|
+
* $injector.invoke(function(serviceA){});
|
2394
2403
|
*
|
2395
2404
|
* // annotated
|
2396
2405
|
* function explicit(serviceA) {};
|
2397
2406
|
* explicit.$inject = ['serviceA'];
|
2398
|
-
* $
|
2407
|
+
* $injector.invoke(explicit);
|
2399
2408
|
*
|
2400
2409
|
* // inline
|
2401
|
-
* $
|
2410
|
+
* $injector.invoke(['serviceA', function(serviceA){}]);
|
2402
2411
|
* </pre>
|
2403
2412
|
*
|
2404
2413
|
* ## Inference
|
@@ -2544,7 +2553,7 @@ function annotate(fn) {
|
|
2544
2553
|
* @description
|
2545
2554
|
*
|
2546
2555
|
* Use `$provide` to register new providers with the `$injector`. The providers are the factories for the instance.
|
2547
|
-
* The providers share the same name as the instance they create with
|
2556
|
+
* The providers share the same name as the instance they create with `Provider` suffixed to them.
|
2548
2557
|
*
|
2549
2558
|
* A provider is an object with a `$get()` method. The injector calls the `$get` method to create a new instance of
|
2550
2559
|
* a service. The Provider can have additional methods which would allow for configuration of the provider.
|
@@ -2891,6 +2900,7 @@ function createInjector(modulesToLoad) {
|
|
2891
2900
|
};
|
2892
2901
|
}
|
2893
2902
|
}
|
2903
|
+
|
2894
2904
|
/**
|
2895
2905
|
* @ngdoc function
|
2896
2906
|
* @name ng.$anchorScroll
|
@@ -2958,6 +2968,383 @@ function $AnchorScrollProvider() {
|
|
2958
2968
|
}];
|
2959
2969
|
}
|
2960
2970
|
|
2971
|
+
|
2972
|
+
/**
|
2973
|
+
* @ngdoc object
|
2974
|
+
* @name ng.$animationProvider
|
2975
|
+
* @description
|
2976
|
+
*
|
2977
|
+
* The $AnimationProvider provider allows developers to register and access custom JavaScript animations directly inside
|
2978
|
+
* of a module.
|
2979
|
+
*
|
2980
|
+
*/
|
2981
|
+
$AnimationProvider.$inject = ['$provide'];
|
2982
|
+
function $AnimationProvider($provide) {
|
2983
|
+
var suffix = 'Animation';
|
2984
|
+
|
2985
|
+
/**
|
2986
|
+
* @ngdoc function
|
2987
|
+
* @name ng.$animation#register
|
2988
|
+
* @methodOf ng.$animationProvider
|
2989
|
+
*
|
2990
|
+
* @description
|
2991
|
+
* Registers a new injectable animation factory function. The factory function produces the animation object which
|
2992
|
+
* has these two properties:
|
2993
|
+
*
|
2994
|
+
* * `setup`: `function(Element):*` A function which receives the starting state of the element. The purpose
|
2995
|
+
* of this function is to get the element ready for animation. Optionally the function returns an memento which
|
2996
|
+
* is passed to the `start` function.
|
2997
|
+
* * `start`: `function(Element, doneFunction, *)` The element to animate, the `doneFunction` to be called on
|
2998
|
+
* element animation completion, and an optional memento from the `setup` function.
|
2999
|
+
*
|
3000
|
+
* @param {string} name The name of the animation.
|
3001
|
+
* @param {function} factory The factory function that will be executed to return the animation object.
|
3002
|
+
*
|
3003
|
+
*/
|
3004
|
+
this.register = function(name, factory) {
|
3005
|
+
$provide.factory(camelCase(name) + suffix, factory);
|
3006
|
+
};
|
3007
|
+
|
3008
|
+
this.$get = ['$injector', function($injector) {
|
3009
|
+
/**
|
3010
|
+
* @ngdoc function
|
3011
|
+
* @name ng.$animation
|
3012
|
+
* @function
|
3013
|
+
*
|
3014
|
+
* @description
|
3015
|
+
* The $animation service is used to retrieve any defined animation functions. When executed, the $animation service
|
3016
|
+
* will return a object that contains the setup and start functions that were defined for the animation.
|
3017
|
+
*
|
3018
|
+
* @param {String} name Name of the animation function to retrieve. Animation functions are registered and stored
|
3019
|
+
* inside of the AngularJS DI so a call to $animate('custom') is the same as injecting `customAnimation`
|
3020
|
+
* via dependency injection.
|
3021
|
+
* @return {Object} the animation object which contains the `setup` and `start` functions that perform the animation.
|
3022
|
+
*/
|
3023
|
+
return function $animation(name) {
|
3024
|
+
if (name) {
|
3025
|
+
try {
|
3026
|
+
return $injector.get(camelCase(name) + suffix);
|
3027
|
+
} catch (e) {
|
3028
|
+
//TODO(misko): this is a hack! we should have a better way to test if the injector has a given key.
|
3029
|
+
// The issue is that the animations are optional, and if not present they should be silently ignored.
|
3030
|
+
// The proper way to fix this is to add API onto the injector so that we can ask to see if a given
|
3031
|
+
// animation is supported.
|
3032
|
+
}
|
3033
|
+
}
|
3034
|
+
}
|
3035
|
+
}];
|
3036
|
+
};
|
3037
|
+
|
3038
|
+
// NOTE: this is a pseudo directive.
|
3039
|
+
|
3040
|
+
/**
|
3041
|
+
* @ngdoc directive
|
3042
|
+
* @name ng.directive:ngAnimate
|
3043
|
+
*
|
3044
|
+
* @description
|
3045
|
+
* The `ngAnimate` directive works as an attribute that is attached alongside pre-existing directives.
|
3046
|
+
* It effects how the directive will perform DOM manipulation. This allows for complex animations to take place while
|
3047
|
+
* without burduning the directive which uses the animation with animation details. The built dn directives
|
3048
|
+
* `ngRepeat`, `ngInclude`, `ngSwitch`, `ngShow`, `ngHide` and `ngView` already accept `ngAnimate` directive.
|
3049
|
+
* Custom directives can take advantage of animation through {@link ng.$animator $animator service}.
|
3050
|
+
*
|
3051
|
+
* Below is a more detailed breakdown of the supported callback events provided by pre-exisitng ng directives:
|
3052
|
+
*
|
3053
|
+
* * {@link ng.directive:ngRepeat#animations ngRepeat} — enter, leave and move
|
3054
|
+
* * {@link ng.directive:ngView#animations ngView} — enter and leave
|
3055
|
+
* * {@link ng.directive:ngInclude#animations ngInclude} — enter and leave
|
3056
|
+
* * {@link ng.directive:ngSwitch#animations ngSwitch} — enter and leave
|
3057
|
+
* * {@link ng.directive:ngShow#animations ngShow & ngHide} - show and hide respectively
|
3058
|
+
*
|
3059
|
+
* You can find out more information about animations upon visiting each directive page.
|
3060
|
+
*
|
3061
|
+
* Below is an example of a directive that makes use of the ngAnimate attribute:
|
3062
|
+
*
|
3063
|
+
* <pre>
|
3064
|
+
* <!-- you can also use data-ng-animate, ng:animate or x-ng-animate as well -->
|
3065
|
+
* <ANY ng-directive ng-animate="{event1: 'animation-name', event2: 'animation-name-2'}"></ANY>
|
3066
|
+
*
|
3067
|
+
* <!-- you can also use a short hand -->
|
3068
|
+
* <ANY ng-directive ng-animate=" 'animation' "></ANY>
|
3069
|
+
* <!-- which expands to -->
|
3070
|
+
* <ANY ng-directive ng-animate="{ enter: 'animation-enter', leave: 'animation-leave', ...}"></ANY>
|
3071
|
+
*
|
3072
|
+
* <!-- keep in mind that ng-animate can take expressions -->
|
3073
|
+
* <ANY ng-directive ng-animate=" computeCurrentAnimation() "></ANY>
|
3074
|
+
* </pre>
|
3075
|
+
*
|
3076
|
+
* The `event1` and `event2` attributes refer to the animation events specific to the directive that has been assigned.
|
3077
|
+
*
|
3078
|
+
* <h2>CSS-defined Animations</h2>
|
3079
|
+
* By default, ngAnimate attaches two CSS3 classes per animation event to the DOM element to achieve the animation.
|
3080
|
+
* This is up to you, the developer, to ensure that the animations take place using cross-browser CSS3 transitions.
|
3081
|
+
* All that is required is the following CSS code:
|
3082
|
+
*
|
3083
|
+
* <pre>
|
3084
|
+
* <style type="text/css">
|
3085
|
+
* /*
|
3086
|
+
* The animate-enter prefix is the event name that you
|
3087
|
+
* have provided within the ngAnimate attribute.
|
3088
|
+
* */
|
3089
|
+
* .animate-enter-setup {
|
3090
|
+
* -webkit-transition: 1s linear all; /* Safari/Chrome */
|
3091
|
+
* -moz-transition: 1s linear all; /* Firefox */
|
3092
|
+
* -ms-transition: 1s linear all; /* IE10 */
|
3093
|
+
* -o-transition: 1s linear all; /* Opera */
|
3094
|
+
* transition: 1s linear all; /* Future Browsers */
|
3095
|
+
*
|
3096
|
+
* /* The animation preparation code */
|
3097
|
+
* opacity: 0;
|
3098
|
+
* }
|
3099
|
+
*
|
3100
|
+
* /*
|
3101
|
+
* Keep in mind that you want to combine both CSS
|
3102
|
+
* classes together to avoid any CSS-specificity
|
3103
|
+
* conflicts
|
3104
|
+
* */
|
3105
|
+
* .animate-enter-setup.animate-enter-start {
|
3106
|
+
* /* The animation code itself */
|
3107
|
+
* opacity: 1;
|
3108
|
+
* }
|
3109
|
+
* </style>
|
3110
|
+
*
|
3111
|
+
* <div ng-directive ng-animate="{enter: 'animate-enter'}"></div>
|
3112
|
+
* </pre>
|
3113
|
+
*
|
3114
|
+
* Upon DOM mutation, the setup class is added first, then the browser is allowed to reflow the content and then,
|
3115
|
+
* the start class is added to trigger the animation. The ngAnimate directive will automatically extract the duration
|
3116
|
+
* of the animation to determine when the animation ends. Once the animation is over then both CSS classes will be
|
3117
|
+
* removed from the DOM. If a browser does not support CSS transitions then the animation will start and end
|
3118
|
+
* immediately resulting in a DOM element that is at it's final state. This final state is when the DOM element
|
3119
|
+
* has no CSS animation classes surrounding it.
|
3120
|
+
*
|
3121
|
+
* <h2>JavaScript-defined Animations</h2>
|
3122
|
+
* In the event that you do not want to use CSS3 animations or if you wish to offer animations to browsers that do not
|
3123
|
+
* yet support them, then you can make use of JavaScript animations defined inside ngModule.
|
3124
|
+
*
|
3125
|
+
* <pre>
|
3126
|
+
* var ngModule = angular.module('YourApp', []);
|
3127
|
+
* ngModule.animation('animate-enter', function() {
|
3128
|
+
* return {
|
3129
|
+
* setup : function(element) {
|
3130
|
+
* //prepare the element for animation
|
3131
|
+
* element.css({ 'opacity': 0 });
|
3132
|
+
* var memo = "..."; //this value is passed to the start function
|
3133
|
+
* return memo;
|
3134
|
+
* },
|
3135
|
+
* start : function(element, done, memo) {
|
3136
|
+
* //start the animation
|
3137
|
+
* element.animate({
|
3138
|
+
* 'opacity' : 1
|
3139
|
+
* }, function() {
|
3140
|
+
* //call when the animation is complete
|
3141
|
+
* done()
|
3142
|
+
* });
|
3143
|
+
* }
|
3144
|
+
* }
|
3145
|
+
* });
|
3146
|
+
* </pre>
|
3147
|
+
*
|
3148
|
+
* As you can see, the JavaScript code follows a similar template to the CSS3 animations. Once defined, the animation
|
3149
|
+
* can be used in the same way with the ngAnimate attribute. Keep in mind that, when using JavaScript-enabled
|
3150
|
+
* animations, ngAnimate will also add in the same CSS classes that CSS-enabled animations do (even if you're using
|
3151
|
+
* JavaScript animations) to animated the element, but it will not attempt to find any CSS3 transition duration value.
|
3152
|
+
* It will instead close off the animation once the provided done function is executed. So it's important that you
|
3153
|
+
* make sure your animations remember to fire off the done function once the animations are complete.
|
3154
|
+
*
|
3155
|
+
* @param {expression} ngAnimate Used to configure the DOM manipulation animations.
|
3156
|
+
*
|
3157
|
+
*/
|
3158
|
+
|
3159
|
+
/**
|
3160
|
+
* @ngdoc function
|
3161
|
+
* @name ng.$animator
|
3162
|
+
*
|
3163
|
+
* @description
|
3164
|
+
* The $animator service provides the DOM manipulation API which is decorated with animations.
|
3165
|
+
*
|
3166
|
+
* @param {Scope} scope the scope for the ng-animate.
|
3167
|
+
* @param {Attributes} attr the attributes object which contains the ngAnimate key / value pair. (The attributes are
|
3168
|
+
* passed into the linking function of the directive using the `$animator`.)
|
3169
|
+
* @return {object} the animator object which contains the enter, leave, move, show, hide and animate methods.
|
3170
|
+
*/
|
3171
|
+
var $AnimatorProvider = function() {
|
3172
|
+
this.$get = ['$animation', '$window', '$sniffer', function($animation, $window, $sniffer) {
|
3173
|
+
return function(scope, attrs) {
|
3174
|
+
var ngAnimateAttr = attrs.ngAnimate;
|
3175
|
+
var animator = {};
|
3176
|
+
|
3177
|
+
/**
|
3178
|
+
* @ngdoc function
|
3179
|
+
* @name ng.animator#enter
|
3180
|
+
* @methodOf ng.$animator
|
3181
|
+
* @function
|
3182
|
+
*
|
3183
|
+
* @description
|
3184
|
+
* Injects the element object into the DOM (inside of the parent element) and then runs the enter animation.
|
3185
|
+
*
|
3186
|
+
* @param {jQuery/jqLite element} element the element that will be the focus of the enter animation
|
3187
|
+
* @param {jQuery/jqLite element} parent the parent element of the element that will be the focus of the enter animation
|
3188
|
+
* @param {jQuery/jqLite element} after the sibling element (which is the previous element) of the element that will be the focus of the enter animation
|
3189
|
+
*/
|
3190
|
+
animator.enter = animateActionFactory('enter', insert, noop);
|
3191
|
+
|
3192
|
+
/**
|
3193
|
+
* @ngdoc function
|
3194
|
+
* @name ng.animator#leave
|
3195
|
+
* @methodOf ng.$animator
|
3196
|
+
* @function
|
3197
|
+
*
|
3198
|
+
* @description
|
3199
|
+
* Runs the leave animation operation and, upon completion, removes the element from the DOM.
|
3200
|
+
*
|
3201
|
+
* @param {jQuery/jqLite element} element the element that will be the focus of the leave animation
|
3202
|
+
* @param {jQuery/jqLite element} parent the parent element of the element that will be the focus of the leave animation
|
3203
|
+
*/
|
3204
|
+
animator.leave = animateActionFactory('leave', noop, remove);
|
3205
|
+
|
3206
|
+
/**
|
3207
|
+
* @ngdoc function
|
3208
|
+
* @name ng.animator#move
|
3209
|
+
* @methodOf ng.$animator
|
3210
|
+
* @function
|
3211
|
+
*
|
3212
|
+
* @description
|
3213
|
+
* Fires the move DOM operation. Just before the animation starts, the animator will either append it into the parent container or
|
3214
|
+
* add the element directly after the after element if present. Then the move animation will be run.
|
3215
|
+
*
|
3216
|
+
* @param {jQuery/jqLite element} element the element that will be the focus of the move animation
|
3217
|
+
* @param {jQuery/jqLite element} parent the parent element of the element that will be the focus of the move animation
|
3218
|
+
* @param {jQuery/jqLite element} after the sibling element (which is the previous element) of the element that will be the focus of the move animation
|
3219
|
+
*/
|
3220
|
+
animator.move = animateActionFactory('move', move, noop);
|
3221
|
+
|
3222
|
+
/**
|
3223
|
+
* @ngdoc function
|
3224
|
+
* @name ng.animator#show
|
3225
|
+
* @methodOf ng.$animator
|
3226
|
+
* @function
|
3227
|
+
*
|
3228
|
+
* @description
|
3229
|
+
* Reveals the element by setting the CSS property `display` to `block` and then starts the show animation directly after.
|
3230
|
+
*
|
3231
|
+
* @param {jQuery/jqLite element} element the element that will be rendered visible or hidden
|
3232
|
+
*/
|
3233
|
+
animator.show = animateActionFactory('show', show, noop);
|
3234
|
+
|
3235
|
+
/**
|
3236
|
+
* @ngdoc function
|
3237
|
+
* @name ng.animator#hide
|
3238
|
+
* @methodOf ng.$animator
|
3239
|
+
*
|
3240
|
+
* @description
|
3241
|
+
* Starts the hide animation first and sets the CSS `display` property to `none` upon completion.
|
3242
|
+
*
|
3243
|
+
* @param {jQuery/jqLite element} element the element that will be rendered visible or hidden
|
3244
|
+
*/
|
3245
|
+
animator.hide = animateActionFactory('hide', noop, hide);
|
3246
|
+
return animator;
|
3247
|
+
|
3248
|
+
function animateActionFactory(type, beforeFn, afterFn) {
|
3249
|
+
var ngAnimateValue = ngAnimateAttr && scope.$eval(ngAnimateAttr);
|
3250
|
+
var className = ngAnimateAttr
|
3251
|
+
? isObject(ngAnimateValue) ? ngAnimateValue[type] : ngAnimateValue + '-' + type
|
3252
|
+
: '';
|
3253
|
+
var animationPolyfill = $animation(className);
|
3254
|
+
|
3255
|
+
var polyfillSetup = animationPolyfill && animationPolyfill.setup;
|
3256
|
+
var polyfillStart = animationPolyfill && animationPolyfill.start;
|
3257
|
+
|
3258
|
+
if (!className) {
|
3259
|
+
return function(element, parent, after) {
|
3260
|
+
beforeFn(element, parent, after);
|
3261
|
+
afterFn(element, parent, after);
|
3262
|
+
}
|
3263
|
+
} else {
|
3264
|
+
var setupClass = className + '-setup';
|
3265
|
+
var startClass = className + '-start';
|
3266
|
+
|
3267
|
+
return function(element, parent, after) {
|
3268
|
+
if (!$sniffer.supportsTransitions && !polyfillSetup && !polyfillStart) {
|
3269
|
+
beforeFn(element, parent, after);
|
3270
|
+
afterFn(element, parent, after);
|
3271
|
+
return;
|
3272
|
+
}
|
3273
|
+
|
3274
|
+
element.addClass(setupClass);
|
3275
|
+
beforeFn(element, parent, after);
|
3276
|
+
if (element.length == 0) return done();
|
3277
|
+
|
3278
|
+
var memento = (polyfillSetup || noop)(element);
|
3279
|
+
|
3280
|
+
// $window.setTimeout(beginAnimation, 0); this was causing the element not to animate
|
3281
|
+
// keep at 1 for animation dom rerender
|
3282
|
+
$window.setTimeout(beginAnimation, 1);
|
3283
|
+
|
3284
|
+
function beginAnimation() {
|
3285
|
+
element.addClass(startClass);
|
3286
|
+
if (polyfillStart) {
|
3287
|
+
polyfillStart(element, done, memento);
|
3288
|
+
} else if (isFunction($window.getComputedStyle)) {
|
3289
|
+
var vendorTransitionProp = $sniffer.vendorPrefix + 'Transition';
|
3290
|
+
var w3cTransitionProp = 'transition'; //one day all browsers will have this
|
3291
|
+
|
3292
|
+
var durationKey = 'Duration';
|
3293
|
+
var duration = 0;
|
3294
|
+
//we want all the styles defined before and after
|
3295
|
+
forEach(element, function(element) {
|
3296
|
+
var globalStyles = $window.getComputedStyle(element) || {};
|
3297
|
+
duration = Math.max(
|
3298
|
+
parseFloat(globalStyles[w3cTransitionProp + durationKey]) ||
|
3299
|
+
parseFloat(globalStyles[vendorTransitionProp + durationKey]) ||
|
3300
|
+
0,
|
3301
|
+
duration);
|
3302
|
+
});
|
3303
|
+
|
3304
|
+
$window.setTimeout(done, duration * 1000);
|
3305
|
+
} else {
|
3306
|
+
done();
|
3307
|
+
}
|
3308
|
+
}
|
3309
|
+
|
3310
|
+
function done() {
|
3311
|
+
afterFn(element, parent, after);
|
3312
|
+
element.removeClass(setupClass);
|
3313
|
+
element.removeClass(startClass);
|
3314
|
+
}
|
3315
|
+
}
|
3316
|
+
}
|
3317
|
+
}
|
3318
|
+
}
|
3319
|
+
|
3320
|
+
function show(element) {
|
3321
|
+
element.css('display', '');
|
3322
|
+
}
|
3323
|
+
|
3324
|
+
function hide(element) {
|
3325
|
+
element.css('display', 'none');
|
3326
|
+
}
|
3327
|
+
|
3328
|
+
function insert(element, parent, after) {
|
3329
|
+
if (after) {
|
3330
|
+
after.after(element);
|
3331
|
+
} else {
|
3332
|
+
parent.append(element);
|
3333
|
+
}
|
3334
|
+
}
|
3335
|
+
|
3336
|
+
function remove(element) {
|
3337
|
+
element.remove();
|
3338
|
+
}
|
3339
|
+
|
3340
|
+
function move(element, parent, after) {
|
3341
|
+
// Do not remove element before insert. Removing will cause data associated with the
|
3342
|
+
// element to be dropped. Insert will implicitly do the remove.
|
3343
|
+
insert(element, parent, after);
|
3344
|
+
}
|
3345
|
+
}];
|
3346
|
+
};
|
3347
|
+
|
2961
3348
|
/**
|
2962
3349
|
* ! This is a private undocumented service !
|
2963
3350
|
*
|
@@ -3210,7 +3597,7 @@ function Browser(window, document, $log, $sniffer) {
|
|
3210
3597
|
* @methodOf ng.$browser
|
3211
3598
|
*
|
3212
3599
|
* @param {string=} name Cookie name
|
3213
|
-
* @param {string=} value
|
3600
|
+
* @param {string=} value Cookie value
|
3214
3601
|
*
|
3215
3602
|
* @description
|
3216
3603
|
* The cookies method provides a 'private' low level access to browser cookies.
|
@@ -3272,7 +3659,7 @@ function Browser(window, document, $log, $sniffer) {
|
|
3272
3659
|
* @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
|
3273
3660
|
*
|
3274
3661
|
* @description
|
3275
|
-
* Executes a fn
|
3662
|
+
* Executes a fn asynchronously via `setTimeout(fn, delay)`.
|
3276
3663
|
*
|
3277
3664
|
* Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
|
3278
3665
|
* `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
|
@@ -3299,7 +3686,7 @@ function Browser(window, document, $log, $sniffer) {
|
|
3299
3686
|
* Cancels a defered task identified with `deferId`.
|
3300
3687
|
*
|
3301
3688
|
* @param {*} deferId Token returned by the `$browser.defer` function.
|
3302
|
-
* @returns {boolean} Returns `true` if the task hasn't executed yet and was
|
3689
|
+
* @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully canceled.
|
3303
3690
|
*/
|
3304
3691
|
self.defer.cancel = function(deferId) {
|
3305
3692
|
if (pendingDeferIds[deferId]) {
|
@@ -3319,6 +3706,7 @@ function $BrowserProvider(){
|
|
3319
3706
|
return new Browser($window, $document, $log, $sniffer);
|
3320
3707
|
}];
|
3321
3708
|
}
|
3709
|
+
|
3322
3710
|
/**
|
3323
3711
|
* @ngdoc object
|
3324
3712
|
* @name ng.$cacheFactory
|
@@ -3648,7 +4036,7 @@ function $CompileProvider($provide) {
|
|
3648
4036
|
COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
|
3649
4037
|
CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
|
3650
4038
|
MULTI_ROOT_TEMPLATE_ERROR = 'Template must have exactly one root element. was: ',
|
3651
|
-
urlSanitizationWhitelist = /^\s*(https?|ftp|mailto):/;
|
4039
|
+
urlSanitizationWhitelist = /^\s*(https?|ftp|mailto|file):/;
|
3652
4040
|
|
3653
4041
|
|
3654
4042
|
/**
|
@@ -3662,7 +4050,7 @@ function $CompileProvider($provide) {
|
|
3662
4050
|
*
|
3663
4051
|
* @param {string} name Name of the directive in camel-case. (ie <code>ngBind</code> which will match as
|
3664
4052
|
* <code>ng-bind</code>).
|
3665
|
-
* @param {function} directiveFactory An injectable directive
|
4053
|
+
* @param {function} directiveFactory An injectable directive factory function. See {@link guide/directive} for more
|
3666
4054
|
* info.
|
3667
4055
|
* @returns {ng.$compileProvider} Self for chaining.
|
3668
4056
|
*/
|
@@ -3841,7 +4229,8 @@ function $CompileProvider($provide) {
|
|
3841
4229
|
? identity
|
3842
4230
|
: function denormalizeTemplate(template) {
|
3843
4231
|
return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
|
3844
|
-
|
4232
|
+
},
|
4233
|
+
NG_ATTR_BINDING = /^ngAttr[A-Z]/;
|
3845
4234
|
|
3846
4235
|
|
3847
4236
|
return compile;
|
@@ -3850,7 +4239,7 @@ function $CompileProvider($provide) {
|
|
3850
4239
|
|
3851
4240
|
function compile($compileNodes, transcludeFn, maxPriority) {
|
3852
4241
|
if (!($compileNodes instanceof jqLite)) {
|
3853
|
-
// jquery always rewraps,
|
4242
|
+
// jquery always rewraps, whereas we need to preserve the original selector so that we can modify it.
|
3854
4243
|
$compileNodes = jqLite($compileNodes);
|
3855
4244
|
}
|
3856
4245
|
// We can not compile top level text elements since text nodes can be merged and we will
|
@@ -3902,7 +4291,7 @@ function $CompileProvider($provide) {
|
|
3902
4291
|
* functions return values - the linking functions - are combined into a composite linking
|
3903
4292
|
* function, which is the a linking function for the node.
|
3904
4293
|
*
|
3905
|
-
* @param {NodeList} nodeList an array of nodes to compile
|
4294
|
+
* @param {NodeList} nodeList an array of nodes or NodeList to compile
|
3906
4295
|
* @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
|
3907
4296
|
* scope argument is auto-generated to the new child of the transcluded parent scope.
|
3908
4297
|
* @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then the
|
@@ -3925,7 +4314,7 @@ function $CompileProvider($provide) {
|
|
3925
4314
|
? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement)
|
3926
4315
|
: null;
|
3927
4316
|
|
3928
|
-
childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes.length)
|
4317
|
+
childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes || !nodeList[i].childNodes.length)
|
3929
4318
|
? null
|
3930
4319
|
: compileNodes(nodeList[i].childNodes,
|
3931
4320
|
nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
|
@@ -4006,11 +4395,16 @@ function $CompileProvider($provide) {
|
|
4006
4395
|
directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority);
|
4007
4396
|
|
4008
4397
|
// iterate over the attributes
|
4009
|
-
for (var attr, name, nName, value, nAttrs = node.attributes,
|
4398
|
+
for (var attr, name, nName, ngAttrName, value, nAttrs = node.attributes,
|
4010
4399
|
j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
|
4011
4400
|
attr = nAttrs[j];
|
4012
4401
|
if (attr.specified) {
|
4013
4402
|
name = attr.name;
|
4403
|
+
// support ngAttr attribute binding
|
4404
|
+
ngAttrName = directiveNormalize(name);
|
4405
|
+
if (NG_ATTR_BINDING.test(ngAttrName)) {
|
4406
|
+
name = ngAttrName.substr(6).toLowerCase();
|
4407
|
+
}
|
4014
4408
|
nName = directiveNormalize(name.toLowerCase());
|
4015
4409
|
attrsMap[nName] = name;
|
4016
4410
|
attrs[nName] = value = trim((msie && name == 'href')
|
@@ -4138,9 +4532,14 @@ function $CompileProvider($provide) {
|
|
4138
4532
|
}
|
4139
4533
|
}
|
4140
4534
|
|
4141
|
-
if (
|
4535
|
+
if (directive.template) {
|
4142
4536
|
assertNoDuplicate('template', templateDirective, directive, $compileNode);
|
4143
4537
|
templateDirective = directive;
|
4538
|
+
|
4539
|
+
directiveValue = (isFunction(directive.template))
|
4540
|
+
? directive.template($compileNode, templateAttrs)
|
4541
|
+
: directive.template;
|
4542
|
+
|
4144
4543
|
directiveValue = denormalizeTemplate(directiveValue);
|
4145
4544
|
|
4146
4545
|
if (directive.replace) {
|
@@ -4260,13 +4659,14 @@ function $CompileProvider($provide) {
|
|
4260
4659
|
$element = attrs.$$element;
|
4261
4660
|
|
4262
4661
|
if (newIsolateScopeDirective) {
|
4263
|
-
var LOCAL_REGEXP = /^\s*([@=&])\s*(\w*)\s*$/;
|
4662
|
+
var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
|
4264
4663
|
|
4265
4664
|
var parentScope = scope.$parent || scope;
|
4266
4665
|
|
4267
4666
|
forEach(newIsolateScopeDirective.scope, function(definiton, scopeName) {
|
4268
4667
|
var match = definiton.match(LOCAL_REGEXP) || [],
|
4269
|
-
attrName = match[
|
4668
|
+
attrName = match[3] || scopeName,
|
4669
|
+
optional = (match[2] == '?'),
|
4270
4670
|
mode = match[1], // @, =, or &
|
4271
4671
|
lastValue,
|
4272
4672
|
parentGet, parentSet;
|
@@ -4288,6 +4688,9 @@ function $CompileProvider($provide) {
|
|
4288
4688
|
}
|
4289
4689
|
|
4290
4690
|
case '=': {
|
4691
|
+
if (optional && !attrs[attrName]) {
|
4692
|
+
return;
|
4693
|
+
}
|
4291
4694
|
parentGet = $parse(attrs[attrName]);
|
4292
4695
|
parentSet = parentGet.assign || function() {
|
4293
4696
|
// reset the change, or we will throw this exception on every $digest
|
@@ -4459,11 +4862,14 @@ function $CompileProvider($provide) {
|
|
4459
4862
|
// The fact that we have to copy and patch the directive seems wrong!
|
4460
4863
|
derivedSyncDirective = extend({}, origAsyncDirective, {
|
4461
4864
|
controller: null, templateUrl: null, transclude: null, scope: null
|
4462
|
-
})
|
4865
|
+
}),
|
4866
|
+
templateUrl = (isFunction(origAsyncDirective.templateUrl))
|
4867
|
+
? origAsyncDirective.templateUrl($compileNode, tAttrs)
|
4868
|
+
: origAsyncDirective.templateUrl;
|
4463
4869
|
|
4464
4870
|
$compileNode.html('');
|
4465
4871
|
|
4466
|
-
$http.get(
|
4872
|
+
$http.get(templateUrl, {cache: $templateCache}).
|
4467
4873
|
success(function(content) {
|
4468
4874
|
var compileNode, tempTemplateAttrs, $template;
|
4469
4875
|
|
@@ -4488,14 +4894,14 @@ function $CompileProvider($provide) {
|
|
4488
4894
|
|
4489
4895
|
directives.unshift(derivedSyncDirective);
|
4490
4896
|
afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, childTranscludeFn);
|
4491
|
-
afterTemplateChildLinkFn = compileNodes($compileNode.
|
4897
|
+
afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
|
4492
4898
|
|
4493
4899
|
|
4494
4900
|
while(linkQueue.length) {
|
4495
|
-
var
|
4496
|
-
|
4497
|
-
|
4498
|
-
|
4901
|
+
var scope = linkQueue.shift(),
|
4902
|
+
beforeTemplateLinkNode = linkQueue.shift(),
|
4903
|
+
linkRootElement = linkQueue.shift(),
|
4904
|
+
controller = linkQueue.shift(),
|
4499
4905
|
linkNode = compileNode;
|
4500
4906
|
|
4501
4907
|
if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
|
@@ -4576,11 +4982,13 @@ function $CompileProvider($provide) {
|
|
4576
4982
|
compile: valueFn(function attrInterpolateLinkFn(scope, element, attr) {
|
4577
4983
|
var $$observers = (attr.$$observers || (attr.$$observers = {}));
|
4578
4984
|
|
4579
|
-
|
4580
|
-
|
4581
|
-
|
4582
|
-
|
4583
|
-
|
4985
|
+
// we need to interpolate again, in case the attribute value has been updated
|
4986
|
+
// (e.g. by another directive's compile function)
|
4987
|
+
interpolateFn = $interpolate(attr[name], true);
|
4988
|
+
|
4989
|
+
// if attribute was updated so that there is no interpolation going on we don't want to
|
4990
|
+
// register any observers
|
4991
|
+
if (!interpolateFn) return;
|
4584
4992
|
|
4585
4993
|
attr[name] = interpolateFn(scope);
|
4586
4994
|
($$observers[name] || ($$observers[name] = [])).$$inter = true;
|
@@ -4677,7 +5085,7 @@ function directiveNormalize(name) {
|
|
4677
5085
|
* @param {string} name Normalized element attribute name of the property to modify. The name is
|
4678
5086
|
* revers translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
|
4679
5087
|
* property to the original name.
|
4680
|
-
* @param {string} value Value to set the attribute to.
|
5088
|
+
* @param {string} value Value to set the attribute to. The value can be an interpolated string.
|
4681
5089
|
*/
|
4682
5090
|
|
4683
5091
|
|
@@ -4753,7 +5161,7 @@ function $ControllerProvider() {
|
|
4753
5161
|
* @description
|
4754
5162
|
* `$controller` service is responsible for instantiating controllers.
|
4755
5163
|
*
|
4756
|
-
* It's just simple call to {@link AUTO.$injector $injector}, but extracted into
|
5164
|
+
* It's just a simple call to {@link AUTO.$injector $injector}, but extracted into
|
4757
5165
|
* a service, so that one can override this service with {@link https://gist.github.com/1649788
|
4758
5166
|
* BC version}.
|
4759
5167
|
*/
|
@@ -5000,7 +5408,7 @@ function $InterpolateProvider() {
|
|
5000
5408
|
}];
|
5001
5409
|
}
|
5002
5410
|
|
5003
|
-
var URL_MATCH = /^([^:]+):\/\/(\w+:{0,1}\w*@)?([\w\.-]
|
5411
|
+
var URL_MATCH = /^([^:]+):\/\/(\w+:{0,1}\w*@)?(\{?[\w\.-]*\}?)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/,
|
5004
5412
|
PATH_MATCH = /^([^\?#]*)?(\?([^#]*))?(#(.*))?$/,
|
5005
5413
|
HASH_MATCH = PATH_MATCH,
|
5006
5414
|
DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
|
@@ -5079,7 +5487,8 @@ function convertToHashbangUrl(url, basePath, hashPrefix) {
|
|
5079
5487
|
var match = matchUrl(url);
|
5080
5488
|
|
5081
5489
|
// already hashbang url
|
5082
|
-
if (decodeURIComponent(match.path) == basePath)
|
5490
|
+
if (decodeURIComponent(match.path) == basePath && !isUndefined(match.hash) &&
|
5491
|
+
match.hash.indexOf(hashPrefix) === 0) {
|
5083
5492
|
return url;
|
5084
5493
|
// convert html5 url -> hashbang url
|
5085
5494
|
} else {
|
@@ -6471,11 +6880,11 @@ function setter(obj, path, setValue) {
|
|
6471
6880
|
}
|
6472
6881
|
|
6473
6882
|
/**
|
6474
|
-
* Return the value
|
6883
|
+
* Return the value accessible from the object by path. Any undefined traversals are ignored
|
6475
6884
|
* @param {Object} obj starting object
|
6476
6885
|
* @param {string} path path to traverse
|
6477
6886
|
* @param {boolean=true} bindFnToScope
|
6478
|
-
* @returns value as
|
6887
|
+
* @returns value as accessible by path
|
6479
6888
|
*/
|
6480
6889
|
//TODO(misko): this function needs to be removed
|
6481
6890
|
function getter(obj, path, bindFnToScope) {
|
@@ -6647,7 +7056,7 @@ function getterFn(path, csp) {
|
|
6647
7056
|
* @returns {function(context, locals)} a function which represents the compiled expression:
|
6648
7057
|
*
|
6649
7058
|
* * `context` – `{object}` – an object against which any expressions embedded in the strings
|
6650
|
-
* are evaluated against (
|
7059
|
+
* are evaluated against (typically a scope object).
|
6651
7060
|
* * `locals` – `{object=}` – local variables context object, useful for overriding values in
|
6652
7061
|
* `context`.
|
6653
7062
|
*
|
@@ -7055,29 +7464,30 @@ function qFactory(nextTick, exceptionHandler) {
|
|
7055
7464
|
* Combines multiple promises into a single promise that is resolved when all of the input
|
7056
7465
|
* promises are resolved.
|
7057
7466
|
*
|
7058
|
-
* @param {Array.<Promise>} promises An array of promises.
|
7059
|
-
* @returns {Promise} Returns a single promise that will be resolved with an array of values,
|
7060
|
-
* each value corresponding to the promise at the same index in the `promises` array. If any of
|
7467
|
+
* @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
|
7468
|
+
* @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
|
7469
|
+
* each value corresponding to the promise at the same index/key in the `promises` array/hash. If any of
|
7061
7470
|
* the promises is resolved with a rejection, this resulting promise will be resolved with the
|
7062
7471
|
* same rejection.
|
7063
7472
|
*/
|
7064
7473
|
function all(promises) {
|
7065
7474
|
var deferred = defer(),
|
7066
|
-
counter =
|
7067
|
-
results = [];
|
7068
|
-
|
7069
|
-
|
7070
|
-
|
7071
|
-
|
7072
|
-
|
7073
|
-
|
7074
|
-
|
7075
|
-
|
7076
|
-
|
7077
|
-
|
7078
|
-
});
|
7475
|
+
counter = 0,
|
7476
|
+
results = isArray(promises) ? [] : {};
|
7477
|
+
|
7478
|
+
forEach(promises, function(promise, key) {
|
7479
|
+
counter++;
|
7480
|
+
ref(promise).then(function(value) {
|
7481
|
+
if (results.hasOwnProperty(key)) return;
|
7482
|
+
results[key] = value;
|
7483
|
+
if (!(--counter)) deferred.resolve(results);
|
7484
|
+
}, function(reason) {
|
7485
|
+
if (results.hasOwnProperty(key)) return;
|
7486
|
+
deferred.reject(reason);
|
7079
7487
|
});
|
7080
|
-
}
|
7488
|
+
});
|
7489
|
+
|
7490
|
+
if (counter === 0) {
|
7081
7491
|
deferred.resolve(results);
|
7082
7492
|
}
|
7083
7493
|
|
@@ -7183,13 +7593,18 @@ function $RouteProvider(){
|
|
7183
7593
|
* If the option is set to `false` and url in the browser changes, then
|
7184
7594
|
* `$routeUpdate` event is broadcasted on the root scope.
|
7185
7595
|
*
|
7596
|
+
* - `[caseInsensitiveMatch=false]` - {boolean=} - match routes without being case sensitive
|
7597
|
+
*
|
7598
|
+
* If the option is set to `true`, then the particular route can be matched without being
|
7599
|
+
* case sensitive
|
7600
|
+
*
|
7186
7601
|
* @returns {Object} self
|
7187
7602
|
*
|
7188
7603
|
* @description
|
7189
7604
|
* Adds a new route definition to the `$route` service.
|
7190
7605
|
*/
|
7191
7606
|
this.when = function(path, route) {
|
7192
|
-
routes[path] = extend({reloadOnSearch: true}, route);
|
7607
|
+
routes[path] = extend({reloadOnSearch: true, caseInsensitiveMatch: false}, route);
|
7193
7608
|
|
7194
7609
|
// create redirection for trailing slashes
|
7195
7610
|
if (path) {
|
@@ -7375,8 +7790,9 @@ function $RouteProvider(){
|
|
7375
7790
|
* {@link ng.directive:ngView ngView} listens for the directive
|
7376
7791
|
* to instantiate the controller and render the view.
|
7377
7792
|
*
|
7793
|
+
* @param {Object} angularEvent Synthetic event object.
|
7378
7794
|
* @param {Route} current Current route information.
|
7379
|
-
* @param {Route} previous Previous route information.
|
7795
|
+
* @param {Route|Undefined} previous Previous route information, or undefined if current is first route entered.
|
7380
7796
|
*/
|
7381
7797
|
|
7382
7798
|
/**
|
@@ -7434,14 +7850,16 @@ function $RouteProvider(){
|
|
7434
7850
|
/**
|
7435
7851
|
* @param on {string} current url
|
7436
7852
|
* @param when {string} route when template to match the url against
|
7853
|
+
* @param whenProperties {Object} properties to define when's matching behavior
|
7437
7854
|
* @return {?Object}
|
7438
7855
|
*/
|
7439
|
-
function switchRouteMatcher(on, when) {
|
7856
|
+
function switchRouteMatcher(on, when, whenProperties) {
|
7440
7857
|
// TODO(i): this code is convoluted and inefficient, we should construct the route matching
|
7441
7858
|
// regex only once and then reuse it
|
7442
7859
|
|
7443
7860
|
// Escape regexp special characters.
|
7444
7861
|
when = '^' + when.replace(/[-\/\\^$:*+?.()|[\]{}]/g, "\\$&") + '$';
|
7862
|
+
|
7445
7863
|
var regex = '',
|
7446
7864
|
params = [],
|
7447
7865
|
dst = {};
|
@@ -7468,7 +7886,7 @@ function $RouteProvider(){
|
|
7468
7886
|
// Append trailing path part.
|
7469
7887
|
regex += when.substr(lastMatchedIndex);
|
7470
7888
|
|
7471
|
-
var match = on.match(new RegExp(regex));
|
7889
|
+
var match = on.match(new RegExp(regex, whenProperties.caseInsensitiveMatch ? 'i' : ''));
|
7472
7890
|
if (match) {
|
7473
7891
|
forEach(params, function(name, index) {
|
7474
7892
|
dst[name] = match[index + 1];
|
@@ -7481,7 +7899,7 @@ function $RouteProvider(){
|
|
7481
7899
|
var next = parseRoute(),
|
7482
7900
|
last = $route.current;
|
7483
7901
|
|
7484
|
-
if (next && last && next
|
7902
|
+
if (next && last && next.$$route === last.$$route
|
7485
7903
|
&& equals(next.pathParams, last.pathParams) && !next.reloadOnSearch && !forceReload) {
|
7486
7904
|
last.params = next.params;
|
7487
7905
|
copy(last.params, $routeParams);
|
@@ -7505,14 +7923,13 @@ function $RouteProvider(){
|
|
7505
7923
|
$q.when(next).
|
7506
7924
|
then(function() {
|
7507
7925
|
if (next) {
|
7508
|
-
var
|
7509
|
-
values = [],
|
7926
|
+
var locals = extend({}, next.resolve),
|
7510
7927
|
template;
|
7511
7928
|
|
7512
|
-
forEach(
|
7513
|
-
|
7514
|
-
values.push(isString(value) ? $injector.get(value) : $injector.invoke(value));
|
7929
|
+
forEach(locals, function(value, key) {
|
7930
|
+
locals[key] = isString(value) ? $injector.get(value) : $injector.invoke(value);
|
7515
7931
|
});
|
7932
|
+
|
7516
7933
|
if (isDefined(template = next.template)) {
|
7517
7934
|
if (isFunction(template)) {
|
7518
7935
|
template = template(next.params);
|
@@ -7528,16 +7945,9 @@ function $RouteProvider(){
|
|
7528
7945
|
}
|
7529
7946
|
}
|
7530
7947
|
if (isDefined(template)) {
|
7531
|
-
|
7532
|
-
values.push(template);
|
7948
|
+
locals['$template'] = template;
|
7533
7949
|
}
|
7534
|
-
return $q.all(
|
7535
|
-
var locals = {};
|
7536
|
-
forEach(values, function(value, index) {
|
7537
|
-
locals[keys[index]] = value;
|
7538
|
-
});
|
7539
|
-
return locals;
|
7540
|
-
});
|
7950
|
+
return $q.all(locals);
|
7541
7951
|
}
|
7542
7952
|
}).
|
7543
7953
|
// after route change
|
@@ -7565,11 +7975,11 @@ function $RouteProvider(){
|
|
7565
7975
|
// Match a route
|
7566
7976
|
var params, match;
|
7567
7977
|
forEach(routes, function(route, path) {
|
7568
|
-
if (!match && (params = switchRouteMatcher($location.path(), path))) {
|
7978
|
+
if (!match && (params = switchRouteMatcher($location.path(), path, route))) {
|
7569
7979
|
match = inherit(route, {
|
7570
7980
|
params: extend({}, $location.search(), params),
|
7571
7981
|
pathParams: params});
|
7572
|
-
match
|
7982
|
+
match.$$route = route;
|
7573
7983
|
}
|
7574
7984
|
});
|
7575
7985
|
// No route matched; fallback to "otherwise" route
|
@@ -7577,7 +7987,7 @@ function $RouteProvider(){
|
|
7577
7987
|
}
|
7578
7988
|
|
7579
7989
|
/**
|
7580
|
-
* @returns interpolation of the redirect path with the
|
7990
|
+
* @returns interpolation of the redirect path with the parameters
|
7581
7991
|
*/
|
7582
7992
|
function interpolate(string, params) {
|
7583
7993
|
var result = [];
|
@@ -7709,25 +8119,7 @@ function $RootScopeProvider(){
|
|
7709
8119
|
*
|
7710
8120
|
* Here is a simple scope snippet to show how you can interact with the scope.
|
7711
8121
|
* <pre>
|
7712
|
-
|
7713
|
-
var scope = $rootScope.$new();
|
7714
|
-
scope.salutation = 'Hello';
|
7715
|
-
scope.name = 'World';
|
7716
|
-
|
7717
|
-
expect(scope.greeting).toEqual(undefined);
|
7718
|
-
|
7719
|
-
scope.$watch('name', function() {
|
7720
|
-
scope.greeting = scope.salutation + ' ' + scope.name + '!';
|
7721
|
-
}); // initialize the watch
|
7722
|
-
|
7723
|
-
expect(scope.greeting).toEqual(undefined);
|
7724
|
-
scope.name = 'Misko';
|
7725
|
-
// still old value, since watches have not been called yet
|
7726
|
-
expect(scope.greeting).toEqual(undefined);
|
7727
|
-
|
7728
|
-
scope.$digest(); // fire all the watches
|
7729
|
-
expect(scope.greeting).toEqual('Hello Misko!');
|
7730
|
-
});
|
8122
|
+
* <file src="./test/ng/rootScopeSpec.js" tag="docs1" />
|
7731
8123
|
* </pre>
|
7732
8124
|
*
|
7733
8125
|
* # Inheritance
|
@@ -7946,51 +8338,192 @@ function $RootScopeProvider(){
|
|
7946
8338
|
};
|
7947
8339
|
},
|
7948
8340
|
|
8341
|
+
|
7949
8342
|
/**
|
7950
8343
|
* @ngdoc function
|
7951
|
-
* @name ng.$rootScope.Scope#$
|
8344
|
+
* @name ng.$rootScope.Scope#$watchCollection
|
7952
8345
|
* @methodOf ng.$rootScope.Scope
|
7953
8346
|
* @function
|
7954
8347
|
*
|
7955
8348
|
* @description
|
7956
|
-
*
|
7957
|
-
*
|
7958
|
-
*
|
7959
|
-
* firing. This means that it is possible to get into an infinite loop. This function will throw
|
7960
|
-
* `'Maximum iteration limit exceeded.'` if the number of iterations exceeds 10.
|
7961
|
-
*
|
7962
|
-
* Usually you don't call `$digest()` directly in
|
7963
|
-
* {@link ng.directive:ngController controllers} or in
|
7964
|
-
* {@link ng.$compileProvider#directive directives}.
|
7965
|
-
* Instead a call to {@link ng.$rootScope.Scope#$apply $apply()} (typically from within a
|
7966
|
-
* {@link ng.$compileProvider#directive directives}) will force a `$digest()`.
|
8349
|
+
* Shallow watches the properties of an object and fires whenever any of the properties change
|
8350
|
+
* (for arrays this implies watching the array items, for object maps this implies watching the properties).
|
8351
|
+
* If a change is detected the `listener` callback is fired.
|
7967
8352
|
*
|
7968
|
-
*
|
7969
|
-
*
|
7970
|
-
*
|
8353
|
+
* - The `obj` collection is observed via standard $watch operation and is examined on every call to $digest() to
|
8354
|
+
* see if any items have been added, removed, or moved.
|
8355
|
+
* - The `listener` is called whenever anything within the `obj` has changed. Examples include adding new items
|
8356
|
+
* into the object or array, removing and moving items around.
|
7971
8357
|
*
|
7972
|
-
* You may have a need to call `$digest()` from within unit-tests, to simulate the scope
|
7973
|
-
* life-cycle.
|
7974
8358
|
*
|
7975
8359
|
* # Example
|
7976
8360
|
* <pre>
|
7977
|
-
|
7978
|
-
|
7979
|
-
scope.counter = 0;
|
8361
|
+
$scope.names = ['igor', 'matias', 'misko', 'james'];
|
8362
|
+
$scope.dataCount = 4;
|
7980
8363
|
|
7981
|
-
|
7982
|
-
|
7983
|
-
|
7984
|
-
});
|
7985
|
-
expect(scope.counter).toEqual(0);
|
8364
|
+
$scope.$watchCollection('names', function(newNames, oldNames) {
|
8365
|
+
$scope.dataCount = newNames.length;
|
8366
|
+
});
|
7986
8367
|
|
7987
|
-
|
7988
|
-
|
7989
|
-
expect(scope.counter).toEqual(0);
|
8368
|
+
expect($scope.dataCount).toEqual(4);
|
8369
|
+
$scope.$digest();
|
7990
8370
|
|
7991
|
-
|
7992
|
-
|
7993
|
-
|
8371
|
+
//still at 4 ... no changes
|
8372
|
+
expect($scope.dataCount).toEqual(4);
|
8373
|
+
|
8374
|
+
$scope.names.pop();
|
8375
|
+
$scope.$digest();
|
8376
|
+
|
8377
|
+
//now there's been a change
|
8378
|
+
expect($scope.dataCount).toEqual(3);
|
8379
|
+
* </pre>
|
8380
|
+
*
|
8381
|
+
*
|
8382
|
+
* @param {string|Function(scope)} obj Evaluated as {@link guide/expression expression}. The expression value
|
8383
|
+
* should evaluate to an object or an array which is observed on each
|
8384
|
+
* {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the collection will trigger
|
8385
|
+
* a call to the `listener`.
|
8386
|
+
*
|
8387
|
+
* @param {function(newCollection, oldCollection, scope)} listener a callback function that is fired with both
|
8388
|
+
* the `newCollection` and `oldCollection` as parameters.
|
8389
|
+
* The `newCollection` object is the newly modified data obtained from the `obj` expression and the
|
8390
|
+
* `oldCollection` object is a copy of the former collection data.
|
8391
|
+
* The `scope` refers to the current scope.
|
8392
|
+
*
|
8393
|
+
* @returns {function()} Returns a de-registration function for this listener. When the de-registration function is executed
|
8394
|
+
* then the internal watch operation is terminated.
|
8395
|
+
*/
|
8396
|
+
$watchCollection: function(obj, listener) {
|
8397
|
+
var self = this;
|
8398
|
+
var oldValue;
|
8399
|
+
var newValue;
|
8400
|
+
var changeDetected = 0;
|
8401
|
+
var objGetter = $parse(obj);
|
8402
|
+
var internalArray = [];
|
8403
|
+
var internalObject = {};
|
8404
|
+
var oldLength = 0;
|
8405
|
+
|
8406
|
+
function $watchCollectionWatch() {
|
8407
|
+
newValue = objGetter(self);
|
8408
|
+
var newLength, key;
|
8409
|
+
|
8410
|
+
if (!isObject(newValue)) {
|
8411
|
+
if (oldValue !== newValue) {
|
8412
|
+
oldValue = newValue;
|
8413
|
+
changeDetected++;
|
8414
|
+
}
|
8415
|
+
} else if (isArray(newValue)) {
|
8416
|
+
if (oldValue !== internalArray) {
|
8417
|
+
// we are transitioning from something which was not an array into array.
|
8418
|
+
oldValue = internalArray;
|
8419
|
+
oldLength = oldValue.length = 0;
|
8420
|
+
changeDetected++;
|
8421
|
+
}
|
8422
|
+
|
8423
|
+
newLength = newValue.length;
|
8424
|
+
|
8425
|
+
if (oldLength !== newLength) {
|
8426
|
+
// if lengths do not match we need to trigger change notification
|
8427
|
+
changeDetected++;
|
8428
|
+
oldValue.length = oldLength = newLength;
|
8429
|
+
}
|
8430
|
+
// copy the items to oldValue and look for changes.
|
8431
|
+
for (var i = 0; i < newLength; i++) {
|
8432
|
+
if (oldValue[i] !== newValue[i]) {
|
8433
|
+
changeDetected++;
|
8434
|
+
oldValue[i] = newValue[i];
|
8435
|
+
}
|
8436
|
+
}
|
8437
|
+
} else {
|
8438
|
+
if (oldValue !== internalObject) {
|
8439
|
+
// we are transitioning from something which was not an object into object.
|
8440
|
+
oldValue = internalObject = {};
|
8441
|
+
oldLength = 0;
|
8442
|
+
changeDetected++;
|
8443
|
+
}
|
8444
|
+
// copy the items to oldValue and look for changes.
|
8445
|
+
newLength = 0;
|
8446
|
+
for (key in newValue) {
|
8447
|
+
if (newValue.hasOwnProperty(key)) {
|
8448
|
+
newLength++;
|
8449
|
+
if (oldValue.hasOwnProperty(key)) {
|
8450
|
+
if (oldValue[key] !== newValue[key]) {
|
8451
|
+
changeDetected++;
|
8452
|
+
oldValue[key] = newValue[key];
|
8453
|
+
}
|
8454
|
+
} else {
|
8455
|
+
oldLength++;
|
8456
|
+
oldValue[key] = newValue[key];
|
8457
|
+
changeDetected++;
|
8458
|
+
}
|
8459
|
+
}
|
8460
|
+
}
|
8461
|
+
if (oldLength > newLength) {
|
8462
|
+
// we used to have more keys, need to find them and destroy them.
|
8463
|
+
changeDetected++;
|
8464
|
+
for(key in oldValue) {
|
8465
|
+
if (oldValue.hasOwnProperty(key) && !newValue.hasOwnProperty(key)) {
|
8466
|
+
oldLength--;
|
8467
|
+
delete oldValue[key];
|
8468
|
+
}
|
8469
|
+
}
|
8470
|
+
}
|
8471
|
+
}
|
8472
|
+
return changeDetected;
|
8473
|
+
}
|
8474
|
+
|
8475
|
+
function $watchCollectionAction() {
|
8476
|
+
listener(newValue, oldValue, self);
|
8477
|
+
}
|
8478
|
+
|
8479
|
+
return this.$watch($watchCollectionWatch, $watchCollectionAction);
|
8480
|
+
},
|
8481
|
+
|
8482
|
+
/**
|
8483
|
+
* @ngdoc function
|
8484
|
+
* @name ng.$rootScope.Scope#$digest
|
8485
|
+
* @methodOf ng.$rootScope.Scope
|
8486
|
+
* @function
|
8487
|
+
*
|
8488
|
+
* @description
|
8489
|
+
* Process all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and its children.
|
8490
|
+
* Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change the model, the
|
8491
|
+
* `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers} until no more listeners are
|
8492
|
+
* firing. This means that it is possible to get into an infinite loop. This function will throw
|
8493
|
+
* `'Maximum iteration limit exceeded.'` if the number of iterations exceeds 10.
|
8494
|
+
*
|
8495
|
+
* Usually you don't call `$digest()` directly in
|
8496
|
+
* {@link ng.directive:ngController controllers} or in
|
8497
|
+
* {@link ng.$compileProvider#directive directives}.
|
8498
|
+
* Instead a call to {@link ng.$rootScope.Scope#$apply $apply()} (typically from within a
|
8499
|
+
* {@link ng.$compileProvider#directive directives}) will force a `$digest()`.
|
8500
|
+
*
|
8501
|
+
* If you want to be notified whenever `$digest()` is called,
|
8502
|
+
* you can register a `watchExpression` function with {@link ng.$rootScope.Scope#$watch $watch()}
|
8503
|
+
* with no `listener`.
|
8504
|
+
*
|
8505
|
+
* You may have a need to call `$digest()` from within unit-tests, to simulate the scope
|
8506
|
+
* life-cycle.
|
8507
|
+
*
|
8508
|
+
* # Example
|
8509
|
+
* <pre>
|
8510
|
+
var scope = ...;
|
8511
|
+
scope.name = 'misko';
|
8512
|
+
scope.counter = 0;
|
8513
|
+
|
8514
|
+
expect(scope.counter).toEqual(0);
|
8515
|
+
scope.$watch('name', function(newValue, oldValue) {
|
8516
|
+
scope.counter = scope.counter + 1;
|
8517
|
+
});
|
8518
|
+
expect(scope.counter).toEqual(0);
|
8519
|
+
|
8520
|
+
scope.$digest();
|
8521
|
+
// no variable change
|
8522
|
+
expect(scope.counter).toEqual(0);
|
8523
|
+
|
8524
|
+
scope.name = 'adam';
|
8525
|
+
scope.$digest();
|
8526
|
+
expect(scope.counter).toEqual(1);
|
7994
8527
|
* </pre>
|
7995
8528
|
*
|
7996
8529
|
*/
|
@@ -8362,7 +8895,7 @@ function $RootScopeProvider(){
|
|
8362
8895
|
* Afterwards, the event propagates to all direct and indirect scopes of the current scope and
|
8363
8896
|
* calls all registered listeners along the way. The event cannot be canceled.
|
8364
8897
|
*
|
8365
|
-
* Any exception
|
8898
|
+
* Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
|
8366
8899
|
* onto the {@link ng.$exceptionHandler $exceptionHandler} service.
|
8367
8900
|
*
|
8368
8901
|
* @param {string} name Event name to emit.
|
@@ -8459,6 +8992,7 @@ function $RootScopeProvider(){
|
|
8459
8992
|
*
|
8460
8993
|
* @property {boolean} history Does the browser support html5 history api ?
|
8461
8994
|
* @property {boolean} hashchange Does the browser support hashchange event ?
|
8995
|
+
* @property {boolean} supportsTransitions Does the browser support CSS transition events ?
|
8462
8996
|
*
|
8463
8997
|
* @description
|
8464
8998
|
* This is very simple implementation of testing browser's features.
|
@@ -8466,8 +9000,25 @@ function $RootScopeProvider(){
|
|
8466
9000
|
function $SnifferProvider() {
|
8467
9001
|
this.$get = ['$window', '$document', function($window, $document) {
|
8468
9002
|
var eventSupport = {},
|
8469
|
-
android = int((/android (\d+)/.exec(lowercase($window.navigator.userAgent)) || [])[1]),
|
8470
|
-
document = $document[0]
|
9003
|
+
android = int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
|
9004
|
+
document = $document[0] || {},
|
9005
|
+
vendorPrefix,
|
9006
|
+
vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/,
|
9007
|
+
bodyStyle = document.body && document.body.style,
|
9008
|
+
transitions = false,
|
9009
|
+
match;
|
9010
|
+
|
9011
|
+
if (bodyStyle) {
|
9012
|
+
for(var prop in bodyStyle) {
|
9013
|
+
if(match = vendorRegex.exec(prop)) {
|
9014
|
+
vendorPrefix = match[0];
|
9015
|
+
vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
|
9016
|
+
break;
|
9017
|
+
}
|
9018
|
+
}
|
9019
|
+
transitions = !!(vendorPrefix + 'Transition' in bodyStyle);
|
9020
|
+
}
|
9021
|
+
|
8471
9022
|
|
8472
9023
|
return {
|
8473
9024
|
// Android has history.pushState, but it does not update location correctly
|
@@ -8491,7 +9042,9 @@ function $SnifferProvider() {
|
|
8491
9042
|
|
8492
9043
|
return eventSupport[event];
|
8493
9044
|
},
|
8494
|
-
csp: document.securityPolicy ? document.securityPolicy.isActive : false
|
9045
|
+
csp: document.securityPolicy ? document.securityPolicy.isActive : false,
|
9046
|
+
vendorPrefix: vendorPrefix,
|
9047
|
+
supportsTransitions : transitions
|
8495
9048
|
};
|
8496
9049
|
}];
|
8497
9050
|
}
|
@@ -8504,7 +9057,7 @@ function $SnifferProvider() {
|
|
8504
9057
|
* A reference to the browser's `window` object. While `window`
|
8505
9058
|
* is globally available in JavaScript, it causes testability problems, because
|
8506
9059
|
* it is a global variable. In angular we always refer to it through the
|
8507
|
-
* `$window` service, so it may be
|
9060
|
+
* `$window` service, so it may be overridden, removed or mocked for testing.
|
8508
9061
|
*
|
8509
9062
|
* All expressions are evaluated with respect to current scope so they don't
|
8510
9063
|
* suffer from window globality.
|
@@ -8678,20 +9231,52 @@ function $HttpProvider() {
|
|
8678
9231
|
xsrfHeaderName: 'X-XSRF-TOKEN'
|
8679
9232
|
};
|
8680
9233
|
|
8681
|
-
|
9234
|
+
/**
|
9235
|
+
* Are order by request. I.E. they are applied in the same order as
|
9236
|
+
* array on request, but revers order on response.
|
9237
|
+
*/
|
9238
|
+
var interceptorFactories = this.interceptors = [];
|
9239
|
+
/**
|
9240
|
+
* For historical reasons, response interceptors ordered by the order in which
|
9241
|
+
* they are applied to response. (This is in revers to interceptorFactories)
|
9242
|
+
*/
|
9243
|
+
var responseInterceptorFactories = this.responseInterceptors = [];
|
8682
9244
|
|
8683
9245
|
this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
|
8684
9246
|
function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
|
8685
9247
|
|
8686
|
-
var defaultCache = $cacheFactory('$http')
|
8687
|
-
responseInterceptors = [];
|
9248
|
+
var defaultCache = $cacheFactory('$http');
|
8688
9249
|
|
8689
|
-
|
8690
|
-
|
8691
|
-
|
8692
|
-
|
8693
|
-
|
8694
|
-
|
9250
|
+
/**
|
9251
|
+
* Interceptors stored in reverse order. Inner interceptors before outer interceptors.
|
9252
|
+
* The reversal is needed so that we can build up the interception chain around the
|
9253
|
+
* server request.
|
9254
|
+
*/
|
9255
|
+
var reversedInterceptors = [];
|
9256
|
+
|
9257
|
+
forEach(interceptorFactories, function(interceptorFactory) {
|
9258
|
+
reversedInterceptors.unshift(isString(interceptorFactory)
|
9259
|
+
? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
|
9260
|
+
});
|
9261
|
+
|
9262
|
+
forEach(responseInterceptorFactories, function(interceptorFactory, index) {
|
9263
|
+
var responseFn = isString(interceptorFactory)
|
9264
|
+
? $injector.get(interceptorFactory)
|
9265
|
+
: $injector.invoke(interceptorFactory);
|
9266
|
+
|
9267
|
+
/**
|
9268
|
+
* Response interceptors go before "around" interceptors (no real reason, just
|
9269
|
+
* had to pick one.) But they are already revesed, so we can't use unshift, hence
|
9270
|
+
* the splice.
|
9271
|
+
*/
|
9272
|
+
reversedInterceptors.splice(index, 0, {
|
9273
|
+
response: function(response) {
|
9274
|
+
return responseFn($q.when(response));
|
9275
|
+
},
|
9276
|
+
responseError: function(response) {
|
9277
|
+
return responseFn($q.reject(response));
|
9278
|
+
}
|
9279
|
+
});
|
8695
9280
|
});
|
8696
9281
|
|
8697
9282
|
|
@@ -8788,7 +9373,7 @@ function $HttpProvider() {
|
|
8788
9373
|
* `$httpProvider.defaults.headers.get['My-Header']='value'`.
|
8789
9374
|
*
|
8790
9375
|
* Additionally, the defaults can be set at runtime via the `$http.defaults` object in a similar
|
8791
|
-
*
|
9376
|
+
* fashion as described above.
|
8792
9377
|
*
|
8793
9378
|
*
|
8794
9379
|
* # Transforming Requests and Responses
|
@@ -8806,10 +9391,14 @@ function $HttpProvider() {
|
|
8806
9391
|
* - if XSRF prefix is detected, strip it (see Security Considerations section below)
|
8807
9392
|
* - if json response is detected, deserialize it using a JSON parser
|
8808
9393
|
*
|
8809
|
-
* To override
|
8810
|
-
*
|
8811
|
-
*
|
8812
|
-
*
|
9394
|
+
* To globally augment or override the default transforms, modify the `$httpProvider.defaults.transformRequest` and
|
9395
|
+
* `$httpProvider.defaults.transformResponse` properties of the `$httpProvider`. These properties are by default an
|
9396
|
+
* array of transform functions, which allows you to `push` or `unshift` a new transformation function into the
|
9397
|
+
* transformation chain. You can also decide to completely override any default transformations by assigning your
|
9398
|
+
* transformation functions to these properties directly without the array wrapper.
|
9399
|
+
*
|
9400
|
+
* Similarly, to locally override the request/response transforms, augment the `transformRequest` and/or
|
9401
|
+
* `transformResponse` properties of the config object passed into `$http`.
|
8813
9402
|
*
|
8814
9403
|
*
|
8815
9404
|
* # Caching
|
@@ -8825,8 +9414,94 @@ function $HttpProvider() {
|
|
8825
9414
|
* cache, but the cache is not populated yet, only one request to the server will be made and
|
8826
9415
|
* the remaining requests will be fulfilled using the response for the first request.
|
8827
9416
|
*
|
9417
|
+
* A custom default cache built with $cacheFactory can be provided in $http.defaults.cache.
|
9418
|
+
* To skip it, set configuration property `cache` to `false`.
|
9419
|
+
*
|
8828
9420
|
*
|
8829
|
-
* #
|
9421
|
+
* # Interceptors
|
9422
|
+
*
|
9423
|
+
* Before you start creating interceptors, be sure to understand the
|
9424
|
+
* {@link ng.$q $q and deferred/promise APIs}.
|
9425
|
+
*
|
9426
|
+
* For purposes of global error handling, authentication or any kind of synchronous or
|
9427
|
+
* asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
|
9428
|
+
* able to intercept requests before they are handed to the server and
|
9429
|
+
* responses before they are handed over to the application code that
|
9430
|
+
* initiated these requests. The interceptors leverage the {@link ng.$q
|
9431
|
+
* promise APIs} to fulfil this need for both synchronous and asynchronous pre-processing.
|
9432
|
+
*
|
9433
|
+
* The interceptors are service factories that are registered with the $httpProvider by
|
9434
|
+
* adding them to the `$httpProvider.interceptors` array. The factory is called and
|
9435
|
+
* injected with dependencies (if specified) and returns the interceptor.
|
9436
|
+
*
|
9437
|
+
* There are two kinds of interceptors (and two kinds of rejection interceptors):
|
9438
|
+
*
|
9439
|
+
* * `request`: interceptors get called with http `config` object. The function is free to modify
|
9440
|
+
* the `config` or create a new one. The function needs to return the `config` directly or as a
|
9441
|
+
* promise.
|
9442
|
+
* * `requestError`: interceptor gets called when a previous interceptor threw an error or resolved
|
9443
|
+
* with a rejection.
|
9444
|
+
* * `response`: interceptors get called with http `response` object. The function is free to modify
|
9445
|
+
* the `response` or create a new one. The function needs to return the `response` directly or as a
|
9446
|
+
* promise.
|
9447
|
+
* * `responseError`: interceptor gets called when a previous interceptor threw an error or resolved
|
9448
|
+
* with a rejection.
|
9449
|
+
*
|
9450
|
+
*
|
9451
|
+
* <pre>
|
9452
|
+
* // register the interceptor as a service
|
9453
|
+
* $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
|
9454
|
+
* return {
|
9455
|
+
* // optional method
|
9456
|
+
* 'request': function(config) {
|
9457
|
+
* // do something on success
|
9458
|
+
* return config || $q.when(config);
|
9459
|
+
* },
|
9460
|
+
*
|
9461
|
+
* // optional method
|
9462
|
+
* 'requestError': function(rejection) {
|
9463
|
+
* // do something on error
|
9464
|
+
* if (canRecover(rejection)) {
|
9465
|
+
* return responseOrNewPromise
|
9466
|
+
* }
|
9467
|
+
* return $q.reject(rejection);
|
9468
|
+
* },
|
9469
|
+
*
|
9470
|
+
*
|
9471
|
+
*
|
9472
|
+
* // optional method
|
9473
|
+
* 'response': function(response) {
|
9474
|
+
* // do something on success
|
9475
|
+
* return response || $q.when(response);
|
9476
|
+
* },
|
9477
|
+
*
|
9478
|
+
* // optional method
|
9479
|
+
* 'responseError': function(rejection) {
|
9480
|
+
* // do something on error
|
9481
|
+
* if (canRecover(rejection)) {
|
9482
|
+
* return responseOrNewPromise
|
9483
|
+
* }
|
9484
|
+
* return $q.reject(rejection);
|
9485
|
+
* };
|
9486
|
+
* }
|
9487
|
+
* });
|
9488
|
+
*
|
9489
|
+
* $httpProvider.interceptors.push('myHttpInterceptor');
|
9490
|
+
*
|
9491
|
+
*
|
9492
|
+
* // register the interceptor via an anonymous factory
|
9493
|
+
* $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
|
9494
|
+
* return {
|
9495
|
+
* 'request': function(config) {
|
9496
|
+
* // same as above
|
9497
|
+
* },
|
9498
|
+
* 'response': function(response) {
|
9499
|
+
* // same as above
|
9500
|
+
* }
|
9501
|
+
* });
|
9502
|
+
* </pre>
|
9503
|
+
*
|
9504
|
+
* # Response interceptors (DEPRECATED)
|
8830
9505
|
*
|
8831
9506
|
* Before you start creating interceptors, be sure to understand the
|
8832
9507
|
* {@link ng.$q $q and deferred/promise APIs}.
|
@@ -9042,45 +9717,66 @@ function $HttpProvider() {
|
|
9042
9717
|
</file>
|
9043
9718
|
</example>
|
9044
9719
|
*/
|
9045
|
-
function $http(
|
9046
|
-
config
|
9720
|
+
function $http(requestConfig) {
|
9721
|
+
var config = {
|
9722
|
+
transformRequest: defaults.transformRequest,
|
9723
|
+
transformResponse: defaults.transformResponse
|
9724
|
+
};
|
9725
|
+
var headers = {};
|
9047
9726
|
|
9048
|
-
|
9049
|
-
|
9050
|
-
|
9051
|
-
xsrfToken = isSameDomain(config.url, $browser.url()) ?
|
9052
|
-
$browser.cookies()[xsrfCookieName] : undefined;
|
9053
|
-
xsrfHeader[xsrfHeaderName] = xsrfToken;
|
9727
|
+
extend(config, requestConfig);
|
9728
|
+
config.headers = headers;
|
9729
|
+
config.method = uppercase(config.method);
|
9054
9730
|
|
9055
|
-
|
9056
|
-
|
9057
|
-
|
9058
|
-
|
9059
|
-
defHeaders.common, defHeaders[lowercase(config.method)], config.headers),
|
9060
|
-
reqData = transformData(config.data, headersGetter(reqHeaders), reqTransformFn),
|
9061
|
-
promise;
|
9731
|
+
extend(headers,
|
9732
|
+
defaults.headers.common,
|
9733
|
+
defaults.headers[lowercase(config.method)],
|
9734
|
+
requestConfig.headers);
|
9062
9735
|
|
9063
|
-
|
9064
|
-
|
9065
|
-
|
9736
|
+
var xsrfValue = isSameDomain(config.url, $browser.url())
|
9737
|
+
? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName]
|
9738
|
+
: undefined;
|
9739
|
+
if (xsrfValue) {
|
9740
|
+
headers[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
|
9066
9741
|
}
|
9067
9742
|
|
9068
|
-
if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
|
9069
|
-
config.withCredentials = defaults.withCredentials;
|
9070
|
-
}
|
9071
9743
|
|
9072
|
-
|
9073
|
-
|
9744
|
+
var serverRequest = function(config) {
|
9745
|
+
var reqData = transformData(config.data, headersGetter(headers), config.transformRequest);
|
9746
|
+
|
9747
|
+
// strip content-type if data is undefined
|
9748
|
+
if (isUndefined(config.data)) {
|
9749
|
+
delete headers['Content-Type'];
|
9750
|
+
}
|
9751
|
+
|
9752
|
+
if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
|
9753
|
+
config.withCredentials = defaults.withCredentials;
|
9754
|
+
}
|
9074
9755
|
|
9756
|
+
// send request
|
9757
|
+
return sendReq(config, reqData, headers).then(transformResponse, transformResponse);
|
9758
|
+
};
|
9075
9759
|
|
9076
|
-
|
9077
|
-
promise =
|
9760
|
+
var chain = [serverRequest, undefined];
|
9761
|
+
var promise = $q.when(config);
|
9078
9762
|
|
9079
9763
|
// apply interceptors
|
9080
|
-
forEach(
|
9081
|
-
|
9764
|
+
forEach(reversedInterceptors, function(interceptor) {
|
9765
|
+
if (interceptor.request || interceptor.requestError) {
|
9766
|
+
chain.unshift(interceptor.request, interceptor.requestError);
|
9767
|
+
}
|
9768
|
+
if (interceptor.response || interceptor.responseError) {
|
9769
|
+
chain.push(interceptor.response, interceptor.responseError);
|
9770
|
+
}
|
9082
9771
|
});
|
9083
9772
|
|
9773
|
+
while(chain.length) {
|
9774
|
+
var thenFn = chain.shift();
|
9775
|
+
var rejectFn = chain.shift();
|
9776
|
+
|
9777
|
+
promise = promise.then(thenFn, rejectFn);
|
9778
|
+
};
|
9779
|
+
|
9084
9780
|
promise.success = function(fn) {
|
9085
9781
|
promise.then(function(response) {
|
9086
9782
|
fn(response.data, response.status, response.headers, config);
|
@@ -9100,7 +9796,7 @@ function $HttpProvider() {
|
|
9100
9796
|
function transformResponse(response) {
|
9101
9797
|
// make a copy since the response must be cacheable
|
9102
9798
|
var resp = extend({}, response, {
|
9103
|
-
data: transformData(response.data, response.headers,
|
9799
|
+
data: transformData(response.data, response.headers, config.transformResponse)
|
9104
9800
|
});
|
9105
9801
|
return (isSuccess(response.status))
|
9106
9802
|
? resp
|
@@ -9252,8 +9948,10 @@ function $HttpProvider() {
|
|
9252
9948
|
promise.then(removePendingReq, removePendingReq);
|
9253
9949
|
|
9254
9950
|
|
9255
|
-
if (config.cache && config.method == 'GET') {
|
9256
|
-
cache = isObject(config.cache) ? config.cache
|
9951
|
+
if ((config.cache || defaults.cache) && config.cache !== false && config.method == 'GET') {
|
9952
|
+
cache = isObject(config.cache) ? config.cache
|
9953
|
+
: isObject(defaults.cache) ? defaults.cache
|
9954
|
+
: defaultCache;
|
9257
9955
|
}
|
9258
9956
|
|
9259
9957
|
if (cache) {
|
@@ -9351,6 +10049,7 @@ function $HttpProvider() {
|
|
9351
10049
|
|
9352
10050
|
}];
|
9353
10051
|
}
|
10052
|
+
|
9354
10053
|
var XHR = window.XMLHttpRequest || function() {
|
9355
10054
|
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
|
9356
10055
|
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
|
@@ -9440,8 +10139,12 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
|
|
9440
10139
|
}
|
9441
10140
|
// end of the workaround.
|
9442
10141
|
|
9443
|
-
|
9444
|
-
|
10142
|
+
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
|
10143
|
+
// response and responseType properties were introduced in XHR Level2 spec (supported by IE10)
|
10144
|
+
completeRequest(callback,
|
10145
|
+
status || xhr.status,
|
10146
|
+
(xhr.responseType ? xhr.response : xhr.responseText),
|
10147
|
+
responseHeaders);
|
9445
10148
|
}
|
9446
10149
|
};
|
9447
10150
|
|
@@ -9667,7 +10370,7 @@ function $TimeoutProvider() {
|
|
9667
10370
|
*
|
9668
10371
|
* Filters are just functions which transform input to an output. However filters need to be Dependency Injected. To
|
9669
10372
|
* achieve this a filter definition consists of a factory function which is annotated with dependencies and is
|
9670
|
-
* responsible for creating a
|
10373
|
+
* responsible for creating a filter function.
|
9671
10374
|
*
|
9672
10375
|
* <pre>
|
9673
10376
|
* // Filter registration
|
@@ -9822,11 +10525,11 @@ function $FilterProvider($provide) {
|
|
9822
10525
|
|
9823
10526
|
Search: <input ng-model="searchText">
|
9824
10527
|
<table id="searchTextResults">
|
9825
|
-
<tr><th>Name</th><th>Phone</th
|
10528
|
+
<tr><th>Name</th><th>Phone</th></tr>
|
9826
10529
|
<tr ng-repeat="friend in friends | filter:searchText">
|
9827
10530
|
<td>{{friend.name}}</td>
|
9828
10531
|
<td>{{friend.phone}}</td>
|
9829
|
-
|
10532
|
+
</tr>
|
9830
10533
|
</table>
|
9831
10534
|
<hr>
|
9832
10535
|
Any: <input ng-model="search.$"> <br>
|
@@ -9834,11 +10537,11 @@ function $FilterProvider($provide) {
|
|
9834
10537
|
Phone only <input ng-model="search.phone"å><br>
|
9835
10538
|
Equality <input type="checkbox" ng-model="strict"><br>
|
9836
10539
|
<table id="searchObjResults">
|
9837
|
-
<tr><th>Name</th><th>Phone</th
|
10540
|
+
<tr><th>Name</th><th>Phone</th></tr>
|
9838
10541
|
<tr ng-repeat="friend in friends | filter:search:strict">
|
9839
10542
|
<td>{{friend.name}}</td>
|
9840
10543
|
<td>{{friend.phone}}</td>
|
9841
|
-
|
10544
|
+
</tr>
|
9842
10545
|
</table>
|
9843
10546
|
</doc:source>
|
9844
10547
|
<doc:scenario>
|
@@ -10185,7 +10888,8 @@ function timeZoneGetter(date) {
|
|
10185
10888
|
var zone = -1 * date.getTimezoneOffset();
|
10186
10889
|
var paddedZone = (zone >= 0) ? "+" : "";
|
10187
10890
|
|
10188
|
-
paddedZone += padNumber(zone
|
10891
|
+
paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
|
10892
|
+
padNumber(Math.abs(zone % 60), 2);
|
10189
10893
|
|
10190
10894
|
return paddedZone;
|
10191
10895
|
}
|
@@ -10255,7 +10959,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
|
|
10255
10959
|
* * `'s'`: Second in minute (0-59)
|
10256
10960
|
* * `'.sss' or ',sss'`: Millisecond in second, padded (000-999)
|
10257
10961
|
* * `'a'`: am/pm marker
|
10258
|
-
* * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200
|
10962
|
+
* * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
|
10259
10963
|
*
|
10260
10964
|
* `format` string can also be one of the following predefined
|
10261
10965
|
* {@link guide/i18n localizable formats}:
|
@@ -10545,7 +11249,7 @@ function limitToFilter(){
|
|
10545
11249
|
* Orders a specified `array` by the `expression` predicate.
|
10546
11250
|
*
|
10547
11251
|
* Note: this function is used to augment the `Array` type in Angular expressions. See
|
10548
|
-
* {@link ng.$filter} for more
|
11252
|
+
* {@link ng.$filter} for more information about Angular arrays.
|
10549
11253
|
*
|
10550
11254
|
* @param {Array} array The array to sort.
|
10551
11255
|
* @param {function(*)|string|Array.<(function(*)|string)>} expression A predicate to be
|
@@ -10588,12 +11292,12 @@ function limitToFilter(){
|
|
10588
11292
|
(<a href ng-click="predicate = '-name'; reverse=false">^</a>)</th>
|
10589
11293
|
<th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
|
10590
11294
|
<th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
|
10591
|
-
|
11295
|
+
</tr>
|
10592
11296
|
<tr ng-repeat="friend in friends | orderBy:predicate:reverse">
|
10593
11297
|
<td>{{friend.name}}</td>
|
10594
11298
|
<td>{{friend.phone}}</td>
|
10595
11299
|
<td>{{friend.age}}</td>
|
10596
|
-
|
11300
|
+
</tr>
|
10597
11301
|
</table>
|
10598
11302
|
</div>
|
10599
11303
|
</doc:source>
|
@@ -12195,7 +12899,7 @@ var VALID_CLASS = 'ng-valid',
|
|
12195
12899
|
* @property {Array.<Function>} $formatters Whenever the model value changes, it executes all of
|
12196
12900
|
* these functions to convert the value as well as validate.
|
12197
12901
|
*
|
12198
|
-
* @property {Object} $error An
|
12902
|
+
* @property {Object} $error An object hash with all errors as keys.
|
12199
12903
|
*
|
12200
12904
|
* @property {boolean} $pristine True if user has not interacted with the control yet.
|
12201
12905
|
* @property {boolean} $dirty True if user has already interacted with the control.
|
@@ -12703,7 +13407,7 @@ var ngValueDirective = function() {
|
|
12703
13407
|
* Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
|
12704
13408
|
* `{{ expression }}` which is similar but less verbose.
|
12705
13409
|
*
|
12706
|
-
* Once scenario in which the use of `ngBind` is
|
13410
|
+
* Once scenario in which the use of `ngBind` is preferred over `{{ expression }}` binding is when
|
12707
13411
|
* it's desirable to put bindings into template that is momentarily displayed by the browser in its
|
12708
13412
|
* raw state before Angular compiles it. Since `ngBind` is an element attribute, it makes the
|
12709
13413
|
* bindings invisible to the user while the page is loading.
|
@@ -13041,13 +13745,13 @@ var ngClassEvenDirective = classDirective('Even', 1);
|
|
13041
13745
|
* directive to avoid the undesirable flicker effect caused by the html template display.
|
13042
13746
|
*
|
13043
13747
|
* The directive can be applied to the `<body>` element, but typically a fine-grained application is
|
13044
|
-
*
|
13748
|
+
* preferred in order to benefit from progressive rendering of the browser view.
|
13045
13749
|
*
|
13046
13750
|
* `ngCloak` works in cooperation with a css rule that is embedded within `angular.js` and
|
13047
13751
|
* `angular.min.js` files. Following is the css rule:
|
13048
13752
|
*
|
13049
13753
|
* <pre>
|
13050
|
-
* [ng\:cloak], [ng-cloak], .ng-cloak {
|
13754
|
+
* [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
|
13051
13755
|
* display: none;
|
13052
13756
|
* }
|
13053
13757
|
* </pre>
|
@@ -13256,7 +13960,7 @@ var ngCspDirective = ['$sniffer', function($sniffer) {
|
|
13256
13960
|
*/
|
13257
13961
|
var ngEventDirectives = {};
|
13258
13962
|
forEach(
|
13259
|
-
'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup'.split(' '),
|
13963
|
+
'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress'.split(' '),
|
13260
13964
|
function(name) {
|
13261
13965
|
var directiveName = directiveNormalize('ng-' + name);
|
13262
13966
|
ngEventDirectives[directiveName] = ['$parse', function($parse) {
|
@@ -13415,6 +14119,22 @@ forEach(
|
|
13415
14119
|
*/
|
13416
14120
|
|
13417
14121
|
|
14122
|
+
/**
|
14123
|
+
* @ngdoc directive
|
14124
|
+
* @name ng.directive:ngKeypress
|
14125
|
+
*
|
14126
|
+
* @description
|
14127
|
+
* Specify custom behavior on keypress event.
|
14128
|
+
*
|
14129
|
+
* @element ANY
|
14130
|
+
* @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
|
14131
|
+
* keypress. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
|
14132
|
+
*
|
14133
|
+
* @example
|
14134
|
+
* See {@link ng.directive:ngClick ngClick}
|
14135
|
+
*/
|
14136
|
+
|
14137
|
+
|
13418
14138
|
/**
|
13419
14139
|
* @ngdoc directive
|
13420
14140
|
* @name ng.directive:ngSubmit
|
@@ -13484,6 +14204,13 @@ var ngSubmitDirective = ngDirective(function(scope, element, attrs) {
|
|
13484
14204
|
* (e.g. ngInclude won't work for cross-domain requests on all browsers and for
|
13485
14205
|
* file:// access on some browsers).
|
13486
14206
|
*
|
14207
|
+
* Additionally, you can also provide animations via the ngAnimate attribute to animate the **enter**
|
14208
|
+
* and **leave** effects.
|
14209
|
+
*
|
14210
|
+
* @animations
|
14211
|
+
* enter - happens just after the ngInclude contents change and a new DOM element is created and injected into the ngInclude container
|
14212
|
+
* leave - happens just after the ngInclude contents change and just before the former contents are removed from the DOM
|
14213
|
+
*
|
13487
14214
|
* @scope
|
13488
14215
|
*
|
13489
14216
|
* @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
|
@@ -13506,7 +14233,9 @@ var ngSubmitDirective = ngDirective(function(scope, element, attrs) {
|
|
13506
14233
|
</select>
|
13507
14234
|
url of the template: <tt>{{template.url}}</tt>
|
13508
14235
|
<hr/>
|
13509
|
-
<div
|
14236
|
+
<div class="example-animate-container"
|
14237
|
+
ng-include="template.url"
|
14238
|
+
ng-animate="{enter: 'example-enter', leave: 'example-leave'}"></div>
|
13510
14239
|
</div>
|
13511
14240
|
</file>
|
13512
14241
|
<file name="script.js">
|
@@ -13518,10 +14247,45 @@ var ngSubmitDirective = ngDirective(function(scope, element, attrs) {
|
|
13518
14247
|
}
|
13519
14248
|
</file>
|
13520
14249
|
<file name="template1.html">
|
13521
|
-
Content of template1.html
|
14250
|
+
<div>Content of template1.html</div>
|
13522
14251
|
</file>
|
13523
14252
|
<file name="template2.html">
|
13524
|
-
Content of template2.html
|
14253
|
+
<div>Content of template2.html</div>
|
14254
|
+
</file>
|
14255
|
+
<file name="animations.css">
|
14256
|
+
.example-leave-setup,
|
14257
|
+
.example-enter-setup {
|
14258
|
+
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
14259
|
+
-moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
14260
|
+
-ms-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
14261
|
+
-o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
14262
|
+
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
14263
|
+
|
14264
|
+
position:absolute;
|
14265
|
+
top:0;
|
14266
|
+
left:0;
|
14267
|
+
right:0;
|
14268
|
+
bottom:0;
|
14269
|
+
}
|
14270
|
+
|
14271
|
+
.example-animate-container > * {
|
14272
|
+
display:block;
|
14273
|
+
padding:10px;
|
14274
|
+
}
|
14275
|
+
|
14276
|
+
.example-enter-setup {
|
14277
|
+
top:-50px;
|
14278
|
+
}
|
14279
|
+
.example-enter-setup.example-enter-start {
|
14280
|
+
top:0;
|
14281
|
+
}
|
14282
|
+
|
14283
|
+
.example-leave-setup {
|
14284
|
+
top:0;
|
14285
|
+
}
|
14286
|
+
.example-leave-setup.example-leave-start {
|
14287
|
+
top:50px;
|
14288
|
+
}
|
13525
14289
|
</file>
|
13526
14290
|
<file name="scenario.js">
|
13527
14291
|
it('should load template1.html', function() {
|
@@ -13550,8 +14314,8 @@ var ngSubmitDirective = ngDirective(function(scope, element, attrs) {
|
|
13550
14314
|
* @description
|
13551
14315
|
* Emitted every time the ngInclude content is reloaded.
|
13552
14316
|
*/
|
13553
|
-
var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile',
|
13554
|
-
function($http, $templateCache, $anchorScroll, $compile) {
|
14317
|
+
var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile', '$animator',
|
14318
|
+
function($http, $templateCache, $anchorScroll, $compile, $animator) {
|
13555
14319
|
return {
|
13556
14320
|
restrict: 'ECA',
|
13557
14321
|
terminal: true,
|
@@ -13560,7 +14324,8 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
|
|
13560
14324
|
onloadExp = attr.onload || '',
|
13561
14325
|
autoScrollExp = attr.autoscroll;
|
13562
14326
|
|
13563
|
-
return function(scope, element) {
|
14327
|
+
return function(scope, element, attr) {
|
14328
|
+
var animate = $animator(scope, attr);
|
13564
14329
|
var changeCounter = 0,
|
13565
14330
|
childScope;
|
13566
14331
|
|
@@ -13569,8 +14334,7 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
|
|
13569
14334
|
childScope.$destroy();
|
13570
14335
|
childScope = null;
|
13571
14336
|
}
|
13572
|
-
|
13573
|
-
element.html('');
|
14337
|
+
animate.leave(element.contents(), element);
|
13574
14338
|
};
|
13575
14339
|
|
13576
14340
|
scope.$watch(srcExp, function ngIncludeWatchAction(src) {
|
@@ -13582,9 +14346,12 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
|
|
13582
14346
|
|
13583
14347
|
if (childScope) childScope.$destroy();
|
13584
14348
|
childScope = scope.$new();
|
14349
|
+
animate.leave(element.contents(), element);
|
13585
14350
|
|
13586
|
-
|
13587
|
-
|
14351
|
+
var contents = jqLite('<div/>').html(response).contents();
|
14352
|
+
|
14353
|
+
animate.enter(contents, element);
|
14354
|
+
$compile(contents)(childScope);
|
13588
14355
|
|
13589
14356
|
if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
|
13590
14357
|
$anchorScroll();
|
@@ -13595,7 +14362,9 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
|
|
13595
14362
|
}).error(function() {
|
13596
14363
|
if (thisChangeId === changeCounter) clearContent();
|
13597
14364
|
});
|
13598
|
-
} else
|
14365
|
+
} else {
|
14366
|
+
clearContent();
|
14367
|
+
}
|
13599
14368
|
});
|
13600
14369
|
};
|
13601
14370
|
}
|
@@ -13689,7 +14458,7 @@ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
|
|
13689
14458
|
* {@link http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
|
13690
14459
|
* plural categories} in Angular's default en-US locale: "one" and "other".
|
13691
14460
|
*
|
13692
|
-
* While a
|
14461
|
+
* While a plural category may match many numbers (for example, in en-US locale, "other" can match
|
13693
14462
|
* any number that is not 1), an explicit number rule can only match one number. For example, the
|
13694
14463
|
* explicit number rule for "3" matches the number 3. You will see the use of plural categories
|
13695
14464
|
* and explicit number rules throughout later parts of this documentation.
|
@@ -13757,7 +14526,7 @@ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
|
|
13757
14526
|
* plural categories "one" and "other".
|
13758
14527
|
*
|
13759
14528
|
* @param {string|expression} count The variable to be bounded to.
|
13760
|
-
* @param {string} when The mapping between plural category to its
|
14529
|
+
* @param {string} when The mapping between plural category to its corresponding strings.
|
13761
14530
|
* @param {number=} offset Offset to deduct from the total number.
|
13762
14531
|
*
|
13763
14532
|
* @example
|
@@ -13892,11 +14661,18 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
|
|
13892
14661
|
* * `$middle` – `{boolean}` – true if the repeated element is between the first and last in the iterator.
|
13893
14662
|
* * `$last` – `{boolean}` – true if the repeated element is last in the iterator.
|
13894
14663
|
*
|
14664
|
+
* Additionally, you can also provide animations via the ngAnimate attribute to animate the **enter**,
|
14665
|
+
* **leave** and **move** effects.
|
14666
|
+
*
|
14667
|
+
* @animations
|
14668
|
+
* enter - when a new item is added to the list or when an item is revealed after a filter
|
14669
|
+
* leave - when an item is removed from the list or when an item is filtered out
|
14670
|
+
* move - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
|
13895
14671
|
*
|
13896
14672
|
* @element ANY
|
13897
14673
|
* @scope
|
13898
14674
|
* @priority 1000
|
13899
|
-
* @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection.
|
14675
|
+
* @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
|
13900
14676
|
* formats are currently supported:
|
13901
14677
|
*
|
13902
14678
|
* * `variable in expression` – where variable is the user defined loop variable and `expression`
|
@@ -13909,160 +14685,278 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
|
|
13909
14685
|
*
|
13910
14686
|
* For example: `(name, age) in {'adam':10, 'amalie':12}`.
|
13911
14687
|
*
|
14688
|
+
* * `variable in expression track by tracking_expression` – You can also provide an optional tracking function
|
14689
|
+
* which can be used to associate the objects in the collection with the DOM elements. If no tractking function
|
14690
|
+
* is specified the ng-repeat associates elements by identity in the collection. It is an error to have
|
14691
|
+
* more then one tractking function to resolve to the same key. (This would mean that two distinct objects are
|
14692
|
+
* mapped to the same DOM element, which is not possible.)
|
14693
|
+
*
|
14694
|
+
* For example: `item in items` is equivalent to `item in items track by $id(item)'. This implies that the DOM elements
|
14695
|
+
* will be associated by item identity in the array.
|
14696
|
+
*
|
14697
|
+
* For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
|
14698
|
+
* `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
|
14699
|
+
* with the corresponding item in the array by identity. Moving the same object in array would move the DOM
|
14700
|
+
* element in the same way ian the DOM.
|
14701
|
+
*
|
14702
|
+
* For example: `item in items track by item.id` Is a typical pattern when the items come from the database. In this
|
14703
|
+
* case the object identity does not matter. Two objects are considered equivalent as long as their `id`
|
14704
|
+
* property is same.
|
14705
|
+
*
|
13912
14706
|
* @example
|
13913
14707
|
* This example initializes the scope to a list of names and
|
13914
14708
|
* then uses `ngRepeat` to display every person:
|
13915
|
-
|
13916
|
-
|
13917
|
-
|
13918
|
-
|
13919
|
-
|
13920
|
-
|
13921
|
-
|
13922
|
-
|
13923
|
-
|
13924
|
-
|
13925
|
-
|
13926
|
-
|
13927
|
-
|
13928
|
-
|
13929
|
-
|
13930
|
-
|
13931
|
-
|
13932
|
-
|
13933
|
-
|
13934
|
-
|
13935
|
-
|
13936
|
-
|
13937
|
-
|
13938
|
-
|
13939
|
-
|
13940
|
-
|
13941
|
-
|
13942
|
-
|
13943
|
-
|
13944
|
-
|
13945
|
-
|
13946
|
-
|
13947
|
-
|
13948
|
-
|
13949
|
-
|
13950
|
-
|
13951
|
-
match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
|
13952
|
-
if (!match) {
|
13953
|
-
throw Error("'item' in 'item in collection' should be identifier or (key, value) but got '" +
|
13954
|
-
lhs + "'.");
|
13955
|
-
}
|
13956
|
-
valueIdent = match[3] || match[1];
|
13957
|
-
keyIdent = match[2];
|
13958
|
-
|
13959
|
-
// Store a list of elements from previous run. This is a hash where key is the item from the
|
13960
|
-
// iterator, and the value is an array of objects with following properties.
|
13961
|
-
// - scope: bound scope
|
13962
|
-
// - element: previous element.
|
13963
|
-
// - index: position
|
13964
|
-
// We need an array of these objects since the same object can be returned from the iterator.
|
13965
|
-
// We expect this to be a rare case.
|
13966
|
-
var lastOrder = new HashQueueMap();
|
13967
|
-
|
13968
|
-
scope.$watch(function ngRepeatWatch(scope){
|
13969
|
-
var index, length,
|
13970
|
-
collection = scope.$eval(rhs),
|
13971
|
-
cursor = iterStartElement, // current position of the node
|
13972
|
-
// Same as lastOrder but it has the current state. It will become the
|
13973
|
-
// lastOrder on the next iteration.
|
13974
|
-
nextOrder = new HashQueueMap(),
|
13975
|
-
arrayLength,
|
13976
|
-
childScope,
|
13977
|
-
key, value, // key/value of iteration
|
13978
|
-
array,
|
13979
|
-
last; // last object information {scope, element, index}
|
13980
|
-
|
13981
|
-
|
13982
|
-
|
13983
|
-
if (!isArray(collection)) {
|
13984
|
-
// if object, extract keys, sort them and use to determine order of iteration over obj props
|
13985
|
-
array = [];
|
13986
|
-
for(key in collection) {
|
13987
|
-
if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
|
13988
|
-
array.push(key);
|
13989
|
-
}
|
13990
|
-
}
|
13991
|
-
array.sort();
|
13992
|
-
} else {
|
13993
|
-
array = collection || [];
|
13994
|
-
}
|
14709
|
+
<example animations="true">
|
14710
|
+
<file name="index.html">
|
14711
|
+
<div ng-init="friends = [
|
14712
|
+
{name:'John', age:25, gender:'boy'},
|
14713
|
+
{name:'Jessie', age:30, gender:'girl'},
|
14714
|
+
{name:'Johanna', age:28, gender:'girl'},
|
14715
|
+
{name:'Joy', age:15, gender:'girl'},
|
14716
|
+
{name:'Mary', age:28, gender:'girl'},
|
14717
|
+
{name:'Peter', age:95, gender:'boy'},
|
14718
|
+
{name:'Sebastian', age:50, gender:'boy'},
|
14719
|
+
{name:'Erika', age:27, gender:'girl'},
|
14720
|
+
{name:'Patrick', age:40, gender:'boy'},
|
14721
|
+
{name:'Samantha', age:60, gender:'girl'}
|
14722
|
+
]">
|
14723
|
+
I have {{friends.length}} friends. They are:
|
14724
|
+
<input type="search" ng-model="q" placeholder="filter friends..." />
|
14725
|
+
<ul>
|
14726
|
+
<li ng-repeat="friend in friends | filter:q"
|
14727
|
+
ng-animate="{enter: 'example-repeat-enter',
|
14728
|
+
leave: 'example-repeat-leave',
|
14729
|
+
move: 'example-repeat-move'}">
|
14730
|
+
[{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
|
14731
|
+
</li>
|
14732
|
+
</ul>
|
14733
|
+
</div>
|
14734
|
+
</file>
|
14735
|
+
<file name="animations.css">
|
14736
|
+
.example-repeat-enter-setup,
|
14737
|
+
.example-repeat-leave-setup,
|
14738
|
+
.example-repeat-move-setup {
|
14739
|
+
-webkit-transition:all linear 0.5s;
|
14740
|
+
-moz-transition:all linear 0.5s;
|
14741
|
+
-ms-transition:all linear 0.5s;
|
14742
|
+
-o-transition:all linear 0.5s;
|
14743
|
+
transition:all linear 0.5s;
|
14744
|
+
}
|
13995
14745
|
|
13996
|
-
|
14746
|
+
.example-repeat-enter-setup {
|
14747
|
+
line-height:0;
|
14748
|
+
opacity:0;
|
14749
|
+
}
|
14750
|
+
.example-repeat-enter-setup.example-repeat-enter-start {
|
14751
|
+
line-height:20px;
|
14752
|
+
opacity:1;
|
14753
|
+
}
|
13997
14754
|
|
13998
|
-
|
13999
|
-
|
14000
|
-
|
14001
|
-
|
14755
|
+
.example-repeat-leave-setup {
|
14756
|
+
opacity:1;
|
14757
|
+
line-height:20px;
|
14758
|
+
}
|
14759
|
+
.example-repeat-leave-setup.example-repeat-leave-start {
|
14760
|
+
opacity:0;
|
14761
|
+
line-height:0;
|
14762
|
+
}
|
14002
14763
|
|
14003
|
-
|
14764
|
+
.example-repeat-move-setup { }
|
14765
|
+
.example-repeat-move-setup.example-repeat-move-start { }
|
14766
|
+
</file>
|
14767
|
+
<file name="scenario.js">
|
14768
|
+
it('should render initial data set', function() {
|
14769
|
+
var r = using('.doc-example-live').repeater('ul li');
|
14770
|
+
expect(r.count()).toBe(10);
|
14771
|
+
expect(r.row(0)).toEqual(["1","John","25"]);
|
14772
|
+
expect(r.row(1)).toEqual(["2","Jessie","30"]);
|
14773
|
+
expect(r.row(9)).toEqual(["10","Samantha","60"]);
|
14774
|
+
expect(binding('friends.length')).toBe("10");
|
14775
|
+
});
|
14004
14776
|
|
14005
|
-
|
14006
|
-
|
14007
|
-
|
14008
|
-
childScope = last.scope;
|
14009
|
-
nextOrder.push(value, last);
|
14777
|
+
it('should update repeater when filter predicate changes', function() {
|
14778
|
+
var r = using('.doc-example-live').repeater('ul li');
|
14779
|
+
expect(r.count()).toBe(10);
|
14010
14780
|
|
14011
|
-
|
14012
|
-
// do nothing
|
14013
|
-
cursor = last.element;
|
14014
|
-
} else {
|
14015
|
-
// existing item which got moved
|
14016
|
-
last.index = index;
|
14017
|
-
// This may be a noop, if the element is next, but I don't know of a good way to
|
14018
|
-
// figure this out, since it would require extra DOM access, so let's just hope that
|
14019
|
-
// the browsers realizes that it is noop, and treats it as such.
|
14020
|
-
cursor.after(last.element);
|
14021
|
-
cursor = last.element;
|
14022
|
-
}
|
14023
|
-
} else {
|
14024
|
-
// new item which we don't know about
|
14025
|
-
childScope = scope.$new();
|
14026
|
-
}
|
14781
|
+
input('q').enter('ma');
|
14027
14782
|
|
14028
|
-
|
14029
|
-
|
14030
|
-
|
14031
|
-
|
14032
|
-
|
14033
|
-
|
14034
|
-
|
14035
|
-
|
14036
|
-
|
14037
|
-
|
14038
|
-
|
14039
|
-
|
14040
|
-
|
14041
|
-
|
14042
|
-
|
14043
|
-
|
14044
|
-
|
14045
|
-
|
14783
|
+
expect(r.count()).toBe(2);
|
14784
|
+
expect(r.row(0)).toEqual(["1","Mary","28"]);
|
14785
|
+
expect(r.row(1)).toEqual(["2","Samantha","60"]);
|
14786
|
+
});
|
14787
|
+
</file>
|
14788
|
+
</example>
|
14789
|
+
*/
|
14790
|
+
var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {
|
14791
|
+
var NG_REMOVED = '$$NG_REMOVED';
|
14792
|
+
return {
|
14793
|
+
transclude: 'element',
|
14794
|
+
priority: 1000,
|
14795
|
+
terminal: true,
|
14796
|
+
compile: function(element, attr, linker) {
|
14797
|
+
return function($scope, $element, $attr){
|
14798
|
+
var animate = $animator($scope, $attr);
|
14799
|
+
var expression = $attr.ngRepeat;
|
14800
|
+
var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),
|
14801
|
+
trackByExp, hashExpFn, trackByIdFn, lhs, rhs, valueIdentifier, keyIdentifier,
|
14802
|
+
hashFnLocals = {$id: hashKey};
|
14803
|
+
|
14804
|
+
if (!match) {
|
14805
|
+
throw Error("Expected ngRepeat in form of '_item_ in _collection_[ track by _id_]' but got '" +
|
14806
|
+
expression + "'.");
|
14807
|
+
}
|
14808
|
+
|
14809
|
+
lhs = match[1];
|
14810
|
+
rhs = match[2];
|
14811
|
+
trackByExp = match[4];
|
14812
|
+
|
14813
|
+
if (trackByExp) {
|
14814
|
+
hashExpFn = $parse(trackByExp);
|
14815
|
+
trackByIdFn = function(key, value, index) {
|
14816
|
+
// assign key, value, and $index to the locals so that they can be used in hash functions
|
14817
|
+
if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
|
14818
|
+
hashFnLocals[valueIdentifier] = value;
|
14819
|
+
hashFnLocals.$index = index;
|
14820
|
+
return hashExpFn($scope, hashFnLocals);
|
14821
|
+
};
|
14822
|
+
} else {
|
14823
|
+
trackByIdFn = function(key, value) {
|
14824
|
+
return hashKey(value);
|
14046
14825
|
}
|
14047
14826
|
}
|
14048
14827
|
|
14049
|
-
|
14050
|
-
|
14051
|
-
|
14052
|
-
|
14053
|
-
|
14054
|
-
|
14055
|
-
|
14056
|
-
|
14828
|
+
match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
|
14829
|
+
if (!match) {
|
14830
|
+
throw Error("'item' in 'item in collection' should be identifier or (key, value) but got '" +
|
14831
|
+
lhs + "'.");
|
14832
|
+
}
|
14833
|
+
valueIdentifier = match[3] || match[1];
|
14834
|
+
keyIdentifier = match[2];
|
14835
|
+
|
14836
|
+
// Store a list of elements from previous run. This is a hash where key is the item from the
|
14837
|
+
// iterator, and the value is objects with following properties.
|
14838
|
+
// - scope: bound scope
|
14839
|
+
// - element: previous element.
|
14840
|
+
// - index: position
|
14841
|
+
var lastBlockMap = {};
|
14842
|
+
|
14843
|
+
//watch props
|
14844
|
+
$scope.$watchCollection(rhs, function ngRepeatAction(collection){
|
14845
|
+
var index, length,
|
14846
|
+
cursor = $element, // current position of the node
|
14847
|
+
nextCursor,
|
14848
|
+
// Same as lastBlockMap but it has the current state. It will become the
|
14849
|
+
// lastBlockMap on the next iteration.
|
14850
|
+
nextBlockMap = {},
|
14851
|
+
arrayLength,
|
14852
|
+
childScope,
|
14853
|
+
key, value, // key/value of iteration
|
14854
|
+
trackById,
|
14855
|
+
collectionKeys,
|
14856
|
+
block, // last object information {scope, element, id}
|
14857
|
+
nextBlockOrder = [];
|
14858
|
+
|
14859
|
+
|
14860
|
+
if (isArray(collection)) {
|
14861
|
+
collectionKeys = collection;
|
14862
|
+
} else {
|
14863
|
+
// if object, extract keys, sort them and use to determine order of iteration over obj props
|
14864
|
+
collectionKeys = [];
|
14865
|
+
for (key in collection) {
|
14866
|
+
if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
|
14867
|
+
collectionKeys.push(key);
|
14868
|
+
}
|
14869
|
+
}
|
14870
|
+
collectionKeys.sort();
|
14871
|
+
}
|
14872
|
+
|
14873
|
+
arrayLength = collectionKeys.length;
|
14874
|
+
|
14875
|
+
// locate existing items
|
14876
|
+
length = nextBlockOrder.length = collectionKeys.length;
|
14877
|
+
for(index = 0; index < length; index++) {
|
14878
|
+
key = (collection === collectionKeys) ? index : collectionKeys[index];
|
14879
|
+
value = collection[key];
|
14880
|
+
trackById = trackByIdFn(key, value, index);
|
14881
|
+
if((block = lastBlockMap[trackById])) {
|
14882
|
+
delete lastBlockMap[trackById];
|
14883
|
+
nextBlockMap[trackById] = block;
|
14884
|
+
nextBlockOrder[index] = block;
|
14885
|
+
} else if (nextBlockMap.hasOwnProperty(trackById)) {
|
14886
|
+
// restore lastBlockMap
|
14887
|
+
forEach(nextBlockOrder, function(block) {
|
14888
|
+
if (block && block.element) lastBlockMap[block.id] = block;
|
14889
|
+
});
|
14890
|
+
// This is a duplicate and we need to throw an error
|
14891
|
+
throw new Error('Duplicates in a repeater are not allowed. Repeater: ' + expression);
|
14892
|
+
} else {
|
14893
|
+
// new never before seen block
|
14894
|
+
nextBlockOrder[index] = { id: trackById };
|
14895
|
+
}
|
14896
|
+
}
|
14897
|
+
|
14898
|
+
// remove existing items
|
14899
|
+
for (key in lastBlockMap) {
|
14900
|
+
if (lastBlockMap.hasOwnProperty(key)) {
|
14901
|
+
block = lastBlockMap[key];
|
14902
|
+
animate.leave(block.element);
|
14903
|
+
block.element[0][NG_REMOVED] = true;
|
14904
|
+
block.scope.$destroy();
|
14057
14905
|
}
|
14058
14906
|
}
|
14059
|
-
}
|
14060
14907
|
|
14061
|
-
|
14062
|
-
|
14063
|
-
|
14064
|
-
|
14065
|
-
|
14908
|
+
// we are not using forEach for perf reasons (trying to avoid #call)
|
14909
|
+
for (index = 0, length = collectionKeys.length; index < length; index++) {
|
14910
|
+
key = (collection === collectionKeys) ? index : collectionKeys[index];
|
14911
|
+
value = collection[key];
|
14912
|
+
block = nextBlockOrder[index];
|
14913
|
+
|
14914
|
+
if (block.element) {
|
14915
|
+
// if we have already seen this object, then we need to reuse the
|
14916
|
+
// associated scope/element
|
14917
|
+
childScope = block.scope;
|
14918
|
+
|
14919
|
+
nextCursor = cursor[0];
|
14920
|
+
do {
|
14921
|
+
nextCursor = nextCursor.nextSibling;
|
14922
|
+
} while(nextCursor && nextCursor[NG_REMOVED]);
|
14923
|
+
|
14924
|
+
if (block.element[0] == nextCursor) {
|
14925
|
+
// do nothing
|
14926
|
+
cursor = block.element;
|
14927
|
+
} else {
|
14928
|
+
// existing item which got moved
|
14929
|
+
animate.move(block.element, null, cursor);
|
14930
|
+
cursor = block.element;
|
14931
|
+
}
|
14932
|
+
} else {
|
14933
|
+
// new item which we don't know about
|
14934
|
+
childScope = $scope.$new();
|
14935
|
+
}
|
14936
|
+
|
14937
|
+
childScope[valueIdentifier] = value;
|
14938
|
+
if (keyIdentifier) childScope[keyIdentifier] = key;
|
14939
|
+
childScope.$index = index;
|
14940
|
+
childScope.$first = (index === 0);
|
14941
|
+
childScope.$last = (index === (arrayLength - 1));
|
14942
|
+
childScope.$middle = !(childScope.$first || childScope.$last);
|
14943
|
+
|
14944
|
+
if (!block.element) {
|
14945
|
+
linker(childScope, function(clone) {
|
14946
|
+
animate.enter(clone, null, cursor);
|
14947
|
+
cursor = clone;
|
14948
|
+
block.scope = childScope;
|
14949
|
+
block.element = clone;
|
14950
|
+
nextBlockMap[block.id] = block;
|
14951
|
+
});
|
14952
|
+
}
|
14953
|
+
}
|
14954
|
+
lastBlockMap = nextBlockMap;
|
14955
|
+
});
|
14956
|
+
};
|
14957
|
+
}
|
14958
|
+
};
|
14959
|
+
}];
|
14066
14960
|
|
14067
14961
|
/**
|
14068
14962
|
* @ngdoc directive
|
@@ -14070,20 +14964,86 @@ var ngRepeatDirective = ngDirective({
|
|
14070
14964
|
*
|
14071
14965
|
* @description
|
14072
14966
|
* The `ngShow` and `ngHide` directives show or hide a portion of the DOM tree (HTML)
|
14073
|
-
* conditionally.
|
14967
|
+
* conditionally based on **"truthy"** values evaluated within an {expression}. In other
|
14968
|
+
* words, if the expression assigned to **ngShow evaluates to a true value** then **the element is set to visible**
|
14969
|
+
* (via `display:block` in css) and **if false** then **the element is set to hidden** (so display:none).
|
14970
|
+
* With ngHide this is the reverse whereas true values cause the element itself to become
|
14971
|
+
* hidden.
|
14972
|
+
*
|
14973
|
+
* Additionally, you can also provide animations via the ngAnimate attribute to animate the **show**
|
14974
|
+
* and **hide** effects.
|
14975
|
+
*
|
14976
|
+
* @animations
|
14977
|
+
* show - happens after the ngShow expression evaluates to a truthy value and the contents are set to visible
|
14978
|
+
* hide - happens before the ngShow expression evaluates to a non truthy value and just before the contents are set to hidden
|
14074
14979
|
*
|
14075
14980
|
* @element ANY
|
14076
14981
|
* @param {expression} ngShow If the {@link guide/expression expression} is truthy
|
14077
14982
|
* then the element is shown or hidden respectively.
|
14078
14983
|
*
|
14079
14984
|
* @example
|
14080
|
-
|
14081
|
-
|
14082
|
-
|
14083
|
-
|
14084
|
-
|
14085
|
-
|
14086
|
-
|
14985
|
+
<example animations="true">
|
14986
|
+
<file name="index.html">
|
14987
|
+
Click me: <input type="checkbox" ng-model="checked"><br/>
|
14988
|
+
<div>
|
14989
|
+
Show:
|
14990
|
+
<span class="check-element"
|
14991
|
+
ng-show="checked"
|
14992
|
+
ng-animate="{show: 'example-show', hide: 'example-hide'}">
|
14993
|
+
<span class="icon-thumbs-up"></span> I show up when your checkbox is checked.
|
14994
|
+
</span>
|
14995
|
+
</div>
|
14996
|
+
<div>
|
14997
|
+
Hide:
|
14998
|
+
<span class="check-element"
|
14999
|
+
ng-hide="checked"
|
15000
|
+
ng-animate="{show: 'example-show', hide: 'example-hide'}">
|
15001
|
+
<span class="icon-thumbs-down"></span> I hide when your checkbox is checked.
|
15002
|
+
</span>
|
15003
|
+
</div>
|
15004
|
+
</file>
|
15005
|
+
<file name="animations.css">
|
15006
|
+
.example-show-setup, .example-hide-setup {
|
15007
|
+
-webkit-transition:all linear 0.5s;
|
15008
|
+
-moz-transition:all linear 0.5s;
|
15009
|
+
-ms-transition:all linear 0.5s;
|
15010
|
+
-o-transition:all linear 0.5s;
|
15011
|
+
transition:all linear 0.5s;
|
15012
|
+
}
|
15013
|
+
|
15014
|
+
.example-show-setup {
|
15015
|
+
line-height:0;
|
15016
|
+
opacity:0;
|
15017
|
+
padding:0 10px;
|
15018
|
+
}
|
15019
|
+
.example-show-start.example-show-start {
|
15020
|
+
line-height:20px;
|
15021
|
+
opacity:1;
|
15022
|
+
padding:10px;
|
15023
|
+
border:1px solid black;
|
15024
|
+
background:white;
|
15025
|
+
}
|
15026
|
+
|
15027
|
+
.example-hide-setup {
|
15028
|
+
line-height:20px;
|
15029
|
+
opacity:1;
|
15030
|
+
padding:10px;
|
15031
|
+
border:1px solid black;
|
15032
|
+
background:white;
|
15033
|
+
}
|
15034
|
+
.example-hide-start.example-hide-start {
|
15035
|
+
line-height:0;
|
15036
|
+
opacity:0;
|
15037
|
+
padding:0 10px;
|
15038
|
+
}
|
15039
|
+
|
15040
|
+
.check-element {
|
15041
|
+
padding:10px;
|
15042
|
+
border:1px solid black;
|
15043
|
+
background:white;
|
15044
|
+
}
|
15045
|
+
</file>
|
15046
|
+
<file name="scenario.js">
|
14087
15047
|
it('should check ng-show / ng-hide', function() {
|
14088
15048
|
expect(element('.doc-example-live span:first:hidden').count()).toEqual(1);
|
14089
15049
|
expect(element('.doc-example-live span:last:visible').count()).toEqual(1);
|
@@ -14093,15 +15053,18 @@ var ngRepeatDirective = ngDirective({
|
|
14093
15053
|
expect(element('.doc-example-live span:first:visible').count()).toEqual(1);
|
14094
15054
|
expect(element('.doc-example-live span:last:hidden').count()).toEqual(1);
|
14095
15055
|
});
|
14096
|
-
|
14097
|
-
|
15056
|
+
</file>
|
15057
|
+
</example>
|
14098
15058
|
*/
|
14099
15059
|
//TODO(misko): refactor to remove element from the DOM
|
14100
|
-
var ngShowDirective =
|
14101
|
-
scope
|
14102
|
-
|
14103
|
-
|
14104
|
-
|
15060
|
+
var ngShowDirective = ['$animator', function($animator) {
|
15061
|
+
return function(scope, element, attr) {
|
15062
|
+
var animate = $animator(scope, attr);
|
15063
|
+
scope.$watch(attr.ngShow, function ngShowWatchAction(value){
|
15064
|
+
animate[toBoolean(value) ? 'show' : 'hide'](element);
|
15065
|
+
});
|
15066
|
+
};
|
15067
|
+
}];
|
14105
15068
|
|
14106
15069
|
|
14107
15070
|
/**
|
@@ -14109,39 +15072,108 @@ var ngShowDirective = ngDirective(function(scope, element, attr){
|
|
14109
15072
|
* @name ng.directive:ngHide
|
14110
15073
|
*
|
14111
15074
|
* @description
|
14112
|
-
* The `
|
14113
|
-
* conditionally.
|
15075
|
+
* The `ngShow` and `ngHide` directives show or hide a portion of the DOM tree (HTML)
|
15076
|
+
* conditionally based on **"truthy"** values evaluated within an {expression}. In other
|
15077
|
+
* words, if the expression assigned to **ngShow evaluates to a true value** then **the element is set to visible**
|
15078
|
+
* (via `display:block` in css) and **if false** then **the element is set to hidden** (so display:none).
|
15079
|
+
* With ngHide this is the reverse whereas true values cause the element itself to become
|
15080
|
+
* hidden.
|
15081
|
+
*
|
15082
|
+
* Additionally, you can also provide animations via the ngAnimate attribute to animate the **show**
|
15083
|
+
* and **hide** effects.
|
15084
|
+
*
|
15085
|
+
* @animations
|
15086
|
+
* show - happens after the ngHide expression evaluates to a non truthy value and the contents are set to visible
|
15087
|
+
* hide - happens after the ngHide expression evaluates to a truthy value and just before the contents are set to hidden
|
14114
15088
|
*
|
14115
15089
|
* @element ANY
|
14116
15090
|
* @param {expression} ngHide If the {@link guide/expression expression} is truthy then
|
14117
15091
|
* the element is shown or hidden respectively.
|
14118
15092
|
*
|
14119
15093
|
* @example
|
14120
|
-
|
14121
|
-
|
14122
|
-
|
14123
|
-
|
14124
|
-
|
14125
|
-
|
14126
|
-
|
15094
|
+
<example animations="true">
|
15095
|
+
<file name="index.html">
|
15096
|
+
Click me: <input type="checkbox" ng-model="checked"><br/>
|
15097
|
+
<div>
|
15098
|
+
Show:
|
15099
|
+
<span class="check-element"
|
15100
|
+
ng-show="checked"
|
15101
|
+
ng-animate="{show: 'example-show', hide: 'example-hide'}">
|
15102
|
+
<span class="icon-thumbs-up"></span> I show up when your checkbox is checked.
|
15103
|
+
</span>
|
15104
|
+
</div>
|
15105
|
+
<div>
|
15106
|
+
Hide:
|
15107
|
+
<span class="check-element"
|
15108
|
+
ng-hide="checked"
|
15109
|
+
ng-animate="{show: 'example-show', hide: 'example-hide'}">
|
15110
|
+
<span class="icon-thumbs-down"></span> I hide when your checkbox is checked.
|
15111
|
+
</span>
|
15112
|
+
</div>
|
15113
|
+
</file>
|
15114
|
+
<file name="animations.css">
|
15115
|
+
.example-show-setup, .example-hide-setup {
|
15116
|
+
-webkit-transition:all linear 0.5s;
|
15117
|
+
-moz-transition:all linear 0.5s;
|
15118
|
+
-ms-transition:all linear 0.5s;
|
15119
|
+
-o-transition:all linear 0.5s;
|
15120
|
+
transition:all linear 0.5s;
|
15121
|
+
}
|
15122
|
+
|
15123
|
+
.example-show-setup {
|
15124
|
+
line-height:0;
|
15125
|
+
opacity:0;
|
15126
|
+
padding:0 10px;
|
15127
|
+
}
|
15128
|
+
.example-show-start.example-show-start {
|
15129
|
+
line-height:20px;
|
15130
|
+
opacity:1;
|
15131
|
+
padding:10px;
|
15132
|
+
border:1px solid black;
|
15133
|
+
background:white;
|
15134
|
+
}
|
15135
|
+
|
15136
|
+
.example-hide-setup {
|
15137
|
+
line-height:20px;
|
15138
|
+
opacity:1;
|
15139
|
+
padding:10px;
|
15140
|
+
border:1px solid black;
|
15141
|
+
background:white;
|
15142
|
+
}
|
15143
|
+
.example-hide-start.example-hide-start {
|
15144
|
+
line-height:0;
|
15145
|
+
opacity:0;
|
15146
|
+
padding:0 10px;
|
15147
|
+
}
|
15148
|
+
|
15149
|
+
.check-element {
|
15150
|
+
padding:10px;
|
15151
|
+
border:1px solid black;
|
15152
|
+
background:white;
|
15153
|
+
}
|
15154
|
+
</file>
|
15155
|
+
<file name="scenario.js">
|
14127
15156
|
it('should check ng-show / ng-hide', function() {
|
14128
|
-
expect(element('.doc-example-live
|
14129
|
-
expect(element('.doc-example-live
|
15157
|
+
expect(element('.doc-example-live .check-element:first:hidden').count()).toEqual(1);
|
15158
|
+
expect(element('.doc-example-live .check-element:last:visible').count()).toEqual(1);
|
14130
15159
|
|
14131
15160
|
input('checked').check();
|
14132
15161
|
|
14133
|
-
expect(element('.doc-example-live
|
14134
|
-
expect(element('.doc-example-live
|
15162
|
+
expect(element('.doc-example-live .check-element:first:visible').count()).toEqual(1);
|
15163
|
+
expect(element('.doc-example-live .check-element:last:hidden').count()).toEqual(1);
|
14135
15164
|
});
|
14136
|
-
|
14137
|
-
|
15165
|
+
</file>
|
15166
|
+
</example>
|
14138
15167
|
*/
|
14139
15168
|
//TODO(misko): refactor to remove element from the DOM
|
14140
|
-
var ngHideDirective =
|
14141
|
-
scope
|
14142
|
-
|
14143
|
-
|
14144
|
-
|
15169
|
+
var ngHideDirective = ['$animator', function($animator) {
|
15170
|
+
return function(scope, element, attr) {
|
15171
|
+
var animate = $animator(scope, attr);
|
15172
|
+
scope.$watch(attr.ngHide, function ngHideWatchAction(value){
|
15173
|
+
animate[toBoolean(value) ? 'hide' : 'show'](element);
|
15174
|
+
});
|
15175
|
+
};
|
15176
|
+
}];
|
14145
15177
|
|
14146
15178
|
/**
|
14147
15179
|
* @ngdoc directive
|
@@ -14195,18 +15227,37 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
|
|
14195
15227
|
* @restrict EA
|
14196
15228
|
*
|
14197
15229
|
* @description
|
14198
|
-
*
|
15230
|
+
* The ngSwitch directive is used to conditionally swap DOM structure on your template based on a scope expression.
|
15231
|
+
* Elements within ngSwitch but without ngSwitchWhen or ngSwitchDefault directives will be preserved at the location
|
15232
|
+
* as specified in the template.
|
15233
|
+
*
|
15234
|
+
* The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
|
15235
|
+
* from the template cache), ngSwitch simply choses one of the nested elements and makes it visible based on which element
|
15236
|
+
* matches the value obtained from the evaluated expression. In other words, you define a container element
|
15237
|
+
* (where you place the directive), place an expression on the **on="..." attribute**
|
15238
|
+
* (or the **ng-switch="..." attribute**), define any inner elements inside of the directive and place
|
15239
|
+
* a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
|
15240
|
+
* expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
|
15241
|
+
* attribute is displayed.
|
15242
|
+
*
|
15243
|
+
* Additionally, you can also provide animations via the ngAnimate attribute to animate the **enter**
|
15244
|
+
* and **leave** effects.
|
14199
15245
|
*
|
14200
|
-
* @
|
14201
|
-
*
|
15246
|
+
* @animations
|
15247
|
+
* enter - happens after the ngSwtich contents change and the matched child element is placed inside the container
|
15248
|
+
* leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
|
15249
|
+
*
|
15250
|
+
* @usage
|
15251
|
+
* <ANY ng-switch="expression">
|
15252
|
+
* <ANY ng-switch-when="matchValue1">...</ANY>
|
14202
15253
|
* <ANY ng-switch-when="matchValue2">...</ANY>
|
14203
|
-
* ...
|
14204
15254
|
* <ANY ng-switch-default>...</ANY>
|
15255
|
+
* </ANY>
|
14205
15256
|
*
|
14206
15257
|
* @scope
|
14207
15258
|
* @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
|
14208
15259
|
* @paramDescription
|
14209
|
-
* On child
|
15260
|
+
* On child elements add:
|
14210
15261
|
*
|
14211
15262
|
* * `ngSwitchWhen`: the case statement to match against. If match then this
|
14212
15263
|
* case will be displayed. If the same match appears multiple times, all the
|
@@ -14215,79 +15266,122 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
|
|
14215
15266
|
* are multiple default cases, all of them will be displayed when no other
|
14216
15267
|
* case match.
|
14217
15268
|
*
|
15269
|
+
*
|
14218
15270
|
* @example
|
14219
|
-
|
14220
|
-
|
14221
|
-
|
14222
|
-
|
14223
|
-
|
14224
|
-
|
14225
|
-
|
14226
|
-
|
14227
|
-
|
14228
|
-
|
14229
|
-
|
14230
|
-
<tt>selection={{selection}}</tt>
|
14231
|
-
<hr/>
|
14232
|
-
<div ng-switch on="selection" >
|
15271
|
+
<example animations="true">
|
15272
|
+
<file name="index.html">
|
15273
|
+
<div ng-controller="Ctrl">
|
15274
|
+
<select ng-model="selection" ng-options="item for item in items">
|
15275
|
+
</select>
|
15276
|
+
<tt>selection={{selection}}</tt>
|
15277
|
+
<hr/>
|
15278
|
+
<div
|
15279
|
+
class="example-animate-container"
|
15280
|
+
ng-switch on="selection"
|
15281
|
+
ng-animate="{enter: 'example-enter', leave: 'example-leave'}">
|
14233
15282
|
<div ng-switch-when="settings">Settings Div</div>
|
14234
|
-
<
|
14235
|
-
<
|
14236
|
-
</div>
|
15283
|
+
<div ng-switch-when="home">Home Span</div>
|
15284
|
+
<div ng-switch-default>default</div>
|
14237
15285
|
</div>
|
14238
|
-
</
|
14239
|
-
|
14240
|
-
|
14241
|
-
|
14242
|
-
|
14243
|
-
|
14244
|
-
|
14245
|
-
|
14246
|
-
|
14247
|
-
|
14248
|
-
|
14249
|
-
|
14250
|
-
|
14251
|
-
|
14252
|
-
|
14253
|
-
*/
|
14254
|
-
var NG_SWITCH = 'ng-switch';
|
14255
|
-
var ngSwitchDirective = valueFn({
|
14256
|
-
restrict: 'EA',
|
14257
|
-
require: 'ngSwitch',
|
14258
|
-
// asks for $scope to fool the BC controller module
|
14259
|
-
controller: ['$scope', function ngSwitchController() {
|
14260
|
-
this.cases = {};
|
14261
|
-
}],
|
14262
|
-
link: function(scope, element, attr, ctrl) {
|
14263
|
-
var watchExpr = attr.ngSwitch || attr.on,
|
14264
|
-
selectedTranscludes,
|
14265
|
-
selectedElements,
|
14266
|
-
selectedScopes = [];
|
15286
|
+
</div>
|
15287
|
+
</file>
|
15288
|
+
<file name="script.js">
|
15289
|
+
function Ctrl($scope) {
|
15290
|
+
$scope.items = ['settings', 'home', 'other'];
|
15291
|
+
$scope.selection = $scope.items[0];
|
15292
|
+
}
|
15293
|
+
</file>
|
15294
|
+
<file name="animations.css">
|
15295
|
+
.example-leave-setup, .example-enter-setup {
|
15296
|
+
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
15297
|
+
-moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
15298
|
+
-ms-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
15299
|
+
-o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
15300
|
+
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
14267
15301
|
|
14268
|
-
|
14269
|
-
|
14270
|
-
|
14271
|
-
|
15302
|
+
position:absolute;
|
15303
|
+
top:0;
|
15304
|
+
left:0;
|
15305
|
+
right:0;
|
15306
|
+
bottom:0;
|
14272
15307
|
}
|
14273
15308
|
|
14274
|
-
|
14275
|
-
|
15309
|
+
.example-animate-container > * {
|
15310
|
+
display:block;
|
15311
|
+
padding:10px;
|
15312
|
+
}
|
14276
15313
|
|
14277
|
-
|
14278
|
-
|
14279
|
-
forEach(selectedTranscludes, function(selectedTransclude) {
|
14280
|
-
var selectedScope = scope.$new();
|
14281
|
-
selectedScopes.push(selectedScope);
|
14282
|
-
selectedTransclude(selectedScope, function(caseElement) {
|
14283
|
-
selectedElements.push(caseElement);
|
14284
|
-
element.append(caseElement);
|
14285
|
-
});
|
14286
|
-
});
|
15314
|
+
.example-enter-setup {
|
15315
|
+
top:-50px;
|
14287
15316
|
}
|
14288
|
-
|
15317
|
+
.example-enter-start.example-enter-start {
|
15318
|
+
top:0;
|
15319
|
+
}
|
15320
|
+
|
15321
|
+
.example-leave-setup {
|
15322
|
+
top:0;
|
15323
|
+
}
|
15324
|
+
.example-leave-start.example-leave-start {
|
15325
|
+
top:50px;
|
15326
|
+
}
|
15327
|
+
</file>
|
15328
|
+
<file name="scenario.js">
|
15329
|
+
it('should start in settings', function() {
|
15330
|
+
expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Settings Div/);
|
15331
|
+
});
|
15332
|
+
it('should change to home', function() {
|
15333
|
+
select('selection').option('home');
|
15334
|
+
expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Home Span/);
|
15335
|
+
});
|
15336
|
+
it('should select default', function() {
|
15337
|
+
select('selection').option('other');
|
15338
|
+
expect(element('.doc-example-live [ng-switch]').text()).toMatch(/default/);
|
15339
|
+
});
|
15340
|
+
</file>
|
15341
|
+
</example>
|
15342
|
+
*/
|
15343
|
+
var ngSwitchDirective = ['$animator', function($animator) {
|
15344
|
+
return {
|
15345
|
+
restrict: 'EA',
|
15346
|
+
require: 'ngSwitch',
|
15347
|
+
|
15348
|
+
// asks for $scope to fool the BC controller module
|
15349
|
+
controller: ['$scope', function ngSwitchController() {
|
15350
|
+
this.cases = {};
|
15351
|
+
}],
|
15352
|
+
link: function(scope, element, attr, ngSwitchController) {
|
15353
|
+
var animate = $animator(scope, attr);
|
15354
|
+
var watchExpr = attr.ngSwitch || attr.on,
|
15355
|
+
selectedTranscludes,
|
15356
|
+
selectedElements,
|
15357
|
+
selectedScopes = [];
|
15358
|
+
|
15359
|
+
scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
|
15360
|
+
for (var i= 0, ii=selectedScopes.length; i<ii; i++) {
|
15361
|
+
selectedScopes[i].$destroy();
|
15362
|
+
animate.leave(selectedElements[i]);
|
15363
|
+
}
|
15364
|
+
|
15365
|
+
selectedElements = [];
|
15366
|
+
selectedScopes = [];
|
15367
|
+
|
15368
|
+
if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
|
15369
|
+
scope.$eval(attr.change);
|
15370
|
+
forEach(selectedTranscludes, function(selectedTransclude) {
|
15371
|
+
var selectedScope = scope.$new();
|
15372
|
+
selectedScopes.push(selectedScope);
|
15373
|
+
selectedTransclude.transclude(selectedScope, function(caseElement) {
|
15374
|
+
var anchor = selectedTransclude.element;
|
15375
|
+
|
15376
|
+
selectedElements.push(caseElement);
|
15377
|
+
animate.enter(caseElement, anchor.parent(), anchor);
|
15378
|
+
});
|
15379
|
+
});
|
15380
|
+
}
|
15381
|
+
});
|
15382
|
+
}
|
14289
15383
|
}
|
14290
|
-
}
|
15384
|
+
}];
|
14291
15385
|
|
14292
15386
|
var ngSwitchWhenDirective = ngDirective({
|
14293
15387
|
transclude: 'element',
|
@@ -14296,7 +15390,7 @@ var ngSwitchWhenDirective = ngDirective({
|
|
14296
15390
|
compile: function(element, attrs, transclude) {
|
14297
15391
|
return function(scope, element, attr, ctrl) {
|
14298
15392
|
ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
|
14299
|
-
ctrl.cases['!' + attrs.ngSwitchWhen].push(transclude);
|
15393
|
+
ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: transclude, element: element });
|
14300
15394
|
};
|
14301
15395
|
}
|
14302
15396
|
});
|
@@ -14308,7 +15402,7 @@ var ngSwitchDefaultDirective = ngDirective({
|
|
14308
15402
|
compile: function(element, attrs, transclude) {
|
14309
15403
|
return function(scope, element, attr, ctrl) {
|
14310
15404
|
ctrl.cases['?'] = (ctrl.cases['?'] || []);
|
14311
|
-
ctrl.cases['?'].push(transclude);
|
15405
|
+
ctrl.cases['?'].push({ transclude: transclude, element: element });
|
14312
15406
|
};
|
14313
15407
|
}
|
14314
15408
|
});
|
@@ -14382,9 +15476,16 @@ var ngTranscludeDirective = ngDirective({
|
|
14382
15476
|
* Every time the current route changes, the included view changes with it according to the
|
14383
15477
|
* configuration of the `$route` service.
|
14384
15478
|
*
|
15479
|
+
* Additionally, you can also provide animations via the ngAnimate attribute to animate the **enter**
|
15480
|
+
* and **leave** effects.
|
15481
|
+
*
|
15482
|
+
* @animations
|
15483
|
+
* enter - happens just after the ngView contents are changed (when the new view DOM element is inserted into the DOM)
|
15484
|
+
* leave - happens just after the current ngView contents change and just before the former contents are removed from the DOM
|
15485
|
+
*
|
14385
15486
|
* @scope
|
14386
15487
|
* @example
|
14387
|
-
<example module="ngView">
|
15488
|
+
<example module="ngView" animations="true">
|
14388
15489
|
<file name="index.html">
|
14389
15490
|
<div ng-controller="MainCntl">
|
14390
15491
|
Choose:
|
@@ -14394,7 +15495,10 @@ var ngTranscludeDirective = ngDirective({
|
|
14394
15495
|
<a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
|
14395
15496
|
<a href="Book/Scarlet">Scarlet Letter</a><br/>
|
14396
15497
|
|
14397
|
-
<div
|
15498
|
+
<div
|
15499
|
+
ng-view
|
15500
|
+
class="example-animate-container"
|
15501
|
+
ng-animate="{enter: 'example-enter', leave: 'example-leave'}"></div>
|
14398
15502
|
<hr />
|
14399
15503
|
|
14400
15504
|
<pre>$location.path() = {{$location.path()}}</pre>
|
@@ -14406,14 +15510,58 @@ var ngTranscludeDirective = ngDirective({
|
|
14406
15510
|
</file>
|
14407
15511
|
|
14408
15512
|
<file name="book.html">
|
14409
|
-
|
14410
|
-
|
15513
|
+
<div>
|
15514
|
+
controller: {{name}}<br />
|
15515
|
+
Book Id: {{params.bookId}}<br />
|
15516
|
+
</div>
|
14411
15517
|
</file>
|
14412
15518
|
|
14413
15519
|
<file name="chapter.html">
|
14414
|
-
|
14415
|
-
|
14416
|
-
|
15520
|
+
<div>
|
15521
|
+
controller: {{name}}<br />
|
15522
|
+
Book Id: {{params.bookId}}<br />
|
15523
|
+
Chapter Id: {{params.chapterId}}
|
15524
|
+
</div>
|
15525
|
+
</file>
|
15526
|
+
|
15527
|
+
<file name="animations.css">
|
15528
|
+
.example-leave-setup, .example-enter-setup {
|
15529
|
+
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
|
15530
|
+
-moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
|
15531
|
+
-ms-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
|
15532
|
+
-o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
|
15533
|
+
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
|
15534
|
+
}
|
15535
|
+
|
15536
|
+
.example-animate-container {
|
15537
|
+
position:relative;
|
15538
|
+
height:100px;
|
15539
|
+
}
|
15540
|
+
|
15541
|
+
.example-animate-container > * {
|
15542
|
+
display:block;
|
15543
|
+
width:100%;
|
15544
|
+
border-left:1px solid black;
|
15545
|
+
|
15546
|
+
position:absolute;
|
15547
|
+
top:0;
|
15548
|
+
left:0;
|
15549
|
+
right:0;
|
15550
|
+
bottom:0;
|
15551
|
+
padding:10px;
|
15552
|
+
}
|
15553
|
+
|
15554
|
+
.example-enter-setup {
|
15555
|
+
left:100%;
|
15556
|
+
}
|
15557
|
+
.example-enter-setup.example-enter-start {
|
15558
|
+
left:0;
|
15559
|
+
}
|
15560
|
+
|
15561
|
+
.example-leave-setup { }
|
15562
|
+
.example-leave-setup.example-leave-start {
|
15563
|
+
left:-100%;
|
15564
|
+
}
|
14417
15565
|
</file>
|
14418
15566
|
|
14419
15567
|
<file name="script.js">
|
@@ -14475,15 +15623,16 @@ var ngTranscludeDirective = ngDirective({
|
|
14475
15623
|
* Emitted every time the ngView content is reloaded.
|
14476
15624
|
*/
|
14477
15625
|
var ngViewDirective = ['$http', '$templateCache', '$route', '$anchorScroll', '$compile',
|
14478
|
-
'$controller',
|
15626
|
+
'$controller', '$animator',
|
14479
15627
|
function($http, $templateCache, $route, $anchorScroll, $compile,
|
14480
|
-
$controller) {
|
15628
|
+
$controller, $animator) {
|
14481
15629
|
return {
|
14482
15630
|
restrict: 'ECA',
|
14483
15631
|
terminal: true,
|
14484
15632
|
link: function(scope, element, attr) {
|
14485
15633
|
var lastScope,
|
14486
|
-
onloadExp = attr.onload || ''
|
15634
|
+
onloadExp = attr.onload || '',
|
15635
|
+
animate = $animator(scope, attr);
|
14487
15636
|
|
14488
15637
|
scope.$on('$routeChangeSuccess', update);
|
14489
15638
|
update();
|
@@ -14497,7 +15646,7 @@ var ngViewDirective = ['$http', '$templateCache', '$route', '$anchorScroll', '$c
|
|
14497
15646
|
}
|
14498
15647
|
|
14499
15648
|
function clearContent() {
|
14500
|
-
element.
|
15649
|
+
animate.leave(element.contents(), element);
|
14501
15650
|
destroyLastScope();
|
14502
15651
|
}
|
14503
15652
|
|
@@ -14506,8 +15655,8 @@ var ngViewDirective = ['$http', '$templateCache', '$route', '$anchorScroll', '$c
|
|
14506
15655
|
template = locals && locals.$template;
|
14507
15656
|
|
14508
15657
|
if (template) {
|
14509
|
-
|
14510
|
-
|
15658
|
+
clearContent();
|
15659
|
+
animate.enter(jqLite('<div></div>').html(template).contents(), element);
|
14511
15660
|
|
14512
15661
|
var link = $compile(element.contents()),
|
14513
15662
|
current = $route.current,
|
@@ -14701,7 +15850,7 @@ var scriptDirective = ['$templateCache', function($templateCache) {
|
|
14701
15850
|
|
14702
15851
|
var ngOptionsDirective = valueFn({ terminal: true });
|
14703
15852
|
var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
14704
|
-
//
|
15853
|
+
//0000111110000000000022220000000000000000000000333300000000000000444444444444444440000000005555555555555555500000006666666666666666600000000000000077770
|
14705
15854
|
var NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*)$/,
|
14706
15855
|
nullModelCtrl = {$setViewValue: noop};
|
14707
15856
|
|
@@ -15150,6 +16299,7 @@ var styleDirective = valueFn({
|
|
15150
16299
|
restrict: 'E',
|
15151
16300
|
terminal: true
|
15152
16301
|
});
|
16302
|
+
|
15153
16303
|
//try to bind to jquery now so that one can write angular.element().read()
|
15154
16304
|
//but we will rebind on bootstrap again.
|
15155
16305
|
bindJQuery();
|