lib/TWiki/Plugins/EditTablePlugin/Core.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
colas@0
     1
# Plugin for TWiki Enterprise Collaboration Platform, http://TWiki.org/
colas@0
     2
#
colas@0
     3
# Copyright (C) 2002-2007 Peter Thoeny, peter@thoeny.org and
colas@0
     4
# TWiki Contributors.
colas@0
     5
#
colas@0
     6
# This program is free software; you can redistribute it and/or
colas@0
     7
# modify it under the terms of the GNU General Public License
colas@0
     8
# as published by the Free Software Foundation; either version 2
colas@0
     9
# of the License, or (at your option) any later version. For
colas@0
    10
# more details read LICENSE in the root of this distribution.
colas@0
    11
#
colas@0
    12
# This program is distributed in the hope that it will be useful,
colas@0
    13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
colas@0
    14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
colas@0
    15
#
colas@0
    16
# As per the GPL, removal of this notice is prohibited.
colas@0
    17
#
colas@0
    18
# This is the EditTablePlugin used to edit tables in place.
colas@0
    19
colas@0
    20
package TWiki::Plugins::EditTablePlugin::Core;
colas@0
    21
colas@0
    22
use strict;
colas@0
    23
use Assert;
colas@0
    24
colas@0
    25
use vars qw(
colas@0
    26
  $preSp %params @format @formatExpanded
colas@0
    27
  $prefsInitialized $prefCHANGEROWS $prefEDIT_BUTTON $prefSAVE_BUTTON $prefQUIET_SAVE_BUTTON $prefADD_ROW_BUTTON $prefDELETE_LAST_ROW_BUTTON $prefCANCEL_BUTTON $prefMESSAGE_INCLUDED_TOPIC_DOES_NOT_EXIST
colas@0
    28
  $prefQUIETSAVE
colas@0
    29
  $nrCols $encodeStart $encodeEnd $table $query %regex
colas@0
    30
  $warningMessage
colas@0
    31
);
colas@0
    32
colas@0
    33
my $RENDER_HACK        = "\n<nop>\n";
colas@0
    34
my $DEFAULT_FIELD_SIZE = 16;
colas@0
    35
colas@0
    36
BEGIN {
colas@0
    37
    %regex                    = ();
colas@0
    38
    $regex{edit_table_plugin} = '%EDITTABLE{(.*?)}%';
colas@0
    39
    $regex{table_plugin}      = '%TABLE(?:{(.*?)})?%';
colas@0
    40
    $regex{table_row_full}    = '^(\s*)\|.*\|\s*$';
colas@0
    41
    $regex{table_row}         = '^(\s*)\|(.*)';
colas@0
    42
}
colas@0
    43
colas@0
    44
sub init {
colas@0
    45
    $preSp                      = '';
colas@0
    46
    %params                     = ();
colas@0
    47
    @format                     = ();
colas@0
    48
    @formatExpanded             = ();
colas@0
    49
    $prefsInitialized           = undef;
colas@0
    50
    $prefCHANGEROWS             = undef;
colas@0
    51
    $prefEDIT_BUTTON            = undef;
colas@0
    52
    $prefSAVE_BUTTON            = undef;
colas@0
    53
    $prefQUIET_SAVE_BUTTON      = undef;
colas@0
    54
    $prefADD_ROW_BUTTON         = undef;
colas@0
    55
    $prefDELETE_LAST_ROW_BUTTON = undef;
colas@0
    56
    $prefDELETE_LAST_ROW_BUTTON = undef;
colas@0
    57
    $prefQUIETSAVE              = undef;
colas@0
    58
    $nrCols                     = undef;
colas@0
    59
    $encodeStart                = undef;
colas@0
    60
    $encodeEnd                  = undef;
colas@0
    61
    $table                      = undef;
colas@0
    62
    $query                      = undef;
colas@0
    63
    $warningMessage             = '';
colas@0
    64
}
colas@0
    65
colas@0
    66
=pod
colas@0
    67
colas@0
    68
---+++ process( $doSave, $saveTableNr, $doSaveQuiet, $text, $topic, $web )
colas@0
    69
colas@0
    70
Called from commonTagsHandler. Pass over to processText in 'no Save' mode.
colas@0
    71
colas@0
    72
=cut
colas@0
    73
colas@0
    74
sub process {
colas@0
    75
    init();
colas@0
    76
    my $saveMode      = $TWiki::Plugins::EditTablePlugin::saveMode{'NONE'};
colas@0
    77
    my $saveTableNr   = 0;
colas@0
    78
    my $saveQuietMode = $TWiki::Plugins::EditTablePlugin::saveMode{'SAVEQUIET'};
colas@0
    79
    processText( $saveMode, $saveTableNr, $saveQuietMode, @_ );
colas@0
    80
}
colas@0
    81
colas@0
    82
=pod
colas@0
    83
colas@0
    84
---+++ processText( $doSave, $saveTableNr, $doSaveQuiet, $text, $topic, $web )
colas@0
    85
colas@0
    86
Process the text line by line.
colas@0
    87
When a EditTablePlugin table is encountered, its contents is rendered according to the view: 
colas@0
    88
   * View mode - default
colas@0
    89
   * Edit mode - when an Edit button is clicked, renders the rest of the table in edit mode
colas@0
    90
   * Save mode - when called from a Save button: calls processText again, only renders the selected table number, then saves the topic text
colas@0
    91
colas@0
    92
=cut
colas@0
    93
colas@0
    94
