The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

###########################################################################
# Copyright (c) Nate Wiger http://nateware.com. All Rights Reserved.
# Please visit http://formbuilder.org for tutorials, support, and examples.
###########################################################################

# The majority of this module's methods (including new) are
# inherited directly from ::base, since they involve things
# which are common, such as parameter parsing. The only methods
# that are individual to different fields are those that affect
# the rendering, such as script() and tag()

package CGI::FormBuilder::Field::number;

use strict;
use warnings;
no  warnings 'uninitialized';

use CGI::FormBuilder::Util;
use CGI::FormBuilder::Field;
use base 'CGI::FormBuilder::Field';


our $VERSION = '3.10';

sub script {
    my $self = shift;
    my $name = $self->name;

    # The way script() works is slightly backwards: First the
    # type-specific JS DOM code is generated, then this is
    # passed as a string to Field->jsfield, which wraps this
    # in the generic handling.

    # Holders for different parts of JS code
    my $jsfunc  = '';
    my $jsfield = tovar($name);
    my $close_brace = '';
    my $in = indent(my $idt = 1);   # indent

    my $alertstr = escapejs($self->jsmessage);  # handle embedded '
    $alertstr .= '\n';

    if ($self->growable) {
        # special handling for growable, have to dynamically
        # find out how many have been created
        $jsfunc .= <<EOJS;
    // $name: growable text or file box
    var $jsfield = null;
    var entered_$jsfield = 0;
    var i = 0;
    while (1) {
        var growel = document.getElementById('$jsfield'+'_'+i);
        if (growel == null) break;  // last element
        $jsfield = growel.value;
        entered_$jsfield++;
        i++;
EOJS

        $close_brace = <<EOJS;

    } // while $name
EOJS

        # required?
        $close_brace .= <<EOJS if $self->required;
    if (! entered_$jsfield) {
        alertstr += '$alertstr';
        invalid++;
    }
EOJS
        # indent the very last if/else tests so they're in the while loop
        $in = indent($idt += 1);

    } else {

        # get value from text or other straight input
        # at least this part makes some sense
        $jsfunc .= <<EOJS;
    // $name: standard text, hidden, password, or textarea box
    var $jsfield = form.elements['$name'].value;
EOJS

    }

    return $self->jsfield($jsfunc, $close_brace, $in);
}

*render = \&tag;
sub tag {
    local $^W = 0;    # -w sucks
    my $self = shift;
    my $attr = $self->attr;

    my $jspre = $self->{_form}->jsprefix;

    my $tag   = '';
    my @value = $self->tag_value;   # sticky is different in <tag>
    my @opt   = $self->options;
    debug 2, "my(@opt) = \$field->options";

    # Add in our "Other:" option if applicable
    push @opt, [$self->othername, $self->{_form}{messages}->form_other_default]
             if $self->other;

    debug 2, "$self->{name}: generating $attr->{type} input type";

    # We iterate over each value - this is the only reliable
    # way to handle multiple form values of the same name
    # (i.e., multiple <input> or <hidden> fields)
    @value = (undef) unless @value; # this creates a single-element array

    # growable handling
    my $count = 0;  # for tracking the size of growable fields
    my $limit;      # for providing (optional) limits to growable fields 
    my $at_limit;   # have we reached the limit of a growable field?
    if ($self->growable && $self->growable ne 1) {
        $limit = $self->growable;
    }

    for my $value (@value) {
        if ($limit && $count == $limit) {
            belch "Number of supplied values (" . @value . ")"
                . " for '$attr->{name}' exceeds growable limit $limit - discarding excess";
            $at_limit = 1;
            last;
        }
        
        # setup the value
        $attr->{value} = $value;      # override
        delete $attr->{value} unless defined $value;

        if ($self->growable && $self->javascript) {
            # the inputs in growable fields need a unique id for fb_grow()
            $attr->{id} = tovar("$attr->{name}_$count");
            $count++;
        }

        # render the tag
        $tag .= htmltag('input', $attr);

        #
        # If we have options, lookup the label instead of the true value.
        # This code is reached if a field is marked 'static', since 
        # that is still rendered from ::text (here) but as a 'hidden'
        # field. These options would be leftover from a former select
        # or radio group that is now shown on a confirm() screen. Got it?
        #
        for (@opt) {
            my($o,$n) = optval($_);
            if ($o eq $value) {
                $n ||= $attr->{labels}{$o} || ($self->nameopts ? toname($o) : $o);
                $value = $n;
                last;
            }
        }

        if ($self->growable && $self->javascript) {
            # put linebreaks between the input tags in growable fields
            # this puts the "Additonal [label]" button on the same line
            # as the last input tag
            $tag .= '<br />' unless $count == @value;
        } else {
            $tag .= '<br />' if $self->linebreaks;
        }
    }
    # check to see if we just hit the limit
    $at_limit = 1 if $limit && $count == $limit;

    # add the "Additional [label]" button
    if ($self->growable && $self->javascript) {
        $tag .= ' ' . htmltag('input',
            id      => $self->growname,
            type    => 'button',
            onclick => "${jspre}grow('$attr->{name}')",
            value   => sprintf($self->{_form}{messages}->form_grow_default, $self->label),
            ( $at_limit ? ( disabled => 'disabled') : () ),
        );
    }

    # add an additional tag for our _other field
    $tag .= ' ' . $self->othertag if $self->other;

    debug 2, "$self->{name}: generated tag = $tag";
    return $tag;       # always return scalar tag
}

1;

__END__