1
# Plugin for Foswiki - The Free and Open Source Wiki, http://foswiki.org/
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
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.
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
20
# As per the GPL, removal of this notice is prohibited.
24
package Foswiki::Plugins::TablePlugin::Core;
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
45
my $PATTERN_ATTRIBUTE_SIZE = qr'([0-9]+)(px|%)*'o;
48
$translationToken = "\0";
53
%sortDirection = ( 'ASCENDING', 0, 'DESCENDING', 1, 'NONE', 2 );
55
'TEXT', 'text', 'DATE', 'date',
56
'NUMBER', 'number', 'UNDEFINED', 'undefined'
59
# the maximum number of columns we will handle
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 = ();
72
$sortAllTables = $sortTablesInText;
85
$headerBg = '#6b7f93';
87
$headerColor = '#ffffff';
94
@dataBg = ( '#ecf2f8', '#ffffff' );
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 );
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 ) = @_;
113
return '' if !keys %params;
120
if ( defined $tmp && $tmp ne '' && $tmp ne $tableId ) {
124
$tableId = 'table' . ( $tableCount + 1 );
126
$cssAttrs{tableId} = $tableId;
128
# Defines which column to initially sort : ShawnBradford 20020221
129
$tmp = $params{initsort};
130
$initSort = $tmp if ($tmp);
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 );
140
$tmp = $params{sort};
141
$tmp = '0' if ( defined $tmp && $tmp =~ /^off$/oi );
142
$sortAllTables = $tmp if ( defined $tmp && $tmp ne '' );
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;
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;
161
$tmp = $params{tableborder};
162
if ( defined $tmp && $tmp ne '' ) {
163
$tableBorder = $tmp if $tmp ne $tableBorder;
166
&& ( !defined $defaultCssAttrs{'tableBorder'}
167
|| $tmp ne $defaultCssAttrs{'tableBorder'} )
170
$cssAttrs{tableBorder} = $tableBorder;
171
$defaultCssAttrs{tableBorder} = $tableBorder if $writeDefaults;
175
$tmp = $params{tableframe};
176
if ( defined $tmp && $tmp ne '' && $tmp ne $tableFrame ) {
180
&& ( !defined $defaultCssAttrs{'tableFrame'}
181
|| $tmp ne $defaultCssAttrs{'tableFrame'} )
184
$cssAttrs{tableFrame} = $tableFrame;
185
$defaultCssAttrs{tableFrame} = $tableFrame if $writeDefaults;
189
$tmp = $params{tablerules};
190
if ( defined $tmp && $tmp ne '' && $tmp ne $tableRules ) {
194
&& ( !defined $defaultCssAttrs{'tableRules'}
195
|| $tmp ne $defaultCssAttrs{'tableRules'} )
198
$cssAttrs{tableRules} = $tableRules;
199
$defaultCssAttrs{tableRules} = $tableRules if $writeDefaults;
203
$tmp = $params{cellpadding};
204
if ( defined $tmp && $tmp ne '' && $tmp ne $cellPadding ) {
208
&& ( !defined $defaultCssAttrs{'cellPadding'}
209
|| $tmp ne $defaultCssAttrs{'cellPadding'} )
212
$cssAttrs{cellPadding} = $cellPadding;
213
$defaultCssAttrs{cellPadding} = $cellPadding if $writeDefaults;
217
$tmp = $params{cellspacing};
220
if ( defined $tmp && $tmp ne '' && $tmp ne $cellSpacing ) {
224
$tmp = $params{cellborder};
225
if ( defined $tmp && $tmp ne '' && $tmp ne $cellBorder ) {
229
&& ( !defined $defaultCssAttrs{'cellBorder'}
230
|| $tmp ne $defaultCssAttrs{'cellBorder'} )
233
$cssAttrs{cellBorder} = $cellBorder;
234
$defaultCssAttrs{cellBorder} = $cellBorder if $writeDefaults;
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 );
245
&& ( !defined $defaultCssAttrs{'headerAlign'}
246
|| $tmp ne $defaultCssAttrs{'headerAlign'} )
249
$cssAttrs{headerAlign} = $tmp; # store string
250
$defaultCssAttrs{headerAlign} = $tmp
251
if $writeDefaults; # store string
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 );
263
&& ( !defined $defaultCssAttrs{'dataAlign'}
264
|| $tmp ne $defaultCssAttrs{'dataAlign'} )
267
$cssAttrs{dataAlign} = $tmp; # store string
268
$defaultCssAttrs{dataAlign} = $tmp
269
if $writeDefaults; # store string
274
$tmp = $params{tablewidth};
275
if ( defined $tmp && $tmp ne '' && $tmp ne $tableWidth ) {
279
&& ( !defined $defaultCssAttrs{'tableWidth'}
280
|| $tmp ne $defaultCssAttrs{'tableWidth'} )
283
$cssAttrs{tableWidth} = $tableWidth;
284
$defaultCssAttrs{tableWidth} = $tableWidth if $writeDefaults;
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 );
295
&& ( !defined $defaultCssAttrs{'columnWidths'}
296
|| $tmp ne $defaultCssAttrs{'columnWidths'} )
299
$cssAttrs{columnWidths} = $tmp; # store string
300
$defaultCssAttrs{columnWidths} = $tmp
301
if $writeDefaults; # store string
306
$tmp = $params{headerrows};
307
if ( defined $tmp && $tmp ne '' && $tmp ne $headerRows ) {
311
$headerRows = 1 if ( $headerRows < 1 );
314
$tmp = $params{footerrows};
315
if ( defined $tmp && $tmp ne '' && $tmp ne $footerRows ) {
321
$tmp = $params{valign};
322
if ( defined $tmp && $tmp ne '' && $tmp ne $vAlign ) {
323
$vAlign = $tmp if ( defined $tmp );
326
&& ( !defined $defaultCssAttrs{'vAlign'}
327
|| $tmp ne $defaultCssAttrs{'vAlign'} )
330
$cssAttrs{vAlign} = $vAlign;
331
$defaultCssAttrs{vAlign} = $vAlign if $writeDefaults;
335
$tmp = $params{datavalign};
336
if ( defined $tmp && $tmp ne '' && $tmp ne $dataVAlign ) {
337
$dataVAlign = $tmp if ( defined $tmp );
340
&& ( !defined $defaultCssAttrs{'dataVAlign'}
341
|| $tmp ne $defaultCssAttrs{'dataVAlign'} )
344
$cssAttrs{dataVAlign} = $dataVAlign;
345
$defaultCssAttrs{dataVAlign} = $dataVAlign if $writeDefaults;
349
$tmp = $params{headervalign};
350
if ( defined $tmp && $tmp ne '' && $tmp ne $headerVAlign ) {
351
$headerVAlign = $tmp if ( defined $tmp );
354
&& ( !defined $defaultCssAttrs{'headerVAlign'}
355
|| $tmp ne $defaultCssAttrs{'headerVAlign'} )
358
$cssAttrs{headerVAlign} = $headerVAlign;
359
$defaultCssAttrs{headerVAlign} = $headerVAlign if $writeDefaults;
363
my $tmpheaderbg = $params{headerbg};
364
if ( defined $tmpheaderbg
365
&& $tmpheaderbg ne ''
366
&& $tmpheaderbg ne $headerBg )
368
$headerBg = $tmpheaderbg;
371
&& ( !defined $defaultCssAttrs{'headerBg'}
372
|| $tmpheaderbg ne $defaultCssAttrs{'headerBg'} )
375
$cssAttrs{headerBg} = $headerBg;
376
$defaultCssAttrs{headerBg} = $headerBg if $writeDefaults;
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;
388
if ( defined $tmphbgsorted
389
&& $tmphbgsorted ne ''
390
&& $tmphbgsorted ne $headerBgSorted )
392
$headerBgSorted = $tmphbgsorted;
395
&& ( !defined $defaultCssAttrs{'headerBgSorted'}
396
|| $tmphbgsorted ne $defaultCssAttrs{'headerBgSorted'} )
399
$cssAttrs{headerBgSorted} = $tmphbgsorted;
400
$defaultCssAttrs{headerBgSorted} = $tmphbgsorted if $writeDefaults;
404
$tmp = $params{headercolor};
405
if ( defined $tmp && $tmp ne '' && $tmp ne $headerColor ) {
409
&& ( !defined $defaultCssAttrs{'headerColor'}
410
|| $tmp ne $defaultCssAttrs{'headerColor'} )
413
$cssAttrs{headerColor} = $headerColor;
414
$defaultCssAttrs{headerColor} = $headerColor if $writeDefaults;
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 );
425
&& ( !defined $defaultCssAttrs{'dataBg'}
426
|| $tmpdatabg ne $defaultCssAttrs{'dataBg'} )
429
$cssAttrs{dataBg} = $tmpdatabg; # store string
430
$defaultCssAttrs{dataBg} = $tmpdatabg
431
if $writeDefaults; # store string
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;
443
if ( defined $tmpdatabgsorted && $tmpdatabgsorted ne '' ) {
444
$tmpdatabgsorted =~ s/ //go; # remove spaces
445
if ( $tmpdatabgsorted ne join( ',', @dataBgSorted ) ) {
446
@dataBgSorted = split( /,/, $tmpdatabgsorted );
449
&& ( !defined $defaultCssAttrs{'dataBgSorted'}
450
|| $tmpdatabgsorted ne $defaultCssAttrs{'dataBgSorted'} )
453
$cssAttrs{dataBgSorted} = $tmpdatabgsorted; # store string
454
$defaultCssAttrs{dataBgSorted} = $tmpdatabgsorted
455
if $writeDefaults; # store string
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 );
467
&& ( !defined $defaultCssAttrs{'dataColor'}
468
|| $tmp ne $defaultCssAttrs{'dataColor'} )
471
$cssAttrs{dataColor} = $tmp; # store string
472
$defaultCssAttrs{dataColor} = $tmp
473
if $writeDefaults; # store string
478
$tmp = $params{summary};
479
if ( defined $tmp && $tmp ne '' && $tmp ne $tableSummary ) {
480
$tableSummary = $tmp;
483
$tmp = $params{caption};
484
if ( defined $tmp && $tmp ne '' && $tmp ne $tableCaption ) {
485
$tableCaption = $tmp;
488
if ($writeDefaults) {
490
# just uncomment to write plugin settings as css styles ( .foswikiTable{ ... } )
491
#_addStylesToHead( $useCss, $writeDefaults, %defaultCssAttrs );
494
_addStylesToHead( $useCss, $writeDefaults, %cssAttrs );
497
return $currTablePre . '<nop>';
500
# Convert text to number and date if syntactically possible
501
sub _convertToNumberAndDate {
504
$text = _stripHtml($text);
506
if ( $text =~ /^\s*$/ ) {
514
$date = Foswiki::Time::parseTime($text);
515
} catch Error::Simple with {
516
# nope, wasn't a date
521
if ( $text =~ /^\s*([0-9]+)(\.[0-9]+)?/ ) {
523
# for example for attachment sizes: 1.1 K
524
# but also for other strings that start with a number
527
$num = scalar("$num1$num2");
529
elsif ( $text =~ /^\s*[0-9]+(\.[0-9]+)?\s*$/ ) {
535
return ( $num, $date );
538
sub _processTableRow {
539
my ( $thePre, $theRow ) = @_;
541
$currTablePre = $thePre || '';
546
if ( !$insideTABLE ) {
551
$currentSortDirection = $sortDirection{'NONE'};
553
if ( defined $requestedTable
554
&& $requestedTable == $tableCount
555
&& defined $sortColFromUrl )
557
$sortCol = $sortColFromUrl;
558
$sortCol = $maxSortCols if ( $sortCol > $maxSortCols );
559
$currentSortDirection = _getCurrentSortDirection($up);
561
elsif ( defined $initSort ) {
562
$sortCol = $initSort - 1;
563
$sortCol = $maxSortCols if ( $sortCol > $maxSortCols );
564
$currentSortDirection = _getCurrentSortDirection($initDirection);
569
$theRow =~ s/\t/ /go; # change tabs to space
570
$theRow =~ s/\s*$//o; # remove trailing spaces
572
s/(\|\|+)/'colspan'.$translationToken.length($1)."\|"/geo; # calc COLSPAN
578
foreach ( split( /\|/, $theRow ) ) {
582
#AS 25-5-01 Fix to avoid matching also single columns
583
if (s/colspan$translationToken([0-9]+)//) {
585
$attr->{colspan} = $span;
588
( $l1, $l2 ) = ( 0, 0 );
589
if (/^(\s*).*?(\s*)$/) {
595
$attr->{align} = 'right';
598
$attr->{align} = 'center';
603
_appendColNumberCssClass( $attr->{class}, $colCount );
605
if ( defined $columnWidths[$colCount]
606
&& $columnWidths[$colCount]
611
$attr->{width} = $columnWidths[$colCount];
614
if (/^(\s|<[^>]*>)*\^(\s|<[^>]*>)*$/) { # row span above
615
$rowspan[$colCount]++;
616
push @row, { text => $value, type => 'Y' };
619
for ( my $col = $colCount ; $col < ( $colCount + $span ) ; $col++ )
621
if ( defined( $rowspan[$col] ) && $rowspan[$col] ) {
622
my $nRows = scalar(@curTable);
623
my $rspan = $rowspan[$col] + 1;
625
$curTable[ $nRows - $rspan ][$col]->{attrs}->{rowspan} =
628
undef( $rowspan[$col] );
635
defined $requestedTable
636
&& $requestedTable == $tableCount
641
&& $colCount == $sortCol
646
if ( $currentSortDirection == $sortDirection{'ASCENDING'} ) {
648
_appendSortedAscendingCssClass( $attr->{class} );
650
if ( $currentSortDirection == $sortDirection{'DESCENDING'} ) {
652
_appendSortedDescendingCssClass( $attr->{class} );
657
if (/^\s*\*(.*)\*\s*$/) {
661
@headerAlign[ $colCount % ( $#headerAlign + 1 ) ];
664
$attr->{align} = $align;
669
$attr->{valign} = $headerVAlign if $headerVAlign;
674
$attr->{valign} = $vAlign;
679
if (/^\s*(.*?)\s*$/) { # strip white spaces
684
my $align = @dataAlign[ $colCount % ( $#dataAlign + 1 ) ];
687
$attr->{align} = $align;
692
$attr->{valign} = $dataVAlign if $dataVAlign;
697
$attr->{valign} = $vAlign;
702
push @row, { text => $value, attrs => $attr, type => $type };
704
while ( $span > 1 ) {
705
push @row, { text => $value, type => 'X' };
711
push @curTable, \@row;
713
. '<nop>'; # Avoid Foswiki converting empty lines to new paras
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 {
721
return 0 unless $sortAllTables;
723
# All cells in header are headings?
724
foreach my $cell (@$header) {
725
return 0 if ( $cell->{type} ne 'th' );
731
# Guess if column is a date, number or plain text
732
sub _guessColumnType {
738
my $columnIsValid = 0;
739
foreach my $row (@curTable) {
740
next if ( !$row->[$col]->{text} );
744
( $num, $date ) = _convertToNumberAndDate( $row->[$col]->{text} );
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;
752
return $columnType{'UNDEFINED'} if ( !$columnIsValid );
753
my $type = $columnType{'TEXT'};
755
$type = $columnType{'DATE'};
758
$type = $columnType{'NUMBER'};
763
# Remove HTML from text so it can be sorted
768
s/\[\[[^\]]+\]\[([^\]]+)\]\]/$1/go; # extract label from [[...][...]] link
771
$text; # in case we will remove all contents with stripping html
772
$text =~ s/<[^>]+>//go; # strip HTML
773
$text =~ s/\ / /go;
774
$text = _getImageTextForSorting($orgtext) if ( $text eq '' );
775
$text =~ s/[\[\]\*\|=_\&\<\>]/ /g; # remove Wiki formatting chars
776
$text =~ s/^ *//go; # strip leading space space
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.
789
sub _getImageTextForSorting {
792
# try to see _if_ there is any img data for sorting
793
my $hasImageTag = ( $text =~ m/\<\s*img([^>]+)>/ );
794
return $text if ( !$hasImageTag );
796
# first try to get the alt text
798
$text =~ m/$key=\s*[\"\']([^\"\']*)/;
799
return $1 if ( $1 ne '' );
803
# no alt text; use the url
805
$text =~ m/$key=\s*[\"\']([^\"\']*)/;
806
return $1 if ( $1 ne '' );
815
Appends $className to $classList, separated by a space.
819
sub _appendToClassList {
820
my ( $classList, $className ) = @_;
821
$classList = $classList ? $classList .= ' ' : '';
822
$classList .= $className;
826
sub _appendSortedCssClass {
827
my ($classList) = @_;
829
return _appendToClassList( $classList, 'foswikiSortedCol' );
832
sub _appendRowNumberCssClass {
833
my ( $classList, $colListName, $rowNum ) = @_;
835
my $rowClassName = 'foswikiTableRow' . $colListName . $rowNum;
836
return _appendToClassList( $classList, $rowClassName );
839
sub _appendColNumberCssClass {
840
my ( $classList, $colNum ) = @_;
842
my $colClassName = 'foswikiTableCol' . $colNum;
843
return _appendToClassList( $classList, $colClassName );
846
sub _appendFirstColumnCssClass {
847
my ($classList) = @_;
849
return _appendToClassList( $classList, 'foswikiFirstCol' );
852
sub _appendLastColumnCssClass {
853
my ($classList) = @_;
855
return _appendToClassList( $classList, 'foswikiLastCol' );
858
sub _appendLastRowCssClass {
859
my ($classList) = @_;
861
return _appendToClassList( $classList, 'foswikiLast' );
864
sub _appendSortedAscendingCssClass {
865
my ($classList) = @_;
867
return _appendToClassList( $classList, 'foswikiSortedAscendingCol' );
870
sub _appendSortedDescendingCssClass {
871
my ($classList) = @_;
873
return _appendToClassList( $classList, 'foswikiSortedDescendingCol' );
876
# The default sort direction.
877
sub _getDefaultSortDirection {
878
return $sortDirection{'ASCENDING'};
881
# Gets the current sort direction.
882
sub _getCurrentSortDirection {
883
my ($currentDirection) = @_;
884
$currentDirection ||= _getDefaultSortDirection();
885
return $currentDirection;
888
# Gets the new sort direction (needed for sort button) based on the current sort
890
sub _getNewSortDirection {
891
my ($currentDirection) = @_;
892
if ( !defined $currentDirection ) {
893
return _getDefaultSortDirection();
896
if ( $currentDirection == $sortDirection{'ASCENDING'} ) {
897
$newDirection = $sortDirection{'DESCENDING'};
899
if ( $currentDirection == $sortDirection{'DESCENDING'} ) {
900
if ($unsortEnabled) {
901
$newDirection = $sortDirection{'NONE'};
904
$newDirection = $sortDirection{'ASCENDING'};
907
if ( $currentDirection == $sortDirection{'NONE'} ) {
908
$newDirection = $sortDirection{'ASCENDING'};
910
return $newDirection;
915
Writes css styles to the head if $useCss is true (when custom attributes have been passed to
916
the TABLE{} variable.
918
Explicitly set styles override html styling (in this file marked with comment '# html attribute').
922
sub _addStylesToHead {
923
my ( $useCss, $writeDefaults, %cssAttrs ) = @_;
927
if ( !$didWriteDefaultStyle ) {
929
my $selector = '.foswikiTable';
930
my $attr = 'padding-left:.3em; vertical-align:text-bottom;';
931
push( @styles, ".tableSortIcon img {$attr}" );
934
my $attr = 'padding:' . addDefaultSizeUnit($cellPadding) . ';';
935
push( @styles, "$selector td {$attr}" );
936
push( @styles, "$selector th {$attr}" );
939
#_writeStyleToHead( $id, @styles );
940
$didWriteDefaultStyle = 1;
943
# only write default style
946
my $selector = '.foswikiTable';
947
my $id = $writeDefaults ? $writeDefaults : $cssAttrs{tableId};
948
$selector .= '#' . $id if !$writeDefaults;
951
if ( $cssAttrs{tableRules} ) {
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}" );
970
if ( $cssAttrs{tableFrame} ) {
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}" );
987
if ( defined $cssAttrs{tableBorder} ) {
988
my $tableBorderWidth = $cssAttrs{tableBorder} || 0;
990
'border-width:' . addDefaultSizeUnit($tableBorderWidth) . ';';
991
push( @styles, "$selector {$attr}" );
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}" );
1003
if ( defined $cssAttrs{tableWidth} ) {
1004
my $width = addDefaultSizeUnit( $cssAttrs{tableWidth} );
1005
my $attr = 'width:' . $width . ';';
1006
push( @styles, "$selector {$attr}" );
1010
if ( defined $cssAttrs{vAlign} ) {
1011
my $attr = 'vertical-align:' . $cssAttrs{vAlign} . ';';
1012
push( @styles, "$selector td {$attr}" );
1013
push( @styles, "$selector th {$attr}" );
1017
if ( defined $cssAttrs{headerVAlign} ) {
1018
my $attr = 'vertical-align:' . $cssAttrs{headerVAlign} . ';';
1019
push( @styles, "$selector th {$attr}" );
1023
if ( defined $cssAttrs{dataVAlign} ) {
1024
my $attr = 'vertical-align:' . $cssAttrs{dataVAlign} . ';';
1025
push( @styles, "$selector td {$attr}" );
1029
if ( defined $cssAttrs{headerBg} ) {
1030
unless ( $cssAttrs{headerBg} =~ /none/i ) {
1031
my $attr = 'background-color:' . $cssAttrs{headerBg} . ';';
1032
push( @styles, "$selector th {$attr}" );
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}" );
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};
1057
. ';background-color:'
1058
. $hoverBackgroundColor . ';';
1059
push( @styles, "$selector th a:hover {$attr}" );
1060
push( @styles, "$selector th a:hover font {$attr}" );
1064
if ( defined $cssAttrs{dataBg} ) {
1065
unless ( $cssAttrs{dataBg} =~ /none/i ) {
1067
my @attrDataBg = split( /,/, $cssAttrs{dataBg} );
1068
foreach my $color (@attrDataBg) {
1070
my $rowSelector = 'foswikiTableRow' . 'dataBg';
1071
$rowSelector .= $count;
1072
my $attr = 'background-color:' . $color . ';';
1073
push( @styles, "$selector tr.$rowSelector td {$attr}" );
1079
# databgsorted (array)
1080
if ( defined $cssAttrs{dataBgSorted} ) {
1081
unless ( $cssAttrs{dataBgSorted} =~ /none/i ) {
1083
my @attrDataBgSorted = split( /,/, $cssAttrs{dataBgSorted} );
1084
foreach my $color (@attrDataBgSorted) {
1086
my $rowSelector = 'foswikiTableRow' . 'dataBg';
1087
$rowSelector .= $count;
1088
my $attr = 'background-color:' . $color . ';';
1090
"$selector tr.$rowSelector td.foswikiSortedCol {$attr}" );
1097
if ( defined $cssAttrs{dataColor} ) {
1098
unless ( $cssAttrs{dataColor} =~ /none/i ) {
1100
my @attrDataColor = split( /,/, $cssAttrs{dataColor} );
1101
foreach my $color (@attrDataColor) {
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}" );
1114
if ( defined $cssAttrs{columnWidths} ) {
1116
my @attrColumnWidths = split( /,/, $cssAttrs{columnWidths} );
1117
foreach my $width (@attrColumnWidths) {
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}" );
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}" );
1139
foreach my $align (@attrHeaderAlign) {
1141
my $colSelector = 'foswikiTableCol';
1142
$colSelector .= $count;
1143
my $attr = 'text-align:' . $align . ';';
1144
push( @styles, "$selector th.$colSelector {$attr}" );
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}" );
1160
foreach my $align (@attrDataAlign) {
1162
my $colSelector = 'foswikiTableCol';
1163
$colSelector .= $count;
1164
my $attr = 'text-align:' . $align . ';';
1165
push( @styles, "$selector td.$colSelector {$attr}" );
1171
# cellspacing : no good css equivalent; use table tag attribute
1174
if ( defined $cssAttrs{cellPadding} ) {
1176
'padding:' . addDefaultSizeUnit( $cssAttrs{cellPadding} ) . ';';
1177
push( @styles, "$selector td {$attr}" );
1178
push( @styles, "$selector th {$attr}" );
1181
return if !scalar @styles;
1182
_writeStyleToHead( $id, @styles );
1185
sub _writeStyleToHead {
1186
my ( $id, @styles ) = @_;
1188
my $style = join( "\n", @styles );
1190
'<style type="text/css" media="all">' . "\n" . $style . "\n" . '</style>';
1191
Foswiki::Func::addToHEAD( 'TABLEPLUGIN_' . $id, $header );
1196
StaticMethod addDefaultSizeUnit ($text) -> $text
1198
Adds size unit 'px' if this is missing from the size text.
1202
sub addDefaultSizeUnit {
1206
if ( $inSize =~ m/$PATTERN_ATTRIBUTE_SIZE/ ) {
1207
$unit = 'px' if !$2;
1209
return "$inSize$unit";
1214
#Validate headerrows/footerrows and modify if out of range
1215
if ( $headerRows > @curTable ) {
1216
$headerRows = @curTable; # limit header to size of table!
1218
if ( $headerRows + $footerRows > @curTable ) {
1219
$footerRows = @curTable - $headerRows; # and footer to whatever is left
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 '';
1237
my $text = $currTablePre . CGI::start_table($tattrs);
1238
$text .= $currTablePre . CGI::caption($tableCaption) if ($tableCaption);
1241
# count the number of cols to prevent looping over non-existing columns
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} ||= {};
1252
$curTable[$r][$i]->{attrs}->{rowspan} = $rspan;
1260
&& defined $requestedTable
1261
&& $requestedTable == $tableCount
1263
|| defined $initSort
1267
# DG 08 Aug 2002: Allow multi-line headers
1268
my @header = splice( @curTable, 0, $headerRows );
1270
# DG 08 Aug 2002: Skip sorting any trailers as well
1272
if ( $footerRows && scalar(@curTable) > $footerRows ) {
1273
@trailer = splice( @curTable, -$footerRows );
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++;
1282
$maxCols = $thisRowMaxColCount
1283
if ( $thisRowMaxColCount > $maxCols );
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';
1298
$stype = $columnType{'UNDEFINED'}; # default value
1300
# only get the column type if within bounds
1301
if ( $sortCol < $maxCols ) {
1302
$stype = _guessColumnType($sortCol);
1305
# invalidate sorting if no valid column
1306
if ( $stype eq $columnType{'UNDEFINED'} ) {
1310
elsif ( $stype eq $columnType{'TEXT'} ) {
1311
if ( $currentSortDirection == $sortDirection{'DESCENDING'} ) {
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;
1319
if ( $currentSortDirection == $sortDirection{'ASCENDING'} ) {
1320
@curTable = map { $_->[0] }
1321
sort { $a->[1] cmp $b->[1] }
1322
map { [ $_, lc( $_->[$sortCol]->{text} ) ] } @curTable;
1326
if ( $currentSortDirection == $sortDirection{'DESCENDING'} ) {
1328
sort { $b->[$sortCol]->{$stype} <=> $a->[$sortCol]->{$stype} }
1331
if ( $currentSortDirection == $sortDirection{'ASCENDING'} ) {
1333
sort { $a->[$sortCol]->{$stype} <=> $b->[$sortCol]->{$stype} }
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 ...
1345
my $numberOfRows = scalar(@curTable);
1346
my $dataColorCount = 0;
1348
my @headerRowList = ();
1349
my @bodyRowList = ();
1350
my @footerRowList = ();
1352
my $isPastHeaderRows = 0;
1353
my $singleIndent = "\n\t";
1354
my $doubleIndent = "\n\t\t";
1355
my $tripleIndent = "\n\t\t\t";
1357
foreach my $row (@curTable) {
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);
1366
foreach my $fcell (@$row) {
1368
# check if cell exists
1369
next if ( !$fcell || !$fcell->{type} );
1371
my $tableAnchor = '';
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} || {};
1383
$currentSortDirection != $sortDirection{'NONE'}
1385
&& $colCount == $sortCol
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
1394
$newDirection = _getNewSortDirection($currentSortDirection);
1397
$newDirection = _getDefaultSortDirection();
1400
if ( $type eq 'th' ) {
1403
$upchar = CGI::span(
1404
{ class => 'tableSortIcon tableSortUp' },
1407
src => $iconUrl . 'tablesortup.gif',
1411
alt => 'Sorted ascending',
1412
title => 'Sorted ascending'
1416
$downchar = CGI::span(
1417
{ class => 'tableSortIcon tableSortDown' },
1420
src => $iconUrl . 'tablesortdown.gif',
1424
alt => 'Sorted descending',
1425
title => 'Sorted descending'
1429
$diamondchar = CGI::span(
1430
{ class => 'tableSortIcon tableSortUp' },
1433
src => $iconUrl . 'tablesortdiamond.gif',
1444
# DG: allow headers without b.g too (consistent and yes,
1447
$attr->{bgcolor} = $headerBg unless ( $headerBg =~ /none/i );
1449
# attribute 'maxcols' does not exist in html
1451
#$attr->{maxCols} = $maxCols;
1454
if ( $currentSortDirection == $sortDirection{'ASCENDING'} )
1456
$tableAnchor = $upchar;
1458
if ( $currentSortDirection == $sortDirection{'DESCENDING'} )
1460
$tableAnchor = $downchar;
1464
if ( defined $sortCol
1465
&& $colCount == $sortCol
1466
&& defined $requestedTable
1467
&& $requestedTable == $tableCount )
1471
CGI::a( { name => 'sorted_table' }, '<!-- -->' )
1477
my $cellAttrs = { color => $headerColor };
1480
$cell = CGI::font( $cellAttrs, $cell );
1483
if ( $sortThisTable && $rowCount == $headerRows - 1 ) {
1485
unless ( $headerBgSorted =~ /none/i ) {
1488
$attr->{bgcolor} = $headerBgSorted;
1493
my $linkAttributes = {
1498
. $tableCount . ';up='
1502
title => 'Sort by this column'
1504
if ( $cell =~ /\[\[|href/o ) {
1507
. CGI::a( $linkAttributes, $diamondchar )
1513
. CGI::a( $linkAttributes, $cell )
1524
if ( $isSorted && @dataBgSorted ) {
1526
$dataBgSorted[ $dataColorCount % (
1527
$#dataBgSorted + 1 ) ];
1531
$dataBg[ $dataColorCount % ( $#dataBg + 1 ) ];
1533
unless ( $bgcolor =~ /none/i ) {
1536
$attr->{bgcolor} = $bgcolor;
1541
$dataColor[ $dataColorCount % ( $#dataColor + 1 ) ];
1543
unless ( $color =~ /^(none)$/i ) {
1544
my $cellAttrs = { color => $color };
1547
$cell = CGI::font( $cellAttrs, ' ' . $cell . ' ' );
1550
$type = 'td' unless $type eq 'Y';
1551
} ###if( $type eq 'th' )
1554
$attr->{class} = _appendSortedCssClass( $attr->{class} );
1557
my $isLastRow = ( $rowCount == $numberOfRows - 1 );
1558
if ( $attr->{rowspan} ) {
1560
( ( $rowCount + ( $attr->{rowspan} - 1 ) ) ==
1561
$numberOfRows - 1 );
1565
$attr->{class} = _appendFirstColumnCssClass( $attr->{class} )
1567
my $isLastCol = ( $colCount == $numberOfCols - 1 );
1568
$attr->{class} = _appendLastColumnCssClass( $attr->{class} )
1571
$attr->{class} = _appendLastRowCssClass( $attr->{class} )
1575
next if ( $type eq 'Y' );
1576
my $fn = 'CGI::' . $type;
1578
$rowtext .= "$tripleIndent" . &$fn( $attr, " $cell " );
1580
} # foreach my $fcell ( @$row )
1582
# assign css class names to tr
1583
# based on settings: dataBg, dataBgSorted
1584
my $trClassName = '';
1586
# just 2 css names is too limited, but we will keep it for compatibility
1587
# with existing style sheets
1589
( $rowCount % 2 ) ? 'foswikiTableEven' : 'foswikiTableOdd';
1590
$trClassName = _appendToClassList( $trClassName, $rowTypeName );
1592
if ( scalar @dataBgSorted ) {
1593
my $modRowNum = $dataColorCount % ( $#dataBgSorted + 1 );
1595
_appendRowNumberCssClass( $trClassName, 'dataBgSorted',
1598
if ( scalar @dataBg ) {
1599
my $modRowNum = $dataColorCount % ( $#dataBg + 1 );
1601
_appendRowNumberCssClass( $trClassName, 'dataBg', $modRowNum );
1603
if ( scalar @dataColor ) {
1604
my $modRowNum = $dataColorCount % ( $#dataColor + 1 );
1606
_appendRowNumberCssClass( $trClassName, 'dataColor', $modRowNum );
1608
$rowtext .= $doubleIndent;
1610
$doubleIndent . CGI::Tr( { class => $trClassName }, $rowtext );
1612
my $isHeaderRow = ( $headerCellCount == $colCount );
1613
my $isFooterRow = ( ( $numberOfRows - $rowCount ) <= $footerRows );
1615
if ( !$isHeaderRow && !$isFooterRow ) {
1617
# don't include non-adjacent header rows to the top block of header rows
1618
$isPastHeaderRows = 1;
1622
push @footerRowList, $rowHTML;
1624
elsif ( $isHeaderRow && !$isPastHeaderRows ) {
1625
push( @headerRowList, $rowHTML );
1628
push @bodyRowList, $rowHTML;
1634
# reset data color count to start with first color after
1635
# each table heading
1636
$dataColorCount = 0;
1640
} # foreach my $row ( @curTable )
1643
"$singleIndent<thead>"
1644
. join( "", @headerRowList )
1645
. "$singleIndent</thead>";
1646
$text .= $currTablePre . $thead if scalar @headerRowList;
1649
"$singleIndent<tfoot>"
1650
. join( "", @footerRowList )
1651
. "$singleIndent</tfoot>";
1652
$text .= $currTablePre . $tfoot if scalar @footerRowList;
1655
"$singleIndent<tbody>"
1656
. join( "", @bodyRowList )
1657
. "$singleIndent</tbody>";
1658
$text .= $currTablePre . $tbody if scalar @bodyRowList;
1660
$text .= $currTablePre . CGI::end_table() . "\n";
1666
### my ( $text, $removed ) = @_;
1668
unless ($Foswiki::Plugins::TablePlugin::initialised) {
1674
my $cgi = Foswiki::Func::getCgiQuery();
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;
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;
1693
$cgi->param('sortcol'); # zero based: 0 is first column
1694
$requestedTable = $cgi->param('table');
1695
$up = $cgi->param('up');
1697
$sortTablesInText = 0;
1698
$sortAttachments = 0;
1699
my $tmp = Foswiki::Func::getPreferencesValue('TABLEPLUGIN_SORT')
1701
if ( !$tmp || $tmp =~ /^all$/oi ) {
1702
$sortTablesInText = 1;
1703
$sortAttachments = 1;
1705
elsif ( $tmp =~ /^attachments$/oi ) {
1706
$sortAttachments = 1;
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');
1715
$Foswiki::Plugins::TablePlugin::initialised = 1;
1721
my $defaultSort = $sortAllTables;
1723
my $acceptable = $sortAllTables;
1724
my @lines = split( /\r?\n/, $_[0] );
1727
s/%TABLE(?:{(.*?)})?%/_parseParameters(1,undef,Foswiki::Func::extractParameters($1))/se
1732
elsif (s/^(\s*)\|(.*\|\s*)$/_processTableRow($1,$2)/eo) {
1735
elsif ($insideTABLE) {
1736
$_ = emitTable() . $_;
1739
$sortAllTables = $defaultSort;
1740
$acceptable = $defaultSort;
1743
$_[0] = join( "\n", @lines );
1746
$_[0] .= emitTable();