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   10508 use Mojo::Base 'Mojolicious::Plugin';
  4         6  
  4         22  
3              
4             our $VERSION = '0.15';
5              
6 4     4   729 use Mojo::ByteStream qw/b/;
  4         7  
  4         217  
7 4     4   31 use Data::Dumper;
  4         4  
  4         189  
8 4     4   40 use v5.10;
  4         11  
  4         2320  
9              
10             sub register {
11 5     5 1 570 my ( $self, $app, $config ) = @_;
12              
13 5 100       18 if ( $config->{route} ) {
14             $app->routes->get( $config->{route} => sub {
15 2     2   54836 my $c = shift;
16 2         35 $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   307377 my $c = shift;
26 16         32 state $b_js; # bytestream for $js
27              
28 16 50 66     511 if ( $b_js && $app->mode eq 'production' ) {
29 0         0 return $b_js;
30             }
31              
32 16         712 my $js = $app->_js_url_for_code_only;
33              
34 16         204 $b_js = b('');
35 16         212 return $b_js;
36             }
37 5         771 );
38              
39             $app->helper(
40             _js_url_for_code_only => sub {
41 19     19   3885 my $c = shift;
42 19         340 my $endpoint_routes = $self->_collect_endpoint_routes( $app->routes );
43              
44 19         23 my %names2paths;
45 19         41 foreach my $route (@$endpoint_routes) {
46 117 50       543 next unless $route->name;
47              
48 117         524 my $path = $self->_get_path_for_route($route);
49 117         370 $path =~ s{^/*}{/}g; # TODO remove this quickfix
50              
51 117         282 $names2paths{$route->name} = $path;
52             }
53              
54 19         185 my $json_routes = $c->render_to_string( json => \%names2paths );
55 19         6150 utf8::decode( $json_routes );
56              
57 19         161 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         97 return $js;
77 5         1094 } );
78             }
79              
80              
81             sub _collect_endpoint_routes {
82 35     35   162 my ( $self, $route ) = @_;
83 35         43 my @endpoint_routes;
84              
85 35         37 foreach my $child_route ( @{ $route->children } ) {
  35         609  
86 133 100       458 if ( $child_route->is_endpoint ) {
87 117         4230 push @endpoint_routes, $child_route;
88             } else {
89 16         553 push @endpoint_routes, @{ $self->_collect_endpoint_routes($child_route) };
  16         40  
90             }
91             }
92             return \@endpoint_routes
93 35         99 }
94              
95             sub _get_path_for_route {
96 117     117   128 my ( $self, $parent ) = @_;
97              
98 117   50     1816 my $path = $parent->pattern->pattern // '';
99              
100 117         4124 while ( $parent = $parent->parent ) {
101 245   100     8956 $path = ($parent->pattern->pattern//'') . $path;
102             }
103              
104 117         4772 return $path;
105             }
106              
107             1;
108             __END__