NAME

Tags::HTML::Tree - Tags helper for Tree.

SYNOPSIS

use Tags::HTML::Tree;

my $obj = Tags::HTML::Tree->new(%params);
$obj->cleanup;
$obj->init($tree);
$obj->prepare;
$obj->process;
$obj->process_css;

DESCRIPTION

Tags helper to print HTML page of tree structure defined by Tree instance.

The page contains clickable tree with usage of Javascript code.

Tree node value in HTML could be defined by 'cb_value' callback parameter.

METHODS

new

my $obj = Tags::HTML::Tree->new(%params);

Constructor.

  • cb_value

    Callback for Tree value, which call $self->{'tags'}->put for adding some value.

    Arguments of callback are Tags::HTML::Tree $self and $tree objects.

    Default value is subroutine:

    sub {
            my ($self, $tree) = @_;
            
            $self->{'tags'}->put(
                    ['d', $tree->value],
            );
            
            return;
    };

    which adds HTML text content with $tree->value value.

  • css

    'CSS::Struct::Output' object for process_css processing.

    Default value is undef.

  • no_css

    No CSS support flag. If this flag is set to 1, process_css() returns undef.

    Default value is 0.

  • tags

    'Tags::Output' object.

    Default value is undef.

cleanup

$obj->cleanup;

Cleanup module to init state.

Returns undef.

init

$obj->init($tree);

Set Tree instance defined by $tree to object.

Returns undef.

prepare

$obj->prepare;

Process initialization before page run.

Preparing is about adding javascript used in helper to "script_js" in Tags::HTML method.

Returns undef.

process

$obj->process;

Process Tags structure for output with message.

Returns undef.

process_css

$obj->process_css;

Process CSS::Struct structure for output.

Returns undef.

ERRORS

new():
        From Class::Utils::set_params():
                Unknown parameter '%s'.
        From Mo::utils::check_code():
                Parameter 'cb_value' must be a code.
                        Value: %s
        From Mo::utils::check_required():
                Parameter 'css_class' is required.
        From Mo::utils::CSS::check_css_class():
                Parameter 'css_class' has bad CSS class name.
                        Value: %s
                Parameter 'css_class' has bad CSS class name (number on begin).
                        Value: %s
        From Mo::utils::CSS::check_css_unit():
                Parameter 'indent' contain bad unit.
                        Unit: %s
                        Value: %s
                Parameter 'indent' doesn't contain unit name.
                        Value: %s
                Parameter 'indent' doesn't contain unit number.
                        Value: %s
        From Tags::HTML::new():
                Parameter 'tags' must be a 'Tags::Output::*' class.
        Parameter 'css_class' is required.

init():
        Data object must be a 'Tree' instance.

process():
        From Tags::HTML::process():
                Parameter 'tags' isn't defined.

EXAMPLE1

use strict;
use warnings;

use CSS::Struct::Output::Raw;
use Tags::HTML::Tree;
use Tags::HTML::Page::Begin;
use Tags::HTML::Page::End;
use Tags::Output::Raw;
use Tree;
use Unicode::UTF8 qw(decode_utf8 encode_utf8);

my $css = CSS::Struct::Output::Raw->new;
my $tags = Tags::Output::Raw->new(
        'preserved' => ['style', 'script'],
        'xml' => 1,
);

my $tags_tree = Tags::HTML::Tree->new(
        'css' => $css,
        'tags' => $tags,
);
$tags_tree->prepare;

my $begin = Tags::HTML::Page::Begin->new(
        'author' => decode_utf8('Michal Josef Špaček'),
        'css' => $css,
        'generator' => 'Tags::HTML::Tree',
        'lang' => {
                'title' => 'Tree',
        },
        'script_js' => $tags_tree->script_js,
        'tags' => $tags,
);
my $end = Tags::HTML::Page::End->new(
        'tags' => $tags,
);

# Example tree object.
my $tree = Tree->new('Root');
$tree->meta({'uid' => 0});
my $count = 0;
my %node;
foreach my $node_string (qw/H I J K L M N O P Q/) {
         $node{$node_string} = Tree->new($node_string);
         $node{$node_string}->meta({'uid' => ++$count});
}
$tree->add_child($node{'H'});
$node{'H'}->add_child($node{'I'});
$node{'I'}->add_child($node{'J'});
$node{'H'}->add_child($node{'K'});
$node{'H'}->add_child($node{'L'});
$tree->add_child($node{'M'});
$tree->add_child($node{'N'});
$node{'N'}->add_child($node{'O'});
$node{'O'}->add_child($node{'P'});
$node{'P'}->add_child($node{'Q'});

# Init.
$tags_tree->init($tree);

# Process CSS.
$tags_tree->process_css;

# Process HTML.
$begin->process;
$tags_tree->process;
$end->process;

# Print out.
print encode_utf8($tags->flush);

