# # TWiki WikiClone ($wikiversion has version info) # # Copyright (C) 2002 Peter Thoeny, Peter@Thoeny.com # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details, published at # http://www.gnu.org/copyleft/gpl.html # # ========================= # # This is the EditTablePlugin used to edit tables in place. # # Each plugin is a package that contains the subs: # # initPlugin ( $topic, $web, $user, $installWeb ) # commonTagsHandler ( $text, $topic, $web ) # startRenderingHandler( $text, $web ) # outsidePREHandler ( $text ) # insidePREHandler ( $text ) # endRenderingHandler ( $text ) # # initPlugin is required, all other are optional. # For increased performance, DISABLE handlers you don't need. # # NOTE: To interact with TWiki use the official TWiki functions # in the &TWiki::Func module. Do not reference any functions or # variables elsewhere in TWiki!! # FIXME: The following TWiki calls used will likely break in a # future TWiki release: # TWiki::Store::readTopic(), TWiki::Store::saveTopic() # TWiki::Store::lockTopic(), TWiki::Store::topicIsLockedBy() # ========================= package TWiki::Plugins::EditTablePlugin; # ========================= use vars qw( $web $topic $user $installWeb $VERSION $debug $query $renderingWeb $preSp $header $footer $headerislabel @format $formatcell $changeRows $defaultrows $quietSave $helpTopic $cgiCols $prefsInitialized $prefCHANGEROWS $prefDEFAULTROWS $prefEDITBUTTON $prefQUIETSAVE $prefJSCALENDARDATEFORMAT $prefJSCALENDARLANGUAGE $prefJSCALENDAROPTIONS $nbCols %labels $editButton $encodeStart $encodeEnd $table ); $encodeStart = "--EditTableEncodeStart--"; $encodeEnd = "--EditTableEncodeEnd--"; $prefsInitialized = 0; undef $table; # ========================= sub initPlugin { ( $topic, $web, $user, $installWeb ) = @_; $VERSION = '1.001'; # check for Plugins.pm versions if( $TWiki::Plugins::VERSION < 1 ) { &TWiki::Func::writeWarning( "Version mismatch between EditTablePlugin and Plugins.pm" ); return 0; } $query = &TWiki::Func::getCgiQuery(); if( ! $query ) { return 0; } # Get plugin debug flag $debug = &TWiki::Func::getPreferencesFlag( "EDITTABLEPLUGIN_DEBUG" ); # Get plugin button labels my $ltext = &TWiki::Func::getPreferencesValue( "EDITTABLEPLUGIN_LABELS" ); %labels = (); foreach( split( /\s*,\s*/, $ltext ) ) { my @button = split( /\s*=>\s*/, $_ ); $labels->{$button[0]} = $button[1]; } $prefsInitialized = 0; $renderingWeb = $web; # Plugin correctly initialized &TWiki::Func::writeDebug( "- EditTablePlugin:initPlugin( $web.$topic ) is OK" ) if $debug; # Initialize $table such that the code will correctly detect when to # read in a topic. undef $table; return 1; } # ========================= sub extractParameters { my( $theArgs, $theHeader, $theFooter, $theHeaderislabel, $theFormat, $theCellFormat, $theChangeRows, $theDefaultRows, $theQuietSave, $theHelpTopic, $theEditButton ) = @_; my $tmp = &TWiki::Func::extractNameValuePair( $theArgs, "header" ); $theHeader = $tmp if( $tmp ); $tmp = &TWiki::Func::extractNameValuePair( $theArgs, "footer" ); $theFooter = $tmp if( $tmp ); $tmp = &TWiki::Func::extractNameValuePair( $theArgs, "headerislabel" ); $theHeaderislabel = $tmp if( $tmp ); $tmp = &TWiki::Func::extractNameValuePair( $theArgs, "format" ); $tmp =~ s/^\s*\|*\s*//o; $tmp =~ s/\s*\|*\s*$//o; $theFormat = $tmp if( $tmp ); $tmp = &TWiki::Func::extractNameValuePair( $theArgs, "cells" ); $tmp =~ s/^\s*\|*\s*//o; $tmp =~ s/\s*\|*\s*$//o; $theCellFormat = $tmp if( $tmp ); $tmp = &TWiki::Func::extractNameValuePair( $theArgs, "changerows" ); $theChangeRows = $tmp if( $tmp ); $tmp = &TWiki::Func::extractNameValuePair( $theArgs, "defaultrows" ); $theDefaultRows = $tmp if ( $tmp ); $tmp = &TWiki::Func::extractNameValuePair( $theArgs, "quietsave" ); $theQuietSave = $tmp if( $tmp ); $tmp = &TWiki::Func::extractNameValuePair( $theArgs, "helptopic" ); $theHelpTopic = $tmp if( $tmp ); $tmp = &TWiki::Func::extractNameValuePair( $theArgs, "editbutton" ); $theEditButton = $tmp if( $tmp ); return ( $theHeader, $theFooter, $theHeaderislabel, $theFormat, $theCellFormat, $theChangeRows, $theDefaultRows, $theQuietSave, $theHelpTopic, $theEditButton ); } # ========================= sub commonTagsHandler { ### my ( $text, $topic, $web ) = @_; # do not uncomment, use $_[0], $_[1]... instead &TWiki::Func::writeDebug( "- EditTablePlugin::commonTagsHandler( $_[2].$_[1] )" ) if $debug; # Test presence of EditTable tags return unless $_[0] =~ /%EDIT(TABLE|CELL){(.*)}%/os; unless ( $prefsInitialized ) { $prefCHANGEROWS = &TWiki::Func::getPreferencesValue("CHANGEROWS") || &TWiki::Func::getPreferencesValue("EDITTABLEPLUGIN_CHANGEROWS") || "on"; $prefDEFAULTROWS = &TWiki::Func::getPreferencesValue("DEFAULTROWS") || &TWiki::Func::getPreferencesValue("EDITTABLEPLUGIN_DEFAULTROWS") || "on"; $prefEDITBUTTON = &TWiki::Func::getPreferencesValue("EDITBUTTON") || &TWiki::Func::getPreferencesValue("EDITTABLEPLUGIN_EDITBUTTON") || $labels->{'EDIT'} || "Edit table" ; $prefQUIETSAVE = &TWiki::Func::getPreferencesValue("EDITTABLEPLUGIN_QUIETSAVE") || &TWiki::Func::getPreferencesValue("QUIETSAVE") ||"on"; $prefJSCALENDARDATEFORMAT = &TWiki::Func::getPreferencesValue("JSCALENDARDATEFORMAT") || &TWiki::Func::getPreferencesValue("EDITTABLEPLUGIN_JSCALENDARDATEFORMAT") || "%d/%m/%Y"; $prefJSCALENDARLANGUAGE = &TWiki::Func::getPreferencesValue("JSCALENDARLANGUAGE") || &TWiki::Func::getPreferencesValue("EDITTABLEPLUGIN_JSCALENDARLANGUAGE") || "fr" ; $prefJSCALENDAROPTIONS = &TWiki::Func::getPreferencesValue("JSCALENDAROPTIONS") || &TWiki::Func::getPreferencesValue("EDITTABLEPLUGIN_JSCALENDAROPTIONS") || ""; $prefsInitialized = 1; } # Initialization of variables my $theWeb = $_[2]; my $theTopic = $_[1]; my $result = ""; my $tableNr = 0; my $rowNr = 0; my $doEdit = 0; my $insideTable = 0; my @cgiCells ; my @cgiCellsFormat ; my $getRows = $query->param( 'etrows' ) || -1; my $cgiTableNr = $query->param( 'ettablenr' ) || 0; my $row=0; my $tag=0; $cgiCols = 0; $nbCols = 0; # Parse TWiki page # appended stuff is a hack to handle EDITTABLE correctly if at end foreach( split( /\r?\n/, "$_[0]\n\n" ) ) { &TWiki::Func::writeDebug( "- EditTablePlugin::debug debut parse" ) if $debug; # Handle our EDITTABLE tags if(s/(\s*)%EDITTABLE{(.*)}%/&handleEditTableTag($theWeb,$1,$2)/geo){ $insideTable = 1; $doEdit=0; $cgiRows=-1; $tableNr += 1; $tag=1; $row=0; # Execute a requiried action on the current edited table if( $cgiTableNr == $tableNr ) { $cgiRows=$getRows; # Dump CGI representation of the TWiki table into perl array if ( !$query->param( 'etedit' ) ) { my $nbRow=0; my $oneSelected=0; my @swap=(); my @swap2=(); for (my $row=1; $row<=$cgiRows; $row++) { my $srow=$query->param("SEL${row}"); my $thisSelected= (defined $srow) ? ($row==$srow):0; if ( $thisSelected ) { $oneSelected=1; last; } } for( my $row=1; $row<=$cgiRows; $row++) { my $col=1; my $nrow=$row+1; my @cells; my @cellsFormat; my $srow=$query->param("SEL${row}"); my $snrow=$query->param("SEL${nrow}"); my $thisSelected = (defined $srow) ? ( $row==$srow ):0; my $nextSelected=(defined $snrow) ? ( $nrow==$snrow ):0; if ($query->param('etdelrows') && $thisSelected ) { next; } while (1) { $value=$query->param("etcell${row}x${col}"); $rowFormat=$query->param("etformat${row}x${col}"); if (!defined $value) {last;} my $tmp=$col++; $cells[$tmp] = $value; $cellsFormat[$tmp] = $rowFormat; } if ($query->param('etinsrows') && ($thisSelected || (!$oneSelected && ($row==2)))) { if ( $defaultrows ) { push @cgiCells, ['']; push @cgiCellsFormat, ['']; } else { push @cgiCells,[@cells]; push @cgiCellsFormat, [@cellsFormat]; } $nbRow++; } $nbRow++; if ( ( $query->param('etdownrows' ) && $thisSelected && ($row<$cgiRows) ) || ($query->param( 'etuprows') && $nextSelected && ( $row>1 ) ) ) { push @swap, [@cells]; push @swap2, [@cellsFormat]; } else { push @swap, [@cells]; push @swap2, [@cellsFormat]; my $elem=''; my $elemFormat=''; if($query->param('etuprows')) { $elem=shift(@swap); push @swap, $elem; @swap=reverse @swap; $elemFormat=shift(@swap2); push @swap2, $elemFormat; @swap2=reverse @swap2; } if($query->param('etdownrows')) { $elem=pop(@swap); unshift @swap, $elem; @swap=reverse @swap; $elemFormat=pop(@swap2); unshift @swap2, $elemFormat; @swap2=reverse @swap2; } while ($elem = pop(@swap)){ push @cgiCells, $elem; $elemFormat = pop(@swap2);push @cgiCellsFormat, $elemFormat;} } if ( $query->param('etaddrows') && ($thisSelected || (!oneSelected && ($row==$cgiRows)))) { if ( $defaultrows ) { push @cgiCells, ['']; push @cgiCellsFormat, ['']; } else { push @cgiCells,[@cells]; push @cgiCellsFormat, [@cellsFormat]; } $nbRow++; } if ($col>$nbCols) {$nbCols=$col; } } $cgiRows=$nbRow if ($nbRow > 0); } if( $query->param( 'etsave' ) ) { # FIXME modifier doSaveTable (never return in case browser does # not redirect) doSaveTable( $theWeb, $theTopic, $tableNr, "", \@cgiCells, \@cgiCellsFormat ); return; } # [Quiet Save] button pressed elsif ($query->param( 'etqsave' ) ) { doSaveTable( $theWeb, $theTopic, $tableNr, "on", \@cgiCells, \@cgiCellsFormat ); return; } # [Cancel] button pressed elsif( $query->param( 'etcancel' ) ) { # FIXME modifier doSaveTable (never return in case browser does # not redirect) doCancelEdit( $theWeb, $theTopic ); return; } # [Add or Delete selected rows] button pressed elsif( $query->param( 'etinsrows' ) || $query->param( 'etaddrows' ) || $query->param( 'etdelrows' ) || $query->param( 'etuprows' ) || $query->param( 'etdownrows' ) ) { $doEdit = doEnableEdit( $theWeb, $theTopic, 0 ); return unless( $doEdit ); } # [Edit table] button pressed elsif( $query->param( 'etedit' ) ) { $doEdit = doEnableEdit( $theWeb, $theTopic, 1 ); # return if locked or no permission return unless( $doEdit ); } } $result .= handleTableStart($theWeb,$theTopic,$tableNr,$cgiRows,$doEdit); } else { $tag=0; } # Display the table if($insideTable){ if(!$tag){ # The table must be displayed as a HTML form if(/^(\s*)\|.*\|\s*$/){ if($cgiRows<0 || $query->param( 'etedit' ) || $doEdit==0 ){ $row++; $_ =~ s/^(\s*)\|//eo if ($editEdit==0);# modif Charles : sans ca pas de lien sort sur les tableaux! $result .= handleTableRow($preSp,$_,$tableNr,$row,$doEdit,0,"",""); $result .= "\n"; } else{ next; } } else{ if ($row==0 && $cgiRows==-1 && $doEdit==1){ if( $header ) { $result .= handleTableRow( $preSp, "", $tableNr,$row, $doEdit, 0, "", "") . "\n"; $row++; } $result .= handleTableRow( $preSp, "", $tableNr,$row, $doEdit, 0, "" ,"") . "\n"; $row++; } while($row<$cgiRows){ $result .= handleTableRow($preSp,"",$tableNr,$row,$doEdit,0,\@cgiCells,\@cgiCellsFormat)."\n"; $row++; } $result .= handleTableEnd($theWeb,$row,$doEdit); $insideTable = 0; } } } else{ $result .= "$_\n"; } } # Return page with edition HTML forms included $result =~ s|\n?\n$||o; # clean up hack that handles EDITTABLE correctly if at end $_[0] = $result; } # ========================= sub DISABLE_startRenderingHandler { ### my ( $text, $web ) = @_; # do not uncomment, use $_[0], $_[1] instead &TWiki::Func::writeDebug( "- EditTablePlugin::startRenderingHandler( $_[1] )" ) if $debug; # This handler is called by getRenderedVersion just before the line loop $renderingWeb = $_[1]; } # ========================= sub DISABLE_outsidePREHandler { ### my ( $text ) = @_; # do not uncomment, use $_[0] instead &TWiki::Func::writeDebug( "- EditTablePlugin::outsidePREHandler( $renderingWeb.$topic )" ) if $debug; # This handler is called by getRenderedVersion, in loop outside of
 tag
    # This is the place to define customized rendering rules

    # do custom extension rule, like for example:
    # $_[0] =~ s/old/new/go;
}

