
=encoding UTF-8

=head1 NAME

HTML::Make - A flexible HTML generator

=head1 SYNOPSIS

    
    # Make a table.
    use HTML::Make;
    my $table = HTML::Make->new ('table');
    # Can add elements as text
    $table->add_text ('<tr><th>Item<th>Cost');
    my %items = (
        compressor => 12800,
        heater => 'free',
        camera => 1080,
    );
    for my $k (sort keys %items) {
        # Add an element using "push". The return value is the new element.
        my $tr = $table->push ('tr');
        # Can add element to $tr using "push"
        $tr->push ('td', text => $k);
        # Can also make a new element then "push" it.
        my $td = HTML::Make->new ('td', text => $items{$k},
                                  attr => {style => 'padding:1em'});
        $tr->push ($td);
    }
    # Get the output
    print $table->text ();


produces output

    <table>
    <tr><th>Item<th>Cost<tr>
    <td>camera</td>
    <td style="padding:1em">1080</td>
    </tr>
    <tr>
    <td>compressor</td>
    <td style="padding:1em">12800</td>
    </tr>
    <tr>
    <td>heater</td>
    <td style="padding:1em">free</td>
    </tr>
    </table>


=begin html

<p>As HTML this looks like this:</p>

<table>
<tr><th>Item<th>Cost<tr>
<td>camera</td>
<td style="padding:1em">1080</td>
</tr>
<tr>
<td>compressor</td>
<td style="padding:1em">12800</td>
</tr>
<tr>
<td>heater</td>
<td style="padding:1em">free</td>
</tr>
</table>


=end html

