Jifty::Web::Form - Tools for rendering and dealing with HTML forms


Jifty documentation Contained in the Jifty distribution.

Index


Code Index:

NAME

Top

Jifty::Web::Form - Tools for rendering and dealing with HTML forms

METHODS

Top

new ARGS

Creates a new Jifty::Web::Form. Arguments:

id

The HTML id attribute given to the form. This is aliased to name. That is, name and id are always equal and changing one changes the other.

class

The HTML class attribute given to the form.

name

The name given to the form. This is mostly for naming specific forms for testing.

call

All buttons in this form will act as continuation calls for the given continuation id.

disable_autocomplete

Disable browser autocomplete for this form. Jifty autocomplete will still work.

PRIVATE _init

Reinitialize this form.

name

The form name

call

The continuation id to call

actions

Returns a reference to a hash of Jifty::Action objects in this form keyed by moniker.

If you want to add actions to this form, use add_action

name [VALUE]

Gets or sets the HTML name given to the form element.

call [CONTID]

Gets or sets the continuation ID that will be called for this form.

is_open [BOOL]

This accessor returns true if Jifty is currently in the middle of rendering a form (if it's printed a <form> but not yet printed a </form> tag.) Use this in your components to decide whether to open a form or not if you might be called from a template that opened the form for you.

add_action PARAMHASH

Calls new_action in Jifty::Web with the paramhash given, and adds it to the form.

register_action ACTION

Adds ACTION as an action for this form. Called so that actions' form fields can register the action against the form they're being used in.

has_action MONIKER

If this form has an action whose moniker is MONIKER, returns it. Otherwise returns undef.

start

Renders the opening form tag.

submit MESSAGE, [PARAMETERS]

Renders a submit button with the text MESSAGE on it (which will be HTML escaped). Returns the empty string (for ease of use in interpolation). Any extra PARAMETERS are passed to Jifty::Web::Form::Field::Clickable's constructor.

return MESSAGE, [PARAMETERS]

Renders a return button with the text MESSAGE on it (which will be HTML escaped). Returns the empty string (for ease of use in interpolation). Any extra PARAMETERS are passed to Jifty::Web::Form::Field::Button's constructor.

end

Renders the closing form tag (including rendering errors for and registering all of the actions) After doing this, it resets its internal state such that start may be called again.

next_page PARAMHASH

Set the page this form should go to on success. This simply creates a Jifty::Action::Redirect action; any parameters in the PARAMHASH are passed as arguments to the Jifty::Action::Redirect action.

Returns an empty string so it can be included in forms

DESTROY

Checks to ensure that forms that were opened were actually closed, which is when actions are registered.


Jifty documentation Contained in the Jifty distribution.
use warnings;
use strict;

package Jifty::Web::Form;

use base qw/Jifty::Object Class::Accessor::Fast/;

__PACKAGE__->mk_accessors(qw(actions printed_actions name call is_open disable_autocomplete target submit_to onsubmit class));

# Alias id to name
*id = *name;

use Scalar::Util qw/weaken/;

sub new {
    my $class = shift;
    my $self = bless {}, ref $class ? ref $class : $class;

    my %args = (
        name => undef,
        call => undef,
        submit_to => undef,
        target => undef,
        disable_autocomplete => undef,
        @_,
    );

    $self->_init(%args);
    return $self;
}


sub _init {
    my $self = shift;
    my %args = (name => undef,
                call => undef,
                target => undef,
                submit_to => undef,
                disable_autocomplete => undef,
                @_);

    $self->actions( {} ) ;
    $self->printed_actions( {} ) ;
    $self->name($args{name});
    $self->call($args{call});
    $self->target($args{target});
    $self->submit_to($args{'submit_to'});
    $self->disable_autocomplete($args{disable_autocomplete});
}


sub add_action {
    my $self = shift;
    $self->register_action(Jifty->web->new_action(@_));
}




sub register_action {
    my $self = shift;
    my $action = shift;
    $self->actions->{ $action->moniker } =  $action;
    weaken $self->actions->{ $action->moniker};
    return $action;
}


sub has_action {
    my $self    = shift;
    my $moniker = shift;
    if ( exists $self->actions->{$moniker} ) {
        return $self->actions->{$moniker};
    }
    else { return undef }

}



sub start {
    my $self = shift;
    local $Log::Log4perl::caller_depth = $Log::Log4perl::caller_depth + 1;

    my %args = (@_);

    if ($self->is_open) {
        $self->log->warn("Trying to open a form when we already have one open");
    }

    for (keys %args) {
        if ( $self->can($_) ) {
            $self->$_($args{$_});
        } else {
            my (undef, $template, $line) = caller;
            $self->log->warn("Unknown parameter to Jifty->web->form->start: $_ in $template line $line");
        }
    }

    my $root = $self->submit_to
      || URI->new(Jifty->web->request->top_request->request_uri)->path;

    my $form_start = qq!<form method="post" action="!  . Jifty->web->escape( $root ) . qq!"!;
    $form_start .= qq! name="@{[ $self->name ]}"! if defined $self->name;
    $form_start .= qq! id="@{[ $self->name ]}"! if defined $self->name; # always the same as name
    $form_start .= qq! class="@{[ $self->class ]}"! if defined $self->class;
    $form_start .= qq! target="@{[ $self->target ]}"! if defined $self->target;
    $form_start .= qq! autocomplete="off"!  if defined $self->disable_autocomplete;
    $form_start .= qq! onsubmit="! .Jifty->web->escape( $self->onsubmit ). qq!"!  if defined $self->onsubmit;
    $form_start .= qq! enctype="multipart/form-data" >\n!;
    Jifty->web->out($form_start);

    # Write out state variables early, so that if a form gets
    # submitted before the page finishes loading, the state vars don't
    # get lost
    $self->_preserve_state_variables();

    $self->is_open(1);
    '';
}

sub submit {
    my $self = shift;
    my %args = (
        submit    => undef,
        _form     => $self,
        as_button => 1,
        @_,
    );

    my @submit = ref($args{'submit'}) eq 'ARRAY' ? @{$args{'submit'}} : $args{'submit'};
    if ($self->actions->{'next_page'} && $submit[0] && ! grep {$_->moniker eq 'next_page' } @submit)  {
        push @submit, $self->actions->{'next_page'};
        $args{'submit'} = \@submit;
    }


    my $button = Jifty::Web::Form::Clickable->new(%args)->generate;
    Jifty->web->out(qq{<div class="submit_button">});
    $button->render_widget;
    Jifty->web->out(qq{</div>});

    return '';
}

sub return {
    my $self = shift;

    my $button = Jifty->web->return(as_button => 1, @_);
    Jifty->web->out(qq{<div class="submit_button">});
    $button->render_widget;
    Jifty->web->out(qq{</div>});

    return '';
}

sub end {
    my $self = shift;

    unless ($self->is_open) {
        $self->log->warn("Trying to close a form when we don't have one open");
    }
    Jifty->web->out( qq!<div class="hidden">\n! );

    $self->_print_registered_actions();
    $self->_preserve_continuations();

    Jifty->web->out( qq!</div>\n! );

    Jifty->web->out( qq!</form>\n! );
    $self->is_open(0);
    # Clear out all the registered actions and the name
    $self->_init();

    '';
}



sub print_action_registration {
    my $self = shift;
    my $moniker = shift;


    my $action = $self->has_action($moniker);
    return unless ($action);
    return if exists $self->printed_actions->{$moniker};
    $self->printed_actions->{$moniker} = 1;

    $action->register();

}


# At the point this is called, it should only include actions we're
# registering that have no form fields and haven't been explicitly
# registered.
sub _print_registered_actions {
    my $self = shift;
    for my $a ( keys %{ $self->actions } ) {
        $self->print_action_registration($a);
    }
}

sub _preserve_state_variables {
    my $self = shift;

    my %vars = Jifty->web->state_variables;
    for (keys %vars) {
        Jifty->web->out( qq{<input type="hidden" name="}
                . 'J:V-' . $_
                . qq{" value="}
                . $vars{$_}
                . qq{" />\n} );
    }
}

sub _preserve_continuations {
    my $self = shift;

    if ($self->call) {
        Jifty->web->out( qq{<input type="hidden" name="J:CALL" value="}
                                . (ref $self->call ? $self->call->id : $self->call)
                                . qq{" />});
    } elsif (Jifty->web->request->continuation) {
        Jifty->web->out( qq{<input type="hidden" name="J:C" value="}
                                . Jifty->web->request->continuation->id
                                . qq{" />});
    }

}

sub next_page {
    my $self = shift;
    if (@_ % 2) {
        Carp::carp("next_page accepts a parameter hash. You probably want to specify url => ...");
    }

    $self->add_action(class => "Jifty::Action::Redirect", moniker => "next_page", arguments => {@_});
    return '';
}

sub DESTROY {
    my $self = shift;
    warn "Action $_ was never registered (form was never closed)"
      for grep {not $self->printed_actions->{$_}} keys %{$self->actions};
}

1;