# =========================
sub DISABLE_insidePREHandler
{
### my ( $text ) = @_;   # do not uncomment, use $_[0] instead

    &TWiki::Func::writeDebug( "- EditTablePlugin::insidePREHandler( $web.$topic )" ) if $debug;

    # This handler is called by getRenderedVersion, in loop inside of 
 tag
    # This is the place to define customized rendering rules

    # do custom extension rule, like for example:
    # $_[0] =~ s/old/new/go;
}

# =========================
sub endRenderingHandler
{
### my ( $text ) = @_;   # do not uncomment, use $_[0] instead

    &TWiki::Func::writeDebug( "- EditTablePlugin::endRenderingHandler( $web.$topic )" ) if $debug;

    # This handler is called by getRenderedVersion just after the line loop

    return unless $_[0] =~ /$encodeStart/os;

    $_[0] =~ s/$encodeStart(.*?)$encodeEnd/&decodeValue($1)/geos;
}

# =========================
sub encodeValue
{
    my( $theText ) = @_;

    # WindRiver specific hack to remove SprPlugin rendering
    $theText =~ s/ value)
           if( /^\s*(.*?)\s*=>\s*(.*?)\s*$/ ) {
               my ( $web, $topic, $field ) = ( "", "", "" );
               my $twikiwd = "($webNameRegex)[.]($wikiWordRegex)";
               my ( $key, $option) = ( $1, $2 ) ;
               my $caseok = 0;

               # The 4 cases where value is a reference to a TWiKi topic
               if( $option =~ /^\s*($wikiWordRegex)\s*$/ ){
                 $web = $theWeb; $topic = $1; $field = ""; }
               if( $option =~ /^\s*$twikiwd\s*$/ ){
                 $web = $1; $topic = $2; $field = ""; }
               if( $option =~ /^\s*($wikiWordRegex):($mixedAlphaNumRegex)\s*/ ){
                 $web = $theWeb; $topic = $1; $field = $2; }
               if( $option =~ /^\s*$twikiwd:($mixedAlphaNumRegex)\s*/ ){
                 $web = $1; $topic = $2; $field = $3; }
               if( $web && $topic ){
                 my( $meta , $text ) = &TWiki::Func::readTopic( $web, $topic );

                 # The real values are in the text of the topic
                 if( !$field && $text ) {
                   foreach( split( /\n/, $text ) ) {
                     $_ =~ s/,/\$comma/go;
                     $new .= ",$key => $_";
                     }
                   $caseok = 1;
                   }

                 # The real values are in a field form of the topic
                 if( $field && $meta ) {
                   %ftab = $meta->findOne( "FIELD", $field );
                   $fval = $ftab{"value"};
                   if( $fval ){
                     foreach $subopt ( split( /\n/, $fval ) ){
                       $subopt =~ s/,/\$comma/go;
                       $new .= ",$key => $subopt"; }
                     $caseok = 1;
                     }
                   }
                 }
               if( !$topic && !$caseok ){ $new .= ",$_"; }
               }
           else{ $new .= ",$_"; }
          }
        }
      $format->[$i++]=$new;
      }
}

