package Tags::HTML::Page::Begin; use strict; use warnings; use Class::Utils qw(set_params); use Error::Pure qw(err); use List::MoreUtils qw(none); use Readonly; # Constants. Readonly::Hash my %LANG => ( 'title' => 'Page title', ); our $VERSION = 0.13; # Constructor. sub new { my ($class, @params) = @_; # Create object. my $self = bless {}, $class; # Application name. $self->{'application-name'} = undef; # Author. $self->{'author'} = undef; # Base element. $self->{'base_href'} = undef; $self->{'base_target'} = undef; # 'CSS::Struct' object. $self->{'css'} = undef; # CSS links. $self->{'css_src'} = []; # Charset. $self->{'charset'} = 'UTF-8'; # Description. $self->{'description'} = undef; # Doctype. $self->{'doctype'} = ''; # Favicon. $self->{'favicon'} = undef; # Generator. $self->{'generator'} = 'Perl module: '.__PACKAGE__.', Version: '.$VERSION; # HTML element lang attribute. $self->{'html_lang'} = 'en'; # http-equiv content-type. $self->{'http_equiv_content_type'} = 'text/html'; # Keywords. $self->{'keywords'} = undef; # Languages. $self->{'lang'} = \%LANG; # Refresh. $self->{'refresh'} = undef; # Robots. $self->{'robots'} = undef; # RSS $self->{'rss'} = undef; # Script js code. $self->{'script_js'} = []; # Script js sources. $self->{'script_js_src'} = []; # 'Tags' object. $self->{'tags'} = undef; # Viewport. $self->{'viewport'} = 'width=device-width, initial-scale=1.0'; # Process params. set_params($self, @params); # Check to 'Tags' object. if (! $self->{'tags'} || ! $self->{'tags'}->isa('Tags::Output')) { err "Parameter 'tags' must be a 'Tags::Output::*' class."; } # Check to 'CSS::Struct' object. if ($self->{'css'} && ! $self->{'css'}->isa('CSS::Struct::Output')) { err "Parameter 'css' must be a 'CSS::Struct::Output::*' class."; } # Check for 'css_src' array. if (ref $self->{'css_src'} ne 'ARRAY') { err "Parameter 'css_src' must be a array."; } foreach my $css_src_hr (@{$self->{'css_src'}}) { if (ref $css_src_hr ne 'HASH') { err "Parameter 'css_src' must be a array of hash structures."; } foreach my $key (keys %{$css_src_hr}) { if (none { $key eq $_ } qw(link media)) { err "Parameter 'css_src' must be a array of hash ". "structures with 'media' and 'link' keys." } } } # Check charset. if (! defined $self->{'charset'}) { err "Parameter 'charset' is required."; } # Check for 'script_js' array. if (ref $self->{'script_js'} ne 'ARRAY') { err "Parameter 'script_js' must be a array."; } # Check for 'script_js_src' array. if (ref $self->{'script_js_src'} ne 'ARRAY') { err "Parameter 'script_js_src' must be a array."; } # Check for favicon. if (defined $self->{'favicon'} && $self->{'favicon'} !~ m/\.(ico|png|jpg|gif|svg)$/ms) { err "Parameter 'favicon' contain bad image type."; } # Object. return $self; } # Process 'Tags'. sub process { my $self = shift; my $css; if ($self->{'css'}) { $css = $self->{'css'}->flush(1); if ($css ne '') { $css .= "\n"; } else { undef $css; } } # Begin of page. $self->{'tags'}->put( ['r', $self->{'doctype'}], ['r', "\n"], ['b', 'html'], ['a', 'lang', $self->{'html_lang'}], ['b', 'head'], ); if (defined $self->{'http_equiv_content_type'}) { $self->{'tags'}->put( ['b', 'meta'], ['a', 'http-equiv', 'Content-Type'], ['a', 'content', $self->{'http_equiv_content_type'}. '; charset='.$self->{'charset'}], ['e', 'meta'], ); } if (defined $self->{'base_href'}) { $self->{'tags'}->put( ['b', 'base'], ['a', 'href', $self->{'base_href'}], defined $self->{'base_target'} ? ( ['a', 'target', $self->{'base_target'}], ) : (), ['e', 'base'], ); } if (! defined $self->{'http_equiv_content_type'}) { $self->{'tags'}->put( ['b', 'meta'], ['a', 'charset', $self->{'charset'}], ['e', 'meta'], ); } $self->_meta('application-name'); $self->_meta('author'); $self->_meta('description'); $self->_meta('generator'); $self->_meta('keywords'); $self->_meta('robots'); $self->_meta('viewport'); if (defined $self->{'refresh'}) { $self->{'tags'}->put( ['b', 'meta'], ['a', 'http-equiv', 'refresh'], ['a', 'content', $self->{'refresh'}], ['e', 'meta'], ); } $self->_favicon; if (@{$self->{'script_js'}}) { foreach my $script_js (@{$self->{'script_js'}}) { $self->{'tags'}->put( ['b', 'script'], ['a', 'type', 'text/javascript'], ['d', $script_js], ['e', 'script'], ); } } if (@{$self->{'script_js_src'}}) { foreach my $script_js_src (@{$self->{'script_js_src'}}) { $self->{'tags'}->put( ['b', 'script'], ['a', 'type', 'text/javascript'], ['a', 'src', $script_js_src], ['e', 'script'], ); } } $self->{'tags'}->put( defined $self->{'lang'}->{'title'} ? ( ['b', 'title'], ['d', $self->{'lang'}->{'title'}], ['e', 'title'], ) : (), ( defined $css ? ( ['b', 'style'], ['a', 'type', 'text/css'], ['d', $css], ['e', 'style'], ) : (), ), ); if (@{$self->{'css_src'}}) { foreach my $css_src_hr (@{$self->{'css_src'}}) { $self->{'tags'}->put( ['b', 'link'], ['a', 'rel', 'stylesheet'], ['a', 'href', $css_src_hr->{'link'}], $css_src_hr->{'media'} ? ( ['a', 'media', $css_src_hr->{'media'}], ) : (), ['a', 'type', 'text/css'], ['e', 'link'], ); } } if (defined $self->{'rss'}) { $self->{'tags'}->put( ['b', 'link'], ['a', 'rel', 'alternate'], ['a', 'type', 'application/rss+xml'], ['a', 'title', 'RSS'], ['a', 'href', $self->{'rss'}], ['e', 'link'], ); } $self->{'tags'}->put( ['e', 'head'], ['b', 'body'], ); return; } sub _favicon { my $self = shift; if (! defined $self->{'favicon'}) { return; } my ($suffix) = $self->{'favicon'} =~ m/\.(ico|png|jpg|gif|svg)$/ms; my $image_type; if ($suffix eq 'ico') { $image_type = 'image/vnd.microsoft.icon'; } elsif ($suffix eq 'png') { $image_type = 'image/png'; } elsif ($suffix eq 'svg') { $image_type = 'image/svg+xml'; } elsif ($suffix eq 'gif') { $image_type = 'image/gif'; } else { $image_type = 'image/jpeg'; } $self->{'tags'}->put( ['b', 'link'], ['a', 'rel', 'icon'], ['a', 'href', $self->{'favicon'}], ['a', 'type', $image_type], ['e', 'link'], ); return; } sub _meta { my ($self, $key) = @_; if (! defined $self->{$key}) { return; } $self->{'tags'}->put( ['b', 'meta'], ['a', 'name', $key], ['a', 'content', $self->{$key}], ['e', 'meta'], ); return; } 1; __END__ =pod =encoding utf8 =head1 NAME Tags::HTML::Page::Begin - Tags helper for HTML page begin. =head1 SYNOPSIS use Tags::HTML::Page::Begin; my $obj = Tags::HTML::Page::Begin->new(%params); $obj->process; =head1 METHODS =head2 C my $obj = Tags::HTML::Page::Begin->new(%params); Constructor. =over 8 =item * C Application name. Default name is undef. =item * C Author name. Default value is undef. =item * C Base link (. Default value is undef. =item * C Base target. It's used in if 'base_href' parameter exists. Default value is undef. =item * C 'CSS::Struct::Output' object for L processing. Default value is undef. =item * C List of CSS link structures. Structure is something like: { 'link' => '/foo.css', 'media' => 'screen', } Default value is []. =item * C Document character set. Parameter is required. Default value is 'UTF-8'. =item * C Document description. Default value is undef. =item * C Document doctype string. Default value is ''. =item * C Favorite icon image link. Supported images are 'ICO', 'PNG', 'GIF', 'SVG' and 'JPG' files. Default value is undef. =item * C Generator value. Default value is 'Perl module: Tags::HTML::Page::Begin, Version: __MODULE_VERSION__'. =item * C HTML element lang attribute. Creates html element in form: Default value is 'en'. =item * C http-equiv content-type meta element. If defined creates meta in form: Unless defined creates meta in form: Defaut value is 'text/html'. =item * C Document keywords. Default value is undef. =item * C Hash with language information for output. Keys are: 'title'. Default value is reference to hash with these value: 'title' => 'Page title' =item * C Page refresh time in seconds. Default value is undef. =item * C Robots meta. Default value is undef. =item * C RSS link. Default value is undef. =item * C List of JavaScript scripts. Default value is reference to blank array. =item * C List of JavaScript links. Default value is reference to blank array. =item * C 'Tags::Output' object. It's required. Default value is undef. =item * C Document viewport. It's optional. Default value is 'width=device-width, initial-scale=1.0'. =back =head2 C $obj->process; Process Tags structure for output. Returns undef. =head1 ERRORS new(): Parameter 'css' must be a 'CSS::Struct::Output::*' class. Parameter 'css_src' must be a array. Parameter 'css_src' must be a array of hash structures. Parameter 'css_src' must be a array of hash structures with 'media' and 'link' keys. Parameter 'charset' is required. Parameter 'script_js' must be a array. Parameter 'script_js_src' must be a array. Parameter 'tags' must be a 'Tags::Output::*' class. From Class::Utils::set_params(): Unknown parameter '%s'. =head1 EXAMPLE1 use strict; use warnings; use CSS::Struct::Output::Indent; use Tags::HTML::Page::Begin; use Tags::HTML::Page::End; use Tags::Output::Indent; # Object. my $tags = Tags::Output::Indent->new( 'preserved' => ['style'], 'xml' => 1, ); my $css = CSS::Struct::Output::Indent->new; my $begin = Tags::HTML::Page::Begin->new( 'css' => $css, 'tags' => $tags, ); my $end = Tags::HTML::Page::End->new( 'tags' => $tags, ); # Process page $css->put( ['s', 'div'], ['d', 'color', 'red'], ['d', 'background-color', 'black'], ['e'], ); $begin->process; $tags->put( ['b', 'div'], ['d', 'Hello world!'], ['e', 'div'], ); $end->process; # Print out. print $tags->flush; # Output: # # # # # # # # Page title # # # # #
# Hello world! #
# # =head1 DEPENDENCIES L, L, L, L. =head1 SEE ALSO =over =item L Tags helper for HTML page end. =back =head1 REPOSITORY L =head1 AUTHOR Michal Josef Špaček L L =head1 LICENSE AND COPYRIGHT © Michal Josef Špaček 2020 BSD 2-Clause License =head1 VERSION 0.13 =cut