sub processText {
colas@0
    95
colas@0
    96
    my $doSave = ( shift == $TWiki::Plugins::EditTablePlugin::saveMode{'SAVE'} )
colas@0
    97
      || 0;
colas@0
    98
    my $saveTableNr = shift;
colas@0
    99
    my $doSaveQuiet =
colas@0
   100
      ( shift == $TWiki::Plugins::EditTablePlugin::saveMode{'SAVEQUIET'} ) || 0;
colas@0
   101
colas@0
   102
    $query = TWiki::Func::getCgiQuery();
colas@0
   103
colas@0
   104
    TWiki::Func::writeDebug(
colas@0
   105
        "- EditTablePlugin::commonTagsHandler( $_[2].$_[1] )")
colas@0
   106
      if $TWiki::Plugins::EditTablePlugin::debug;
colas@0
   107
colas@0
   108
    unless ($prefsInitialized) {
colas@0
   109
        $prefCHANGEROWS = TWiki::Func::getPreferencesValue('CHANGEROWS')
colas@0
   110
          || TWiki::Func::getPreferencesValue('EDITTABLEPLUGIN_CHANGEROWS')
colas@0
   111
          || 'on';
colas@0
   112
        $prefQUIETSAVE = TWiki::Func::getPreferencesValue('QUIETSAVE')
colas@0
   113
          || TWiki::Func::getPreferencesValue('EDITTABLEPLUGIN_QUIETSAVE')
colas@0
   114
          || 'on';
colas@0
   115
        $prefEDIT_BUTTON = TWiki::Func::getPreferencesValue('EDIT_BUTTON')
colas@0
   116
          || TWiki::Func::getPreferencesValue('EDITTABLEPLUGIN_EDIT_BUTTON')
colas@0
   117
          || 'Edit table';
colas@0
   118
        $prefSAVE_BUTTON = TWiki::Func::getPreferencesValue('SAVE_BUTTON')
colas@0
   119
          || TWiki::Func::getPreferencesValue('EDITTABLEPLUGIN_SAVE_BUTTON')
colas@0
   120
          || 'Save table';
colas@0
   121
        $prefQUIET_SAVE_BUTTON =
colas@0
   122
          TWiki::Func::getPreferencesValue('QUIET_SAVE_BUTTON')
colas@0
   123
          || TWiki::Func::getPreferencesValue(
colas@0
   124
            'EDITTABLEPLUGIN_QUIET_SAVE_BUTTON')
colas@0
   125
          || 'Quiet save';
colas@0
   126
        $prefADD_ROW_BUTTON = TWiki::Func::getPreferencesValue('ADD_ROW_BUTTON')
colas@0
   127
          || TWiki::Func::getPreferencesValue('EDITTABLEPLUGIN_ADD_ROW_BUTTON')
colas@0
   128
          || 'Add row';
colas@0
   129
        $prefDELETE_LAST_ROW_BUTTON =
colas@0
   130
          TWiki::Func::getPreferencesValue('DELETE_LAST_ROW_BUTTON')
colas@0
   131
          || TWiki::Func::getPreferencesValue(
colas@0
   132
            'EDITTABLEPLUGIN_DELETE_LAST_ROW_BUTTON')
colas@0
   133
          || 'Delete last row';
colas@0
   134
        $prefCANCEL_BUTTON = TWiki::Func::getPreferencesValue('CANCEL_BUTTON')
colas@0
   135
          || TWiki::Func::getPreferencesValue('EDITTABLEPLUGIN_CANCEL_BUTTON')
colas@0
   136
          || 'Cancel';
colas@0
   137
        $prefMESSAGE_INCLUDED_TOPIC_DOES_NOT_EXIST =
colas@0
   138
          TWiki::Func::getPreferencesValue('INCLUDED_TOPIC_DOES_NOT_EXIST')
colas@0
   139
          || TWiki::Func::getPreferencesValue(
colas@0
   140
            'EDITTABLEPLUGIN_INCLUDED_TOPIC_DOES_NOT_EXIST')
colas@0
   141
          || 'Warning: \'include\' topic does not exist!';
colas@0
   142
colas@0
   143
        $prefsInitialized = 1;
colas@0
   144
    }
colas@0
   145
colas@0
   146
    my $theTopic = $query->param('ettabletopic') || $_[1];
colas@0
   147
    my $theWeb   = $query->param('ettableweb')   || $_[2];
colas@0
   148
    my $invokedFromTopic = $_[3];    # not used yet
colas@0
   149
    my $invokedFromWeb   = $_[4];    # not used yet
colas@0
   150
colas@0
   151
    my $result = '';
colas@0
   152
colas@0
   153
    my $insidePRE    = 0;
colas@0
   154
    my $cgiTableNr   = 0;
colas@0
   155
    my $tableNr      = 0;      # current EditTable table
colas@0
   156
    my $isAtTheTable = 0;
colas@0
   157
    my $rowNr        = 0;      # current row number; starting at 1
colas@0
   158
    my $enableForm   = 0;
colas@0
   159
    my $insideTable  = 0;
colas@0
   160
    my $doEdit       = $doSave;
colas@0
   161
    my $hasTableRow  = 0;      # the current line has a row with '| some text |'
colas@0
   162
    my $hasTableTag  = 0;      # the current line has a %TABLE{}% variable tag
colas@0
   163
    my $createdNewTable = 0;
colas@0
   164
    my @rows            = ();
colas@0
   165
    my $etrows          = -1
colas@0
   166
      ; # the number of content rows as passed as form parameter: only available on edit or save; -1 if not rendered
colas@0
   167
    my $etrowsParam;
colas@0
   168
    my $addedRowCount      = 0;
colas@0
   169
    my $addedRowCountParam = 0;
colas@0
   170
    my $headerRowCount     = 0;    #$query->param('etheaderrows') || 0;
colas@0
   171
    my $footerRowCount     = 0;    #$query->param('etfooterrows') || 0;
colas@0
   172
    my $endOfTable         = 0;
colas@0
   173
colas@0
   174
    my $theText;
colas@0
   175
    if ($doSave) {
colas@0
   176
        $theText = TWiki::Func::readTopicText( $theWeb, $theTopic );
colas@0
   177
    }
colas@0
   178
    else {
colas@0
   179
        $theText = $_[0];
colas@0
   180
    }
colas@0
   181
colas@0
   182
    $theText =~
colas@0
   183
      s/\r//go;    # strip out all \r chars (may be pasted into a table cell)
colas@0
   184
    $theText =~ s/\\\n//go;    # Join lines ending in "\"
colas@0
   185
    $theText .= $RENDER_HACK
colas@0
   186
      ;    # appended stuff is a hack to handle EDITTABLE correctly if at end
colas@0
   187
colas@0
   188
    my @lines = split( /\n/, $theText );
colas@0
   189
    for (@lines) {
colas@0
   190
colas@0
   191
        # Check if we are inside <pre> or <verbatim> tags
colas@0
   192
        # if so, do not process
colas@0
   193
        m|<pre>|i       && ( $insidePRE = 1 );
colas@0
   194
        m|<verbatim>|i  && ( $insidePRE = 1 );
colas@0
   195
        m|</pre>|i      && ( $insidePRE = 0 );
colas@0
   196
        m|</verbatim>|i && ( $insidePRE = 0 );
colas@0
   197
colas@0
   198
        if ($insidePRE) {
colas@0
   199
colas@0
   200
            # no need to process, just copy the line
colas@0
   201
            $result .= "$_\n";
colas@0
   202
            next;
colas@0
   203
        }
colas@0
   204
colas@0
   205
        my $isLineWithEditTableTag = m/(\s*)$regex{edit_table_plugin}/go;
colas@0
   206
        if ($isLineWithEditTableTag) {
colas@0
   207
colas@0
   208
            # this is a line with an EDITTABLE tag
colas@0
   209
            if ($doSave) {
colas@0
   210
colas@0
   211
                # no need to process, just copy the line
colas@0
   212
                $result .= "$_\n";
colas@0
   213
            }
colas@0
   214
            else {
colas@0
   215
                my $line = $_;
colas@0
   216
colas@0
   217
                # process the tag contents
colas@0
   218
                my $restRegex = '([^$]*)';
colas@0
   219
                my $editTablePluginRE =
colas@0
   220
                  "(.*?)$regex{edit_table_plugin}$restRegex";
colas@0
   221
                $line =~
colas@0
   222
s/$editTablePluginRE/&handleEditTableTag( $theWeb, $theTopic, $1, $2 )/geo;
colas@0
   223
colas@0
   224
                # TODO: something strange has happened to the prefix
colas@0
   225
                # it is no longer used by handleEditTableTag
colas@0
   226
                # we add it here:
colas@0
   227
                $result .= $1 if $1;
colas@0
   228
                $result .= $3 if $3;
colas@0
   229
            }
colas@0
   230
            $tableNr++;
colas@0
   231
colas@0
   232
            next if ( $doSave && ( $tableNr != $saveTableNr ) );
colas@0
   233
            $enableForm = 1;
colas@0
   234
colas@0
   235
            $cgiTableNr = $query->param('ettablenr')
colas@0
   236
              || 0;    # only on save and edit
colas@0
   237
            $etrowsParam = $query->param('etrows');
colas@0
   238
            $etrows =
colas@0
   239
              ( defined $etrowsParam )
colas@0
   240
              ? $etrowsParam
colas@0
   241
              : -1;
colas@0
   242
            $addedRowCountParam = $query->param('etaddedrows') || 0;
colas@0
   243
            $addedRowCount = $addedRowCountParam;
colas@0
   244
colas@0
   245
            $isAtTheTable = 0;
colas@0
   246
            if (
colas@0
   247
                ( $cgiTableNr == $tableNr )
colas@0
   248
                && (  $theWeb . '.'
colas@0
   249
                    . $theTopic eq
colas@0
   250
"$TWiki::Plugins::EditTablePlugin::web.$TWiki::Plugins::EditTablePlugin::topic"
colas@0
   251
                )
colas@0
   252
              )
colas@0
   253
            {
colas@0
   254
                $isAtTheTable = 1;
colas@0
   255
                if ( !$doSave && $query->param('etsave') ) {
colas@0
   256
colas@0
   257
                    # [Save table] button pressed
colas@0
   258
                    my $theSaveMode =
colas@0
   259
                      $TWiki::Plugins::EditTablePlugin::saveMode{'SAVE'};
colas@0
   260
                    my $theSaveQuietMode =
colas@0
   261
                      $TWiki::Plugins::EditTablePlugin::saveMode{'NONE'};
colas@0
   262
colas@0
   263
                    return processText( $theSaveMode, $tableNr,
colas@0
   264
                        $theSaveQuietMode, @_ );
colas@0
   265
                }
colas@0
   266
                elsif ( !$doSave && $query->param('etqsave') ) {
colas@0
   267
colas@0
   268
                    # [Quiet save] button pressed
colas@0
   269
                    my $theSaveMode =
colas@0
   270
                      $TWiki::Plugins::EditTablePlugin::saveMode{'SAVE'};
colas@0
   271
                    my $theSaveQuietMode =
colas@0
   272
                      $TWiki::Plugins::EditTablePlugin::saveMode{'SAVEQUIET'};
colas@0
   273
                    return processText( $theSaveMode, $tableNr,
colas@0
   274
                        $theSaveQuietMode, @_ );
colas@0
   275
                }
colas@0
   276
                elsif ( $query->param('etcancel') ) {
colas@0
   277
colas@0
   278
                    # [Cancel] button pressed
colas@0
   279
                    doCancelEdit( $theWeb, $theTopic );
colas@0
   280
                    ASSERT(0) if DEBUG;
colas@0
   281
                    return;    # in case browser does not redirect
colas@0
   282
                }
colas@0
   283
                elsif ( $query->param('etaddrow') ) {
colas@0
   284
colas@0
   285
                    # [Add row] button pressed
colas@0
   286
                    $etrows = ( $etrows == -1 ) ? 1 : $etrows + 1;
colas@0
   287
                    $addedRowCount++;
colas@0
   288
                    $doEdit = doEnableEdit( $theWeb, $theTopic, 0 );
colas@0
   289
                    return unless ($doEdit);
colas@0
   290
                }
colas@0
   291
                elsif ( $query->param('etdelrow') ) {
colas@0
   292
colas@0
   293
                    # [Delete row] button pressed
colas@0
   294
                    if ( $etrows > 0 ) {
colas@0
   295
                        $etrows--;
colas@0
   296
                    }
colas@0
   297
                    $addedRowCount--;
colas@0
   298
                    $doEdit = doEnableEdit( $theWeb, $theTopic, 0 );
colas@0
   299
                    return unless ($doEdit);
colas@0
   300
                }
colas@0
   301
                elsif ( $query->param('etedit') ) {
colas@0
   302
colas@0
   303
                    # [Edit table] button pressed
colas@0
   304
                    $doEdit = doEnableEdit( $theWeb, $theTopic, 1 );
colas@0
   305
colas@0
   306
                    # never return if locked or no permission
colas@0
   307
                    return unless ($doEdit);
colas@0
   308
                }
colas@0
   309
            }
colas@0
   310
        }    # if $isLineWithEditTableTag
colas@0
   311
colas@0
   312
        $hasTableTag = 0;
colas@0
   313
        if (/$regex{table_plugin}/) {
colas@0
   314
colas@0
   315
            # match with a TablePlugin line
colas@0
   316
            # works when TABLE tag is just above OR just below the EDITTABLE tag
colas@0
   317
            my %tablePluginParams = TWiki::Func::extractParameters($1);
colas@0
   318
            $headerRowCount = $tablePluginParams{'headerrows'} || 0;
colas@0
   319
            $footerRowCount = $tablePluginParams{'footerrows'} || 0;
colas@0
   320
colas@0
   321
            # When editing we append a disableallsort="on" to the TABLE tag
colas@0
   322
            # to prevent TablePlugin from sorting the table. (Item5135)
colas@0
   323
            $_ =~ s/(}%)/ disableallsort="on"$1/ if ( $doEdit && !$doSave );
colas@0
   324
colas@0
   325
            $hasTableTag = 1;
colas@0
   326
        }
colas@0
   327
colas@0
   328
        $hasTableRow = 0;    # assume no row
colas@0
   329
        if (m/$regex{table_row_full}/) {
colas@0
   330
            $hasTableRow = 1;
colas@0
   331
        }
colas@0
   332
colas@0
   333
        if ($enableForm) {
colas@0
   334
colas@0
   335
            if ( !$doEdit && !$doSave ) {
colas@0
   336
colas@0
   337
                if ( !$hasTableRow && !$insideTable ) {
colas@0
   338
                    my $tableStart =
colas@0
   339
                      handleTableStart( $theWeb, $theTopic, $tableNr, $doEdit );
colas@0
   340
                    $result .= $tableStart;
colas@0
   341
                    $insideTable = 1;
colas@0
   342
                    $hasTableRow = 1;
colas@0
   343
                    next;
colas@0
   344
                }
colas@0
   345
                if ($hasTableRow) {
colas@0
   346
                    $insideTable = 1;
colas@0
   347
                    $rowNr++;
colas@0
   348
                    my $isNewRow = 0;
colas@0
   349
s/^(\s*)\|(.*)/handleTableRow( $1, $2, $tableNr, $isNewRow, $rowNr, $doEdit, $doSave, $theWeb, $theTopic )/eo;
colas@0
   350
                }
colas@0
   351
                elsif ( $insideTable && !$hasTableTag ) {
colas@0
   352
colas@0
   353
                    # end of table
colas@0
   354
                    $endOfTable = 1;
colas@0
   355
                    my $rowCount = $rowNr - $headerRowCount - $footerRowCount;
colas@0
   356
                    my $tableEnd = handleTableEnd( $theWeb, $rowCount, $doEdit,
colas@0
   357
                        $headerRowCount, $footerRowCount );
colas@0
   358
                    $result .= $tableEnd;
colas@0
   359
                }
colas@0
   360
            }    # if !$doEdit && !$doSave
colas@0
   361
colas@0
   362
            if ( $doEdit || $doSave ) {
colas@0
   363
                if ( !$hasTableRow && !$insideTable && !$createdNewTable ) {
colas@0
   364
colas@0
   365
                    # start new table
colas@0
   366
                    $createdNewTable = 1;
colas@0
   367
                    if ( !$doSave ) {
colas@0
   368
                        my $tableStart =
colas@0
   369
                          handleTableStart( $theWeb, $theTopic, $tableNr,
colas@0
   370
                            $doEdit );
colas@0
   371
                        $result .= $tableStart;
colas@0
   372
                    }
colas@0
   373
                    $insideTable = 1;
colas@0
   374
                    $hasTableRow = 1;
colas@0
   375
                    next;
colas@0
   376
                }
colas@0
   377
                if ($hasTableRow) {
colas@0
   378
                    $insideTable = 1;
colas@0
   379
                    $rowNr++;
colas@0
   380
colas@0
   381
# when adding new rows, previously entered values will be mapped onto the new table rows
colas@0
   382
# when the last row is not the newly added, as may happen with footer rows, we need to adjust the mapping
colas@0
   383
# we introduce a 'rowNr shift' for values
colas@0
   384
# we assume that new rows are added just before the footer
colas@0
   385
                    my $shift = 0;
colas@0
   386
                    if ( $footerRowCount > 0 ) {
colas@0
   387
                        my $bodyRowNr = $rowNr - $headerRowCount;
colas@0
   388
                        if ( $bodyRowNr > ( $etrows - $addedRowCount ) ) {
colas@0
   389
                            $shift = $addedRowCountParam;
colas@0
   390
                        }
colas@0
   391
                    }
colas@0
   392
                    my $theRowNr = $rowNr + $shift;
colas@0
   393
                    my $isNewRow = 0;
colas@0
   394
s/$regex{table_row}/handleTableRow( $1, $2, $tableNr, $isNewRow, $theRowNr, $doEdit, $doSave, $theWeb, $theTopic )/eo;
colas@0
   395
                    push @rows, $_;
colas@0
   396
                    next;
colas@0
   397
                }
colas@0
   398
                elsif ( $insideTable && !$hasTableTag ) {
colas@0
   399
colas@0
   400
                    # end of table
colas@0
   401
                    $endOfTable = 1;
colas@0
   402
                    my @headerRows = ();
colas@0
   403
                    my @footerRows = ();
colas@0
   404
                    my @bodyRows   = @rows;    #clone
colas@0
   405
colas@0
   406
                    if ( $headerRowCount > 0 ) {
colas@0
   407
                        @headerRows = @rows;    # clone
colas@0
   408
                        splice @headerRows, $headerRowCount;
colas@0
   409
colas@0
   410
                        # remove the header rows from the body rows
colas@0
   411
                        splice @bodyRows, 0, $headerRowCount;
colas@0
   412
                    }
colas@0
   413
                    if ( $footerRowCount > 0 ) {
colas@0
   414
                        @footerRows = @rows;    # clone
colas@0
   415
                        splice @footerRows, 0,
colas@0
   416
                          ( scalar @footerRows - $footerRowCount );
colas@0
   417
colas@0
   418
                        # remove the footer rows from the body rows
colas@0
   419
                        splice @bodyRows,
colas@0
   420
                          ( scalar @bodyRows - $footerRowCount ),
colas@0
   421
                          $footerRowCount;
colas@0
   422
                    }
colas@0
   423
colas@0
   424
                    # delete rows?
colas@0
   425
                    if ( $doEdit || $doSave ) {
colas@0
   426
                        if ( scalar @bodyRows > $etrows && $etrows != -1 ) {
colas@0
   427
                            splice( @bodyRows, $etrows );
colas@0
   428
                        }
colas@0
   429
                    }
colas@0
   430
colas@0
   431
                    # no table at all?
colas@0
   432
                    if ( $doEdit && !$doSave ) {
colas@0
   433
colas@0
   434
                        # if we are starting with an empty table, we force
colas@0
   435
                        # create a row, with an optional header row
colas@0
   436
                        my $addHeader =
colas@0
   437
                          ( $params{'header'} && $headerRowCount == 0 )
colas@0
   438
                          ? 1
colas@0
   439
                          : 0;
colas@0
   440
                        my $firstRowsCount = 1 + $addHeader;
colas@0
   441
colas@0
   442
                        if ( scalar @bodyRows < $firstRowsCount
colas@0
   443
                            && !$query->param('etdelrow') )
colas@0
   444
                        {
colas@0
   445
                            if ( $etrows < $firstRowsCount ) {
colas@0
   446
                                $etrows = $firstRowsCount;
colas@0
   447
                            }
colas@0
   448
                        }
colas@0
   449
                    }
colas@0
   450
colas@0
   451
                    # add rows?
colas@0
   452
                    if ( $doEdit || $doSave ) {
colas@0
   453
                        while ( scalar @bodyRows < $etrows ) {
colas@0
   454
                            $rowNr++;
colas@0
   455
                            my $newBodyRowNr = scalar @bodyRows + 1;
colas@0
   456
                            my $theRowNr     = $newBodyRowNr + $headerRowCount;
colas@0
   457
colas@0
   458
                            my $isNewRow = ( defined $etrowsParam
colas@0
   459
                                  && $newBodyRowNr > $etrowsParam ) ? 1 : 0;
colas@0
   460
                            my $newRow = handleTableRow(
colas@0
   461
                                '',        '',      $tableNr, $isNewRow,
colas@0
   462
                                $theRowNr, $doEdit, $doSave,  $theWeb,
colas@0
   463
                                $theTopic
colas@0
   464
                            );
colas@0
   465
                            push @bodyRows, $newRow;
colas@0
   466
                        }
colas@0
   467
                    }
colas@0
   468
colas@0
   469
                    my @combinedRows = ( @headerRows, @bodyRows, @footerRows );
colas@0
   470
colas@0
   471
                    # after re-ordering, renumber the cells
colas@0
   472
                    my $rowCounter = 0;
colas@0
   473
                    for my $cellRow (@combinedRows) {
colas@0
   474
                        $rowCounter++;
colas@0
   475
                        $cellRow =~
colas@0
   476
                          s/(etcell)([0-9]+)(x)([0-9]+)/$1$rowCounter$3$4/go;
colas@0
   477
                    }
colas@0
   478
                    $result .= join( "\n", @combinedRows ) . "\n";
colas@0
   479
colas@0
   480
                    if ( !$doSave ) {
colas@0
   481
                        my $rowCount = scalar @bodyRows;
colas@0
   482
                        my $tableEnd =
colas@0
   483
                          handleTableEnd( $theWeb, $rowCount, $doEdit,
colas@0
   484
                            $headerRowCount, $footerRowCount, $addedRowCount );
colas@0
   485
                        $result .= $tableEnd;
colas@0
   486
                    }
colas@0
   487
colas@0
   488
                }    # $hasTableRow
colas@0
   489
            }    #/ if $doEdit
colas@0
   490
        }    # if $enableForm
colas@0
   491
colas@0
   492
        if ($endOfTable) {
colas@0
   493
            $endOfTable = 0;
colas@0
   494
colas@0
   495
            # re-init values
colas@0
   496
            $insideTable     = 0;
colas@0
   497
            $enableForm      = 0;
colas@0
   498
            $doEdit          = 0;
colas@0
   499
            $rowNr           = 0;
colas@0
   500
            $createdNewTable = 0;
colas@0
   501
            $headerRowCount  = 0;
colas@0
   502
            $footerRowCount  = 0;
colas@0
   503
            $etrows          = -1;
colas@0
   504
            @rows            = ();
colas@0
   505
            $isAtTheTable    = 0;
colas@0
   506
            $cgiTableNr      = 0;
colas@0
   507
        }
colas@0
   508
colas@0
   509
        $result .= "$_\n";
colas@0
   510
    }
