(file) Return to EditTablePlugin.pm CVS log (file) (dir) Up to [RizwankCVS] / geekymedia_web / twiki / lib / TWiki / Plugins

  1 rizwank 1.1 #
  2             # TWiki WikiClone ($wikiversion has version info)
  3             #
  4             # Copyright (C) 2002-2004 Peter Thoeny, Peter@Thoeny.com
  5             #
  6             # This program is free software; you can redistribute it and/or
  7             # modify it under the terms of the GNU General Public License
  8             # as published by the Free Software Foundation; either version 2
  9             # of the License, or (at your option) any later version.
 10             #
 11             # This program is distributed in the hope that it will be useful,
 12             # but WITHOUT ANY WARRANTY; without even the implied warranty of
 13             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14             # GNU General Public License for more details, published at
 15             # http://www.gnu.org/copyleft/gpl.html
 16             #
 17             # =========================
 18             #
 19             # This is the EditTablePlugin used to edit tables in place.
 20             #
 21             # Each plugin is a package that contains the subs:
 22 rizwank 1.1 #
 23             #   initPlugin           ( $topic, $web, $user, $installWeb )
 24             #   commonTagsHandler    ( $text, $topic, $web )
 25             #   startRenderingHandler( $text, $web )
 26             #   outsidePREHandler    ( $text )
 27             #   insidePREHandler     ( $text )
 28             #   endRenderingHandler  ( $text )
 29             #
 30             # initPlugin is required, all other are optional.
 31             # For increased performance, DISABLE handlers you don't need.
 32             #
 33             # NOTE: To interact with TWiki use the official TWiki functions
 34             # in the &TWiki::Func module. Do not reference any functions or
 35             # variables elsewhere in TWiki!!
 36             
 37             
 38             # =========================
 39             package TWiki::Plugins::EditTablePlugin;
 40             
 41             # =========================
 42             use vars qw(
 43 rizwank 1.1         $web $topic $user $installWeb $VERSION $debug
 44                     $query $renderingWeb
 45                     $preSp %params @format @formatExpanded
 46                     $prefsInitialized $prefCHANGEROWS $prefEDITBUTTON
 47                     $prefJSCALENDARDATEFORMAT $prefJSCALENDARLANGUAGE $prefJSCALENDAROPTIONS
 48                     $nrCols $encodeStart $encodeEnd $table
 49                 );
 50             
 51             $VERSION = '1.024';
 52             $encodeStart = "--EditTableEncodeStart--";
 53             $encodeEnd   = "--EditTableEncodeEnd--";
 54             $prefsInitialized  = 0;
 55             undef $table;
 56             
 57             # =========================
 58             sub initPlugin
 59             {
 60                 ( $topic, $web, $user, $installWeb ) = @_;
 61             
 62                 # check for Plugins.pm versions
 63                 if( $TWiki::Plugins::VERSION < 1 ) {
 64 rizwank 1.1         &TWiki::Func::writeWarning( "Version mismatch between EditTablePlugin and Plugins.pm" );
 65                     return 0;
 66                 }
 67             
 68                 $query = &TWiki::Func::getCgiQuery();
 69                 if( ! $query ) {
 70                     return 0;
 71                 }
 72             
 73                 # Get plugin debug flag
 74                 $debug = &TWiki::Func::getPreferencesFlag( "EDITTABLEPLUGIN_DEBUG" );
 75             
 76                 $prefsInitialized = 0;
 77                 $renderingWeb = $web;
 78             
 79                 # Plugin correctly initialized
 80                 &TWiki::Func::writeDebug( "- TWiki::Plugins::EditTablePlugin::initPlugin( $web.$topic ) is OK" ) if $debug;
 81             
 82                 # Initialize $table such that the code will correctly detect when to
 83                 # read in a topic.
 84                 undef $table;
 85 rizwank 1.1     return 1;
 86             }
 87             
 88             # =========================
 89             sub extractParams
 90             {
 91                 my( $theArgs, $theHashRef ) = @_;
 92             
 93                 my $tmp = &TWiki::Func::extractNameValuePair( $theArgs, "header" );
 94                 $$theHashRef{"header"} = $tmp if( $tmp );
 95             
 96                 $tmp = &TWiki::Func::extractNameValuePair( $theArgs, "footer" );
 97                 $$theHashRef{"footer"} = $tmp if( $tmp );
 98             
 99                 $tmp = &TWiki::Func::extractNameValuePair( $theArgs, "headerislabel" );
100                 $$theHashRef{"headerislabel"} = $tmp if( $tmp );
101             
102                 $tmp = &TWiki::Func::extractNameValuePair( $theArgs, "format" );
103                 $tmp =~ s/^\s*\|*\s*//o;
104                 $tmp =~ s/\s*\|*\s*$//o;
105                 $$theHashRef{"format"} = $tmp if( $tmp );
106 rizwank 1.1 
107                 $tmp = &TWiki::Func::extractNameValuePair( $theArgs, "changerows" );
108                 $$theHashRef{"changerows"} = $tmp if( $tmp );
109             
110                 $tmp = &TWiki::Func::extractNameValuePair( $theArgs, "quietsave" );
111                 $$theHashRef{"quietsave"} = $tmp if( $tmp );
112             
113                 $tmp = &TWiki::Func::extractNameValuePair( $theArgs, "helptopic" );
114                 $$theHashRef{"helptopic"} = $tmp if( $tmp );
115             
116                 $tmp = &TWiki::Func::extractNameValuePair( $theArgs, "editbutton" );
117                 $$theHashRef{"editbutton"} = $tmp if( $tmp );
118             
119                 return;
120             }
121             
122             # =========================
123             sub commonTagsHandler
124             {
125             ### my ( $text, $topic, $web ) = @_;   # do not uncomment, use $_[0], $_[1]... instead
126             
127 rizwank 1.1     &TWiki::Func::writeDebug( "- EditTablePlugin::commonTagsHandler( $_[2].$_[1] )" ) if $debug;
128             
129                 # Add style sheet for date calendar to skin if needed.
130                 # Handling of the common tags is done separately for the topic text and view skin
131                 # The following if statement must be done before the early escape.
132                 #
133                 # NOTE:
134                 # When adding a new button to the table that needs the table to be in the edit mode,
135                 # be sure to add it below.
136                 if( ( $_[0] =~ m/^[<][!]DOCTYPE/ ) &&
137                     ( $query->param( 'etedit' ) || $query->param( 'etaddrow' ) || $query->param( 'etdelrow') ) &&
138                     (!($_[0] =~ m/calendar-system/) ) ) {
139             
140                     my $string = " <link type=\"text/css\" rel=\"stylesheet\""
141                                . " href=\"%PUBURL%/$installWeb/EditTablePlugin/calendar-system.css\" />\n";
142                     $_[0] =~ s/([<]\/head[>])/$string$1/i;
143                 }
144             
145                 return unless $_[0] =~ /%EDIT(TABLE|CELL){(.*)}%/os;
146             
147                 unless( $prefsInitialized ) {
148 rizwank 1.1         $prefCHANGEROWS           = &TWiki::Func::getPreferencesValue("CHANGEROWS") ||
149                                 &TWiki::Func::getPreferencesValue("EDITTABLEPLUGIN_CHANGEROWS") || "on";
150                     $prefQUIETSAVE            = &TWiki::Func::getPreferencesValue("QUIETSAVE") ||
151                                 &TWiki::Func::getPreferencesValue("EDITTABLEPLUGIN_QUIETSAVE") || "on";
152                     $prefEDITBUTTON           = &TWiki::Func::getPreferencesValue("EDITBUTTON") ||
153                                 &TWiki::Func::getPreferencesValue("EDITTABLEPLUGIN_EDITBUTTON") || "Edit table";
154                     $prefJSCALENDARDATEFORMAT = &TWiki::Func::getPreferencesValue("JSCALENDARDATEFORMAT") ||
155                                 &TWiki::Func::getPreferencesValue("EDITTABLEPLUGIN_JSCALENDARDATEFORMAT") || "%Y/%m/%d";
156                     $prefJSCALENDARLANGUAGE   = &TWiki::Func::getPreferencesValue("JSCALENDARLANGUAGE") ||
157                                 &TWiki::Func::getPreferencesValue("EDITTABLEPLUGIN_JSCALENDARLANGUAGE") || "en";
158                     $prefJSCALENDAROPTIONS    = &TWiki::Func::getPreferencesValue("JSCALENDAROPTIONS") ||
159                                 &TWiki::Func::getPreferencesValue("EDITTABLEPLUGIN_JSCALENDAROPTIONS") || "";
160                     $prefsInitialized = 1;
161                 }
162             
163                 my $theWeb = $_[2];
164                 my $theTopic = $_[1];
165                 my $result = "";
166                 my $tableNr = 0;
167                 my $rowNr = 0;
168                 my $enableForm = 0;
169 rizwank 1.1     my $insideTable = 0;
170                 my $doEdit = 0;
171                 my $cgiRows = -1;
172             
173                 # appended stuff is a hack to handle EDITTABLE correctly if at end
174                 foreach( split( /\r?\n/, "$_[0]\n<nop>\n" ) ) {
175                     if( s/(\s*)%EDITTABLE{(.*)}%/&handleEditTableTag( $theWeb, $theTopic, $1, $2 )/geo ) {
176                         $enableForm = 1;
177                         $tableNr += 1;
178             
179                         my $cgiTableNr = $query->param( 'ettablenr' ) || 0;
180                         $cgiRows = $query->param( 'etrows' ) || -1;
181                         if( ( $cgiTableNr == $tableNr ) && ( "$theWeb.$theTopic" eq "$web.$topic" ) ) {
182             
183                            if( $query->param( 'etsave' ) ) {
184                                # [Save table] button pressed
185                                doSaveTable( $theWeb, $theTopic, $tableNr, "" );   # never return
186                                return; # in case browser does not redirect
187             
188                            } elsif( $query->param( 'etqsave' ) ) {
189                                # [Quiet save] button pressed
190 rizwank 1.1                    doSaveTable( $theWeb, $theTopic, $tableNr, "on" );   # never return
191                                return; # in case browser does not redirect
192             
193                            } elsif( $query->param( 'etcancel' ) ) {
194                                # [Cancel] button pressed
195                                doCancelEdit( $theWeb, $theTopic );            # never return
196                                return; # in case browser does not redirect
197             
198                            } elsif( $query->param( 'etaddrow' ) ) {
199                                # [Add row] button pressed
200                                $cgiRows++ if( $cgiRows >= 0 );
201                                $doEdit = doEnableEdit( $theWeb, $theTopic, 0 );
202                                return unless( $doEdit );
203             
204                            } elsif( $query->param( 'etdelrow' ) ) {
205                                # [Delete row] button pressed
206                                $cgiRows-- if( $cgiRows > 1 );
207                                $doEdit = doEnableEdit( $theWeb, $theTopic, 0 );
208                                return unless( $doEdit );
209             
210                            } elsif( $query->param( 'etedit' ) ) {
211 rizwank 1.1                    # [Edit table] button pressed
212                                $doEdit = doEnableEdit( $theWeb, $theTopic, 1 ); # never return if locked or no permission
213                                return unless( $doEdit );
214                                $cgiRows = -1; # make sure to get the actual number of rows
215                            }
216                         }
217                     }
218                     if( $enableForm ) {
219                         if( /^(\s*)\|.*\|\s*$/ ) {
220                             # found table row
221                             $result .= handleTableStart( $theWeb, $theTopic, $tableNr, $doEdit ) unless $insideTable;
222                             $insideTable = 1;
223                             $rowNr++;
224                             if( ( $doEdit ) && ( $cgiRows >= 0 ) && ( $rowNr > $cgiRows ) ) {
225                                 # deleted row
226                                 $rowNr--;
227                                 next;
228                             }
229                             s/^(\s*)\|(.*)/&handleTableRow( $1, $2, $tableNr, $cgiRows, $rowNr, $doEdit, 0 )/eo;
230             
231                         } elsif( $insideTable ) {
232 rizwank 1.1                 # end of table
233                             $insideTable = 0;
234                             if( ( $doEdit ) && ( $cgiRows >= 0 ) && ( $rowNr < $cgiRows ) ) {
235                                 while( $rowNr < $cgiRows ) {
236                                     $rowNr++;
237                                     $result .= handleTableRow( $theSp, "", $tableNr, $cgiRows, $rowNr, $doEdit, 0 ) . "\n";
238                                 }
239                             }
240                             $result .= handleTableEnd( $theWeb, $rowNr, $doEdit );
241                             $enableForm = 0;
242                             $doEdit = 0;
243                             $rowNr = 0;
244                         }
245                         if( /^\s*$/ ) {      # empty line
246                             if( $enableForm ) {
247                                 # empty %EDITTABLE%, so create a default table
248                                 $result .= handleTableStart( $theWeb, $theTopic, $tableNr, $doEdit );
249                                 $rowNr = 0;
250                                 if( $doEdit ) {
251                                    if( $params{"header"} ) {
252                                        $rowNr++;
253 rizwank 1.1                            $result .= handleTableRow( $preSp, "", $tableNr, $cgiRows, $rowNr, $doEdit, 0 ) . "\n";
254                                     }
255                                     do {
256                                         $rowNr++;
257                                         $result .= handleTableRow( $preSp, "", $tableNr, $cgiRows, $rowNr, $doEdit, 0 ) . "\n";
258                                     } while( $rowNr < $cgiRows );
259                                 }
260                                 $result .= handleTableEnd( $theWeb, $rowNr, $doEdit );
261                                 $enableForm = 0;
262                             }
263                             $doEdit = 0;
264                             $rowNr = 0;
265                         }
266                     }
267                     $result .= "$_\n";
268                 }
269                 $result =~ s|\n?<nop>\n$||o; # clean up hack that handles EDITTABLE correctly if at end
270                 $_[0] = $result;
271             }
272             
273             # =========================
274 rizwank 1.1 sub endRenderingHandler
275             {
276             ### my ( $text ) = @_;   # do not uncomment, use $_[0] instead
277             
278                 &TWiki::Func::writeDebug( "- EditTablePlugin::endRenderingHandler( $web.$topic )" ) if $debug;
279             
280                 # This handler is called by getRenderedVersion just after the line loop
281             
282                 return unless $_[0] =~ /$encodeStart/os;
283             
284                 $_[0] =~ s/$encodeStart(.*?)$encodeEnd/&decodeValue($1)/geos;
285             }
286             
287             # =========================
288             sub encodeValue
289             {
290                 my( $theText ) = @_;
291             
292                 # WindRiver specific hack to remove SprPlugin rendering
293                 $theText =~ s/<a href="[\w\/]*sprreport[^>]*>(.*?) (.*?)<\/a>/$1$2/goi;
294             
295 rizwank 1.1     # FIXME: *very* crude encoding to escape Wiki rendering inside form fields
296                 $theText =~ s/\./%dot%/gos;
297                 $theText =~ s/(.)/\.$1/gos;
298             
299                 # convert <br /> markup to unicode linebreak character for text areas
300                 $theText =~ s/.<.b.r. .\/.>/&#10;/gos;
301                 return $theText;
302             }
303             
304             # =========================
305             sub decodeValue
306             {
307                 my( $theText ) = @_;
308             
309                 $theText =~ s/\.(.)/$1/gos;
310                 $theText =~ s/%dot%/\./gos;
311                 $theText =~ s/\&([^#a-z])/&amp;$1/go; # escape non-entities
312                 $theText =~ s/</\&lt;/go;             # change < to entity
313                 $theText =~ s/>/\&gt;/go;             # change > to entity
314                 $theText =~ s/\"/\&quot;/go;          # change " to entity
315             
316 rizwank 1.1     return $theText;
317             }
318             
319             # =========================
320             sub parseFormat
321             {
322                 my( $theFormat, $theTopic, $theWeb, $doExpand ) = @_;
323             
324                 $theFormat =~ s/\$nop(\(\))?//gos;      # remove filler
325                 $theFormat =~ s/\$quot(\(\))?/\"/gos;   # expand double quote
326                 $theFormat =~ s/\$percnt(\(\))?/\%/gos; # expand percent
327                 $theFormat =~ s/\$dollar(\(\))?/\$/gos; # expand dollar
328                 if( $doExpand ) {
329                     # expanded form to be able to use %-vars in format
330                     $theFormat =~ s/<nop>//gos;
331                     $theFormat = &TWiki::Func::expandCommonVariables( $theFormat, $theTopic, $theWeb );
332                 }
333                 my @aFormat = split( /\s*\|\s*/, $theFormat );
334                 $aFormat[0] = "text,16" unless @aFormat;
335                 return @aFormat;
336             }
337 rizwank 1.1 
338             # =========================
339             sub handleEditTableTag
340             {
341                 my( $theWeb, $theTopic, $thePreSpace, $theArgs ) = @_;
342             
343                 $preSp = $thePreSpace || "";
344                 %params = (
345                     "header"        => "",
346                     "footer"        => "",
347                     "headerislabel" => "1",
348                     "format"        => "",
349                     "changerows"    => $prefCHANGEROWS,
350                     "quietsave"     => $prefQUIETSAVE,
351                     "helptopic"     => "",
352                     "editbutton"    => "",
353                 );
354             
355                 my $iTopic = &TWiki::Func::extractNameValuePair( $theArgs, "include" );
356                 if( $iTopic ) {
357                    # include topic to read definitions
358 rizwank 1.1        if( $iTopic =~ /^([^\.]+)\.(.*)$/o ) {
359                        $theWeb = $1;
360                        $iTopic = $2;
361                    }
362                    my $text = &TWiki::Func::readTopicText( $theWeb, $iTopic );
363                    $text =~ /%EDITTABLE{(.*)}%/os;
364                    if( $1 ) {
365                        my $args = $1;
366                        if( "$theWeb.$iTopic" ne "$web.$topic" ) {
367                            # expand common vars, unless oneself to prevent recursion
368                            $args = &TWiki::Func::expandCommonVariables( $1, $iTopic, $theWeb );
369                        }
370                        extractParams( $args, \%params );
371                    }
372                 }
373             
374                 extractParams( $theArgs, \%params );
375             
376                 $params{"header"} = "" if( $params{"header"} =~ /^(off|no)$/oi );
377                 $params{"header"} =~ s/^\s*\|//o;
378                 $params{"header"} =~ s/\|\s*$//o;
379 rizwank 1.1     $params{"headerislabel"} = "" if( $params{"headerislabel"} =~ /^(off|no)$/oi );
380                 $params{"footer"} = "" if( $params{"footer"} =~ /^(off|no)$/oi );
381                 $params{"footer"} =~ s/^\s*\|//o;
382                 $params{"footer"} =~ s/\|\s*$//o;
383                 $params{"changerows"} = "" if( $params{"changerows"} =~ /^(off|no)$/oi );
384                 $params{"quietsave"}  = "" if( $params{"quietsave"}  =~ /^(off|no)$/oi );
385             
386                 @format = parseFormat( $params{"format"}, $theTopic, $theWeb, 0 );
387                 @formatExpanded = parseFormat( $params{"format"}, $theTopic, $theWeb, 1 );
388                 $nrCols = @format;
389             
390                 # FIXME: No handling yet of footer
391             
392                 return "$preSp<nop>";
393             }
394             
395             # =========================
396             sub handleTableStart
397             {
398                 my( $theWeb, $theTopic, $theTableNr, $doEdit ) = @_;
399             
400 rizwank 1.1     my $viewUrl = &TWiki::Func::getScriptUrl( $theWeb, $theTopic, "viewauth" )
401                             . "\#edittable$theTableNr";
402                 my $text = "";
403                 if( $doEdit ) {
404                     my $dir = "%PUBURL%/$installWeb/EditTablePlugin";
405                     $text .= "$preSp<script type=\"text/javascript\" src=\"$dir/calendar.js\"></script>\n";
406                     $text .= "$preSp<script type=\"text/javascript\" src=\"$dir/calendar-"
407                            . "$prefJSCALENDARLANGUAGE.js\"></script>\n";
408                     $text .= "$preSp<script type=\"text/javascript\" src=\"$dir/calendar-setup.js\"></script>\n";
409                 }
410                 $text .= "$preSp<noautolink>\n" if $doEdit;
411                 $text .= "$preSp<a name=\"edittable$theTableNr\"></a>\n";
412                 $text .= "$preSp<form name=\"edittable$theTableNr\" action=\"$viewUrl\" method=\"post\">\n";
413                 $text .= "$preSp<input type=\"hidden\" name=\"ettablenr\" value=\"$theTableNr\" />\n";
414                 $text .= "$preSp<input type=\"hidden\" name=\"etedit\" value=\"on\" />\n" unless $doEdit;
415                 return $text;
416             }
417             
418             # =========================
419             sub handleTableEnd
420             {
421 rizwank 1.1     my( $theWeb, $theRowNr, $doEdit ) = @_;
422             
423                 my $text   = "$preSp<input type=\"hidden\" name=\"etrows\"   value=\"$theRowNr\" />\n";
424                 if( $doEdit ) {
425                     # Edit mode
426                     $text .= "$preSp<input type=\"submit\" name=\"etsave\"   value=\"Save table\" />\n";
427                     if( $params{"quietsave"} ) {
428                         $text .= "$preSp<input type=\"submit\" name=\"etqsave\"  value=\"Quiet save\" />\n";
429                     }
430                     if( $params{"changerows"} ) {
431                         $text .= "$preSp<input type=\"submit\" name=\"etaddrow\" value=\"Add row\" />\n";
432                         $text .= "$preSp<input type=\"submit\" name=\"etdelrow\" value=\"Delete last row\" />\n"
433                           unless( $params{"changerows"} =~ /^add$/oi );
434                     }
435                     $text .= "$preSp<input type=\"submit\" name=\"etcancel\" value=\"Cancel\" />\n";
436             
437                     if( $params{"helptopic"} ) {
438                         # read help topic and show below the table
439                         if( $params{"helptopic"} =~ /^([^\.]+)\.(.*)$/o ) {
440                             $theWeb = $1;
441                             $params{"helptopic"} = $2;
442 rizwank 1.1             }
443                         my $helpText = &TWiki::Func::readTopicText( $theWeb, $params{"helptopic"} );
444                                     #Strip out the meta data so it won't be displayed.
445                         $helpText =~ s/%META:[A-Za-z0-9]+{.*?}%//g;
446                         if( $helpText ) {
447                             $helpText =~ s/.*?%STARTINCLUDE%//os;
448                             $helpText =~ s/%STOPINCLUDE%.*//os;
449                             $text .= $helpText;
450                         }
451                     }
452             
453                 } else {
454                     # View mode
455                     if( $params{"editbutton"} eq "hide" ) {
456                         # do nothing, button assumed to be in a cell
457                     } else {
458                         # Add edit button to end of table
459                         $text .= "$preSp" . viewEditCell( "editbutton, 1, $params{'editbutton'}" );
460                     }
461                 }
462                 $text .= "$preSp</form>\n";
463 rizwank 1.1     $text .= "$preSp</noautolink>\n" if $doEdit;
464                 return $text;
465             }
466             
467             # =========================
468             sub parseEditCellFormat
469             {
470                 $_[1] = &TWiki::Func::extractNameValuePair( $_[0] );
471                 return "";
472             }
473             
474             # =========================
475             sub viewEditCell
476             {
477                 my ( $theAttr ) = @_;
478                 $theAttr = &TWiki::Func::extractNameValuePair( $theAttr );
479                 return "" unless( $theAttr =~ /^editbutton/ );
480             
481                 $params{"editbutton"} = "hide" unless( $params{"editbutton"} ); # Hide below table edit button
482             
483                 my @bits  = split( /,\s*/, $theAttr );
484 rizwank 1.1     my $value = "";  $value = $bits[2] if( @bits > 2);
485                 my $img   = "";  $img   = $bits[3] if( @bits > 3);
486             
487                 unless( $value ) {
488                     $value = $prefEDITBUTTON;
489                     $img = "";
490                     if( $value =~ s/(.+),\s*(.+)/$1/o ) {
491                         $img = $2;
492                         $img =~ s|%ATTACHURL%|%PUBURL%/$installWeb/EditTablePlugin|o;
493                         $img =~ s|%WEB%|$installWeb|o;
494                     }
495                 }
496             
497                 if( $img ) {
498                     return "<input type=\"image\" src=\"$img\" alt=\"$value\" />";
499                 } else {
500                     return "<input type=\"submit\" value=\"$value\" />";
501                 }
502             }
503             
504             # =========================
505 rizwank 1.1 sub saveEditCellFormat
506             {
507                 my ( $theFormat, $theName ) = @_;
508                 return "" unless( $theFormat );
509                 $theName =~ s/cell/format/;
510                 return "<input type=\"hidden\" name=\"$theName\" value=\"$theFormat\" />";
511             }
512             
513             # =========================
514             sub inputElement
515             {
516                 my ( $theTableNr, $theRowNr, $theCol, $theName, $theValue ) = @_;
517             
518                 my $text = "";
519                 my $i = @format - 1;
520                 $i = $theCol if( $theCol < $i );
521                 my @bits = split( /,\s*/, $format[$i] );
522                 my @bitsExpanded = split( /,\s*/, $formatExpanded[$i] );
523             
524                 my $cellFormat = "";
525                 $theValue =~ s/\s*%EDITCELL{(.*?)}%/&parseEditCellFormat( $1, $cellFormat )/eo;
526 rizwank 1.1     $theValue = "" if( $theValue eq " " );
527                 if( $cellFormat ) {
528                     my @aFormat = parseFormat( $cellFormat, $theTopic, $theWeb, 0);
529                     @bits = split( /,\s*/, $aFormat[0] );
530                     @aFormat = parseFormat( $cellFormat, $theTopic, $theWeb, 1);
531                     @bitsExpanded = split( /,\s*/, $aFormat[0] );
532                 }
533             
534                 my $type = "text";
535                 $type = $bits[0] if @bits > 0;
536                 # a table header is considered a label if read only header flag set
537                 $type = "label" if( ( $params{"headerislabel"} ) && ( $theValue =~ /^\s*\*.*\*\s*$/ ) );
538                 $type = "label" if( $type eq "editbutton" );  # Hide [Edit table] button
539                 my $size = 0;
540                 $size = $bits[1] if @bits > 1;
541                 my $val  = "";
542                 my $valExpanded = "";
543                 my $sel  = "";
544                 my $style = "";
545                 $style = " style='background:#e8e8e8'" if ($theRowNr % 2);
546                 if( $type eq "select" ) {
547 rizwank 1.1         my $expandedValue = &TWiki::Func::expandCommonVariables( $theValue, $theTopic, $theWeb );
548                     $size = 1 if $size < 1;
549                     $text = "<select$style name=\"$theName\" size=\"$size\">";
550                     $i = 2;
551                     while( $i < @bits ) {
552                         $val  = $bits[$i] || "";
553                         $valExpanded  = $bitsExpanded[$i] || "";
554                         if( $valExpanded eq $expandedValue ) {
555                             $text .= " <option selected=\"selected\">$val</option>";
556                         } else {
557                             $text .= " <option>$val</option>";
558                         }
559                         $i++;
560                     }
561                     $text .= " </select>";
562                     $text .= saveEditCellFormat( $cellFormat, $theName );
563             
564                 } elsif( $type eq "radio" ) {
565                     my $expandedValue = &TWiki::Func::expandCommonVariables( $theValue, $theTopic, $theWeb );
566                     $size = 1 if $size < 1;
567                     my $elements = ( @bits - 2 );
568 rizwank 1.1         my $lines = $elements / $size;
569                     $lines = ($lines == int($lines)) ? $lines : int($lines + 1);
570                     $text .= "<table><tr><td valign=\"top\">" if( $lines > 1 );
571                     $i = 2;
572                     while( $i < @bits ) {
573                         $val  = $bits[$i] || "";
574                         $valExpanded  = $bitsExpanded[$i] || "";
575                         $text .= " <input type=\"radio\" name=\"$theName\" value=\"$val\"";
576                         $text .= " checked=\"checked\"" if( $valExpanded eq $expandedValue );
577                         $text .= " /> $val";
578                         if( $lines > 1 ) {
579                             if( ($i-1) % $lines ) {
580                                 $text .= " <br />";
581                             } elsif( $i-1 < $elements ) {
582                                 $text .= "</td><td valign=\"top\">";
583                             }
584                         }
585                         $i++;
586                     }
587                     $text .= "</td></tr></table>" if( $lines > 1 );
588                     $text .= saveEditCellFormat( $cellFormat, $theName );
589 rizwank 1.1 
590                  } elsif( $type eq "checkbox" ) {
591                     my $expandedValue = &TWiki::Func::expandCommonVariables( $theValue, $theTopic, $theWeb );
592                     $size = 1 if $size < 1;
593                     my $elements = ( @bits - 2 );
594                     my $lines = $elements / $size;
595                     my $names = "Chkbx:";
596                     $lines = ($lines == int($lines)) ? $lines : int($lines + 1);
597                     $text .= "<table><tr><td valign=\"top\">" if( $lines > 1 );
598                     $i = 2;
599                     while( $i < @bits ) {
600                         $val  = $bits[$i] || "";
601                         $valExpanded  = $bitsExpanded[$i] || "";
602                         $names .= " ${theName}x$i";
603                         $text .= " <input type=\"checkbox\" name=\"${theName}x$i\" value=\"$val\"";
604                         $text .= " checked=\"checked\"" if( $expandedValue =~ /(^|, )\Q$valExpanded\E(,|$)/ );
605                         $text .= " /> $val";
606                         if( $lines > 1 ) {
607                             if( ($i-1) % $lines ) {
608                                 $text .= " <br />";
609                             } elsif( $i-1 < $elements ) {
610 rizwank 1.1                     $text .= "</td><td valign=\"top\">";
611                             }
612                         }
613                         $i++;
614                     }
615                     $text .= "</td></tr></table>" if( $lines > 1 );
616                     $text .= " <input type=\"hidden\" name=\"$theName\" value=\"$names\" />";
617                     $text .= saveEditCellFormat( $cellFormat, $theName );
618             
619                 } elsif( $type eq "row" ) {
620                     $size = $size + $theRowNr;
621                     $text = "$size<input type=\"hidden\" name=\"$theName\" value=\"$size\" />";
622                     $text .= saveEditCellFormat( $cellFormat, $theName );
623             
624                 } elsif( $type eq "label" ) {
625                     # show label text as is, and add a hidden field with value
626                     my $isHeader = 0;
627                     $isHeader = 1 if( $theValue =~ s/^\s*\*(.*)\*\s*$/$1/o );
628                     $text = $theValue;
629             
630                     # To optimize things, only in the case where a read-only column is
631 rizwank 1.1         # being processed (inside of this unless() statement) do we actually
632                     # go out and read the original topic.  Thus the reason for the
633                     # following unless() so we only read the topic the first time through.
634                     unless( defined $table ) {
635                         # To deal with the situation where TWiki variables, like
636                         # %CALC%, have already been processed and end up getting saved
637                         # in the table that way (processed), we need to read in the
638                         # topic page in raw format
639                         my $topicContents = TWiki::Func::readTopicText( $web, $topic );
640                         $table = TWiki::Plugins::Table->new( $topicContents );
641                     }
642                     my $cell = $table->getCell( $theTableNr, $theRowNr - 1, $theCol );
643                     $theValue = $cell if( defined $cell );  # original value from file
644                     $theValue = $encodeStart . encodeValue( $theValue ) . $encodeEnd unless( $theValue eq "" );
645                     $theValue = "\*$theValue\*" if( $isHeader );
646                     $text .= "<input$style type=\"hidden\" name=\"$theName\" value=\"$theValue\" />";
647                     $text = "\*$text\*" if( $isHeader );
648             
649                 } elsif( $type eq "textarea" ) {
650                     my ($rows, $cols) = split( /x/, $size );
651                     $rows = 3 if $rows < 1;
652 rizwank 1.1         $cols = 30 if $cols < 1;
653             
654                     $theValue = $encodeStart . encodeValue( $theValue ) . $encodeEnd unless( $theValue eq "" );
655                     $text .= "<textarea$style rows=\"$rows\" cols=\"$cols\" name=\"$theName\">$theValue</textarea>";
656                     $text .= saveEditCellFormat( $cellFormat, $theName );
657             
658                 } elsif( $type eq "date" ) {
659                     my $ifFormat = "";
660                     $ifFormat = $bits[3] if( @bits > 3 );
661                     $ifFormat = $ifFormat || $prefJSCALENDARDATEFORMAT;
662                     $size = 10 if $size < 1;
663                     $theValue = $encodeStart . encodeValue( $theValue ) . $encodeEnd unless( $theValue eq "" );
664                     $text .= "<input type=\"text\" name=\"$theName\" id=\"id$theName\" size=\"$size\" value=\"$theValue\" />";
665                     $text .= saveEditCellFormat( $cellFormat, $theName );
666                     $text .= "<button type=\"reset\" id=\"trigger$theName\">...</button>";
667                     $text .= "<script type=\"text/javascript\">Calendar.setup({inputField : \"id$theName\", ifFormat ";
668                     $text .= ": \"$ifFormat\", button : \"trigger$theName\", singleClick : true $prefJSCALENDAROPTIONS });</script>";
669             
670                     $query->{'jscalendar'} = 1;
671             
672                 } else { #  if( $type eq "text")
673 rizwank 1.1         $size = 16 if $size < 1;
674                     $theValue = $encodeStart . encodeValue( $theValue ) . $encodeEnd unless( $theValue eq "" );
675                     $text = "<input$style type=\"text\" name=\"$theName\" size=\"$size\" value=\"$theValue\"/>";
676                     $text .= saveEditCellFormat( $cellFormat, $theName );
677                 }
678                 return $text;
679             }
680             
681             # =========================
682             sub handleTableRow
683             {
684                 my ( $thePre, $theRow, $theTableNr, $theRowMax, $theRowNr, $doEdit, $doSave ) = @_;
685             
686                 $thePre = "" unless( defined( $thePre ) );
687                 my $text = "$thePre\|";
688             
689                 if( $doEdit ) {
690                     $theRow =~ s/\|\s*$//o;
691                     @cells = split( /\|/, $theRow );
692                     my $tmp = @cells;
693                     $nrCols = $tmp if( $tmp > $nrCols );  # expand number of cols
694 rizwank 1.1         my $val = "";
695                     my $cellFormat = "";
696                     my $cell = "";
697                     my $cellDefined = 0;
698                     my $col = 0;
699                     while( $col < $nrCols ) {
700                         $col += 1;
701                         $cellDefined = 0;
702                         $val = $query->param( "etcell${theRowNr}x$col" );
703                         if( $val && $val =~ /^Chkbx: (etcell.*)/ ) {
704                             # Multiple checkboxes, val has format "Chkbx: etcell4x2x2 etcell4x2x3 ..."
705                             my $chkBoxeNames = $1;
706                             my $chkBoxVals = "";
707                             foreach( split( /\s/, $chkBoxeNames ) ) {
708                                 $val = $query->param( $_ );
709                                 $chkBoxVals .= "$val, " if( defined $val );
710                             }
711                             $chkBoxVals =~ s/, $//;
712                             $val = $chkBoxVals;
713                         }
714                         $cellFormat = $query->param( "etformat${theRowNr}x$col" );
715 rizwank 1.1             $val .= " %EDITCELL{$cellFormat}%" if( $cellFormat );
716                         if( defined $val ) {
717                             # change any new line character sequences to <br />
718                             $val =~ s/(\n\r?)|(\r\n?)+/<br \/>/gos;
719                             # escape "|" to HTML entity
720                             $val =~ s/\|/\&\#124;/gos;
721                             $cellDefined = 1;
722                             # Expand %-vars
723                             $cell = $val;
724                         } elsif( $col <= @cells ) {
725                             $cell = $cells[$col-1];
726                             $cellDefined = 1 if( length( $cell ) > 0 );
727                             $cell =~ s/^\s//o;
728                             $cell =~ s/\s$//o;
729                         } else {
730                             $cell = "";
731                         }
732                         if( ( $theRowNr <= 1 ) && ( $params{"header"} ) ) {
733                             unless( $cell ) {
734                                 if( $params{"header"} =~ /^on$/i ) {
735                                     if( ( @format >= $col ) && ( $format[$col-1] =~ /(.*?)\,/ ) ) {
736 rizwank 1.1                             $cell = $1;
737                                     }
738                                     $cell = "text" unless $cell;
739                                     $cell = "*$cell*";
740                                 } else {
741                                     my @hCells = split( /\|/, $params{"header"} );
742                                     $cell = $hCells[$col-1] if( @hCells >= $col );
743                                     $cell = "*text*" unless $cell;
744                                 }
745                             }
746                             $text .= "$cell\|";
747             
748                         } elsif( $doSave ) {
749                             $text .= " $cell \|";
750             
751                         } else {
752                             if( ( ! $cellDefined ) && ( @format >= $col )
753                              && ( $format[$col-1] =~ /^\s*(.*?)\,\s*(.*?)\,\s*(.*?)\s*$/ ) ) {
754                                  # default value of "| text, 20, a, b, c |" cell is "a, b, c"
755                                  # default value of "| select, 1, a, b, c |" cell is "a"
756                                  $val = $1;  # type
757 rizwank 1.1                      $cell = $3;
758                                  $cell = "" unless( defined $cell && $cell ne "" ); # Proper handling of "0"
759                                  $cell =~ s/\,.*$//o if( $val eq "select" || $val eq "date" );
760                             }
761                             $text .= inputElement( $theTableNr, $theRowNr, $col-1, "etcell${theRowNr}x$col", $cell ) . " \|";
762                         }
763                     }
764                 } else {
765                     $theRow =~ s/%EDITCELL{(.*?)}%/viewEditCell($1)/geo;
766                     $text .= "$theRow";
767                 }
768                 return $text;
769             }
770             
771             # =========================
772             sub doSaveTable
773             {
774                 my ( $theWeb, $theTopic, $theTableNr, $quiet ) = @_;
775             
776                 &TWiki::Func::writeDebug( "- EditTablePlugin::doSaveTable( $theWeb, $theTopic, $theTableNr, $quiet )" ) if $debug;
777             
778 rizwank 1.1     my $text = &TWiki::Func::readTopicText( $theWeb, $theTopic );
779             
780                 my $cgiRows = $query->param( 'etrows' ) || 1;
781                 my $tableNr = 0;
782                 my $rowNr = 0;
783                 my $insideTable = 0;
784                 my $doSave = 0;
785                 my $result = "";
786                 # appended stuff is a hack to handle EDITTABLE correctly if at end
787                 foreach( split( /\r?\n/, "$text\n<nop>\n" ) ) {
788                     if( /%EDITTABLE{(.*)}%/o ) {
789                         $tableNr += 1;
790                         if( $tableNr == $theTableNr ) {
791                            $doSave = 1;
792                         }
793                     }
794                     if( $doSave ) {
795                         if( /^(\s*)\|.*\|\s*$/ ) {
796                             $insideTable = 1;
797                             $rowNr++;
798                             if( $rowNr > $cgiRows ) {
799 rizwank 1.1                     # deleted row
800                                 $rowNr--;
801                                 next;
802                             }
803                             s/^(\s*)\|(.*)/&handleTableRow( $1, $2, $tableNr, $cgiRows, $rowNr, 1, 1 )/eo;
804             
805                         } elsif( $insideTable ) {
806                             $insideTable = 0;
807                             if( $rowNr < $cgiRows ) {
808                                 while( $rowNr < $cgiRows ) {
809                                     $rowNr++;
810                                     $result .= handleTableRow( $preSp, "", $tableNr, $cgiRows, $rowNr, 1, 1 ) . "\n";
811                                 }
812                             }
813                             $doSave = 0;
814                             $rowNr = 0;
815                         }
816                         if( /^\s*$/ ) {      # empty line
817                             if( $doSave ) {
818                                 # empty %EDITTABLE%, so create a default table
819                                 $rowNr = 0;
820 rizwank 1.1                     if( $params{"header"} ) {
821                                     $rowNr++;
822                                     $result .= handleTableRow( $preSp, "", $tableNr, $cgiRows, $rowNr,1 , 1 ) . "\n";
823                                 }
824                                 while( $rowNr < $cgiRows ) {
825                                     $rowNr++;
826                                     $result .= handleTableRow( $preSp, "", $tableNr, $cgiRows, $rowNr, 1, 1 ) . "\n";
827                                 }
828                             }
829                             $doSave = 0;
830                             $rowNr = 0;
831                         }
832                     }
833                     $result .= "$_\n";
834                 }
835                 $result =~ s|\n<nop>\n$||o; # clean up hack that handles EDITTABLE correctly if at end
836             
837                 my $error = &TWiki::Func::saveTopicText( $theWeb, $theTopic, $result, "", $quiet );
838                 TWiki::Func::setTopicEditLock( $theWeb, $theTopic, 0 );  # unlock Topic
839                 my $url = &TWiki::Func::getViewUrl( $theWeb, $theTopic );
840                 if( $error ) {
841 rizwank 1.1         $url = &TWiki::Func::getOopsUrl( $theWeb, $theTopic, "oopssaveerr", $error );
842                 }
843                 &TWiki::Func::redirectCgiQuery( $query, $url );
844             }
845             
846             # =========================
847             sub doCancelEdit
848             {
849                 my ( $theWeb, $theTopic ) = @_;
850             
851                 &TWiki::Func::writeDebug( "- EditTablePlugin::doCancelEdit( $theWeb, $theTopic )" ) if $debug;
852             
853                 TWiki::Func::setTopicEditLock( $theWeb, $theTopic, 0 );
854             
855                 &TWiki::Func::redirectCgiQuery( $query, &TWiki::Func::getViewUrl( $theWeb, $theTopic ) );
856             }
857             
858             # =========================
859             sub doEnableEdit
860             {
861                 my ( $theWeb, $theTopic, $doCheckIfLocked ) = @_;
862 rizwank 1.1 
863                 &TWiki::Func::writeDebug( "- EditTablePlugin::doEnableEdit( $theWeb, $theTopic )" ) if $debug;
864             
865                 my $wikiUserName = &TWiki::Func::getWikiUserName();
866                 if( ! &TWiki::Func::checkAccessPermission( "change", $wikiUserName, "", $theTopic, $theWeb ) ) {
867                     # user has not permission to change the topic
868                     my $url = &TWiki::Func::getOopsUrl( $theWeb, $theTopic, "oopsaccesschange" );
869                     &TWiki::Func::redirectCgiQuery( $query, $url );
870                     return 0;
871                 }
872             
873                 my( $oopsUrl, $lockUser ) = &TWiki::Func::checkTopicEditLock( $theWeb, $theTopic );
874                 if( ( $doCheckIfLocked ) && ( $lockUser ) ) {
875                     # warn user that other person is editing this topic
876                     &TWiki::Func::redirectCgiQuery( $query, $oopsUrl );
877                     return 0;
878                 }
879                 TWiki::Func::setTopicEditLock( $theWeb, $theTopic, 1 );
880             
881                 return 1;
882             }
883 rizwank 1.1 
884             # =========================
885             
886             # The following code is copied from the ChartPlugin Table object.
887             
888             package TWiki::Plugins::Table;
889             
890             sub new
891             {
892                 my ($class, $topicContents) = @_;
893                 my $this = {};
894                 bless $this, $class;
895                 $this->_parseOutTables($topicContents);
896                 return $this;
897             }
898             
899             # The guts of this routine was initially copied from SpreadSheetPlugin.pm
900             # and were used in the ChartPlugin Table object which this was copied from,
901             # but this has been modified to support the functionality needed by the
902             # EditTablePlugin.  One major change is to only count and save tables
903             # following an %EDITTABLE{.*}% tag.
904 rizwank 1.1 #
905             # This routine basically returns an array of hashes where each hash
906             # contains the information for a single table.  Thus the first hash in the
907             # array represents the first table found on the topic page, the second hash
908             # in the array represents the second table found on the topic page, etc.
909             sub _parseOutTables
910             {
911                 my ($this, $topic) = @_;
912                 my $tableNum = 1;           # Table number (only count tables with EDITTABLE tag)
913                 my @tableMatrix;            # Currently parsed table.
914             
915                 my $inEditTable = 0;        # Flag to keep track if in an EDITTABLE table
916                 my $result = "";
917                 my $insidePRE = 0;
918                 my $insideTABLE = 0;
919                 my $line = "";
920                 my @row = ();
921             
922                 $topic =~ s/\r//go;
923                 $topic =~ s/\\\n//go;  # Join lines ending in "\"
924                 foreach( split( /\n/, $topic ) ) {
925 rizwank 1.1 
926                     # change state:
927                     m|<pre>|i       && ( $insidePRE = 1 );
928                     m|<verbatim>|i  && ( $insidePRE = 1 );
929                     m|</pre>|i      && ( $insidePRE = 0 );
930                     m|</verbatim>|i && ( $insidePRE = 0 );
931             
932                     if( ! $insidePRE ) {
933                         $inEditTable = 1 if (/%EDITTABLE{(.*)}%/);
934                         if ($inEditTable) {
935                             if( /^\s*\|.*\|\s*$/ ) {
936                                 # inside | table |
937                                 $insideTABLE = 1;
938                                 $line = $_;
939                                 $line =~ s/^(\s*\|)(.*)\|\s*$/$2/o; # Remove starting '|'
940                                 @row  = split( /\|/o, $line, -1 );
941                                 _trim(\@row);
942                                 push (@tableMatrix, [ @row ]);
943             
944                             } else {
945                                 # outside | table |
946 rizwank 1.1                     if( $insideTABLE ) {
947                                     # We were inside a table and are now outside of it so
948                                     # save the table info into the Table object.
949                                     $insideTABLE = 0;
950                                     $inEditTable = 0;
951                                     if (@tableMatrix != 0) {
952                                         # Save the table via its table number
953                                         $$this{"TABLE_$tableNum"} = [@tableMatrix];
954                                         $tableNum++;
955                                     }
956                                     undef @tableMatrix;  # reset table matrix
957                                 }
958                             }
959                         }
960                     }
961                     $result .= "$_\n";
962                 }
963                 $$this{NUM_TABLES} = $tableNum;
964             }
965             
966             # Trim any leading and trailing white space and/or '*'.
967 rizwank 1.1 sub _trim
968             {
969                 my ($totrim) = @_;
970                 for my $element (@$totrim) {
971                     $element =~ s/^[\s\*]+//;       # Strip of leading white/*
972                     $element =~ s/[\s\*]+$//;       # Strip of trailing white/*
973                 }
974             }
975             
976             # Return the contents of the specified cell
977             sub getCell
978             {
979                 my ( $this, $tableNum, $row, $column ) = @_;
980             
981                 my @selectedTable = $this->getTable( $tableNum );
982                 my $value = $selectedTable[$row][$column];
983                 return $value;
984             }
985             
986             sub getTable
987             {
988 rizwank 1.1     my ($this, $tableNumber) = @_;
989                 my $table = $$this{"TABLE_$tableNumber"};
990                 return @$table if defined( $table );
991                 return ();
992             }
993             
994             1;

Rizwan Kassim
Powered by
ViewCVS 0.9.2