File Coverage

lib/Mojolicious/Plugin/JSUrlFor/Angular.pm
Criterion Covered Total %
statement 35 37 94.5
branch 2 4 50.0
condition 2 4 50.0
subroutine 6 6 100.0
pod 1 1 100.0
total 46 52 88.4


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::JSUrlFor::Angular;
2 1     1   711 use Mojo::Base 'Mojolicious::Plugin';
  1         1  
  1         5  
3 1     1   135 use JSON::PP;
  1         1  
  1         517  
4              
5             my $json = JSON::PP->new->utf8(0)->pretty;
6              
7             our $VERSION = '0.18';
8              
9              
10             sub register {
11 1     1 1 29 my ( $self, $app, $config ) = @_;
12              
13             $app->helper(
14             _js_url_for_code_only => sub {
15 1     1   132 my $c = shift;
16 1         5 my $endpoint_routes = $self->_collect_endpoint_routes( $app->routes );
17              
18             #~ my %names2paths;
19 1         1 my @names2paths;
20 1         1 foreach my $route (@$endpoint_routes) {
21 1 50       3 next unless $route->name;
22            
23 1         6 my $path = $self->_get_path_for_route($route);
24 1         4 $path =~ s{^/*}{/}g; # TODO remove this quickfix
25              
26             #~ $names2paths{$route->name} = $path;
27 1         4 push @names2paths, sprintf("'%s': '%s'", $route->name, $path);
28            
29             #~ if ($route->name eq 'assetpack by topic') {
30             #~ push @names2paths, sprintf("'%s': '%s'", "t/$_", $app->url_for('assetpack by topic', topic=>$_))
31             #~ for keys %{$app->assetpack->{by_topic}};
32             #~ }
33             }
34              
35             #~ my $json_routes = $c->render_to_string( json => \%names2paths );
36 1         9 my $json_routes = $json->encode(\@names2paths);
37 1         104 $json_routes =~ s/"//g;
38 1         5 $json_routes =~ s/'/"/g;
39 1         3 $json_routes =~ s/\[/{/g;
40 1         3 $json_routes =~ s/\]/}/g;
41             #~ utf8::decode( $json_routes );
42              
43 1         6 my $js = <<"JS";
44             (function () {
45             'use strict';
46             /*
47             Маршруты/Routes
48            
49             // method url_for
50             appRoutes.url_for(route_name, captures, param)
51             returns url string
52             captures: either object, either array, either scalar
53             param: either object, either scalar
54            
55             appRoutes.url_for('foo name', {id: 123}); // передача объекта подстановки
56             appRoutes.url_for('foo name', [123]); // передача массива подстановки
57             appRoutes.url_for('foo name', 123); // передача скаляра подстановки
58             appRoutes.url_for('foo name', ..., param); // передача параметров запроса (объект или готовая строка)
59            
60             // url_for tests
61             appRoutes.routes['foo bar'] = 'foo=:foo/bar=:bar';
62             console.log(appRoutes.url_for('foo bar', []) == 'foo=/bar=');
63             console.log(appRoutes.url_for('foo bar', [1,2]) == 'foo=1/bar=2');
64             console.log(appRoutes.url_for('foo bar', [1]) == 'foo=1/bar=');
65             console.log(appRoutes.url_for('foo bar') == 'foo=/bar=');
66             console.log(appRoutes.url_for('foo bar', {}) == 'foo=/bar=');
67             console.log(appRoutes.url_for('foo bar', {foo:'ok', baz:'0'}) == 'foo=ok/bar=');
68             console.log(appRoutes.url_for('foo bar', {foo:'ok', bar:'0'}) == 'foo=ok/bar=0' );
69             console.log(appRoutes.url_for('foo bar', 'ook') == 'foo=ook/bar=');
70             console.log(appRoutes.url_for('foo bar', null, 'param1') == 'foo=/bar=?param1');
71             console.log(appRoutes.url_for('foo bar', {foo:'ok', bar:'0'}, {p1:1,p2:2}) == 'foo=ok/bar=0?p1=1&p2=2' );
72             console.log(appRoutes.url_for('foo bar', {foo:'ok', bar:'0'}, {p1:1,"парам2":[1,2]}) == 'foo=ok/bar=0?p1=1&парам2=2&парам2=2' );
73            
74             // method baseURL
75             var base = appRoutes.baseURL();
76             appRoutes.baseURL('http://host...');
77              
78             */
79            
80             var moduleName = "appRoutes";
81              
82             try {
83             if (angular.module(moduleName)) return function () {};
84             } catch(err) { /* failed to require */ }
85              
86             var routes = $json_routes
87             , arr_re = new RegExp('[:*]\\\\w+', 'g')
88             , _baseURL = '';
89              
90             function baseURL (base) {// set/get base URL prefix
91             if (base == undefined) return _baseURL;
92             _baseURL = base;
93             return base;
94            
95             }
96              
97              
98             function url_for(route_name, captures, param) {
99             var pattern = routes[route_name];
100             if(!pattern) {
101             console.log("[angular.appRoutes] Has none route for the name: "+route_name);
102             return baseURL() + route_name;
103             }
104            
105             if ( captures == undefined ) captures = [];
106             if ( !angular.isObject(captures) ) captures = [captures];
107             if ( angular.isArray(captures) ) {
108             var replacer = function () {
109             var c = captures.shift();
110             if(c == undefined) c='';
111             return c;
112             };
113             pattern = pattern.replace(arr_re, replacer);
114             } else {
115             angular.forEach(captures, function(value, placeholder) {
116             var re = new RegExp('[:*]' + placeholder, 'g');
117             pattern = pattern.replace(re, value);
118             });
119             pattern = pattern.replace(/[:*][^/.]+/g, ''); // Clean not replaces placeholders
120             }
121            
122             if ( param == undefined ) return baseURL() + pattern;
123             if ( !angular.isObject(param) ) return baseURL() + pattern + '?' + param;
124             var query = [];
125             angular.forEach(param, function(value, name) {
126             if ( angular.isArray(value) ) { angular.forEach(value, function(val) {query.push(name+'='+val);}); }
127             else { query.push(name+'='+value); }
128             });
129             if (!query.length) return baseURL() + pattern;
130             return baseURL() + pattern + '?' + query.join('&');
131             }
132              
133             var factory = {
134             routes: routes,
135             baseURL: baseURL,
136             url_for: url_for
137             };
138              
139             angular.module(moduleName, [])
140              
141             .run(function (\$window) {
142             \$window['angular.'+moduleName] = factory;
143             })
144              
145             .factory(moduleName, function () {
146             return factory;
147             })
148             ;
149              
150             }());
151             JS
152 1         3 return $js;
153 1         8 } );
154             }
155              
156              
157             sub _collect_endpoint_routes {
158 1     1   4 my ( $self, $route ) = @_;
159 1         1 my @endpoint_routes;
160              
161 1         1 foreach my $child_route ( @{ $route->children } ) {
  1         3  
162 1 50       6 if ( $child_route->is_endpoint ) {
163 1         13 push @endpoint_routes, $child_route;
164             } else {
165 0         0 push @endpoint_routes, @{ $self->_collect_endpoint_routes($child_route) };
  0         0  
166             }
167             }
168             return \@endpoint_routes
169 1         2 }
170              
171             sub _get_path_for_route {
172 1     1   1 my ( $self, $parent ) = @_;
173              
174 1   50     2 my $path = $parent->pattern->unparsed // '';
175              
176 1         7 while ( $parent = $parent->parent ) {
177 1   50     5 $path = ($parent->pattern->unparsed//'') . $path;
178             }
179              
180 1         14 return $path;
181             }
182              
183             1;
184             __END__