| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Catalyst::View::MojoTemplate; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 1 |  |  | 1 |  | 1119 | use Moo; | 
|  | 1 |  |  |  |  | 9273 |  | 
|  | 1 |  |  |  |  | 3 |  | 
| 4 | 1 |  |  | 1 |  | 1654 | use Mojo::Template; | 
|  | 1 |  |  |  |  | 186061 |  | 
|  | 1 |  |  |  |  | 10 |  | 
| 5 | 1 |  |  | 1 |  | 61 | use Mojo::ByteStream qw(b); | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 1187 |  | 
| 6 |  |  |  |  |  |  |  | 
| 7 |  |  |  |  |  |  | extends 'Catalyst::View'; | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | our $VERSION = 0.005; | 
| 10 |  |  |  |  |  |  |  | 
| 11 |  |  |  |  |  |  | has app => (is=>'ro'); | 
| 12 |  |  |  |  |  |  | has auto_escape => (is=>'ro', required=>1, default=>1); | 
| 13 |  |  |  |  |  |  | has append => (is=>'ro', required=>1, default=>''); | 
| 14 |  |  |  |  |  |  | has prepend => (is=>'ro', required=>1, default=>''); | 
| 15 |  |  |  |  |  |  | has capture_end => (is=>'ro', required=>1, default=>sub {'end'}); | 
| 16 |  |  |  |  |  |  | has capture_start => (is=>'ro', required=>1, default=>sub {'begin'}); | 
| 17 |  |  |  |  |  |  | has comment_mark => (is=>'ro', required=>1, default=>'#'); | 
| 18 |  |  |  |  |  |  | has encoding => (is=>'ro', required=>1, default=>'UTF-8'); | 
| 19 |  |  |  |  |  |  | has escape_mark => (is=>'ro', required=>1, default=>'='); | 
| 20 |  |  |  |  |  |  | has expression_mark => (is=>'ro', required=>1, default=>'='); | 
| 21 |  |  |  |  |  |  | has line_start => (is=>'ro', required=>1, default=>'%'); | 
| 22 |  |  |  |  |  |  | has replace_mark => (is=>'ro', required=>1, default=>'%'); | 
| 23 |  |  |  |  |  |  | has trim_mark => (is=>'ro', required=>1, default=>'%'); | 
| 24 |  |  |  |  |  |  | has tag_start=> (is=>'ro', required=>1, default=>'<%'); | 
| 25 |  |  |  |  |  |  | has tag_end => (is=>'ro', required=>1, default=>'%>'); | 
| 26 |  |  |  |  |  |  | has ['name', 'namespace'] => (is=>'rw'); | 
| 27 |  |  |  |  |  |  |  | 
| 28 |  |  |  |  |  |  | has template_extension => (is=>'ro', required=>1, default=>sub { '.ep' }); | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | has content_type => (is=>'ro', required=>1, default=>sub { 'text/html' }); | 
| 31 |  |  |  |  |  |  | has helpers => (is=>'ro', predicate=>'has_helpers'); | 
| 32 |  |  |  |  |  |  | has layout => (is=>'ro', predicate=>'has_layout'); | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | sub build_mojo_template { | 
| 35 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 36 | 0 |  |  |  |  |  | my $prepend = 'my $c = _C;' . $self->prepend; | 
| 37 | 0 |  |  |  |  |  | my %args = ( | 
| 38 |  |  |  |  |  |  | auto_escape => $self->auto_escape, | 
| 39 |  |  |  |  |  |  | append => $self->append, | 
| 40 |  |  |  |  |  |  | capture_end => $self->capture_end, | 
| 41 |  |  |  |  |  |  | capture_start => $self->capture_start, | 
| 42 |  |  |  |  |  |  | comment_mark => $self->comment_mark, | 
| 43 |  |  |  |  |  |  | encoding => $self->encoding, | 
| 44 |  |  |  |  |  |  | escape_mark => $self->escape_mark, | 
| 45 |  |  |  |  |  |  | expression_mark => $self->expression_mark, | 
| 46 |  |  |  |  |  |  | line_start => $self->line_start, | 
| 47 |  |  |  |  |  |  | prepend => $prepend, | 
| 48 |  |  |  |  |  |  | trim_mark => $self->trim_mark, | 
| 49 |  |  |  |  |  |  | tag_start => $self->tag_start, | 
| 50 |  |  |  |  |  |  | tag_end => $self->tag_end, | 
| 51 |  |  |  |  |  |  | vars => 1, | 
| 52 |  |  |  |  |  |  | ); | 
| 53 |  |  |  |  |  |  |  | 
| 54 | 0 |  |  |  |  |  | return Mojo::Template->new(%args); | 
| 55 |  |  |  |  |  |  | } | 
| 56 |  |  |  |  |  |  |  | 
| 57 |  |  |  |  |  |  |  | 
| 58 |  |  |  |  |  |  | has path_base => ( | 
| 59 |  |  |  |  |  |  | is=>'ro', | 
| 60 |  |  |  |  |  |  | required=>1, | 
| 61 |  |  |  |  |  |  | lazy=>1, | 
| 62 |  |  |  |  |  |  | builder=>'_build_path_base'); | 
| 63 |  |  |  |  |  |  |  | 
| 64 |  |  |  |  |  |  | sub _build_path_base { | 
| 65 | 0 |  |  | 0 |  |  | my $self = shift; | 
| 66 | 0 |  |  |  |  |  | my $root = $self->app->path_to('root'); | 
| 67 | 0 | 0 |  |  |  |  | die "No directory '$root'" unless -e $root; | 
| 68 |  |  |  |  |  |  |  | 
| 69 | 0 |  |  |  |  |  | return $root; | 
| 70 |  |  |  |  |  |  | } | 
| 71 |  |  |  |  |  |  |  | 
| 72 |  |  |  |  |  |  | sub COMPONENT { | 
| 73 | 0 |  |  | 0 | 1 |  | my ($class, $app, $args) = @_; | 
| 74 | 0 |  |  |  |  |  | $args = $class->merge_config_hashes($class->config, $args); | 
| 75 | 0 |  |  |  |  |  | $args->{app} = $app; | 
| 76 |  |  |  |  |  |  |  | 
| 77 | 0 |  |  |  |  |  | return $class->new($app, $args); | 
| 78 |  |  |  |  |  |  | } | 
| 79 |  |  |  |  |  |  |  | 
| 80 |  |  |  |  |  |  | sub ACCEPT_CONTEXT { | 
| 81 | 0 |  |  | 0 | 1 |  | my ($self, $c, @args) = @_; | 
| 82 |  |  |  |  |  |  | $c->stash->{'view.layout'} = $self->layout | 
| 83 | 0 | 0 | 0 |  |  |  | if $self->has_layout && !exists($c->stash->{'view.layout'}); | 
| 84 |  |  |  |  |  |  |  | 
| 85 | 0 | 0 |  |  |  |  | if(@args) { | 
| 86 | 0 | 0 |  |  |  |  | my %template_args = %{ pop(@args)||+{} }; | 
|  | 0 |  |  |  |  |  |  | 
| 87 | 0 |  | 0 |  |  |  | my $template = shift @args || $self->find_template($c); | 
| 88 | 0 |  |  |  |  |  | my %global_args = $self->template_vars($c); | 
| 89 | 0 |  |  |  |  |  | my $output = $self->render($c, $template, +{%global_args, %template_args}); | 
| 90 | 0 |  |  |  |  |  | $self->set_response_from($c, $output); | 
| 91 | 0 |  |  |  |  |  | return $self; | 
| 92 |  |  |  |  |  |  | } else { | 
| 93 | 0 |  |  |  |  |  | return $self; | 
| 94 |  |  |  |  |  |  | } | 
| 95 |  |  |  |  |  |  | } | 
| 96 |  |  |  |  |  |  |  | 
| 97 |  |  |  |  |  |  | sub set_response_from { | 
| 98 | 0 |  |  | 0 | 0 |  | my ($self, $c, $output) = @_; | 
| 99 | 0 | 0 |  |  |  |  | $c->response->content_type($self->content_type) unless $c->response->content_type; | 
| 100 | 0 | 0 |  |  |  |  | $c->response->body($output) unless $c->response->body; | 
| 101 |  |  |  |  |  |  | } | 
| 102 |  |  |  |  |  |  |  | 
| 103 |  |  |  |  |  |  | sub process { | 
| 104 | 0 |  |  | 0 | 1 |  | my ($self, $c) = @_; | 
| 105 | 0 |  |  |  |  |  | my $template = $self->find_template($c); | 
| 106 | 0 |  |  |  |  |  | my %template_args = $self->template_vars($c); | 
| 107 | 0 |  |  |  |  |  | my $output = $self->render($c, $template, \%template_args); | 
| 108 | 0 |  |  |  |  |  | $self->set_response_from($c, $output); | 
| 109 |  |  |  |  |  |  |  | 
| 110 | 0 |  |  |  |  |  | return 1; | 
| 111 |  |  |  |  |  |  | } | 
| 112 |  |  |  |  |  |  |  | 
| 113 |  |  |  |  |  |  | sub find_template { | 
| 114 | 0 |  |  | 0 | 0 |  | my ($self, $c) = @_; | 
| 115 |  |  |  |  |  |  | my $template = $c->stash->{template} | 
| 116 | 0 |  | 0 |  |  |  | ||  $c->action . $self->template_extension; | 
| 117 |  |  |  |  |  |  |  | 
| 118 | 0 | 0 |  |  |  |  | unless (defined $template) { | 
| 119 | 0 | 0 |  |  |  |  | $c->log->debug('No template specified for rendering') if $c->debug; | 
| 120 | 0 |  |  |  |  |  | return 0; | 
| 121 |  |  |  |  |  |  | } | 
| 122 |  |  |  |  |  |  |  | 
| 123 | 0 |  |  |  |  |  | return $template; | 
| 124 |  |  |  |  |  |  | } | 
| 125 |  |  |  |  |  |  |  | 
| 126 |  |  |  |  |  |  | sub render { | 
| 127 | 0 |  |  | 0 | 0 |  | my ($self, $c, $template, $template_args) = @_; | 
| 128 | 0 |  |  |  |  |  | my $output = $self->render_template($c, $template, $template_args); | 
| 129 |  |  |  |  |  |  |  | 
| 130 | 0 | 0 |  |  |  |  | if(ref $output) { | 
| 131 |  |  |  |  |  |  | # Its a Mojo::Exception; | 
| 132 | 0 |  |  |  |  |  | $c->response->content_type('text/plain'); | 
| 133 | 0 |  |  |  |  |  | $c->response->body($output); | 
| 134 | 0 |  |  |  |  |  | return $output; | 
| 135 |  |  |  |  |  |  | } | 
| 136 |  |  |  |  |  |  |  | 
| 137 | 0 |  |  |  |  |  | return $self->apply_layout($c, $output); | 
| 138 |  |  |  |  |  |  | } | 
| 139 |  |  |  |  |  |  |  | 
| 140 |  |  |  |  |  |  | sub apply_layout { | 
| 141 | 0 |  |  | 0 | 0 |  | my ($self, $c, $output) = @_; | 
| 142 | 0 | 0 |  |  |  |  | if(my $layout = $self->find_layout($c)) { | 
| 143 | 0 | 0 |  |  |  |  | $c->log->debug(qq/Applying layout "$layout"/) if $c->debug; | 
| 144 | 0 |  |  |  |  |  | $c->stash->{'view.content'}->{main} = b $output; | 
| 145 | 0 |  |  |  |  |  | $output = $self->render($c, $layout, +{ $self->template_vars($c) }); | 
| 146 |  |  |  |  |  |  | } | 
| 147 | 0 |  |  |  |  |  | return $output; | 
| 148 |  |  |  |  |  |  | } | 
| 149 |  |  |  |  |  |  |  | 
| 150 |  |  |  |  |  |  | sub find_layout { | 
| 151 | 0 |  |  | 0 | 0 |  | my ($self, $c) = @_; | 
| 152 | 0 | 0 |  |  |  |  | return exists $c->stash->{'view.layout'} ? delete $c->stash->{'view.layout'} : undef; | 
| 153 |  |  |  |  |  |  | } | 
| 154 |  |  |  |  |  |  |  | 
| 155 |  |  |  |  |  |  | sub render_template { | 
| 156 | 0 |  |  | 0 | 0 |  | my ($self, $c, $template, $template_args) = @_; | 
| 157 | 0 | 0 |  |  |  |  | $c->log->debug(qq/Rendering template "$template"/) if $c->debug; | 
| 158 |  |  |  |  |  |  |  | 
| 159 | 0 |  | 0 |  |  |  | my $mojo_template = $self->{"__mojo_template_${template}"} ||= do { | 
| 160 | 0 |  |  |  |  |  | my $mojo_template = $self->build_mojo_template; | 
| 161 | 0 |  |  |  |  |  | $mojo_template->name($template); | 
| 162 |  |  |  |  |  |  |  | 
| 163 | 0 |  |  |  |  |  | my $namespace_part = $template; | 
| 164 | 0 |  |  |  |  |  | $namespace_part =~s/\//::/g; | 
| 165 | 0 |  |  |  |  |  | $namespace_part =~s/\.ep$//; | 
| 166 | 0 |  |  |  |  |  | $mojo_template->namespace( ref($self) .'::Sandbox::'. $namespace_part); | 
| 167 |  |  |  |  |  |  |  | 
| 168 | 0 |  |  |  |  |  | my $template_full_path = $self->path_base->file($template); | 
| 169 | 0 |  |  |  |  |  | my $template_contents = $template_full_path->slurp; | 
| 170 | 0 | 0 |  |  |  |  | $c->log->debug(qq/Found template at path "$template_full_path"/) if $c->debug; | 
| 171 |  |  |  |  |  |  |  | 
| 172 | 0 |  |  |  |  |  | my $output = $mojo_template->parse($template_contents); | 
| 173 |  |  |  |  |  |  | }; | 
| 174 |  |  |  |  |  |  |  | 
| 175 | 0 |  |  |  |  |  | my $ns = $mojo_template->namespace; | 
| 176 |  |  |  |  |  |  |  | 
| 177 | 1 |  |  | 1 |  | 7 | no strict 'refs'; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 34 |  | 
| 178 | 1 |  |  | 1 |  | 5 | no warnings 'redefine'; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 1151 |  | 
| 179 | 0 |  |  | 0 |  |  | local *{"${ns}::_C"} = sub { $c }; | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 180 |  |  |  |  |  |  |  | 
| 181 | 0 | 0 |  |  |  |  | unless($self->{"__mojo_helper_${ns}"}) { | 
| 182 | 0 |  |  |  |  |  | $self->inject_helpers($c, $ns); | 
| 183 | 0 |  |  |  |  |  | $self->{"__mojo_helper_${ns}"}++; | 
| 184 |  |  |  |  |  |  | } | 
| 185 |  |  |  |  |  |  |  | 
| 186 | 0 |  |  |  |  |  | return my $output = $mojo_template->process($template_args); | 
| 187 |  |  |  |  |  |  | } | 
| 188 |  |  |  |  |  |  |  | 
| 189 |  |  |  |  |  |  | sub inject_helpers { | 
| 190 | 0 |  |  | 0 | 0 |  | my ($self, $c, $namespace) = @_; | 
| 191 | 0 |  |  |  |  |  | my %helpers = $self->get_helpers; | 
| 192 | 0 |  |  |  |  |  | foreach my $helper(keys %helpers) { | 
| 193 | 0 |  |  |  |  |  | eval qq[ | 
| 194 |  |  |  |  |  |  | package $namespace; | 
| 195 |  |  |  |  |  |  | sub $helper { \$self->get_helpers('$helper')->(\$self, _C, \@_) } | 
| 196 | 0 | 0 |  |  |  |  | ]; die $@ if $@; | 
| 197 |  |  |  |  |  |  | } | 
| 198 |  |  |  |  |  |  | } | 
| 199 |  |  |  |  |  |  |  | 
| 200 |  |  |  |  |  |  | sub template_vars { | 
| 201 | 0 |  |  | 0 | 0 |  | my ($self, $c) = @_; | 
| 202 |  |  |  |  |  |  | my %template_args = ( | 
| 203 |  |  |  |  |  |  | base => $c->req->base, | 
| 204 |  |  |  |  |  |  | name => $c->config->{name} || '', | 
| 205 |  |  |  |  |  |  | self => $self, | 
| 206 | 0 | 0 | 0 |  |  |  | %{$c->stash||+{}}, | 
|  | 0 |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | ); | 
| 208 |  |  |  |  |  |  |  | 
| 209 | 0 |  |  |  |  |  | return %template_args; | 
| 210 |  |  |  |  |  |  | } | 
| 211 |  |  |  |  |  |  |  | 
| 212 |  |  |  |  |  |  | sub default_helpers { | 
| 213 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 214 |  |  |  |  |  |  | return ( | 
| 215 |  |  |  |  |  |  | layout => sub { | 
| 216 | 0 |  |  | 0 |  |  | my ($self, $c, $template, %args) = @_; | 
| 217 | 0 |  |  |  |  |  | $c->stash('view.layout' => $template); | 
| 218 | 0 | 0 |  |  |  |  | $c->stash(%args) if %args; | 
| 219 |  |  |  |  |  |  | }, | 
| 220 |  |  |  |  |  |  | wrapper => sub { | 
| 221 | 0 |  |  | 0 |  |  | my ($self, $c, $template, @args) = @_; | 
| 222 | 0 |  |  |  |  |  | $c->stash->{'view.content'}->{main} = pop @args; | 
| 223 | 0 |  |  |  |  |  | my %args = @args; | 
| 224 | 0 |  |  |  |  |  | my %global_args = $self->template_vars($c); | 
| 225 | 0 |  |  |  |  |  | return b($self->render_template($c, $template, +{ %global_args, %args })); | 
| 226 |  |  |  |  |  |  | }, | 
| 227 |  |  |  |  |  |  | include => sub { | 
| 228 | 0 |  |  | 0 |  |  | my ($self, $c, $template, %args) = @_; | 
| 229 | 0 |  |  |  |  |  | my %global_args = $self->template_vars($c); | 
| 230 | 0 |  |  |  |  |  | return b($self->render_template($c, $template, +{ %global_args, %args })); | 
| 231 |  |  |  |  |  |  | }, | 
| 232 |  |  |  |  |  |  | content => sub { | 
| 233 | 0 |  |  | 0 |  |  | my ($self, $c, $name, $proto) = @_; | 
| 234 |  |  |  |  |  |  |  | 
| 235 | 0 |  | 0 |  |  |  | $name ||= 'main'; | 
| 236 | 0 | 0 | 0 |  |  |  | $c->stash->{'view.content'}->{$name} = _block($proto) if $proto && !exists($c->stash->{'view.content'}->{$name}); | 
| 237 |  |  |  |  |  |  |  | 
| 238 | 0 |  |  |  |  |  | my $value = $c->stash->{'view.content'}->{$name}; | 
| 239 | 0 | 0 |  |  |  |  | $value = '' unless defined($value); | 
| 240 |  |  |  |  |  |  |  | 
| 241 | 0 |  |  |  |  |  | return b $value; | 
| 242 |  |  |  |  |  |  | }, | 
| 243 |  |  |  |  |  |  | content_with => sub { | 
| 244 | 0 |  |  | 0 |  |  | my ($self, $c, $name, $proto) = @_; | 
| 245 |  |  |  |  |  |  |  | 
| 246 | 0 |  | 0 |  |  |  | $name ||= 'main'; | 
| 247 | 0 | 0 |  |  |  |  | $c->stash->{'view.content'}->{$name} = _block($proto) if $proto; | 
| 248 |  |  |  |  |  |  |  | 
| 249 | 0 |  |  |  |  |  | my $value = $c->stash->{'view.content'}->{$name}; | 
| 250 | 0 | 0 |  |  |  |  | $value = '' unless defined($value); | 
| 251 |  |  |  |  |  |  |  | 
| 252 | 0 |  |  |  |  |  | return b $value; | 
| 253 |  |  |  |  |  |  | }, | 
| 254 |  |  |  |  |  |  | content_for => sub { | 
| 255 | 0 |  |  | 0 |  |  | my ($self, $c, $name, $proto) = @_; | 
| 256 |  |  |  |  |  |  |  | 
| 257 | 0 |  | 0 |  |  |  | $name ||= 'main'; | 
| 258 | 0 | 0 |  |  |  |  | $c->stash->{'view.content'}->{$name} .= _block($proto) if $proto; | 
| 259 |  |  |  |  |  |  |  | 
| 260 | 0 |  |  |  |  |  | my $value = $c->stash->{'view.content'}->{$name}; | 
| 261 | 0 | 0 |  |  |  |  | $value = '' unless defined($value); | 
| 262 |  |  |  |  |  |  |  | 
| 263 | 0 |  |  |  |  |  | return b $value; | 
| 264 |  |  |  |  |  |  | }, | 
| 265 |  |  |  |  |  |  | stash => sub { | 
| 266 | 0 |  |  | 0 |  |  | my ($self, $c, $name, $proto) = @_; | 
| 267 |  |  |  |  |  |  |  | 
| 268 | 0 | 0 |  |  |  |  | $c->stash->{$name} = _$proto if $proto; | 
| 269 |  |  |  |  |  |  |  | 
| 270 | 0 |  |  |  |  |  | my $value = $c->stash->{$name}; | 
| 271 | 0 | 0 |  |  |  |  | $value = '' unless defined($value); | 
| 272 |  |  |  |  |  |  |  | 
| 273 | 0 |  |  |  |  |  | return b $value; | 
| 274 |  |  |  |  |  |  | }, | 
| 275 |  |  |  |  |  |  |  | 
| 276 | 0 |  |  |  |  |  | ); | 
| 277 |  |  |  |  |  |  | } | 
| 278 |  |  |  |  |  |  |  | 
| 279 | 0 | 0 |  | 0 |  |  | sub _block { ref $_[0] eq 'CODE' ? $_[0]() : $_[0] } | 
| 280 |  |  |  |  |  |  |  | 
| 281 |  |  |  |  |  |  | sub get_helpers { | 
| 282 | 0 |  |  | 0 | 0 |  | my ($self, $helper) = @_; | 
| 283 | 0 | 0 |  |  |  |  | my %helpers = ($self->default_helpers, %{ $self->helpers || +{} }); | 
|  | 0 |  |  |  |  |  |  | 
| 284 |  |  |  |  |  |  |  | 
| 285 | 0 | 0 |  |  |  |  | return $helpers{$helper} if defined $helper; | 
| 286 | 0 |  |  |  |  |  | return %helpers; | 
| 287 |  |  |  |  |  |  | } | 
| 288 |  |  |  |  |  |  |  | 
| 289 |  |  |  |  |  |  | 1; | 
| 290 |  |  |  |  |  |  |  | 
| 291 |  |  |  |  |  |  | =head1 NAME | 
| 292 |  |  |  |  |  |  |  | 
| 293 |  |  |  |  |  |  | Catalyst::View::MojoTemplate - Use Mojolicious Templates for your Catalyst View | 
| 294 |  |  |  |  |  |  |  | 
| 295 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 296 |  |  |  |  |  |  |  | 
| 297 |  |  |  |  |  |  | package Example::View::HTML; | 
| 298 |  |  |  |  |  |  |  | 
| 299 |  |  |  |  |  |  | use Moose; | 
| 300 |  |  |  |  |  |  | extends 'Catalyst::View::MojoTemplate'; | 
| 301 |  |  |  |  |  |  |  | 
| 302 |  |  |  |  |  |  | __PACKAGE__->config(helpers => +{ | 
| 303 |  |  |  |  |  |  | now => sub { | 
| 304 |  |  |  |  |  |  | my ($self, $c, @args) = @_; | 
| 305 |  |  |  |  |  |  | return localtime; | 
| 306 |  |  |  |  |  |  | }, | 
| 307 |  |  |  |  |  |  | }); | 
| 308 |  |  |  |  |  |  |  | 
| 309 |  |  |  |  |  |  | __PACKAGE__->meta->make_immutable; | 
| 310 |  |  |  |  |  |  |  | 
| 311 |  |  |  |  |  |  | Then called from a controller: | 
| 312 |  |  |  |  |  |  |  | 
| 313 |  |  |  |  |  |  | package Example::Controller::Root; | 
| 314 |  |  |  |  |  |  |  | 
| 315 |  |  |  |  |  |  | use Moose; | 
| 316 |  |  |  |  |  |  | use MooseX::MethodAttributes; | 
| 317 |  |  |  |  |  |  |  | 
| 318 |  |  |  |  |  |  | extends 'Catalyst::Controller'; | 
| 319 |  |  |  |  |  |  |  | 
| 320 |  |  |  |  |  |  | sub root :Chained(/) PathPart('') CaptureArgs(0) { } | 
| 321 |  |  |  |  |  |  |  | 
| 322 |  |  |  |  |  |  | sub home :Chained(root) PathPart('') Args(0) { | 
| 323 |  |  |  |  |  |  | my ($self, $c) = @_; | 
| 324 |  |  |  |  |  |  | $c->stash(status => $c->model('Status')); | 
| 325 |  |  |  |  |  |  | } | 
| 326 |  |  |  |  |  |  |  | 
| 327 |  |  |  |  |  |  | sub profile :Chained(root) PathPart(profile) Args(0) { | 
| 328 |  |  |  |  |  |  | my ($self, $c) = @_; | 
| 329 |  |  |  |  |  |  | $c->view('HTML' => 'profile.ep', +{ | 
| 330 |  |  |  |  |  |  | me => $c->user, | 
| 331 |  |  |  |  |  |  | }); | 
| 332 |  |  |  |  |  |  | } | 
| 333 |  |  |  |  |  |  |  | 
| 334 |  |  |  |  |  |  | sub end : ActionClass('RenderView') {} | 
| 335 |  |  |  |  |  |  |  | 
| 336 |  |  |  |  |  |  | __PACKAGE__->config(namespace=>''); | 
| 337 |  |  |  |  |  |  | __PACKAGE__->meta->make_immutable; | 
| 338 |  |  |  |  |  |  |  | 
| 339 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 340 |  |  |  |  |  |  |  | 
| 341 |  |  |  |  |  |  | Use L<Mojo::Template> as your L<Catalyst> view.  While ths might strike some as | 
| 342 |  |  |  |  |  |  | odd, if you are using both L<Catalyst> and L<Mojolicious> you might like the option to | 
| 343 |  |  |  |  |  |  | share the template code and expertise.  You might also just want to use a Perlish | 
| 344 |  |  |  |  |  |  | template system rather than a dedicated mini language (such as L<Xslate>) since you | 
| 345 |  |  |  |  |  |  | already know Perl and don't have the time or desire to become an expert in another | 
| 346 |  |  |  |  |  |  | system. | 
| 347 |  |  |  |  |  |  |  | 
| 348 |  |  |  |  |  |  | This works just like many other L<Catalyst> views.  It will load and render a template | 
| 349 |  |  |  |  |  |  | based on either the current action private name or a stash variable called C<template>. | 
| 350 |  |  |  |  |  |  | It will use the stash to populate variables in the template.  It also offers an alternative | 
| 351 |  |  |  |  |  |  | interface that lets you set a template in the actual call to the view, and pass variables. | 
| 352 |  |  |  |  |  |  |  | 
| 353 |  |  |  |  |  |  | By default we look for templates in C<$APPHOME/root> which is the standard default location | 
| 354 |  |  |  |  |  |  | for L<Catalyst> templates. | 
| 355 |  |  |  |  |  |  |  | 
| 356 |  |  |  |  |  |  | Also like a lot of other template systems you can define helper methods which are injected | 
| 357 |  |  |  |  |  |  | into your template and can take parameters (including text blocks). | 
| 358 |  |  |  |  |  |  |  | 
| 359 |  |  |  |  |  |  | The intention here is to try and make this as similar to how L<Mojo::Template> is used | 
| 360 |  |  |  |  |  |  | in L<Mojolicious> so that people that need to work in both frameworks could in theory use | 
| 361 |  |  |  |  |  |  | this view in L<Catalyst> and be able to switch between the two with less trouble (at least | 
| 362 |  |  |  |  |  |  | for doing view development).  To that end we've added some default helpers that hopefully | 
| 363 |  |  |  |  |  |  | work the same way as they do in L<Mojolicious>.  These are helpers for template layouts | 
| 364 |  |  |  |  |  |  | and includes as well as for sharing data between them.  We've also added a 'wrapper' | 
| 365 |  |  |  |  |  |  | helper because the author has found that feature of Template::Toolkit (L<Template>) to be so | 
| 366 |  |  |  |  |  |  | useful he would have a hard time living without it.  We did not include the L<Mojolicious> | 
| 367 |  |  |  |  |  |  | tag helpers but there's no reason those could not be added as an add on role at a later | 
| 368 |  |  |  |  |  |  | date should people take an interest in this thing. | 
| 369 |  |  |  |  |  |  |  | 
| 370 |  |  |  |  |  |  | There's an example of sorts in the C<example> directory of the module distribution.  You can | 
| 371 |  |  |  |  |  |  | start the example server with the following command: | 
| 372 |  |  |  |  |  |  |  | 
| 373 |  |  |  |  |  |  | perl -Ilib -I example/lib/ example/lib/Example/Server.pm | 
| 374 |  |  |  |  |  |  |  | 
| 375 |  |  |  |  |  |  | B<NOTE> Warning, this is an early access module and I reserve the right to make breaking | 
| 376 |  |  |  |  |  |  | changes if it turns out I totally confused how L<Mojolicious> works.  There's actually | 
| 377 |  |  |  |  |  |  | not a ton of code here since its just a thin wrapper over L<Mojo::Template> so you should | 
| 378 |  |  |  |  |  |  | be confortable looking that over and coping if there's issues. | 
| 379 |  |  |  |  |  |  |  | 
| 380 |  |  |  |  |  |  | =head1 CONFIGURATION | 
| 381 |  |  |  |  |  |  |  | 
| 382 |  |  |  |  |  |  | This view defines the following configuration attributes.  For the most part these | 
| 383 |  |  |  |  |  |  | are just pass thru to the underlying L<Mojo::Template>.  You would do well to review | 
| 384 |  |  |  |  |  |  | those docs if you are not familiar. | 
| 385 |  |  |  |  |  |  |  | 
| 386 |  |  |  |  |  |  | =head2 auto_escape | 
| 387 |  |  |  |  |  |  |  | 
| 388 |  |  |  |  |  |  | =head2 append | 
| 389 |  |  |  |  |  |  |  | 
| 390 |  |  |  |  |  |  | =head2 prepend | 
| 391 |  |  |  |  |  |  |  | 
| 392 |  |  |  |  |  |  | =head2 capture_start | 
| 393 |  |  |  |  |  |  |  | 
| 394 |  |  |  |  |  |  | =head2 capture_end | 
| 395 |  |  |  |  |  |  |  | 
| 396 |  |  |  |  |  |  | =head2 encoding | 
| 397 |  |  |  |  |  |  |  | 
| 398 |  |  |  |  |  |  | =head2 comment_mark | 
| 399 |  |  |  |  |  |  |  | 
| 400 |  |  |  |  |  |  | =head2 escape_mark | 
| 401 |  |  |  |  |  |  |  | 
| 402 |  |  |  |  |  |  | =head2 expression_mark | 
| 403 |  |  |  |  |  |  |  | 
| 404 |  |  |  |  |  |  | =head2 line_start | 
| 405 |  |  |  |  |  |  |  | 
| 406 |  |  |  |  |  |  | =head2 replace_mark | 
| 407 |  |  |  |  |  |  |  | 
| 408 |  |  |  |  |  |  | These are just pass thru to L<Mojo::Template>.  See that for details | 
| 409 |  |  |  |  |  |  |  | 
| 410 |  |  |  |  |  |  | =head2 content_type | 
| 411 |  |  |  |  |  |  |  | 
| 412 |  |  |  |  |  |  | The HTTP content-type that is set in the response unless it is already set. | 
| 413 |  |  |  |  |  |  |  | 
| 414 |  |  |  |  |  |  | =head2 helpers | 
| 415 |  |  |  |  |  |  |  | 
| 416 |  |  |  |  |  |  | A hashref of helper functions.  For example: | 
| 417 |  |  |  |  |  |  |  | 
| 418 |  |  |  |  |  |  | __PACKAGE__->config(helpers=>+{ | 
| 419 |  |  |  |  |  |  | now => sub { | 
| 420 |  |  |  |  |  |  | my ($self, $c, @args) = @_; | 
| 421 |  |  |  |  |  |  | return localtime; | 
| 422 |  |  |  |  |  |  | }, | 
| 423 |  |  |  |  |  |  | ); | 
| 424 |  |  |  |  |  |  |  | 
| 425 |  |  |  |  |  |  | All arguments are passed from the template.  If you are building a block | 
| 426 |  |  |  |  |  |  | helper then the last argument will be a coderef to the enclosed block.  You | 
| 427 |  |  |  |  |  |  | may wish to view the source code around the default helpers for more examples of | 
| 428 |  |  |  |  |  |  | this. | 
| 429 |  |  |  |  |  |  |  | 
| 430 |  |  |  |  |  |  | =head2 layout | 
| 431 |  |  |  |  |  |  |  | 
| 432 |  |  |  |  |  |  | Set a default layout which will be used if none are defined.  Optional. | 
| 433 |  |  |  |  |  |  |  | 
| 434 |  |  |  |  |  |  | =head1 HELPERS | 
| 435 |  |  |  |  |  |  |  | 
| 436 |  |  |  |  |  |  | The following is a list of the default helpers. | 
| 437 |  |  |  |  |  |  |  | 
| 438 |  |  |  |  |  |  | =head2 layout | 
| 439 |  |  |  |  |  |  |  | 
| 440 |  |  |  |  |  |  | % layout "layout.ep", title => "Hello"; | 
| 441 |  |  |  |  |  |  | <h1>The Awesome new Content</h1> | 
| 442 |  |  |  |  |  |  | <p>You are doomed to discover you can never recover from the narcoleptic | 
| 443 |  |  |  |  |  |  | country in which you once stood, where the fires alway burning but there's | 
| 444 |  |  |  |  |  |  | never enough wood</p> | 
| 445 |  |  |  |  |  |  |  | 
| 446 |  |  |  |  |  |  | C<layout> sets a global template wrapper around your content.  Arguments passed | 
| 447 |  |  |  |  |  |  | get merged into the stash and are available to the layout.  The output of your | 
| 448 |  |  |  |  |  |  | template is placed into the 'main' content block.  See L<Mojolicious::Plugin::DefaultHelpers/layout> | 
| 449 |  |  |  |  |  |  | for more. | 
| 450 |  |  |  |  |  |  |  | 
| 451 |  |  |  |  |  |  | =head2 include | 
| 452 |  |  |  |  |  |  |  | 
| 453 |  |  |  |  |  |  | See L<Mojolicious::Plugin::DefaultHelpers/include> | 
| 454 |  |  |  |  |  |  |  | 
| 455 |  |  |  |  |  |  | =head2 content | 
| 456 |  |  |  |  |  |  |  | 
| 457 |  |  |  |  |  |  | See L<Mojolicious::Plugin::DefaultHelpers/content> | 
| 458 |  |  |  |  |  |  |  | 
| 459 |  |  |  |  |  |  | =head2 wrapper | 
| 460 |  |  |  |  |  |  |  | 
| 461 |  |  |  |  |  |  | Similar to the C<layout> helper, the C<wrapper> helper wraps the contained content | 
| 462 |  |  |  |  |  |  | inside a another template.  However unlike C<layout> you can have more than one | 
| 463 |  |  |  |  |  |  | C<wrapper> in your template.  Example: | 
| 464 |  |  |  |  |  |  |  | 
| 465 |  |  |  |  |  |  | %= wrapper "wrapper.ep", header => "The Story Begins...", begin | 
| 466 |  |  |  |  |  |  | <p> | 
| 467 |  |  |  |  |  |  | The story begins like many others; something interesting happend to someone | 
| 468 |  |  |  |  |  |  | while sone other sort of interesting thing was happening all over.  And then | 
| 469 |  |  |  |  |  |  | there wre monkeys.  Monkeys are great, you ever get stuck writing a story I | 
| 470 |  |  |  |  |  |  | really recommend adding monkeys since they help the more boring story. | 
| 471 |  |  |  |  |  |  | </p> | 
| 472 |  |  |  |  |  |  | %end | 
| 473 |  |  |  |  |  |  |  | 
| 474 |  |  |  |  |  |  | This works similar to the WRAPPER directive in Template::Toolkit, if you are familiar | 
| 475 |  |  |  |  |  |  | with that system. | 
| 476 |  |  |  |  |  |  |  | 
| 477 |  |  |  |  |  |  | =head1 AUTHOR | 
| 478 |  |  |  |  |  |  |  | 
| 479 |  |  |  |  |  |  | jnap - John Napiorkowski (cpan:JJNAPIORK)  L<email:jjnapiork@cpan.org> | 
| 480 |  |  |  |  |  |  | With tremendous thanks to SRI and the Mojolicious team! | 
| 481 |  |  |  |  |  |  |  | 
| 482 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 483 |  |  |  |  |  |  |  | 
| 484 |  |  |  |  |  |  | L<Catalyst>, L<Catalyst::View>, L<Mojolicious> | 
| 485 |  |  |  |  |  |  |  | 
| 486 |  |  |  |  |  |  | =head1 COPYRIGHT & LICENSE | 
| 487 |  |  |  |  |  |  |  | 
| 488 |  |  |  |  |  |  | Copyright 2020, John Napiorkowski L<email:jjnapiork@cpan.org> | 
| 489 |  |  |  |  |  |  |  | 
| 490 |  |  |  |  |  |  | This library is free software; you can redistribute it and/or modify it under | 
| 491 |  |  |  |  |  |  | the same terms as Perl itself. | 
| 492 |  |  |  |  |  |  |  | 
| 493 |  |  |  |  |  |  | =cut |