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   11690 use Mojo::Base 'Mojolicious::Plugin';
  4         6  
  4         25  
3              
4             our $VERSION = '0.16';
5              
6 4     4   743 use Mojo::ByteStream qw/b/;
  4         6  
  4         249  
7 4     4   25 use Data::Dumper;
  4         6  
  4         185  
8 4     4   47 use v5.10;
  4         10  
  4         2499  
9              
10             sub register {
11 5     5 1 606 my ( $self, $app, $config ) = @_;
12              
13 5 100       21 if ( $config->{route} ) {
14             $app->routes->get( $config->{route} => sub {
15 2     2   61317 my $c = shift;
16 2         51 $c->render(
17             inline => $c->app->_js_url_for_code_only(),
18             format => 'js'
19             );
20 1         21 } )->name('js_url_for');
21             }
22              
23             $app->helper(
24             js_url_for => sub {
25 16     16   312821 my $c = shift;
26 16         32 state $b_js; # bytestream for $js
27              
28 16 50 66     513 if ( $b_js && $app->mode eq 'production' ) {
29 0         0 return $b_js;
30             }
31              
32 16         685 my $js = $app->_js_url_for_code_only;
33              
34 16         238 $b_js = b('');
35 16         199 return $b_js;
36             }
37 5         667 );
38              
39             $app->helper(
40             _js_url_for_code_only => sub {
41 19     19   4260 my $c = shift;
42 19         526 my $endpoint_routes = $self->_collect_endpoint_routes( $app->routes );
43              
44 19         27 my %names2paths;
45 19         47 foreach my $route (@$endpoint_routes) {
46 117 50       604 next unless $route->name;
47              
48 117         616 my $path = $self->_get_path_for_route($route);
49 117         396 $path =~ s{^/*}{/}g; # TODO remove this quickfix
50              
51 117         285 $names2paths{$route->name} = $path;
52             }
53              
54 19         193 my $json_routes = $c->render_to_string( json => \%names2paths );
55 19         7183 utf8::decode( $json_routes );
56              
57 19         204 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         101 return $js;
77 5         994 } );
78             }
79              
80              
81             sub _collect_endpoint_routes {
82 35     35   176 my ( $self, $route ) = @_;
83 35         40 my @endpoint_routes;
84              
85 35         47 foreach my $child_route ( @{ $route->children } ) {
  35         784  
86 133 100       465 if ( $child_route->is_endpoint ) {
87 117         4417 push @endpoint_routes, $child_route;
88             } else {
89 16         749 push @endpoint_routes, @{ $self->_collect_endpoint_routes($child_route) };
  16         50  
90             }
91             }
92             return \@endpoint_routes
93 35         104 }
94              
95             sub _get_path_for_route {
96 117     117   122 my ( $self, $parent ) = @_;
97              
98 117   50     1988 my $path = $parent->pattern->pattern // '';
99              
100 117         4289 while ( $parent = $parent->parent ) {
101 245   100     8869 $path = ($parent->pattern->pattern//'') . $path;
102             }
103              
104 117         4708 return $path;
105             }
106              
107             1;
108             __END__