# =========================
sub handleEditTableTag
{
    my( $theWeb, $thePreSpace, $theArgs ) = @_;

    $preSp = $thePreSpace || "";
    $header = "";
    $footer = "";
    $headerislabel = "1";
    $quietSave = $prefQUIETSAVE; 
    $editButton = ""; 
    my $tFormat = "";
    $changeRows = $prefCHANGEROWS;
    $defaultrows = $prefDEFAULTROWS;

    my $iTopic = &TWiki::Func::extractNameValuePair( $theArgs, "include" );
    if( $iTopic ) {
       # include topic to read definitions
       if( $iTopic =~ /^([^\.]+)\.(.*)$/o ) {
           $theWeb = $1;
           $iTopic = $2;
       }
       my( $meta, $text ) = &TWiki::Func::readTopic( $theWeb, $iTopic );
       $text =~ /%EDITTABLE{(.*)}%/os;
       if( $1 ) {
           my $args = $1;
           if( "$theWeb.$iTopic" ne "$web.$topic" ) {
               # expand common vars, unless oneself to prevent recursion
               $args = &TWiki::Func::expandCommonVariables($1,$iTopic,$theWeb );
           }
              ( $header, $footer, $headerislabel, $tFormat, $tFormatCell, $changeRows, $defaultrows, $quietSave, $helpTopic, $editButton ) =
	     extractParameters( $args, $header, $footer,$headerislabel, $tFormat, $tFormatCell, $changeRows, $defaultrows, $quietSave, $helpTopic, $editButton );
       }
    }

    ( $header, $footer, $headerislabel, $tFormat, $tFormatCell, $changeRows, $defaultrows, $quietSave, $helpTopic, $editButton ) =
      extractParameters( $theArgs, $header, $footer, $headerislabel,$tFormat, $tFormatCell, $changeRows, $defaultrows, $quietSave, $helpTopic, $editButton );
    $header = "" if( $header =~ /^(off|no)$/oi );
    $header =~ s/^\s*\|//o;
    $header =~ s/\|\s*$//o;
    $headerislabel = "" if( $headerislabel =~ /^(off|no)$/oi );
    $footer = "" if( $footer =~ /^(off|no)$/oi );
    $footer =~ s/^\s*\|//o;
    $footer =~ s/\|\s*$//o;
    $changeRows = "" if( $changeRows =~ /^(off|no)$/oi );
    $defaultrows = "" if( $defaultrows =~ /^(off|no)$/oi );
    $quietSave = "" if ( $quietSave =~ /^(off|no)$/oi );

    @format = parseFormat( $tFormat, $theTopic, $theWeb );
    handleFormatIncludes( $theWeb, \@format );
    $cgiCols = @format;

    if (defined $tFormatCell and $tFormatCell !~ /^\s*$/) {
      $formatcell = parseCellFormat( $tFormatCell, $theTopic, $theWeb );
    } else {
      $formatcell = {};
    }

    # FIXME: No handling yet of footer

    return "$preSp";
}