(This example is included as L<F<synopsis.pl>|https://fastapi.metacpan.org/source/BKB/HTML-Make-0.12/examples/synopsis.pl> in the distribution.)  

=head1 VERSION

This documents HTML::Make version 0.12 corresponding to git
commit L<2419de0d9bc9ccdec56ae906b625162e111dd639|https://github.com/benkasminbullock/HTML-Make/commit/2419de0d9bc9ccdec56ae906b625162e111dd639>
released on Fri Jan 1 23:43:22 2021 +0900.

=head1 DESCRIPTION

HTML::Make is an HTML generator. It generates HTML fragments, such as
HTML lists or tables, rather than complete HTML pages.

=head1 METHODS

=head2 add_attr

    $obj->add_attr (class => 'buggles');

Add attributes to C<$obj>. The following adds a class "beano" to the
"li" element:

    
    use HTML::Make;
    my $obj = HTML::Make->new ('li');
    $obj->add_attr (class => 'beano');
    print $obj->text ();
    
    


produces output

    <li class="beano"></li>


(This example is included as L<F<li-class-beano.pl>|https://fastapi.metacpan.org/source/BKB/HTML-Make-0.12/examples/li-class-beano.pl> in the distribution.)  

This issues a warning of the form B<"Overwriting attribute 'class' for
'p'"> if the object already contains an attribute of the specified
type.

    
    use HTML::Make;
    my $p = HTML::Make->new ('p', attr => {class => 'big'});
    $p->add_attr (class => 'small');
    


produces output

    Overwriting attribute 'class' for 'p' tag at /usr/home/ben/projects/html-make/examples/p-double-class.pl line 6.


(This example is included as L<F<p-double-class.pl>|https://fastapi.metacpan.org/source/BKB/HTML-Make-0.12/examples/p-double-class.pl> in the distribution.)  

This also issues a warning if the attribute is not valid for the tag,
according to L<HTML::Valid::Tagset/tag_attr_ok>. This is restricted to
what is valid in HTML5.

=head2 add_comment

    $element->add_comment ('This should be fixed!');

Add an HTML comment to the element.

=head2 add_text

    $element->add_text ('buggles');

Add text to C<$element>. For example,

    my $element = HTML::Make->new ('p');
    $element->add_text ('peanuts');
    print $element->text ();
    # <p>peanuts</p>

The text may contain HTML elements:

    my $element = HTML::Make->new ('p');
    $element->add_text ('peanuts <i>eggs</i>');
    print $element->text ();
    # <p>peanuts <i>eggs</i></p>

The return value is the added text object.

=head2 multiply

    my @elements = $obj->multiply ('li', \@contents);

Given an HTML tag type as the first argument, and an array reference
as the second argument, this adds multiple child elements to C<$obj>
of type given by the first argument, with text contents given by
C<\@contents>.

    
    use HTML::Make;
    my $ol = HTML::Make->new ('ol');
    $ol->multiply ('li', ['one', 'two', 'three']);
    print $ol->text ();


produces output

    <ol>
    <li>one</li>
    <li>two</li>
    <li>three</li>
    </ol>


=begin html

<p>As HTML this looks like this:</p>

<ol>
<li>one</li>
<li>two</li>
<li>three</li>
</ol>


=end html

(This example is included as L<F<multiply.pl>|https://fastapi.metacpan.org/source/BKB/HTML-Make-0.12/examples/multiply.pl> in the distribution.)  

=head2 new

    my $element = HTML::Make->new ('li');

Make a new HTML element of the specified type.

To add attributes to the element, use

    my $element = HTML::Make->new ('li', attr => {class => 'biglist'});

To add text,

    my $element = HTML::Make->new ('li', text => "White punks on dope");

Both attributes and text may be added:

    my $element = HTML::Make->new ('li', attr => {id => 'ok'}, text => 'OK');

HTML::Make checks the element against a list of known HTML tags from
L</HTML::Valid::Tagset>, and warns if the first argument is not on
this list. To switch off this behaviour and allow arbitrary tags, use
the C<nocheck> option:

    
    use HTML::Make;
    my $freaky = HTML::Make->new ('freaky', nocheck => 1);
    $freaky->push ('franky', nocheck => 1, text => 'Visible man');
    print $freaky->text ();
    


produces output

    <freaky><franky>Visible man</franky>
    </freaky>


(This example is included as L<F<nocheck.pl>|https://fastapi.metacpan.org/source/BKB/HTML-Make-0.12/examples/nocheck.pl> in the distribution.)  

=head2 opening_tag

    my $tag = $obj->opening_tag ();

Returns the text value of the HTML tag opening, complete with
attributes. There is no "closing_tag" method, the module just prints
"</$tag>" within the L</text> method.

=head2 push

    my $child = $element->push ('tag');

Add child element of type <tag> to C<$element> and return the result
as a new C<HTML::Make> object. For example,

    
    use utf8;
    use HTML::Make;
    my $table = HTML::Make->new ('table');
    my $row = $table->push ('tr');
    my $cell = $row->push ('td', text => 'Cell');
    print $table->text ();
    
    


produces output

    <table>
    <tr>
    <td>Cell</td>
    </tr>
    </table>


(This example is included as L<F<table.pl>|https://fastapi.metacpan.org/source/BKB/HTML-Make-0.12/examples/table.pl> in the distribution.)  

C<push> takes all of the same arguments as L</new>, for example:

    
    use HTML::Make;
    my $element = HTML::Make->new ('p', text => 'Here is a ');
    $element->push ('a', attr => {href => 'http://www.example.org/'}, text => 'link to example');
    print $element->text ();
    


produces output

    <p>
    Here is a <a href="http://www.example.org/">
    link to example</a>
    </p>


=begin html

<p>As HTML this looks like this:</p>

<p>
Here is a <a href="http://www.example.org/">
link to example</a>
</p>


=end html

(This example is included as L<F<link-example.pl>|https://fastapi.metacpan.org/source/BKB/HTML-Make-0.12/examples/link-example.pl> in the distribution.)  

=head3 Making a colourful list

An object created with HTML::Make may also be pushed:

    
    use utf8;
    use HTML::Make;
    my @colours = (
        daidai => 0xEE7800,
        murasaki => 0x884898,
        kimidori => 0xB9C42F,
        kogecha => 0x6A4D32,
        uguisuiro => 0x838B0D,
    );
    my $ul = HTML::Make->new ('ul');
    while (@colours) {
        my $colour = shift @colours;
        my $rgb = shift @colours;
        # Here we make a new element and then push it into $ul, rather
        # than using the return value of $ul->push ().
        my $li = HTML::Make->new (
            'li', text => $colour,
            attr => {
                style => sprintf ("background: #%06X", $rgb),
            });
        $ul->push ($li);
    }
    print $ul->text ();


produces output

    <ul>
    <li style="background: #EE7800">daidai</li>
    <li style="background: #884898">murasaki</li>
    <li style="background: #B9C42F">kimidori</li>
    <li style="background: #6A4D32">kogecha</li>
    <li style="background: #838B0D">uguisuiro</li>
    </ul>


=begin html

<p>As HTML this looks like this:</p>

<ul>
<li style="background: #EE7800">daidai</li>
<li style="background: #884898">murasaki</li>
<li style="background: #B9C42F">kimidori</li>
<li style="background: #6A4D32">kogecha</li>
<li style="background: #838B0D">uguisuiro</li>
</ul>


=end html

(This example is included as L<F<push-new.pl>|https://fastapi.metacpan.org/source/BKB/HTML-Make-0.12/examples/push-new.pl> in the distribution.)  

See also L<Make a list of colours with
HTML::Make|https://www.lemoda.net/perl/colour-list/index.html>.

=head3 JSON to HTML

This script converts arbitrary JSON to HTML:

    
    use utf8;
    use JSON::Parse 'parse_json';
    use HTML::Make;
    my $json =<<EOF;
    {"words":[{"j_pron_only":"パイプ","word":"pipe"},{"word":"cutting","j_pron_only":"カティング"},{"word":"implement","j_pron_only":"インプリムント"}]}
    EOF
    my $p = parse_json ($json);
    my $html = json_to_html ($p);
    print $html->text ();
    exit;
    
    sub json_to_html
    {
        my ($input) = @_;
        my $element;
        if (ref $input eq 'ARRAY') {
            $element = HTML::Make->new ('ol');
            for my $k (@$input) {
                my $li = $element->push ('li');
                $li->push (json_to_html ($k));
            }
        }
        elsif (ref $input eq 'HASH') {
            $element = HTML::Make->new ('table');
            for my $k (sort keys %$input) {
                my $tr = $element->push ('tr');
                $tr->push ('th', text => $k);
                my $td = $tr->push ('td');
                $td->push (json_to_html ($input->{$k}));
            }
        }
        else {
            $element = HTML::Make->new ('span', text => $input);
        }
        return $element;
    }


produces output

    <table>
    <tr>
    <th>words</th>
    <td><ol>
    <li><table>
    <tr>
    <th>j_pron_only</th>
    <td><span>パイプ</span>
    </td>
    </tr>
    <tr>
    <th>word</th>
    <td><span>pipe</span>
    </td>
    </tr>
    </table>
    </li>
    <li><table>
    <tr>
    <th>j_pron_only</th>
    <td><span>カティング</span>
    </td>
    </tr>
    <tr>
    <th>word</th>
    <td><span>cutting</span>
    </td>
    </tr>
    </table>
    </li>
    <li><table>
    <tr>
    <th>j_pron_only</th>
    <td><span>インプリムント</span>
    </td>
    </tr>
    <tr>
    <th>word</th>
    <td><span>implement</span>
    </td>
    </tr>
    </table>
    </li>
    </ol>
    </td>
    </tr>
    </table>


=begin html

<p>As HTML this looks like this:</p>

<table>
<tr>
<th>words</th>
<td><ol>
<li><table>
<tr>
<th>j_pron_only</th>
<td><span>パイプ</span>
</td>
</tr>
<tr>
<th>word</th>
<td><span>pipe</span>
</td>
</tr>
</table>
</li>
<li><table>
<tr>
<th>j_pron_only</th>
<td><span>カティング</span>
</td>
</tr>
<tr>
<th>word</th>
<td><span>cutting</span>
</td>
</tr>
</table>
</li>
<li><table>
<tr>
<th>j_pron_only</th>
<td><span>インプリムント</span>
</td>
</tr>
<tr>
<th>word</th>
<td><span>implement</span>
</td>
</tr>
</table>
</li>
</ol>
</td>
</tr>
</table>


=end html

(This example is included as L<F<json-to-html.pl>|https://fastapi.metacpan.org/source/BKB/HTML-Make-0.12/examples/json-to-html.pl> in the distribution.)  

See also L<Convert JSON to HTML with JSON::Parse and
HTML::Make|https://www.lemoda.net/perl/json-to-html/index.html>.

=head3 There are some ad-hoc guardrails

This warns if you add some types of elements to possibly inappropriate
parent elements. For example if you add an <li> tag to a <tr> it
reacts like this:

    
    use HTML::Make;
    my $tr = HTML::Make->new ('tr');
    $tr->push ('li');


produces output

    Pushing non-table element <li> to a table row at /usr/home/ben/projects/html-make/examples/push-li-to-tr.pl line 6.


(This example is included as L<F<push-li-to-tr.pl>|https://fastapi.metacpan.org/source/BKB/HTML-Make-0.12/examples/push-li-to-tr.pl> in the distribution.)  

I've never received a single bug report for this module, and so these
warnings are mostly added in an ad-hoc fashion as I've found myself
making various mistakes. If you find yourself tripping over some kind
of error repeatedly, then feel free to ask me to add that to this
module.

=head2 text

    $element->text ();

This returns the element and its child elements as text, so usually
this is called at the final stage.

=head1 OUTPUT FORMAT

This section discusses the way that HTML is output by the module.

=head2 Whitespace

=over

=item Indentation

The output HTML is not indented.

=item New lines

New lines are added after block-level elements, according to L<HTML::Valid::Tagset/%isBlock>, and after <tr> elements.

=back

=head1 BUGS

This module assumes you want to make HTML5.

There is no way to control the whitespace in the output HTML such as
indentation.

=head1 DEPENDENCIES

This module depends on the following Perl modules.

=over

=item Carp

L<Carp> is used to report errors.

=item HTML::Valid::Tagset

L<HTML::Valid::Tagset> is used to validate tags and tag/attribute pairs.

=back

=head1 SEE ALSO

=head2 CPAN modules

These are the other modules I've found on CPAN (one is only on
sourceforge) which generate HTML programmatically, rather than by
template substitution.

=over

=item L<CGI>

The CGI module contains HTML generation. See also
L<CGI::HTML::Functions>.

=item L<HTML::Builder>

=item L<HTML::Declare>

An HTML mini-language.

=item L<HTML::FromArrayref>

Output HTML described by a Perl data structure

=item L<HTML::Generator|http://cleancode.sourceforge.net/api/perl/HTML/Generator.html>

This project is on the SourceForge site, not CPAN.

=item L<HTML::HTML5::Builder>

"erect some scaffolding for your documents"

=item L<HTML::Native>

Generate and manipulate HTML as native Perl data structures

=item L<HTML::TagTree>

An HTML generator via a tree of 'tag' objects

=item L<HTML::Template>

An HTML-like templating language.

=item L<HTML::Tiny>

This is similar to the HTML generation which is in L<CGI>. Its last
update, version 1.05, was in 2009, and it doesn't include HTML5 tags.

=item L<HTML::Untidy>

=back

=head2 HTML validator

My L<HTML validator is on
github|https://github.com/benkasminbullock/html-validate>. This is in
the Go language, not in Perl.




=head1 AUTHOR

Ben Bullock, <bkb@cpan.org>

=head1 COPYRIGHT & LICENCE

This package and associated files are copyright (C) 
2012-2021
Ben Bullock.

You can use, copy, modify and redistribute this package and associated
files under the Perl Artistic Licence or the GNU General Public
Licence.



