<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;"># Copyright 2005-2006, Fred Steinberg, Brown Bear Software

# Admin for defining Custom Fields
package AdminCustomFields;
use strict;
use CGI;

use Calendar::CustomField;

use vars ('@ISA');
@ISA = ('Operation');

sub perform {
    my $self = shift;
    my $i18n = $self-&gt;I18N;
    my $cgi  = CGI-&gt;new;

    my ($save, $cancel) = $self-&gt;getParams (qw (Save Cancel));
    my $calName = $self-&gt;calendarName;

    if ($cancel) {
        my $op = $calName ? 'AdminPage' : 'SysAdminPage';
        print $self-&gt;redir ($self-&gt;makeURL ({Op =&gt; $op}));
        return;
    }

    my  %labels = (name     =&gt; $i18n-&gt;get ('Name') . ':',
                   default  =&gt; $i18n-&gt;get ('Default Value') . ':',
                   label    =&gt; $i18n-&gt;get ('Label') . ':',
                   required =&gt; $i18n-&gt;get ('Required?'),
                   order    =&gt; $i18n-&gt;get ('Display Order') . ':',
                   display  =&gt; $i18n-&gt;get ('Display the value') . ':',
                   cols     =&gt; $i18n-&gt;get ('Columns') . ':',
                   rows     =&gt; $i18n-&gt;get ('Rows') . ':',
                   width    =&gt; $i18n-&gt;get ('Width') . ':',
                   limit    =&gt; $i18n-&gt;get ('Maximum Length') . ':',
                   values   =&gt; $i18n-&gt;get ('Items') . ':'
                              . '&lt;br&gt;&lt;small&gt;'
                              . $i18n-&gt;get ('(enter each value on a new line)')
                              . '&lt;/small&gt;',
                   multidefault =&gt;
                                $i18n-&gt;get ('Default Values') . ':'
                              . '&lt;br&gt;&lt;small&gt;'
                              . $i18n-&gt;get ('(enter each value on a new line)')
                              . '&lt;/small&gt;',
                  );
    $self-&gt;{form_labels} = \%labels;


    my $prefs = $self-&gt;prefs;

    my $masterPrefs;
    if ($calName) {
        $masterPrefs = MasterDB-&gt;new-&gt;getPreferences;
    } else {
        $masterPrefs = $prefs;
    }

    my @columns = qw (Name Type Default Required);

    my $message;

    # Check for "Delete"s
    my $delete_params = $self-&gt;get_matching_params ('^Delete-.*');
    foreach my $param_name (keys %$delete_params) {
        $param_name =~ /^Delete-(.*)$/;
        my $id = $1;
        $prefs-&gt;delete_custom_field ($id);

        my @field_order = split ',', ($prefs-&gt;CustomFieldOrder || '');
        @field_order = grep {$_ ne $id} @field_order;
        $prefs-&gt;CustomFieldOrder (join ',', @field_order);

        $self-&gt;db-&gt;setPreferences ($prefs);

        $self-&gt;{audit_fieldDeleted} ||= [];
        push @{$self-&gt;{audit_fieldDeleted}}, $id;
    }

    # Handle "modify field" - it's a separate popup window
    my ($modify, $modify_field_id)  = $self-&gt;getParams (qw /Modify FieldID/);
    if ($modify and defined $modify_field_id) {
        # Put up modify fields for the field; on save, refresh opener
        $self-&gt;display_modify_stuff ($modify_field_id);
        return;
    }

    # And handle the actual "Modify"; reload the opening window
    ($modify, $modify_field_id)  = $self-&gt;getParams (qw /SaveModify FieldID/);
    if ($modify and defined $modify_field_id) {
        my ($modified_field, $order) = $self-&gt;field_from_form_params;
        $modified_field-&gt;id ($modify_field_id);
        if ($message = $self-&gt;_check_new_field_name ($modified_field, 1)) {
            $self-&gt;display_modify_stuff ($modify_field_id, $message);
            return;
        }
        $order ||= 1;
        $prefs-&gt;set_custom_field ($modified_field);
        my @field_order = split ',', ($prefs-&gt;CustomFieldOrder || '');
        @field_order = grep {$_ ne $modify_field_id} @field_order;
        if ($order &gt; @field_order) {
            $order = @field_order + 1;
        }
        splice @field_order, $order - 1, 0, $modify_field_id;
        $prefs-&gt;CustomFieldOrder (join ',', @field_order);
        $self-&gt;db-&gt;setPreferences ($prefs);
        my $url = $self-&gt;makeURL ({Op =&gt; __PACKAGE__});
        print GetHTML-&gt;startHTML;
        print &lt;&lt;END_OPENER_JS;
        &lt;script type="text/javascript"&gt;&lt;!--
        window.opener.location = "$url;"
        window.close();
        //--&gt;&lt;/script&gt;
        &lt;/body&gt;&lt;/html&gt;

END_OPENER_JS
    }

    # New Field added
    if ($self-&gt;getParams ('AddNewButton')) {
        my ($new_field, $order) = $self-&gt;field_from_form_params;
        $message = $self-&gt;_check_new_field_name ($new_field);
        if (!$message) {
            $order ||= 1;
            $prefs-&gt;new_custom_field ($new_field);
            my @field_order = split ',', ($prefs-&gt;CustomFieldOrder || '');
            splice @field_order, $order - 1, 0, $new_field-&gt;id;
            $prefs-&gt;CustomFieldOrder (join ',', @field_order);
            $self-&gt;db-&gt;setPreferences ($prefs);
        }
    }

    print GetHTML-&gt;startHTML (title  =&gt; $i18n-&gt;get ('Custom Fields') . ': ' .
                                        ($calName ||
                                             $i18n-&gt;get ('System Defaults')),
                              op     =&gt; $self);

    my $modify_url = $self-&gt;makeURL ({Op     =&gt; __PACKAGE__,
                                      Modify =&gt; 1}) . '&amp;FieldID=';
    print &lt;&lt;END_MODIFY_JS;
&lt;script type="text/javascript"&gt;&lt;!--
  function modify_field (field_id) {
    var width  = Math.round (screen.width/2);
    var height = Math.round (screen.height/2);
    var win = window.open ("$modify_url" + field_id, "ModifyField",
                 "scrollbars,resizable,width=" + width + ",height=" + height);
    win.focus();
  }
//--&gt;
&lt;/script&gt;
END_MODIFY_JS

    if ($calName) {
        print GetHTML-&gt;AdminHeader (I18N    =&gt; $i18n,
                                    cal     =&gt; $calName,
                                    section =&gt; 'Custom Fields');
    } else {
        print GetHTML-&gt;SysAdminHeader ($i18n, 'Custom Fields', 1);
    }

    if ($message) {
        print '&lt;center&gt;';
        print qq (&lt;p class="ErrorHighlight"&gt;$message&lt;/p&gt;);
        print '&lt;/center&gt;';
    }
    print '&lt;br&gt;';

    # Display existing fields, with "Modify/Delete" buttons.
    my %colLabels = (Name     =&gt; $i18n-&gt;get ('Field Name'),
                     Example  =&gt; $i18n-&gt;get ('Example Edit Form control'),
                     Type     =&gt; $i18n-&gt;get ('Input Type'),
                     Default  =&gt; $i18n-&gt;get ('Default Value'),
                     Required =&gt; $i18n-&gt;get ('Required?'));
    my %type_names = (textfield   =&gt; 'Text - Single Line',
                      textarea    =&gt; 'Text - Multiple Line',
                      select      =&gt; 'Popup Menu - Choose One',
                      multiselect =&gt; 'Popup Menu - Choose Many',
                      checkbox    =&gt; 'Checkbox');
    my @type_names = qw /textfield textarea select multiselect checkbox/;

    print $cgi-&gt;startform;

    my $fields_lr = $self-&gt;prefs-&gt;get_custom_fields (system =&gt; undef);
    my %fields = map {$_-&gt;id =&gt; $_} @$fields_lr;
    my @order = split ',', ($self-&gt;prefs-&gt;CustomFieldOrder || '');
    my @names;
    my @rows = ($cgi-&gt;Tr ({-class =&gt; 'AdminTableColumnHeader'},
                          $cgi-&gt;th ([$colLabels{Name},
                                     $colLabels{Example},
                                     $colLabels{Required},
                                     '&amp;nbsp;'])));
    my ($thisRow, $thatRow) = ('thisRow', 'thatRow');
    my $tabindex = 1;
    foreach my $field_id (@order) {
        my $field = $fields{$field_id};
        next unless $field;
        my $field_id = $field-&gt;id;
        push @names, $field-&gt;name;
        my $example = $field-&gt;make_html (disabled =&gt;
                                             $field-&gt;input_type !~ /select/);
        if (my $label = $field-&gt;label) {
            $example = "&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;$label&lt;/b&gt;&lt;/td&gt;"
                     . "&lt;td&gt;$example&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;";
        }

        my $modify = $cgi-&gt;submit (-name  =&gt; "Modify-$field_id",
                                   -value =&gt; $i18n-&gt;get ('Modify'),
                                   -tabindex =&gt; $tabindex++,
                                   -onClick =&gt;
                                      "modify_field ($field_id);return false;");
        my $delete = $cgi-&gt;submit (-class =&gt; 'DeleteButton',
                                   -tabindex =&gt; $tabindex++,
                                   -style =&gt; 'font-size: .6em',
                                   -name  =&gt; "Delete-$field_id",
                                   -value =&gt; $i18n-&gt;get ('Delete'));
        my $required = $field-&gt;required ? $i18n-&gt;get ('yes')
                                        : $i18n-&gt;get ('no');
        if ($field-&gt;input_type eq 'checkbox') {
            $required = ' - ';
        }
        push @rows, $cgi-&gt;Tr ({-class =&gt; $thisRow},
                              $cgi-&gt;td ($field-&gt;name),
                              $cgi-&gt;td ($example),
                              $cgi-&gt;td ({-align =&gt; 'center'}, $required),
                              $cgi-&gt;td ("$modify &amp;nbsp; $delete"));
        ($thisRow, $thatRow) = ($thatRow, $thisRow);
    }
    print $cgi-&gt;table ({-class =&gt; 'alternatingTable',
                        -align  =&gt; 'center',
                        -cellpadding =&gt; 5,
                        -border =&gt; 1}, @rows);

    if (@rows == 1) {
        print $cgi-&gt;p ({-align =&gt; 'center'}, ' - ' .
                       $i18n-&gt;get ('No Custom Fields have been defined')
                       . ' - ');
    }

    # Create New Field Section
    print '&lt;br/&gt;';


    print '&lt;center&gt;&lt;div style="border-width: 1px; border-style: solid; '
          . 'text-align: center; padding: 5px; width: 50%"&gt;';
    print $i18n-&gt;get ('New Field Type') . ': ';
    print $self-&gt;_field_setting_divs (CGI   =&gt; $cgi,
                                      I18N  =&gt; $i18n,
                                      default_type =&gt; 'textfield',
                                      field_count  =&gt; scalar (@order));

    print '&lt;br/&gt;';
    print $cgi-&gt;submit (-name     =&gt; 'AddNewButton',
                        -tabindex =&gt; 40,
                        -value    =&gt; $i18n-&gt;get ('Create New Field'));
    print '&lt;/div&gt;&lt;/center&gt;';
    print '&lt;br&gt;&lt;br&gt;';

    print '&amp;nbsp;';
    print $cgi-&gt;submit (-name     =&gt; 'Cancel',
                        -value    =&gt; $i18n-&gt;get ('Done'),
                        -tabindex =&gt; 105);

    print $cgi-&gt;hidden (-name =&gt; 'Op',           -value =&gt; __PACKAGE__);
    print $cgi-&gt;hidden (-name =&gt; 'CalendarName', -value =&gt; $calName)
      if $calName;

    print $cgi-&gt;endform;
    print '&lt;hr/&gt;';

    my @help_strings;
    my %help;

    $help{general} = &lt;&lt;HELP_STRING;
        You can define templates for custom display of your custom
        fields; templates are available for: the Event Entry form,
        Event Popup windows, the List View "details" column,
        notification Mail, and RSS feeds. (See the Templates settings
        page.)
HELP_STRING

    $help{required} = &lt;&lt;HELP_STRING;
        If a field is marked "Required", new events will not be
        accepted unless a value is set for that field.
HELP_STRING

    $help{popup} = &lt;&lt;HELP_STRING;
        For Popup Menus, a value of - will be ignored. (That's a
        single hyphen.) You can include this as a choice and make it
        the default value for a required field  - this will require that the
        user make a valid choice from the popup menu, instead of
        defaulting to any particular choice.
HELP_STRING

    $help{unused} = &lt;&lt;HELP_STRING;
        The "Label" and "Display Order" are not used if an output
        output template is defined.
HELP_STRING

    foreach my $name (qw /general required popup unused/) {
        my $string_name = "AdminCustomFields_HelpString_$name";
        my $string = $i18n-&gt;get ($string_name);
        if ($string eq $string_name) {
            $string = $help{$name};
        }
        push @help_strings, $string;
    }

    print '&lt;br&gt;&lt;div class="AdminNotes"&gt;';
    print $cgi-&gt;span ({-class =&gt; 'AdminNotesHeader'},
                      $i18n-&gt;get ('Notes') . ':');
    print $cgi-&gt;ul ($cgi-&gt;li (\@help_strings));
    print '&lt;/div&gt;';

    print $cgi-&gt;end_html;
}