colas@0
   511
colas@0
   512
    # clean up hack that handles EDITTABLE correctly if at end
colas@0
   513
    $result =~ s/($RENDER_HACK)+$//go;
colas@0
   514
colas@0
   515
    if ($doSave) {
colas@0
   516
        my $error = TWiki::Func::saveTopicText( $theWeb, $theTopic, $result, '',
colas@0
   517
            $doSaveQuiet );
colas@0
   518
        TWiki::Func::setTopicEditLock( $theWeb, $theTopic, 0 );   # unlock Topic
colas@0
   519
        my $url = TWiki::Func::getViewUrl( $theWeb, $theTopic );
colas@0
   520
        if ($error) {
colas@0
   521
            $url = TWiki::Func::getOopsUrl( $theWeb, $theTopic, 'oopssaveerr',
colas@0
   522
                $error );
colas@0
   523
        }
colas@0
   524
        TWiki::Func::redirectCgiQuery( $query, $url );
colas@0
   525
        return;
colas@0
   526
    }
colas@0
   527
    $_[0] = $result;
colas@0
   528
}
colas@0
   529
colas@0
   530
=pod
colas@0
   531
colas@0
   532
=cut
colas@0
   533
colas@0
   534
sub extractParams {
colas@0
   535
    my ( $theArgs, $theHashRef ) = @_;
colas@0
   536
colas@0
   537
    my $tmp = TWiki::Func::extractNameValuePair( $theArgs, 'header' );
colas@0
   538
    $$theHashRef{'header'} = $tmp if ($tmp);
colas@0
   539
colas@0
   540
    $tmp = TWiki::Func::extractNameValuePair( $theArgs, 'footer' );
colas@0
   541
    $$theHashRef{'footer'} = $tmp if ($tmp);
colas@0
   542
colas@0
   543
    $tmp = TWiki::Func::extractNameValuePair( $theArgs, 'headerislabel' );
colas@0
   544
    $$theHashRef{'headerislabel'} = $tmp if ($tmp);
colas@0
   545
colas@0
   546
    $tmp = TWiki::Func::extractNameValuePair( $theArgs, 'format' );
colas@0
   547
    $tmp =~ s/^\s*\|*\s*//o;
colas@0
   548
    $tmp =~ s/\s*\|*\s*$//o;
colas@0
   549
    $$theHashRef{'format'} = $tmp if ($tmp);
colas@0
   550
colas@0
   551
    $tmp = TWiki::Func::extractNameValuePair( $theArgs, 'changerows' );
colas@0
   552
    $$theHashRef{'changerows'} = $tmp if ($tmp);
colas@0
   553
colas@0
   554
    $tmp = TWiki::Func::extractNameValuePair( $theArgs, 'quietsave' );
colas@0
   555
    $$theHashRef{'quietsave'} = $tmp if ($tmp);
colas@0
   556
colas@0
   557
    $tmp = TWiki::Func::extractNameValuePair( $theArgs, 'helptopic' );
colas@0
   558
    $$theHashRef{'helptopic'} = $tmp if ($tmp);
colas@0
   559
colas@0
   560
    $tmp = TWiki::Func::extractNameValuePair( $theArgs, 'editbutton' );
colas@0
   561
    $$theHashRef{'editbutton'} = $tmp if ($tmp);
colas@0
   562
colas@0
   563
    return;
colas@0
   564
}
colas@0
   565
