File Coverage

blib/lib/Yukki/Web/View.pm
Criterion Covered Total %
statement 35 98 35.7
branch 0 16 0.0
condition 0 20 0.0
subroutine 12 21 57.1
pod 6 6 100.0
total 53 161 32.9


line stmt bran cond sub pod time code
1             package Yukki::Web::View;
2             $Yukki::Web::View::VERSION = '0.991_002'; # TRIAL
3              
4 5     5   62 $Yukki::Web::View::VERSION = '0.991002';use v5.24;
  5         19  
5 5     5   31 use utf8;
  5         12  
  5         30  
6 5     5   115 use Moo;
  5         10  
  5         24  
7              
8 5     5   3395 use Type::Params qw( validate );
  5         121168  
  5         62  
9 5     5   1257 use Scalar::Util qw( blessed reftype );
  5         17  
  5         354  
10 5     5   1947 use Spreadsheet::Engine;
  5         160647  
  5         248  
11 5     5   3510 use Template::Pure;
  5         298565  
  5         270  
12 5     5   2825 use Text::MultiMarkdown;
  5         156161  
  5         418  
13 5     5   619 use Try::Tiny;
  5         1809  
  5         342  
14 5     5   488 use Type::Utils;
  5         6856  
  5         116  
15 5     5   8068 use Types::Standard qw( Dict Str ArrayRef HashRef slurpy );
  5         14  
  5         61  
16              
17 5     5   6344 use namespace::clean;
  5         10915  
  5         49  