# Return undef if new name ok, message otherwise
sub _check_new_field_name {
    my ($self, $field, $modifying) = @_;
    my $fields_lr = $self-&gt;prefs-&gt;get_custom_fields (system =&gt; undef);
    my %fields_by_name = map {$_-&gt;name, $_} @$fields_lr;
    if (!$field-&gt;name) {
        return $self-&gt;I18N-&gt;get ('Sorry - a field name is required.');
    }
    # If adding a new field w/same name as existing, or changing an existing
    #  name to the name of another field
    my $existing_field = $fields_by_name{$field-&gt;name};
    if ($existing_field
        and (!$modifying or ($field-&gt;id ne $existing_field-&gt;id))) {
        return sprintf $self-&gt;I18N-&gt;get ("Sorry, there's already a field "
                                         . "named '%s'"), $field-&gt;name;
    }
    return;
}


sub auditString {
    my ($self, $short) = @_;
    return unless $self-&gt;{audit_formsaved};
    my $line = $self-&gt;SUPER::auditString ($short);
    return $line;
}

sub field_from_form_params {
    my $self = shift;

    # Get params based on type of new field
    my $field_type = $self-&gt;getParams ('FieldTypeSelector');

    # These should be defined for all field types
    my ($name, $default, $label, $required, $display, $order) =
      $self-&gt;getParams (map {$field_type . $_}
                        qw /Name Default Label Required Display Order/);

    # Some of these will be undef, based on field type
    my ($cols, $rows, $max_size) =
              $self-&gt;getParams (map {$field_type . $_} qw /Cols Rows Max/);

    # Input Values only for drop down menus; text area, split on newlines
    my $input_values;
    if ($field_type =~ 'select') {
        my $values = $self-&gt;getParams ($field_type . 'InputValues');
        $values =~ s/\r//g;      # get rid of carriage returns
        $input_values = [split "\n", $values];
    }

    # Multi select might have arrayref for default values
    if ($field_type eq 'multiselect') {
        my $values = $self-&gt;getParams ('multiselectDefault');
        $values =~ s/\r//g;      # get rid of carriage returns
        $default = [split "\n", $values];
    }

    my $new_field = CustomField-&gt;new (name         =&gt; $name,
                                      input_type   =&gt; $field_type,
                                      default      =&gt; $default,
                                      required     =&gt; $required,
                                      display      =&gt; $display ? 1 : undef,
                                      label        =&gt; $label,
                                      input_values =&gt; $input_values,
                                      cols         =&gt; $cols,
                                      rows         =&gt; $rows,
                                      max_size     =&gt; $max_size);
    return ($new_field, $order);
}

