~kosova/+junk/tuxfamily-twiki

« back to all changes in this revision

Viewing changes to foswiki/lib/Foswiki/Plugins/TablePlugin/Core.pm

  • Committer: James Michael DuPont
  • Date: 2009-07-18 19:58:49 UTC
  • Revision ID: jamesmikedupont@gmail.com-20090718195849-vgbmaht2ys791uo2
added foswiki

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Plugin for Foswiki - The Free and Open Source Wiki, http://foswiki.org/
 
2
#
 
3
# Copyright (C) 2008 Foswiki Contributors.
 
4
# Copyright (C) 2005-2006 TWiki Contributors
 
5
# Copyright (C) 2001-2004 Peter Thoeny, peter@thoeny.org
 
6
# Copyright (C) 2001-2003 John Talintyre, jet@cheerful.com
 
7
#
 
8
# This program is free software; you can redistribute it and/or
 
9
# modify it under the terms of the GNU General Public License
 
10
# as published by the Free Software Foundation; either version 2
 
11
# of the License, or (at your option) any later version. For
 
12
# more details read LICENSE in the root of this distribution.
 
13
#
 
14
# This program is distributed in the hope that it will be useful,
 
15
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
# GNU General Public License for more details, published at
 
18
# http://www.gnu.org/copyleft/gpl.html
 
19
#
 
20
# As per the GPL, removal of this notice is prohibited.
 
21
 
 
22
use strict;
 
23
 
 
24
package Foswiki::Plugins::TablePlugin::Core;
 
25
 
 
26
use Foswiki::Time;
 
27
use Error qw(:try);
 
28
 
 
29
use vars qw( $translationToken
 
30
  $insideTABLE $tableCount @curTable $sortCol $maxSortCols $requestedTable $up
 
31
  $sortTablesInText $sortAttachments $currTablePre $sortColFromUrl
 
32
  $tableWidth @columnWidths
 
33
  $tableBorder $tableFrame $tableRules $cellPadding $cellSpacing $cellBorder
 
34
  @headerAlign @dataAlign $vAlign $headerVAlign $dataVAlign
 
35
  $headerBg $headerBgSorted $headerColor $sortAllTables $twoCol @dataBg @dataBgSorted @dataColor
 
36
  $headerRows $footerRows
 
37
  $upchar $downchar $diamondchar $url
 
38
  $initSort $initDirection $currentSortDirection
 
39
  @rowspan $pluginAttrs $prefsAttrs $tableId $tableSummary $tableCaption
 
40
  $iconUrl $unsortEnabled
 
41
  %sortDirection %columnType
 
42
  %cssAttrs %defaultCssAttrs $didWriteDefaultStyle
 
43
);
 
44
 
 
45
my $PATTERN_ATTRIBUTE_SIZE = qr'([0-9]+)(px|%)*'o;
 
46
 
 
47
BEGIN {
 
48
    $translationToken = "\0";
 
49
    $currTablePre     = '';
 
50
    $upchar           = '';
 
51
    $downchar         = '';
 
52
    $diamondchar      = '';
 
53
    %sortDirection = ( 'ASCENDING', 0, 'DESCENDING', 1, 'NONE', 2 );
 
54
    %columnType = (
 
55
        'TEXT',   'text',   'DATE',      'date',
 
56
        'NUMBER', 'number', 'UNDEFINED', 'undefined'
 
57
    );
 
58
 
 
59
    # the maximum number of columns we will handle
 
60
    $maxSortCols = 10000;
 
61
    $iconUrl =
 
62
        Foswiki::Func::getPubUrlPath() . '/'
 
63
      . Foswiki::Func::getTwikiWebname()
 
64
      . '/DocumentGraphics/';
 
65
    $unsortEnabled        = 1;    # if true, table columns can be unsorted
 
66
    $didWriteDefaultStyle = 0;
 
67
    my %defaultCssAttrs = ();
 
68
 
 
69
}
 
70
 
 
71
sub _setDefaults {
 
72
    $sortAllTables  = $sortTablesInText;
 
73
    $tableBorder    = 1;
 
74
    $tableFrame     = '';
 
75
    $tableRules     = '';
 
76
    $cellSpacing    = '';
 
77
    $cellPadding    = '';
 
78
    $cellBorder     = '';
 
79
    $tableWidth     = '';
 
80
    $headerRows     = 1;
 
81
    $footerRows     = 0;
 
82
    $vAlign         = '';
 
83
    $headerVAlign   = '';
 
84
    $dataVAlign     = '';
 
85
    $headerBg       = '#6b7f93';
 
86
    $headerBgSorted = '';
 
87
    $headerColor    = '#ffffff';
 
88
    $tableId        = '';
 
89
    $tableSummary   = '';
 
90
    $tableCaption   = '';
 
91
    @columnWidths   = ();
 
92
    @headerAlign    = ();
 
93
    @dataAlign      = ();
 
94
    @dataBg         = ( '#ecf2f8', '#ffffff' );
 
95
    @dataBgSorted   = ();
 
96
    @dataColor      = ();
 
97
 
 
98
    undef $initSort;
 
99
 
 
100
    # Preferences setting
 
101
    # It seems overkill to redo this every time!
 
102
    my %pluginParams   = Foswiki::Func::extractParameters($pluginAttrs);
 
103
    my %prefsParams    = Foswiki::Func::extractParameters($prefsAttrs);
 
104
    my %combinedParams = ( %pluginParams, %prefsParams );
 
105
    _parseParameters( 1, 'default', %combinedParams );
 
106
}
 
107
 
 
108
# Table attributes defined as a Plugin setting, a preferences setting
 
109
# e.g. in WebPreferences or as a %TABLE{...}% setting
 