colas@0
   566
=pod
colas@0
   567
colas@0
   568
=cut
colas@0
   569
colas@0
   570
sub parseFormat {
colas@0
   571
    my ( $theFormat, $theTopic, $theWeb, $doExpand ) = @_;
colas@0
   572
colas@0
   573
    #$theFormat =~ s/\$nop(\(\))?//gos;         # remove filler
colas@0
   574
    #$theFormat =~ s/\$quot(\(\))?/\"/gos;      # expand double quote
colas@0
   575
    #$theFormat =~ s/\$percnt(\(\))?/\%/gos;    # expand percent
colas@0
   576
    #$theFormat =~ s/\$dollar(\(\))?/\$/gos;    # expand dollar
colas@0
   577
colas@0
   578
    if ($doExpand) {
colas@0
   579
colas@0
   580
        # expanded form to be able to use %-vars in format
colas@0
   581
        $theFormat =~ s/<nop>//gos;
colas@0
   582
        $theFormat =
colas@0
   583
          TWiki::Func::expandCommonVariables( $theFormat, $theTopic, $theWeb );
colas@0
   584
    }
colas@0
   585
    my @aFormat = split( /\s*\|\s*/, $theFormat );
colas@0
   586
    $aFormat[0] = "text,$DEFAULT_FIELD_SIZE" unless @aFormat;
colas@0
   587
colas@0
   588
    return @aFormat;
colas@0
   589
}
colas@0
   590
colas@0
   591
=pod
colas@0
   592
colas@0
   593
=cut
colas@0
   594
colas@0
   595
sub handleEditTableTag {
colas@0
   596
    my ( $theWeb, $theTopic, $thePreSpace, $theArgs ) = @_;
colas@0
   597
colas@0
   598
    #$preSp = $thePreSpace || '';
colas@0
   599
colas@0
   600
    %params = (
colas@0
   601
        'header'        => '',
colas@0
   602
        'footer'        => '',
colas@0
   603
        'headerislabel' => "1",
colas@0
   604
        'format'        => '',
colas@0
   605
        'changerows'    => $prefCHANGEROWS,
colas@0
   606
        'quietsave'     => $prefQUIETSAVE,
colas@0
   607
        'helptopic'     => '',
colas@0
   608
        'editbutton'    => '',
colas@0
   609
    );
colas@0
   610
    $warningMessage = '';
colas@0
   611
colas@0
   612
    # include topic to read definitions
colas@0
   613
    my $iTopic = TWiki::Func::extractNameValuePair( $theArgs, 'include' );
colas@0
   614
    my $iTopicExists = 0;
colas@0
   615
    if ($iTopic) {
colas@0
   616
        if ( $iTopic =~ /^([^\.]+)\.(.*)$/o ) {
colas@0
   617
            $theWeb = $1;
colas@0
   618
            $iTopic = $2;
colas@0
   619
        }
colas@0
   620
colas@0
   621
        $iTopicExists = TWiki::Func::topicExists( $theWeb, $iTopic )
colas@0
   622
          if $iTopic ne '';
colas@0
   623
        if ( $iTopic && !$iTopicExists ) {
colas@0
   624
            $warningMessage = $prefMESSAGE_INCLUDED_TOPIC_DOES_NOT_EXIST;
colas@0
   625
        }
colas@0
   626
        if ($iTopicExists) {
colas@0
   627
colas@0
   628
            my $text = TWiki::Func::readTopicText( $theWeb, $iTopic );
colas@0
   629
            $text =~ /$regex{edit_table_plugin}/os;
colas@0
   630
            if ($1) {
colas@0
   631
                my $args = $1;
colas@0
   632
                if (   $theWeb ne $TWiki::Plugins::EditTablePlugin::web
colas@0
   633
                    || $iTopic ne $TWiki::Plugins::EditTablePlugin::topic )
colas@0
   634
                {
colas@0
   635
colas@0
   636
                    # expand common vars, unless oneself to prevent recursion
colas@0
   637
                    $args = TWiki::Func::expandCommonVariables( $1, $iTopic,
colas@0
   638
                        $theWeb );
colas@0
   639
                }
colas@0
   640
                extractParams( $args, \%params );
colas@0
   641
            }
colas@0
   642
        }
colas@0
   643
    }
colas@0
   644
colas@0
   645
    extractParams( $theArgs, \%params );
colas@0
   646
colas@0
   647
    # FIXME: should use TWiki::Func::extractParameters
colas@0
   648
    $params{'header'} = '' if ( $params{header} =~ /^(off|no)$/oi );
colas@0
   649
    $params{'header'} =~ s/^\s*\|//o;
colas@0
   650
    $params{'header'} =~ s/\|\s*$//o;
colas@0
   651
    $params{'headerislabel'} = ''
colas@0
   652
      if ( $params{headerislabel} =~ /^(off|no)$/oi );
colas@0
   653
    $params{'footer'} = '' if ( $params{footer} =~ /^(off|no)$/oi );
colas@0
   654
    $params{'footer'} =~ s/^\s*\|//o;
colas@0
   655
    $params{'footer'} =~ s/\|\s*$//o;
colas@0
   656
    $params{'changerows'} = '' if ( $params{changerows} =~ /^(off|no)$/oi );
colas@0
   657
    $params{'quietsave'}  = '' if ( $params{quietsave}  =~ /^(off|no)$/oi );
colas@0
   658
colas@0
   659
    @format         = parseFormat( $params{format}, $theTopic, $theWeb, 0 );
colas@0
   660
    @formatExpanded = parseFormat( $params{format}, $theTopic, $theWeb, 1 );
colas@0
   661
    $nrCols         = @format;
colas@0
   662
colas@0
   663
    return "$preSp";
colas@0
   664
}
colas@0
   665
colas@0
   666
=pod
colas@0
   667
colas@0
   668
=cut
colas@0
   669
colas@0
   670
sub handleTableStart {
colas@0
   671
    my ( $theWeb, $theTopic, $theTableNr, $doEdit ) = @_;
colas@0
   672
    my $viewUrl = TWiki::Func::getScriptUrl( $theWeb, $theTopic, 'viewauth' )
colas@0
   673
      . "\#edittable$theTableNr";
colas@0
   674
    my $text = '';
colas@0
   675
    if ($doEdit) {
colas@0
   676
        require TWiki::Contrib::JSCalendarContrib;
colas@0
   677
        unless ($@) {
colas@0
   678
            TWiki::Contrib::JSCalendarContrib::addHEAD('twiki');
colas@0
   679
        }
colas@0
   680
    }
colas@0
   681
    $text .= "$preSp<noautolink>\n" if $doEdit;
colas@0
   682
    $text .= "$preSp<a name=\"edittable$theTableNr\"></a>\n";
colas@0
   683
    my $cssClass = 'editTable';
colas@0
   684
    if ($doEdit) {
colas@0
   685
        $cssClass .= ' editTableEdit';
colas@0
   686
    }
colas@0
   687
    $text .= "<div class=\"" . $cssClass . "\">\n";
colas@0
   688
    $text .=
colas@0
   689
"$preSp<form name=\"edittable$theTableNr\" action=\"$viewUrl\" method=\"post\">\n";
colas@0
   690
    $text .= hiddenField( $preSp, 'ettablenr', $theTableNr, "\n" );
colas@0
   691
    $text .= hiddenField( $preSp, 'etedit', 'on', "\n" )
colas@0
   692
      unless $doEdit;
colas@0
   693
    return $text;
colas@0
   694
}
colas@0
   695
colas@0
   696
sub hiddenField {
colas@0
   697
    my ( $prefix, $name, $value, $suffix ) = @_;
colas@0
   698
    $prefix = defined $prefix ? $prefix : '';
colas@0
   699
    $suffix = defined $suffix ? $suffix : '';
colas@0
   700
    return
colas@0
   701
      "$prefix<input type=\"hidden\" name=\"$name\" value=\"$value\" />$suffix";
colas@0
   702
}
colas@0
   703
colas@0
   704
=pod
colas@0
   705
colas@0
   706
=cut
colas@0
   707
colas@0
   708