# Return hash of form entry controls common to all field types
sub _common_form_fields {
    my %params = @_;
    my $name        = $params{name};
    my $cgi         = $params{cgi};
    my $defaults    = $params{defaults} || {};
    my $field_count = $params{field_count};
    my $tab_index   = $params{tab_index};

    my %controls;
    $controls{name} = $cgi-&gt;textfield (-name      =&gt; $name . 'Name',
                                       -default   =&gt; $defaults-&gt;{name},
                                       -tabindex  =&gt; $tab_index-&gt;{name},
                                       -size      =&gt; 20,
                                       -maxlength =&gt; 60);
    $controls{order} = $cgi-&gt;popup_menu (-name      =&gt; $name . 'Order',
                                         -default   =&gt; $defaults-&gt;{order},
                                         -tabindex  =&gt; $tab_index-&gt;{order},
                                         -override  =&gt; 1,
                                         -values    =&gt; [1..$field_count+1]);
    $controls{label} = $cgi-&gt;textfield (-name     =&gt; $name . 'Label',
                                        -default  =&gt; $defaults-&gt;{label},
                                        -tabindex  =&gt; $tab_index-&gt;{label},
                                        -size     =&gt; 20);
    $controls{required} = $cgi-&gt;checkbox (-name    =&gt; $name . 'Required',
                                          -default  =&gt; $defaults-&gt;{required},
                                          -tabindex  =&gt; $tab_index-&gt;{required},
                                          -label =&gt; '');
    $controls{display} =  $cgi-&gt;popup_menu (-name     =&gt; $name . 'Display',
                                            -default  =&gt;
                                                  $defaults-&gt;{display} ? 1 : 0,
                                            -tabindex =&gt; $tab_index-&gt;{display},
                                            -values   =&gt; [0, 1],
                                            -labels   =&gt; {0 =&gt;
                                               'in Event Details',
                                                          1 =&gt;
                                               'in Event Summary and Details'});
    return %controls;
}


