How can I override WRAPPER in a Template Toolkit template file? - perl

Is there a way to disabling a WRAPPER that was set in new(\%config), through either the template, or a temporary override with parse()? I want to have a single default WRAPPER (that I'll use for 99.9% of my templates), but exclude a few.
I'm doing this all through Catalyst::View::TT just like the example in the configuration synopsis, except I don't want the WRAPPER to apply to all of my templates.

Edit the wrapper, to include a conditional like:
[% IF no_wrapper OR template.no_wrapper %] [% content %] [% ELSE %]
top;
[% content %]
bottom;
[% END %]
This allows me to disable the wrapper either (1) inside of template, or (2) from the stash.
[%- META no_wrapper = 1 -%]
$c->stash->{no_wrapper} = 1
META var ...; is a directive that makes var accessible through the template hash as template.var
source: http://wiki.catalystframework.org/wiki/gettingstarted/howtos/template_wrappers

Define exceptions in site/wrapper itself, and btw there are exceptions defined there already.
[% IF template.name.match('\.(css|js|txt)');
debug("Passing page through as text: $template.name");
content;
ELSE;
debug("Applying HTML page layout wrappers to $template.name\n");
content WRAPPER site/html + site/layout;
END;
-%]

I stumbled into the same problem, and created a more generalized solution that allows for dynamic switching of layouts, or to have no layout at all. See here:
More than one layout/wrapper with Dancer and Template::Toolkit

Related

Perl - When <%method PREPARE> gets called

I am new to Perl Mason.
I came across this with the suggestion that service calls should be put inside PREPARE block. But when I placed my service calls inside it, seems like the code inside it is never getting executed itself.
<%method PREPARE>
Kindly suggest what is the above block for and its usage.
From the Mason Manual:
The base component class, Mason::Component, has but a few built-in
methods: handle, render, wrap, main, m, and cmeta.
The main method contains the mix of HTML and Perl in the main part of
the component.
You can add other methods that output HTML via the section;
these methods automatically have access to $self and $m.
<%method leftcol>
<table><tr>
<td><% $foo %></td>
...
</tr></table>
</%method>
...
<% # call leftcol method and insert HTML here %>
<% $.leftcol %>
Which means you are declaring a method named PREPARE without any argument lists by <%method PREPARE> and after writing the method body you will end it using </%method>.
And, later somewhere you will call it using <% $.PREPARE %>.For more info refer the Mason Manual.

Template Toolkit browser detection

Is there a way to detect what browser you are using through template toolkit? For example I can achieve what I want to do using jQuery but thought it would be useful to know how to do it in template toolkit if possible?
Jquery
<script>
jQuery(window).load(function(){
if ( (jQuery.browser.msie && jQuery.browser.version < 9.0) )
{
jQuery('body').addClass('old-ie');
}
});
</script>
In template toolkit I want to do something like the below but can't see this in the documentation anywhere?
<body
[% IF browser.msie && browser.version < 9.0 %]
class="old-ie"
[% ELSE %]
[% END %]
>
I'm not aware of a TT plug-in for this, but it's trivial to add a line or two to your back-end application to make the information available to the template. For example, if your app is Catalyst based, you would add something like this to your main program:
__PACKAGE__->apply_request_class_roles(qw/
Catalyst::TraitFor::Request::BrowserDetect
/);
... and in your 'auto' handler, introduce a line such as (untested):
$c->stash(browser => $c->req->browser);
... or just use this is your template:
[%- SET browser = c.req.browser;
SET old_ie = 'class="old-ie"'
IF browser.windows && browser.ie && browser.public_major < 9.0;
-%]
and then include old_ie wherever it's required in your template.
See Catalyst::TraitFor::Request::BrowserDetect and HTTP::BrowserDetect for more info and options. I'm sure there are similar plugins/methods for Dancer, Mojolicious etc.
You could do that through the HTTP request headers. You didn't mention what was calling TT, but if you're using Catalyst, you could use Catalyst::TraitFor::Request::BrowserDetect, and then pass a variable to TT to say what kind of browser was requesting the page.

Strategy for migrating Perl CGI to Template Toolkit?

I have a relatively large legacy Perl/CGI/DBI web application which generates HTML on-the-fly piece by piece. We are reworking the HTML being produced, to come in to compliance with HTML 5 / CSS 3. This would be a good time to move to some sort of template system. We do NOT want to engage in a complete rewrite, and thus do NOT want to migrate to a framework such as Catalyst.
I'm thinking that Perl Template Toolkit might be our lowest-impact means. I'm re-reading the venerable Badger Book to study up on feasibility.
My question is this. Has anyone here migrated "old school" Perl web code to Template Toolkit? Are there any tricks you can share for minimizing the rewrite/rework needed? We have not 100% decided on Template Toolkit, either. If there is an alternative which we should consider?
What problem, specifically, are we trying to solve? We're generating invalid HTML and need to clean that up. Since we're cleaning, we want to produce fully-valid HTML 5 and, to the extent practicable, valid CSS3 and Javascript. We use jQuery, jQuery UI widgets, and AJAX via jQuery. We have typical Page Controller MVC architecture except no View layer as such. We'd like to go to some sort of template system but don't want to rewrite everything (or much of anything!) to migrate.
Thank You!
Ed Barnard, Cannon Falls MN
Here's what I've found, as I've moved my practice from CGI.pm to TT, and what I've also learned along the way using HTML::Mason, HTML::Template, Text::Template, and working with ERB and HAML in Rails.
The more logic you have in in your displays, especially if it is written in a display specific language, the less fun you're going to have.
I've come to prefer HAML for the reduction in size of the contents of my templates [ In HAML, closing tags are implied by indentation ]
Perform as much of the logic to compute the various dynamic bits of the page before you drop into the template, in the application's native language. [ call view methods, before engaging in rendering ].
In relation to (3), by using methods, instead of inline display/rendering logic, you can make your templates declarative, so while you might be performing logic in the middle of the render, your templates don't have a bunch of IF/THEN/ELSE logic causing clutter.
Let's imagine a reasonably small, contrived web page made up of a header, and footer and a body. Let's assume that the footer is completely static, the body changes every time a new page loads, but the header only changes when a user logs in/out.
You can imagine the header containing code like this:
<header>
[% IF $user.is_logged_in THEN %]
Hello [% $user.name %] - Log Out
[% ELSE %]
Please Log In
[% END %]
</header>
But you're better off in the long term doing this in header.tt:
<header>
[% user_info($user) |html %]
</header>
and this in View::Helpers::Header.pm:
sub user_info {
my $user = shift;
if ($user->{is_logged_in} ) {
return "Hello $user->{name} - " . logout_link($user->{id});
}
else {
return "Please " . login_link();
}
}
sub logout_link {
my $userid = shift;
return qq(Log Out)
}
You can, of course, implement the view helpers in TT rather than pure Perl, and I don't have any kind of numbers for you, but if you've done all of your logic in Perl already, you can refactor the Perl into modules (if it isn't there already), instead of re-coding them in TT.
As part of your test suite, consider an HTML validator like HTML::Lint or HTML::Tidy.

Template Toolkit, test for last iteration in a nested loop

I'm using template toolkit to form a simple JSON response (see the code below).
I need to put a comma after all elements of the response except the last.
I believe I need to make use of TTs iterator, however I'm not getting it right.
With this code, a comma is still printed on the end of the last element.
The problem lies with the section that contains
[% UNLESS outer.last && loop.last %],[% END %]
this should add a comma unless the outer and inner loops are on their last iteration.
Any help on what I'm getting wrong greatly appreciated.
{ "success": true, "filesdata": [
[%~ USE outer = iterator(objects); FOREACH object IN outer;
FOREACH rep IN object.reps;
IF rep.rep == reptype %]
{ "id":"[% object.id | xml %]", "url":"[% rep.src | xml %]", "story":"[% object.story | xml %]" }[% UNLESS outer.last && loop.last %],[% END %]
[%~ END;
END;
END ~%]
] }
This works for me:
[% IF loop.last %]}[% ELSE %]},[% END %]
Have you tried using the join vmethod? You can create a list and join it with a comma:
[% items.join(', ') %]
Having said that, you may also want to look at Template::Plugin::SimpleJson. You could create a hash and then pass it to this plugin. However you do decide to do it, you probably don't want to worry about quoting your JSON in the actual template file and using something like this could save you some heartache down the line.
There's also the option of creating the JSON outside of the template itself, but that's outside the scope of your question.