110
sub _parseParameters {
 
111
    my ( $useCss, $writeDefaults, %params ) = @_;
 
112
 
 
113
    return '' if !keys %params;
 
114
 
 
115
    %cssAttrs = ();
 
116
 
 
117
    my $tmp;
 
118
 
 
119
    $tmp = $params{id};
 
120
    if ( defined $tmp && $tmp ne '' && $tmp ne $tableId ) {
 
121
        $tableId = $tmp;
 
122
    }
 
123
    else {
 
124
        $tableId = 'table' . ( $tableCount + 1 );
 
125
    }
 
126
    $cssAttrs{tableId} = $tableId;
 
127
 
 
128
    # Defines which column to initially sort : ShawnBradford 20020221
 
129
    $tmp = $params{initsort};
 
130
    $initSort = $tmp if ($tmp);
 
131
 
 
132
    # Defines which direction to sort the column set by initsort :
 
133
    # ShawnBradford 20020221
 
134
    $tmp           = $params{initdirection};
 
135
    $initDirection = $sortDirection{'ASCENDING'}
 
136
      if ( defined $tmp && $tmp =~ /^down$/i );
 
137
    $initDirection = $sortDirection{'DESCENDING'}
 
138
      if ( defined $tmp && $tmp =~ /^up$/i );
 
139
 
 
140
    $tmp           = $params{sort};
 
141
    $tmp           = '0' if ( defined $tmp && $tmp =~ /^off$/oi );
 
142
    $sortAllTables = $tmp if ( defined $tmp && $tmp ne '' );
 
143
 
 
144
# If EditTablePlugin is installed and we are editing a table, the CGI
 
145
# parameter 'sort' is defined as "off" to disable all header sorting ((Item5135)
 
146
    my $cgi = Foswiki::Func::getCgiQuery();
 
147
    $tmp = $cgi->param('sort');
 
148
    if ( defined $tmp && $tmp =~ /^off$/oi ) {
 
149
        undef $sortAllTables;
 
150
    }
 
151
 
 
152
    # If EditTablePlugin is installed and we are editing a table, the
 
153
    # 'disableallsort' TABLE parameter is added to disable initsort and header
 
154
    # sorting in the table that is being edited. (Item5135)
 
155
    $tmp = $params{disableallsort};
 
156
    if ( defined $tmp && $tmp =~ /^on$/oi ) {
 
157
        undef $sortAllTables;
 
158
        undef $initSort;
 
159
    }
 
160
 
 
161
    $tmp = $params{tableborder};
 
162
    if ( defined $tmp && $tmp ne '' ) {
 
163
        $tableBorder = $tmp if $tmp ne $tableBorder;
 
164
        if (
 
165
            $useCss
 
166
            && ( !defined $defaultCssAttrs{'tableBorder'}
 
167
                || $tmp ne $defaultCssAttrs{'tableBorder'} )
 
168
          )
 
169
        {
 
170
            $cssAttrs{tableBorder} = $tableBorder;
 
171
            $defaultCssAttrs{tableBorder} = $tableBorder if $writeDefaults;
 
172
        }
 
173
    }
 
174
 
 
175
    $tmp = $params{tableframe};
 
176
    if ( defined $tmp && $tmp ne '' && $tmp ne $tableFrame ) {
 
177
        $tableFrame = $tmp;
 
178
        if (
 
179
            $useCss
 
180
            && ( !defined $defaultCssAttrs{'tableFrame'}
 
181
                || $tmp ne $defaultCssAttrs{'tableFrame'} )
 
182
          )
 
183
        {
 
184
            $cssAttrs{tableFrame} = $tableFrame;
 
185
            $defaultCssAttrs{tableFrame} = $tableFrame if $writeDefaults;
 
186
        }
 
187
    }
 
188
 
 
189
    $tmp = $params{tablerules};
 
190
    if ( defined $tmp && $tmp ne '' && $tmp ne $tableRules ) {
 
191
        $tableRules = $tmp;
 
192
        if (
 
193
            $useCss
 
194
            && ( !defined $defaultCssAttrs{'tableRules'}
 
195
                || $tmp ne $defaultCssAttrs{'tableRules'} )
 
196
          )
 
197
        {
 
198
            $cssAttrs{tableRules} = $tableRules;
 
199
            $defaultCssAttrs{tableRules} = $tableRules if $writeDefaults;
 
200
        }
 
201
    }
 
202
 
 
203
    $tmp = $params{cellpadding};
 
204
    if ( defined $tmp && $tmp ne '' && $tmp ne $cellPadding ) {
 
205
        $cellPadding = $tmp;
 
206
        if (
 
207
            $useCss
 
208
            && ( !defined $defaultCssAttrs{'cellPadding'}
 
209
                || $tmp ne $defaultCssAttrs{'cellPadding'} )
 
210
          )
 
211
        {
 
212
            $cssAttrs{cellPadding} = $cellPadding;
 
213
            $defaultCssAttrs{cellPadding} = $cellPadding if $writeDefaults;
 
214
        }
 
215
    }
 
216
 
 
217
    $tmp = $params{cellspacing};
 
218
 
 
219
    # not used in CSS
 
220
    if ( defined $tmp && $tmp ne '' && $tmp ne $cellSpacing ) {
 
221
        $cellSpacing = $tmp;
 
222
    }
 
223
 
 
224
    $tmp = $params{cellborder};
 
225
    if ( defined $tmp && $tmp ne '' && $tmp ne $cellBorder ) {
 
226
        $cellBorder = $tmp;
 
227
        if (
 
228
            $useCss
 
229
            && ( !defined $defaultCssAttrs{'cellBorder'}
 
230
                || $tmp ne $defaultCssAttrs{'cellBorder'} )
 
231
          )
 
232
        {
 
233
            $cssAttrs{cellBorder} = $cellBorder;
 
234
            $defaultCssAttrs{cellBorder} = $cellBorder if $writeDefaults;
 
235
        }
 
236
    }
 
237
 
 
238
    $tmp = $params{headeralign};
 
239
    if ( defined $tmp && $tmp ne '' ) {
 
240
        $tmp =~ s/ //go;    # remove spaces
 
241
        if ( $tmp ne join( ',', @headerAlign ) ) {
 
242
            @headerAlign = split( /,/, $tmp );
 
243
            if (
 
244
                $useCss
 
245
                && ( !defined $defaultCssAttrs{'headerAlign'}
 
246
                    || $tmp ne $defaultCssAttrs{'headerAlign'} )
 
247
              )
 
248
            {
 
249
                $cssAttrs{headerAlign}        = $tmp;    # store string
 
250
                $defaultCssAttrs{headerAlign} = $tmp
 
251
                  if $writeDefaults;                     # store string
 
252
            }
 
253
        }
 
254
    }
 
255
 
 
256
    $tmp = $params{dataalign};
 
257
    if ( defined $tmp && $tmp ne '' ) {
 
258
        $tmp =~ s/ //go;                                 # remove spaces
 
259
        if ( $tmp ne join( ',', @dataAlign ) ) {
 
260
            @dataAlign = split( /,/, $tmp );
 
261
            if (
 
262
                $useCss
 
263
                && ( !defined $defaultCssAttrs{'dataAlign'}
 
264
                    || $tmp ne $defaultCssAttrs{'dataAlign'} )
 
265
              )
 
266
            {
 
267
                $cssAttrs{dataAlign}        = $tmp;      # store string
 
268
                $defaultCssAttrs{dataAlign} = $tmp
 
269
                  if $writeDefaults;                     # store string
 
270
            }
 
271
        }
 
272
    }
 
273
 
 
274
    $tmp = $params{tablewidth};
 
275
    if ( defined $tmp && $tmp ne '' && $tmp ne $tableWidth ) {
 
276
        $tableWidth = $tmp;
 
277
        if (
 
278
            $useCss
 
279
            && ( !defined $defaultCssAttrs{'tableWidth'}
 
280
                || $tmp ne $defaultCssAttrs{'tableWidth'} )
 
281
          )
 
282
        {
 
283
            $cssAttrs{tableWidth} = $tableWidth;
 
284
            $defaultCssAttrs{tableWidth} = $tableWidth if $writeDefaults;
 
285
        }
 
286
    }
 
287
 
 
288
    $tmp = $params{columnwidths};
 
289
    if ( defined $tmp && $tmp ne '' ) {
 
290
        $tmp =~ s/ //go;    # remove spaces
 
291
        if ( $tmp ne join( ',', @columnWidths ) ) {
 
292
            @columnWidths = split( /,/, $tmp );
 
293
            if (
 
294
                $useCss
 
295
                && ( !defined $defaultCssAttrs{'columnWidths'}
 
296
                    || $tmp ne $defaultCssAttrs{'columnWidths'} )
 
297
              )
 
298
            {
 
299
                $cssAttrs{columnWidths}        = $tmp;    # store string
 
300
                $defaultCssAttrs{columnWidths} = $tmp
 
301
                  if $writeDefaults;                      # store string
 
302
            }
 
303
        }
 
304
    }
 
305
 
 
306
    $tmp = $params{headerrows};
 
307
    if ( defined $tmp && $tmp ne '' && $tmp ne $headerRows ) {
 
308
 
 
309
        # not used in CSS
 
310
        $headerRows = $tmp;
 
311
        $headerRows = 1 if ( $headerRows < 1 );
 
312
    }
 
313
 
 
314
    $tmp = $params{footerrows};
 
315
    if ( defined $tmp && $tmp ne '' && $tmp ne $footerRows ) {
 
316
 
 
317
        # not used in CSS
 
318
        $footerRows = $tmp;
 
319
    }
 
320
 
 
321
    $tmp = $params{valign};
 
322
    if ( defined $tmp && $tmp ne '' && $tmp ne $vAlign ) {
 
323
        $vAlign = $tmp if ( defined $tmp );
 
324
        if (
 
325
            $useCss
 
326
            && ( !defined $defaultCssAttrs{'vAlign'}
 
327
                || $tmp ne $defaultCssAttrs{'vAlign'} )
 
328
          )
 
329
        {
 
330
            $cssAttrs{vAlign} = $vAlign;
 
331
            $defaultCssAttrs{vAlign} = $vAlign if $writeDefaults;
 
332
        }
 
333
    }
 
334
 
 
335
    $tmp = $params{datavalign};
 
336
    if ( defined $tmp && $tmp ne '' && $tmp ne $dataVAlign ) {
 
337
        $dataVAlign = $tmp if ( defined $tmp );
 
338
        if (
 
339
            $useCss
 
340
            && ( !defined $defaultCssAttrs{'dataVAlign'}
 
341
                || $tmp ne $defaultCssAttrs{'dataVAlign'} )
 
342
          )
 
343
        {
 
344
            $cssAttrs{dataVAlign} = $dataVAlign;
 
345
            $defaultCssAttrs{dataVAlign} = $dataVAlign if $writeDefaults;
 
346
        }
 
347
    }
 
348
 
 
349
    $tmp = $params{headervalign};
 
350
    if ( defined $tmp && $tmp ne '' && $tmp ne $headerVAlign ) {
 
351
        $headerVAlign = $tmp if ( defined $tmp );
 
352
        if (
 
353
            $useCss
 
354
            && ( !defined $defaultCssAttrs{'headerVAlign'}
 
355
                || $tmp ne $defaultCssAttrs{'headerVAlign'} )
 
356
          )
 
357
        {
 
358
            $cssAttrs{headerVAlign} = $headerVAlign;
 
359
            $defaultCssAttrs{headerVAlign} = $headerVAlign if $writeDefaults;
 
360
        }
 
361
    }
 
362
 
 
363
    my $tmpheaderbg = $params{headerbg};
 
364
    if (   defined $tmpheaderbg
 
365
        && $tmpheaderbg ne ''
 
366
        && $tmpheaderbg ne $headerBg )
 
367
    {
 
368
        $headerBg = $tmpheaderbg;
 
369
        if (
 
370
            $useCss
 
371
            && ( !defined $defaultCssAttrs{'headerBg'}
 
372
                || $tmpheaderbg ne $defaultCssAttrs{'headerBg'} )
 
373
          )
 
374
        {
 
375
            $cssAttrs{headerBg} = $headerBg;
 
376
            $defaultCssAttrs{headerBg} = $headerBg if $writeDefaults;
 
377
        }
 
378
    }
 
379
 
 
380
    # only set headerbgsorted color if it is defined
 
381
    # otherwise use headerbg
 
382
    my $tmphbgsorted = $tmpheaderbg;
 
383
    $tmp = $params{headerbgsorted};
 
384
    if ( defined $tmp && $tmp ne '' ) {
 
385
        $tmphbgsorted = $tmp;
 
386
    }
 
387
 
 
388
    if (   defined $tmphbgsorted
 
389
        && $tmphbgsorted ne ''
 
390
        && $tmphbgsorted ne $headerBgSorted )
 
391
    {
 
392
        $headerBgSorted = $tmphbgsorted;
 
393
        if (
 
394
            $useCss
 
395
            && ( !defined $defaultCssAttrs{'headerBgSorted'}
 
396
                || $tmphbgsorted ne $defaultCssAttrs{'headerBgSorted'} )
 
397
          )
 
398
        {
 
399
            $cssAttrs{headerBgSorted} = $tmphbgsorted;
 
400
            $defaultCssAttrs{headerBgSorted} = $tmphbgsorted if $writeDefaults;
 
401
        }
 
402
    }
 
403
 
 
404
    $tmp = $params{headercolor};
 
405
    if ( defined $tmp && $tmp ne '' && $tmp ne $headerColor ) {
 
406
        $headerColor = $tmp;
 
407
        if (
 
408
            $useCss
 
409
            && ( !defined $defaultCssAttrs{'headerColor'}
 
410
                || $tmp ne $defaultCssAttrs{'headerColor'} )
 
411
          )
 
412
        {
 
413
            $cssAttrs{headerColor} = $headerColor;
 
414
            $defaultCssAttrs{headerColor} = $headerColor if $writeDefaults;
 
415
        }
 
416
    }
 
417
 
 
418
    my $tmpdatabg = $params{databg};
 
419
    if ( defined $tmpdatabg && $tmpdatabg ne '' ) {
 
420
        $tmpdatabg =~ s/ //go;    # remove spaces
 
421
        if ( $tmpdatabg ne join( ',', @dataBg ) ) {
 
422
            @dataBg = split( /,/, $tmpdatabg );
 
423
            if (
 
424
                $useCss
 
425
                && ( !defined $defaultCssAttrs{'dataBg'}
 
426
                    || $tmpdatabg ne $defaultCssAttrs{'dataBg'} )
 
427
              )
 
428
            {
 
429
                $cssAttrs{dataBg}        = $tmpdatabg;    # store string
 
430
                $defaultCssAttrs{dataBg} = $tmpdatabg
 
431
                  if $writeDefaults;                      # store string
 
432
            }
 
433
        }
 
434
    }
 
435
 
 
436
    # only set databgsorted color if it is defined
 
437
    # otherwise use databg
 
438
    my $tmpdatabgsorted = $tmpdatabg;
 
439
    $tmp = $params{databgsorted};
 
440
    if ( defined $tmp && $tmp ne '' ) {
 
441
        $tmpdatabgsorted = $tmp;
 
442
    }
 
443
    if ( defined $tmpdatabgsorted && $tmpdatabgsorted ne '' ) {
 
444
        $tmpdatabgsorted =~ s/ //go;    # remove spaces
 
445
        if ( $tmpdatabgsorted ne join( ',', @dataBgSorted ) ) {
 
446
            @dataBgSorted = split( /,/, $tmpdatabgsorted );
 
447
            if (
 
448
                $useCss
 
449
                && ( !defined $defaultCssAttrs{'dataBgSorted'}
 
450
                    || $tmpdatabgsorted ne $defaultCssAttrs{'dataBgSorted'} )
 
451
              )
 
452
            {
 
453
                $cssAttrs{dataBgSorted} = $tmpdatabgsorted;    # store string
 
454
                $defaultCssAttrs{dataBgSorted} = $tmpdatabgsorted
 
455
                  if $writeDefaults;                           # store string
 
456
            }
 
457
        }
 
458
    }
 
459
 
 
460
    $tmp = $params{datacolor};
 
461
    if ( defined $tmp && $tmp ne '' ) {
 
462
        $tmp =~ s/ //go;                                       # remove spaces
 
463
        if ( $tmp ne join( ',', @dataColor ) ) {
 
464
            @dataColor = split( /,/, $tmp );
 
465
            if (
 
466
                $useCss
 
467
                && ( !defined $defaultCssAttrs{'dataColor'}
 
468
                    || $tmp ne $defaultCssAttrs{'dataColor'} )
 
469
              )
 
470
            {
 
471
                $cssAttrs{dataColor}        = $tmp;            # store string
 
472
                $defaultCssAttrs{dataColor} = $tmp
 
473
                  if $writeDefaults;                           # store string
 
474
            }
 
475
        }
 
476
    }
 
477
 
 
478
    $tmp = $params{summary};
 
479
    if ( defined $tmp && $tmp ne '' && $tmp ne $tableSummary ) {
 
480
        $tableSummary = $tmp;
 
481
    }
 
482
 
 
483
    $tmp = $params{caption};
 
484
    if ( defined $tmp && $tmp ne '' && $tmp ne $tableCaption ) {
 
485
        $tableCaption = $tmp;
 
486
    }
 
487
 
 
488
    if ($writeDefaults) {
 
489
 
 
490
# just uncomment to write plugin settings as css styles ( .foswikiTable{ ... } )
 
491
#_addStylesToHead( $useCss, $writeDefaults, %defaultCssAttrs );
 
492
    }
 
493
    else {
 
494
        _addStylesToHead( $useCss, $writeDefaults, %cssAttrs );
 
495
    }
 
496
 
 
497
    return $currTablePre . '<nop>';
 
498
}
 