18              
19             # ABSTRACT: base class for Yukki::Web views
20              
21              
22             has app => (
23             is => 'ro',
24             isa => class_type('Yukki::Web'),
25             required => 1,
26             weak_ref => 1,
27             handles => 'Yukki::Role::App',
28             );
29              
30              
31             has markdown => (
32             is => 'ro',
33             isa => class_type('Text::MultiMarkdown'),
34             required => 1,
35             lazy => 1,
36             builder => '_build_markdown',
37             handles => {
38             'format_markdown' => 'markdown',
39             },
40             );
41              
42             sub _build_markdown {
43 0     0     Text::MultiMarkdown->new(
44             markdown_in_html_blocks => 1,
45             heading_ids => 0,
46             );
47             }
48              
49              
50             has messages_template => (
51             is => 'ro',
52             isa => class_type('Template::Pure'),
53             lazy => 1,
54             builder => '_build_messages_template',
55             );
56              
57             sub _build_messages_template {
58 0     0     my $self = shift;
59 0           return $self->prepare_template(
60             template => 'messages.html',
61             directives => [
62             '.error' => {
63             'error<-errors' => [
64             '.' => 'error',
65             ],
66             },
67             '.warning' => {
68             'warning<-warnings' => [
69             '.' => 'warning',
70             ],
71             },
72             '.info' => {
73             'one_info<-info' => [
74             '.' => 'one_info',
75             ],
76             },
77             ],
78             );
79             }
80              
81             has _page_templates => (
82             is => 'ro',
83             isa => HashRef,
84             required => 1,
85             default => sub { +{} },
86             );
87              
88              
89             has links_template => (
90             is => 'ro',
91             isa => class_type('Template::Pure'),
92             lazy => 1,
93             builder => '_build_links_template',
94             );
95              
96             sub _build_links_template {
97 0     0     my $self = shift;
98 0           $self->prepare_template(
99             template => 'links.html',
100             directives => [
101             '.links' => {
102             'link<-links' => [
103             'a' => 'link.label',
104             'a@href' => 'link.href',
105             ],
106             },
107             ],
108             );
109             }
110              
111              
112             sub page_template {
113 0     0 1   my ($self, $which) = @_;
114              
115             return $self->_page_templates->{ $which }
116 0 0         if $self->_page_templates->{ $which };
117              
118 0   0       my $view = $which // 'default';
119 0   0       my $view_args = $self->app->settings->page_views->{ $view }
120             // { template => 'shell.html' };
121 0   0       $view_args->{directives} //= [];
122              
123             my %menu_vars = map {
124 0           my $menu_name = $_;
125 0           "#nav-$menu_name .navigation" => {
126             "menu_item<-$menu_name" => [
127             'a' => 'menu_item.label',
128             'a@href' => 'menu_item.href',
129             ],
130             },
131 0           } @{ $self->app->settings->menu_names };
  0            
132              
133             return $self->_page_templates->{ $which } = $self->prepare_template(
134             template => $view_args->{template},
135             directives => [
136             $view_args->{directives}->@*,
137 0           'head script.local' => {
138             'script<-scripts' => [
139             '@src' => 'script',
140             ],
141             },
142             'head link.local' => {
143             'link<-links' => [
144             '@href' => 'link',
145             ],
146             },
147             '#messages' => 'messages | encoded_string',
148             'title' => 'main_title',
149             '.masthead-title' => 'title',
150             %menu_vars,
151             '#breadcrumb li' => {
152             'crumb<-breadcrumb' => [
153             'a' => 'crumb.label',
154             'a@href' => 'crumb.href',
155             ],
156             },
157             '#content' => 'content | encoded_string',
158             ],
159             );
160             }
161              
162              
163             sub prepare_template {
164 0     0 1   my ($self, $opt)
165             = validate(\@_, class_type(__PACKAGE__),
166             slurpy Dict[
167             template => Str,
168             directives => ArrayRef,
169             ]);
170 0           my ($template, $directives) = @{$opt}{qw( template directives )};
  0            
171              
172 0           my $template_content =
173             $self->app->locate_dir('template_path', $template)->slurp;
174              
175 0           return Template::Pure->new(
176             template => $template_content,
177             directives => $directives,
178             );
179             }
180              
181              
182             sub render_page {
183 0     0 1   my ($self, $opt)
184             = validate(\@_, class_type(__PACKAGE__),
185             slurpy Dict[
186             template => class_type('Template::Pure'),
187             context => class_type('Yukki::Web::Context'),
188             vars => HashRef,
189             ]);
190 0           my ($template, $ctx, $vars) = @{$opt}{qw( template context vars )};
  0            
191 0   0       $vars //= {};
192              
193 0 0         my $messages = $self->render(
    0          
    0          
194             template => $self->messages_template,
195             context => $ctx,
196             vars => {
197             errors => $ctx->has_errors ? [ $ctx->list_errors ] : undef,
198             warnings => $ctx->has_warnings ? [ $ctx->list_warnings ] : undef,
199             info => $ctx->has_info ? [ $ctx->list_info ] : undef,
200             },
201             );
202              
203 0           my ($main_title, $title);
204 0 0         if ($ctx->response->has_page_title) {
205 0           $title = $ctx->response->page_title;
206 0           $main_title = $ctx->response->page_title . ' - Yukki';
207             }
208             else {
209 0           $title = $main_title = 'Yukki';
210             }
211              
212             my %menu_vars = map {
213 0           $_ => $self->available_menu_items($ctx, $_)
214 0           } @{ $self->app->settings->menu_names };
  0            
215              
216 0           my @scripts = $self->app->settings->all_scripts;
217 0           my @styles = $self->app->settings->all_styles;
218              
219 0   0       my $view = $ctx->request->parameters->{view} // 'default';
220              
221 0   0       $vars->{'head script.local'} //= [];
222 0   0       $vars->{'head link.local'} //= [];
223              
224             return $self->render(
225             template => $self->page_template($view),
226             context => $ctx,
227             vars => {
228             $vars->%*,
229             scripts => [
230 0           map { $ctx->rebase_url($_) }
231             @scripts,
232             $vars->{'head script.local'}->@*,
233             ],
234             links => [
235 0           map { $ctx->rebase_url($_) }
236             @styles,
237             $vars->{'head link.local'}->@*,
238             ],
239             'messages' => $messages,
240             'main_title' => $main_title,
241             'title' => $title,
242             %menu_vars,
243             'breadcrumb' => $ctx->response->has_breadcrumb ? [
244             map {
245 0 0         +{
246             %$_,
247 0           href => $ctx->rebase_url($_->{href}),
248             }
249             } $ctx->response->breadcrumb_links
250             ] : undef,
251             'content' => $self->render(
252             template => $template,
253             context => $ctx,
254             vars => $vars,
255             ),
256             },
257             );
258             }
259              
260              
261             sub available_menu_items {
262 0     0 1   my ($self, $ctx, $name) = @_;
263              
264             my @items = map {
265             +{
266             %$_,
267 0           href => $ctx->rebase_url($_->{href}),
268             },
269             } grep {
270 0           my $url = $_->{href}; $url =~ s{\?.*$}{};
  0            
  0            
271              
272 0           my $match = $self->app->router->match($url);
273 0 0         return unless $match;
274 0           my $access_level_needed = $match->access_level;
275             $self->check_access(
276             user => $ctx->session->{user},
277             repository => $match->mapping->{repository} // '-',
278 0   0       special => $match->mapping->{special} // '-',
      0        
279             needs => $access_level_needed,
280             );
281             } $ctx->response->navigation_menu($name);
282              
283 0 0         return @items ? \@items : undef;
284             }
285              
286              
287             sub render_links {
288 0     0 1   my ($self, $opt)
289             = validate(\@_, class_type(__PACKAGE__),
290             slurpy Dict[
291             context => class_type('Yukki::Web::Context'),
292             links => ArrayRef[HashRef],
293             ]);
294 0           my ($ctx, $links) = @{$opt}{qw( context links )};
  0            
295              
296             return $self->render(
297             template => $self->links_template,
298             context => $ctx,
299             vars => {
300             links => [ map {
301 0           +{
302             label => $_->{label},
303 0           href => $ctx->rebase_url($_->{href}),
304             }
305             } @$links ],
306             },
307             );
308             }
309              
310              
311             sub render {
312 0     0 1   my ($self, $opt)
313             = validate(\@_, class_type(__PACKAGE__),
314             slurpy Dict[
315             template => class_type('Template::Pure'),
316             context => class_type('Yukki::Web::Context'),
317             vars => HashRef,
318             ]);
319 0           my ($template, $ctx, $vars) = @{$opt}{qw( template context vars )};
  0            
320 0   0       $vars //= {};
321              
322 0           my %vars = (
323             %$vars,
324             ctx => $ctx,
325             view => $self,
326             );
327              
328 0           return $template->render($vars);
329             }
330              
331             1;
332              
333             __END__
334              
335             =pod
336              
337             =encoding UTF-8
338              
339             =head1 NAME
340              
341             Yukki::Web::View - base class for Yukki::Web views
342              
343             =head1 VERSION
344              
345             version 0.991_002
346              
347             =head1 DESCRIPTION
348              
349             This is the base class for all L<Yukki::Web> views.
350              
351             =head1 ATTRIBUTES
352              
353             =head2 app
354              
355             This is the L<Yukki::Web> singleton.
356              
357             =head2 markdown
358              
359             This is the L<Text::MultiMarkdown> object for rendering L</yukkitext>. Do not
360             use.
361              
362             Provides a C<format_markdown> method delegated to C<markdown>. Do not use.
363              
364             =head2 messages_template
365              
366             This is the template used to render info, warning, and error messages to the page.
367              
368             =head2 links_template
369              
370             This is the template object used to render links.
371              
372             =head1 METHODS
373              
374             =head2 page_template
375              
376             my $template = $self->page_template('default');
377              
378             Returns the template used to render pages for the given style name.
379              
380             =head2 prepare_template
381              
382             my $template = $self->prepare_template({
383             template => 'foo.html',
384             directives => { ... },
385             });
386              
387             This prepares a template for later rendering.
388              
389             The C<template> is the name of the template file to use.
390              
391             The C<directives> are the L<Template::Pure> directives to apply data given at render time to modify the template to create the output.
392              
393             =head2 render_page
394              
395             my $document = $self->render_page({
396             template => 'foo.html',
397             context => $ctx,
398             vars => { ... },
399             });
400              
401             This renders the given template and places it into the content section of the
402             F<shell.html> template.
403              
404             The C<context> is used to render parts of the shell template.
405              
406             The C<vars> are processed against the given template with L<Template::Pure>.
407              
408             =head2 available_menu_items
409              
410             my @items = $self->available_menu_items($ctx, 'menu_name');
411              
412             Retrieves the navigation menu from the L<Yukki::Web::Response> and purges any links that the current user does not have access to.
413              
414             =head2 render_links
415              
416             my $document = $self->render_links($ctx, \@navigation_links);
417              
418             This renders a set of links using the F<links.html> template.
419              
420             =head2 render
421              
422             my $document = $self->render({
423             template => $template,
424             vars => { ... },
425             });
426              
427             This renders the given L<Template::Pure>. The C<vars> are
428             used as the ones passed to the C<process> method.
429              
430             =head1 AUTHOR
431              
432             Andrew Sterling Hanenkamp <hanenkamp@cpan.org>
433              
434             =head1 COPYRIGHT AND LICENSE
435              
436             This software is copyright (c) 2017 by Qubling Software LLC.
437              
438             This is free software; you can redistribute it and/or modify it under
439             the same terms as the Perl 5 programming language system itself.
440              
441             =cut