lib/TWiki/Form/FieldDefinition.pm
changeset 0 414e01d06fd5
child 1 e2915a7cbdfa
equal deleted inserted replaced
-1:000000000000 0:414e01d06fd5
       
     1 # See bottom of file for license and copyright details
       
     2 # base class for all form field types
       
     3 
       
     4 =pod
       
     5 
       
     6 ---+ package TWiki::Form::FieldDefinition
       
     7 
       
     8 Base class of all field definition classes.
       
     9 
       
    10 Type-specific classes are derived from this class to define specific
       
    11 per-type behaviours. This class also provides default behaviours for when
       
    12 a specific type cannot be loaded.
       
    13 
       
    14 =cut
       
    15 
       
    16 package TWiki::Form::FieldDefinition;
       
    17 
       
    18 use strict;
       
    19 use Assert;
       
    20 
       
    21 =pod
       
    22 
       
    23 ---++ ClassMethod new(%...)
       
    24 
       
    25 Construct a new FieldDefinition. Parameters are passed in a hash. See
       
    26 Form.pm for how it is called. Subclasses should pass @_ on to this class.
       
    27 
       
    28 =cut
       
    29 
       
    30 sub new {
       
    31     my $class = shift;
       
    32     my %attrs = @_;
       
    33     ASSERT($attrs{session}) if DEBUG;
       
    34 
       
    35     $attrs{name} ||= '';
       
    36     $attrs{attributes} ||= '';
       
    37     $attrs{type} ||= ''; # default
       
    38     $attrs{size} =~ s/^\s*//;
       
    39     $attrs{size} =~ s/\s*$//;
       
    40 
       
    41     return bless(\%attrs, $class);
       
    42 }
       
    43 
       
    44 =begin twiki
       
    45 
       
    46 ---++ ObjectMethod finish()
       
    47 Break circular references.
       
    48 
       
    49 =cut
       
    50 
       
    51 # Note to developers; please undef *all* fields in the object explicitly,
       
    52 # whether they are references or not. That way this method is "golden
       
    53 # documentation" of the live fields in the object.
       
    54 sub finish {
       
    55     my $this = shift;
       
    56 
       
    57     undef $this->{name};
       
    58     undef $this->{attributes};
       
    59     undef $this->{type};
       
    60     undef $this->{size};
       
    61     undef $this->{session};
       
    62 }
       
    63 
       
    64 =pod
       
    65 
       
    66 ---++ isEditable() -> $boolean
       
    67 
       
    68 Is the field type editable? Labels aren't, for example. Subclasses may need
       
    69 to redefine this.
       
    70 
       
    71 =cut
       
    72 
       
    73 sub isEditable { 1 }
       
    74 
       
    75 =pod
       
    76 
       
    77 ---++ isMultiValued() -> $boolean
       
    78 
       
    79 Is the field type multi-valued (i.e. does it store multiple values)?
       
    80 Subclasses may need to redefine this.
       
    81 
       
    82 =cut
       
    83 
       
    84 sub isMultiValued { 0 }
       
    85 
       
    86 =pod
       
    87 
       
    88 ---++ isTextMergeable() -> $boolean
       
    89 
       
    90 Is this field type mergeable using a conventional text merge?
       
    91 
       
    92 =cut
       
    93 
       
    94 # can't merge multi-valued fields (select+multi, checkbox)
       
    95 sub isTextMergeable { return !shift->isMultiValued() }
       
    96 
       
    97 =pod
       
    98 
       
    99 ---++ isMandatory() -> $boolean
       
   100 
       
   101 Is this field mandatory (required)?
       
   102 
       
   103 =cut
       
   104 
       
   105 sub isMandatory { return shift->{attributes} =~ /M/ }
       
   106 
       
   107 =pod
       
   108 
       
   109 ---++ renderForEdit( $web, $topic, $value ) -> ($col0html, $col1html)
       
   110    =$web= - the web containing the topic being edited
       
   111    =$topic= - the topic being edited
       
   112 Render the field for editing. Returns two chunks of HTML; the
       
   113 =$col0html= is appended to the HTML for the first column in the
       
   114 form table, and the =$col1html= is used as the content of the second column.
       
   115 
       
   116 =cut
       
   117 
       
   118 sub renderForEdit {
       
   119     my( $this, $web, $topic, $value ) = @_;
       
   120 
       
   121     # Treat like text, make it reasonably long, add a warning
       
   122     return ( '<br /><span class="twikiAlert">MISSING TYPE '.
       
   123                $this->{type}.'</span>',
       
   124             CGI::textfield( -class => $this->cssClasses('twikiEditFormError'),
       
   125                             -name => $this->{name},
       
   126                             -size => 80,
       
   127                             -value => $value ));
       
   128 }
       
   129 
       
   130 =pod
       
   131 
       
   132 ---++ cssClasses(@classes) -> $classes
       
   133 Construct a list of the CSS classes for the form field. Adds additional
       
   134 class specifiers related to the attributes of the field e.g mandatory.
       
   135 Pass it a list of the other classnames you want on the field.
       
   136 
       
   137 =cut
       
   138 
       
   139 sub cssClasses {
       
   140     my $this = shift;
       
   141     if ($this->isMandatory()) {
       
   142         push(@_, 'twikiMandatory');
       
   143     }
       
   144     return join(' ', @_);
       
   145 }
       
   146 
       
   147 =pod
       
   148 
       
   149 ---++ getDefaultValue() -> $value
       
   150 Try and get a sensible default value for the field from the
       
   151 values stored in the form definition. The result should be
       
   152 a value string.
       
   153 
       
   154 Some subclasses may not support the definition of defaults in
       
   155 the form definition. In that case this method should return =undef=.
       
   156 
       
   157 =cut
       
   158 
       
   159 sub getDefaultValue {
       
   160     my $this = shift;
       
   161 
       
   162     my $value = $this->{value};
       
   163     $value = '' unless defined $value;  # allow 0 values
       
   164 
       
   165     return $value;
       
   166 }
       
   167 
       
   168 =pod
       
   169 
       
   170 ---++ renderHidden($meta) -> $html
       
   171 Render the form in =$meta= as a set of hidden fields.
       
   172 
       
   173 =cut
       
   174 
       
   175 sub renderHidden {
       
   176     my( $this, $meta ) = @_;
       
   177 
       
   178     my $value;
       
   179     if( $this->{name} ) {
       
   180         my $field = $meta->get( 'FIELD', $this->{name} );
       
   181         $value = $field->{value};
       
   182     }
       
   183 
       
   184     my @values;
       
   185 
       
   186     if( defined( $value )) {
       
   187         if( $this->isMultiValued() ) {
       
   188             push( @values, split(/\s*,\s*/, $value ));
       
   189         } else {
       
   190             push( @values, $value );
       
   191         }
       
   192     } else {
       
   193         $value = $this->getDefaultValue();
       
   194         push( @values, $this->getDefaultValue() ) if $value;
       
   195     }
       
   196 
       
   197     return '' unless scalar( @values );
       
   198 
       
   199     return CGI::hidden( -name => $this->{name}, -default => \@values );
       
   200 }
       
   201 
       
   202 =pod
       
   203 
       
   204 ---++ populateMetaDataFromQuery( $query, $meta, $old ) -> ($bValid, $bPresent)
       
   205 
       
   206 Given a CGI =$query=, a =$meta= object, and an array of =$old= field entries,
       
   207 then populate the $meta with a row for this field definition, taking the
       
   208 content from the query if it's there, otherwise from $old or failing that,
       
   209 from the default defined for the type. Refuses to update mandatory fields
       
   210 that have an empty value.
       
   211 
       
   212 Return $bValid true if the value in $meta was updated (either from the
       
   213 query or from a default in the form.
       
   214 Return $bPresent true if a value was present in the query (even it was undef)
       
   215 
       
   216 =cut
       
   217 
       
   218 sub populateMetaFromQueryData {
       
   219     my( $this, $query, $meta, $old ) = @_;
       
   220     my $value;
       
   221     my $bPresent = 0;
       
   222 
       
   223     return unless $this->{name};
       
   224 
       
   225     if( defined( $query->param( $this->{name} ))) {
       
   226         $bPresent = 1;
       
   227         if( $this->isMultiValued() ) {
       
   228             my @values = $query->param( $this->{name} );
       
   229 
       
   230             if( scalar( @values ) == 1 ) {
       
   231                 @values = split( /,|%2C/, $values[0] );
       
   232             }
       
   233             my %vset = ();
       
   234             foreach my $val ( @values ) {
       
   235                 $val =~ s/^\s*//o;
       
   236                 $val =~ s/\s*$//o;
       
   237                 # skip empty values
       
   238                 $vset{$val} = (defined $val && $val =~ /\S/);
       
   239             }
       
   240             $value = '';
       
   241             my $isValues = ( $this->{type} =~ /\+values/ );
       
   242 
       
   243             foreach my $option ( @{$this->getOptions()} ) {
       
   244                 $option =~ s/^.*?[^\\]=(.*)$/$1/ if $isValues;
       
   245                 # Maintain order of definition
       
   246                 if( $vset{$option} ) {
       
   247                     $value .= ', ' if length( $value );
       
   248                     $value .= $option;
       
   249                 }
       
   250             }
       
   251         } else {
       
   252             $value = $query->param( $this->{name} );
       
   253             if( defined( $value ) && $this->{session}->inContext('edit')) {
       
   254                 $value = TWiki::expandStandardEscapes( $value );
       
   255             }
       
   256         }
       
   257     }
       
   258 
       
   259     # Find the old value of this field
       
   260     my $preDef;
       
   261     foreach my $item ( @$old ) {
       
   262         if( $item->{name} eq $this->{name} ) {
       
   263             $preDef = $item;
       
   264             last;
       
   265         }
       
   266     }
       
   267     my $def;
       
   268 
       
   269     if( defined( $value ) ) {
       
   270         # mandatory fields must have length > 0
       
   271         if( $this->isMandatory() && length( $value ) == 0) {
       
   272             return (0, $bPresent);
       
   273         }
       
   274         # NOTE: title and name are stored in the topic so that it can be
       
   275         # viewed without reading in the form definition
       
   276         my $title = $this->{title};
       
   277         if( $this->{definingTopic} ) {
       
   278             $title = '[['.$this->{definingTopic}.']['.$title.']]';
       
   279         }
       
   280         $def =
       
   281           {
       
   282               name =>  $this->{name},
       
   283               title => $title,
       
   284               value => $value,
       
   285               attributes => $this->{attributes},
       
   286           };
       
   287     } elsif( $preDef ) {
       
   288         $def = $preDef;
       
   289     } else {
       
   290         return (0, $bPresent);
       
   291     }
       
   292 
       
   293     $meta->putKeyed( 'FIELD', $def ) if $def;
       
   294 
       
   295     return (1, $bPresent);
       
   296 }
       
   297 
       
   298 =pod
       
   299 
       
   300 ---++ ObjectMethod renderForDisplay($format, $attrs) -> $html
       
   301 
       
   302 Render the field for display, under the control of $attrs.
       
   303 
       
   304 The following vars in $format are expanded:
       
   305    $title - title of the form field
       
   306    $value - expanded to the *protected* value of the form field
       
   307 
       
   308 The value is protected by TWiki::Render::protectFormFieldValue.
       
   309 
       
   310 =cut
       
   311 
       
   312 sub renderForDisplay {
       
   313     my( $this, $format, $value, $attrs ) = @_;
       
   314     ASSERT(!$attrs || ref($attrs) eq 'HASH') if DEBUG;
       
   315 
       
   316     require TWiki::Render;
       
   317     $value = TWiki::Render::protectFormFieldValue( $value, $attrs );
       
   318 
       
   319     $format =~ s/\$title/$this->{title}/g;
       
   320     $format =~ s/\$value/$value/g;
       
   321     $format =~ s/\$name/$this->{name}/g;
       
   322     $format =~ s/\$attributes/$this->{attributes}/g;
       
   323     $format =~ s/\$type/$this->{type}/g;
       
   324     $format =~ s/\$size/$this->{size}/g;
       
   325     my $definingTopic = $this->{definingTopic}|'FIELD';
       
   326     $format =~ s/\$definingTopic/$definingTopic/g;
       
   327 
       
   328     return $format;
       
   329 }
       
   330 
       
   331 1;
       
   332 __DATA__
       
   333 
       
   334 Module of TWiki Enterprise Collaboration Platform, http://TWiki.org/
       
   335 
       
   336 Copyright (C) 2001-2007 TWiki Contributors. All Rights Reserved.
       
   337 TWiki Contributors are listed in the AUTHORS file in the root of
       
   338 this distribution. NOTE: Please extend that file, not this notice.
       
   339 
       
   340 This program is free software; you can redistribute it and/or
       
   341 modify it under the terms of the GNU General Public License
       
   342 as published by the Free Software Foundation; either version 2
       
   343 of the License, or (at your option) any later version. For
       
   344 more details read LICENSE in the root of this distribution.
       
   345 
       
   346 This program is distributed in the hope that it will be useful,
       
   347 but WITHOUT ANY WARRANTY; without even the implied warranty of
       
   348 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
       
   349 
       
   350 As per the GPL, removal of this notice is prohibited.
       
   351