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.

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.

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