HTML::Zoom
2022-12-22 perl HTML template Mojo::Template HTML::Zoom CSS::InlinerTraditional approach to template system is something like this (example made with Mojo::Template):
%= include 'head.html.ep'
%= include 'navigation.html.ep'
<table class="table table-bordered table-hover table-sm">
<tr>
<th>Author</th>
<th>Book</th>
<th>Published</th>
</tr>
% for my $book (@books) {
<tr>
<td><%= $book->author %></td>
<td><%= $book->name %></td>
<td><%= $book->published %></td>
</tr>
% }
</table>
%= include 'foot.html.ep'
This approach works nicely, but the template is then not valid HTML and concerns are not well-separated between layout and data logic. It is also not possible to validate your templates.
Recently I tried different approach and was quite happy with the result. The template system is called HTML::Zoom. The assignment was to generate blocks for OrgChart on sharepoint, so I created simple HTML with layout as desired:
<td class="maincontainer" colspan="11">
<a class="teamlink">
<table class="t5">
<tr>
<td><img class="photo" /></td>
<td class="manname">Manager Name</td>
</tr>
<tr><td class="team" colspan="2">Team Name</td></tr>
</table>
</a>
</td>
Then the script to create blocks for all teams was something like this:
use HTML::Zoom;
use Path::Class qw(file);
my @teams = $db->get_all_teams();
my $output = HTML::Zoom->from_file('template.html')
->select('.maincontainer')
->repeat_content(
[ map {
my $team = $_;
sub {
$_ ->select('.teamlink') ->add_to_attribute(href => $team->link)
->select('.photo') ->add_to_attribute(src => $team->manager_photo_link)
->select('.manname') ->replace_content($team->manager->name)
->select('.team') ->replace_content($team->name);
}
} @teams
]
)->to_html;
file('chart.html')->spew($output);
The sharepoint does not support separate CSS styles, so I had to find a way to inline the styles into resulting HTML. There is handy module CSS::Inliner that could help with it.
use CSS::Inliner;
my $inliner = CSS::Inliner->new;
$inliner->read_file({ filename => 'chart.html' });
file('chart_inlined.html')->spew(iomode => '>:utf8', $inliner->inlinify());