# Single-line text field
sub _new_textfield_div {
    my $self = shift;
    my %args = @_;
    my ($cgi, $i18n, $field, $display, $display_order, $field_count)
             = @args{qw /cgi i18n field display display_order field_count/};
    my %defaults;
    if ($field) {
        $defaults{name}     = $field-&gt;name;
        $defaults{default}  = $field-&gt;default;
        $defaults{required} = $field-&gt;required;
        $defaults{display}  = $field-&gt;display;
        $defaults{label}    = $field-&gt;label;
        $defaults{width}    = $field-&gt;cols;
        $defaults{max}      = $field-&gt;max_size;
        if (ref $defaults{default}) {
            $defaults{default} = join ',', @{$defaults{default}};
        }
    }
    $defaults{order} = $display_order;

    my @display_order = qw /name default required label width limit
                            display order/;
    my $order_index = ($field_count * 2) + 1;
    my %tab_index = map {$_ =&gt; $order_index++} @display_order;

    # Get Name, Required, Display?, Label, Order
    my %common_fields = _common_form_fields (name        =&gt; 'textfield',
                                             defaults    =&gt; \%defaults,
                                             field_count =&gt; $field_count,
                                             tab_index   =&gt; \%tab_index,
                                             cgi         =&gt; $cgi);

    my $default  = $cgi-&gt;textfield (-name      =&gt; 'textfieldDefault',
                                    -default   =&gt; $defaults{default},
                                    -tabindex  =&gt; $tab_index{default},
                                    -size      =&gt; 20,
                                    -maxlength =&gt; 60);
    my $width    = $cgi-&gt;textfield (-name      =&gt; 'textfieldCols',
                                    -default   =&gt; $defaults{width} || '20',
                                    -tabindex  =&gt; $tab_index{width},
                                    -size      =&gt; 3,
                                    -maxlength =&gt; 4);
    my $limit    = $cgi-&gt;textfield (-name      =&gt; 'textfieldMax',
                                    -default   =&gt; $defaults{max} || '',
                                    -tabindex  =&gt; $tab_index{limit},
                                    -size      =&gt; 3,
                                    -maxlength =&gt; 5);
    my %controls = (name     =&gt; $common_fields{name},
                    default  =&gt; $default,
                    required =&gt; $common_fields{required},
                    display  =&gt; $common_fields{display},
                    label    =&gt; $common_fields{label},
                    order    =&gt; $common_fields{order},
                    width    =&gt; $width,
                    limit    =&gt; $limit);

    my @rows;
    foreach my $item (@display_order) {
        push @rows, $cgi-&gt;Tr ($cgi-&gt;td ({-align =&gt; 'right'},
                                        $self-&gt;{form_labels}-&gt;{$item}),
                              $cgi-&gt;td ({-align =&gt; 'left'},  $controls{$item}));
    }
    my $table = $cgi-&gt;table ({-align =&gt; 'center'}, @rows);
    my $hide  = $display ? '' : 'style = "display: none"';
    return qq (&lt;div id="New_textfield_div" $hide&gt;$table&lt;/div&gt;);
}

