package Mozilla::Mechanize::Input;
use strict;
use warnings;
# $Id: Input.pm,v 1.4 2005/10/07 12:17:24 slanning Exp $
=head1 NAME
Mozilla::Mechanize::Input - A small class to interface with the Input objects
=head1 SYNOPSIS
sorry, read the source for now
=head1 DESCRIPTION
The C<Mozilla::Mechanize::Input> object is a thin wrapper around
HTML input elements.
=head1 METHODS
=head2 Mozilla::Mechanize::Input->new($input_node, $moz)
Initialize a new object. $input_node is a
L<Mozilla::DOM::HTMLElement|Mozilla::DOM::HTMLElement>
(or a node that can be QueryInterfaced to one); specifically,
it must be an HTMLInputElement, an HTMLButtonElement, an HTMLSelectElement,
or an HTMLTextAreaElement.
$moz is a L<Mozilla::Mechanize|Mozilla::Mechanize> object.
(This latter is a hack for `click', so that new pages can load
in the browser. The GUI has to be able to enter its main loop.
If you don't plan to use that method, you don't have to pass it in.)
=cut
sub new {
my $class = shift;
my $node = shift;
my $moz = shift;
my $iid;
# turn the Node into the appropriate HTMLElement
if (lc $node->GetNodeName eq 'input') {
$iid = Mozilla::DOM::HTMLInputElement->GetIID;
} elsif (lc $node->GetNodeName eq 'button') {
$iid = Mozilla::DOM::HTMLButtonElement->GetIID;
} elsif (lc $node->GetNodeName eq 'select') {
$iid = Mozilla::DOM::HTMLSelectElement->GetIID;
} elsif (lc $node->GetNodeName eq 'textarea') {
$iid = Mozilla::DOM::HTMLTextAreaElement->GetIID;
} else {
my $errstr = "Invalid Input node";
defined($moz) ? $moz->die($errstr) : die($errstr);
}
my $input = $node->QueryInterface($iid);
my $self = { input => $input };
$self->{moz} = $moz if defined $moz;
bless($self, $class);
}
=head2 $input->name
Return the input-control name.
=cut
sub name {
my $self = shift;
my $input = $self->{input};
return $input->GetAttribute('name');
}
=head2 $input->type
Return the type of the input control.
Note: for <select>, this returns 'select-one' for single select,
and 'select-multiple' for multiple. (I don't know why.)
=cut
sub type {
my $self = shift;
my $input = $self->{input};
my $tagname = lc $input->GetNodeName;
if ($tagname eq 'select') {
if ($input->GetMultiple) {
return 'select-multiple';
} else {
# I don't know what this is about,
# but it works like Win32::IE::Mechanize
return 'select-one';
}
} else {
return $input->GetAttribute('type');
}
}
=head2 $input->value( [$value] )
Get/Set the value of the input control.
=cut
sub value {
my $self = shift;
my $input = $self->{input};
my $type = $self->type || '';
$type =~ /^select/i and return $self->select_value( @_ );
$type =~ /^radio/i and return $self->radio_value( @_ );
if (@_ && defined $_[0]) {
my $value = shift;
$input->SetValue($value);
}
return $input->GetValue;
}
=head2 $input->select_value( [$value] )
Mark all options with C<$value> as selected and unselect all other options.
=cut
sub select_value {
my $self = shift;
my $input = $self->{input};
# XXX: I think this could be done better, but I just ported it straight
my %vals;
my @options = $input->GetOptions;
if ( @_ ) {
my @values = @_;
if ( @values == 1 && ref $values[0] eq 'HASH' ) {
my @ords = ref $values[0]->{n}
? @{ $values[0]->{n} } : $values[0]->{n};
@values = ();
foreach my $i ( @ords ) {
($i > 0) && ($i <= @options) and
push @values, $options[$i - 1]->GetValue;
}
}
@values = @{ $values[0] } if @values == 1 && ref $values[0];
# Make sure only the last value is set for:
# select-one type with multiple values;
# XXX: not sure if same type in Mozilla
@values = ( $values[-1] ) if lc($self->type) eq 'select-one';
%vals = map { ( $_ => undef ) } @values;
for ( my $i = 0; $i < @options; $i++ ) {
$options[$i]->SetSelected(exists $vals{ $options[$i]->GetValue });
}
} else {
for ( my $i = 0; $i < @options; $i++ ) {
$options[$i]->GetSelected and
$vals{ $options[$i]->GetValue } = 1;
}
}
return keys %vals;
}
=head2 $input->radio_value( [$value] )
Locate all radio-buttons with the same name within this form. Now
uncheck all values that are not equal to C<$value>.
=cut
sub radio_value {
my $self = shift;
my $input = $self->{input};
return unless $self->type =~ /^radio/i;
my $form = Mozilla::Mechanize::Form->new($input->GetForm, $self->{moz});
my @radios = $form->_radio_group($self->name);
if (@_) {
my $value = shift;
for (@radios) {
$_->SetChecked(($_->GetValue eq $value) || 0);
}
}
my ($value) = map($_->GetValue, grep($_->GetChecked, @radios));
return $value;
}
=head2 $input->click
Calls the C<click()> method on the actual object.
=cut
sub click {
my $self = shift;
my $input = $self->{input};
$input->Click();
# XXX: if they didn't pass $moz to `new', they're stuck..
my $moz = $self->{moz} || return;
$moz->_wait_while_busy();
}
1;
__END__
=head1 COPYRIGHT AND LICENSE
Copyright 2005,2009 Scott Lanning <slanning@cpan.org>. All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
=cut