File Coverage

blib/lib/Minima/View/HTML.pm
Criterion Covered Total %
statement 23 23 100.0
branch n/a
condition n/a
subroutine 8 8 100.0
pod n/a
total 31 31 100.0


line stmt bran cond sub pod time code
1 3     3   1286 use v5.40;
  3         14  
2 3     3   18 use experimental 'class';
  3         5  
  3         32  
3              
4 1     1   480 class Minima::View::HTML :isa(Minima::View);
  1         4  
  1         27  
5              
6 3     3   563 use Carp;
  3         7  
  3         249  
7 3     3   20 use Path::Tiny;
  3         6  
  3         178  
8 3     3   1241 use Template;
  3         42936  
  3         134  
9 3     3   20 use Template::Constants qw/ :debug /;
  3         5  
  3         578  
10 3     3   23 use utf8;
  3         7  
  3         25  
11              
12             field $app :param;
13             field @include;
14             field $template;
15             field @before_template;
16             field @after_template;
17             field $default_data = {};
18              
19             field %settings = (
20             block_indexing => 1, # block robots with a
21             name_as_class => 1, # include template name in @classes
22             theme_color => '', # hex color for the
23             );
24              
25             field %content = (
26             title => undef,
27             description => undef,
28             header_scripts => [], # scripts to be loaded in
29             header_css => [], # CSS to be loaded in
30             body_open => [], # used right after the opening of
31             body_close => [], # used right before the closing of
32             scripts => [], # scripts to be embedded directly in
33             classes => [], # classes added to
or
34             );
35              
36             ADJUST {
37             my $config = $app->config;
38              
39             $content{title} = $config->{default_title} // '';
40              
41             $settings{block_indexing} = $config->{block_indexing} // 1;
42             $settings{name_as_class} = $config->{name_as_class} // 1;
43             $settings{theme_color} = $config->{theme_color} // '';
44              
45             if (exists $config->{templates_dir}) {
46             if (ref $config->{templates_dir} eq ref []) {
47             $self->add_directory($_)
48             for reverse @{ $config->{templates_dir} };
49             }
50             } else {
51             $self->add_directory('js');
52             $self->add_directory('templates');
53             }
54             }
55              
56             method add_directory ($d) { unshift @include, $app->path($d) }
57             method clear_directories { @include = () }
58             method set_template ($t) { $template = $self->_ext($t) }
59             method add_before_template ($p) { push @before_template, $self->_ext($p) }
60             method add_after_template ($p) { push @after_template, $self->_ext($p) }
61             method set_default_data ($d) { $default_data = $d }
62              
63             method set_block_indexing ($n = 1) { $settings{block_indexing} = $n }
64             method set_name_as_class ($n = 1) { $settings{name_as_class} = $n }
65             method set_theme_color ($c) { $settings{theme_color} = $c }
66              
67             method set_title ($t, $d = undef)
68             {
69             $content{title} = $t;
70             $content{description} = $d;
71             }
72              
73             method set_compound_title ($t, $d = undef)
74             {
75             $self->set_title(
76             ( $content{title} ? "$content{title} • $t" : $t ),
77             $d
78             );
79             }
80              
81             method set_description ($d) { $content{description} = $d }
82             method add_header_script ($s) { push @{$content{header_scripts}}, $s }
83             method add_header_css ($c) { push @{$content{header_css}}, $c }
84             method add_script ($s) { push @{$content{scripts}}, $s }
85             method add_class ($c) { push @{$content{classes}}, $c }
86              
87             method add_body_open ($p)
88             {
89             push @{$content{body_open}}, $self->_ext($p)
90             }
91              
92             method add_body_close ($p)
93             {
94             push @{$content{body_close}}, $self->_ext($p)
95             }
96              
97             method prepare_response ($response)
98             {
99             $response->content_type('text/html; charset=utf-8');
100             }
101              
102             method render ($data = {})
103             {
104             croak "No template set." unless $template;
105              
106             # Merge default data
107             $data = { %$default_data, %$data };
108              
109             # Build vars to send to template
110             my %vars = ( %content, settings => \%settings );
111             $data->{view} = \%vars;
112              
113             # Format CSS classes
114             my @classes = @{ $content{classes} };
115             if ($settings{name_as_class}) {
116             my $clean_name = $template;
117             $clean_name =~ s/\.\w+$//;
118             $clean_name =~ tr/./-/;
119             push @classes, $clean_name;
120             }
121             $vars{classes} = "@classes";
122              
123             # If any var is undef, replace with empty string
124             $vars{$_} //= '' for keys %vars;
125              
126             # Setup Template Toolkit:
127             # Create a default and overwrite with user configuration.
128             my %tt_default = (
129             INCLUDE_PATH => \@include,
130             OUTLINE_TAG => '%%',
131             ANYCASE => 1,
132             ENCODING => 'utf8',
133             );
134             my $tt_app_config = $app->config->{tt} // {};
135             my %tt_config = ( %tt_default, %$tt_app_config );
136             my $tt = Template->new(\%tt_config);
137              
138             # Render
139             my ( $body, $r );
140              
141             for my $t (@before_template, $template, @after_template) {
142             $r = $tt->process($t, $data, \$body);
143             croak "Failed to load template `$t` (include path: `@include`): ",
144             $tt->error, "\n" unless $r;
145             }
146              
147             utf8::encode($body);
148             $body;
149             }
150              
151             method _ext ($file)
152             {
153             my $ext = $app->config->{template_ext} // 'ht';
154             $file = "$file.$ext" unless $file =~ /\.\w+$/;
155             $file;
156             }
157              
158             __END__