sub handleTableEnd {
colas@0
   709
    my ( $theWeb, $rowCount, $doEdit, $headerRowCount, $footerRowCount,
colas@0
   710
        $addedRowCount )
colas@0
   711
      = @_;
colas@0
   712
    my $text = '';
colas@0
   713
    $text .= hiddenField( $preSp, 'etrows',       $rowCount,       "\n" );
colas@0
   714
    $text .= hiddenField( $preSp, 'etheaderrows', $headerRowCount, "\n" )
colas@0
   715
      if $headerRowCount;
colas@0
   716
    $text .= hiddenField( $preSp, 'etfooterrows', $footerRowCount, "\n" )
colas@0
   717
      if $footerRowCount;
colas@0
   718
    $text .= hiddenField( $preSp, 'etaddedrows', $addedRowCount, "\n" )
colas@0
   719
      if $addedRowCount;
colas@0
   720
colas@0
   721
    $text .= hiddenField( $preSp, 'sort', 'off', "\n" );
colas@0
   722
colas@0
   723
    if ($doEdit) {
colas@0
   724
colas@0
   725
        # Edit mode
colas@0
   726
        $text .=
colas@0
   727
"$preSp<input type=\"submit\" name=\"etsave\" id=\"etsave\" value=\"$prefSAVE_BUTTON\" class=\"twikiSubmit\" />\n";
colas@0
   728
        if ( $params{'quietsave'} ) {
colas@0
   729
            $text .=
colas@0
   730
"$preSp<input type=\"submit\" name=\"etqsave\" id=\"etqsave\" value=\"$prefQUIET_SAVE_BUTTON\" class=\"twikiButton\" />\n";
colas@0
   731
        }
colas@0
   732
        if ( $params{'changerows'} ) {
colas@0
   733
            $text .=
colas@0
   734
"$preSp<input type=\"submit\" name=\"etaddrow\" id=\"etaddrow\" value=\"$prefADD_ROW_BUTTON\" class=\"twikiButton\" />\n";
colas@0
   735
            $text .=
colas@0
   736
"$preSp<input type=\"submit\" name=\"etdelrow\" id=\"etdelrow\" value=\"$prefDELETE_LAST_ROW_BUTTON\" class=\"twikiButton\" />\n"
colas@0
   737
              unless ( $params{'changerows'} =~ /^add$/oi );
colas@0
   738
        }
colas@0
   739
        $text .=
colas@0
   740
"$preSp<input type=\"submit\" name=\"etcancel\" id=\"etcancel\" value=\"$prefCANCEL_BUTTON\" class=\"twikiButton twikiButtonCancel\" />\n";
colas@0
   741
colas@0
   742
        if ( $params{'helptopic'} ) {
colas@0
   743
colas@0
   744
            # read help topic and show below the table
colas@0
   745
            if ( $params{'helptopic'} =~ /^([^\.]+)\.(.*)$/o ) {
colas@0
   746
                $theWeb = $1;
colas@0
   747
                $params{'helptopic'} = $2;
colas@0
   748
            }
colas@0
   749
            my $helpText =
colas@0
   750
              TWiki::Func::readTopicText( $theWeb, $params{'helptopic'} );
colas@0
   751
colas@0
   752
            #Strip out the meta data so it won't be displayed.
colas@0
   753
            $helpText =~ s/%META:[A-Za-z0-9]+{.*?}%//g;
colas@0
   754
            if ($helpText) {
colas@0
   755
                $helpText =~ s/.*?%STARTINCLUDE%//os;
colas@0
   756
                $helpText =~ s/%STOPINCLUDE%.*//os;
colas@0
   757
                $text .= $helpText;
colas@0
   758
            }
colas@0
   759
        }
colas@0
   760
        my $assetUrl = '%PUBURL%/%TWIKIWEB%/EditTablePlugin';
colas@0
   761
colas@0
   762
        # table specific script
colas@0
   763
        my $tableNr = $query->param('ettablenr');
colas@0
   764
        &TWiki::Plugins::EditTablePlugin::addEditModeHeadersToHead( $tableNr,
colas@0
   765
            $assetUrl );
colas@0
   766
    }
colas@0
   767
    else {
colas@0
   768
        $params{editbutton} |= '';
colas@0
   769
colas@0
   770
        # View mode
colas@0
   771
        if ( $params{editbutton} eq "hide" ) {
colas@0
   772
colas@0
   773
            # do nothing, button assumed to be in a cell
colas@0
   774
        }
colas@0
   775
        else {
colas@0
   776
colas@0
   777
            # Add edit button to end of table
colas@0
   778
            $text .=
colas@0
   779
              $preSp . viewEditCell("editbutton, 1, $params{'editbutton'}");
colas@0
   780
        }
colas@0
   781
    }
colas@0
   782
    $text .= "$preSp</form>\n";
colas@0
   783
    $text .= "</div><!-- /editTable -->";
colas@0
   784
    $text .= "$preSp</noautolink>\n" if $doEdit;
colas@0
   785
    $text .= "\n";
colas@0
   786
    return $text;
colas@0
   787
}
colas@0
   788
colas@0
   789
=pod
colas@0
   790
colas@0
   791
=cut
colas@0
   792
colas@0
   793
sub parseEditCellFormat {
colas@0
   794
    $_[1] = TWiki::Func::extractNameValuePair( $_[0] );
colas@0
   795
    return '';
colas@0
   796
}
colas@0
   797
colas@0
   798
=pod
colas@0
   799
colas@0
   800
=cut
colas@0
   801
colas@0
   802
sub viewEditCell {
colas@0
   803
    my ($theAttr) = @_;
colas@0
   804
    $theAttr = TWiki::Func::extractNameValuePair($theAttr);
colas@0
   805
    return '' unless ( $theAttr =~ /^editbutton/ );
colas@0
   806
colas@0
   807
    $params{editbutton} = 'hide'
colas@0
   808
      unless ( $params{editbutton} );    # Hide below table edit button
colas@0
   809
colas@0
   810
    my @bits = split( /,\s*/, $theAttr );
colas@0
   811
    my $value = '';
colas@0
   812
    $value = $bits[2] if ( @bits > 2 );
colas@0
   813
    my $img = '';
colas@0
   814
    $img = $bits[3] if ( @bits > 3 );
colas@0
   815
colas@0
   816
    unless ($value) {
colas@0
   817
        $value = $prefEDIT_BUTTON || '';
colas@0
   818
        $img = '';
colas@0
   819
        if ( $value =~ s/(.+),\s*(.+)/$1/o ) {
colas@0
   820
            $img = $2;
colas@0
   821
            $img =~ s|%ATTACHURL%|%PUBURL%/%TWIKIWEB%/EditTablePlugin|o;
colas@0
   822
            $img =~ s|%WEB%|%TWIKIWEB%|o;
colas@0
   823
        }
colas@0
   824
    }
colas@0
   825
    if ($img) {
colas@0
   826
        return
colas@0
   827
"<input class=\"editTableEditImageButton\" type=\"image\" src=\"$img\" alt=\"$value\" /> $warningMessage";
colas@0
   828
    }
colas@0
   829
    else {
colas@0
   830
        return
colas@0
   831
"<input class=\"twikiButton editTableEditButton\" type=\"submit\" value=\"$value\" /> $warningMessage";
colas@0
   832
    }
colas@0
   833
}
colas@0
   834
colas@0
   835
=pod
colas@0
   836
colas@0
   837
=cut
colas@0
   838
colas@0
   839
sub saveEditCellFormat {
colas@0
   840
    my ( $theFormat, $theName ) = @_;
colas@0
   841
    return '' unless ($theFormat);
colas@0
   842
    $theName =~ s/cell/format/;
colas@0
   843
    return hiddenField( '', $theName, $theFormat, '' );
colas@0
   844
}
colas@0
   845
colas@0
   846
=pod
colas@0
   847
colas@0
   848
digestedCellValue: properly handle labels whose rows may have been moved around by javascript, and therefore no longer correspond to the raw saved table text.
colas@0
   849
colas@0
   850
=cut
colas@0
   851
colas@0
   852