# Multi-line text area
sub _new_textarea_div {
    my $self = shift;
    my %args = @_;
    my ($cgi, $i18n, $field, $display, $display_order, $field_count)
             = @args{qw /cgi i18n field display display_order field_count/};
    my %defaults;
    if ($field) {
        $defaults{name}     = $field-&gt;name;
        $defaults{default}  = $field-&gt;default;
        $defaults{required} = $field-&gt;required;
        $defaults{display}  = $field-&gt;display;
        $defaults{label}    = $field-&gt;label;
        $defaults{cols}     = $field-&gt;cols;
        $defaults{rows}     = $field-&gt;rows;
        if (ref $defaults{default}) {
            $defaults{default} = join "\n", @{$defaults{default}};
        }
    }
    $defaults{order} = $display_order;

    my @display_order = qw /name default required label cols rows
                            display order/;
    my $order_index = ($field_count * 2) + 1;
    my %tab_index = map {$_ =&gt; $order_index++} @display_order;

    my $default  = $cgi-&gt;textarea (-name     =&gt; 'textareaDefault',
                                   -default  =&gt; $defaults{default},
                                   -tabindex =&gt; $tab_index{default},
                                   -rows     =&gt; 6,
                                   -cols     =&gt; 40,
                                   -wrap     =&gt; 'SOFT');
    my $cols     = $cgi-&gt;textfield (-name      =&gt; 'textareaCols',
                                    -default   =&gt; $defaults{cols} || '40',
                                    -tabindex =&gt; $tab_index{cols},
                                    -size      =&gt; 3,
                                    -maxlength =&gt; 4);
    my $rows     = $cgi-&gt;textfield (-name      =&gt; 'textareaRows',
                                    -default   =&gt; $defaults{rows} || '6',
                                    -tabindex =&gt; $tab_index{rows},
                                    -size      =&gt; 3,
                                    -maxlength =&gt; 4);
    # Get Name, Order, etc.
    my %common_fields = _common_form_fields (name        =&gt; 'textarea',
                                             defaults    =&gt; \%defaults,
                                             field_count =&gt; $field_count,
                                             tab_index   =&gt; \%tab_index,
                                             cgi         =&gt; $cgi);
    my %controls = (name     =&gt; $common_fields{name},
                    default  =&gt; $default,
                    label    =&gt; $common_fields{label},
                    required =&gt; $common_fields{required},
                    display  =&gt; $common_fields{display},
                    order    =&gt; $common_fields{order},
                    cols     =&gt; $cols,
                    rows     =&gt; $rows);

    my @rows;
    foreach my $item (@display_order) {
        push @rows, $cgi-&gt;Tr ($cgi-&gt;td ({-align =&gt; 'right'},
                                        $self-&gt;{form_labels}-&gt;{$item}),
                              $cgi-&gt;td ({-align =&gt; 'left'},  $controls{$item}));
    }
    my $table = $cgi-&gt;table ({-align =&gt; 'center'}, @rows);
    my $hide = $display ? '' : 'style = "display: none"';
    return qq (&lt;div id="New_textarea_div" $hide&gt;$table&lt;/div&gt;);
}

