| Mozilla-Mechanize documentation | Contained in the Mozilla-Mechanize distribution. |
Mozilla::Mechanize::Form - Mimic HTML::Form
Read the code for now
The Mozilla::Mechanize::Form object is a thin wrapper around
Mozilla::DOM::HTMLFormElement (Mozilla::DOM::HTMLFormElement).
Initialize a new object. $form_node is a Mozilla::DOM::HTMLFormElement (Mozilla::DOM::HTMLFormElement) (or a node that can be QueryInterfaced to one). $moz is a Mozilla::Mechanize object. (This latter is a hack for `submit' and `reset', 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 those methods, you don't have to pass it in.)
Get/Set the method used to submit the from (i.e. GET or POST).
Get/Set the action for submitting the form.
Get/Set the enctype of the form.
Return the name of this form.
Get/Set any of the attributes from the FORM-tag (acceptcharset, action, enctype, method, name, target (returns undef if $name isn't one of these)).
Returns a list of Mozilla::Mechanize::Input objects. In scalar context it will return the number of inputs.
XXX: I'm confused about how radio buttons are implemented. Win32::IE::Mechanize only pushes on the first one for some reason. (I push them all for now.)
This method is used to locate specific inputs within the form. All
inputs that match the arguments given are returned. In scalar context
only the first is returned, or undef if none match.
If $name is specified, then the input must have the indicated name.
If $type is specified, then the input must have the specified type. The following type names are used: "text", "password", "hidden", "textarea", "file", "image", "submit", "radio", "checkbox", and "option". (and "button" and "select"?)
The $index is the sequence number of the input matched where 1 is the first. If combined with $name and/or $type then it select the nth input with the given name and/or type.
(This method is ported from HTML::Form)
Get/Set the value for the input-control with specified name.
Submit this form. (Note: does not trigger onSubmit.)
Reset inputs to their default values. (Note: I added this method, though it wasn't in WWW::Mechanize.)
Returns a list of Mozilla::DOM::HTMLInputElement objects with name eq $name. (Intended for use with Input.pm's radio_value method.)
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.
| Mozilla-Mechanize documentation | Contained in the Mozilla-Mechanize distribution. |
package Mozilla::Mechanize::Form; use strict; use warnings; # $Id: Form.pm,v 1.4 2005/10/07 12:17:24 slanning Exp $ use Mozilla::Mechanize::Input;
sub new { my $class = shift; my $node = shift; my $moz = shift; # turn the Node into an HTMLFormElement my $form = $node->QueryInterface(Mozilla::DOM::HTMLFormElement->GetIID); my $self = { form => $form }; $self->{moz} = $moz if defined $moz; bless($self, $class); }
sub method { my $self = shift; my $val = shift; my $form = $self->{form}; $form->SetMethod($val) if defined $val; my $method = $form->GetMethod; # XXX: provide default value (not sure about this...) $method = 'GET' unless $method =~ /\S/; return $method; }
sub action { my $self = shift; my $val = shift; my $form = $self->{form}; $form->SetAction($val) if defined $val; # This is supposed to be required in HTML 4.01 return $form->GetAction; }
sub enctype { my $self = shift; my $val = shift; my $form = $self->{form}; $form->SetEnctype($val) if defined $val; my $enctype = $form->GetEnctype; # XXX: provide default value (not sure about this...) $enctype = 'application/x-www-form-urlencoded' unless $enctype =~ /\S/; return $enctype; }
sub name { my $self = shift; my $val = shift; my $form = $self->{form}; $form->SetName($val) if defined $val; return $form->GetName; }
sub attr { my $self = shift; return unless @_; my $name = shift; my $form = $self->{form}; my ($attr) = grep $name =~ /^$_$/i, qw(AcceptCharset Action Enctype Method Name Target); return unless defined $attr; my $method = "Set$attr"; $form->$method(shift) if @_; $method = "Get$attr"; my $val = $form->$method; # Defaults for non-present attributes unless ($val =~ /\S/) { $val = 'GET' if $attr eq 'Method'; $val = 'application/x-www-form-urlencoded' if $attr eq 'Enctype'; # action is supposed to be required in HTML 4.01 } return $val; }
{ # Recursively get input elements. This is necessary in order # to preserve their order. (cf. _extract_links, _extract_images in Mechanize.pm) my (@inputs, %radio_seen); sub inputs { my ($self, $subelement) = @_; # 2nd arg is undocumented my $node; # The first time, it's called with no subelement if (defined $subelement) { $node = $subelement; } else { @inputs = (); %radio_seen = (); $node = $self->{form}; } # If it's an input element, get it; otherwise, recurse if has children if ($node->GetNodeName =~ /^(input|button|select|textarea)$/i) { my $tagname = lc $1; if ($tagname eq 'input') { my $input = $node->QueryInterface(Mozilla::DOM::HTMLInputElement->GetIID); my $name = lc $input->GetName; my $type = lc $input->GetType; # For some reason, we only get the first in a radio group unless ($type eq 'radio' and $radio_seen{$name}++) { push @inputs, Mozilla::Mechanize::Input->new($node, $self->{moz}); } } else { push @inputs, Mozilla::Mechanize::Input->new($node, $self->{moz}); } $self->debug("added '$tagname' input"); } elsif ($node->HasChildNodes) { my @children = $node->GetChildNodes; # skips #text nodes foreach my $child (grep {$_->GetNodeName !~ /^#/} @children) { $self->inputs($child); } } # Continue only at the top-level return if defined $subelement; return wantarray ? @inputs : scalar @inputs; } }
sub find_input { my $self = shift; my( $name, $type, $index ) = @_; my $form = $self->{form}; my $typere = qr/.*/; $type and $typere = $type =~ /^select/i ? qr/^$type/i : qr/^$type$/i; if ( wantarray ) { my( $cnt, @res ) = ( 0 ); for my $input ( $self->inputs ) { if ( defined $name ) { $input->name or next; $input->name ne $name and next; } $input->type =~ $typere or next; $cnt++; $index && $index ne $cnt and next; push @res, $input; } return @res; } else { $index ||= 1; for my $input ( $self->inputs ) { if ( defined $name ) { $input->name or next; $input->name ne $name and next; } $input->type =~ $typere or next; --$index and next; return $input; } return undef; } }
sub value { my $self = shift; my $input = $self->find_input( shift ); return $input->value( @_ ); }
sub submit { my $self = shift; my $form = $self->{form}; $form->Submit(); # XXX: if they didn't pass $moz to `new', they're stuck.. my $moz = $self->{moz} || return; $moz->_wait_while_busy(); }
sub reset { my $self = shift; my $form = $self->{form}; $form->Reset(); # XXX: if they didn't pass $moz to `new', they're stuck.. my $moz = $self->{moz} || return; $moz->_wait_while_busy(); }
sub _radio_group { my $self = shift; my $form = $self->{form}; my $name = shift or return; my @rgroup; my @inputs = $form->GetElementsByTagName('input'); my $iid = Mozilla::DOM::HTMLInputElement->GetIID; foreach my $input (map {$_->QueryInterface($iid)} @inputs) { next unless lc($input->GetType) eq 'radio'; next unless lc($input->GetName) eq lc($name); push @rgroup, $input; } return wantarray ? @rgroup : \@rgroup; } sub debug { my ($self, $msg) = @_; my (undef, $file, $line) = caller(); print STDERR "$msg at $file line $line\n" if $self->{debug}; } 1; __END__