package HTML::Menu::Select; use 5.004; use strict; use Carp 'carp'; our $VERSION = '1.01'; require Exporter; our @ISA = qw( Exporter ); our @EXPORT_OK = qw( options menu popup_menu ); our %EXPORT_TAGS = ( all => \@EXPORT_OK ); our @KNOWN_KEYS = qw( name value values default defaults labels attributes size multiple override ); sub popup_menu { &menu }; sub menu { my %arg = (ref $_[0]) ? %{$_[0]} : @_; my $html = ''; $arg{name} = '' if not exists $arg{name}; $html = sprintf '<select name="%s"', _escapeHTML( $arg{name} ); for my $key (keys %arg) { if (! grep {$key eq $_} @KNOWN_KEYS) { $html .= sprintf ' %s="%s"', $key, _escapeHTML( $arg{$key} ); } } $html .= ">\n"; $html .= options(%arg); $html .= "</select>\n"; return $html; } sub options { my %arg = (ref $_[0]) ? %{$_[0]} : @_; my $html = ''; # aliases for (qw/ value default /) { $arg{$_} = $arg{"${_}s"} if exists $arg{"${_}s"}; $arg{$_} = [$arg{$_}] if exists $arg{$_} && ! ref $arg{$_}; } # don't support CGI.pm's 'override' argument if (exists $arg{override}) { carp "CGI.pm's 'override' argument is not supported by HTML::Menu::Select"; } for my $option (@{ $arg{value} }) { $html .= '<option '; for my $default (@{ $arg{default} }) { if ($option eq $default) { $html .= 'selected="selected" '; } } for my $att (keys %{ $arg{attributes} }) { if ($att eq $option) { for (keys %{ $arg{attributes}{$att} }) { $html .= sprintf '%s="%s" ', $_, _escapeHTML( $arg{attributes}{$att}{$_} ); } } } $html .= sprintf 'value="%s">', _escapeHTML( $option ); if (exists $arg{labels} && exists $arg{labels}{$option}) { $html .= _escapeHTML( $arg{labels}{$option} ); } else { $html .= _escapeHTML( $option ); } $html .= '</option>'; $html .= "\n"; } return $html; } sub _escapeHTML { my ($escape) = (@_); return unless defined $escape; if (exists $::INC{'CGI.pm'}) { return CGI::escapeHTML( $escape ); } elsif (exists $::INC{'CGI/Simple/Util.pm'}) { return CGI::Simple::Util::escapeHTML( $escape ); } elsif (exists $::INC{'HTML/Entities.pm'}) { return HTML::Entities::encode_entities( $escape ); } elsif (exists $::INC{'Apache/Util.pm'}) { return Apache::Util::escape_html( $escape ); } # looks like nothing's already loaded to do it for us $escape =~ s/&/&/gs; $escape =~ s/</</gs; $escape =~ s/>/>/gs; $escape =~ s/"/"/gs; return $escape; } 1; __END__ =head1 NAME HTML::Menu::Select - Create HTML for select menus to simplify your templates. =head1 SYNOPSIS use HTML::Menu::Select qw( menu options ); my $html = menu( name => 'myMenu', values => [ 'yes', 'no' ], ); $tmpl->param( select_menu => $html ); =head1 DESCRIPTION This modules creates HTML for form C<select> items. Traditionally, if you wanted to dynamically generate a list of options in a C<select> menu, you would either have to use CGI's HTML generation routines, or use a complicated template such as this: <select name="day"> <TMPL_LOOP day> <option value="<TMPL_VAR value>" <TMPL_VAR selected>> <TMPL_VAR label> </option> </TMPL_LOOP> </select> This module allows you to quickly prototype a page, allowing the CGI to completely generate the HTML, while allowing you at a later stage to easily change how much HTML it generates. =head1 INSTALLATION To install this module, run the following commands: perl Makefile.PL make make test make install Alternatively, to install with Module::Build, you can use the following commands: perl Build.PL ./Build ./Build test ./Build install =head1 METHODS =head2 menu() Use C<menu()> to generate the entire HTML for a select menu. This allows you to have a very simple template tag, such as: <TMPL_VAR select_menu> C<menu()> accepts the following parameters: =over =item name This is used in the C<select> tag's C<name=""> attribute. The name value will be run through escapeHTML(), see L<"HTML escaping">. =item values This is an array-ref of values used for each of the C<option> tags. The values will be run through escapeHTML, see L<"HTML escaping">. =item default This selects which (if any) C<option> tag should have a C<selected="selected"> attribute. =item labels This is a hash-ref of values to provide different values for the user-visible label of each C<option> tag. Each key should match a value provided by the C<values> parameter. If this parameter is not provided, or for any C<value> which doesn't have a matching key here, the user-visible label will be the C<option>'s C<value>. print menu( values => [1, 2], labels => { 1 => 'one'}, 2 => 'two'}, }, ); # will output <select name=""> <option name="1">one</option> <option name="2">two</option> </select> The labels will be run through escapeHTML, see L<"HTML escaping">. =item attributes This is a hash-ref of values to provide extra HTML attributes for the C<option> tags. Like the C<labels> parameter, the keys should match a value provided by the c<values> parameter. Each value of this hash-ref should be a hash-ref representing the name and value of a HTML attribute. print menu( values => ['one', 'two'], attributes => { one => {onSubmit => 'do(this);'}, two => {style => 'color: #000;'}, }, ); # will output <select name=""> <option onSubmit="do(this);" name="one">one</option> <option style="color: #000;" name="two">two</option> </select> All attribute values (but not the attribute name) will be run through escapeHTML, see L<"HTML escaping">. =item value An alias for C<value>. =item defaults An alias for C<default>. =back All parameters are optional, though it doesn't make much sense to not provide anything for C<values>. Any unrecognised parameters will be used to provide extra HTML attributes for the C<select> tag. For example: print menu( id => 'myID', values => ['one'], onChange => 'do(this);', ); # will output <select name="" id="myID" onChange="do(this);"> <option name="one">one</option> </select> All attribute values (but not the attribute name) will be run through escapeHTML, see L<"HTML escaping">. =head2 options() Use C<options()> to generate the HTML for only the C<option> tags, allowing you to keep the outer C<select> tag in the template, so that, for example, a designer can easily make changes to the CSS or JavaScript handlers. You would have something like the following in your template: <select name="day"> <TMPL_VAR menu_options> </select> C<options()> accepts the same parameters as L<"menu()">, but the C<name> parameter is ignored. =head2 popup_menu() C<popup_menu()> is an alias for L<"menu()"> for those familiar with CGI. =head1 HTML escaping If any of the following modules are already loaded into memory, their own escapeHTML (or equivalent) method will be used =over =item CGI =item CGI::Simple =item HTML::Entities =item Apache::Util =back Otherwise the following characters will be escaped & < > " =head1 CGI.pm COMPATABILITY =over =item Arguments may be passed as a hash-reference, rather than a hash. This allows compile time checking, rather than runtime. popup_menu( name => $name ); # OR popup_menu( {name => $name} ); =back Arguments to the L<"menu()">, L<"options()"> and L<"popup_menu()"> functions are similar to CGI.pm's, excepting the following differences. =over =item Named arguments should not have a leading dash popup_menu( name => $name ); # NOT # popup_menu( -name => $name ); =item Positional arguments are not supported popup_menu( name => $name, labels => \@labels ); # NOT # popup_menu( $name, \@labels ); =item Attribute names not lowercased An argument to CGI.pm's popup_menu such as C<-onChange => 'check()'> will output the HTML C<onchange="check()">. This module will retain the case, outputting C<onChange="check()">. =item The C<optgroup> function is not yet supported =back =head1 SUPPORT / BUGS Please log bugs, feature requests and patch submissions at L<http://sourceforge.net/projects/html-menu>. Support mailing list: html-menu-users@lists.sourceforge.net =head1 SEE ALSO HTML::Menu::DateTime, HTML::Template, Template, Template::Magic, DateTime::Locale. =head1 AUTHOR Carl Franks <cpan@fireartist.com> =head1 CREDITS Ron Savage =head1 COPYRIGHT AND LICENSE Copyright 2005, Carl Franks. All rights reserved. This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Licenses are in the files "Artistic" and "Copying" in this distribution. =cut