499
 
 
500
# Convert text to number and date if syntactically possible
 
501
sub _convertToNumberAndDate {
 
502
    my ($text) = @_;
 
503
 
 
504
    $text = _stripHtml($text);
 
505
 
 
506
    if ( $text =~ /^\s*$/ ) {
 
507
      return (0, 0);
 
508
    } 
 
509
 
 
510
    my $num;
 
511
    my $date;
 
512
    
 
513
    try {
 
514
      $date = Foswiki::Time::parseTime($text);
 
515
    } catch Error::Simple with {
 
516
      # nope, wasn't a date
 
517
    };
 
518
 
 
519
    unless ($date) {
 
520
      $date = undef;
 
521
      if ( $text =~ /^\s*([0-9]+)(\.[0-9]+)?/ ) {
 
522
 
 
523
        # for example for attachment sizes: 1.1 K
 
524
        # but also for other strings that start with a number
 
525
        my $num1 = $1 || 0;
 
526
        my $num2 = $2 || 0;
 
527
        $num = scalar("$num1$num2");
 
528
      }
 
529
      elsif ( $text =~ /^\s*[0-9]+(\.[0-9]+)?\s*$/ ) {
 
530
 
 
531
        $num = $text;
 
532
      }
 
533
    }
 
534
 
 
535
    return ( $num, $date );
 
536
}
 
