Use Mojolicious action as title in template - perl

I'm trying to make the default "title" variable in stash be set to the English version of the action name. For example:
sub customer_orders {
...
}
Would have:
title => 'Customer Orders',
Available in the stash for the templates to use. Does anyone know how to do this? Thanks!

You could get the subroutine name via caller:
my $sub_name = (caller(0))[3];.
Judging from your output, you may want to also upcase it and replace _ with whitespace
$sub_name =~ s /_/ /g;
I would upcase like this:
my $title = join(' ', map{ ucfirst lc }split(' ', $sub_name) );

It looks like $c->action is available in Mojolicious templates as $action. So you can just do this:
<title><%= title || action_to_title($action) %>
This way other templates can override the title like so:
% title 'My Override Title'
And you can add the action_to_title helper to prepare the action for a title if title is not set.

You can put title into layout template
<!DOCTYPE html>
<html>
<head>
<title><%= content 'title' %></title>
<style>
label.field-with-error { color: #FF4C4D }
input.field-with-error { background-color: #FF4C4D }
.error_msg { color: #FF4C4D }
</style>
%= content 'styles';
</head>
<body>
%= include 'basic/menu'
%= include 'basic/error_messages'
%= content
%= content_for 'include_js'
</body>
</html>
Then at your template fill it with content (read also about content_for, content_with)
% content_with title => "$title_schet за $title_date";
% content_for styles => '<link rel="stylesheet" type="text/css" href="/static/css/report.css">';
<form>
...
</form>

Related

Passing variable to layout template in Mojolicious

I am trying to set the refresh rate of a status page using a stash variable
So I have the following code in the controller to render the page:
my $refreshrate = 10;
$self->stash( refreshrate => $refreshrate);
$self->render();
in the html template I have:
% layout 'refreshLayout', title => 'A title';
% content_for refresh => begin
% end
<div>....body content .../<div>
and in the layout template I have:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
<meta charset="UTF-8"/>
<meta http-equiv="refresh" content="<%= refreshrate %>"/>
.....
<title><%= title %></title>
</head>
<body><%= content %></body>
</html>
I always end up with a page rendered with no value in the content attribute of the refresh meta tag.
It looks like the refreshrate replacement does not work.
However both the content and title replacements do work.
So what am I doing wrong here?
And while we are here, why in the layout template do we do use <%= content %> (and not $content)
While in the template of the regular page we use the more logical <%= $variable %>
How does the replacement work in the layout template versus the replacement in the template of the main page?
The stash values appear as perl variables in your templates. (title is special as it's also a default helper function).
If you want to pass the stash value for refreshrate to the layout, you have to add it to your layout() args:
use Mojolicious::Lite;
get '/' => sub {
my $c = shift;
$c->stash (refreshrate => 10),
$c->render(template => 'foo/bar')};
app->start;
__DATA__
## foo/bar.html.ep
% layout 'mylayout', title => 'Hi there',refreshrate => $refreshrate;
Hello World!
## layouts/mylayout.html.ep
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
<meta charset="UTF-8"/>
<meta http-equiv="refresh" content="<%= $refreshrate %>"/>
<title><%= $title %></title></head>
<body><%= content %></body>
</html>
See Layouts in Rendering doc

How to postpone <head> rendering?

I have the layout like this:
## layouts/v2.html.ep
<html lang="en">
<head>
%= content_for 'stylesheets'
</head>
<body>
%= include 'layouts/v2/header'
<main class="main">
%= include 'layouts/v2/menu'
<div class="content">
%= content
</div>
</main>
</body>
</html>
## layouts/v2/menu
% content_for stylesheets => begin
%= stylesheet 'v2/css/menu.css'
% end
<aside class="menu">
...
</aside>
## layouts/v2/header
% content_for stylesheets => begin
%= stylesheet 'v2/css/header.css'
% end
<header class="header">
...
</header>
Here when templates are included I include their style sheets.
Notice this in template:
% content_for stylesheets => begin
%= stylesheet 'v2/css/menu.css'
% end
But this is too late to do that, because the <head> is already rendered.
As workaround this problem I can move %= content_for 'stylesheets' from <head> to the bottom of page. But I want style sheets are loaded first.
Is there any way to postpone rendering for the content of 'stylesheets' block until whole page is rendered?
UPD
Thank to #amon about that Mojolicous layouts are rendered inside out. I understand the problem and there for templates included from first layout I include stylesheets manually:
## layouts/v2.html.ep
<html lang="en">
<head>
%= stylesheet 'v2/css/header.css'
%= stylesheet 'v2/css/menu.css'
%= content_for 'stylesheets'
</head>
<body>
%= include 'layouts/v2/header'
<main class="main">
%= include 'layouts/v2/menu'
<div class="content">
%= content
</div>
</main>
</body>
</html>
So in any rendered/included template (except layout) next works fine:
## some/template
% content_for stylesheets => begin
%= stylesheet 'some/template.css'
% end
template content
Mojolicous layouts are rendered inside-out, and you can nest arbitrarily many layouts.
Create a template that includes just the outermost document content and other HTML boilerplate, with a placeholder for the content of <body>
<html lang="en">
<head>
%= content_for 'stylesheets'
</head>
<body>
%= content
</body>
</html>
Then you can use that template as the layout for the body of your HTML page. I.e., use the layout helper like this:
% layout 'outermost_layout';
%= include 'layouts/v2/header'
<main class="main">
%= include 'layouts/v2/menu'
<div class="content">
%= content
</div>
</main>
After rendering the template, Mojolicious will check whether you specified a layout and then render it, using the output from this template as the outer layout's content. So because the innermost layout is rendered first, data can flow from your templates through the stash to wrapping layouts.

Search and replace the content between a specific tag

#!/usr/bin/perl
use strict;
use warnings;
my $html = q|
<html>
<head>
<style>
.classname{
color: red;
}
</style>
</head>
<body>
classname will have a color property.
</body>
</html>
|;
$html=~s/classname/NEW/g;
print $html;
This replaces classname in both places. How can I limit the replacement only to content of <body>? I'd like to see it done using HTML::Parser or HTML::TreeBuilder.
I believe this does what you want, replaces classname with your regexp on all children of body element, using HTML::TreeBuilder.
I added another dummy div to input to make sure it was being processed correctly.
#!/usr/bin/perl
use strict;
use warnings;
use HTML::TreeBuilder;
my $html = q|
<html>
<head>
<style>
.classname{
color: red;
}
</style>
</head>
<body>
classname will have a color property.
<div>more text with classname in it</div>
</body>
</html>
|;
my $tree = HTML::TreeBuilder->new_from_content($html);
replace_text( $tree->find_by_tag_name("body") );
print $tree->as_HTML."\n";
sub replace_text {
my $html_element = shift;
for my $el ( $html_element->content_refs_list ){
if ( ref( $$el ) ){
replace_text( $$el );
next;
}
$$el =~ s /classname/NEW/g;
}
return $html_element;
}

How can I remove an attribute from all DOM elements with Mojolicious?

I want to remove the bgcolor attribute from all elements of a page I am scraping via Mojolicious.
My attempt has been the following:
$dom->all_contents->each(sub { $_->attr('bgcolor' => undef) });
but this seems not to work.
How do I do it right?
The following uses Mojo::DOM to delete the bgcolor attribute for every node:
use strict;
use warnings;
use Mojo::DOM;
my $dom = Mojo::DOM->new(do {local $/; <DATA>});
for my $node ($dom->find('*')->each) {
delete $node->{bgcolor};
}
print $dom;
__DATA__
<html>
<head>
<title>Hello background color</title>
</head>
<body bgcolor="white">
<h1>Hello world</h1>
<table>
<tr><td bgcolor="blue">blue</td></tr>
<tr><td bgcolor="green">green</td></tr>
</table>
</body>
</html>
Outputs:
<html>
<head>
<title>Hello background color</title>
</head>
<body>
<h1>Hello world</h1>
<table>
<tr><td>blue</td></tr>
<tr><td>green</td></tr>
</table>
</body>
</html>
Notes:
It's possible to use CSS Selectors to limit the returned nodes to only those containing the specific attribute:
for my $node ($dom->find('[bgcolor]')->each) {
One can also let Mojo handle the iteration like the following:
$dom->find('*')->each(sub {
delete $_->{bgcolor};
});
As I understand it, the DOM attribute you're looking for isn't bgcolor but background-color, the css variety. bgcolor fell out of popularity a while ago, in favor of defining classes and using CSS to set the styling on an object (including its background color). Try background-color instead.

html calling perl subroutine and return values from subroutine to display in the html

here is my html code
<html>
<title>Results</title>
<body><h1> Here are your results</h1>
<p>Please click the Button to see your result run by Ravi's team.</p>
<form action='index.pl' method='post'>
<input type='submit' value='submit'>
</form>
</body>
</html>
and index.pl is my perl and my subroutine is as follows.
sub my_result{
my $run;
my $dir="/kbio/sraja/BenzoExposedDataSet/database/Output";
my $parsebphtml = "/parse_bphtml.pl";
my $olgacsvfile = "/database/Output/sample.csv";
my #bp=<$dir/*.bp>;
$run ="perl $parsebphtml > $olgacsvfile";
# print "$com\n";
system($run)==0 or my_err("Could not run $run\n");
#printing the table
open(F,"$olgacsvfile") or my_err("Could not open the csv ($olgacsvfile) file");
print "<h2> Average Results </h2>";
print "<table border=1>";
while(my $line=<F>){
print "<tr>";
my #cells= split ',',$line;
foreach my $cell (#cells)
{
print "<td colspan=1>$cell</td>";
}
print "</tr>";
}
print "</table>";
}
So as you see, table is what i need to return to results.html
Any help would be really appreciable.
thanks .
Geet
I don't know how much work you want to do but, if you want to keep it simple give a try at the HTML::Template module. Here is a simple usage example.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset=utf-8>
<title>A random page</title>
</head>
<body>
<TMPL_VAR NAME=page_content>
</body>
</html>
My perl code contained something like this. Better yet, check the documentation at http://metacpan.org/pod/HTML::Template .
use HTML::Template;
sub my_result {
return $html_string;
}
my $master_template = HTML::Template->new(filename => "Path to html template file");
$master_template->param('page_content' => my_result());
Depending on how far you plan on going with this, I would recommend that you a more advanced templating system such as the one used by the mojolicious framework (http://mojolicio.us/perldoc/Mojo/Template).
Cheers,
MrMcKizzle