angular-gem 1.1.3 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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();
|