# Output:
# <!DOCTYPE html>
# <html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><meta name="author" content="Michal Josef Špaček" /><meta name="generator" content="Tags::HTML::Tree" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><script type="text/javascript">
# window.addEventListener('load', (event) => {
#     let toggler = document.getElementsByClassName("caret");
#     for (let i = 0; i < toggler.length; i++) {
#         toggler[i].addEventListener("click", function() {
#             this.parentElement.querySelector(".nested").classList.toggle("active");
#             this.classList.toggle("caret-down");
#         });
#     }
# });
# </script><title>Tree</title><style type="text/css">
# ul, .tree{list-style-type:none;padding-left:2em;}.caret{cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;}.caret::before{content:"⯈";color:black;display:inline-block;margin-right:6px;}.caret-down::before{transform:rotate(90deg);}.nested{display:none;}.active{display:block;}
# </style></head><body><ul class="tree"><li><span class="caret">Root</span><ul class="nested"><li><span class="caret">H</span><ul class="nested"><li><span class="caret">I</span><ul class="nested"><li>J</li></ul></li><li>K</li><li>L</li></ul></li><li>M</li><li><span class="caret">N</span><ul class="nested"><li><span class="caret">O</span><ul class="nested"><li><span class="caret">P</span><ul class="nested"><li>Q</li></ul></li></ul></li></ul></li></ul></li></ul></body></html>

EXAMPLE2

use strict;
use warnings;

use CSS::Struct::Output::Indent;
use Tags::HTML::Tree;
use Tags::HTML::Page::Begin;
use Tags::HTML::Page::End;
use Tags::Output::Indent;
use Tree;
use Unicode::UTF8 qw(decode_utf8 encode_utf8);

my $css = CSS::Struct::Output::Indent->new;
my $tags = Tags::Output::Indent->new(
        'preserved' => ['style', 'script'],
        'xml' => 1,
);

my $tags_tree = Tags::HTML::Tree->new(
        'css' => $css,
        'tags' => $tags,
);
$tags_tree->prepare;

my $begin = Tags::HTML::Page::Begin->new(
        'author' => decode_utf8('Michal Josef Špaček'),
        'css' => $css,
        'generator' => 'Tags::HTML::Tree',
        'lang' => {
                'title' => 'Tree',
        },
        'script_js' => $tags_tree->script_js,
        'tags' => $tags,
);
my $end = Tags::HTML::Page::End->new(
        'tags' => $tags,
);

# Example tree object.
my $tree = Tree->new('Root');
$tree->meta({'uid' => 0});
my $count = 0;
my %node;
foreach my $node_string (qw/H I J K L M N O P Q/) {
         $node{$node_string} = Tree->new($node_string);
         $node{$node_string}->meta({'uid' => ++$count});
}
$tree->add_child($node{'H'});
$node{'H'}->add_child($node{'I'});
$node{'I'}->add_child($node{'J'});
$node{'H'}->add_child($node{'K'});
$node{'H'}->add_child($node{'L'});
$tree->add_child($node{'M'});
$tree->add_child($node{'N'});
$node{'N'}->add_child($node{'O'});
$node{'O'}->add_child($node{'P'});
$node{'P'}->add_child($node{'Q'});

# Init.
$tags_tree->init($tree);

# Process CSS.
$tags_tree->process_css;

# Process HTML.
$begin->process;
$tags_tree->process;
$end->process;

# Print out.
print encode_utf8($tags->flush);

# Output:
# <!DOCTYPE html>
# <html lang="en">
#   <head>
#     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
#     <meta name="author" content="Michal Josef Špaček" />
#     <meta name="generator" content="Tags::HTML::Tree" />
#     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
#     <script type="text/javascript">
# window.addEventListener('load', (event) => {
#     let toggler = document.getElementsByClassName("caret");
#     for (let i = 0; i < toggler.length; i++) {
#         toggler[i].addEventListener("click", function() {
#             this.parentElement.querySelector(".nested").classList.toggle("active");
#             this.classList.toggle("caret-down");
#         });
#     }
# });
# </script>    <title>
#       Tree
#     </title>
#     <style type="text/css">
# ul, .tree {
# 	list-style-type: none;
# 	padding-left: 2em;
# }
# .caret {
# 	cursor: pointer;
# 	-webkit-user-select: none;
# 	-moz-user-select: none;
# 	-ms-user-select: none;
# 	user-select: none;
# }
# .caret::before {
# 	content: "⯈";
# 	color: black;
# 	display: inline-block;
# 	margin-right: 6px;
# }
# .caret-down::before {
# 	transform: rotate(90deg);
# }
# .nested {
# 	display: none;
# }
# .active {
# 	display: block;
# }
# </style>
#   </head>
#   <body>
#     <ul class="tree">
#       <li>
#         <span class="caret">
#           Root
#         </span>
#         <ul class="nested">
#           <li>
#             <span class="caret">
#               H
#             </span>
#             <ul class="nested">
#               <li>
#                 <span class="caret">
#                   I
#                 </span>
#                 <ul class="nested">
#                   <li>
#                     J
#                   </li>
#                 </ul>
#               </li>
#               <li>
#                 K
#               </li>
#               <li>
#                 L
#               </li>
#             </ul>
#           </li>
#           <li>
#             M
#           </li>
#           <li>
#             <span class="caret">
#               N
#             </span>
#             <ul class="nested">
#               <li>
#                 <span class="caret">
#                   O
#                 </span>
#                 <ul class="nested">
#                   <li>
#                     <span class="caret">
#                       P
#                     </span>
#                     <ul class="nested">
#                       <li>
#                         Q
#                       </li>
#                     </ul>
#                   </li>
#                 </ul>
#               </li>
#             </ul>
#           </li>
#         </ul>
#       </li>
#     </ul>
#   </body>
# </html>