# Single select drop-down menu
sub _new_select_div {
    my $self = shift;
    my %args = @_;
    my ($cgi, $i18n, $field, $display, $display_order, $field_count)
             = @args{qw /cgi i18n field display display_order field_count/};
    my %defaults;
    if ($field) {
        $defaults{name}     = $field-&gt;name;
        $defaults{default}  = $field-&gt;default;
        $defaults{required} = $field-&gt;required;
        $defaults{display}  = $field-&gt;display;
        $defaults{label}    = $field-&gt;label;
        $defaults{values}   = join "\n", $field-&gt;input_values;
        if (ref $defaults{default}) {
            $defaults{default} = join ',', @{$defaults{default}};
        }
    }
    $defaults{order} = $display_order;

    my @display_order = qw /name values default required label display order/;
    my $order_index = ($field_count * 2) + 1;
    my %tab_index = map {$_ =&gt; $order_index++} @display_order;

    # Get Name, Required, Label, Order
    my %common_fields = _common_form_fields (name        =&gt; 'select',
                                             defaults    =&gt; \%defaults,
                                             field_count =&gt; $field_count,
                                             tab_index   =&gt; \%tab_index,
                                             cgi         =&gt; $cgi);
    my $default  = $cgi-&gt;textfield (-name      =&gt; 'selectDefault',
                                    -default   =&gt; $defaults{default},
                                    -tabindex  =&gt; $tab_index{default},
                                    -size      =&gt; 20,
                                    -maxlength =&gt; 60);
    my $values   = $cgi-&gt;textarea (-name =&gt; 'selectInputValues',
                                   -default =&gt; $defaults{values},
                                   -tabindex  =&gt; $tab_index{values},
                                   -rows =&gt; 6,
                                   -cols =&gt; 40,
                                   -wrap =&gt; 'SOFT');

    my %controls = (name     =&gt; $common_fields{name},
                    default  =&gt; $default,
                    required =&gt; $common_fields{required},
                    display  =&gt; $common_fields{display},
                    label    =&gt; $common_fields{label},
                    order    =&gt; $common_fields{order},
                    values   =&gt; $values);

    my @rows;
    foreach my $item (@display_order) {
        push @rows, $cgi-&gt;Tr ($cgi-&gt;td ({-align =&gt; 'right'},
                                        $self-&gt;{form_labels}-&gt;{$item}),
                              $cgi-&gt;td ({-align =&gt; 'left'},  $controls{$item}));
    }
    my $table = $cgi-&gt;table ({-align =&gt; 'center'}, @rows);
    my $hide  = $display ? '' : 'style = "display: none"';
    return qq (&lt;div id="New_select_div" $hide&gt;$table&lt;/div&gt;);
}

# Multi select drop-down menu
sub _new_multiselect_div {
    my $self = shift;
    my %args = @_;
    my ($cgi, $i18n, $field, $display, $display_order, $field_count)
             = @args{qw /cgi i18n field display display_order field_count/};
    my %defaults;
    if ($field) {
        $defaults{name}     = $field-&gt;name;
        $defaults{default}  = $field-&gt;is_multi_valued
                                  ? join "\n", @{$field-&gt;default}
                                  : $field-&gt;default;
        $defaults{required} = $field-&gt;required;
        $defaults{display}  = $field-&gt;display;
        $defaults{label}    = $field-&gt;label;
        $defaults{values}   = join "\n", $field-&gt;input_values;
        $defaults{rows}     = $field-&gt;rows;
    }
    $defaults{order} = $display_order;

    my @display_order = qw /name values multidefault required label rows
                            display order/;
    my $order_index = ($field_count * 2) + 1;
    my %tab_index = map {$_ =&gt; $order_index++} @display_order;

    # Get Name, Required, Label, Order
    my %common_fields = _common_form_fields (name        =&gt; 'multiselect',
                                             defaults    =&gt; \%defaults,
                                             field_count =&gt; $field_count,
                                             tab_index   =&gt; \%tab_index,
                                             cgi         =&gt; $cgi);
    my $default  = $cgi-&gt;textarea (-name    =&gt; 'multiselectDefault',
                                   -default =&gt; $defaults{default},
                                   -tabindex  =&gt; $tab_index{multidefault},
                                   -rows    =&gt; 4,
                                   -cols    =&gt; 40,
                                   -wrap    =&gt; 'SOFT');
    my $values   = $cgi-&gt;textarea (-name =&gt; 'multiselectInputValues',
                                   -default =&gt; $defaults{values},
                                   -tabindex  =&gt; $tab_index{values},
                                   -rows =&gt; 6,
                                   -cols =&gt; 40,
                                   -wrap =&gt; 'SOFT');
    my $rows     = $cgi-&gt;textfield (-name      =&gt; 'multiselectRows',
                                    -default   =&gt; $defaults{rows} || '5',
                                    -tabindex =&gt; $tab_index{rows},
                                    -size      =&gt; 3,
                                    -maxlength =&gt; 4);

    my %controls = (name     =&gt; $common_fields{name},
                    multidefault  =&gt; $default,
                    required =&gt; $common_fields{required},
                    display  =&gt; $common_fields{display},
                    label    =&gt; $common_fields{label},
                    order    =&gt; $common_fields{order},
                    rows     =&gt; $rows,
                    values   =&gt; $values);

    my @rows;
    foreach my $item (@display_order) {
        push @rows, $cgi-&gt;Tr ($cgi-&gt;td ({-align =&gt; 'right'},
                                        $self-&gt;{form_labels}-&gt;{$item}),
                              $cgi-&gt;td ({-align =&gt; 'left'},  $controls{$item}));
    }
    my $table = $cgi-&gt;table ({-align =&gt; 'center'}, @rows);
    my $hide  = $display ? '' : 'style = "display: none"';
    return qq (&lt;div id="New_multiselect_div" $hide&gt;$table&lt;/div&gt;);
}

