File Coverage

blib/lib/Tags/HTML/Footer.pm
Criterion Covered Total %
statement 65 65 100.0
branch 26 26 100.0
condition 6 6 100.0
subroutine 16 16 100.0
pod 1 1 100.0
total 114 114 100.0


line stmt bran cond sub pod time code
1             package Tags::HTML::Footer;
2              
3 7     7   607174 use base qw(Tags::HTML);
  7         21  
  7         4484  
4 7     7   61054 use strict;
  7         16  
  7         183  
5 7     7   36 use warnings;
  7         61  
  7         2649  
6              
7 7     7   68 use Class::Utils qw(set_params split_params);
  7         125  
  7         439  
8 7     7   47 use Error::Pure qw(err);
  7         14  
  7         480  
9 7     7   4517 use Mo::utils::Hash 0.02 qw(check_hash check_hash_keys);
  7         6283  
  7         189  
10 7     7   6521 use Mo::utils::Language 0.05 qw(check_language_639_2);
  7         2057008  
  7         212  
11 7     7   581 use Readonly;
  7         23  
  7         386  
12 7     7   47 use Scalar::Util qw(blessed);
  7         14  
  7         396  
13 7     7   3828 use Unicode::UTF8 qw(decode_utf8);
  7         5427  
  7         6629  