sub inputElement {
colas@0
   853
    my ( $theTableNr, $theRowNr, $theCol, $theName, $theValue,
colas@0
   854
        $digestedCellValue, $theWeb, $theTopic )
colas@0
   855
      = @_;
colas@0
   856
colas@0
   857
    my $rawValue = $theValue;
colas@0
   858
    my $text     = '';
colas@0
   859
    my $i        = @format - 1;
colas@0
   860
    $i = $theCol if ( $theCol < $i );
colas@0
   861
colas@0
   862
    my @bits         = split( /,\s*/, $format[$i] );
colas@0
   863
    my @bitsExpanded = split( /,\s*/, $formatExpanded[$i] );
colas@0
   864
colas@0
   865
    my $cellFormat = '';
colas@0
   866
    $theValue =~
colas@0
   867
      s/\s*%EDITCELL{(.*?)}%/&parseEditCellFormat( $1, $cellFormat )/eo;
colas@0
   868
colas@0
   869
    # If cell is empty we remove the space to not annoy the user when
colas@0
   870
    # he needs to add text to empty cell.
colas@0
   871
    $theValue = '' if ( $theValue eq ' ' );
colas@0
   872
    
colas@0
   873
    if ($cellFormat) {
colas@0
   874
        my @aFormat = parseFormat( $cellFormat, $theTopic, $theWeb, 0 );
colas@0
   875
        @bits = split( /,\s*/, $aFormat[0] );
colas@0
   876
        @aFormat = parseFormat( $cellFormat, $theTopic, $theWeb, 1 );
colas@0
   877
        @bitsExpanded = split( /,\s*/, $aFormat[0] );
colas@0
   878
    }
colas@0
   879
colas@0
   880
    my $type = 'text';
colas@0
   881
    $type = $bits[0] if @bits > 0;
colas@0
   882
colas@0
   883
    # a table header is considered a label if read only header flag set
colas@0
   884
    $type = 'label'
colas@0
   885
      if ( ( $params{'headerislabel'} ) && ( $theValue =~ /^\s*\*.*\*\s*$/ ) );
colas@0
   886
    $type = 'label' if ( $type eq 'editbutton' );    # Hide [Edit table] button
colas@0
   887
    my $size = 0;
colas@0
   888
    $size = $bits[1] if @bits > 1;
colas@0
   889
    my $val         = '';
colas@0
   890
    my $valExpanded = '';
colas@0
   891
    my $sel         = '';
colas@0
   892
    if ( $type eq 'select' ) {
colas@0
   893
        my $expandedValue =
colas@0
   894
          TWiki::Func::expandCommonVariables( $theValue, $theTopic, $theWeb );
colas@0
   895
        $size = 1 if $size < 1;
colas@0
   896
        $text =
colas@0
   897
          "<select class=\"twikiSelect\" name=\"$theName\" size=\"$size\">";
colas@0
   898
        $i = 2;
colas@0
   899
        while ( $i < @bits ) {
colas@0
   900
            $val         = $bits[$i]         || '';
colas@0
   901
            $valExpanded = $bitsExpanded[$i] || '';
colas@0
   902
            $expandedValue =~ s/^\s+//;
colas@0
   903
            $expandedValue =~ s/\s+$//;
colas@0
   904
            $valExpanded   =~ s/^\s+//;
colas@0
   905
            $valExpanded   =~ s/\s+$//;
colas@0
   906
colas@0
   907
            if ( $valExpanded eq $expandedValue ) {
colas@0
   908
                $text .= " <option selected=\"selected\">$val</option>";
colas@0
   909
            }
colas@0
   910
            else {
colas@0
   911
                $text .= " <option>$val</option>";
colas@0
   912
            }
colas@0
   913
            $i++;
colas@0
   914
        }
colas@0
   915
        $text .= "</select>";
colas@0
   916
        $text .= saveEditCellFormat( $cellFormat, $theName );
colas@0
   917
colas@0
   918
    }
colas@0
   919
    elsif ( $type eq "radio" ) {
colas@0
   920
        my $expandedValue =
colas@0
   921
          &TWiki::Func::expandCommonVariables( $theValue, $theTopic, $theWeb );
colas@0
   922
        $size = 1 if $size < 1;
colas@0
   923
        my $elements = ( @bits - 2 );
colas@0
   924
        my $lines    = $elements / $size;
colas@0
   925
        $lines = ( $lines == int($lines) ) ? $lines : int( $lines + 1 );
colas@0
   926
        $text .= "<table class=\"editTableInnerTable\"><tr><td valign=\"top\">"
colas@0
   927
          if ( $lines > 1 );
colas@0
   928
        $i = 2;
colas@0
   929
        while ( $i < @bits ) {
colas@0
   930
            $val         = $bits[$i]         || "";
colas@0
   931
            $valExpanded = $bitsExpanded[$i] || "";
colas@0
   932
            $expandedValue =~ s/^\s+//;
colas@0
   933
            $expandedValue =~ s/\s+$//;
colas@0
   934
            $valExpanded   =~ s/^\s+//;
colas@0
   935
            $valExpanded   =~ s/\s+$//;
colas@0
   936
            $text .= "<input type=\"radio\" name=\"$theName\" value=\"$val\"";
colas@0
   937
colas@0
   938
            # make space to expand variables
colas@0
   939
            $val = addSpaceToBothSides($val);
colas@0
   940
            $text .= " checked=\"checked\""
colas@0
   941
              if ( $valExpanded eq $expandedValue );
colas@0
   942
            $text .= " />$val";
colas@0
   943
            if ( $lines > 1 ) {
colas@0
   944
colas@0
   945
                if ( ( $i - 1 ) % $lines ) {
colas@0
   946
                    $text .= "<br />";
colas@0
   947
                }
colas@0
   948
                elsif ( $i - 1 < $elements ) {
colas@0
   949
                    $text .= "</td><td valign=\"top\">";
colas@0
   950
                }
colas@0
   951
            }
colas@0
   952
            $i++;
colas@0
   953
        }
colas@0
   954
        $text .= "</td></tr></table>" if ( $lines > 1 );
colas@0
   955
        $text .= saveEditCellFormat( $cellFormat, $theName );
colas@0
   956
colas@0
   957
    }
colas@0
   958
    elsif ( $type eq "checkbox" ) {
colas@0
   959
        my $expandedValue =
colas@0
   960
          &TWiki::Func::expandCommonVariables( $theValue, $theTopic, $theWeb );
colas@0
   961
        $size = 1 if $size < 1;
colas@0
   962
        my $elements = ( @bits - 2 );
colas@0
   963
        my $lines    = $elements / $size;
colas@0
   964
        my $names    = "Chkbx:";
colas@0
   965
        $lines = ( $lines == int($lines) ) ? $lines : int( $lines + 1 );
colas@0
   966
        $text .= "<table class=\"editTableInnerTable\"><tr><td valign=\"top\">"
colas@0
   967
          if ( $lines > 1 );
colas@0
   968
        $i = 2;
colas@0
   969
colas@0
   970
        while ( $i < @bits ) {
colas@0
   971
            $val         = $bits[$i]         || "";
colas@0
   972
            $valExpanded = $bitsExpanded[$i] || "";
colas@0
   973
            $expandedValue =~ s/^\s+//;
colas@0
   974
            $expandedValue =~ s/\s+$//;
colas@0
   975
            $valExpanded   =~ s/^\s+//;
colas@0
   976
            $valExpanded   =~ s/\s+$//;
colas@0
   977
            $names .= " ${theName}x$i";
colas@0
   978
            $text .=
colas@0
   979
              " <input type=\"checkbox\" name=\"${theName}x$i\" value=\"$val\"";
colas@0
   980
colas@0
   981
            $val = addSpaceToBothSides($val);
colas@0
   982
colas@0
   983
            $text .= " checked=\"checked\""
colas@0
   984
              if ( $expandedValue =~ /(^|\s*,\s*)\Q$valExpanded\E(\s*,\s*|$)/ );
colas@0
   985
            $text .= " />$val";
colas@0
   986
colas@0
   987
            if ( $lines > 1 ) {
colas@0
   988
                if ( ( $i - 1 ) % $lines ) {
colas@0
   989
                    $text .= "<br />";
colas@0
   990
                }
colas@0
   991
                elsif ( $i - 1 < $elements ) {
colas@0
   992
                    $text .= "</td><td valign=\"top\">";
colas@0
   993
                }
colas@0
   994
            }
colas@0
   995
            $i++;
colas@0
   996
        }
colas@0
   997
        $text .= "</td></tr></table>" if ( $lines > 1 );
colas@0
   998
        $text .= hiddenField( $preSp, $theName, $names );
colas@0
   999
        $text .= saveEditCellFormat( $cellFormat, $theName, "\n" );
colas@0
  1000
colas@0
  1001
    }
colas@0
  1002
    elsif ( $type eq 'row' ) {
colas@0
  1003
        $size = $size + $theRowNr;
colas@0
  1004
        $text =
colas@0
  1005
            "<span class=\"et_rowlabel\">"
colas@0
  1006
          . hiddenField( $size, $theName, $size )
colas@0
  1007
          . "</span>";
colas@0
  1008
        $text .= saveEditCellFormat( $cellFormat, $theName );
colas@0
  1009
colas@0
  1010
    }
colas@0
  1011
    elsif ( $type eq 'label' ) {
colas@0
  1012
colas@0
  1013
        # show label text as is, and add a hidden field with value
colas@0
  1014
        my $isHeader = 0;
colas@0
  1015
        $isHeader = 1 if ( $theValue =~ s/^\s*\*(.*)\*\s*$/$1/o );
colas@0
  1016
        $text = $theValue;
colas@0
  1017
colas@0
  1018
        # To optimize things, only in the case where a read-only column is
colas@0
  1019
        # being processed (inside of this unless() statement) do we actually
colas@0
  1020
        # go out and read the original topic.  Thus the reason for the
colas@0
  1021
        # following unless() so we only read the topic the first time through.
colas@0
  1022
        unless ( defined $table and $digestedCellValue ) {
colas@0
  1023
colas@0
  1024
            # To deal with the situation where TWiki variables, like
colas@0
  1025
            # %CALC%, have already been processed and end up getting saved
colas@0
  1026
            # in the table that way (processed), we need to read in the
colas@0
  1027
            # topic page in raw format
colas@0
  1028
            my $topicContents = TWiki::Func::readTopicText(
colas@0
  1029
                $TWiki::Plugins::EditTablePlugin::web,
colas@0
  1030
                $TWiki::Plugins::EditTablePlugin::topic
colas@0
  1031
            );
colas@0
  1032
            $table = TWiki::Plugins::Table->new($topicContents);
colas@0
  1033
        }
colas@0
  1034
        my $cell =
colas@0
  1035
            $digestedCellValue
colas@0
  1036
          ? $table->getCell( $theTableNr, $theRowNr - 1, $theCol )
colas@0
  1037
          : $rawValue;
colas@0
  1038
        $theValue = $cell if ( defined $cell );    # original value from file
colas@0
  1039
        $theValue = TWiki::Plugins::EditTablePlugin::encodeValue($theValue)
colas@0
  1040
          unless ( $theValue eq '' );
colas@0
  1041
        $theValue = "\*$theValue\*" if ( $isHeader and $digestedCellValue );
colas@0
  1042
        $text .= hiddenField( $preSp, $theName, $theValue );
colas@0
  1043
        $text = "\*$text\*" if ($isHeader);
colas@0
  1044
colas@0
  1045
    }
colas@0
  1046
    elsif ( $type eq 'textarea' ) {
colas@0
  1047
        my ( $rows, $cols ) = split( /x/, $size );
colas@0
  1048
colas@0
  1049
        $rows |= 3  if !defined $rows;
colas@0
  1050
        $cols |= 30 if !defined $cols;
colas@0
  1051
        $theValue = TWiki::Plugins::EditTablePlugin::encodeValue($theValue)
colas@0
  1052
          unless ( $theValue eq '' );
colas@0
  1053
        $text .=
colas@0
  1054
"<textarea class=\"twikiTextarea editTableTextarea\" rows=\"$rows\" cols=\"$cols\" name=\"$theName\">$theValue</textarea>";
colas@0
  1055
        $text .= saveEditCellFormat( $cellFormat, $theName );
colas@0
  1056
colas@0
  1057
    }
colas@0
  1058
    elsif ( $type eq 'date' ) {
colas@0
  1059
        my $ifFormat = '';
colas@0
  1060
        $ifFormat = $bits[3] if ( @bits > 3 );
colas@0
  1061
        $ifFormat ||= $TWiki::cfg{JSCalendarContrib}{format} || '%e %B %Y';
colas@0
  1062
        $size = 10 if ( !$size || $size < 1 );
colas@0
  1063
        $theValue = TWiki::Plugins::EditTablePlugin::encodeValue($theValue)
colas@0
  1064
          unless ( $theValue eq '' );
colas@0
  1065
        $text .= CGI::textfield(
colas@0
  1066
            {
colas@0
  1067
                name     => $theName,
colas@0
  1068
                class    => 'twikiInputField editTableInput',
colas@0
  1069
                id       => 'id' . $theName,
colas@0
  1070
                size     => $size,
colas@0
  1071
                value    => $theValue,
colas@0
  1072
                override => 1
colas@0
  1073
            }
colas@0
  1074
        );
colas@0
  1075
        $text .= saveEditCellFormat( $cellFormat, $theName );
colas@0
  1076
        eval 'use TWiki::Contrib::JSCalendarContrib';
colas@0
  1077
colas@0
  1078
        unless ($@) {
colas@0
  1079
            $text .= '<span class="twikiMakeVisible">';
colas@0
  1080
            $text .= CGI::image_button(
colas@0
  1081
                -class   => 'editTableCalendarButton',
colas@0
  1082
                -name    => 'calendar',
colas@0
  1083
                -onclick => "return showCalendar('id$theName','$ifFormat')",
colas@0
  1084
                -src     => TWiki::Func::getPubUrlPath() . '/'
colas@0
  1085
                  . TWiki::Func::getTwikiWebname()
colas@0
  1086
                  . '/JSCalendarContrib/img.gif',
colas@0
  1087
                -alt   => 'Calendar',
colas@0
  1088
                -align => 'middle'
colas@0
  1089
            );
colas@0
  1090
            $text .= '</span>';
colas@0
  1091
        }
colas@0
  1092
        $query->{'jscalendar'} = 1;
colas@0
  1093
    }
colas@0
  1094
    else {    #  if( $type eq 'text')
colas@0
  1095
        $size = $DEFAULT_FIELD_SIZE if $size < 1;
colas@0
  1096
        $theValue = TWiki::Plugins::EditTablePlugin::encodeValue($theValue)
colas@0
  1097
          unless ( $theValue eq '' );
colas@0
  1098
        $text =
colas@0
  1099
"<input class=\"twikiInputField editTableInput\" type=\"text\" name=\"$theName\" size=\"$size\" value=\"$theValue\" />";
colas@0
  1100
        $text .= saveEditCellFormat( $cellFormat, $theName );
colas@0
  1101
    }
colas@0
  1102
colas@0
  1103
    if ( $type ne 'textarea' ) {
colas@0
  1104
        $text =~
colas@0
  1105
          s/&#10;/<br \/>/go;    # change unicode linebreak character to <br />
colas@0
  1106
    }
colas@0
  1107
    return $text;
colas@0
  1108
}
colas@0
  1109