sub _new_checkbox_div {
    my $self = shift;
    my %args = @_;
    my ($cgi, $i18n, $field, $display, $display_order, $field_count)
             = @args{qw /cgi i18n field display display_order field_count/};
    my %defaults;
    if ($field) {
        $defaults{name}     = $field-&gt;name;
        $defaults{default}  = $field-&gt;default;
        $defaults{required} = $field-&gt;required;
        $defaults{display}  = $field-&gt;display;
        $defaults{label}    = $field-&gt;label;
    }
    $defaults{order} = $display_order;

    my @display_order = qw /name default label display order/;
    my $order_index = ($field_count * 2) + 1;
    my %tab_index = map {$_ =&gt; $order_index++} @display_order;

    # Get Name, Required, Label, Order (don't use "required" actually)
    my %common_fields = _common_form_fields (name        =&gt; 'checkbox',
                                             defaults    =&gt; \%defaults,
                                             field_count =&gt; $field_count,
                                             tab_index   =&gt; \%tab_index,
                                             cgi         =&gt; $cgi);

    my $default  = $cgi-&gt;checkbox (-name      =&gt; 'checkboxDefault',
                                   -checked   =&gt; $defaults{default},
                                   -tabindex  =&gt; $tab_index{default},
                                   -label     =&gt; '');
    my %controls = (name     =&gt; $common_fields{name},
                    default  =&gt; $default,
                    label    =&gt; $common_fields{label},
                    display  =&gt; $common_fields{display},
                    order    =&gt; $common_fields{order});

    my @rows;
    foreach my $item (@display_order) {
        push @rows, $cgi-&gt;Tr ($cgi-&gt;td ({-align =&gt; 'right'},
                                        $self-&gt;{form_labels}-&gt;{$item}),
                              $cgi-&gt;td ({-align =&gt; 'left'},  $controls{$item}));
    }
    my $table = $cgi-&gt;table ({-align =&gt; 'center'}, @rows);
    my $hide  = $display ? '' : 'style = "display: none"';
    return qq (&lt;div id="New_checkbox_div" $hide&gt;$table&lt;/div&gt;);
}