# =========================
sub generateJavascript
{
my( $formName, $nbRows, $cellName ) = @_;

my @select=();
my @dynsel=();
my $nocol=0;
foreach (@format){
  if(/^\s*select\s*\(/){ push @dynsel,$nocol; }
  if(/^\s*select/){ push @select,$nocol; }
  $nocol++;
  }

# Javascript header
my $text = "\n";

return $text;
}

# =========================
sub handleTableStart
{
    my( $theWeb, $theTopic, $theTableNr, $nbRows, $doEdit ) = @_;

    my $viewUrl = &TWiki::Func::getScriptUrl( $theWeb, $theTopic, "viewauth" ) . "\#edittable$theTableNr";
    my $formName="edittable$theTableNr";
    my $text = "";
    my $dir = "%PUBURL%/$installWeb/EditTablePlugin" if $doEdit;
    $text .= "$preSp" if $doEdit;
    $text .= "$preSp\n " if $doEdit;
    $text .= "$preSp\n" if $doEdit;
    $text .= "$preSp\n" if $doEdit;
    $text .= generateJavascript( $formName, $nbRows, "etcell" ) if $doEdit;
    $text .= "$preSp\n" if $doEdit;
    $text .= "$preSp\n";
    $text .= "$preSp
\n"; $text .= "$preSp\n"; $text .= "$preSp\n" unless $doEdit; return $text; } # ========================= sub handleTableEnd { my( $theWeb, $theRowNr, $doEdit ) = @_; my $text = "$preSp\n"; if( $doEdit ) { # Edit mode # Get plugin button labels $lsave = $labels->{'SAVE'}; $lqsave = $labels->{'QUIET_SAVE'}; $linsbef = $labels->{'INSERT_BEFORE'}; $linsaft = $labels->{'INSERT_AFTER'}; $lup = $labels->{'UP'}; $ldown = $labels->{'DOWN'}; $ldelete = $labels->{'DELETE'}; $lcancel = $labels->{'CANCEL'}; if(!defined $lsave){ $lsave = "Save table"; } if(!defined $lqsave){ $lqsave = "Quiet save"; } if(!defined $linsbef){ $linsbef = "Insert before"; } if(!defined $linsaft){ $linsaft = "Insert after"; } if(!defined $lup){ $lup = "Go up"; } if(!defined $ldown){ $ldown = "Go down"; } if(!defined $ldelete){ $ldelete = "Delete"; } if(!defined $lcancel){ $lcancel = "Cancel"; } $text .= "$preSp\n"; if ( $quietSave ) { $text .= "$preSp\n"; } if( $changeRows ) { $text .= "$preSp\n"; $text .= "$preSp\n"; $text .= "$preSp\n"; $text .= "$preSp\n"; if( ! ($changeRows =~ /^add$/oi) ){ $text .= "$preSp\n" } } $text .= "$preSp\n"; if( $helpTopic ) { # read help topic and show below the table if( $helpTopic =~ /^([^\.]+)\.(.*)$/o ) { $theWeb = $1; $helpTopic = $2; } my( $meta, $helpText ) = &TWiki::Func::readTopic( $theWeb, $helpTopic ); if( $helpText ) { $helpText =~ s/.*?%STARTINCLUDE%//os; $helpText =~ s/%STOPINCLUDE%.*//os; $text .= $helpText; } } } else { # View mode if( $editButton eq "hide" ) { # do nothing, button assumed to be in a cell } else { # Add edit button to end of table $text .= "$preSp" . viewEditCell( "editbutton, 1, $editButton" ); } } $text .= "$preSp
\n"; $text .= "$preSp\n" if $doEdit; return $text; } # ========================= sub parseEditCellFormat { $_[1] = &TWiki::Func::extractNameValuePair( $_[0] ); return ""; } # ========================= sub viewEditCell { my ( $theAttr ) = @_; $theAttr = &TWiki::Func::extractNameValuePair( $theAttr ); return "" unless( $theAttr =~ /^editbutton/ ); $editButton = "hide" unless( $editButton ); # Hide below table edit button my @bits = split( /,\s*/, $theAttr ); my $value = ""; $value = $bits[2] if( @bits > 2); my $img = ""; $img = $bits[3] if( @bits > 3); unless( $value ) { $value = $prefEDITBUTTON; $img = ""; if( $value =~ s/(.+),\s*(.+)/$1/o ) { $img = $2; $img =~ s|%ATTACHURL%|%PUBURL%/$installWeb/EditTablePlugin|o; $img =~ s|%WEB%|$installWeb|o; } } if( $img ) { return ""; } else { return "\n"; } } # ========================= sub saveEditCellFormat { my ( $theFormat, $theName ) = @_; return "" unless( $theFormat ); $theName =~ s/cell/format/; return ""; } # ========================= sub parseFormat { my( $theFormat, $theTopic, $theWeb) = @_; $theFormat =~ s/\$nop(\(\))?//gos; # remove filler $theFormat =~ s/\$quot(\(\))?/\"/gos; # expand double quote $theFormat =~ s/\$percnt(\(\))?/\%/gos; # expand percent $theFormat =~ s/\$dollar(\(\))?/\$/gos; # expand dollar my @aFormat = split( /\s*\|\s*/, $theFormat ); my @aHeader = split( /\s*\|\s*/, $header ); # In case there is a header and no format while ( @aHeader > @aFormat) { push(@aFormat,'text,16');} $aFormat[0] = "text,16" unless @aFormat; return @aFormat; } # ========================= sub parseCellFormat { my( $theFormat, $theTopic, $theWeb ) = @_; $theFormat =~ s/\$nop(\(\))?//gos; # remove filler $theFormat =~ s/\$quot(\(\))?/\"/gos; # expand double quote $theFormat =~ s/\$percnt(\(\))?/\%/gos; # expand percent $theFormat =~ s/\$dollar(\(\))?/\$/gos; # expand dollar my @tmpFormat = split( /\s*\|\s*/, $theFormat ); handleFormatIncludes( $theWeb, \@tmpFormat ); my $cFormat = {}; foreach my $cellFormat (@tmpFormat) { my ($row,$col,$format) = ($cellFormat =~ m/^\s*([0-9]+)\s*x\s*([0-9]+)\s*,(.*)/); $cFormat->{$row} = {} if not exists $cFormat->{$row}; $cFormat->{$row}->{$col-1} = $format; } return $cFormat; } # ========================= sub inputElement { my ( $theTableNr, $theRowNr, $theCol, $theName, $theValue, $islabel ) = @_; $theValue = "" if( $theValue eq " " ); my $striped = $theValue; $striped =~ s/\s*$//o; $striped =~ s/^\s*//o; my $text = ""; my $i = @format - 1; $i = $theCol if( $theCol < $i ); my @bits; if (exists $formatcell->{$theRowNr} and exists $formatcell->{$theRowNr}->{$theCol}) { # per cell override @bits = split( /,\s*/, $formatcell->{$theRowNr}->{$theCol}); } else { # per column override @bits = split( /,\s*/, $format[$i] ); } my $cellFormat = ""; $striped =~ s/\s*%EDITCELL{(.*?)}%/&parseEditCellFormat( $1, $cellFormat )/eo; $striped = "" if( $striped eq " " ); if( $cellFormat ) { my @aFormat = parseFormat( $cellFormat, $theTopic, $theWeb); @bits = split( /,\s*/, $aFormat[0] ); } my $type = "text"; if(@bits > 0){ $type = $bits[0]; $type =~ s/\s*\(.*\)\s*$//o; } # a table header is considered a label if read only header flag set if( ( $headerislabel ) && ( $theValue =~ /^\s*\*.*\*\s*$/ ) ) {$type = "label"; $islabel=1;} $type = "label" if( $type eq "editbutton" ); # Hide [Edit table] button my $size = 0; $size = $bits[1] if @bits > 1; my $val = ""; my $sel = ""; my $style = ""; $style = " style='background:#FFFFCC'" if ($theRowNr % 2); if( $type eq "label" || $islabel) { # show label text as is, and add a hidden field with value $striped =~ s/^\s*\*(.*)\*(.*)\s*$/$1$2/o if ( $islabel ); $text = "$striped"; $theValue = $encodeStart . encodeValue( $striped ) . $encodeEnd; $theValue = "\*$theValue\*" if ( $islabel ); $text .= " "; $text = "\*$text\*" if ( $islabel ); } elsif( $type eq "select" ) { my $colNo=$theCol+1; my $jsfct = "updateRowOfSelect"; my $jstext = " onchange=$jsfct($theRowNr,$colNo)"; my $sizetext = ""; my $oneSelect = 0; if($size>0){ $sizetext = " size=\"$size\""; } $text = ""; $i = 2; while( $i < @bits ) { my $selected=""; $val = $bits[$i] || ""; if ( !($val =~ /·*?=>.*/) ) { if($val eq $striped){ $selected="selected"; $oneSelect=1; } $text .= " "; } $i++; } if( !$oneSelect && $striped ne "" ) { $text .= " "; } $text .= " "; $text .= saveEditCellFormat( $cellFormat, $theName ); } elsif( $type eq "radio" ) { $size = 1 if $size < 1; my $elements = ( @bits - 2 ); my $lines = $elements / $size; $lines = ($lines == int($lines)) ? $lines : int($lines + 1); $text .= "
" if( $lines > 1 ); $i = 2; while( $i < @bits ) { $val = $bits[$i] || ""; $text .= " 1 ) { if( ($i-1) % $lines ) { $text .= "
"; } elsif( $i-1 < $elements ) { $text .= "
"; } } $i++; } $text .= "
" if( $lines > 1 ); $text .= saveEditCellFormat( $cellFormat, $theName ); } elsif( $type eq "checkbox" ) { $size = 1 if $size < 1; my $elements = ( @bits - 2 ); my $lines = $elements / $size; my $names = "Chkbx:"; $lines = ($lines == int($lines)) ? $lines : int($lines + 1); $text .= "
" if( $lines > 1 ); $i = 2; while( $i < @bits ) { $val = $bits[$i] || ""; $names .= " ${theName}x$i"; $text .= " 1 ) { if( ($i-1) % $lines ) { $text .= "
"; } elsif( $i-1 < $elements ) { $text .= "
"; } } $i++; } $text .= "
" if( $lines > 1 ); $text .= " "; $text .= saveEditCellFormat( $cellFormat, $theName ); } elsif( $type eq "row" ) { $size = $size + $theRowNr; $text = "$size"; $text .= saveEditCellFormat( $cellFormat, $theName ); } elsif ( $type eq "textarea" ) { my ($rows, $cols) = split( /x/ , $size ); $rows = 3 if $rows < 1; $cols = 30 if $cols < 1; $theValue = $encodeStart . encodeValue( $striped ) . $encodeEnd if $theValue; $text = "$theValue"; $text .= saveEditCellFormat( $cellFormat, $theName ); } elsif ($type eq "date") { my $ifFormat = ""; $ifFormat = $bits[3] if (@bits > 3); $ifFormat = $ifFormat || $prefJSCALENDARDATEFORMAT; $size=10 if $size < 1; $theValue = $encodeStart . encodeValue( $striped ) . $encodeEnd if $theValue; $text .= ""; $text .= saveEditCellFormat( $cellFormat, $theName); $text .= ""; $text .= ""; $query->{'jscalendar'} = 1; } else { # if( $type eq "text" ) $size = 16 if $size < 1; $theValue = $encodeStart . encodeValue( $striped ) . $encodeEnd if $theValue; $text = ""; $text .= saveEditCellFormat( $cellFormat, $theName ); } return $text; } # ========================= sub handleTableRow { my ( $thePre, $theRow, $theTableNr,$theRowNr, $doEdit, $doSave, $cgiTable, $cgiTableFormat ) = @_; $thePre = "" unless( defined( $thePre ) ); my $text = "$thePre\|"; if( $doEdit ) { if ($theRow){ $theRow =~ s/\|\s*$//o; @cells = split( /\|/, $theRow ); my $tmp = @cells; $cgiCols = $tmp if( $tmp > $cgiCols ); # expand number of cols } else { for (my $i=1;$i<$nbCols;$i++){ $cells[$i-1]=$$cgiTable[$theRowNr][$i];} for (my $i=1;$i<$nbCols;$i++){ $cellsformat[$i-1]=$$cgiTableFormat[$theRowNr][$i];} $theRowNr++; } my $val = ""; my $cellFormat = ""; my $cell = ""; my $cellDefined = 0; my $col = 0; if(($theRowNr>1 && !$doSave && ( $changeRows )) || (!$doSave && ( $changeRows ) && $theRowNr<=1 && !$header) ){ $text .= "\|"; } elsif( !$doSave && ( $changeRows ) ) { $text .="\|"; } while( $col < $cgiCols ) { $col += 1; $cellDefined = 0; $val = $cells[$col-1]; if( $val && $val =~ /^Chkbx: (etcell.*)/ ) { # Multiple checkboxes, val has format "Chkbx: etcell4x2x2 etcell4x2x3 ..." my $chkBoxeNames = $1; my $chkBoxVals = ""; foreach( split( /\s/, $chkBoxeNames ) ) { $val = $query->param( $_ ); $chkBoxVals .= "$val, " if( defined $val ); } $chkBoxVals =~ s/, $//; $val = $chkBoxVals; } $cellFormat = $cellsformat[$col-1]; $val .= " %EDITCELL{$cellFormat}%" if( $cellFormat ); if( defined $val ) { # change any new line character sequences to
$val =~ s/(\n\r?)|(\r\n?)+/
/gos; # escape "|" to HTML entity $val =~ s/\|/\&\#124;/gos; $cellDefined = 1; # Expand %-vars $cell = $val; } elsif( $col <= @cells ) { $cell = $cells[$col-1]; $cellDefined = 1 if( length( $cell ) > 0 ); $cell =~ s/^\s//o; $cell =~ s/\s$//o; } else { $cell = ""; } if( ( $theRowNr <= 1 ) && ( $header ) && !$doSave ) { unless( $cell ) { if( $header =~ /^on$/i ) { if( ( @format >= $col ) && ( $format[$col] =~ /(.*?)\,/ ) ) { $cell = $1; } $cell = "text" unless $cell; $cell = "*$cell*"; } else { my @hCells = split( /\|/, ( $header ) ); $cell = $hCells[$col-1] if( @hCells >= $col ); $cell = "*text*" unless $cell; } } $text .= inputElement($theTableNr,$theRowNr,$col,"etcell${theRowNr}x$col",$cell,1)."\|"; } elsif( $doSave ) { $text .= " $cell \|"; } else { if( ( ! $cellDefined ) && ( @format >= $col ) && ( $format[$col-1] =~ /^\s*(.*?)\,\s*(.*?)\,\s*(.*?)\s*$/ ) ) { # default value of "| text, 20, a, b, c |" cell is "a, b, c" # default value of "| select, 1, a, b, c |" cell is "a" $val = $1; # type $cell = $3; $cell = "" unless( defined $cell && $cell ne "" ); # Proper handling of "0" $cell =~ s/\,.*$//o if( $val eq "select" || $val eq "date" ); $cell =~ s/^.*?=>//o if( $type =~ '^select\(' ); } $text .= inputElement( $theTableNr, $theRowNr, $col-1, "etcell${theRowNr}x$col", $cell,0 ) . " \|"; } } } else { $theRow =~ s/%EDITCELL{(.*?)}%/viewEditCell($1)/geo; $text .= "$theRow"; } return $text; } # ========================= sub doSaveTable { my ( $theWeb, $theTopic, $theTableNr, $quietSave, $cgiCells, $cgiCellsFormat) = @_; &TWiki::Func::writeDebug( "- EditTablePlugin::doSaveTable( $theWeb, $theTopic, $theTableNr, $quietSave, $cgiCells, $cgiCellsFormat )" ) if $debug; my( $meta, $text ) = &TWiki::Store::readTopic( $theWeb, $theTopic ); my $cgiRows = $query->param( 'etrows' ) || 1; my $tableNr = 0; my $rowNr = 0; my $insideTable = 0; my $doSave = 0; my $result = ""; # appended stuff is a hack to handle EDITTABLE correctly if at end foreach( split( /\r?\n/, "$text\n\n" ) ) { if( /%EDITTABLE{(.*)}%/o ) { $tableNr += 1; if( $tableNr == $theTableNr ) { $doSave = 1; $result .= "$_\n"; } } if( $doSave ) { if( /^(\s*)\|.*\|\s*$/ ) { $insideTable = 1; } elsif( $insideTable ) { $insideTable = 0; $row=0; while($row<$cgiRows){ $result .= handleTableRow($preSp,"",$tableNr,$row,1,1,$cgiCells,$cgiCellsFormat); $result .= "\n"; $row++; } $result .= "$_\n"; $doSave = 0; } if( /^\s*$/ ) { # empty line if ($doSave) { $row=0; while( $row < $cgiRows ) { $result .= handleTableRow($preSp, "",$tableNr,$row,1,1,$cgiCells,$cgiCellsFormat); $result .= "\n"; $row++; } $result .= "$_\n"; } $doSave = 0; } } else { $result .= "$_\n"; } } $result =~ s|\n\n$||o; # clean up hack that handles EDITTABLE correctly if at end &TWiki::Func::writeDebug( "- EditTablePlugin:debug dosave \n $result ") if $debug; my $error = &TWiki::Func::saveTopicText( $theWeb, $theTopic, $result,$meta, $quietSave ); &TWiki::Store::lockTopic( $theTopic, "on" ); my $url = &TWiki::Func::getViewUrl( $theWeb, $theTopic ); if( $error ) { $url = &TWiki::Func::getOopsUrl( $theWeb, $theTopic, "oopssaveerr", $error ); } &TWiki::Func::redirectCgiQuery( $query, $url ); } # ========================= sub doCancelEdit { my ( $theWeb, $theTopic ) = @_; &TWiki::Func::writeDebug( "- EditTablePlugin::doCancelEdit( $theWeb, $theTopic )" ) if $debug; &TWiki::Store::lockTopic( $theTopic, "on" ); &TWiki::Func::redirectCgiQuery( $query, &TWiki::Func::getViewUrl( $theWeb, $theTopic ) ); } # ========================= sub doEnableEdit { my ( $theWeb, $theTopic, $doCheckIfLocked ) = @_; &TWiki::Func::writeDebug( "- EditTablePlugin::doEnableEdit( $theWeb, $theTopic )" ) if $debug; my $wikiUserName = &TWiki::Func::getWikiUserName(); if( ! &TWiki::Func::checkAccessPermission( "change", $wikiUserName, "", $theTopic, $theWeb ) ) { # user has not permission to change the topic my $url = &TWiki::Func::getOopsUrl( $theWeb, $theTopic, "oopsaccesschange" ); &TWiki::Func::redirectCgiQuery( $query, $url ); return 0; } my( $lockUser, $lockTime ) = &TWiki::Store::topicIsLockedBy( $theWeb, $theTopic ); if( ( $doCheckIfLocked ) && ( $lockUser ) ) { # warn user that other person is editing this topic $lockUser = &TWiki::Func::userToWikiName( $lockUser ); use integer; $lockTime = ( $lockTime / 60 ) + 1; # convert to minutes my $editLock = $TWiki::editLockTime / 60; my $url = &TWiki::Func::getOopsUrl( $theWeb, $theTopic, "oopslocked", $lockUser, $editLock, $lockTime ); &TWiki::Func::redirectCgiQuery( $query, $url ); return 0; } &TWiki::Store::lockTopic( $theTopic ); return 1; } 1;