You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
469 lines
14 KiB
469 lines
14 KiB
7 years ago
|
package Anvil::Tools::Template;
|
||
8 years ago
|
#
|
||
|
# This module contains methods used to handle templates.
|
||
|
#
|
||
|
|
||
|
use strict;
|
||
|
use warnings;
|
||
|
use Data::Dumper;
|
||
7 years ago
|
use Scalar::Util qw(weaken isweak);
|
||
8 years ago
|
|
||
|
our $VERSION = "3.0.0";
|
||
|
my $THIS_FILE = "Template.pm";
|
||
|
|
||
|
### Methods;
|
||
|
# get
|
||
7 years ago
|
# select_form
|
||
8 years ago
|
# skin
|
||
8 years ago
|
|
||
|
=pod
|
||
|
|
||
|
=encoding utf8
|
||
|
|
||
|
=head1 NAME
|
||
|
|
||
7 years ago
|
Anvil::Tools::Template
|
||
8 years ago
|
|
||
|
Provides all methods related to template handling.
|
||
|
|
||
|
=head1 SYNOPSIS
|
||
|
|
||
7 years ago
|
use Anvil::Tools;
|
||
8 years ago
|
|
||
7 years ago
|
# Template a common object handle on all Anvil::Tools modules.
|
||
|
my $anvil = Anvil::Tools->new();
|
||
8 years ago
|
|
||
7 years ago
|
# Access to methods using '$anvil->Template->X'.
|
||
8 years ago
|
#
|
||
|
# Example using '()';
|
||
|
|
||
|
|
||
|
=head1 METHODS
|
||
|
|
||
|
Methods in this module;
|
||
|
|
||
|
=cut
|
||
|
sub new
|
||
|
{
|
||
|
my $class = shift;
|
||
|
my $self = {
|
||
|
SKIN => {
|
||
|
HTML => "",
|
||
|
},
|
||
|
};
|
||
|
|
||
|
bless $self, $class;
|
||
|
|
||
|
return ($self);
|
||
|
}
|
||
|
|
||
7 years ago
|
# Get a handle on the Anvil::Tools object. I know that technically that is a sibling module, but it makes more
|
||
8 years ago
|
# sense in this case to think of it as a parent.
|
||
|
sub parent
|
||
|
{
|
||
|
my $self = shift;
|
||
|
my $parent = shift;
|
||
|
|
||
|
$self->{HANDLE}{TOOLS} = $parent if $parent;
|
||
|
|
||
7 years ago
|
# Defend against memory leads. See Scalar::Util'.
|
||
|
if (not isweak($self->{HANDLE}{TOOLS}))
|
||
|
{
|
||
|
weaken($self->{HANDLE}{TOOLS});;
|
||
|
}
|
||
|
|
||
8 years ago
|
return ($self->{HANDLE}{TOOLS});
|
||
|
}
|
||
|
|
||
|
|
||
|
#############################################################################################################
|
||
|
# Public methods #
|
||
|
#############################################################################################################
|
||
|
|
||
|
=head2 get
|
||
|
|
||
|
This method takes a template file name and a template section name and returns that body template.
|
||
|
|
||
7 years ago
|
my $body = $anvil->Template->get({file => "foo.html", name => "bar"}))
|
||
8 years ago
|
|
||
|
=head2 Parameters;
|
||
|
|
||
|
=head3 file (required)
|
||
|
|
||
|
This is the name of the template file containing the template section you want to read.
|
||
|
|
||
8 years ago
|
=head3 language (optional)
|
||
|
|
||
|
This is the language (iso code) to use when inserting strings into the template. When not specified, 'C<< Words->language >>' is used.
|
||
|
|
||
8 years ago
|
=head3 name (required)
|
||
|
|
||
|
This is the name of the template section, bounded by 'C<< <!-- start foo --> >>' and 'C<< <!-- end food --> >>' to read in from the file.
|
||
|
|
||
7 years ago
|
=head3 show_name (optional)
|
||
|
|
||
|
If set the C<< 1 >>, the HTML will have comments shows which parts came from what file. By default, this is disabled.
|
||
|
|
||
8 years ago
|
=head3 skin (optional)
|
||
|
|
||
8 years ago
|
By default, the active skin is set by 'C<< defaults::template::html >>' ('C<< alteeve >>' by default). This can be checked or set using 'C<< Template->skin >>'.
|
||
|
|
||
|
This parameter allows for an override to use another skin.
|
||
|
|
||
|
=head3 variables (optional)
|
||
|
|
||
|
If there are variables to inject into the template, pass them as a hash referencce using this paramter.
|
||
8 years ago
|
|
||
|
=cut
|
||
|
sub get
|
||
|
{
|
||
|
my $self = shift;
|
||
|
my $parameter = shift;
|
||
7 years ago
|
my $anvil = $self->parent;
|
||
8 years ago
|
|
||
7 years ago
|
my $debug = 3;
|
||
8 years ago
|
my $file = defined $parameter->{file} ? $parameter->{file} : "";
|
||
7 years ago
|
my $language = defined $parameter->{language} ? $parameter->{language} : $anvil->Words->language;
|
||
8 years ago
|
my $name = defined $parameter->{name} ? $parameter->{name} : "";
|
||
7 years ago
|
my $show_name = defined $parameter->{show_name} ? $parameter->{show_name} : 0;
|
||
|
my $skin = defined $parameter->{skin} ? $parameter->{skin} : $anvil->Template->skin;
|
||
8 years ago
|
my $variables = defined $parameter->{variables} ? $parameter->{variables} : "";
|
||
7 years ago
|
$skin = $anvil->data->{path}{directories}{skins}."/".$skin;
|
||
8 years ago
|
my $template = "";
|
||
|
my $source = "";
|
||
7 years ago
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
|
||
8 years ago
|
file => $file,
|
||
|
language => $language,
|
||
|
name => $name,
|
||
|
skin => $skin,
|
||
|
}});
|
||
7 years ago
|
|
||
|
# The 'http_headers' template can never show the name
|
||
|
$show_name = 0 if $name eq "http_headers";
|
||
8 years ago
|
|
||
8 years ago
|
my $error = 0;
|
||
|
if (not $file)
|
||
|
{
|
||
8 years ago
|
# No file passed.
|
||
7 years ago
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0024"});
|
||
8 years ago
|
$error = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
# Make sure the file exists.
|
||
8 years ago
|
if ($file =~ /^\//)
|
||
|
{
|
||
|
# Fully defined path, don't alter it.
|
||
|
$source = $file;
|
||
7 years ago
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { source => $source }});
|
||
8 years ago
|
}
|
||
|
else
|
||
|
{
|
||
|
# Just a file name, prepend the skin path.
|
||
|
$source = $skin."/".$file;
|
||
7 years ago
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { source => $source }});
|
||
8 years ago
|
}
|
||
8 years ago
|
|
||
8 years ago
|
if (not -e $source)
|
||
|
{
|
||
8 years ago
|
# Source doesn't exist
|
||
7 years ago
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0025", variables => { source => $source }});
|
||
8 years ago
|
$error = 1;
|
||
|
}
|
||
|
elsif (not -r $source)
|
||
|
{
|
||
8 years ago
|
# Source isn't readable.
|
||
8 years ago
|
my $user_name = getpwuid($<);
|
||
|
$user_name = $< if not $user_name;
|
||
7 years ago
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0026", variables => { source => $source, user_name => $user_name }});
|
||
8 years ago
|
$error = 1;
|
||
|
}
|
||
|
}
|
||
|
if (not $name)
|
||
|
{
|
||
7 years ago
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0027"});
|
||
8 years ago
|
$error = 1;
|
||
|
}
|
||
|
|
||
|
if (not $error)
|
||
|
{
|
||
7 years ago
|
my $in_template = 0;
|
||
7 years ago
|
my $template_file = $anvil->Storage->read_file({file => $source});
|
||
7 years ago
|
foreach my $line (split/\n/, $template_file)
|
||
8 years ago
|
{
|
||
7 years ago
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0023", variables => { line => $line }});
|
||
8 years ago
|
if ($line =~ /^<!-- start $name -->/)
|
||
|
{
|
||
|
$in_template = 1;
|
||
7 years ago
|
if ($show_name)
|
||
|
{
|
||
7 years ago
|
$template .= "<!-- start: [$source] -> [$name] -->\n";
|
||
7 years ago
|
}
|
||
8 years ago
|
next;
|
||
8 years ago
|
}
|
||
|
if ($in_template)
|
||
|
{
|
||
|
if ($line =~ /^<!-- end $name -->/)
|
||
|
{
|
||
|
$in_template = 0;
|
||
7 years ago
|
if ($show_name)
|
||
|
{
|
||
7 years ago
|
$template .= "<!-- end: [$source] -> [$name] -->\n";
|
||
7 years ago
|
}
|
||
8 years ago
|
last;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
$template .= $line."\n";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
7 years ago
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { template => $template }});
|
||
8 years ago
|
|
||
|
# Now that I have the skin, inject my variables. We'll use Words->string() to do this for us.
|
||
7 years ago
|
$template = $anvil->Words->string({
|
||
8 years ago
|
string => $template,
|
||
|
variables => $variables,
|
||
|
});
|
||
7 years ago
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { source => $source }});
|
||
8 years ago
|
}
|
||
|
|
||
|
return($template);
|
||
|
}
|
||
|
|
||
7 years ago
|
=head2 select_form
|
||
|
|
||
|
This builds a <select/> form field for use when building forms in templates.
|
||
|
|
||
|
Parameters;
|
||
|
|
||
|
=head3 blank (optional, default C<< 0 >>)
|
||
|
|
||
|
By default, only the options passed are available in the select menu. If this is set to C<< 1 >>, then a blank entry will be inserted to the top of the select list.
|
||
|
|
||
|
=head3 class (optional)
|
||
|
|
||
|
This allows a custom CSS class to be used.
|
||
|
|
||
|
=head3 id (optional)
|
||
|
|
||
|
This is the ID to set. If this is not passed, the C<< name >> is used for the ID.
|
||
|
|
||
|
=head3 name (required)
|
||
|
|
||
|
This is the name of the select box.
|
||
|
|
||
|
=head3 options (required)
|
||
|
|
||
|
This is an array reference of options to put into the select box.
|
||
|
|
||
|
Example;
|
||
|
|
||
|
my $options = ["a", "b", "c"];
|
||
|
|
||
|
If you wanted to have a separate value passed to the form versus what is shown to the user, you can do so by using c<< <value>#!#<string> >>. In the case, C<< <string >> is what the user sees but C<< <value> >> is what is returned if that option is selected.
|
||
|
|
||
|
Example
|
||
|
|
||
|
my $options = ["MiB#!#Mibibyte", "GiB#!#Gibibyte"];
|
||
|
|
||
|
Would create a list where the user can choose between C<< Mibibyte >> or C<< Gibibyte >>, and the form would return C<< MiB >> or C<< GiB >>, respectively.
|
||
|
|
||
|
=head3 say_blank (optional)
|
||
|
|
||
|
If C<< blank >> is set, this can be a string to show in the place of the empty entry. This entry will use the C<< subtle_text >> CSS class and if it is selected, nothing is returned when the form is submitted.
|
||
|
|
||
|
=head3 selected (optional)
|
||
|
|
||
|
If this is set and if it matches one of the C<< options >> array values, then that option will be selected when the form is loaded.
|
||
|
|
||
|
=head3 sort (optional, default C<< 1 >>)
|
||
|
|
||
|
By default, the options array will be sorted alphabetically. If this is set to C<< 0 >>, then the order the options were entered into the array is used.
|
||
|
|
||
|
=cut
|
||
|
sub select_form
|
||
|
{
|
||
|
my $self = shift;
|
||
|
my $parameter = shift;
|
||
7 years ago
|
my $anvil = $self->parent;
|
||
7 years ago
|
|
||
|
my $debug = 3;
|
||
|
my $name = defined $parameter->{name} ? $parameter->{name} : "";
|
||
|
my $options = defined $parameter->{options} ? $parameter->{options} : "";
|
||
|
my $id = defined $parameter->{id} ? $parameter->{id} : $name;
|
||
|
my $sort = defined $parameter->{'sort'} ? $parameter->{'sort'} : 1; # Sort the entries?
|
||
|
my $class = defined $parameter->{class} ? $parameter->{class} : "";
|
||
|
my $blank = defined $parameter->{blank} ? $parameter->{blank} : 0; # Add a blank/null entry?
|
||
|
my $say_blank = defined $parameter->{say_blank} ? $parameter->{say_blank} : ""; # An optional, grayed-out string in the place of the "blank" option
|
||
|
my $selected = defined $parameter->{selected} ? $parameter->{selected} : ""; # Pre-select an option?
|
||
7 years ago
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
|
||
7 years ago
|
name => $name,
|
||
|
options => $options,
|
||
|
'sort' => $sort,
|
||
|
class => $class,
|
||
|
blank => $blank,
|
||
|
say_blank => $say_blank,
|
||
|
selected => $selected,
|
||
|
}});
|
||
|
|
||
|
# Lets start!
|
||
|
my $select = "<select name=\"$name\" id=\"$id\">\n";
|
||
|
if ($class)
|
||
|
{
|
||
|
$select = "<select name=\"$name\" id=\"$id\" class=\"$class\">\n";
|
||
|
}
|
||
7 years ago
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'select' => $select }});
|
||
7 years ago
|
|
||
|
# Insert a blank line.
|
||
|
if ($blank)
|
||
|
{
|
||
|
# If 'say_blank' is a string key, use it.
|
||
|
my $blank_string = "";
|
||
|
my $blank_class = "";
|
||
|
if ($say_blank)
|
||
|
{
|
||
|
$blank_string = $say_blank;
|
||
|
$blank_class = "class=\"subtle_text\"";
|
||
|
}
|
||
|
if ($selected eq "new")
|
||
|
{
|
||
|
$selected = "";
|
||
|
$select .= "<option value=\"\" $blank_class selected>$blank_string</option>\n";
|
||
7 years ago
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'select' => $select }});
|
||
7 years ago
|
}
|
||
|
else
|
||
|
{
|
||
|
$select .= "<option value=\"\" $blank_class>$blank_string</option>\n";
|
||
7 years ago
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'select' => $select }});
|
||
7 years ago
|
}
|
||
|
}
|
||
|
|
||
|
# TODO: This needs to be smarter... I shouldn't need two loops for sorted/not sorted.
|
||
|
if ($sort)
|
||
|
{
|
||
|
foreach my $entry (sort {$a cmp $b} @{$options})
|
||
|
{
|
||
|
next if not $entry;
|
||
|
if ($entry =~ /^(.*?)#!#(.*)$/)
|
||
|
{
|
||
|
my $value = $1;
|
||
|
my $description = $2;
|
||
|
$select .= "<option value=\"$value\">$description</option>\n";
|
||
7 years ago
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'select' => $select }});
|
||
7 years ago
|
}
|
||
|
else
|
||
|
{
|
||
|
$select .= "<option value=\"$entry\">$entry</option>\n";
|
||
7 years ago
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'select' => $select }});
|
||
7 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
foreach my $entry (@{$options})
|
||
|
{
|
||
|
next if not $entry;
|
||
|
if ($entry =~ /^(.*?)#!#(.*)$/)
|
||
|
{
|
||
|
my $value = $1;
|
||
|
my $description = $2;
|
||
|
$select .= "<option value=\"$value\">$description</option>\n";
|
||
7 years ago
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'select' => $select }});
|
||
7 years ago
|
}
|
||
|
else
|
||
|
{
|
||
|
$select .= "<option value=\"$entry\">$entry</option>\n";
|
||
7 years ago
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'select' => $select }});
|
||
7 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# Was an entry selected?
|
||
|
if ($selected)
|
||
|
{
|
||
|
$select =~ s/value=\"$selected\">/value=\"$selected\" selected>/m;
|
||
7 years ago
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'select' => $select }});
|
||
7 years ago
|
}
|
||
|
|
||
|
# Done!
|
||
|
$select .= "</select>\n";
|
||
|
|
||
7 years ago
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'select' => $select }});
|
||
7 years ago
|
return($select);
|
||
|
}
|
||
|
|
||
8 years ago
|
=head2 skin
|
||
|
|
||
8 years ago
|
This sets or returns the active skin used when rendering web output.
|
||
8 years ago
|
|
||
|
The default skin is set via 'C<< defaults::template::html >>' and it must be the same as the directory name under 'C<< /var/www/html/skins/ >>'.
|
||
|
|
||
8 years ago
|
Get the active skin directory;
|
||
8 years ago
|
|
||
7 years ago
|
my $skin = $anvil->Template->skin;
|
||
8 years ago
|
|
||
8 years ago
|
Set the active skin to 'C<< foo >>'. Only pass the skin name, not the full path.
|
||
8 years ago
|
|
||
7 years ago
|
$anvil->Template->skin({set => "foo"});
|
||
8 years ago
|
|
||
8 years ago
|
Parameters;
|
||
|
|
||
|
=head3 fatal (optional)
|
||
|
|
||
|
If passed along with C<< set >>, the skin will be set even if the skin directory does not exit.
|
||
|
|
||
|
=head3 set (optional)
|
||
|
|
||
|
If passed a string, that will become the new active skin. If the skin directory does not exist, however, and C<< fatal >> is not set, the request will be ignored.
|
||
|
|
||
8 years ago
|
=cut
|
||
|
sub skin
|
||
|
{
|
||
|
my $self = shift;
|
||
|
my $parameter = shift;
|
||
7 years ago
|
my $anvil = $self->parent;
|
||
8 years ago
|
|
||
8 years ago
|
my $debug = 3;
|
||
|
my $fatal = defined $parameter->{fatal} ? $parameter->{fatal} : 1;
|
||
|
my $set = defined $parameter->{set} ? $parameter->{set} : "";
|
||
7 years ago
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { fatal => $fatal, set => $set }});
|
||
8 years ago
|
|
||
|
if ($set)
|
||
|
{
|
||
7 years ago
|
my $skin_directory = $anvil->data->{path}{directories}{skins}."/".$set;
|
||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { skin_directory => $skin_directory }});
|
||
8 years ago
|
if ((-d $skin_directory) or (not $fatal))
|
||
8 years ago
|
{
|
||
8 years ago
|
$self->{SKIN}{HTML} = $set;
|
||
7 years ago
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'SKIN::HTML' => $self->{SKIN}{HTML} }});
|
||
8 years ago
|
}
|
||
|
else
|
||
|
{
|
||
7 years ago
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "alert", key => "log_0031", variables => { set => $set, skin_directory => $skin_directory }});
|
||
8 years ago
|
}
|
||
|
}
|
||
|
|
||
7 years ago
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'SKIN::HTML' => $self->{SKIN}{HTML} }});
|
||
8 years ago
|
if (not $self->{SKIN}{HTML})
|
||
|
{
|
||
7 years ago
|
$self->{SKIN}{HTML} = $anvil->data->{defaults}{template}{html};
|
||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'SKIN::HTML' => $self->{SKIN}{HTML}, 'defaults::template::html' => $anvil->data->{defaults}{template}{html} }});
|
||
8 years ago
|
}
|
||
|
|
||
7 years ago
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'SKIN::HTML' => $self->{SKIN}{HTML} }});
|
||
8 years ago
|
return($self->{SKIN}{HTML});
|
||
|
}
|
||
|
|
||
|
# =head3
|
||
|
#
|
||
|
# Private Functions;
|
||
|
#
|
||
|
# =cut
|
||
|
|
||
|
#############################################################################################################
|
||
|
# Private functions #
|
||
|
#############################################################################################################
|
||
|
|
||
|
1;
|