537
 
 
538
sub _processTableRow {
 
539
    my ( $thePre, $theRow ) = @_;
 
540
 
 
541
    $currTablePre = $thePre || '';
 
542
    my $span = 0;
 
543
    my $l1   = 0;
 
544
    my $l2   = 0;
 
545
 
 
546
    if ( !$insideTABLE ) {
 
547
        @curTable = ();
 
548
        @rowspan  = ();
 
549
 
 
550
        $tableCount++;
 
551
        $currentSortDirection = $sortDirection{'NONE'};
 
552
 
 
553
        if (   defined $requestedTable
 
554
            && $requestedTable == $tableCount
 
555
            && defined $sortColFromUrl )
 
556
        {
 
557
            $sortCol              = $sortColFromUrl;
 
558
            $sortCol              = $maxSortCols if ( $sortCol > $maxSortCols );
 
559
            $currentSortDirection = _getCurrentSortDirection($up);
 
560
        }
 
561
        elsif ( defined $initSort ) {
 
562
            $sortCol              = $initSort - 1;
 
563
            $sortCol              = $maxSortCols if ( $sortCol > $maxSortCols );
 
564
            $currentSortDirection = _getCurrentSortDirection($initDirection);
 
565
        }
 
566
 
 
567
    }
 
568
 
 
569
    $theRow =~ s/\t/   /go;    # change tabs to space
 
570
    $theRow =~ s/\s*$//o;      # remove trailing spaces
 
571
    $theRow =~
 
572
      s/(\|\|+)/'colspan'.$translationToken.length($1)."\|"/geo;  # calc COLSPAN
 
573
    my $colCount = 0;
 
574
    my @row      = ();
 
575
    $span = 0;
 
576
    my $value = '';
 
577
 
 
578
    foreach ( split( /\|/, $theRow ) ) {
 
579
        my $attr = {};
 
580
        $span = 1;
 
581
 
 
582
        #AS 25-5-01 Fix to avoid matching also single columns
 
583
        if (s/colspan$translationToken([0-9]+)//) {
 
584
            $span = $1;
 
585
            $attr->{colspan} = $span;
 
586
        }
 
587
        s/^\s+$/ &nbsp; /o;
 
588
        ( $l1, $l2 ) = ( 0, 0 );
 
589
        if (/^(\s*).*?(\s*)$/) {
 
590
            $l1 = length($1);
 
591
            $l2 = length($2);
 
592
        }
 
593
        if ( $l1 >= 2 ) {
 
594
            if ( $l2 <= 1 ) {
 
595
                $attr->{align} = 'right';
 
596
            }
 
597
            else {
 
598
                $attr->{align} = 'center';
 
599
            }
 
600
        }
 
601
        if ( $span <= 2 ) {
 
602
            $attr->{class} =
 
603
              _appendColNumberCssClass( $attr->{class}, $colCount );
 
604
        }
 
605
        if (   defined $columnWidths[$colCount]
 
606
            && $columnWidths[$colCount]
 
607
            && $span <= 2 )
 
608
        {
 
609
 
 
610
            # html attribute
 
611
            $attr->{width} = $columnWidths[$colCount];
 
612
        }
 
613
 
 
614
        if (/^(\s|<[^>]*>)*\^(\s|<[^>]*>)*$/) {    # row span above
 
615
            $rowspan[$colCount]++;
 
616
            push @row, { text => $value, type => 'Y' };
 
617
        }
 
618
        else {
 
619
            for ( my $col = $colCount ; $col < ( $colCount + $span ) ; $col++ )
 
620
            {
 
621
                if ( defined( $rowspan[$col] ) && $rowspan[$col] ) {
 
622
                    my $nRows = scalar(@curTable);
 
623
                    my $rspan = $rowspan[$col] + 1;
 
624
                    if ( $rspan > 1 ) {
 
625
                        $curTable[ $nRows - $rspan ][$col]->{attrs}->{rowspan} =
 
626
                          $rspan;
 
627
                    }
 
628
                    undef( $rowspan[$col] );
 
629
                }
 
630
            }
 
631
 
 
632
            if (
 
633
                (
 
634
                    (
 
635
                        defined $requestedTable
 
636
                        && $requestedTable == $tableCount
 
637
                    )
 
638
                    || defined $initSort
 
639
                )
 
640
                && defined $sortCol
 
641
                && $colCount == $sortCol
 
642
              )
 
643
            {
 
644
 
 
645
                # CSS class name
 
646
                if ( $currentSortDirection == $sortDirection{'ASCENDING'} ) {
 
647
                    $attr->{class} =
 
648
                      _appendSortedAscendingCssClass( $attr->{class} );
 
649
                }
 
650
                if ( $currentSortDirection == $sortDirection{'DESCENDING'} ) {
 
651
                    $attr->{class} =
 
652
                      _appendSortedDescendingCssClass( $attr->{class} );
 
653
                }
 
654
            }
 
655
 
 
656
            my $type = '';
 
657
            if (/^\s*\*(.*)\*\s*$/) {
 
658
                $value = $1;
 
659
                if (@headerAlign) {
 
660
                    my $align =
 
661
                      @headerAlign[ $colCount % ( $#headerAlign + 1 ) ];
 
662
 
 
663
                    # html attribute
 
664
                    $attr->{align} = $align;
 
665
                }
 
666
                if ($headerVAlign) {
 
667
 
 
668
                    # html attribute
 
669
                    $attr->{valign} = $headerVAlign if $headerVAlign;
 
670
                }
 
671
                elsif ($vAlign) {
 
672
 
 
673
                    # html attribute
 
674
                    $attr->{valign} = $vAlign;
 
675
                }
 
676
                $type = 'th';
 
677
            }
 
678
            else {
 
679
                if (/^\s*(.*?)\s*$/) {    # strip white spaces
 
680
                    $_ = $1;
 
681
                }
 
682
                $value = $_;
 
683
                if (@dataAlign) {
 
684
                    my $align = @dataAlign[ $colCount % ( $#dataAlign + 1 ) ];
 
685
 
 
686
                    # html attribute
 
687
                    $attr->{align} = $align;
 
688
                }
 
689
                if ($dataVAlign) {
 
690
 
 
691
                    # html attribute
 
692
                    $attr->{valign} = $dataVAlign if $dataVAlign;
 
693
                }
 
694
                elsif ($vAlign) {
 
695
 
 
696
                    # html attribute
 
697
                    $attr->{valign} = $vAlign;
 
698
                }
 
699
                $type = 'td';
 
700
            }
 
701
 
 
702
            push @row, { text => $value, attrs => $attr, type => $type };
 
703
        }
 
704
        while ( $span > 1 ) {
 
705
            push @row, { text => $value, type => 'X' };
 
706
            $colCount++;
 
707
            $span--;
 
708
        }
 
709
        $colCount++;
 
710
    }
 
711
    push @curTable, \@row;
 
712
    return $currTablePre
 
713
      . '<nop>';    # Avoid Foswiki converting empty lines to new paras
 
714
}
 
715
 
 
716
# Determine whether to generate sorting headers for this table. The header
 
717
# indicates the context of the table (body or file attachment)
 
718
sub _shouldISortThisTable {
 
719
    my ($header) = @_;
 
720
 
 
721
    return 0 unless $sortAllTables;
 
722
 
 
723
    # All cells in header are headings?
 
724
    foreach my $cell (@$header) {
 
725
        return 0 if ( $cell->{type} ne 'th' );
 
726
    }
 
727
 
 
728
    return 1;
 
729
}
 
730
 
 
731
# Guess if column is a date, number or plain text
 
732
sub _guessColumnType {
 
733
    my ($col)         = @_;
 
734
    my $isDate        = 1;
 
735
    my $isNum         = 1;
 
736
    my $num           = '';
 
737
    my $date          = '';
 
738
    my $columnIsValid = 0;
 
739
    foreach my $row (@curTable) {
 
740
        next if ( !$row->[$col]->{text} );
 
741
 
 
742
        # else
 
743
        $columnIsValid = 1;
 
744
        ( $num, $date ) = _convertToNumberAndDate( $row->[$col]->{text} );
 
745
 
 
746
        $isDate = 0 if ( !defined($date) );
 
747
        $isNum  = 0 if ( !defined($num) );
 
748
        last if ( !$isDate && !$isNum );
 
749
        $row->[$col]->{date}   = $date;
 
750
        $row->[$col]->{number} = $num;
 
751
    }
 
752
    return $columnType{'UNDEFINED'} if ( !$columnIsValid );
 
753
    my $type = $columnType{'TEXT'};
 
754
    if ($isDate) {
 
755
        $type = $columnType{'DATE'};
 
756
    }
 
757
    elsif ($isNum) {
 
758
        $type = $columnType{'NUMBER'};
 
759
    }
 
760
    return $type;
 
761
}
 
762
 
 
763
# Remove HTML from text so it can be sorted
 
764
sub _stripHtml {
 
765
    my ($text) = @_;
 
766
 
 
767
    $text =~
 
768
      s/\[\[[^\]]+\]\[([^\]]+)\]\]/$1/go; # extract label from [[...][...]] link
 
769
 
 
770
    my $orgtext =
 
771
      $text;    # in case we will remove all contents with stripping html
 
772
    $text =~ s/<[^>]+>//go;    # strip HTML
 
773
    $text =~ s/\&nbsp;/ /go;
 
774
    $text = _getImageTextForSorting($orgtext) if ( $text eq '' );
 
775
    $text =~ s/[\[\]\*\|=_\&\<\>]/ /g;    # remove Wiki formatting chars
 
776
    $text =~ s/^ *//go;                   # strip leading space space
 
777
 
 
778
    return $text;
 
779
}
 
780
 
 
781
=pod
 
782
 
 
783
Retrieve text data from an image html tag to be used for sorting.
 
784
First try the alt tag string. If not available, return the url string.
 
785
If not available, return the original string.
 
786
 
 
787
=cut
 
788
 
 
789
sub _getImageTextForSorting {
 
790
    my ($text) = @_;
 
791
 
 
792
    # try to see _if_ there is any img data for sorting
 
793
    my $hasImageTag = ( $text =~ m/\<\s*img([^>]+)>/ );
 
794
    return $text if ( !$hasImageTag );
 
795
 
 
796
    # first try to get the alt text
 
797
    my $key = 'alt';
 
798
    $text =~ m/$key=\s*[\"\']([^\"\']*)/;
 
799
    return $1 if ( $1 ne '' );
 
800
 
 
801
    # else
 
802
 
 
803
    # no alt text; use the url
 
804
    $key = 'url';
 
805
    $text =~ m/$key=\s*[\"\']([^\"\']*)/;
 
806
    return $1 if ( $1 ne '' );
 
807
 
 
808
    # else
 
809
 
 
810
    return $text;
 
811
}
 
812
 
 
813
=pod
 
814
 
 
815
Appends $className to $classList, separated by a space.  
 
816
 
 
817
=cut
 
818
 
 
819
sub _appendToClassList {
 
820
    my ( $classList, $className ) = @_;
 
821
    $classList = $classList ? $classList .= ' ' : '';
 
822
    $classList .= $className;
 
823
    return $classList;
 
824
}
 
825
 
 
826
sub _appendSortedCssClass {
 
827
    my ($classList) = @_;
 
828
 
 
829
    return _appendToClassList( $classList, 'foswikiSortedCol' );
 
830
}
 
831
 
 
832
sub _appendRowNumberCssClass {
 
833
    my ( $classList, $colListName, $rowNum ) = @_;
 
834
 
 
835
    my $rowClassName = 'foswikiTableRow' . $colListName . $rowNum;
 
836
    return _appendToClassList( $classList, $rowClassName );
 
837
}
 
838
 
 
839
sub _appendColNumberCssClass {
 
840
    my ( $classList, $colNum ) = @_;
 
841
 
 
842
    my $colClassName = 'foswikiTableCol' . $colNum;
 
843
    return _appendToClassList( $classList, $colClassName );
 
844
}
 
845
 
 
846
sub _appendFirstColumnCssClass {
 
847
    my ($classList) = @_;
 
848
 
 
849
    return _appendToClassList( $classList, 'foswikiFirstCol' );
 
850
}
 
851
 
 
852
sub _appendLastColumnCssClass {
 
853
    my ($classList) = @_;
 
854
 
 
855
    return _appendToClassList( $classList, 'foswikiLastCol' );
 
856
}
 
857
 
 
858
sub _appendLastRowCssClass {
 
859
    my ($classList) = @_;
 
860
 
 
861
    return _appendToClassList( $classList, 'foswikiLast' );
 
862
}
 
863
 
 
864
sub _appendSortedAscendingCssClass {
 
865
    my ($classList) = @_;
 
866
 
 
867
    return _appendToClassList( $classList, 'foswikiSortedAscendingCol' );
 
868
}
 
869
 
 
870
sub _appendSortedDescendingCssClass {
 
871
    my ($classList) = @_;
 
872
 
 
873
    return _appendToClassList( $classList, 'foswikiSortedDescendingCol' );
 
874
}
 
875
 
 
876
# The default sort direction.
 
877
sub _getDefaultSortDirection {
 
878
    return $sortDirection{'ASCENDING'};
 
879
}
 
880
 
 
881
# Gets the current sort direction.
 
882
sub _getCurrentSortDirection {
 
883
    my ($currentDirection) = @_;
 
884
    $currentDirection ||= _getDefaultSortDirection();
 
885
    return $currentDirection;
 
886
}
 
887
 
 
888
# Gets the new sort direction (needed for sort button) based on the current sort
 
889
# direction.
 
890
sub _getNewSortDirection {
 
891
    my ($currentDirection) = @_;
 
892
    if ( !defined $currentDirection ) {
 
893
        return _getDefaultSortDirection();
 
894
    }
 
895
    my $newDirection;
 
896
    if ( $currentDirection == $sortDirection{'ASCENDING'} ) {
 
897
        $newDirection = $sortDirection{'DESCENDING'};
 
898
    }
 
899
    if ( $currentDirection == $sortDirection{'DESCENDING'} ) {
 
900
        if ($unsortEnabled) {
 
901
            $newDirection = $sortDirection{'NONE'};
 
902
        }
 
903
        else {
 
904
            $newDirection = $sortDirection{'ASCENDING'};
 
905
        }
 
906
    }
 
907
    if ( $currentDirection == $sortDirection{'NONE'} ) {
 
908
        $newDirection = $sortDirection{'ASCENDING'};
 
909
    }
 
910
    return $newDirection;
 
911
}
 
912
 
 
913
=pod
 
914
 
 
915
Writes css styles to the head if $useCss is true (when custom attributes have been passed to
 
916
the TABLE{} variable.
 
917
 
 
918
Explicitly set styles override html styling (in this file marked with comment '# html attribute').
 
919
 
 
920
=cut
 
921
 
 
922
sub _addStylesToHead {
 
923
    my ( $useCss, $writeDefaults, %cssAttrs ) = @_;
 
924
 
 
925
    my @styles = ();
 
926
 
 
927
    if ( !$didWriteDefaultStyle ) {
 
928
        my $id       = 'default';
 
929
        my $selector = '.foswikiTable';
 
930
        my $attr     = 'padding-left:.3em; vertical-align:text-bottom;';
 
931
        push( @styles, ".tableSortIcon img {$attr}" );
 
932
 
 
933
        if ($cellPadding) {
 
934
            my $attr = 'padding:' . addDefaultSizeUnit($cellPadding) . ';';
 
935
            push( @styles, "$selector td {$attr}" );
 
936
            push( @styles, "$selector th {$attr}" );
 
937
        }
 
938
 
 
939
        #_writeStyleToHead( $id, @styles );
 
940
        $didWriteDefaultStyle = 1;
 
941
    }
 
942
 
 
943
    # only write default style
 
944
    return if !$useCss;
 
945
 
 
946
    my $selector = '.foswikiTable';
 
947
    my $id = $writeDefaults ? $writeDefaults : $cssAttrs{tableId};
 
948
    $selector .= '#' . $id if !$writeDefaults;
 
949
 
 
950
    # tablerules
 
951
    if ( $cssAttrs{tableRules} ) {
 
952
        my $attr_table = {};
 
953
        $attr_table->{all}->{td} = $attr_table->{all}->{th} =
 
954
          'border-style:solid;';
 
955
        $attr_table->{none}->{td} = $attr_table->{none}->{th} =
 
956
          'border-style:none;';
 
957
        $attr_table->{cols}->{td} = $attr_table->{cols}->{th} =
 
958
          'border-style:none solid;';
 
959
        $attr_table->{rows}->{td} = $attr_table->{rows}->{th} =
 
960
          'border-style:solid none;';
 
961
        $attr_table->{groups}->{td} = 'border-style:none;';
 
962
        $attr_table->{groups}->{th} = 'border-style:solid none;';
 
963
        my $attr_td = $attr_table->{ $cssAttrs{tableRules} }->{td};
 
964
        my $attr_th = $attr_table->{ $cssAttrs{tableRules} }->{th};
 
965
        push( @styles, "$selector th {$attr_th}" );
 
966
        push( @styles, "$selector td {$attr_td}" );
 
967
    }
 
968
 
 
969
    # tableframe
 
970
    if ( $cssAttrs{tableFrame} ) {
 
971
 
 
972
        my $attr_table = {};
 
973
        $attr_table->{void}   = 'border-style:none;';
 
974
        $attr_table->{above}  = 'border-style:solid none none none;';
 
975
        $attr_table->{below}  = 'border-style:none none solid none;';
 
976
        $attr_table->{lhs}    = 'border-style:none none none solid;';
 
977
        $attr_table->{rhs}    = 'border-style:none solid none none;';
 
978
        $attr_table->{hsides} = 'border-style:solid none solid none;';
 
979
        $attr_table->{vsides} = 'border-style:none solid none solid;';
 
980
        $attr_table->{box}    = 'border-style:solid;';
 
981
        $attr_table->{border} = 'border-style:solid;';
 
982
        my $attr = $attr_table->{ $cssAttrs{tableFrame} };
 
983
        push( @styles, "$selector {$attr}" );
 
984
    }
 
985
 
 
986
    # tableborder
 
987
    if ( defined $cssAttrs{tableBorder} ) {
 
988
        my $tableBorderWidth = $cssAttrs{tableBorder} || 0;
 
989
        my $attr =
 
990
          'border-width:' . addDefaultSizeUnit($tableBorderWidth) . ';';
 
991
        push( @styles, "$selector {$attr}" );
 
992
    }
 
993
 
 
994
    # cellborder
 
995
    if ( defined $cssAttrs{cellBorder} ) {
 
996
        my $cellBorderWidth = $cssAttrs{cellBorder} || 0;
 
997
        my $attr = 'border-width:' . addDefaultSizeUnit($cellBorderWidth) . ';';
 
998
        push( @styles, "$selector td {$attr}" );
 
999
        push( @styles, "$selector th {$attr}" );
 
1000
    }
 
1001
 
 
1002
    # tablewidth
 
1003
    if ( defined $cssAttrs{tableWidth} ) {
 
1004
        my $width = addDefaultSizeUnit( $cssAttrs{tableWidth} );
 
1005
        my $attr  = 'width:' . $width . ';';
 
1006
        push( @styles, "$selector {$attr}" );
 
1007
    }
 
1008
 
 
1009
    # valign
 
1010
    if ( defined $cssAttrs{vAlign} ) {
 
1011
        my $attr = 'vertical-align:' . $cssAttrs{vAlign} . ';';
 
1012
        push( @styles, "$selector td {$attr}" );
 
1013
        push( @styles, "$selector th {$attr}" );
 
1014
    }
 
1015
 
 
1016
    # headerVAlign
 
1017
    if ( defined $cssAttrs{headerVAlign} ) {
 
1018
        my $attr = 'vertical-align:' . $cssAttrs{headerVAlign} . ';';
 
1019
        push( @styles, "$selector th {$attr}" );
 
1020
    }
 
1021
 
 
1022
    # dataVAlign
 
1023
    if ( defined $cssAttrs{dataVAlign} ) {
 
1024
        my $attr = 'vertical-align:' . $cssAttrs{dataVAlign} . ';';
 
1025
        push( @styles, "$selector td {$attr}" );
 
1026
    }
 
1027
 
 
1028
    # headerbg
 
1029
    if ( defined $cssAttrs{headerBg} ) {
 
1030
        unless ( $cssAttrs{headerBg} =~ /none/i ) {
 
1031
            my $attr = 'background-color:' . $cssAttrs{headerBg} . ';';
 
1032
            push( @styles, "$selector th {$attr}" );
 
1033
        }
 
1034
    }
 
1035
 
 
1036
    # headerbgsorted
 
1037
    if ( defined $cssAttrs{headerBgSorted} ) {
 
1038
        unless ( $cssAttrs{headerBgSorted} =~ /none/i ) {
 
1039
            my $attr = 'background-color:' . $cssAttrs{headerBgSorted} . ';';
 
1040
            push( @styles, "$selector th.foswikiSortedCol {$attr}" );
 
1041
        }
 
1042
    }
 
1043
 
 
1044
    # headercolor
 
1045
    if ( defined $cssAttrs{headerColor} ) {
 
1046
        my $attr = 'color:' . $cssAttrs{headerColor} . ';';
 
1047
        push( @styles, "$selector th {$attr}" );
 
1048
        push( @styles, "$selector th a:link {$attr}" );
 
1049
        push( @styles, "$selector th a:visited {$attr}" );
 
1050
        push( @styles, "$selector th a:link font {$attr}" );
 
1051
        push( @styles, "$selector th a:visited font {$attr}" );
 
1052
        my $hoverLinkColor = $cssAttrs{headerBg} || '#fff';
 
1053
        my $hoverBackgroundColor = $cssAttrs{headerColor};
 
1054
        $attr =
 
1055
            'color:'
 
1056
          . $hoverLinkColor
 
1057
          . ';background-color:'
 
1058
          . $hoverBackgroundColor . ';';
 
1059
        push( @styles, "$selector th a:hover {$attr}" );
 
1060
        push( @styles, "$selector th a:hover font {$attr}" );
 
1061
    }
 
1062
 
 
1063
    # databg (array)
 
1064
    if ( defined $cssAttrs{dataBg} ) {
 
1065
        unless ( $cssAttrs{dataBg} =~ /none/i ) {
 
1066
            my $count = 0;
 
1067
            my @attrDataBg = split( /,/, $cssAttrs{dataBg} );
 
1068
            foreach my $color (@attrDataBg) {
 
1069
                next if !$color;
 
1070
                my $rowSelector = 'foswikiTableRow' . 'dataBg';
 
1071
                $rowSelector .= $count;
 
1072
                my $attr = 'background-color:' . $color . ';';
 
1073
                push( @styles, "$selector tr.$rowSelector td {$attr}" );
 
1074
                $count++;
 
1075
            }
 
1076
        }
 
1077
    }
 
1078
 
 
1079
    # databgsorted (array)
 
1080
    if ( defined $cssAttrs{dataBgSorted} ) {
 
1081
        unless ( $cssAttrs{dataBgSorted} =~ /none/i ) {
 
1082
            my $count = 0;
 
1083
            my @attrDataBgSorted = split( /,/, $cssAttrs{dataBgSorted} );
 
1084
            foreach my $color (@attrDataBgSorted) {
 
1085
                next if !$color;
 
1086
                my $rowSelector = 'foswikiTableRow' . 'dataBg';
 
1087
                $rowSelector .= $count;
 
1088
                my $attr = 'background-color:' . $color . ';';
 
1089
                push( @styles,
 
1090
                    "$selector tr.$rowSelector td.foswikiSortedCol {$attr}" );
 
1091
                $count++;
 
1092
            }
 
1093
        }
 
1094
    }
 
1095
 
 
1096
    # datacolor (array)
 
1097
    if ( defined $cssAttrs{dataColor} ) {
 
1098
        unless ( $cssAttrs{dataColor} =~ /none/i ) {
 
1099
            my $count = 0;
 
1100
            my @attrDataColor = split( /,/, $cssAttrs{dataColor} );
 
1101
            foreach my $color (@attrDataColor) {
 
1102
                next if !$color;
 
1103
                my $rowSelector = 'foswikiTableRow' . 'dataColor';
 
1104
                $rowSelector .= $count;
 
1105
                my $attr = 'color:' . $color . ';';
 
1106
                push( @styles, "$selector tr.$rowSelector td {$attr}" );
 
1107
                push( @styles, "$selector tr.$rowSelector td font {$attr}" );
 
1108
                $count++;
 
1109
            }
 
1110
        }
 
1111
    }
 
1112
 
 
1113
    # columnwidths
 
1114
    if ( defined $cssAttrs{columnWidths} ) {
 
1115
        my $count = 0;
 
1116
        my @attrColumnWidths = split( /,/, $cssAttrs{columnWidths} );
 
1117
        foreach my $width (@attrColumnWidths) {
 
1118
            next if !$width;
 
1119
            $width = addDefaultSizeUnit($width);
 
1120
            my $colSelector = 'foswikiTableCol';
 
1121
            $colSelector .= $count;
 
1122
            my $attr = 'width:' . $width . ';';
 
1123
            push( @styles, "$selector td.$colSelector {$attr}" );
 
1124
            push( @styles, "$selector th.$colSelector {$attr}" );
 
1125
            $count++;
 
1126
        }
 
1127
    }
 
1128
 
 
1129
    # headeralign
 
1130
    if ( defined $cssAttrs{headerAlign} ) {
 
1131
        my @attrHeaderAlign = split( /,/, $cssAttrs{headerAlign} );
 
1132
        if ( scalar @attrHeaderAlign == 1 ) {
 
1133
            my $align = $attrHeaderAlign[0];
 
1134
            my $attr  = 'text-align:' . $align . ';';
 
1135
            push( @styles, "$selector th {$attr}" );
 
1136
        }
 
1137
        else {
 
1138
            my $count = 0;
 
1139
            foreach my $align (@attrHeaderAlign) {
 
1140
                next if !$align;
 
1141
                my $colSelector = 'foswikiTableCol';
 
1142
                $colSelector .= $count;
 
1143
                my $attr = 'text-align:' . $align . ';';
 
1144
                push( @styles, "$selector th.$colSelector {$attr}" );
 
1145
                $count++;
 
1146
            }
 
1147
        }
 
1148
    }
 
1149
 
 
1150
    # dataAlign
 
1151
    if ( defined $cssAttrs{dataAlign} ) {
 
1152
        my @attrDataAlign = split( /,/, $cssAttrs{dataAlign} );
 
1153
        if ( scalar @attrDataAlign == 1 ) {
 
1154
            my $align = $attrDataAlign[0];
 
1155
            my $attr  = 'text-align:' . $align . ';';
 
1156
            push( @styles, "$selector td {$attr}" );
 
1157
        }
 
1158
        else {
 
1159
            my $count = 0;
 
1160
            foreach my $align (@attrDataAlign) {
 
1161
                next if !$align;
 
1162
                my $colSelector = 'foswikiTableCol';
 
1163
                $colSelector .= $count;
 
1164
                my $attr = 'text-align:' . $align . ';';
 
1165
                push( @styles, "$selector td.$colSelector {$attr}" );
 
1166
                $count++;
 
1167
            }
 
1168
        }
 
1169
    }
 
1170
 
 
1171
    # cellspacing : no good css equivalent; use table tag attribute
 
1172
 
 
1173
    # cellpadding
 
1174
    if ( defined $cssAttrs{cellPadding} ) {
 
1175
        my $attr =
 
1176
          'padding:' . addDefaultSizeUnit( $cssAttrs{cellPadding} ) . ';';
 
1177
        push( @styles, "$selector td {$attr}" );
 
1178
        push( @styles, "$selector th {$attr}" );
 
1179
    }
 
1180
 
 
1181
    return if !scalar @styles;
 
1182
    _writeStyleToHead( $id, @styles );
 
1183
}
 
1184
 
 
1185
sub _writeStyleToHead {
 
1186
    my ( $id, @styles ) = @_;
 
1187
 
 
1188
    my $style = join( "\n", @styles );
 
1189
    my $header =
 
1190
      '<style type="text/css" media="all">' . "\n" . $style . "\n" . '</style>';
 
1191
    Foswiki::Func::addToHEAD( 'TABLEPLUGIN_' . $id, $header );
 
1192
}
 
1193
 
 
1194
=pod
 
1195
 
 
1196
StaticMethod addDefaultSizeUnit ($text) -> $text
 
1197
 
 
1198
Adds size unit 'px' if this is missing from the size text.
 
1199
 
 
1200
=cut
 
1201
 
 
1202
sub addDefaultSizeUnit {
 
1203
    my ($inSize) = @_;
 
1204
 
 
1205
    my $unit = '';
 
1206
    if ( $inSize =~ m/$PATTERN_ATTRIBUTE_SIZE/ ) {
 
1207
        $unit = 'px' if !$2;
 
1208
    }
 
1209
    return "$inSize$unit";
 
1210
}
 
1211
 
 
1212
sub emitTable {
 
1213
 
 
1214
    #Validate headerrows/footerrows and modify if out of range
 
1215
    if ( $headerRows > @curTable ) {
 
1216
        $headerRows = @curTable;    # limit header to size of table!
 
1217
    }
 
1218
    if ( $headerRows + $footerRows > @curTable ) {
 
1219
        $footerRows = @curTable - $headerRows;  # and footer to whatever is left
 
1220
    }
 
1221
 
 
1222
    my $sortThisTable = _shouldISortThisTable( $curTable[ $headerRows - 1 ] );
 
1223
    my $tattrs = { class => 'foswikiTable' };
 
1224
    $tattrs->{border} = $tableBorder
 
1225
      if defined $tableBorder && $tableBorder ne '';
 
1226
    $tattrs->{cellspacing} = $cellSpacing
 
1227
      if defined $cellSpacing && $cellSpacing ne '';
 
1228
    $tattrs->{cellpadding} = $cellPadding
 
1229
      if defined $cellPadding && $cellPadding ne '';
 
1230
    $tattrs->{id} = $tableId if defined $tableId && $tableId ne '';
 
1231
    $tattrs->{summary} = $tableSummary
 
1232
      if defined $tableSummary && $tableSummary ne '';
 
1233
    $tattrs->{frame} = $tableFrame if defined $tableFrame && $tableFrame ne '';
 
1234
    $tattrs->{rules} = $tableRules if defined $tableRules && $tableRules ne '';
 
1235
    $tattrs->{width} = $tableWidth if defined $tableWidth && $tableWidth ne '';
 
1236
 
 
1237
    my $text = $currTablePre . CGI::start_table($tattrs);
 
1238
    $text .= $currTablePre . CGI::caption($tableCaption) if ($tableCaption);
 
1239
    my $stype = '';
 
1240
 
 
1241
    # count the number of cols to prevent looping over non-existing columns
 
1242
    my $maxCols = 0;
 
1243
 
 
1244
    #Flush out any remaining rowspans
 
1245
    for ( my $i = 0 ; $i < @rowspan ; $i++ ) {
 
1246
        if ( defined( $rowspan[$i] ) && $rowspan[$i] ) {
 
1247
            my $nRows = scalar(@curTable);
 
1248
            my $rspan = $rowspan[$i] + 1;
 
1249
            my $r     = $nRows - $rspan;
 
1250
            $curTable[$r][$i]->{attrs} ||= {};
 
1251
            if ( $rspan > 1 ) {
 
1252
                $curTable[$r][$i]->{attrs}->{rowspan} = $rspan;
 
1253
            }
 
1254
        }
 
1255
    }
 
1256
 
 
1257
    if (
 
1258
        (
 
1259
               defined $sortCol
 
1260
            && defined $requestedTable
 
1261
            && $requestedTable == $tableCount
 
1262
        )
 
1263
        || defined $initSort
 
1264
      )
 
1265
    {
 
1266
 
 
1267
        # DG 08 Aug 2002: Allow multi-line headers
 
1268
        my @header = splice( @curTable, 0, $headerRows );
 
1269
 
 
1270
        # DG 08 Aug 2002: Skip sorting any trailers as well
 
1271
        my @trailer = ();
 
1272
        if ( $footerRows && scalar(@curTable) > $footerRows ) {
 
1273
            @trailer = splice( @curTable, -$footerRows );
 
1274
        }
 
1275
 
 
1276
        # Count the maximum number of columns of this table
 
1277
        for my $row ( 0 .. $#curTable ) {
 
1278
            my $thisRowMaxColCount = 0;
 
1279
            for my $col ( 0 .. $#{ $curTable[$row] } ) {
 
1280
                $thisRowMaxColCount++;
 
1281
            }
 
1282
            $maxCols = $thisRowMaxColCount
 
1283
              if ( $thisRowMaxColCount > $maxCols );
 
1284
        }
 
1285
 
 
1286
        # Handle multi-row labels by killing rowspans in sorted tables
 
1287
        for my $row ( 0 .. $#curTable ) {
 
1288
            for my $col ( 0 .. $#{ $curTable[$row] } ) {
 
1289
                $curTable[$row][$col]->{attrs}->{rowspan} = 1;
 
1290
                if ( $curTable[$row][$col]->{type} eq 'Y' ) {
 
1291
                    $curTable[$row][$col]->{text} =
 
1292
                      $curTable[ $row - 1 ][$col]->{text};
 
1293
                    $curTable[$row][$col]->{type} = 'td';
 
1294
                }
 
1295
            }
 
1296
        }
 
1297
 
 
1298
        $stype = $columnType{'UNDEFINED'};    # default value
 
1299
 
 
1300
        # only get the column type if within bounds
 
1301
        if ( $sortCol < $maxCols ) {
 
1302
            $stype = _guessColumnType($sortCol);
 
1303
        }
 
1304
 
 
1305
        # invalidate sorting if no valid column
 
1306
        if ( $stype eq $columnType{'UNDEFINED'} ) {
 
1307
            undef $initSort;
 
1308
            undef $sortCol;
 
1309
        }
 
1310
        elsif ( $stype eq $columnType{'TEXT'} ) {
 
1311
            if ( $currentSortDirection == $sortDirection{'DESCENDING'} ) {
 
1312
 
 
1313
                # efficient way of sorting stripped HTML text
 
1314
                # SMELL: efficient? That's not efficient!
 
1315
                @curTable = map { $_->[0] }
 
1316
                  sort { $b->[1] cmp $a->[1] }
 
1317
                  map { [ $_, lc( $_->[$sortCol]->{text} ) ] } @curTable;
 
1318
            }
 
1319
            if ( $currentSortDirection == $sortDirection{'ASCENDING'} ) {
 
1320
                @curTable = map { $_->[0] }
 
1321
                  sort { $a->[1] cmp $b->[1] }
 
1322
                  map { [ $_, lc( $_->[$sortCol]->{text} ) ] } @curTable;
 
1323
            }
 
1324
        }
 
1325
        else {
 
1326
            if ( $currentSortDirection == $sortDirection{'DESCENDING'} ) {
 
1327
                @curTable =
 
1328
                  sort { $b->[$sortCol]->{$stype} <=> $a->[$sortCol]->{$stype} }
 
1329
                  @curTable;
 
1330
            }
 
1331
            if ( $currentSortDirection == $sortDirection{'ASCENDING'} ) {
 
1332
                @curTable =
 
1333
                  sort { $a->[$sortCol]->{$stype} <=> $b->[$sortCol]->{$stype} }
 
1334
                  @curTable;
 
1335
            }
 
1336
 
 
1337
        }
 
1338
 
 
1339
        # DG 08 Aug 2002: Cleanup after the header/trailer splicing
 
1340
        # this is probably awfully inefficient - but how big is a table?
 
1341
        @curTable = ( @header, @curTable, @trailer );
 
1342
    }    # if defined $sortCol ...
 
1343
 
 
1344
    my $rowCount       = 0;
 
1345
    my $numberOfRows   = scalar(@curTable);
 
1346
    my $dataColorCount = 0;
 
1347
 
 
1348
    my @headerRowList = ();
 
1349
    my @bodyRowList   = ();
 
1350
    my @footerRowList = ();
 
1351
 
 
1352
    my $isPastHeaderRows = 0;
 
1353
    my $singleIndent     = "\n\t";
 
1354
    my $doubleIndent     = "\n\t\t";
 
1355
    my $tripleIndent     = "\n\t\t\t";
 
1356
 
 
1357
    foreach my $row (@curTable) {
 
1358
        my $rowtext  = '';
 
1359
        my $colCount = 0;
 
1360
 
 
1361
        # keep track of header cells: if all cells are header cells, do not
 
1362
        # update the data color count
 
1363
        my $headerCellCount = 0;
 
1364
        my $numberOfCols    = scalar(@$row);
 
1365
 
 
1366
        foreach my $fcell (@$row) {
 
1367
 
 
1368
            # check if cell exists
 
1369
            next if ( !$fcell || !$fcell->{type} );
 
1370
 
 
1371
            my $tableAnchor = '';
 
1372
            next
 
1373
              if ( $fcell->{type} eq 'X' )
 
1374
              ;    # data was there so sort could work with col spanning
 
1375
            my $type = $fcell->{type};
 
1376
            my $cell = $fcell->{text};
 
1377
            my $attr = $fcell->{attrs} || {};
 
1378
 
 
1379
            my $newDirection;
 
1380
            my $isSorted = 0;
 
1381
 
 
1382
            if (
 
1383
                   $currentSortDirection != $sortDirection{'NONE'}
 
1384
                && defined $sortCol
 
1385
                && $colCount == $sortCol
 
1386
 
 
1387
                # Removing the line below hides the marking of sorted columns
 
1388
                # until the user clicks on a header (KJL)
 
1389
                # && defined $requestedTable && $requestedTable == $tableCount
 
1390
                && $stype ne ''
 
1391
              )
 
1392
            {
 
1393
                $isSorted     = 1;
 
1394
                $newDirection = _getNewSortDirection($currentSortDirection);
 
1395
            }
 
1396
            else {
 
1397
                $newDirection = _getDefaultSortDirection();
 
1398
            }
 
1399
 
 
1400
            if ( $type eq 'th' ) {
 
1401
                $headerCellCount++;
 
1402
                unless ($upchar) {
 
1403
                    $upchar = CGI::span(
 
1404
                        { class => 'tableSortIcon tableSortUp' },
 
1405
                        CGI::img(
 
1406
                            {
 
1407
                                src    => $iconUrl . 'tablesortup.gif',
 
1408
                                border => 0,
 
1409
                                width  => 11,
 
1410
                                height => 13,
 
1411
                                alt    => 'Sorted ascending',
 
1412
                                title  => 'Sorted ascending'
 
1413
                            }
 
1414
                        )
 
1415
                    );
 
1416
                    $downchar = CGI::span(
 
1417
                        { class => 'tableSortIcon tableSortDown' },
 
1418
                        CGI::img(
 
1419
                            {
 
1420
                                src    => $iconUrl . 'tablesortdown.gif',
 
1421
                                border => 0,
 
1422
                                width  => 11,
 
1423
                                height => 13,
 
1424
                                alt    => 'Sorted descending',
 
1425
                                title  => 'Sorted descending'
 
1426
                            }
 
1427
                        )
 
1428
                    );
 
1429
                    $diamondchar = CGI::span(
 
1430
                        { class => 'tableSortIcon tableSortUp' },
 
1431
                        CGI::img(
 
1432
                            {
 
1433
                                src    => $iconUrl . 'tablesortdiamond.gif',
 
1434
                                border => 0,
 
1435
                                width  => 11,
 
1436
                                height => 13,
 
1437
                                alt    => 'Sort',
 
1438
                                title  => 'Sort'
 
1439
                            }
 
1440
                        )
 
1441
                    );
 
1442
                }
 
1443
 
 
1444
                # DG: allow headers without b.g too (consistent and yes,
 
1445
                # I use this)
 
1446
                # html attribute
 
1447
                $attr->{bgcolor} = $headerBg unless ( $headerBg =~ /none/i );
 
1448
 
 
1449
                # attribute 'maxcols' does not exist in html
 
1450
                # so commenting out
 
1451
                #$attr->{maxCols} = $maxCols;
 
1452
 
 
1453
                if ($isSorted) {
 
1454
                    if ( $currentSortDirection == $sortDirection{'ASCENDING'} )
 
1455
                    {
 
1456
                        $tableAnchor = $upchar;
 
1457
                    }
 
1458
                    if ( $currentSortDirection == $sortDirection{'DESCENDING'} )
 
1459
                    {
 
1460
                        $tableAnchor = $downchar;
 
1461
                    }
 
1462
                }
 
1463
 
 
1464
                if (   defined $sortCol
 
1465
                    && $colCount == $sortCol
 
1466
                    && defined $requestedTable
 
1467
                    && $requestedTable == $tableCount )
 
1468
                {
 
1469
 
 
1470
                    $tableAnchor =
 
1471
                      CGI::a( { name => 'sorted_table' }, '<!-- -->' )
 
1472
                      . $tableAnchor;
 
1473
                }
 
1474
 
 
1475
                if ($headerColor) {
 
1476
 
 
1477
                    my $cellAttrs = { color => $headerColor };
 
1478
 
 
1479
                    # html attribute
 
1480
                    $cell = CGI::font( $cellAttrs, $cell );
 
1481
                }
 
1482
 
 
1483
                if ( $sortThisTable && $rowCount == $headerRows - 1 ) {
 
1484
                    if ($isSorted) {
 
1485
                        unless ( $headerBgSorted =~ /none/i ) {
 
1486
 
 
1487
                            # html attribute
 
1488
                            $attr->{bgcolor} = $headerBgSorted;
 
1489
                        }
 
1490
                    }
 
1491
 
 
1492
                    my $debugText      = '';
 
1493
                    my $linkAttributes = {
 
1494
                        href => $url
 
1495
                          . 'sortcol='
 
1496
                          . $colCount
 
1497
                          . ';table='
 
1498
                          . $tableCount . ';up='
 
1499
                          . $newDirection
 
1500
                          . '#sorted_table',
 
1501
                        rel   => 'nofollow',
 
1502
                        title => 'Sort by this column'
 
1503
                    };
 
1504
                    if ( $cell =~ /\[\[|href/o ) {
 
1505
                        $cell .=
 
1506
                            $debugText . ' '
 
1507
                          . CGI::a( $linkAttributes, $diamondchar )
 
1508
                          . $tableAnchor;
 
1509
                    }
 
1510
                    else {
 
1511
                        $cell =
 
1512
                            $debugText
 
1513
                          . CGI::a( $linkAttributes, $cell )
 
1514
                          . $tableAnchor;
 
1515
                    }
 
1516
                }
 
1517
 
 
1518
            }
 
1519
            else {
 
1520
 
 
1521
                # $type is not 'th'
 
1522
                if (@dataBg) {
 
1523
                    my $bgcolor;
 
1524
                    if ( $isSorted && @dataBgSorted ) {
 
1525
                        $bgcolor =
 
1526
                          $dataBgSorted[ $dataColorCount % (
 
1527
                              $#dataBgSorted + 1 ) ];
 
1528
                    }
 
1529
                    else {
 
1530
                        $bgcolor =
 
1531
                          $dataBg[ $dataColorCount % ( $#dataBg + 1 ) ];
 
1532
                    }
 
1533
                    unless ( $bgcolor =~ /none/i ) {
 
1534
 
 
1535
                        # html attribute
 
1536
                        $attr->{bgcolor} = $bgcolor;
 
1537
                    }
 
1538
                }
 
1539
                if (@dataColor) {
 
1540
                    my $color =
 
1541
                      $dataColor[ $dataColorCount % ( $#dataColor + 1 ) ];
 
1542
 
 
1543
                    unless ( $color =~ /^(none)$/i ) {
 
1544
                        my $cellAttrs = { color => $color };
 
1545
 
 
1546
                        # html attribute
 
1547
                        $cell = CGI::font( $cellAttrs, ' ' . $cell . ' ' );
 
1548
                    }
 
1549
                }
 
1550
                $type = 'td' unless $type eq 'Y';
 
1551
            }    ###if( $type eq 'th' )
 
1552
 
 
1553
            if ($isSorted) {
 
1554
                $attr->{class} = _appendSortedCssClass( $attr->{class} );
 
1555
            }
 
1556
 
 
1557
            my $isLastRow = ( $rowCount == $numberOfRows - 1 );
 
1558
            if ( $attr->{rowspan} ) {
 
1559
                $isLastRow =
 
1560
                  ( ( $rowCount + ( $attr->{rowspan} - 1 ) ) ==
 
1561
                      $numberOfRows - 1 );
 
1562
            }
 
1563
 
 
1564
            # CSS class name
 
1565
            $attr->{class} = _appendFirstColumnCssClass( $attr->{class} )
 
1566
              if $colCount == 0;
 
1567
            my $isLastCol = ( $colCount == $numberOfCols - 1 );
 
1568
            $attr->{class} = _appendLastColumnCssClass( $attr->{class} )
 
1569
              if $isLastCol;
 
1570
 
 
1571
            $attr->{class} = _appendLastRowCssClass( $attr->{class} )
 
1572
              if $isLastRow;
 
1573
 
 
1574
            $colCount++;
 
1575
            next if ( $type eq 'Y' );
 
1576
            my $fn = 'CGI::' . $type;
 
1577
            no strict 'refs';
 
1578
            $rowtext .= "$tripleIndent" . &$fn( $attr, " $cell " );
 
1579
            use strict 'refs';
 
1580
        }    # foreach my $fcell ( @$row )
 
1581
 
 
1582
        # assign css class names to tr
 
1583
        # based on settings: dataBg, dataBgSorted
 
1584
        my $trClassName = '';
 
1585
 
 
1586
        # just 2 css names is too limited, but we will keep it for compatibility
 
1587
        # with existing style sheets
 
1588
        my $rowTypeName =
 
1589
          ( $rowCount % 2 ) ? 'foswikiTableEven' : 'foswikiTableOdd';
 
1590
        $trClassName = _appendToClassList( $trClassName, $rowTypeName );
 
1591
 
 
1592
        if ( scalar @dataBgSorted ) {
 
1593
            my $modRowNum = $dataColorCount % ( $#dataBgSorted + 1 );
 
1594
            $trClassName =
 
1595
              _appendRowNumberCssClass( $trClassName, 'dataBgSorted',
 
1596
                $modRowNum );
 
1597
        }
 
1598
        if ( scalar @dataBg ) {
 
1599
            my $modRowNum = $dataColorCount % ( $#dataBg + 1 );
 
1600
            $trClassName =
 
1601
              _appendRowNumberCssClass( $trClassName, 'dataBg', $modRowNum );
 
1602
        }
 
1603
        if ( scalar @dataColor ) {
 
1604
            my $modRowNum = $dataColorCount % ( $#dataColor + 1 );
 
1605
            $trClassName =
 
1606
              _appendRowNumberCssClass( $trClassName, 'dataColor', $modRowNum );
 
1607
        }
 
1608
        $rowtext .= $doubleIndent;
 
1609
        my $rowHTML =
 
1610
          $doubleIndent . CGI::Tr( { class => $trClassName }, $rowtext );
 
1611
 
 
1612
        my $isHeaderRow = ( $headerCellCount == $colCount );
 
1613
        my $isFooterRow = ( ( $numberOfRows - $rowCount ) <= $footerRows );
 
1614
 
 
1615
        if ( !$isHeaderRow && !$isFooterRow ) {
 
1616
 
 
1617
        # don't include non-adjacent header rows to the top block of header rows
 
1618
            $isPastHeaderRows = 1;
 
1619
        }
 
1620
 
 
1621
        if ($isFooterRow) {
 
1622
            push @footerRowList, $rowHTML;
 
1623
        }
 
1624
        elsif ( $isHeaderRow && !$isPastHeaderRows ) {
 
1625
            push( @headerRowList, $rowHTML );
 
1626
        }
 
1627
        else {
 
1628
            push @bodyRowList, $rowHTML;
 
1629
            $dataColorCount++;
 
1630
        }
 
1631
 
 
1632
        if ($isHeaderRow) {
 
1633
 
 
1634
            # reset data color count to start with first color after
 
1635
            # each table heading
 
1636
            $dataColorCount = 0;
 
1637
        }
 
1638
 
 
1639
        $rowCount++;
 
1640
    }    # foreach my $row ( @curTable )
 
1641
 
 
1642
    my $thead =
 
1643
        "$singleIndent<thead>"
 
1644
      . join( "", @headerRowList )
 
1645
      . "$singleIndent</thead>";
 
1646
    $text .= $currTablePre . $thead if scalar @headerRowList;
 
1647
 
 
1648
    my $tfoot =
 
1649
        "$singleIndent<tfoot>"
 
1650
      . join( "", @footerRowList )
 
1651
      . "$singleIndent</tfoot>";
 
1652
    $text .= $currTablePre . $tfoot if scalar @footerRowList;
 
1653
 
 
1654
    my $tbody =
 
1655
        "$singleIndent<tbody>"
 
1656
      . join( "", @bodyRowList )
 
1657
      . "$singleIndent</tbody>";
 
1658
    $text .= $currTablePre . $tbody if scalar @bodyRowList;
 
1659
 
 
1660
    $text .= $currTablePre . CGI::end_table() . "\n";
 
1661
    _setDefaults();
 
1662
    return $text;
 
1663
}
 
1664
 
 
1665
sub handler {
 
1666
    ### my ( $text, $removed ) = @_;
 
1667
 
 
1668
    unless ($Foswiki::Plugins::TablePlugin::initialised) {
 
1669
        $insideTABLE = 0;
 
1670
        $tableCount  = 0;
 
1671
 
 
1672
        $twoCol = 1;
 
1673
 
 
1674
        my $cgi = Foswiki::Func::getCgiQuery();
 
1675
        return unless $cgi;
 
1676
 
 
1677
        # Copy existing values
 
1678
        my ( @origSort, @origTable, @origUp );
 
1679
        @origSort  = $cgi->param('sortcol');
 
1680
        @origTable = $cgi->param('table');
 
1681
        @origUp    = $cgi->param('up');
 
1682
        $cgi->delete( 'sortcol', 'table', 'up' );
 
1683
        $url = $cgi->url( -absolute => 1, -path => 1 ) . '?';
 
1684
        my $queryString = $cgi->query_string();
 
1685
        $url .= $queryString . ';' if $queryString;
 
1686
 
 
1687
        # Restore parameters, so we don't interfere on the remaining execution
 
1688
        $cgi->param( -name => 'sortcol', -value => \@origSort )  if @origSort;
 
1689
        $cgi->param( -name => 'table',   -value => \@origTable ) if @origTable;
 
1690
        $cgi->param( -name => 'up',      -value => \@origUp )    if @origUp;
 
1691
 
 
1692
        $sortColFromUrl =
 
1693
          $cgi->param('sortcol');    # zero based: 0 is first column
 
1694
        $requestedTable = $cgi->param('table');
 
1695
        $up             = $cgi->param('up');
 
1696
 
 
1697
        $sortTablesInText = 0;
 
1698
        $sortAttachments  = 0;
 
1699
        my $tmp = Foswiki::Func::getPreferencesValue('TABLEPLUGIN_SORT')
 
1700
          || 'all';
 
1701
        if ( !$tmp || $tmp =~ /^all$/oi ) {
 
1702
            $sortTablesInText = 1;
 
1703
            $sortAttachments  = 1;
 
1704
        }
 
1705
        elsif ( $tmp =~ /^attachments$/oi ) {
 
1706
            $sortAttachments = 1;
 
1707
        }
 
1708
 
 
1709
        $pluginAttrs =
 
1710
          Foswiki::Func::getPreferencesValue('TABLEPLUGIN_TABLEATTRIBUTES')
 
1711
          || 'tableborder="1" cellpadding="0" cellspacing="0" valign="top" headercolor="#ffffff" headerbg="#687684" headerbgsorted="#334455" databg="#ffffff,#edf4f9" databgsorted="#f1f7fc,#ddebf6" tablerules="rows"';
 
1712
        $prefsAttrs = Foswiki::Func::getPreferencesValue('TABLEATTRIBUTES');
 
1713
        _setDefaults();
 
1714
 
 
1715
        $Foswiki::Plugins::TablePlugin::initialised = 1;
 
1716
    }
 
1717
 
 
1718
    undef $initSort;
 
1719
    $insideTABLE = 0;
 
1720
 
 
1721
    my $defaultSort = $sortAllTables;
 
1722
 
 
1723
    my $acceptable = $sortAllTables;
 
1724
    my @lines = split( /\r?\n/, $_[0] );
 
1725
    for (@lines) {
 
1726
        if (
 
1727
s/%TABLE(?:{(.*?)})?%/_parseParameters(1,undef,Foswiki::Func::extractParameters($1))/se
 
1728
          )
 
1729
        {
 
1730
            $acceptable = 1;
 
1731
        }
 
1732
        elsif (s/^(\s*)\|(.*\|\s*)$/_processTableRow($1,$2)/eo) {
 
1733
            $insideTABLE = 1;
 
1734
        }
 
1735
        elsif ($insideTABLE) {
 
1736
            $_           = emitTable() . $_;
 
1737
            $insideTABLE = 0;
 
1738
            undef $initSort;
 
1739
            $sortAllTables = $defaultSort;
 
1740
            $acceptable    = $defaultSort;
 
1741
        }
 
1742
    }
 
1743
    $_[0] = join( "\n", @lines );
 
1744
 
 
1745
    if ($insideTABLE) {
 
1746
        $_[0] .= emitTable();
 
1747
    }
 
1748
}
 
1749
 
 
1750
1;