colas@0
  1110
=pod
colas@0
  1111
colas@0
  1112
=cut
colas@0
  1113
colas@0
  1114
sub handleTableRow {
colas@0
  1115
    my (
colas@0
  1116
        $thePre, $theRow, $theTableNr, $isNewRow, $theRowNr,
colas@0
  1117
        $doEdit, $doSave, $theWeb,     $theTopic
colas@0
  1118
    ) = @_;
colas@0
  1119
    $thePre |= '';
colas@0
  1120
    my $text = "$thePre\|";
colas@0
  1121
    if ($doEdit) {
colas@0
  1122
        $theRow =~ s/\|\s*$//o;
colas@0
  1123
        my $rowID = $query->param("etrow_id$theRowNr");
colas@0
  1124
        $rowID = $theRowNr if !defined $rowID;
colas@0
  1125
        my @cells = split( /\|/, $theRow );
colas@0
  1126
        my $tmp = @cells;
colas@0
  1127
        $nrCols = $tmp if ( $tmp > $nrCols );    # expand number of cols
colas@0
  1128
        my $val         = '';
colas@0
  1129
        my $cellFormat  = '';
colas@0
  1130
        my $cell        = '';
colas@0
  1131
        my $digested    = 0;
colas@0
  1132
        my $cellDefined = 0;
colas@0
  1133
        my $col         = 0;
colas@0
  1134
colas@0
  1135
        while ( $col < $nrCols ) {
colas@0
  1136
            $col += 1;
colas@0
  1137
            $cellDefined = 0;
colas@0
  1138
            $val = $isNewRow ? undef : $query->param("etcell${rowID}x$col");
colas@0
  1139
            if ( $val && $val =~ /^Chkbx: (etcell.*)/ ) {
colas@0
  1140
colas@0
  1141
      # Multiple checkboxes, val has format "Chkbx: etcell4x2x2 etcell4x2x3 ..."
colas@0
  1142
                my $chkBoxeNames = $1;
colas@0
  1143
                my $chkBoxVals   = "";
colas@0
  1144
                foreach ( split( /\s/, $chkBoxeNames ) ) {
colas@0
  1145
                    $val = $query->param($_);
colas@0
  1146
colas@0
  1147
                    #$chkBoxVals .= "$val," if ( defined $val );
colas@0
  1148
                    if ( defined $val ) {
colas@0
  1149
colas@0
  1150
                        # make space to expand variables
colas@0
  1151
                        $val = addSpaceToBothSides($val);
colas@0
  1152
                        $chkBoxVals .= $val . ',';
colas@0
  1153
                    }
colas@0
  1154
                }
colas@0
  1155
                $chkBoxVals =~ s/,\s*$//;
colas@0
  1156
                $val = $chkBoxVals;
colas@0
  1157
            }
colas@0
  1158
            $cellFormat = $query->param("etformat${rowID}x$col");
colas@0
  1159
            $val .= " %EDITCELL{$cellFormat}%" if ($cellFormat);
colas@0
  1160
            if ( defined $val ) {
colas@0
  1161
colas@0
  1162
                # change any new line character sequences to <br />
colas@0
  1163
                $val =~ s/[\n\r]{2,}?/%BR%/gos;
colas@0
  1164
colas@0
  1165
                # escape "|" to HTML entity
colas@0
  1166
                $val =~ s/\|/\&\#124;/gos;
colas@0
  1167
                $cellDefined = 1;
colas@0
  1168
colas@0
  1169
                # Expand %-vars
colas@0
  1170
                $cell = $val;
colas@0
  1171
            }
colas@0
  1172
            elsif ( $col <= @cells ) {
colas@0
  1173
                $cell = $cells[ $col - 1 ];
colas@0
  1174
                $digested = 1;    # Flag that we are using non-raw cell text.
colas@0
  1175
                $cellDefined = 1 if ( length($cell) > 0 );
colas@0
  1176
                $cell =~ s/^\s*(.+?)\s*$/$1/o
colas@0
  1177
                  ; # remove spaces around content, but do not void a cell with just spaces
colas@0
  1178
            }
colas@0
  1179
            else {
colas@0
  1180
                $cell = '';
colas@0
  1181
            }
colas@0
  1182
colas@0
  1183
            if ( ( $theRowNr <= 1 ) && ( $params{'header'} ) ) {
colas@0
  1184
                unless ($cell) {
colas@0
  1185
                    if ( $params{'header'} =~ /^on$/i ) {
colas@0
  1186
                        if (   ( @format >= $col )
colas@0
  1187
                            && ( $format[ $col - 1 ] =~ /(.*?)\,/ ) )
colas@0
  1188
                        {
colas@0
  1189
                            $cell = $1;
colas@0
  1190
                        }
colas@0
  1191
                        $cell = 'text' unless $cell;
colas@0
  1192
                        $cell = "*$cell*";
colas@0
  1193
                    }
colas@0
  1194
                    else {
colas@0
  1195
                        my @hCells = split( /\|/, $params{'header'} );
colas@0
  1196
                        $cell = $hCells[ $col - 1 ] if ( @hCells >= $col );
colas@0
  1197
                        $cell = "*text*" unless $cell;
colas@0
  1198
                    }
colas@0
  1199
                }
colas@0
  1200
                $cell = addSpaceToBothSides($cell);
colas@0
  1201
                $text .= "$cell\|";
colas@0
  1202
            }
colas@0
  1203
            elsif ($doSave) {
colas@0
  1204
                $cell = addSpaceToBothSides($cell);
colas@0
  1205
                
colas@0
  1206
                # Item5217 Avoid that deleting content of cell creates unwanted span
colas@0
  1207
                $cell = ' ' if $cell eq '';
colas@0
  1208
                
colas@0
  1209
                $text .= "$cell\|";
colas@0
  1210
            }
colas@0
  1211
            else {
colas@0
  1212
                if (
colas@0
  1213
                       ( !$cellDefined )
colas@0
  1214
                    && ( @format >= $col )
colas@0
  1215
                    && ( $format[ $col - 1 ] =~
colas@0
  1216
                        /^\s*(.*?)\,\s*(.*?)\,\s*(.*?)\s*$/ )
colas@0
  1217
                  )
colas@0
  1218
                {
colas@0
  1219
colas@0
  1220
                    # default value of "| text, 20, a, b, c |" cell is "a, b, c"
colas@0
  1221
                    # default value of '| select, 1, a, b, c |' cell is "a"
colas@0
  1222
                    $val  = $1;    # type
colas@0
  1223
                    $cell = $3;
colas@0
  1224
                    $cell = ''
colas@0
  1225
                      unless ( defined $cell && $cell ne '' )
colas@0
  1226
                      ;            # Proper handling of '0'
colas@0
  1227
                    $cell =~ s/\,.*$//o
colas@0
  1228
                      if ( $val eq 'select' || $val eq 'date' );
colas@0
  1229
                }
colas@0
  1230
                my $element = '';
colas@0
  1231
                $element =
colas@0
  1232
                  inputElement( $theTableNr, $theRowNr, $col - 1,
colas@0
  1233
                    "etcell${theRowNr}x$col", $cell, $digested, $theWeb,
colas@0
  1234
                    $theTopic );
colas@0
  1235
                $element = " $element \|";
colas@0
  1236
                $text .= $element;
colas@0
  1237
            }
colas@0
  1238
        }
colas@0
  1239
    }
colas@0
  1240
    else {
colas@0
  1241
        $theRow =~ s/%EDITCELL{(.*?)}%/viewEditCell($1)/geo;
colas@0
  1242
        $text .= $theRow;
colas@0
  1243
    }
colas@0
  1244
colas@0
  1245
    # render final value in view mode (not edit or save)
colas@0
  1246
    TWiki::Plugins::EditTablePlugin::decodeFormatTokens($text)
colas@0
  1247
      if ( !$doSave && !$doEdit );
colas@0
  1248
colas@0
  1249
    # put one space before linebreak (but not more than one)
colas@0
  1250
    # so TML can get expanded
colas@0
  1251
    $text =~ s/\s*<br \/>/ <br \/>/go;
colas@0
  1252
    return $text;
colas@0
  1253
}
colas@0
  1254
colas@0
  1255
=pod
colas@0
  1256
colas@0
  1257
Add one space to both sides of the text to allow TML expansion.
colas@0
  1258
Convert multiple (existing) spaces to one space.
colas@0
  1259
colas@0
  1260
=cut
colas@0
  1261
colas@0
  1262
sub addSpaceToBothSides {
colas@0
  1263
    my ($text) = @_;
colas@0
  1264
    return $text if $text eq '';
colas@0
  1265
colas@0
  1266
    $text = " $text ";
colas@0
  1267
    $text =~ s/^\s+/ /;    # remove extra spaces
colas@0
  1268
    $text =~ s/\s+$/ /;
colas@0
  1269
    return $text;
colas@0
  1270
}
colas@0
  1271
colas@0
  1272
