package Data::FormValidator::Util::HTML;

use 5.005;
use strict;

require Exporter;
require HTML::TokeParser::Simple;
use vars qw($VERSION @ISA @EXPORT);
@ISA = qw(Exporter);

# Items to export into callers namespace by default. Note: do not export
# names by default without a very good reason. Use EXPORT_OK instead.
# Do not simply export all your public functions/methods/constants.

@EXPORT = qw(add_error_tokens);

$VERSION = '0.10';

use  strict;
use HTML::TokeParser::Simple;
use Params::Validate;

sub add_error_tokens {
	my %styles = (
		'ht_comment' => {
			prepend => ' <!-- tmpl_var name="',
			append  => '" --> ',
		},
		'ht_tag' => {
			prepend => ' <tmpl_var "',
			append  => '"> ',
		},
   );

  my %in = 	validate(@_, {
		html		=> { default => *STDIN },
		prefix  	=> { default => 'err_' },
		style   	=> { default => 'ht_comment' },
		prepend 	=> 0,
		append 	    => 0, 
		}
	);

	defined $styles{$in{style}} or die "unknown style: $in{style}";

	# Default to style if none is provided
	$in{prepend} = $styles{$in{style}}->{prepend} unless defined $in{prepend};
	$in{append} = $styles{$in{style}}->{append} unless defined $in{append};

	my $p = HTML::TokeParser::Simple->new($in{html}) || 
		die "failed to create HTML::TokeParser::Simple object: $!"; 

	my $select_name;
	my $out;
	while ( my $token = $p->get_token ) {
		if ( ( $token->is_start_tag( 'input' ) ) &&
			( $token->return_attr->{type} !~ m/^(button|submit|image)$/i )) {
			my $name = $token->return_attr->{name};
			$out .= $token->as_is.qq/$in{prepend}$in{prefix}$name$in{append}/;
		}
		elsif ( $token->is_start_tag( 'select' ) ) {
			$select_name = $token->return_attr->{name};
			$out .= $token->as_is;
		}
		elsif ( $token->is_end_tag('select') ) {
			$out .= $token->as_is.qq/$in{prepend}$in{prefix}$select_name$in{append}/;
		}
		elsif ( $token->is_start_tag( 'textarea' ) ) {
			my $name = $token->return_attr->{name};
			$out .= qq/$in{prepend}$in{prefix}$name$in{append}/.$token->as_is;
		}
		else {
			$out .= $token->as_is;
		}
	}
	return $out;	
}





1;
__END__

=head1 NAME

Data::FormValidator::Util::HTML - HTML utility functions for DFV

=head1 SYNOPSIS

  # Add error tokens to an HTML page, for later 
  # use with Data::FormValidator and a templating system

  # Example #1, a standard Unix filter
  # takes input from STDIN and prints to STDOUT

  #!/usr/bin/perl 
  use Data::FormValidator::Util::HTML;
  print add_error_tokens();	


  # Example #2, modifying some HTML
  # you have as a scalar

  my $html = add_error_tokens(
  	html=>\$html,
	prefix=>'err_',
  );

The C<add_error_tokens()> routine will add HTML::Template tags next to all the
appropriate form fields, which can be used to display errors.
 
B<Example HTML:>

 <input type="text" name="fruit">

B<Becomes:>

 <input type="text" name="fruit"> <!-- tmpl_var name="err_fruit" -->

=head1 DESCRIPTION

This module adds tokens to HTML pages, which can be used to display
error messages generated by the Data::FormValidator module. 

The easiest way to understand this might be to check out the tutorial,
which provides example of using the kind of output this module produces,
including a screenshot.

http://mark.stosberg.com/dfv/

=head1 add_error_tokens()

This functions adds error tokens to some HTML and returns the modified HTML.

B<input parameters:>

=over 4

=item html  (default: STDIN)

This is the HTML to modify. It can be a file name, a file handle object, or
the complete document to be parsed.

If the argument is a plain scalar, then it is taken as the name of
a file to be opened and parsed.  If the file can't be opened for
reading, then the constructor will return an undefined value and $!
will tell you why it failed.

If the argument is a reference to a plain scalar, then this scalar
is taken to be the literal document to parse.  The value of this
scalar should not be changed before all tokens have been extracted.

Otherwise the argument is taken to be some object that the
"HTML::TokeParser" can read() from when it needs more data.  Typi-
cally it will be a filehandle of some kind.  The stream will be
read() until EOF, but not closed.


=item prefix (default: 'err_' )

This is the same 'prefix' that you define in your DFV profile to denote that these
are error fields. I like to use "err_", so that's what the default is. :)

=item style (default: 'ht_comment')

Recognizing that people will want to use this different templating systems,
you can set C<style> to a pre-defined template style to use. Currently just
a couple for HTML::Template are included, but patches are welcome for more.

Here's what they look like:
 
 ht_comment: <!-- tmpl_var name="err_field" -->
 ht_tag      <tmpl_var name="err_field">

=item prepend and append 

If you don't want to use one of the built-in styles or patch the code, fear
not.  C<prepend> and C<append> are for you. Use these to define what text you
want to come before and after the field name. Defining these will override any
setting for 'style'.

=back


=head1 EXPORT

C<add_error_tokens()>

=head1 KNOWN ISSUES

=over 4

=item o

There is no way to specify which kinds of form fields get tokens added, or exactly
where the tokens appear in relation to the field. 

=item o

The token adding is currently not related to a Data::FormValidator profile. It could
potentially be even smarter by only adding tokens for fields that have the possibility
of being missing or invalid in a profile.

=back

=head1 SEE ALSO

Data::FormValidator

=head1 AUTHOR

Mark Stosberg, E<lt>mark@summersault.comE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright 2003 by Mark Stosberg

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself. 

=cut