Call to Subroutine from Catalyst Controller

I am working on catalyst to design a front end for a database. I am new to perl and catalyst. I am stuck with one error in the controller.
I want to fetch gene names from one table and pass each gene name to a subroutine gene_name(call a subroutine gene_name) which will perform certain function. I some how fetched the column with gene names but they are in the form of Hash reference to other table. My call to gene_name is not working.
Any idea how to pass the values to the subroutine rather than reference?
My code is as follows:
my #gene_list = $c->model('Gene::GeneTable')->search({
},{
column =>[qw/symbol/],
}
);
foreach my $gene (#gene_list){
push #gene_aliases, &gene_name($gene);
}
The error I am getting after executing the code is as follows:
DBIx::Class::ResultSet::find(): Can't bind a reference (MyApp::Model::Gene::GeneTable=HASH(0x7ff6d88b7c58))
UPDATED
My gene_name() subroutine is in another module which I have included in the controller. Now I have changed the for loop(in controller) as following and currently it is passing gene name to gene_name() to fetch aliases(But query remains the same):
foreach my $gene (#gene_list){
push #gene_aliases, &gene_name($gene-> symbol);
}
I am accessing the #gene_aliases in my view file as follows:
[% FOREACH g in gene_aliases -%]
[% g %]
[% END -%]
The above code is fetching hash references instead of names in the page. I am not able to display the gene names on web page.If I give [% g.symbol %] in for loop then the page would be empty with no error message.Hope this would be sufficient information for answering my question. If not I would elaborate on it.
My SQL query is as follows:
Select Symbol from GeneTable;
Thanks in advance
UPDATED2
As I am not a full time programmer, I am asking these questions on the blog. Kindly help me resolve my issues. If in case I have search form which takes gene name from user and this gene name has to be passed to the gene_name() subroutine, how do I pass this (to the controller and how to call the gene_name()). Kindly help me in resolving this issue.
My form in view.tt is as follows:
<form method="post" action "[% c.uri_for('/gene')%]">
<input type="text" name="search_alias">
<input type="submit" name="alias_search" value="Search">
</form>
All my aliases are in the other table called Alias, which is been used in gene_name() subroutine.
Either the gene_name() function needs to expect a GeneTable object being passed to it, or you would call it like this: gene_name($gene->symbol).
Having said that, the Controller does not look like the right place for this, based on what limited information you've provided.
It would make a lot more sense to have gene_name as a method of Gene::GeneTable itself, ie:
package GeneTable;
...
sub gene_name {
my $self = shift;
my $gene_name = ... # do something with $self->symbol
$gene_name
}
...
So that the ->gene_name method is available to any GeneTable object in any context.
UPDATE following OP's initial two comments
It sounds like gene_name() (which possibly should be called gene_aliases()) is a method of a Gene object. Putting such a conversion into a Controller does not adhere to good MVC philosophy.
Presumably you have model code somewhere - MyApp/Model/Gene/ most likely - and this sub should exist inside Gene/GeneTable.pm. Then you could use it thus:
[%- FOREACH g IN gene_list -%]
[% g.symbol %]<br/><ul>
[%- FOREACH gn IN g.gene_name -%]
<li>[% gn %]</li>
[%- END -%]
</ul>
[%- END -%]
in your template, and anywhere else you have a GeneTable object or collection thereof.
UPDATE #2 Following updated question
DBIx:Class will return an array of objects when called in list context as you do. Perhaps you need to add some Data::Dumper->Dumper() calls to get a handle on what each step is returning to you.
I suggest you add the following line immediately after your call to ->search():
$c->log->debug("gene_list contains: ", Data::Dumper->Dumper(\#gene_list));
...and possibly the equivalent debug for #gene_aliases after you've populated that.
That might give you a clearer picture of what you're getting back from your search, but I'd hazard a guess you're getting Gene::GeneTable objects.