EXAMPLE3

use strict;
use warnings;

use CSS::Struct::Output::Indent;
use Plack::App::Tags::HTML;
use Plack::Runner;
use Tags::HTML::Tree;
use Tags::Output::Indent;
use Tree;

# Example tree object.
my $data_tree = Tree->new('Root');
my %node;
foreach my $node_string (qw/H I J K L M N O P Q/) {
         $node{$node_string} = Tree->new($node_string);
}
$data_tree->add_child($node{'H'});
$node{'H'}->add_child($node{'I'});
$node{'I'}->add_child($node{'J'});
$node{'H'}->add_child($node{'K'});
$node{'H'}->add_child($node{'L'});
$data_tree->add_child($node{'M'});
$data_tree->add_child($node{'N'});
$node{'N'}->add_child($node{'O'});
$node{'O'}->add_child($node{'P'});
$node{'P'}->add_child($node{'Q'});

my $css = CSS::Struct::Output::Indent->new;
my $tags = Tags::Output::Indent->new(
        'xml' => 1,
        'preserved' => ['script', 'style'],
);
my $app = Plack::App::Tags::HTML->new(
        'component' => 'Tags::HTML::Tree',
        'data_init' => [$data_tree],
        'css' => $css,
        'tags' => $tags,
)->to_app;
Plack::Runner->new->run($app);

# Output screenshot is in images/ directory.
Web app example

EXAMPLE4

use strict;
use warnings;

use CSS::Struct::Output::Indent;
use Plack::App::Tags::HTML;
use Plack::Runner;
use Tags::HTML::Tree;
use Tags::Output::Indent;
use Tree;

# Example tree object.
my $data_tree = Tree->new('Root');
$data_tree->meta({'color' => 'orange'});
my %node;
foreach my $node_string (qw/H I J K L M N O P Q/) {
         $node{$node_string} = Tree->new($node_string);
}
$data_tree->add_child($node{'H'});
$node{'H'}->meta({'color' => 'red'});
$node{'H'}->add_child($node{'I'});
$node{'I'}->add_child($node{'J'});
$node{'J'}->meta({'color' => 'green'});
$node{'H'}->add_child($node{'K'});
$node{'H'}->add_child($node{'L'});
$data_tree->add_child($node{'M'});
$data_tree->add_child($node{'N'});
$node{'N'}->add_child($node{'O'});
$node{'O'}->add_child($node{'P'});
$node{'O'}->meta({'color' => 'blue'});
$node{'P'}->add_child($node{'Q'});

my $css = CSS::Struct::Output::Indent->new;
my $tags = Tags::Output::Indent->new(
        'xml' => 1,
        'preserved' => ['script', 'style'],
);
my $app = Plack::App::Tags::HTML->new(
        'component' => 'Tags::HTML::Tree',
        'constructor_args' => {
                'cb_value' => sub {
                        my ($self, $tree) = @_;

                        if (exists $tree->meta->{'color'}) {
                                $self->{'tags'}->put(
                                        ['b', 'span'],
                                        ['a', 'style', 'color:'.$tree->meta->{'color'}.';'],
                                );
                        }
                        $self->{'tags'}->put(
                                ['d', $tree->value],
                        );
                        if (exists $tree->meta->{'color'}) {
                                $self->{'tags'}->put(
                                        ['e', 'span'],
                                );
                        }

                        return;
                },
        },
        'data_init' => [$data_tree],
        'css' => $css,
        'tags' => $tags,
)->to_app;
Plack::Runner->new->run($app);

# Output screenshot is in images/ directory.
Web app example

DEPENDENCIES

Class::Utils, English, Error::Pure, Mo::utils, Mo::utils::CSS, Scalar::Util, Unicode::UTF8, Tags::HTML.

REPOSITORY

https://github.com/michal-josef-spacek/Tags-HTML-Tree

AUTHOR

Michal Josef Špaček mailto:skim@cpan.org

http://skim.cz

LICENSE AND COPYRIGHT

© 2024 Michal Josef Špaček

BSD 2-Clause License

VERSION

0.07