lib/TWiki/Plugins/PreferencesPlugin.pm
author Colas Nahaboo <colas@nahaboo.net>
Sat, 26 Jan 2008 15:50:53 +0100
changeset 0 414e01d06fd5
child 1 e2915a7cbdfa
permissions -rw-r--r--
RELEASE 4.2.0 freetown
     1 # Plugin for TWiki Enterprise Collaboration Platform, http://TWiki.org/
     2 #
     3 # Copyright (C) 2005-2007  TWiki Contributors.
     4 # All Rights Reserved. TWiki Contributors are listed in the
     5 # AUTHORS file in the root of this distribution.
     6 # NOTE: Please extend that file, not this notice.
     7 #
     8 # This program is free software; you can redistribute it and/or
     9 # modify it under the terms of the GNU General Public License
    10 # as published by the Free Software Foundation; either version 2
    11 # of the License, or (at your option) any later version. For
    12 # more details read LICENSE in the root of this distribution.
    13 #
    14 # This program is distributed in the hope that it will be useful,
    15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
    16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    17 #
    18 # For licensing info read LICENSE file in the TWiki root.
    19 
    20 # Still do to:
    21 # Handle continuation lines (see Prefs::parseText). These should always
    22 # go into a text area.
    23 
    24 package TWiki::Plugins::PreferencesPlugin;
    25 
    26 use strict;
    27 
    28 require TWiki::Func;    # The plugins API
    29 require TWiki::Plugins; # For the API version
    30 
    31 use vars qw( $VERSION $RELEASE @shelter );
    32 
    33 # This should always be $Rev: 15487 (22 Jan 2008) $ so that TWiki can determine the checked-in
    34 # status of the plugin. It is used by the build automation tools, so
    35 # you should leave it alone.
    36 $VERSION = '$Rev: 15487 (22 Jan 2008) $';
    37 
    38 # This is a free-form string you can use to "name" your own plugin version.
    39 # It is *not* used by the build automation tools, but is reported as part
    40 # of the version number in PLUGINDESCRIPTIONS.
    41 $RELEASE = 'TWiki-4.2';
    42 
    43 my $MARKER = "\007";
    44 
    45 # Markers used during form generation
    46 my $START_MARKER  = $MARKER.'STARTPREF'.$MARKER;
    47 my $END_MARKER    = $MARKER.'ENDPREF'.$MARKER;
    48 
    49 sub initPlugin {
    50     # check for Plugins.pm versions
    51     if( $TWiki::Plugins::VERSION < 1.026 ) {
    52         TWiki::Func::writeWarning( 'Version mismatch between PreferencesPlugin and Plugins.pm' );
    53         return 0;
    54     }
    55     @shelter = ();
    56 
    57     return 1;
    58 }
    59 
    60 sub beforeCommonTagsHandler {
    61     ### my ( $text, $topic, $web ) = @_;
    62     my $topic = $_[1];
    63     my $web = $_[2];
    64     return unless ( $_[0] =~ m/%EDITPREFERENCES(?:{(.*?)})?%/ );
    65 
    66     require CGI;
    67     require TWiki::Attrs;
    68     my $formDef;
    69     my $attrs = new TWiki::Attrs( $1 );
    70     if( defined( $attrs->{_DEFAULT} )) {
    71         my( $formWeb, $form ) = TWiki::Func::normalizeWebTopicName(
    72             $web, $attrs->{_DEFAULT} );
    73 
    74         # SMELL: Unpublished API. No choice, though :-(
    75         require TWiki::Form;    # SMELL
    76         $formDef =
    77           new TWiki::Form( $TWiki::Plugins::SESSION, $formWeb, $form );
    78     }
    79 
    80     my $query = TWiki::Func::getCgiQuery();
    81 
    82     my $action = lc $query->param( 'prefsaction' );
    83     $query->Delete( 'prefsaction' );
    84     $action =~ s/\s.*$//;
    85 
    86     if ( $action eq 'edit' ) {
    87         TWiki::Func::setTopicEditLock( $web, $topic, 1 );
    88         
    89         # Replace setting values by form fields but not inside comments Item4816
    90         my $outtext = '';
    91         my $insidecomment = 0;
    92         foreach my $token ( split/(<!--|-->)/, $_[0] ) {
    93             if ( $token =~ /<!--/ ) {
    94                 $insidecomment++;
    95             } elsif ( $token =~ /-->/ ) {
    96                 $insidecomment-- if ( $insidecomment > 0 );
    97             } elsif ( !$insidecomment ) {
    98                 $token =~ s(^((?:\t|   )+\*\sSet\s*)(\w+)\s*\=(.*$(\n[ \t]+[^\s*].*$)*))
    99                            ($1._generateEditField($web, $topic, $2, $3, $formDef))gem;
   100             }
   101             $outtext .= $token;
   102         }
   103         $_[0] = $outtext;
   104           
   105         $_[0] =~ s/%EDITPREFERENCES({.*?})?%/
   106           _generateControlButtons($web, $topic)/ge;
   107         my $viewUrl = TWiki::Func::getScriptUrl(
   108             $web, $topic, 'viewauth' );
   109         my $startForm = CGI::start_form(
   110             -name => 'editpreferences',
   111             -method => 'post',
   112             -action => $viewUrl );
   113         $startForm =~ s/\s+$//s;
   114         my $endForm = CGI::end_form();
   115         $endForm =~ s/\s+$//s;
   116         $_[0] =~ s/^(.*?)$START_MARKER(.*)$END_MARKER(.*?)$/$1$startForm$2$endForm$3/s;
   117         $_[0] =~ s/$START_MARKER|$END_MARKER//gs;
   118     }
   119 
   120     if( $action eq 'cancel' ) {
   121         TWiki::Func::setTopicEditLock( $web, $topic, 0 );
   122 
   123     } elsif( $action eq 'save' ) {
   124 
   125         my( $meta, $text ) = TWiki::Func::readTopic( $web, $topic );
   126         $text =~ s(^((?:\t|   )+\*\sSet\s)(\w+)\s\=\s(.*)$)
   127           ($1._saveSet($query, $web, $topic, $2, $3, $formDef))mgeo;
   128         TWiki::Func::saveTopic( $web, $topic, $meta, $text );
   129         TWiki::Func::setTopicEditLock( $web, $topic, 0 );
   130         # Finish with a redirect so that the *new* values are seen
   131         my $viewUrl = TWiki::Func::getScriptUrl( $web, $topic, 'view' );
   132         TWiki::Func::redirectCgiQuery( undef, $viewUrl );
   133         return;
   134     }
   135     # implicit action="view", or drop through from "save" or "cancel"
   136     $_[0] =~ s/%EDITPREFERENCES({.*?})?%/_generateEditButton($web, $topic)/ge;
   137 }
   138 
   139 # Use the post-rendering handler to plug our formatted editor units
   140 # into the text
   141 sub postRenderingHandler {
   142     ### my ( $text ) = @_;
   143 
   144     $_[0] =~ s/SHELTER$MARKER(\d+)/$shelter[$1]/g;
   145 }
   146 
   147 # Pluck the default value of a named field from a form definition
   148 sub _getField {
   149     my( $formDef, $name ) = @_;
   150     foreach my $f ( @{$formDef->{fields}} ) {
   151         if( $f->{name} eq $name ) {
   152             return $f;
   153         }
   154     }
   155     return undef;
   156 }
   157 
   158 # Generate a field suitable for editing this type. Use of the core
   159 # function 'renderFieldForEdit' ensures that we will pick up
   160 # extra edit types defined in other plugins.
   161 sub _generateEditField {
   162     my( $web, $topic, $name, $value, $formDef ) = @_;
   163     $value =~ s/^\s*(.*?)\s*$/$1/ge;
   164 
   165     my ($extras, $html);
   166 
   167     if( $formDef ) {
   168         my $fieldDef;
   169         if (defined(&TWiki::Form::getField)) {
   170             # TWiki 4.2 and later
   171             $fieldDef = $formDef->getField( $name );
   172         } else {
   173             # TWiki < 4.2
   174             $fieldDef = _getField( $formDef, $name );
   175         }
   176         if ( $fieldDef ) {
   177             if( defined(&TWiki::Form::renderFieldForEdit)) {
   178                 # TWiki < 4.2 SMELL: use of unpublished core function
   179                 ( $extras, $html ) =
   180                   $formDef->renderFieldForEdit( $fieldDef, $web, $topic, $value);
   181             } else {
   182                 # TWiki 4.2 and later SMELL: use of unpublished core function
   183                 ( $extras, $html ) =
   184                   $fieldDef->renderForEdit( $web, $topic, $value );
   185             }
   186         }
   187     }
   188     unless( $html ) {
   189         # No form definition, default to text field.
   190         $html = CGI::textfield( -class=>'twikiEditFormError twikiInputField',
   191                                 -name => $name,
   192                                 -size => 80, -value => $value );
   193     }
   194 
   195     push( @shelter, $html );
   196 
   197     return $START_MARKER.
   198       CGI::span({class=>'twikiAlert',
   199                  style=>'font-weight:bold;'},
   200                 $name . ' = SHELTER' . $MARKER . $#shelter).$END_MARKER;
   201 }
   202 
   203 # Generate the button that replaces the EDITPREFERENCES tag in view mode
   204 sub _generateEditButton {
   205     my( $web, $topic ) = @_;
   206 
   207     my $viewUrl = TWiki::Func::getScriptUrl(
   208         $web, $topic, 'viewauth' );
   209     my $text = CGI::start_form(
   210         -name => 'editpreferences',
   211         -method => 'post',
   212         -action => $viewUrl );
   213     $text .= CGI::input({
   214         type => 'hidden',
   215         name => 'prefsaction',
   216         value => 'edit'});
   217     $text .= CGI::submit(-name => 'edit',
   218                          -value=>'Edit Preferences',
   219                          -class=>'twikiButton');
   220     $text .= CGI::end_form();
   221     $text =~ s/\n//sg;
   222     return $text;
   223 }
   224 
   225 # Generate the buttons that replace the EDITPREFERENCES tag in edit mode
   226 sub _generateControlButtons {
   227     my( $web, $topic ) = @_;
   228 
   229     my $text = $START_MARKER.CGI::submit(-name=>'prefsaction',
   230                                          -value=>'Save new settings',
   231                                          -class=>'twikiSubmit',
   232                                          -accesskey=>'s');
   233     $text .= '&nbsp;';
   234     $text .= CGI::submit(-name=>'prefsaction', -value=>'Cancel',
   235                          -class=>'twikiButton',
   236                          -accesskey=>'c').$END_MARKER;
   237     return $text;
   238 }
   239 
   240 # Given a Set in the topic being saved, look in the query to see
   241 # if there is a new value for the Set and generate a new
   242 # Set statement.
   243 sub _saveSet {
   244     my( $query, $web, $topic, $name, $value, $formDef ) = @_;
   245 
   246     my $newValue = $query->param( $name ) || $value;
   247 
   248     if( $formDef ) {
   249         my $fieldDef = _getField( $formDef, $name );
   250         my $type = $fieldDef->{type} || '';
   251         if( $type && $type =~ /^checkbox/ ) {
   252             my $val = '';
   253             my $vals = $fieldDef->{value};
   254             foreach my $item ( @$vals ) {
   255                 my $cvalue = $query->param( $name.$item );
   256                 if( defined( $cvalue ) ) {
   257                     if( ! $val ) {
   258                         $val = '';
   259                     } else {
   260                         $val .= ', ' if( $cvalue );
   261                     }
   262                     $val .= $item if( $cvalue );
   263                 }
   264             }
   265             $newValue = $val;
   266         }
   267     }
   268     # if no form def, it's just treated as text
   269 
   270     return $name.' = '.$newValue;
   271 }
   272 
   273 1;