angular-rails-engine 1.1.5.0 → 1.2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/README.md +2 -2
- data/app/assets/javascripts/angular/angular-animate.js +677 -0
- data/app/assets/javascripts/angular/angular-animate.min.js +14 -0
- data/app/assets/javascripts/angular/angular-cookies.js +2 -3
- data/app/assets/javascripts/angular/angular-cookies.min.js +6 -3
- data/app/assets/javascripts/angular/angular-loader.js +311 -0
- data/app/assets/javascripts/angular/angular-loader.min.js +10 -0
- data/app/assets/javascripts/angular/angular-mocks.js +1952 -0
- data/app/assets/javascripts/angular/angular-resource.js +81 -70
- data/app/assets/javascripts/angular/angular-resource.min.js +10 -7
- data/app/assets/javascripts/angular/angular-route.js +860 -0
- data/app/assets/javascripts/angular/angular-route.min.js +15 -0
- data/app/assets/javascripts/angular/angular-sanitize.js +62 -62
- data/app/assets/javascripts/angular/angular-sanitize.min.js +11 -9
- data/app/assets/javascripts/angular/angular-scenario.js +29531 -0
- data/app/assets/javascripts/angular/angular-touch.js +536 -0
- data/app/assets/javascripts/angular/angular-touch.min.js +14 -0
- data/app/assets/javascripts/angular/angular.js +7383 -6357
- data/app/assets/javascripts/angular/angular.min.js +181 -174
- data/lib/angular-rails-engine.rb +1 -1
- data/lib/angular-rails-engine/version.rb +1 -1
- metadata +11 -1
- metadata.gz.sig +0 -0
@@ -1,10 +1,11 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.
|
2
|
+
* @license AngularJS v1.2.0rc1
|
3
3
|
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
6
|
-
(function(window, angular, undefined) {
|
7
|
-
|
6
|
+
(function(window, angular, undefined) {'use strict';
|
7
|
+
|
8
|
+
var $resourceMinErr = angular.$$minErr('$resource');
|
8
9
|
|
9
10
|
/**
|
10
11
|
* @ngdoc overview
|
@@ -37,12 +38,11 @@
|
|
37
38
|
*
|
38
39
|
* @param {string} url A parametrized URL template with parameters prefixed by `:` as in
|
39
40
|
* `/user/:username`. If you are using a URL with a port number (e.g.
|
40
|
-
* `http://example.com:8080/api`),
|
41
|
-
* number, like this: `$resource('http://example.com\\:8080/api')`.
|
41
|
+
* `http://example.com:8080/api`), it will be respected.
|
42
42
|
*
|
43
|
-
* If you are using a url with a suffix, just add the suffix, like this:
|
43
|
+
* If you are using a url with a suffix, just add the suffix, like this:
|
44
44
|
* `$resource('http://example.com/resource.json')` or `$resource('http://example.com/:id.json')
|
45
|
-
* or even `$resource('http://example.com/resource/:resource_id.:format')`
|
45
|
+
* or even `$resource('http://example.com/resource/:resource_id.:format')`
|
46
46
|
* If the parameter before the suffix is empty, :resource_id in this case, then the `/.` will be
|
47
47
|
* collapsed down to a single `.`. If you need this sequence to appear and not collapse then you
|
48
48
|
* can escape it with `/\.`.
|
@@ -98,6 +98,9 @@
|
|
98
98
|
* requests with credentials} for more information.
|
99
99
|
* - **`responseType`** - `{string}` - see {@link
|
100
100
|
* https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}.
|
101
|
+
* - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods -
|
102
|
+
* `response` and `responseError`. Both `response` and `responseError` interceptors get called
|
103
|
+
* with `http response` object. See {@link ng.$http $http interceptors}.
|
101
104
|
*
|
102
105
|
* @returns {Object} A resource "class" object with methods for the default set of resource actions
|
103
106
|
* optionally extended with custom `actions`. The default set contains these actions:
|
@@ -136,24 +139,27 @@
|
|
136
139
|
* - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
|
137
140
|
* - non-GET instance actions: `instance.$action([parameters], [success], [error])`
|
138
141
|
*
|
142
|
+
* Success callback is called with (value, responseHeaders) arguments. Error callback is called
|
143
|
+
* with (httpResponse) argument.
|
139
144
|
*
|
140
|
-
*
|
145
|
+
* Class actions return empty instance (with additional properties below).
|
146
|
+
* Instance actions return promise of the action.
|
141
147
|
*
|
142
|
-
*
|
143
|
-
* {@link ng.$http $http} call.
|
148
|
+
* The Resource instances and collection have these additional properties:
|
144
149
|
*
|
145
|
-
*
|
146
|
-
*
|
150
|
+
* - `$promise`: the {@link ng.$q promise} of the original server interaction that created this
|
151
|
+
* instance or collection.
|
147
152
|
*
|
148
|
-
*
|
149
|
-
*
|
150
|
-
*
|
153
|
+
* On success, the promise is resolved with the same resource instance or collection object,
|
154
|
+
* updated with data from server. This makes it easy to use in
|
155
|
+
* {@link ngRoute.$routeProvider resolve section of $routeProvider.when()} to defer view rendering
|
156
|
+
* until the resource(s) are loaded.
|
151
157
|
*
|
152
|
-
*
|
153
|
-
*
|
158
|
+
* On failure, the promise is resolved with the {@link ng.$http http response} object,
|
159
|
+
* without the `resource` property.
|
154
160
|
*
|
155
|
-
* - `$resolved`: true
|
156
|
-
* Knowing if the Resource has been resolved is useful in data-binding.
|
161
|
+
* - `$resolved`: `true` after first server interaction is completed (either with success or rejection),
|
162
|
+
* `false` before that. Knowing if the Resource has been resolved is useful in data-binding.
|
157
163
|
*
|
158
164
|
* @example
|
159
165
|
*
|
@@ -274,7 +280,7 @@
|
|
274
280
|
</doc:example>
|
275
281
|
*/
|
276
282
|
angular.module('ngResource', ['ng']).
|
277
|
-
factory('$resource', ['$http', '$parse', function($http, $parse) {
|
283
|
+
factory('$resource', ['$http', '$parse', '$q', function($http, $parse, $q) {
|
278
284
|
var DEFAULT_ACTIONS = {
|
279
285
|
'get': {method:'GET'},
|
280
286
|
'save': {method:'POST'},
|
@@ -345,7 +351,7 @@ angular.module('ngResource', ['ng']).
|
|
345
351
|
|
346
352
|
var urlParams = self.urlParams = {};
|
347
353
|
forEach(url.split(/\W/), function(param){
|
348
|
-
if (param && (new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
|
354
|
+
if (!(new RegExp("^\\d+$").test(param)) && param && (new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
|
349
355
|
urlParams[param] = true;
|
350
356
|
}
|
351
357
|
});
|
@@ -376,7 +382,7 @@ angular.module('ngResource', ['ng']).
|
|
376
382
|
url = url.replace(/\/\.(?=\w+($|\?))/, '.');
|
377
383
|
// replace escaped `/\.` with `/.`
|
378
384
|
config.url = url.replace(/\/\\\./, '/.');
|
379
|
-
|
385
|
+
|
380
386
|
|
381
387
|
// set params - delegate param encoding to $http
|
382
388
|
forEach(params, function(value, key){
|
@@ -404,19 +410,19 @@ angular.module('ngResource', ['ng']).
|
|
404
410
|
return ids;
|
405
411
|
}
|
406
412
|
|
413
|
+
function defaultResponseInterceptor(response) {
|
414
|
+
return response.resource;
|
415
|
+
}
|
416
|
+
|
407
417
|
function Resource(value){
|
408
418
|
copy(value || {}, this);
|
409
419
|
}
|
410
420
|
|
411
421
|
forEach(actions, function(action, name) {
|
412
|
-
|
413
|
-
|
422
|
+
var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);
|
423
|
+
|
414
424
|
Resource[name] = function(a1, a2, a3, a4) {
|
415
|
-
var params = {};
|
416
|
-
var data;
|
417
|
-
var success = noop;
|
418
|
-
var error = null;
|
419
|
-
var promise;
|
425
|
+
var params = {}, data, success, error;
|
420
426
|
|
421
427
|
switch(arguments.length) {
|
422
428
|
case 4:
|
@@ -448,33 +454,35 @@ angular.module('ngResource', ['ng']).
|
|
448
454
|
break;
|
449
455
|
case 0: break;
|
450
456
|
default:
|
451
|
-
throw
|
452
|
-
arguments
|
457
|
+
throw $resourceMinErr('badargs',
|
458
|
+
"Expected up to 4 arguments [params, data, success, error], got {0} arguments", arguments.length);
|
453
459
|
}
|
454
460
|
|
455
|
-
var
|
456
|
-
var
|
457
|
-
|
461
|
+
var isInstanceCall = data instanceof Resource;
|
462
|
+
var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data));
|
463
|
+
var httpConfig = {};
|
464
|
+
var responseInterceptor = action.interceptor && action.interceptor.response || defaultResponseInterceptor;
|
465
|
+
var responseErrorInterceptor = action.interceptor && action.interceptor.responseError || undefined;
|
458
466
|
|
459
467
|
forEach(action, function(value, key) {
|
460
|
-
if (key != 'params' && key != 'isArray' ) {
|
468
|
+
if (key != 'params' && key != 'isArray' && key != 'interceptor') {
|
461
469
|
httpConfig[key] = copy(value);
|
462
470
|
}
|
463
471
|
});
|
472
|
+
|
464
473
|
httpConfig.data = data;
|
465
474
|
route.setUrlParams(httpConfig, extend({}, extractParams(data, action.params || {}), params), action.url);
|
466
475
|
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
value.$resolved = false;
|
471
|
-
|
472
|
-
promise.then(markResolved, markResolved);
|
473
|
-
value.$then = promise.then(function(response) {
|
474
|
-
var data = response.data;
|
475
|
-
var then = value.$then, resolved = value.$resolved;
|
476
|
+
var promise = $http(httpConfig).then(function(response) {
|
477
|
+
var data = response.data,
|
478
|
+
promise = value.$promise;
|
476
479
|
|
477
480
|
if (data) {
|
481
|
+
if ( angular.isArray(data) != !!action.isArray ) {
|
482
|
+
throw $resourceMinErr('badcfg', 'Error in resource configuration. Expected response' +
|
483
|
+
' to contain an {0} but got an {1}',
|
484
|
+
action.isArray?'array':'object', angular.isArray(data)?'array':'object');
|
485
|
+
}
|
478
486
|
if (action.isArray) {
|
479
487
|
value.length = 0;
|
480
488
|
forEach(data, function(item) {
|
@@ -482,44 +490,47 @@ angular.module('ngResource', ['ng']).
|
|
482
490
|
});
|
483
491
|
} else {
|
484
492
|
copy(data, value);
|
485
|
-
value.$
|
486
|
-
value.$resolved = resolved;
|
493
|
+
value.$promise = promise;
|
487
494
|
}
|
488
495
|
}
|
489
496
|
|
497
|
+
value.$resolved = true;
|
498
|
+
|
490
499
|
(success||noop)(value, response.headers);
|
491
500
|
|
492
501
|
response.resource = value;
|
502
|
+
|
493
503
|
return response;
|
494
|
-
},
|
504
|
+
}, function(response) {
|
505
|
+
value.$resolved = true;
|
495
506
|
|
496
|
-
|
497
|
-
};
|
507
|
+
(error||noop)(response);
|
498
508
|
|
509
|
+
return $q.reject(response);
|
510
|
+
}).then(responseInterceptor, responseErrorInterceptor);
|
499
511
|
|
500
|
-
Resource.prototype['$' + name] = function(a1, a2, a3) {
|
501
|
-
var params = extractParams(this),
|
502
|
-
success = noop,
|
503
|
-
error;
|
504
512
|
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
513
|
+
if (!isInstanceCall) {
|
514
|
+
// we are creating instance / collection
|
515
|
+
// - set the initial promise
|
516
|
+
// - return the instance / collection
|
517
|
+
value.$promise = promise;
|
518
|
+
value.$resolved = false;
|
519
|
+
|
520
|
+
return value;
|
521
|
+
}
|
522
|
+
|
523
|
+
// instance call
|
524
|
+
return promise;
|
525
|
+
};
|
526
|
+
|
527
|
+
|
528
|
+
Resource.prototype['$' + name] = function(params, success, error) {
|
529
|
+
if (isFunction(params)) {
|
530
|
+
error = success; success = params; params = {};
|
520
531
|
}
|
521
|
-
var
|
522
|
-
|
532
|
+
var result = Resource[name](params, this, success, error);
|
533
|
+
return result.$promise || result;
|
523
534
|
};
|
524
535
|
});
|
525
536
|
|
@@ -1,11 +1,14 @@
|
|
1
1
|
/*
|
2
|
-
AngularJS v1.
|
2
|
+
AngularJS v1.2.0rc1
|
3
3
|
(c) 2010-2012 Google, Inc. http://angularjs.org
|
4
4
|
License: MIT
|
5
5
|
*/
|
6
|
-
(function(
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
":");
|
11
|
-
|
6
|
+
(function(H,g,C){'use strict';var A=g.$$minErr("$resource");g.module("ngResource",["ng"]).factory("$resource",["$http","$parse","$q",function(D,y,E){function n(g,h){this.template=g;this.defaults=h||{};this.urlParams={}}function u(l,h,d){function p(c,b){var e={};b=v({},h,b);q(b,function(a,b){t(a)&&(a=a());var m;a&&a.charAt&&"@"==a.charAt(0)?(m=a.substr(1),m=y(m)(c)):m=a;e[b]=m});return e}function b(c){return c.resource}function e(c){z(c||{},this)}var F=new n(l);d=v({},G,d);q(d,function(c,f){var h=
|
7
|
+
/^(POST|PUT|PATCH)$/i.test(c.method);e[f]=function(a,f,m,l){var d={},r,s,w;switch(arguments.length){case 4:w=l,s=m;case 3:case 2:if(t(f)){if(t(a)){s=a;w=f;break}s=f;w=m}else{d=a;r=f;s=m;break}case 1:t(a)?s=a:h?r=a:d=a;break;case 0:break;default:throw A("badargs",arguments.length);}var n=r instanceof e,k=n?r:c.isArray?[]:new e(r),x={},u=c.interceptor&&c.interceptor.response||b,y=c.interceptor&&c.interceptor.responseError||C;q(c,function(a,c){"params"!=c&&("isArray"!=c&&"interceptor"!=c)&&(x[c]=z(a))});
|
8
|
+
x.data=r;F.setUrlParams(x,v({},p(r,c.params||{}),d),c.url);d=D(x).then(function(a){var b=a.data,f=k.$promise;if(b){if(g.isArray(b)!=!!c.isArray)throw A("badcfg",c.isArray?"array":"object",g.isArray(b)?"array":"object");c.isArray?(k.length=0,q(b,function(a){k.push(new e(a))})):(z(b,k),k.$promise=f)}k.$resolved=!0;(s||B)(k,a.headers);a.resource=k;return a},function(a){k.$resolved=!0;(w||B)(a);return E.reject(a)}).then(u,y);return n?d:(k.$promise=d,k.$resolved=!1,k)};e.prototype["$"+f]=function(a,c,
|
9
|
+
b){t(a)&&(b=c,c=a,a={});a=e[f](a,this,c,b);return a.$promise||a}});e.bind=function(c){return u(l,v({},h,c),d)};return e}var G={get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}},B=g.noop,q=g.forEach,v=g.extend,z=g.copy,t=g.isFunction;n.prototype={setUrlParams:function(l,h,d){var p=this,b=d||p.template,e,n,c=p.urlParams={};q(b.split(/\W/),function(f){!/^\d+$/.test(f)&&(f&&RegExp("(^|[^\\\\]):"+f+"(\\W|$)").test(b))&&(c[f]=!0)});
|
10
|
+
b=b.replace(/\\:/g,":");h=h||{};q(p.urlParams,function(c,d){e=h.hasOwnProperty(d)?h[d]:p.defaults[d];g.isDefined(e)&&null!==e?(n=encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"%20").replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+"),b=b.replace(RegExp(":"+d+"(\\W|$)","g"),n+"$1")):b=b.replace(RegExp("(/?):"+d+"(\\W|$)","g"),function(a,c,b){return"/"==b.charAt(0)?b:c+b})});b=b.replace(/\/+$/,"");b=b.replace(/\/\.(?=\w+($|\?))/,
|
11
|
+
".");l.url=b.replace(/\/\\\./,"/.");q(h,function(c,b){p.urlParams[b]||(l.params=l.params||{},l.params[b]=c)})}};return u}])})(window,window.angular);
|
12
|
+
/*
|
13
|
+
//@ sourceMappingURL=angular-resource.min.js.map
|
14
|
+
*/
|
@@ -0,0 +1,860 @@
|
|
1
|
+
/**
|
2
|
+
* @license AngularJS v1.2.0rc1
|
3
|
+
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
4
|
+
* License: MIT
|
5
|
+
*/
|
6
|
+
(function(window, angular, undefined) {'use strict';
|
7
|
+
|
8
|
+
var copy = angular.copy,
|
9
|
+
equals = angular.equals,
|
10
|
+
extend = angular.extend,
|
11
|
+
forEach = angular.forEach,
|
12
|
+
isDefined = angular.isDefined,
|
13
|
+
isFunction = angular.isFunction,
|
14
|
+
isString = angular.isString,
|
15
|
+
jqLite = angular.element,
|
16
|
+
noop = angular.noop,
|
17
|
+
toJson = angular.toJson;
|
18
|
+
|
19
|
+
|
20
|
+
function inherit(parent, extra) {
|
21
|
+
return extend(new (extend(function() {}, {prototype:parent}))(), extra);
|
22
|
+
}
|
23
|
+
|
24
|
+
/**
|
25
|
+
* @ngdoc overview
|
26
|
+
* @name ngRoute
|
27
|
+
* @description
|
28
|
+
*
|
29
|
+
* Module that provides routing and deeplinking services and directives for angular apps.
|
30
|
+
*/
|
31
|
+
|
32
|
+
var ngRouteModule = angular.module('ngRoute', ['ng']).
|
33
|
+
provider('$route', $RouteProvider);
|
34
|
+
|
35
|
+
/**
|
36
|
+
* @ngdoc object
|
37
|
+
* @name ngRoute.$routeProvider
|
38
|
+
* @function
|
39
|
+
*
|
40
|
+
* @description
|
41
|
+
*
|
42
|
+
* Used for configuring routes. See {@link ngRoute.$route $route} for an example.
|
43
|
+
*/
|
44
|
+
function $RouteProvider(){
|
45
|
+
var routes = {};
|
46
|
+
|
47
|
+
/**
|
48
|
+
* @ngdoc method
|
49
|
+
* @name ngRoute.$routeProvider#when
|
50
|
+
* @methodOf ngRoute.$routeProvider
|
51
|
+
*
|
52
|
+
* @param {string} path Route path (matched against `$location.path`). If `$location.path`
|
53
|
+
* contains redundant trailing slash or is missing one, the route will still match and the
|
54
|
+
* `$location.path` will be updated to add or drop the trailing slash to exactly match the
|
55
|
+
* route definition.
|
56
|
+
*
|
57
|
+
* * `path` can contain named groups starting with a colon (`:name`). All characters up
|
58
|
+
* to the next slash are matched and stored in `$routeParams` under the given `name`
|
59
|
+
* when the route matches.
|
60
|
+
* * `path` can contain named groups starting with a colon and ending with a star (`:name*`).
|
61
|
+
* All characters are eagerly stored in `$routeParams` under the given `name`
|
62
|
+
* when the route matches.
|
63
|
+
* * `path` can contain optional named groups with a question mark (`:name?`).
|
64
|
+
*
|
65
|
+
* For example, routes like `/color/:color/largecode/:largecode*\/edit` will match
|
66
|
+
* `/color/brown/largecode/code/with/slashs/edit` and extract:
|
67
|
+
*
|
68
|
+
* * `color: brown`
|
69
|
+
* * `largecode: code/with/slashs`.
|
70
|
+
*
|
71
|
+
*
|
72
|
+
* @param {Object} route Mapping information to be assigned to `$route.current` on route
|
73
|
+
* match.
|
74
|
+
*
|
75
|
+
* Object properties:
|
76
|
+
*
|
77
|
+
* - `controller` – `{(string|function()=}` – Controller fn that should be associated with newly
|
78
|
+
* created scope or the name of a {@link angular.Module#controller registered controller}
|
79
|
+
* if passed as a string.
|
80
|
+
* - `controllerAs` – `{string=}` – A controller alias name. If present the controller will be
|
81
|
+
* published to scope under the `controllerAs` name.
|
82
|
+
* - `template` – `{string=|function()=}` – html template as a string or a function that
|
83
|
+
* returns an html template as a string which should be used by {@link
|
84
|
+
* ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives.
|
85
|
+
* This property takes precedence over `templateUrl`.
|
86
|
+
*
|
87
|
+
* If `template` is a function, it will be called with the following parameters:
|
88
|
+
*
|
89
|
+
* - `{Array.<Object>}` - route parameters extracted from the current
|
90
|
+
* `$location.path()` by applying the current route
|
91
|
+
*
|
92
|
+
* - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
|
93
|
+
* template that should be used by {@link ngRoute.directive:ngView ngView}.
|
94
|
+
*
|
95
|
+
* If `templateUrl` is a function, it will be called with the following parameters:
|
96
|
+
*
|
97
|
+
* - `{Array.<Object>}` - route parameters extracted from the current
|
98
|
+
* `$location.path()` by applying the current route
|
99
|
+
*
|
100
|
+
* - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
|
101
|
+
* be injected into the controller. If any of these dependencies are promises, they will be
|
102
|
+
* resolved and converted to a value before the controller is instantiated and the
|
103
|
+
* `$routeChangeSuccess` event is fired. The map object is:
|
104
|
+
*
|
105
|
+
* - `key` – `{string}`: a name of a dependency to be injected into the controller.
|
106
|
+
* - `factory` - `{string|function}`: If `string` then it is an alias for a service.
|
107
|
+
* Otherwise if function, then it is {@link api/AUTO.$injector#invoke injected}
|
108
|
+
* and the return value is treated as the dependency. If the result is a promise, it is resolved
|
109
|
+
* before its value is injected into the controller. Be aware that `ngRoute.$routeParams` will
|
110
|
+
* still refer to the previous route within these resolve functions. Use `$route.current.params`
|
111
|
+
* to access the new route parameters, instead.
|
112
|
+
*
|
113
|
+
* - `redirectTo` – {(string|function())=} – value to update
|
114
|
+
* {@link ng.$location $location} path with and trigger route redirection.
|
115
|
+
*
|
116
|
+
* If `redirectTo` is a function, it will be called with the following parameters:
|
117
|
+
*
|
118
|
+
* - `{Object.<string>}` - route parameters extracted from the current
|
119
|
+
* `$location.path()` by applying the current route templateUrl.
|
120
|
+
* - `{string}` - current `$location.path()`
|
121
|
+
* - `{Object}` - current `$location.search()`
|
122
|
+
*
|
123
|
+
* The custom `redirectTo` function is expected to return a string which will be used
|
124
|
+
* to update `$location.path()` and `$location.search()`.
|
125
|
+
*
|
126
|
+
* - `[reloadOnSearch=true]` - {boolean=} - reload route when only $location.search()
|
127
|
+
* changes.
|
128
|
+
*
|
129
|
+
* If the option is set to `false` and url in the browser changes, then
|
130
|
+
* `$routeUpdate` event is broadcasted on the root scope.
|
131
|
+
*
|
132
|
+
* - `[caseInsensitiveMatch=false]` - {boolean=} - match routes without being case sensitive
|
133
|
+
*
|
134
|
+
* If the option is set to `true`, then the particular route can be matched without being
|
135
|
+
* case sensitive
|
136
|
+
*
|
137
|
+
* @returns {Object} self
|
138
|
+
*
|
139
|
+
* @description
|
140
|
+
* Adds a new route definition to the `$route` service.
|
141
|
+
*/
|
142
|
+
this.when = function(path, route) {
|
143
|
+
routes[path] = extend(
|
144
|
+
{reloadOnSearch: true},
|
145
|
+
route,
|
146
|
+
path && pathRegExp(path, route)
|
147
|
+
);
|
148
|
+
|
149
|
+
// create redirection for trailing slashes
|
150
|
+
if (path) {
|
151
|
+
var redirectPath = (path[path.length-1] == '/')
|
152
|
+
? path.substr(0, path.length-1)
|
153
|
+
: path +'/';
|
154
|
+
|
155
|
+
routes[redirectPath] = extend(
|
156
|
+
{redirectTo: path},
|
157
|
+
pathRegExp(redirectPath, route)
|
158
|
+
);
|
159
|
+
}
|
160
|
+
|
161
|
+
return this;
|
162
|
+
};
|
163
|
+
|
164
|
+
/**
|
165
|
+
* @param path {string} path
|
166
|
+
* @param opts {Object} options
|
167
|
+
* @return {?Object}
|
168
|
+
*
|
169
|
+
* @description
|
170
|
+
* Normalizes the given path, returning a regular expression
|
171
|
+
* and the original path.
|
172
|
+
*
|
173
|
+
* Inspired by pathRexp in visionmedia/express/lib/utils.js.
|
174
|
+
*/
|
175
|
+
function pathRegExp(path, opts) {
|
176
|
+
var insensitive = opts.caseInsensitiveMatch,
|
177
|
+
ret = {
|
178
|
+
originalPath: path,
|
179
|
+
regexp: path
|
180
|
+
},
|
181
|
+
keys = ret.keys = [];
|
182
|
+
|
183
|
+
path = path
|
184
|
+
.replace(/([().])/g, '\\$1')
|
185
|
+
.replace(/(\/)?:(\w+)([\?|\*])?/g, function(_, slash, key, option){
|
186
|
+
var optional = option === '?' ? option : null;
|
187
|
+
var star = option === '*' ? option : null;
|
188
|
+
keys.push({ name: key, optional: !!optional });
|
189
|
+
slash = slash || '';
|
190
|
+
return ''
|
191
|
+
+ (optional ? '' : slash)
|
192
|
+
+ '(?:'
|
193
|
+
+ (optional ? slash : '')
|
194
|
+
+ (star && '(.+)?' || '([^/]+)?') + ')'
|
195
|
+
+ (optional || '');
|
196
|
+
})
|
197
|
+
.replace(/([\/$\*])/g, '\\$1');
|
198
|
+
|
199
|
+
ret.regexp = new RegExp('^' + path + '$', insensitive ? 'i' : '');
|
200
|
+
return ret;
|
201
|
+
}
|
202
|
+
|
203
|
+
/**
|
204
|
+
* @ngdoc method
|
205
|
+
* @name ngRoute.$routeProvider#otherwise
|
206
|
+
* @methodOf ngRoute.$routeProvider
|
207
|
+
*
|
208
|
+
* @description
|
209
|
+
* Sets route definition that will be used on route change when no other route definition
|
210
|
+
* is matched.
|
211
|
+
*
|
212
|
+
* @param {Object} params Mapping information to be assigned to `$route.current`.
|
213
|
+
* @returns {Object} self
|
214
|
+
*/
|
215
|
+
this.otherwise = function(params) {
|
216
|
+
this.when(null, params);
|
217
|
+
return this;
|
218
|
+
};
|
219
|
+
|
220
|
+
|
221
|
+
this.$get = ['$rootScope', '$location', '$routeParams', '$q', '$injector', '$http', '$templateCache', '$sce',
|
222
|
+
function( $rootScope, $location, $routeParams, $q, $injector, $http, $templateCache, $sce) {
|
223
|
+
|
224
|
+
/**
|
225
|
+
* @ngdoc object
|
226
|
+
* @name ngRoute.$route
|
227
|
+
* @requires $location
|
228
|
+
* @requires $routeParams
|
229
|
+
*
|
230
|
+
* @property {Object} current Reference to the current route definition.
|
231
|
+
* The route definition contains:
|
232
|
+
*
|
233
|
+
* - `controller`: The controller constructor as define in route definition.
|
234
|
+
* - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for
|
235
|
+
* controller instantiation. The `locals` contain
|
236
|
+
* the resolved values of the `resolve` map. Additionally the `locals` also contain:
|
237
|
+
*
|
238
|
+
* - `$scope` - The current route scope.
|
239
|
+
* - `$template` - The current route template HTML.
|
240
|
+
*
|
241
|
+
* @property {Array.<Object>} routes Array of all configured routes.
|
242
|
+
*
|
243
|
+
* @description
|
244
|
+
* Is used for deep-linking URLs to controllers and views (HTML partials).
|
245
|
+
* It watches `$location.url()` and tries to map the path to an existing route definition.
|
246
|
+
*
|
247
|
+
* You can define routes through {@link ngRoute.$routeProvider $routeProvider}'s API.
|
248
|
+
*
|
249
|
+
* The `$route` service is typically used in conjunction with {@link ngRoute.directive:ngView ngView}
|
250
|
+
* directive and the {@link ngRoute.$routeParams $routeParams} service.
|
251
|
+
*
|
252
|
+
* @example
|
253
|
+
This example shows how changing the URL hash causes the `$route` to match a route against the
|
254
|
+
URL, and the `ngView` pulls in the partial.
|
255
|
+
|
256
|
+
Note that this example is using {@link ng.directive:script inlined templates}
|
257
|
+
to get it working on jsfiddle as well.
|
258
|
+
|
259
|
+
<example module="ngView" deps="angular-route.js">
|
260
|
+
<file name="index.html">
|
261
|
+
<div ng-controller="MainCntl">
|
262
|
+
Choose:
|
263
|
+
<a href="Book/Moby">Moby</a> |
|
264
|
+
<a href="Book/Moby/ch/1">Moby: Ch1</a> |
|
265
|
+
<a href="Book/Gatsby">Gatsby</a> |
|
266
|
+
<a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
|
267
|
+
<a href="Book/Scarlet">Scarlet Letter</a><br/>
|
268
|
+
|
269
|
+
<div ng-view></div>
|
270
|
+
<hr />
|
271
|
+
|
272
|
+
<pre>$location.path() = {{$location.path()}}</pre>
|
273
|
+
<pre>$route.current.templateUrl = {{$route.current.templateUrl}}</pre>
|
274
|
+
<pre>$route.current.params = {{$route.current.params}}</pre>
|
275
|
+
<pre>$route.current.scope.name = {{$route.current.scope.name}}</pre>
|
276
|
+
<pre>$routeParams = {{$routeParams}}</pre>
|
277
|
+
</div>
|
278
|
+
</file>
|
279
|
+
|
280
|
+
<file name="book.html">
|
281
|
+
controller: {{name}}<br />
|
282
|
+
Book Id: {{params.bookId}}<br />
|
283
|
+
</file>
|
284
|
+
|
285
|
+
<file name="chapter.html">
|
286
|
+
controller: {{name}}<br />
|
287
|
+
Book Id: {{params.bookId}}<br />
|
288
|
+
Chapter Id: {{params.chapterId}}
|
289
|
+
</file>
|
290
|
+
|
291
|
+
<file name="script.js">
|
292
|
+
angular.module('ngView', ['ngRoute']).config(function($routeProvider, $locationProvider) {
|
293
|
+
$routeProvider.when('/Book/:bookId', {
|
294
|
+
templateUrl: 'book.html',
|
295
|
+
controller: BookCntl,
|
296
|
+
resolve: {
|
297
|
+
// I will cause a 1 second delay
|
298
|
+
delay: function($q, $timeout) {
|
299
|
+
var delay = $q.defer();
|
300
|
+
$timeout(delay.resolve, 1000);
|
301
|
+
return delay.promise;
|
302
|
+
}
|
303
|
+
}
|
304
|
+
});
|
305
|
+
$routeProvider.when('/Book/:bookId/ch/:chapterId', {
|
306
|
+
templateUrl: 'chapter.html',
|
307
|
+
controller: ChapterCntl
|
308
|
+
});
|
309
|
+
|
310
|
+
// configure html5 to get links working on jsfiddle
|
311
|
+
$locationProvider.html5Mode(true);
|
312
|
+
});
|
313
|
+
|
314
|
+
function MainCntl($scope, $route, $routeParams, $location) {
|
315
|
+
$scope.$route = $route;
|
316
|
+
$scope.$location = $location;
|
317
|
+
$scope.$routeParams = $routeParams;
|
318
|
+
}
|
319
|
+
|
320
|
+
function BookCntl($scope, $routeParams) {
|
321
|
+
$scope.name = "BookCntl";
|
322
|
+
$scope.params = $routeParams;
|
323
|
+
}
|
324
|
+
|
325
|
+
function ChapterCntl($scope, $routeParams) {
|
326
|
+
$scope.name = "ChapterCntl";
|
327
|
+
$scope.params = $routeParams;
|
328
|
+
}
|
329
|
+
</file>
|
330
|
+
|
331
|
+
<file name="scenario.js">
|
332
|
+
it('should load and compile correct template', function() {
|
333
|
+
element('a:contains("Moby: Ch1")').click();
|
334
|
+
var content = element('.doc-example-live [ng-view]').text();
|
335
|
+
expect(content).toMatch(/controller\: ChapterCntl/);
|
336
|
+
expect(content).toMatch(/Book Id\: Moby/);
|
337
|
+
expect(content).toMatch(/Chapter Id\: 1/);
|
338
|
+
|
339
|
+
element('a:contains("Scarlet")').click();
|
340
|
+
sleep(2); // promises are not part of scenario waiting
|
341
|
+
content = element('.doc-example-live [ng-view]').text();
|
342
|
+
expect(content).toMatch(/controller\: BookCntl/);
|
343
|
+
expect(content).toMatch(/Book Id\: Scarlet/);
|
344
|
+
});
|
345
|
+
</file>
|
346
|
+
</example>
|
347
|
+
*/
|
348
|
+
|
349
|
+
/**
|
350
|
+
* @ngdoc event
|
351
|
+
* @name ngRoute.$route#$routeChangeStart
|
352
|
+
* @eventOf ngRoute.$route
|
353
|
+
* @eventType broadcast on root scope
|
354
|
+
* @description
|
355
|
+
* Broadcasted before a route change. At this point the route services starts
|
356
|
+
* resolving all of the dependencies needed for the route change to occurs.
|
357
|
+
* Typically this involves fetching the view template as well as any dependencies
|
358
|
+
* defined in `resolve` route property. Once all of the dependencies are resolved
|
359
|
+
* `$routeChangeSuccess` is fired.
|
360
|
+
*
|
361
|
+
* @param {Route} next Future route information.
|
362
|
+
* @param {Route} current Current route information.
|
363
|
+
*/
|
364
|
+
|
365
|
+
/**
|
366
|
+
* @ngdoc event
|
367
|
+
* @name ngRoute.$route#$routeChangeSuccess
|
368
|
+
* @eventOf ngRoute.$route
|
369
|
+
* @eventType broadcast on root scope
|
370
|
+
* @description
|
371
|
+
* Broadcasted after a route dependencies are resolved.
|
372
|
+
* {@link ngRoute.directive:ngView ngView} listens for the directive
|
373
|
+
* to instantiate the controller and render the view.
|
374
|
+
*
|
375
|
+
* @param {Object} angularEvent Synthetic event object.
|
376
|
+
* @param {Route} current Current route information.
|
377
|
+
* @param {Route|Undefined} previous Previous route information, or undefined if current is first route entered.
|
378
|
+
*/
|
379
|
+
|
380
|
+
/**
|
381
|
+
* @ngdoc event
|
382
|
+
* @name ngRoute.$route#$routeChangeError
|
383
|
+
* @eventOf ngRoute.$route
|
384
|
+
* @eventType broadcast on root scope
|
385
|
+
* @description
|
386
|
+
* Broadcasted if any of the resolve promises are rejected.
|
387
|
+
*
|
388
|
+
* @param {Route} current Current route information.
|
389
|
+
* @param {Route} previous Previous route information.
|
390
|
+
* @param {Route} rejection Rejection of the promise. Usually the error of the failed promise.
|
391
|
+
*/
|
392
|
+
|
393
|
+
/**
|
394
|
+
* @ngdoc event
|
395
|
+
* @name ngRoute.$route#$routeUpdate
|
396
|
+
* @eventOf ngRoute.$route
|
397
|
+
* @eventType broadcast on root scope
|
398
|
+
* @description
|
399
|
+
*
|
400
|
+
* The `reloadOnSearch` property has been set to false, and we are reusing the same
|
401
|
+
* instance of the Controller.
|
402
|
+
*/
|
403
|
+
|
404
|
+
var forceReload = false,
|
405
|
+
$route = {
|
406
|
+
routes: routes,
|
407
|
+
|
408
|
+
/**
|
409
|
+
* @ngdoc method
|
410
|
+
* @name ngRoute.$route#reload
|
411
|
+
* @methodOf ngRoute.$route
|
412
|
+
*
|
413
|
+
* @description
|
414
|
+
* Causes `$route` service to reload the current route even if
|
415
|
+
* {@link ng.$location $location} hasn't changed.
|
416
|
+
*
|
417
|
+
* As a result of that, {@link ngRoute.directive:ngView ngView}
|
418
|
+
* creates new scope, reinstantiates the controller.
|
419
|
+
*/
|
420
|
+
reload: function() {
|
421
|
+
forceReload = true;
|
422
|
+
$rootScope.$evalAsync(updateRoute);
|
423
|
+
}
|
424
|
+
};
|
425
|
+
|
426
|
+
$rootScope.$on('$locationChangeSuccess', updateRoute);
|
427
|
+
|
428
|
+
return $route;
|
429
|
+
|
430
|
+
/////////////////////////////////////////////////////
|
431
|
+
|
432
|
+
/**
|
433
|
+
* @param on {string} current url
|
434
|
+
* @param route {Object} route regexp to match the url against
|
435
|
+
* @return {?Object}
|
436
|
+
*
|
437
|
+
* @description
|
438
|
+
* Check if the route matches the current url.
|
439
|
+
*
|
440
|
+
* Inspired by match in
|
441
|
+
* visionmedia/express/lib/router/router.js.
|
442
|
+
*/
|
443
|
+
function switchRouteMatcher(on, route) {
|
444
|
+
var keys = route.keys,
|
445
|
+
params = {};
|
446
|
+
|
447
|
+
if (!route.regexp) return null;
|
448
|
+
|
449
|
+
var m = route.regexp.exec(on);
|
450
|
+
if (!m) return null;
|
451
|
+
|
452
|
+
var N = 0;
|
453
|
+
for (var i = 1, len = m.length; i < len; ++i) {
|
454
|
+
var key = keys[i - 1];
|
455
|
+
|
456
|
+
var val = 'string' == typeof m[i]
|
457
|
+
? decodeURIComponent(m[i])
|
458
|
+
: m[i];
|
459
|
+
|
460
|
+
if (key && val) {
|
461
|
+
params[key.name] = val;
|
462
|
+
}
|
463
|
+
}
|
464
|
+
return params;
|
465
|
+
}
|
466
|
+
|
467
|
+
function updateRoute() {
|
468
|
+
var next = parseRoute(),
|
469
|
+
last = $route.current;
|
470
|
+
|
471
|
+
if (next && last && next.$$route === last.$$route
|
472
|
+
&& equals(next.pathParams, last.pathParams) && !next.reloadOnSearch && !forceReload) {
|
473
|
+
last.params = next.params;
|
474
|
+
copy(last.params, $routeParams);
|
475
|
+
$rootScope.$broadcast('$routeUpdate', last);
|
476
|
+
} else if (next || last) {
|
477
|
+
forceReload = false;
|
478
|
+
$rootScope.$broadcast('$routeChangeStart', next, last);
|
479
|
+
$route.current = next;
|
480
|
+
if (next) {
|
481
|
+
if (next.redirectTo) {
|
482
|
+
if (isString(next.redirectTo)) {
|
483
|
+
$location.path(interpolate(next.redirectTo, next.params)).search(next.params)
|
484
|
+
.replace();
|
485
|
+
} else {
|
486
|
+
$location.url(next.redirectTo(next.pathParams, $location.path(), $location.search()))
|
487
|
+
.replace();
|
488
|
+
}
|
489
|
+
}
|
490
|
+
}
|
491
|
+
|
492
|
+
$q.when(next).
|
493
|
+
then(function() {
|
494
|
+
if (next) {
|
495
|
+
var locals = extend({}, next.resolve),
|
496
|
+
template, templateUrl;
|
497
|
+
|
498
|
+
forEach(locals, function(value, key) {
|
499
|
+
locals[key] = isString(value) ? $injector.get(value) : $injector.invoke(value);
|
500
|
+
});
|
501
|
+
|
502
|
+
if (isDefined(template = next.template)) {
|
503
|
+
if (isFunction(template)) {
|
504
|
+
template = template(next.params);
|
505
|
+
}
|
506
|
+
} else if (isDefined(templateUrl = next.templateUrl)) {
|
507
|
+
if (isFunction(templateUrl)) {
|
508
|
+
templateUrl = templateUrl(next.params);
|
509
|
+
}
|
510
|
+
templateUrl = $sce.getTrustedResourceUrl(templateUrl);
|
511
|
+
if (isDefined(templateUrl)) {
|
512
|
+
next.loadedTemplateUrl = templateUrl;
|
513
|
+
template = $http.get(templateUrl, {cache: $templateCache}).
|
514
|
+
then(function(response) { return response.data; });
|
515
|
+
}
|
516
|
+
}
|
517
|
+
if (isDefined(template)) {
|
518
|
+
locals['$template'] = template;
|
519
|
+
}
|
520
|
+
return $q.all(locals);
|
521
|
+
}
|
522
|
+
}).
|
523
|
+
// after route change
|
524
|
+
then(function(locals) {
|
525
|
+
if (next == $route.current) {
|
526
|
+
if (next) {
|
527
|
+
next.locals = locals;
|
528
|
+
copy(next.params, $routeParams);
|
529
|
+
}
|
530
|
+
$rootScope.$broadcast('$routeChangeSuccess', next, last);
|
531
|
+
}
|
532
|
+
}, function(error) {
|
533
|
+
if (next == $route.current) {
|
534
|
+
$rootScope.$broadcast('$routeChangeError', next, last, error);
|
535
|
+
}
|
536
|
+
});
|
537
|
+
}
|
538
|
+
}
|
539
|
+
|
540
|
+
|
541
|
+
/**
|
542
|
+
* @returns the current active route, by matching it against the URL
|
543
|
+
*/
|
544
|
+
function parseRoute() {
|
545
|
+
// Match a route
|
546
|
+
var params, match;
|
547
|
+
forEach(routes, function(route, path) {
|
548
|
+
if (!match && (params = switchRouteMatcher($location.path(), route))) {
|
549
|
+
match = inherit(route, {
|
550
|
+
params: extend({}, $location.search(), params),
|
551
|
+
pathParams: params});
|
552
|
+
match.$$route = route;
|
553
|
+
}
|
554
|
+
});
|
555
|
+
// No route matched; fallback to "otherwise" route
|
556
|
+
return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}});
|
557
|
+
}
|
558
|
+
|
559
|
+
/**
|
560
|
+
* @returns interpolation of the redirect path with the parameters
|
561
|
+
*/
|
562
|
+
function interpolate(string, params) {
|
563
|
+
var result = [];
|
564
|
+
forEach((string||'').split(':'), function(segment, i) {
|
565
|
+
if (i == 0) {
|
566
|
+
result.push(segment);
|
567
|
+
} else {
|
568
|
+
var segmentMatch = segment.match(/(\w+)(.*)/);
|
569
|
+
var key = segmentMatch[1];
|
570
|
+
result.push(params[key]);
|
571
|
+
result.push(segmentMatch[2] || '');
|
572
|
+
delete params[key];
|
573
|
+
}
|
574
|
+
});
|
575
|
+
return result.join('');
|
576
|
+
}
|
577
|
+
}];
|
578
|
+
}
|
579
|
+
|
580
|
+
ngRouteModule.provider('$routeParams', $RouteParamsProvider);
|
581
|
+
|
582
|
+
|
583
|
+
/**
|
584
|
+
* @ngdoc object
|
585
|
+
* @name ngRoute.$routeParams
|
586
|
+
* @requires $route
|
587
|
+
*
|
588
|
+
* @description
|
589
|
+
* Current set of route parameters. The route parameters are a combination of the
|
590
|
+
* {@link ng.$location $location} `search()`, and `path()`. The `path` parameters
|
591
|
+
* are extracted when the {@link ngRoute.$route $route} path is matched.
|
592
|
+
*
|
593
|
+
* In case of parameter name collision, `path` params take precedence over `search` params.
|
594
|
+
*
|
595
|
+
* The service guarantees that the identity of the `$routeParams` object will remain unchanged
|
596
|
+
* (but its properties will likely change) even when a route change occurs.
|
597
|
+
*
|
598
|
+
* Note that the `$routeParams` are only updated *after* a route change completes successfully.
|
599
|
+
* This means that you cannot rely on `$routeParams` being correct in route resolve functions.
|
600
|
+
* Instead you can use `$route.current.params` to access the new route's parameters.
|
601
|
+
*
|
602
|
+
* @example
|
603
|
+
* <pre>
|
604
|
+
* // Given:
|
605
|
+
* // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
|
606
|
+
* // Route: /Chapter/:chapterId/Section/:sectionId
|
607
|
+
* //
|
608
|
+
* // Then
|
609
|
+
* $routeParams ==> {chapterId:1, sectionId:2, search:'moby'}
|
610
|
+
* </pre>
|
611
|
+
*/
|
612
|
+
function $RouteParamsProvider() {
|
613
|
+
this.$get = function() { return {}; };
|
614
|
+
}
|
615
|
+
|
616
|
+
/**
|
617
|
+
* @ngdoc directive
|
618
|
+
* @name ngRoute.directive:ngView
|
619
|
+
* @restrict ECA
|
620
|
+
*
|
621
|
+
* @description
|
622
|
+
* # Overview
|
623
|
+
* `ngView` is a directive that complements the {@link ngRoute.$route $route} service by
|
624
|
+
* including the rendered template of the current route into the main layout (`index.html`) file.
|
625
|
+
* Every time the current route changes, the included view changes with it according to the
|
626
|
+
* configuration of the `$route` service.
|
627
|
+
*
|
628
|
+
* @animations
|
629
|
+
* enter - animation is used to bring new content into the browser.
|
630
|
+
* leave - animation is used to animate existing content away.
|
631
|
+
*
|
632
|
+
* The enter and leave animation occur concurrently.
|
633
|
+
*
|
634
|
+
* @scope
|
635
|
+
* @example
|
636
|
+
<example module="ngViewExample" deps="angular-route.js" animations="true">
|
637
|
+
<file name="index.html">
|
638
|
+
<div ng-controller="MainCntl as main">
|
639
|
+
Choose:
|
640
|
+
<a href="Book/Moby">Moby</a> |
|
641
|
+
<a href="Book/Moby/ch/1">Moby: Ch1</a> |
|
642
|
+
<a href="Book/Gatsby">Gatsby</a> |
|
643
|
+
<a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
|
644
|
+
<a href="Book/Scarlet">Scarlet Letter</a><br/>
|
645
|
+
|
646
|
+
<div class="example-animate-container">
|
647
|
+
<div ng-view class="view-example"></div>
|
648
|
+
</div>
|
649
|
+
<hr />
|
650
|
+
|
651
|
+
<pre>$location.path() = {{main.$location.path()}}</pre>
|
652
|
+
<pre>$route.current.templateUrl = {{main.$route.current.templateUrl}}</pre>
|
653
|
+
<pre>$route.current.params = {{main.$route.current.params}}</pre>
|
654
|
+
<pre>$route.current.scope.name = {{main.$route.current.scope.name}}</pre>
|
655
|
+
<pre>$routeParams = {{main.$routeParams}}</pre>
|
656
|
+
</div>
|
657
|
+
</file>
|
658
|
+
|
659
|
+
<file name="book.html">
|
660
|
+
<div>
|
661
|
+
controller: {{book.name}}<br />
|
662
|
+
Book Id: {{book.params.bookId}}<br />
|
663
|
+
</div>
|
664
|
+
</file>
|
665
|
+
|
666
|
+
<file name="chapter.html">
|
667
|
+
<div>
|
668
|
+
controller: {{chapter.name}}<br />
|
669
|
+
Book Id: {{chapter.params.bookId}}<br />
|
670
|
+
Chapter Id: {{chapter.params.chapterId}}
|
671
|
+
</div>
|
672
|
+
</file>
|
673
|
+
|
674
|
+
<file name="animations.css">
|
675
|
+
.example-animate-container {
|
676
|
+
position:relative;
|
677
|
+
background:white;
|
678
|
+
border:1px solid black;
|
679
|
+
height:40px;
|
680
|
+
overflow:hidden;
|
681
|
+
}
|
682
|
+
|
683
|
+
.example-animate-container > div {
|
684
|
+
padding:10px;
|
685
|
+
}
|
686
|
+
|
687
|
+
.view-example.ng-enter, .view-example.ng-leave {
|
688
|
+
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
|
689
|
+
-moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
|
690
|
+
-o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
|
691
|
+
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
|
692
|
+
|
693
|
+
display:block;
|
694
|
+
width:100%;
|
695
|
+
border-left:1px solid black;
|
696
|
+
|
697
|
+
position:absolute;
|
698
|
+
top:0;
|
699
|
+
left:0;
|
700
|
+
right:0;
|
701
|
+
bottom:0;
|
702
|
+
padding:10px;
|
703
|
+
}
|
704
|
+
|
705
|
+
.example-animate-container {
|
706
|
+
position:relative;
|
707
|
+
height:100px;
|
708
|
+
}
|
709
|
+
|
710
|
+
.view-example.ng-enter {
|
711
|
+
left:100%;
|
712
|
+
}
|
713
|
+
.view-example.ng-enter.ng-enter-active {
|
714
|
+
left:0;
|
715
|
+
}
|
716
|
+
|
717
|
+
.view-example.ng-leave { }
|
718
|
+
.view-example.ng-leave.ng-leave-active {
|
719
|
+
left:-100%;
|
720
|
+
}
|
721
|
+
</file>
|
722
|
+
|
723
|
+
<file name="script.js">
|
724
|
+
angular.module('ngViewExample', ['ngRoute', 'ngAnimate'], function($routeProvider, $locationProvider) {
|
725
|
+
$routeProvider.when('/Book/:bookId', {
|
726
|
+
templateUrl: 'book.html',
|
727
|
+
controller: BookCntl,
|
728
|
+
controllerAs: 'book'
|
729
|
+
});
|
730
|
+
$routeProvider.when('/Book/:bookId/ch/:chapterId', {
|
731
|
+
templateUrl: 'chapter.html',
|
732
|
+
controller: ChapterCntl,
|
733
|
+
controllerAs: 'chapter'
|
734
|
+
});
|
735
|
+
|
736
|
+
// configure html5 to get links working on jsfiddle
|
737
|
+
$locationProvider.html5Mode(true);
|
738
|
+
});
|
739
|
+
|
740
|
+
function MainCntl($route, $routeParams, $location) {
|
741
|
+
this.$route = $route;
|
742
|
+
this.$location = $location;
|
743
|
+
this.$routeParams = $routeParams;
|
744
|
+
}
|
745
|
+
|
746
|
+
function BookCntl($routeParams) {
|
747
|
+
this.name = "BookCntl";
|
748
|
+
this.params = $routeParams;
|
749
|
+
}
|
750
|
+
|
751
|
+
function ChapterCntl($routeParams) {
|
752
|
+
this.name = "ChapterCntl";
|
753
|
+
this.params = $routeParams;
|
754
|
+
}
|
755
|
+
</file>
|
756
|
+
|
757
|
+
<file name="scenario.js">
|
758
|
+
it('should load and compile correct template', function() {
|
759
|
+
element('a:contains("Moby: Ch1")').click();
|
760
|
+
var content = element('.doc-example-live [ng-view]').text();
|
761
|
+
expect(content).toMatch(/controller\: ChapterCntl/);
|
762
|
+
expect(content).toMatch(/Book Id\: Moby/);
|
763
|
+
expect(content).toMatch(/Chapter Id\: 1/);
|
764
|
+
|
765
|
+
element('a:contains("Scarlet")').click();
|
766
|
+
content = element('.doc-example-live [ng-view]').text();
|
767
|
+
expect(content).toMatch(/controller\: BookCntl/);
|
768
|
+
expect(content).toMatch(/Book Id\: Scarlet/);
|
769
|
+
});
|
770
|
+
</file>
|
771
|
+
</example>
|
772
|
+
*/
|
773
|
+
|
774
|
+
|
775
|
+
/**
|
776
|
+
* @ngdoc event
|
777
|
+
* @name ngRoute.directive:ngView#$viewContentLoaded
|
778
|
+
* @eventOf ngRoute.directive:ngView
|
779
|
+
* @eventType emit on the current ngView scope
|
780
|
+
* @description
|
781
|
+
* Emitted every time the ngView content is reloaded.
|
782
|
+
*/
|
783
|
+
var NG_VIEW_PRIORITY = 500;
|
784
|
+
var ngViewDirective = ['$route', '$anchorScroll', '$compile', '$controller', '$animate',
|
785
|
+
function($route, $anchorScroll, $compile, $controller, $animate) {
|
786
|
+
return {
|
787
|
+
restrict: 'ECA',
|
788
|
+
terminal: true,
|
789
|
+
priority: NG_VIEW_PRIORITY,
|
790
|
+
compile: function(element, attr) {
|
791
|
+
var onloadExp = attr.onload || '';
|
792
|
+
|
793
|
+
element.html('');
|
794
|
+
var anchor = jqLite(document.createComment(' ngView '));
|
795
|
+
element.replaceWith(anchor);
|
796
|
+
|
797
|
+
return function(scope) {
|
798
|
+
var currentScope, currentElement;
|
799
|
+
|
800
|
+
scope.$on('$routeChangeSuccess', update);
|
801
|
+
update();
|
802
|
+
|
803
|
+
function cleanupLastView() {
|
804
|
+
if (currentScope) {
|
805
|
+
currentScope.$destroy();
|
806
|
+
currentScope = null;
|
807
|
+
}
|
808
|
+
if(currentElement) {
|
809
|
+
$animate.leave(currentElement);
|
810
|
+
currentElement = null;
|
811
|
+
}
|
812
|
+
}
|
813
|
+
|
814
|
+
function update() {
|
815
|
+
var locals = $route.current && $route.current.locals,
|
816
|
+
template = locals && locals.$template;
|
817
|
+
|
818
|
+
if (template) {
|
819
|
+
cleanupLastView();
|
820
|
+
|
821
|
+
currentScope = scope.$new();
|
822
|
+
currentElement = element.clone();
|
823
|
+
currentElement.html(template);
|
824
|
+
$animate.enter(currentElement, null, anchor);
|
825
|
+
|
826
|
+
var link = $compile(currentElement, false, NG_VIEW_PRIORITY - 1),
|
827
|
+
current = $route.current;
|
828
|
+
|
829
|
+
if (current.controller) {
|
830
|
+
locals.$scope = currentScope;
|
831
|
+
var controller = $controller(current.controller, locals);
|
832
|
+
if (current.controllerAs) {
|
833
|
+
currentScope[current.controllerAs] = controller;
|
834
|
+
}
|
835
|
+
currentElement.data('$ngControllerController', controller);
|
836
|
+
currentElement.children().data('$ngControllerController', controller);
|
837
|
+
}
|
838
|
+
|
839
|
+
current.scope = currentScope;
|
840
|
+
|
841
|
+
link(currentScope);
|
842
|
+
|
843
|
+
currentScope.$emit('$viewContentLoaded');
|
844
|
+
currentScope.$eval(onloadExp);
|
845
|
+
|
846
|
+
// $anchorScroll might listen on event...
|
847
|
+
$anchorScroll();
|
848
|
+
} else {
|
849
|
+
cleanupLastView();
|
850
|
+
}
|
851
|
+
}
|
852
|
+
}
|
853
|
+
}
|
854
|
+
};
|
855
|
+
}];
|
856
|
+
|
857
|
+
ngRouteModule.directive('ngView', ngViewDirective);
|
858
|
+
|
859
|
+
|
860
|
+
})(window, window.angular);
|