So far we've copied the look-and-feel from search.cpan.org, but the only page we serve is the main page of the site. Let's add another static page to see if there are any challenges. We are going to add the feedback page of search.cpan.org.
Content
First we need to retreive the unique content of this page. We can do that either by clicking view-source in the browser when visiting
the page or we can download it using wget http://search.cpan.org/feedback
and then open it with our regular editor.
We put the content tt/feedback.tt.
Actually I made some small changes, to include a link to the GitHub page of this project (but forgetting to add the actual URL), instead of the mail address of the real search.cpan.org site, and to explicitly say that this is a clone.
Mapping URL (routing)
We need to map the path /feedback
in the URL to yhe appropriate template. This is done in the
run
function of
lib/MetaCPAN/SCO.pm
by adding the following lines:
if ($request->path_info eq '/feedback') {
return template('feedback');
}
This maps the URL to the specific template.
Looking at the new page now reveals, that we need some more changes in order to move the logo and the search box to the top left corner.
If we look around the rest of the search.cpan.org site, we can see that every page looks like the
feedback page except the front page. After some research we can find out that the difference is in the body
tag.
Specifically that the body tag of the front-page also includes class="front"
.
This class is set to 'front' on the front page, but the class attribute is missing on every other page.
On the front page:
<body id="cpansearch" onload="document.f.query.focus();" class="front">
On the feedback page:
<body id="cpansearch">
So we need to have a way to implement the same.
Conditional in Template::Toolkit
Template::Toolkit is huge and it also allows us to have conditionals.
We replace the original code we had in the template:
<body id="cpansearch" onload="document.f.query.focus();" class="front">
with this line:
<body id="cpansearch" onload="document.f.query.focus();" <% IF front %>class="front"<% END %>>
This means that if the arguments passed to the process
method of Template::Toolkit
contains a key called front
with some true value, then the class="front"
will be included in the generated HTML.
The question then, how do we pass front => 1
to the process method for the front page, but
not for the other pages? We need to be able to pass such parameters to the template()
function which will then pass them to the process
method.
Accepting parameters for individual pages
In the previous article we passed the { totals => $totals }
to the process method, but now we need to be able to accept such parameters from the user of the
template()
function, but also include the totals => $totals
pair in it.
We change lib/MetaCPAN/SCO.pm file again to to contain the following code in the template function:
sub template {
my ( $file, $vars ) = @_;
$vars //= {};
Carp::confess 'Need to pass HASH-ref to template()'
if ref $vars ne 'HASH';
my $root = root();
$vars->{totals} = from_json path("$root/totals.json")->slurp_utf8;
# ...
$tt->process( "$file.tt", $vars, \$out )
# ...
}
Instead of accepting only the $file
parameter, we now also accept a parameter called $vars
that
is supposed to be the hash we pass to the process
method of Template::Toolkit.
If the user does not provide the second parameter, we set it to an empty hash, and then we check if this
variable is indeed a reference to a hash. If not we call Carp::confess
with an error message explaining the problem.
Then we fill the 'totals' key with the values retrieved from the totals.json
file:
$vars->{totals} = from_json path("$root/totals.json")->slurp_utf8;
Passing parameters to template()
Then we can replace this code in the run
function:
if ($request->path_info eq '/') {
return template('index');
}
by this code:
if ($request->path_info eq '/') {
return template('index', {front => 1});
}
That is, we pass {front => 1}
to the template()
function which then passes
it to the process
method and then the class="front"
is included on the
front pages but not on any other pages.
With this we have finished adding the feedback page to our clone.
We arrived to another commit:
$ git add .
$ git commit -m "add feedback page"
Add Github link to feedback page
Then I noticed the link to GitHub wasn't working on the feedback page and so I added it with this commit.