package HTML::Data::Bind;

use strict; use warnings;

use base 'Markup::Processor';

use Markup;
use Alias;

use vars qw(@elements $i $e $type $tag $name @context $content $object_name %data);

sub bind {
	my ($class, $markup, $data) = @_;
	my $p = $class->new($markup);
	$p->{data} = $data;
	$p->{content} = undef;
	$p->{object_name} = undef;
	$p->main_loop;
}

sub clear {
	my ($class, $markup) = @_;
	my $data = {};
	$class->bind($markup, $data);
}

sub main_loop {
	my $p = attr shift;
	while(1) {
		$p->read or last;
		if ($type eq "open" && defined $name && $name !~ /^_/) {
			$object_name = $name;
			# XXX TODO cope with different types of $data,
			# not just a hash, also objects, arrays
			# (this is why not using the aliased %data)
			$content = $p->{data}{$name};
			$content = "" if !defined $content;
			if ($tag eq "input") {
				$p->input_bind;
			} elsif ($tag eq "textarea") {
				$p->textarea_bind;
			} elsif ($tag eq "select") {
				$p->select_bind;
			} else {
				$p->non_editable_bind;
			}
		}
	}
}

sub non_editable_bind {
	my $p = attr shift;
	my $element = Markup::Text->new($content);
	$p->replace_container_content($element);
}

sub input_bind {
	my $p = attr shift;
	my $input_type = $e->attr_get("type") || "text";
	if ($input_type eq "submit") {
		die "submit should not have a name, or should start with _"
	} elsif ($input_type eq "checkbox" or $input_type eq "radio") {
		if ($content) { $e->attr_set('checked', undef); }
		else { $e->attr_del('checked'); }
	} elsif ($input_type eq "file") {
		# no value attr for a file upload,
		# can't bind anything to it
	} else {
		$e->attr_set("value", $content);
	}
}

sub textarea_bind {
	my $p = attr shift;
	if ($p->read and $type eq "text") {
		$e->set($content);
	} else {
		my $e = Markup::Text->new($content);
		$p->insert($e);
	}
}

sub select_bind {
	my $p = attr shift;
	my $found_it;
	while(1) {
		$p->read or last;
		if ($type eq "close" && $tag eq "select") {
			last;
		}
		if ($type eq "open" && $tag eq "option") {
			my $option_e = $e;
			my $option_name = $name;
			if (!defined $option_name) {
				$p->read;
				if ($type eq "text") {
					$option_name = $e->get;
				} else {
					$option_name = "";
				}
			}
			if ($option_name eq $content) {
				$option_e->attr_set("selected", undef);
				$found_it = 1;
			} else {
				$option_e->attr_del("selected");
			}
		}
	}
	if (!$found_it) {
		die qq{couldn't select option '$content' in <select name="$object_name">};
	}
}

1