sub display_modify_stuff {
    my ($self, $field_id, $message) = @_;
    my $i18n = $self-&gt;I18N;
    my $cgi = CGI-&gt;new;
    my $calName = $self-&gt;calendarName;
    my $fields_lr = $self-&gt;prefs-&gt;get_custom_fields (system =&gt; undef);
    my $field_count = @$fields_lr;
    my ($field) = grep {$_-&gt;id eq $field_id} @$fields_lr;
    my $only_message;
    if (!$field or !ref $field) {
        $message = "Can't find field for id $field_id. $field";
        $only_message = 1;
    }

    my $position = 1;
    my @order = split ',', ($self-&gt;prefs-&gt;CustomFieldOrder || '');
    foreach my $existing_id (@order) {
        last if ($existing_id  eq $field_id);
        $position++;
    }

    print GetHTML-&gt;startHTML (title  =&gt; $i18n-&gt;get ('Custom Fields') . ': ' .
                                        ($calName ||
                                             $i18n-&gt;get ('System Defaults'))
                                        . $i18n-&gt;get ('Modify'),
                              op     =&gt; $self);
    print GetHTML-&gt;SectionHeader ($i18n-&gt;get ('Modify Custom Field'));

    if ($message) {
        print '&lt;center&gt;';
        print qq (&lt;p class="ErrorHighlight"&gt;$message&lt;/p&gt;);
        print '&lt;/center&gt;';
    }
    if ($only_message) {
        return;
    }

    print $cgi-&gt;startform;
    print '&lt;center&gt;&lt;div style="border-width: 1px; border-style: solid; '
          . 'text-align: center; padding: 5px; margin: 5px;"&gt;';
    print $i18n-&gt;get ('Field Type') . ': ';
    print $self-&gt;_field_setting_divs (CGI   =&gt; $cgi,
                                      I18N  =&gt; $i18n,
                                      field =&gt; $field,
                                      field_count =&gt; $field_count,
                                      position    =&gt; $position);
    print '&lt;/div&gt;&lt;/center&gt;';
    print $cgi-&gt;submit (-name =&gt; 'SaveModify', -value =&gt; $i18n-&gt;get ('Save'));
    print '&amp;nbsp;';
    print $cgi-&gt;submit (-value =&gt; $i18n-&gt;get ('Cancel'),
                        -onClick =&gt; 'window.close()');

    print $cgi-&gt;hidden (-name =&gt; 'FieldID'     , -value =&gt; $field-&gt;id);
    print $cgi-&gt;hidden (-name =&gt; 'Op',           -value =&gt; __PACKAGE__);
    print $cgi-&gt;hidden (-name =&gt; 'CalendarName', -value =&gt; $calName)
      if $calName;
    print $cgi-&gt;endform;
    print $cgi-&gt;end_html;
}

# Create DIVs of form controls for all types of custom fields.
# All but one div is set to "display: none" so they don't show; made
# visible when the pulldown selector set to that field type.
sub _field_setting_divs {
    my $self = shift;
    my %args = @_;
    my $cgi   = $args{CGI};
    my $i18n  = $args{I18N};
    my $field = $args{field};
    my $default_type = $args{default_type};
    my $field_count  = $args{field_count};
    my $position     = $args{position} || ($field_count + 1);

    my @type_names = qw /textfield textarea select multiselect checkbox/;
    my %type_names = (textfield   =&gt; 'Text - Single Line',
                      textarea    =&gt; 'Text - Multiple Line',
                      select      =&gt; 'Popup Menu - Choose One',
                      multiselect =&gt; 'Popup Menu - Choose Many',
                      checkbox    =&gt; 'Checkbox');

    # If we've got a field, we're editing; set defaults appropriately
    my %defaults;
    $defaults{field_type} = $field ? $field-&gt;input_type : $default_type;

    # First, JS for hiding/showing divs
    my $html =&lt;&lt;END_JS;
&lt;script type="text/javascript"&gt;
&lt;!--
  var displayed_div;
  function display_div (field_type) {
      if (displayed_div != undefined) {
          displayed_div.style.display = "none";
      }
      el = document.getElementById ('New_' + field_type + '_div');
      el.style.display = "";
      displayed_div = el;
  }
//--&gt;
&lt;/script&gt;
END_JS

    # Next, the pulldown to allow selecting a type
    $html .= $cgi-&gt;popup_menu (-name     =&gt; 'FieldTypeSelector',
                               -default  =&gt; $defaults{field_type},
                               -values   =&gt; \@type_names,
                               -labels   =&gt; \%type_names,
                               -tabindex =&gt; ($field_count * 2) + 1,
                               -onChange =&gt;
               'display_div(this.options[this.selectedIndex].value)');

    $html .= '&lt;hr width="50%"/&gt;';

    my %display_it = ($defaults{field_type} =&gt; 1);

    my %div_subs = (textfield   =&gt; \&amp;_new_textfield_div,
                    textarea    =&gt; \&amp;_new_textarea_div,
                    select      =&gt; \&amp;_new_select_div,
                    multiselect =&gt; \&amp;_new_multiselect_div,
                    checkbox    =&gt; \&amp;_new_checkbox_div);

    # Finally, the divs for each type
    foreach my $type (@type_names) {
        $html .= $div_subs{$type}-&gt;($self,
                                    cgi           =&gt; $cgi,
                                    i18n          =&gt; $i18n,
                                    field         =&gt; $field,
                                    field_count   =&gt; $field_count,
                                    display_order =&gt; $position,
                                    display       =&gt; $display_it{$type});
    }

    my $default_id = "New_$defaults{field_type}_div";
    $html .=&lt;&lt;END_SET_DIV;
&lt;script type="text/javascript"&gt;
&lt;!--
  var displayed_div = document.getElementById ('$default_id');
//--&gt;
&lt;/script&gt;
END_SET_DIV

    return $html;
}


sub cssDefaults {
    my $self = shift;
    my $css = $self-&gt;SUPER::cssDefaults;
    $css .= GetHTML-&gt;AdminCSS ($self);
    return $css;
}

1;
</pre></body></html>