14              
15             Readonly::Scalar our $DEFAULT_HEIGHT => '40px';
16              
17             our $VERSION = 0.04;
18              
19             # Constructor.
20             sub new {
21 29     29 1 1868927 my ($class, @params) = @_;
22              
23             # Create object.
24 29         182 my ($object_params_ar, $other_params_ar) = split_params(
25             ['lang', 'text'], @params);
26 29         735 my $self = $class->SUPER::new(@{$other_params_ar});
  29         177  
27              
28             # Language.
29 26         1007 $self->{'lang'} = 'eng';
30              
31             # Language texts.
32 26         164 $self->{'text'} = {
33             'eng' => {
34             'version' => 'Version',
35             },
36             };
37              
38             # Process params.
39 26         62 set_params($self, @{$object_params_ar});
  26         83  
40              
41             # Check lang.
42 26         242 check_language_639_2($self, 'lang');
43              
44             # Check text.
45 25         261966 check_hash($self, 'text');
46 23         453 check_hash_keys($self, 'text', $self->{'lang'}, 'version');
47              
48             # Object.
49 20         1141 return $self;
50             }
51              
52             sub _cleanup {
53 1     1   26 my $self = shift;
54              
55 1         4 delete $self->{'_footer'};
56              
57 1         3 return;
58             }
59              
60             sub _init {
61 13     13   13913 my ($self, $footer) = @_;
62              
63             # Check a.
64 13 100 100     218 if (! defined $footer
      100        
65             || ! blessed($footer)
66             || ! $footer->isa('Data::HTML::Footer')) {
67              
68 3         102 err "Footer object must be a 'Data::HTML::Footer' instance.";
69             }
70              
71 10         32 $self->{'_footer'} = $footer;
72              
73 10         34 return;
74             }
75              
76             # Process 'Tags'.
77             sub _process {
78 8     8   122 my $self = shift;
79              
80 8 100       35 if (! exists $self->{'_footer'}) {
81 1         3 return;
82             }
83              
84             $self->{'tags'}->put(
85             ['b', 'footer'],
86              
87             defined $self->{'_footer'}->version ? (
88             ['b', 'span'],
89             ['a', 'class', 'version'],
90             defined $self->{'_footer'}->version_url ? (
91             ['b', 'a'],
92             ['a', 'href', $self->{'_footer'}->version_url],
93             ) : (),
94             ['d', $self->_text('version').': '.$self->{'_footer'}->version],
95             defined $self->{'_footer'}->version_url ? (
96             ['e', 'a'],
97             ) : (),
98             ['e', 'span'],
99             ) : (),
100              
101             defined $self->{'_footer'}->copyright_years ? (
102             defined $self->{'_footer'}->version ? ['d', ', '] : (),
103             ['d', decode_utf8('©').' '.$self->{'_footer'}->copyright_years],
104             defined $self->{'_footer'}->author ? ['d', ' '] : (),
105             ) : (),
106              
107             defined $self->{'_footer'}->author ? (
108             ['b', 'span'],
109             ['a', 'class', 'author'],
110             defined $self->{'_footer'}->author_url ? (
111             ['b', 'a'],
112             ['a', 'href', $self->{'_footer'}->author_url],
113             ) : (),
114             ['d', $self->{'_footer'}->author],
115 7 100       59 defined $self->{'_footer'}->author_url ? (
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
116             ['e', 'a'],
117             ) : (),
118             ['e', 'span'],
119             ) : (),
120              
121             ['e', 'footer'],
122             );
123              
124 7         1986 return;
125             }
126              
127             sub _process_css {
128 3     3   71 my $self = shift;
129              
130 3 100       17 if (! exists $self->{'_footer'}) {
131 1         4 return;
132             }
133              
134 2         12 my $height = $self->{'_footer'}->height;
135 2 100       27 if (! defined $height) {
136 1         3 $height = $DEFAULT_HEIGHT;
137             }
138 2         92 $self->{'css'}->put(
139             ['s', '#main'],
140             ['d', 'padding-bottom', $height],
141             ['e'],
142              
143             ['s', 'footer'],
144             ['d', 'text-align', 'center'],
145             ['d', 'padding', '10px 0'],
146             ['d', 'background-color', '#f3f3f3'],
147             ['d', 'color', '#333'],
148             ['d', 'position', 'fixed'],
149             ['d', 'bottom', 0],
150             ['d', 'width', '100%'],
151             ['d', 'height', $height],
152             ['d', 'font-family', 'Arial, Helvetica, sans-serif'],
153             ['e'],
154             );
155              
156 2         1014 return;
157             }
158              
159             sub _text {
160 3     3   108 my ($self, $key) = @_;
161              
162 3         17 return $self->{'text'}->{$self->{'lang'}}->{$key};
163             }
164              
165             1;
166              
167             __END__
168              
169             =pod
170              
171             =encoding utf8
172              
173             =head1 NAME
174              
175             Tags::HTML::Footer - Tags helper for HTML footer.
176              
177             =head1 SYNOPSIS
178              
179             use Tags::HTML::Footer;
180              
181             my $obj = Tags::HTML::Footer->new(%params);
182             $obj->cleanup;
183             $obj->init($footer);
184             $obj->prepare;
185             $obj->process;
186             $obj->process_css;
187              
188             =head1 METHODS
189              
190             =head2 C<new>
191              
192             my $obj = Tags::HTML::Footer->new(%params);
193              
194             Constructor.
195              
196             =over 8
197              
198             =item * C<css>
199              
200             L<CSS::Struct::Output> object for L<process_css> processing.
201              
202             Default value is undef.
203              
204             =item * C<lang>
205              
206             Language in ISO 639-2 code.
207              
208             Default value is 'eng'.
209              
210             =item * C<tags>
211              
212             L<Tags::Output> object.
213              
214             Default value is undef.
215              
216             =item * C<text>
217              
218             Hash reference with keys defined language in ISO 639-2 code and value with hash
219             reference with texts.
220              
221             Required key is 'version' only.
222              
223             Default value is:
224              
225             {
226             'eng' => {
227             'version' => 'Version',
228             },
229             }
230              
231             =back
232              
233             =head2 C<cleanup>
234              
235             $obj->cleanup;
236              
237             Process cleanup after page run.
238              
239             In this case cleanup internal representation of a set by L<init>.
240              
241             Returns undef.
242              
243             =head2 C<init>
244              
245             $obj->init($footer);
246              
247             Process initialization in page run.
248              
249             Accepted C<$footer> is L<Data::HTML::Footer>.
250              
251             Returns undef.
252              
253             =head2 C<prepare>
254              
255             $obj->prepare;
256              
257             Process initialization before page run.
258              
259             Do nothing in this object.
260              
261             Returns undef.
262              
263             =head2 C<process>
264              
265             $obj->process;
266              
267             Process L<Tags> structure for HTML a element to output.
268              
269             Do nothing in case without inicialization by L<init>.
270              
271             Returns undef.
272              
273             =head2 C<process_css>
274              
275             $obj->process_css;
276              
277             Process L<CSS::Struct> structure for HTML a element to output.
278              
279             Do nothing in case without inicialization by L<init>.
280              
281             Returns undef.
282              
283             =head1 ERRORS
284              
285             new():
286             From Mo::utils::Hash::check_hash():
287             Parameter '%s' isn't hash reference.
288             Reference: %s
289             From Mo::utils::Hash::check_hash_keys():
290             Expected keys doesn't exists.
291             Parameter '%s' doesn't contain expected keys.
292             Keys: %s
293             From Mo::utils::Language::check_language_639_2():
294             Parameter '%s' doesn't contain valid ISO 639-2 code.
295             Codeset: %s
296             Value: %s
297             From Tags::HTML::new():
298             Parameter 'css' must be a 'CSS::Struct::Output::*' class.
299             Parameter 'tags' must be a 'Tags::Output::*' class.
300              
301             init():
302             Footer object must be a 'Data::HTML::Footer' instance.
303              
304             process():
305             From Tags::HTML::process():
306             Parameter 'tags' isn't defined.
307              
308             process_css():
309             From Tags::HTML::process_css():
310             Parameter 'css' isn't defined.
311              
312             =head1 EXAMPLE1
313              
314             =for comment filename=create_and_print_footer.pl
315              
316             use strict;
317             use warnings;
318              
319             use CSS::Struct::Output::Indent;
320             use Data::HTML::Footer;
321             use Tags::HTML::Footer;
322             use Tags::Output::Indent;
323             use Unicode::UTF8 qw(encode_utf8);
324              
325             # Object.
326             my $css = CSS::Struct::Output::Indent->new;
327             my $tags = Tags::Output::Indent->new(
328             'xml' => 1,
329             );
330             my $obj = Tags::HTML::Footer->new(
331             'css' => $css,
332             'tags' => $tags,
333             );
334              
335             # Data object for footer.
336             my $footer = Data::HTML::Footer->new(
337             'author' => 'John',
338             'author_url' => 'https://example.com',
339             'copyright_years' => '2022-2024',
340             'height' => '40px',
341             'version' => '0.07',
342             'version_url' => '/changes',
343             );
344              
345             # Initialize.
346             $obj->init($footer);
347              
348             # Process a.
349             $obj->process;
350             $obj->process_css;
351              
352             # Print out.
353             print "HTML:\n";
354             print encode_utf8($tags->flush);
355             print "\n\n";
356             print "CSS:\n";
357             print $css->flush;
358              
359             # Output:
360             # HTML:
361             # <footer>
362             # <span class="version">
363             # <a href="/changes">
364             # Version: 0.07
365             # </a>
366             # </span>
367             # ,&nbsp;
368             # © 2022-2024
369             #
370             # <span class="author">
371             # <a href="https://example.com">
372             # John
373             # </a>
374             # </span>
375             # </footer>
376             #
377             # CSS:
378             # #main {
379             # padding-bottom: 40px;
380             # }
381             # footer {
382             # text-align: center;
383             # padding: 10px 0;
384             # background-color: #f3f3f3;
385             # color: #333;
386             # position: fixed;
387             # bottom: 0;
388             # width: 100%;
389             # height: 40px;
390             # font-family: Arial, Helvetica, sans-serif;
391             # }
392              
393             =head1 EXAMPLE2
394              
395             =for comment filename=plack_app_table_with_footer.pl
396              
397             use strict;
398             use warnings;
399              
400             package Example;
401              
402             use base qw(Plack::Component::Tags::HTML);
403              
404             use Data::HTML::Footer;
405             use Tags::HTML::Table::View;
406             use Tags::HTML::Footer;
407              
408             sub _cleanup {
409             my ($self, $env) = @_;
410              
411             $self->{'_tags_table'}->cleanup;
412             $self->{'_tags_footer'}->cleanup;
413              
414             return;
415             }
416              
417             sub _css {
418             my ($self, $env) = @_;
419              
420             $self->{'_tags_table'}->process_css;
421             $self->{'_tags_footer'}->process_css;
422              
423             return;
424             }
425              
426             sub _prepare_app {
427             my $self = shift;
428              
429             $self->SUPER::_prepare_app();
430              
431             my %p = (
432             'css' => $self->{'css'},
433             'tags' => $self->{'tags'},
434             );
435             $self->{'_tags_table'} = Tags::HTML::Table::View->new(%p);
436             $self->{'_tags_footer'} = Tags::HTML::Footer->new(%p);
437              
438             # Data object for footer.
439             $self->{'_footer_data'} = Data::HTML::Footer->new(
440             'author' => 'John',
441             'author_url' => 'https://example.com',
442             'copyright_years' => '2022-2024',
443             'height' => '40px',
444             'version' => '0.07',
445             'version_url' => '/changes',
446             );
447              
448             # Data for table.
449             $self->{'_table_data'} = [
450             ['name', 'surname'],
451             ['John', 'Wick'],
452             ['Jan', 'Novak'],
453             ];
454              
455             return;
456             }
457              
458             sub _process_actions {
459             my ($self, $env) = @_;
460              
461             # Init.
462             $self->{'_tags_footer'}->init($self->{'_footer_data'});
463             $self->{'_tags_table'}->init($self->{'_table_data'}, 'no data');
464              
465             return;
466             }
467              
468             sub _tags_middle {
469             my ($self, $env) = @_;
470              
471             $self->{'tags'}->put(
472             ['b', 'div'],
473             ['a', 'id', '#main'],
474             );
475             $self->{'_tags_table'}->process;
476             $self->{'tags'}->put(
477             ['e', 'div'],
478             );
479              
480             $self->{'_tags_footer'}->process;
481              
482             return;
483             }
484              
485             package main;
486              
487             use CSS::Struct::Output::Indent;
488             use Plack::Runner;
489             use Tags::Output::Indent;
490            
491             my $css = CSS::Struct::Output::Indent->new;
492             my $tags = Tags::Output::Indent->new(
493             'xml' => 1,
494             'preserved' => ['style'],
495             );
496             my $app = Example->new(
497             'css' => $css,
498             'tags' => $tags,
499             )->to_app;
500             Plack::Runner->new->run($app);
501              
502             # Output screenshot is in images/ directory.
503              
504             =begin html
505              
506             <a href="https://raw.githubusercontent.com/michal-josef-spacek/Tags-HTML-Footer/master/images/plack_app_table_with_footer.png">
507             <img src="https://raw.githubusercontent.com/michal-josef-spacek/Tags-HTML-Footer/master/images/plack_app_table_with_footer.png" alt="Web app example" width="300px" height="300px" />
508             </a>
509              
510             =end html
511              
512             =head1 DEPENDENCIES
513              
514             L<Class::Utils>,
515             L<Error::Pure>,
516             L<Mo::utils::Hash>,
517             L<Mo::utils::Language>,
518             L<Readonly>,
519             L<Scalar::Util>,
520             L<Tags::HTML>,
521             L<Unicode::UTF8>.
522              
523             =head1 REPOSITORY
524              
525             L<https://github.com/michal-josef-spacek/Tags-HTML-Footer>
526              
527             =head1 AUTHOR
528              
529             Michal Josef Špaček L<mailto:skim@cpan.org>
530              
531             L<http://skim.cz>
532              
533             =head1 LICENSE AND COPYRIGHT
534              
535             © 2024-2025 Michal Josef Špaček
536              
537             BSD 2-Clause License
538              
539             =head1 VERSION
540              
541             0.04
542              
543             =cut