=pod
colas@0
  1273
colas@0
  1274
=cut
colas@0
  1275
colas@0
  1276
sub doCancelEdit {
colas@0
  1277
    my ( $theWeb, $theTopic ) = @_;
colas@0
  1278
colas@0
  1279
    TWiki::Func::writeDebug(
colas@0
  1280
        "- EditTablePlugin::doCancelEdit( $theWeb, $theTopic )")
colas@0
  1281
      if $TWiki::Plugins::EditTablePlugin::debug;
colas@0
  1282
colas@0
  1283
    TWiki::Func::setTopicEditLock( $theWeb, $theTopic, 0 );
colas@0
  1284
colas@0
  1285
    TWiki::Func::redirectCgiQuery( $query,
colas@0
  1286
        TWiki::Func::getViewUrl( $theWeb, $theTopic ) );
colas@0
  1287
}
colas@0
  1288
colas@0
  1289
=pod
colas@0
  1290
colas@0
  1291
=cut
colas@0
  1292
colas@0
  1293
sub doEnableEdit {
colas@0
  1294
    my ( $theWeb, $theTopic, $doCheckIfLocked ) = @_;
colas@0
  1295
colas@0
  1296
    TWiki::Func::writeDebug(
colas@0
  1297
        "- EditTablePlugin::doEnableEdit( $theWeb, $theTopic )")
colas@0
  1298
      if $TWiki::Plugins::EditTablePlugin::debug;
colas@0
  1299
colas@0
  1300
    my $wikiUserName = TWiki::Func::getWikiName();
colas@0
  1301
    if (
colas@0
  1302
        !TWiki::Func::checkAccessPermission(
colas@0
  1303
            'change', $wikiUserName, undef, $theTopic, $theWeb
colas@0
  1304
        )
colas@0
  1305
      )
colas@0
  1306
    {
colas@0
  1307
colas@0
  1308
        # user has no permission to change the topic
colas@0
  1309
        throw TWiki::OopsException(
colas@0
  1310
            'accessdenied',
colas@0
  1311
            def    => 'topic_access',
colas@0
  1312
            web    => $theWeb,
colas@0
  1313
            topic  => $theTopic,
colas@0
  1314
            params => [ 'change', 'denied' ]
colas@0
  1315
        );
colas@0
  1316
    }
colas@0
  1317
colas@0
  1318
    my $breakLock = $query->param('breaklock') || '';
colas@0
  1319
    unless ($breakLock) {
colas@0
  1320
        my ( $oopsUrl, $lockUser ) =
colas@0
  1321
          TWiki::Func::checkTopicEditLock( $theWeb, $theTopic, 'view' );
colas@0
  1322
        if ($oopsUrl) {
colas@0
  1323
            my $loginUser = TWiki::Func::wikiToUserName($wikiUserName);
colas@0
  1324
            if ( $lockUser ne $loginUser ) {
colas@0
  1325
colas@0
  1326
                # change the default oopsleaseconflict url
colas@0
  1327
                # use viewauth instead of view
colas@0
  1328
                $oopsUrl =~ s/param4=view/param4=viewauth/;
colas@0
  1329
colas@0
  1330
                # add info of the edited table
colas@0
  1331
                my $params = '';
colas@0
  1332
                $query = TWiki::Func::getCgiQuery();
colas@0
  1333
                $params .= ';ettablenr=' . $query->param('ettablenr');
colas@0
  1334
                $params .= ';etedit=on';
colas@0
  1335
                $oopsUrl =~ s/($|#\w*)/$params/;
colas@0
  1336
colas@0
  1337
                # warn user that other person is editing this topic
colas@0
  1338
                TWiki::Func::redirectCgiQuery( $query, $oopsUrl );
colas@0
  1339
                return 0;
colas@0
  1340
            }
colas@0
  1341
        }
colas@0
  1342
    }
colas@0
  1343
colas@0
  1344
    # We are allowed to edit
colas@0
  1345
    TWiki::Func::setTopicEditLock( $theWeb, $theTopic, 1 );
colas@0
  1346
colas@0
  1347
    return 1;
colas@0
  1348
}
colas@0
  1349
colas@0
  1350
package TWiki::Plugins::Table;
colas@0
  1351
colas@0
  1352
use vars qw(
colas@0
  1353
  %regex
colas@0
  1354
);
colas@0
  1355
$regex{edit_table_plugin} = '%EDITTABLE{(.*?)}%';
colas@0
  1356
colas@0
  1357
=pod
colas@0
  1358
colas@0
  1359
=cut
colas@0
  1360
colas@0
  1361
sub new {
colas@0
  1362
    my ( $class, $topicContents ) = @_;
colas@0
  1363
    my $this = {};
colas@0
  1364
    bless $this, $class;
colas@0
  1365
    $this->_parseOutTables($topicContents);
colas@0
  1366
    return $this;
colas@0
  1367
}
colas@0
  1368
colas@0
  1369
=pod
colas@0
  1370
colas@0
  1371
TODO: this is currently only used for label tags, so this seams a lot of overhead for such a small thing
colas@0
  1372
colas@0
  1373
The guts of this routine was initially copied from SpreadSheetPlugin.pm
colas@0
  1374
and were used in the ChartPlugin Table object which this was copied from,
colas@0
  1375
but this has been modified to support the functionality needed by the
colas@0
  1376
EditTablePlugin.  One major change is to only count and save tables
colas@0
  1377
following an %EDITTABLE{.*}% tag.
colas@0
  1378
colas@0
  1379
This routine basically returns an array of hashes where each hash
colas@0
  1380
contains the information for a single table.  Thus the first hash in the
colas@0
  1381
array represents the first table found on the topic page, the second hash
colas@0
  1382
in the array represents the second table found on the topic page, etc.
colas@0
  1383
colas@0
  1384
=cut
colas@0
  1385
colas@0
  1386
sub _parseOutTables {
colas@0
  1387
    my ( $this, $topic ) = @_;
colas@0
  1388
    my $tableNum = 1;    # Table number (only count tables with EDITTABLE tag)
colas@0
  1389
    my @tableMatrix;     # Currently parsed table.
colas@0
  1390
colas@0
  1391
    my $inEditTable = 0; # Flag to keep track if in an EDITTABLE table
colas@0
  1392
    my $insidePRE   = 0;
colas@0
  1393
    my $insideTABLE = 0;
colas@0
  1394
    my $line        = '';
colas@0
  1395
    my @row         = ();
colas@0
  1396
colas@0
  1397
    foreach ( split( /\n/, $topic ) ) {
colas@0
  1398
colas@0
  1399
        # change state:
colas@0
  1400
        m|<pre\b|i      && ( $insidePRE = 1 );
colas@0
  1401
        m|<verbatim\b|i && ( $insidePRE = 1 );
colas@0
  1402
        m|</pre>|i      && ( $insidePRE = 0 );
colas@0
  1403
        m|</verbatim>|i && ( $insidePRE = 0 );
colas@0
  1404
colas@0
  1405
        if ( !$insidePRE ) {
colas@0
  1406
            $inEditTable = 1 if (/$regex{edit_table_plugin}/);
colas@0
  1407
            if ($inEditTable) {
colas@0
  1408
                if (/^\s*\|.*\|\s*$/) {
colas@0
  1409
colas@0
  1410
                    # inside | table |
colas@0
  1411
                    $insideTABLE = 1;
colas@0
  1412
                    $line        = $_;
colas@0
  1413
                    $line =~ s/^(\s*\|)(.*)\|\s*$/$2/o;    # Remove starting '|'
colas@0
  1414
                    @row = split( /\|/o, $line, -1 );
colas@0
  1415
                    _trim( \@row );
colas@0
  1416
                    push( @tableMatrix, [@row] );
colas@0
  1417
colas@0
  1418
                }
colas@0
  1419
                else {
colas@0
  1420
colas@0
  1421
                    # outside | table |
colas@0
  1422
                    if ($insideTABLE) {
colas@0
  1423
colas@0
  1424
                        # We were inside a table and are now outside of it so
colas@0
  1425
                        # save the table info into the Table object.
colas@0
  1426
                        $insideTABLE = 0;
colas@0
  1427
                        $inEditTable = 0;
colas@0
  1428
                        if ( @tableMatrix != 0 ) {
colas@0
  1429
colas@0
  1430
                            # Save the table via its table number
colas@0
  1431
                            $$this{"TABLE_$tableNum"} = [@tableMatrix];
colas@0
  1432
                            $tableNum++;
colas@0
  1433
                        }
colas@0
  1434
                        undef @tableMatrix;    # reset table matrix
colas@0
  1435
                    }
colas@0
  1436
                }
colas@0
  1437
            }
colas@0
  1438
        }
colas@0
  1439
    }
colas@0
  1440
    $$this{NUM_TABLES} = $tableNum;
colas@0
  1441
}
colas@0
  1442
colas@0
  1443
=pod
colas@0
  1444
colas@0
  1445
Trim any leading and trailing white space and/or '*'.
colas@0
  1446
colas@0
  1447
=cut
colas@0
  1448
colas@0
  1449
sub _trim {
colas@0
  1450
    my ($totrim) = @_;
colas@0
  1451
    for my $element (@$totrim) {
colas@0
  1452
        $element =~ s/^[\s\*]+//;    # Strip off leading white
colas@0
  1453
        $element =~ s/[\s\*]+$//;    # Strip off trailing white
colas@0
  1454
    }
colas@0
  1455
}
colas@0
  1456
colas@0
  1457
=pod
colas@0
  1458
colas@0
  1459
Return the contents of the specified cell
colas@0
  1460
colas@0
  1461
=cut
colas@0
  1462
colas@0
  1463
sub getCell {
colas@0
  1464
    my ( $this, $tableNum, $row, $column ) = @_;
colas@0
  1465
colas@0
  1466
    my @selectedTable = $this->getTable($tableNum);
colas@0
  1467
    my $value         = $selectedTable[$row][$column];
colas@0
  1468
    return $value;
colas@0
  1469
}
colas@0
  1470
colas@0
  1471
=pod
colas@0
  1472
colas@0
  1473
=cut
colas@0
  1474
colas@0
  1475
sub getTable {
colas@0
  1476
    my ( $this, $tableNumber ) = @_;
colas@0
  1477
    my $table = $$this{"TABLE_$tableNumber"};
colas@0
  1478
    return @$table if defined($table);
colas@0
  1479
    return ();
colas@0
  1480
}
colas@0
  1481
colas@0
  1482
1;