File Coverage

lib/Mojolicious/Plugin/JSUrlFor.pm
Criterion Covered Total %
statement 51 52 98.0
branch 6 8 75.0
condition 5 7 71.4
subroutine 10 10 100.0
pod 1 1 100.0
total 73 78 93.5


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::JSUrlFor;
2 4     4   7355 use Mojo::Base 'Mojolicious::Plugin';
  4         5  
  4         21  
3              
4             our $VERSION = '0.17';
5              
6 4     4   715 use Mojo::ByteStream qw/b/;
  4         5  
  4         228  
7 4     4   29 use Data::Dumper;
  4         8  
  4         184  
8 4     4   45 use v5.10;
  4         9  
  4         2186  
9              
10             sub register {
11 5     5 1 439 my ( $self, $app, $config ) = @_;
12              
13 5 100       17 if ( $config->{route} ) {
14             $app->routes->get( $config->{route} => sub {
15 2     2   15757 my $c = shift;
16 2         5 $c->render(
17             inline => $c->app->_js_url_for_code_only(),
18             format => 'js'
19             );
20 1         4 } )->name('js_url_for');
21             }
22              
23             $app->helper(
24             js_url_for => sub {
25 16     16   150482 my $c = shift;
26 16         28 state $b_js; # bytestream for $js
27              
28 16 50 66     481 if ( $b_js && $app->mode eq 'production' ) {
29 0         0 return $b_js;
30             }
31              
32 16         366 my $js = $app->_js_url_for_code_only;
33              
34 16         187 $b_js = b('');
35 16         163 return $b_js;
36             }
37 5         356 );
38              
39             $app->helper(
40             _js_url_for_code_only => sub {
41 19     19   2240 my $c = shift;
42 19         68 my $endpoint_routes = $self->_collect_endpoint_routes( $app->routes );
43              
44 19         35 my %names2paths;
45 19         36 foreach my $route (@$endpoint_routes) {
46 117 50       469 next unless $route->name;
47              
48 117         466 my $path = $self->_get_path_for_route($route);
49 117         354 $path =~ s{^/*}{/}g; # TODO remove this quickfix
50              
51 117         216 $names2paths{$route->name} = $path;
52             }
53              
54 19         170 my $json_routes = $c->render_to_string( json => \%names2paths );
55 19         4375 utf8::decode( $json_routes );
56              
57 19         174 my $js = <<"JS";
58             var mojolicious_routes = $json_routes;
59             function url_for(route_name, captures) {
60             var pattern = mojolicious_routes[route_name];
61             if(!pattern) return route_name;
62              
63             // Fill placeholders with values
64             if (!captures) captures = {};
65             for (var placeholder in captures) { // TODO order placeholders from longest to shortest
66             var re = new RegExp('[:*]' + placeholder, 'g');
67             pattern = pattern.replace(re, captures[placeholder]);
68             }
69              
70             // Clean not replaces placeholders
71             pattern = pattern.replace(/[:*][^/.]+/g, '');
72              
73             return pattern;
74             }
75             JS
76 19         86 return $js;
77 5         463 } );
78             }
79              
80              
81             sub _collect_endpoint_routes {
82 35     35   111 my ( $self, $route ) = @_;
83 35         40 my @endpoint_routes;
84              
85 35         33 foreach my $child_route ( @{ $route->children } ) {
  35         112  
86 133 100       352 if ( $child_route->is_endpoint ) {
87 117         1033 push @endpoint_routes, $child_route;
88             } else {
89 16         126 push @endpoint_routes, @{ $self->_collect_endpoint_routes($child_route) };
  16         43  
90             }
91             }
92             return \@endpoint_routes
93 35         87 }
94              
95             sub _get_path_for_route {
96 117     117   103 my ( $self, $parent ) = @_;
97              
98 117   50     202 my $path = $parent->pattern->unparsed // '';
99              
100 117         797 while ( $parent = $parent->parent ) {
101 245   100     1638 $path = ($parent->pattern->unparsed//'') . $path;
102             }
103              
104 117         1053 return $path;
105             }
106              
107             1;
108             __END__