← Index
NYTProf Performance Profile   « line view »
For ./view
  Run on Fri Jul 31 18:42:36 2015
Reported on Fri Jul 31 18:48:16 2015

Filename/var/www/foswikidev/core/lib/Foswiki/Plugins/TablePlugin/Core.pm
StatementsExecuted 619 statements in 9.23ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
511658µs1.54msFoswiki::Plugins::TablePlugin::Core::::handlerFoswiki::Plugins::TablePlugin::Core::handler
111152µs248µsFoswiki::Plugins::TablePlugin::Core::::_parseAttributesFoswiki::Plugins::TablePlugin::Core::_parseAttributes
621139µs139µsFoswiki::Plugins::TablePlugin::Core::::_mergeHashesFoswiki::Plugins::TablePlugin::Core::_mergeHashes
51163µs213µsFoswiki::Plugins::TablePlugin::Core::::_resetReusedVariablesFoswiki::Plugins::TablePlugin::Core::_resetReusedVariables
11157µs821µsFoswiki::Plugins::TablePlugin::Core::::_initFoswiki::Plugins::TablePlugin::Core::_init
135153µs78µsFoswiki::Plugins::TablePlugin::Core::::_debugFoswiki::Plugins::TablePlugin::Core::_debug
2121136µs36µsFoswiki::Plugins::TablePlugin::Core::::_storeAttributeFoswiki::Plugins::TablePlugin::Core::_storeAttribute
11117µs305µsFoswiki::Plugins::TablePlugin::Core::::_initDefaultsFoswiki::Plugins::TablePlugin::Core::_initDefaults
11116µs29µsFoswiki::Plugins::TablePlugin::::BEGIN@3 Foswiki::Plugins::TablePlugin::BEGIN@3
11115µs267µsFoswiki::Plugins::TablePlugin::Core::::_parseDefaultAttributesFoswiki::Plugins::TablePlugin::Core::_parseDefaultAttributes
11112µs26µsFoswiki::Plugins::TablePlugin::Core::::BEGIN@1760Foswiki::Plugins::TablePlugin::Core::BEGIN@1760
66112µs12µsFoswiki::Plugins::TablePlugin::Core::::_arrayRefFromParamFoswiki::Plugins::TablePlugin::Core::_arrayRefFromParam
11110µs13µsFoswiki::Plugins::TablePlugin::Core::::BEGIN@10Foswiki::Plugins::TablePlugin::Core::BEGIN@10
11110µs146µsFoswiki::Plugins::TablePlugin::Core::::BEGIN@11Foswiki::Plugins::TablePlugin::Core::BEGIN@11
1119µs19µsFoswiki::Plugins::TablePlugin::Core::::BEGIN@1762Foswiki::Plugins::TablePlugin::Core::BEGIN@1762
1119µs13µsFoswiki::Plugins::TablePlugin::::BEGIN@4 Foswiki::Plugins::TablePlugin::BEGIN@4
2218µs15µsFoswiki::Plugins::TablePlugin::Core::::_debugDataFoswiki::Plugins::TablePlugin::Core::_debugData
1117µs7µsFoswiki::Plugins::TablePlugin::Core::::BEGIN@8Foswiki::Plugins::TablePlugin::Core::BEGIN@8
1115µs5µsFoswiki::Plugins::TablePlugin::Core::::BEGIN@13Foswiki::Plugins::TablePlugin::Core::BEGIN@13
1114µs4µsFoswiki::Plugins::TablePlugin::Core::::BEGIN@9Foswiki::Plugins::TablePlugin::Core::BEGIN@9
2213µs3µsFoswiki::Plugins::TablePlugin::Core::::_cleanParamValueFoswiki::Plugins::TablePlugin::Core::_cleanParamValue
0000s0sFoswiki::Plugins::TablePlugin::Core::::__ANON__[:1044]Foswiki::Plugins::TablePlugin::Core::__ANON__[:1044]
0000s0sFoswiki::Plugins::TablePlugin::Core::::__ANON__[:497]Foswiki::Plugins::TablePlugin::Core::__ANON__[:497]
0000s0sFoswiki::Plugins::TablePlugin::Core::::__ANON__[:502]Foswiki::Plugins::TablePlugin::Core::__ANON__[:502]
0000s0sFoswiki::Plugins::TablePlugin::Core::::_addDefaultStylesFoswiki::Plugins::TablePlugin::Core::_addDefaultStyles
0000s0sFoswiki::Plugins::TablePlugin::Core::::_addHeadStylesFoswiki::Plugins::TablePlugin::Core::_addHeadStyles
0000s0sFoswiki::Plugins::TablePlugin::Core::::_appendColNumberCssClassFoswiki::Plugins::TablePlugin::Core::_appendColNumberCssClass
0000s0sFoswiki::Plugins::TablePlugin::Core::::_appendFirstColumnCssClassFoswiki::Plugins::TablePlugin::Core::_appendFirstColumnCssClass
0000s0sFoswiki::Plugins::TablePlugin::Core::::_appendLastColumnCssClassFoswiki::Plugins::TablePlugin::Core::_appendLastColumnCssClass
0000s0sFoswiki::Plugins::TablePlugin::Core::::_appendLastRowCssClassFoswiki::Plugins::TablePlugin::Core::_appendLastRowCssClass
0000s0sFoswiki::Plugins::TablePlugin::Core::::_appendRowNumberCssClassFoswiki::Plugins::TablePlugin::Core::_appendRowNumberCssClass
0000s0sFoswiki::Plugins::TablePlugin::Core::::_appendSortedAscendingCssClassFoswiki::Plugins::TablePlugin::Core::_appendSortedAscendingCssClass
0000s0sFoswiki::Plugins::TablePlugin::Core::::_appendSortedCssClassFoswiki::Plugins::TablePlugin::Core::_appendSortedCssClass
0000s0sFoswiki::Plugins::TablePlugin::Core::::_appendSortedDescendingCssClassFoswiki::Plugins::TablePlugin::Core::_appendSortedDescendingCssClass
0000s0sFoswiki::Plugins::TablePlugin::Core::::_appendToClassListFoswiki::Plugins::TablePlugin::Core::_appendToClassList
0000s0sFoswiki::Plugins::TablePlugin::Core::::_convertStringToDateFoswiki::Plugins::TablePlugin::Core::_convertStringToDate
0000s0sFoswiki::Plugins::TablePlugin::Core::::_convertStringToNumberFoswiki::Plugins::TablePlugin::Core::_convertStringToNumber
0000s0sFoswiki::Plugins::TablePlugin::Core::::_createCssStylesFoswiki::Plugins::TablePlugin::Core::_createCssStyles
0000s0sFoswiki::Plugins::TablePlugin::Core::::_getCurrentSortDirectionFoswiki::Plugins::TablePlugin::Core::_getCurrentSortDirection
0000s0sFoswiki::Plugins::TablePlugin::Core::::_getDefaultSortDirectionFoswiki::Plugins::TablePlugin::Core::_getDefaultSortDirection
0000s0sFoswiki::Plugins::TablePlugin::Core::::_getImageTextForSortingFoswiki::Plugins::TablePlugin::Core::_getImageTextForSorting
0000s0sFoswiki::Plugins::TablePlugin::Core::::_getIncludeParamsFoswiki::Plugins::TablePlugin::Core::_getIncludeParams
0000s0sFoswiki::Plugins::TablePlugin::Core::::_getNewSortDirectionFoswiki::Plugins::TablePlugin::Core::_getNewSortDirection
0000s0sFoswiki::Plugins::TablePlugin::Core::::_headerRowCountFoswiki::Plugins::TablePlugin::Core::_headerRowCount
0000s0sFoswiki::Plugins::TablePlugin::Core::::_parseTableSpecificTableAttributesFoswiki::Plugins::TablePlugin::Core::_parseTableSpecificTableAttributes
0000s0sFoswiki::Plugins::TablePlugin::Core::::_processTableRowFoswiki::Plugins::TablePlugin::Core::_processTableRow
0000s0sFoswiki::Plugins::TablePlugin::Core::::_setSortTypeForCellsFoswiki::Plugins::TablePlugin::Core::_setSortTypeForCells
0000s0sFoswiki::Plugins::TablePlugin::Core::::_stripHtmlFoswiki::Plugins::TablePlugin::Core::_stripHtml
0000s0sFoswiki::Plugins::TablePlugin::Core::::_writeStyleToHeadFoswiki::Plugins::TablePlugin::Core::_writeStyleToHead
0000s0sFoswiki::Plugins::TablePlugin::Core::::addDefaultSizeUnitFoswiki::Plugins::TablePlugin::Core::addDefaultSizeUnit
0000s0sFoswiki::Plugins::TablePlugin::Core::::emitTableFoswiki::Plugins::TablePlugin::Core::emitTable
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1# See bottom of file for license and copyright information
2
3229µs242µs
# spent 29µs (16+13) within Foswiki::Plugins::TablePlugin::BEGIN@3 which was called: # once (16µs+13µs) by Foswiki::Plugins::TablePlugin::preRenderingHandler at line 3
use strict;
# spent 29µs making 1 call to Foswiki::Plugins::TablePlugin::BEGIN@3 # spent 13µs making 1 call to strict::import
4232µs218µs
# spent 13µs (9+4) within Foswiki::Plugins::TablePlugin::BEGIN@4 which was called: # once (9µs+4µs) by Foswiki::Plugins::TablePlugin::preRenderingHandler at line 4
use warnings;
# spent 13µs making 1 call to Foswiki::Plugins::TablePlugin::BEGIN@4 # spent 4µs making 1 call to warnings::import
5
6package Foswiki::Plugins::TablePlugin::Core;
7
8224µs17µs
# spent 7µs within Foswiki::Plugins::TablePlugin::Core::BEGIN@8 which was called: # once (7µs+0s) by Foswiki::Plugins::TablePlugin::preRenderingHandler at line 8
use Foswiki::Func;
# spent 7µs making 1 call to Foswiki::Plugins::TablePlugin::Core::BEGIN@8
9221µs14µs
# spent 4µs within Foswiki::Plugins::TablePlugin::Core::BEGIN@9 which was called: # once (4µs+0s) by Foswiki::Plugins::TablePlugin::preRenderingHandler at line 9
use Foswiki::Plugins::TablePlugin ();
# spent 4µs making 1 call to Foswiki::Plugins::TablePlugin::Core::BEGIN@9
10228µs217µs
# spent 13µs (10+4) within Foswiki::Plugins::TablePlugin::Core::BEGIN@10 which was called: # once (10µs+4µs) by Foswiki::Plugins::TablePlugin::preRenderingHandler at line 10
use Foswiki::Time;
# spent 13µs making 1 call to Foswiki::Plugins::TablePlugin::Core::BEGIN@10 # spent 4µs making 1 call to Foswiki::Time::import
11257µs2283µs
# spent 146µs (10+137) within Foswiki::Plugins::TablePlugin::Core::BEGIN@11 which was called: # once (10µs+137µs) by Foswiki::Plugins::TablePlugin::preRenderingHandler at line 11
use Error qw(:try);
# spent 146µs making 1 call to Foswiki::Plugins::TablePlugin::Core::BEGIN@11 # spent 137µs making 1 call to Error::import
12
13
# spent 5µs within Foswiki::Plugins::TablePlugin::Core::BEGIN@13 which was called: # once (5µs+0s) by Foswiki::Plugins::TablePlugin::preRenderingHandler at line 18
BEGIN {
1416µs if ( $Foswiki::cfg{UseLocale} ) {
15 require locale;
16 import locale();
17 }
1816.57ms15µs}
# spent 5µs making 1 call to Foswiki::Plugins::TablePlugin::Core::BEGIN@13
19
201200nsmy @curTable;
211100nsmy $translationToken;
2210smy $insideTABLE;
2310smy $currTablePre;
2410smy $didWriteDefaultStyle;
2510smy $defaultAttrs; # to write generic table CSS
261100nsmy $tableSpecificAttrs; # to write table specific table CSS
271100nsmy $combinedTableAttrs; # default and specific table attributes
281800nsmy $styles = {}; # hash of default and specific styles
291600nsmy @messages = ();
30
31# not yet refactored:
321100nsmy $tableCount;
331100nsmy $sortCol;
341100nsmy $MAX_SORT_COLS;
351100nsmy $requestedTable;
361100nsmy $up;
371100nsmy $sortTablesInText;
3810smy $sortAttachments;
391100nsmy $sortColFromUrl;
4010smy $url;
4110smy $currentSortDirection;
4210smy @rowspan;
43
441400nsmy $HEAD_ID_DEFAULT_STYLE =
45 'TABLEPLUGIN_default'; # this name is part of the API, do not change
461200nsmy $HEAD_ID_SPECIFIC_STYLE =
47 'TABLEPLUGIN_specific'; # this name is part of the API, do not change
48
4912µsmy $PATTERN_TABLE = qr/%TABLE(?:{(.*?)})?%/;
5010smy $URL_ICON;
5110smy $GIF_TABLE_SORT_ASCENDING;
5210smy $GIF_TABLE_SORT_DESCENDING;
5310smy $GIF_TABLE_SORT_BOTH;
5410smy $CHAR_SORT_ASCENDING;
5510smy $CHAR_SORT_DESCENDING;
5610smy $CHAR_SORT_BOTH;
57
5810smy $SORT_DIRECTION;
59
601800nsmy $PATTERN_ATTRIBUTE_SIZE = qr'([0-9]+)(px|%)*'o;
61
6212µsmy $TABLE_RULES = {};
6313µs$TABLE_RULES->{all}->{TD} = $TABLE_RULES->{all}->{TH} =
64 $TABLE_RULES->{data_all}->{TD} = $TABLE_RULES->{header_all}->{TH} =
65 'border-style:solid';
6612µs$TABLE_RULES->{none}->{TD} = $TABLE_RULES->{none}->{TH} =
67 $TABLE_RULES->{data_none}->{TD} = $TABLE_RULES->{header_none}->{TH} =
68 'border-style:none';
6912µs$TABLE_RULES->{cols}->{TD} = $TABLE_RULES->{cols}->{TH} =
70 $TABLE_RULES->{data_cols}->{TD} = $TABLE_RULES->{header_cols}->{TH} =
71 'border-style:none solid';
7211µs$TABLE_RULES->{rows}->{TD} = $TABLE_RULES->{rows}->{TH} =
73 $TABLE_RULES->{data_rows}->{TD} = $TABLE_RULES->{header_rows}->{TH} =
74 'border-style:solid none';
751500ns$TABLE_RULES->{groups}->{TD} = 'border-style:none';
761400ns$TABLE_RULES->{groups}->{TH} = 'border-style:solid none';
77
781200nsmy $TABLE_FRAME = {};
791400ns$TABLE_FRAME->{void} = 'border-style:none';
801400ns$TABLE_FRAME->{above} = 'border-style:solid none none none';
811300ns$TABLE_FRAME->{below} = 'border-style:none none solid none';
821300ns$TABLE_FRAME->{lhs} = 'border-style:none none none solid';
831300ns$TABLE_FRAME->{rhs} = 'border-style:none solid none none';
841300ns$TABLE_FRAME->{hsides} = 'border-style:solid none solid none';
851300ns$TABLE_FRAME->{vsides} = 'border-style:none solid none solid';
861700ns$TABLE_FRAME->{box} = 'border-style:solid';
871300ns$TABLE_FRAME->{border} = 'border-style:solid';
88
89
# spent 821µs (57+764) within Foswiki::Plugins::TablePlugin::Core::_init which was called: # once (57µs+764µs) by Foswiki::Plugins::TablePlugin::preRenderingHandler at line 80 of /var/www/foswikidev/core/lib/Foswiki/Plugins/TablePlugin.pm
sub _init {
9011µs19µs _debug("_init");
# spent 9µs making 1 call to Foswiki::Plugins::TablePlugin::Core::_debug
911400ns $translationToken = "\0";
92
93 # the maximum number of columns we will handle
941200ns $MAX_SORT_COLS = 10000;
951100ns $didWriteDefaultStyle = 0;
961100ns $tableCount = 0;
971200ns $currTablePre = '';
981400ns $combinedTableAttrs = {};
991200ns $tableSpecificAttrs = {};
1001800ns $styles = {};
10114µs132µs $URL_ICON =
# spent 32µs making 1 call to Foswiki::Func::getPubUrlPath
102 Foswiki::Func::getPubUrlPath() . '/'
103 . $Foswiki::cfg{SystemWebName}
104 . '/DocumentGraphics/';
105110µs1232µs $GIF_TABLE_SORT_ASCENDING = CGI::img(
# spent 232µs making 1 call to CGI::AUTOLOAD
106 {
107 src => $URL_ICON . 'tablesortup.gif',
108 border => 0,
109 width => 11,
110 height => 13,
111 alt => 'Sorted ascending',
112 title => 'Sorted ascending'
113 }
114 );
115
11614µs156µs $GIF_TABLE_SORT_DESCENDING = CGI::img(
# spent 56µs making 1 call to CGI::img
117 {
118 src => $URL_ICON . 'tablesortdown.gif',
119 border => 0,
120 width => 11,
121 height => 13,
122 alt => 'Sorted descending',
123 title => 'Sorted descending'
124 }
125 );
126
12714µs155µs $GIF_TABLE_SORT_BOTH = CGI::img(
# spent 55µs making 1 call to CGI::img
128 {
129 src => $URL_ICON . 'tablesortdiamond.gif',
130 border => 0,
131 width => 11,
132 height => 13,
133 alt => 'Sort',
134 title => 'Sort'
135 }
136 );
13714µs1202µs $CHAR_SORT_ASCENDING = CGI::span( { class => 'tableSortIcon tableSortUp' },
# spent 202µs making 1 call to CGI::AUTOLOAD
138 $GIF_TABLE_SORT_ASCENDING );
13912µs128µs $CHAR_SORT_DESCENDING =
# spent 28µs making 1 call to CGI::span
140 CGI::span( { class => 'tableSortIcon tableSortDown' },
141 $GIF_TABLE_SORT_DESCENDING );
14212µs126µs $CHAR_SORT_BOTH = CGI::span( { class => 'tableSortIcon tableSortUp' },
# spent 26µs making 1 call to CGI::span
143 $GIF_TABLE_SORT_BOTH );
144
14515µs $SORT_DIRECTION = {
146 'ASCENDING' => 0,
147 'DESCENDING' => 1,
148 'NONE' => 2,
149 };
150}
151
152# called one time
153
# spent 305µs (17+289) within Foswiki::Plugins::TablePlugin::Core::_initDefaults which was called: # once (17µs+289µs) by Foswiki::Plugins::TablePlugin::Core::handler at line 1930
sub _initDefaults {
1541900ns15µs _debug('_initDefaults');
# spent 5µs making 1 call to Foswiki::Plugins::TablePlugin::Core::_debug
15512µs $defaultAttrs = {
156 headerrows => 0,
157 footerrows => 0,
158 sort => 1,
159 class => 'foswikiTable',
160 sortAllTables => $sortTablesInText,
161 };
16215µs1267µs _parseDefaultAttributes(
163 %{Foswiki::Plugins::TablePlugin::pluginAttributes} );
164
16515µs116µs $combinedTableAttrs = _mergeHashes( {}, $defaultAttrs );
# spent 16µs making 1 call to Foswiki::Plugins::TablePlugin::Core::_mergeHashes
166}
167
168sub _addDefaultStyles {
169 return if $Foswiki::Plugins::TablePlugin::writtenToHead;
170 $Foswiki::Plugins::TablePlugin::writtenToHead = 1;
171
172 # create CSS styles tables in general
173 my ( $id, @styles ) = _createCssStyles( 1, $defaultAttrs );
174 _addHeadStyles( $HEAD_ID_DEFAULT_STYLE, @styles ) if scalar(@styles);
175}
176
177
# spent 213µs (63+150) within Foswiki::Plugins::TablePlugin::Core::_resetReusedVariables which was called 5 times, avg 43µs/call: # 5 times (63µs+150µs) by Foswiki::Plugins::TablePlugin::Core::handler at line 1968, avg 43µs/call
sub _resetReusedVariables {
17855µs527µs _debug('_resetReusedVariables');
# spent 27µs making 5 calls to Foswiki::Plugins::TablePlugin::Core::_debug, avg 5µs/call
17952µs $currTablePre = '';
180524µs5122µs $combinedTableAttrs = _mergeHashes( {}, $defaultAttrs );
# spent 122µs making 5 calls to Foswiki::Plugins::TablePlugin::Core::_mergeHashes, avg 24µs/call
18153µs $tableSpecificAttrs = {};
18251µs $sortCol = 0;
183517µs @messages = ();
184}
185
186=pod
187
188=cut
189
190
# spent 36µs within Foswiki::Plugins::TablePlugin::Core::_storeAttribute which was called 21 times, avg 2µs/call: # once (3µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 335 # once (3µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 375 # once (2µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 380 # once (2µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 398 # once (2µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 392 # once (2µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 400 # once (2µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 381 # once (2µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 395 # once (2µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 336 # once (2µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 377 # once (2µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 393 # once (2µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 394 # once (2µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 338 # once (2µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 340 # once (1µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 382 # once (1µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 386 # once (1µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 383 # once (1µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 339 # once (1µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 408 # once (1µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 405 # once (1µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 389
sub _storeAttribute {
1912111µs my ( $inAttrName, $inValue, $inCollection ) = @_;
192
193213µs if ( !$inCollection ) {
194 _debug('_storeAttribute -- missing inCollection!');
195 return;
196 }
1972138µs return if !defined $inValue;
19882µs return if !defined $inAttrName || $inAttrName eq '';
199829µs $inCollection->{$inAttrName} = $inValue;
200}
201
202=pod
203
204=cut
205
206
# spent 267µs (15+252) within Foswiki::Plugins::TablePlugin::Core::_parseDefaultAttributes which was called: # once (15µs+252µs) by Foswiki::Plugins::TablePlugin::Core::_initDefaults at line 162
sub _parseDefaultAttributes {
20717µs my (%params) = @_;
208
20911µs14µs _debug('_parseDefaultAttributes');
# spent 4µs making 1 call to Foswiki::Plugins::TablePlugin::Core::_debug
210
21114µs1248µs _parseAttributes( 0, $defaultAttrs, \%params );
212}
213
214=pod
215
216=cut
217
218sub _parseTableSpecificTableAttributes {
219 my (%params) = @_;
220
221 _debug('_parseTableSpecificTableAttributes');
222
223 _parseAttributes( 1, $tableSpecificAttrs, \%params );
224
225 # remove default values from hash
226 while ( my ( $key, $value ) = each %{$tableSpecificAttrs} ) {
227 delete $tableSpecificAttrs->{$key}
228 if $defaultAttrs->{$key} && $value eq $defaultAttrs->{$key};
229 }
230 $combinedTableAttrs =
231 _mergeHashes( $combinedTableAttrs, $tableSpecificAttrs );
232 _debugData( 'combinedTableAttrs', $combinedTableAttrs );
233
234 # create CSS styles for this table only
235 my ( $id, @styles ) = _createCssStyles( 0, $tableSpecificAttrs );
236 _debugData( "after _createCssStyles, id=$id; styles", \@styles );
237
238 _addHeadStyles( $id, @styles ) if scalar(@styles);
239
240 return $currTablePre . '<nop>';
241}
242
243=pod
244
245=cut
246
247
# spent 248µs (152+96) within Foswiki::Plugins::TablePlugin::Core::_parseAttributes which was called: # once (152µs+96µs) by Foswiki::Plugins::TablePlugin::Core::_parseDefaultAttributes at line 211
sub _parseAttributes {
2481500ns my ( $isTableSpecific, $inCollection, $inParams ) = @_;
249
25012µs19µs _debugData( "isTableSpecific=$isTableSpecific; _parseAttributes=",
# spent 9µs making 1 call to Foswiki::Plugins::TablePlugin::Core::_debugData
251 $inParams );
252
253 # include topic to read definitions
2541300ns if ( $inParams->{include} ) {
255 my ( $includeParams, $message ) =
256 _getIncludeParams( $inParams->{include} );
257
258 if ($includeParams) {
259 $inParams = $includeParams;
260 }
261 if ($message) {
262 push( @messages, $message );
263 }
264 }
265
266 # table attributes
267 # some will be used for css styling as well
268
2691200ns _storeAttribute( 'generateInlineMarkup',
270 Foswiki::Func::isTrue( $inParams->{inlinemarkup} ),
271 $inCollection )
272 if defined $inParams->{inlinemarkup};
273
274 # sort attributes
2751300ns if ( defined $inParams->{sort} ) {
276 my $sort = Foswiki::Func::isTrue( $inParams->{sort} );
277 _storeAttribute( 'sort', $sort, $inCollection );
278 _storeAttribute( 'sortAllTables', $sort, $inCollection );
279 }
2801200ns if ( defined( $inParams->{initsort} )
281 and int( $inParams->{initsort} ) > 0 )
282 {
283 _storeAttribute( 'initSort', $inParams->{initsort}, $inCollection );
284
285 # override sort attribute: we are sorting after all
286 _storeAttribute( 'sort', 1, $inCollection );
287 }
288
2891200ns if ( $inParams->{initdirection} ) {
290 _storeAttribute( 'initDirection', $SORT_DIRECTION->{'ASCENDING'},
291 $inCollection )
292 if $inParams->{initdirection} =~ /^down$/i;
293 _storeAttribute( 'initDirection', $SORT_DIRECTION->{'DESCENDING'},
294 $inCollection )
295 if $inParams->{initdirection} =~ /^up$/i;
296 }
297
298 # Don't allow sort requests when rendering for static use.
299 # Force sort=off but allow initsort / initdirection
30011µs11µs my $context = Foswiki::Func::getContext();
# spent 1µs making 1 call to Foswiki::Func::getContext
3011400ns if ( $context->{static} ) {
302 delete $inCollection->{sortAllTables};
303 }
304
305 # If EditTablePlugin is installed and we are editing a table,
306 # the CGI parameter 'sort' is defined as "off" to disable all
307 # header sorting ((Item5135)
30811µs14µs my $cgi = Foswiki::Func::getCgiQuery();
# spent 4µs making 1 call to Foswiki::Func::getCgiQuery
30912µs118µs my $urlParamSort = $cgi->param('sort');
# spent 18µs making 1 call to Foswiki::Request::param
3101200ns if ( $urlParamSort && $urlParamSort =~ /^off$/oi ) {
311 delete $inCollection->{sortAllTables};
312 }
313
314 # If EditTablePlugin is installed and we are editing a table, the
315 # 'disableallsort' TABLE parameter is added to disable initsort and header
316 # sorting in the table that is being edited. (Item5135)
31713µs15µs if ( Foswiki::Func::isTrue( $inParams->{disableallsort} ) ) {
# spent 5µs making 1 call to Foswiki::Func::isTrue
318 $inCollection->{sortAllTables} = 0;
319 delete $inCollection->{initSort};
320 }
321
3221200ns if ($isTableSpecific) {
323
324 _storeAttribute( 'summary', $inParams->{summary}, $inCollection );
325 my $id =
326 defined $inParams->{id}
327 ? $inParams->{id}
328 : 'table'
329 . $Foswiki::Plugins::TablePlugin::topic
330 . ( $tableCount + 1 );
331 _storeAttribute( 'id', $id, $inCollection );
332 _storeAttribute( 'headerrows', $inParams->{headerrows}, $inCollection );
333 _storeAttribute( 'footerrows', $inParams->{footerrows}, $inCollection );
334 }
33511µs13µs _storeAttribute( 'border', $inParams->{tableborder}, $inCollection );
33612µs12µs _storeAttribute( 'tableBorderColor', $inParams->{tablebordercolor},
337 $inCollection );
33811µs12µs _storeAttribute( 'cellpadding', $inParams->{cellpadding}, $inCollection );
33911µs11µs _storeAttribute( 'cellspacing', $inParams->{cellspacing}, $inCollection );
34012µs12µs _storeAttribute( 'frame', $inParams->{tableframe}, $inCollection );
341
342 # tablerules css settings
3431400ns my @tableRulesList = ();
3441500ns if ( $inParams->{tablerules} ) {
345
346 # store tablerules as array, so that headerrules and datarules
347 # can be appended to that list
34811µs12µs my $param = _cleanParamValue( $inParams->{tablerules} );
3491700ns if ($param) {
350 push( @tableRulesList, $param );
351 }
352 }
3531400ns if ( $inParams->{headerrules} ) {
35411µs11µs my $param = _cleanParamValue( $inParams->{headerrules} );
3551300ns if ($param) {
3561600ns $param = "header_$param";
3571400ns push( @tableRulesList, $param );
358 }
359 }
3601300ns if ( $inParams->{datarules} ) {
361 my $param = _cleanParamValue( $inParams->{datarules} );
362 if ($param) {
363 $param = "data_$param";
364 push( @tableRulesList, $param );
365 }
366 }
3671700ns $inCollection->{tableRules} = \@tableRulesList if scalar(@tableRulesList);
368
369 # use 'rules' as table attribute only (not to define css styles)
370 # but set to
3711500ns my $rules =
372 ( defined $inParams->{headerrules} || defined $inParams->{datarules} )
373 ? 'none'
374 : $inParams->{tablerules};
3751900ns13µs _storeAttribute( 'rules', $rules, $inCollection );
376
37712µs12µs _storeAttribute( 'width', $inParams->{tablewidth}, $inCollection );
378
379 # css attributes
38011µs12µs _storeAttribute( 'headerColor', $inParams->{headercolor}, $inCollection );
3811900ns12µs _storeAttribute( 'headerBg', $inParams->{headerbg}, $inCollection );
38211µs11µs _storeAttribute( 'cellBorder', $inParams->{cellborder}, $inCollection );
38312µs23µs _storeAttribute( 'headerAlignListRef',
384 _arrayRefFromParam( $inParams->{headeralign} ),
385 $inCollection );
38612µs23µs _storeAttribute( 'dataAlignListRef',
387 _arrayRefFromParam( $inParams->{dataalign} ),
388 $inCollection );
38912µs22µs _storeAttribute( 'columnWidthsListRef',
390 _arrayRefFromParam( $inParams->{columnwidths} ),
391 $inCollection );
39211µs12µs _storeAttribute( 'vAlign', $inParams->{valign} || 'top', $inCollection );
39312µs12µs _storeAttribute( 'dataVAlign', $inParams->{datavalign}, $inCollection );
39412µs12µs _storeAttribute( 'headerVAlign', $inParams->{headervalign}, $inCollection );
39511µs12µs _storeAttribute( 'headerBgSorted',
396 $inParams->{headerbgsorted} || $inParams->{headerbg},
397 $inCollection );
39812µs26µs _storeAttribute( 'dataBgListRef', _arrayRefFromParam( $inParams->{databg} ),
399 $inCollection );
40012µs25µs _storeAttribute(
401 'dataBgSortedListRef',
402 _arrayRefFromParam( $inParams->{databgsorted} || $inParams->{databg} ),
403 $inCollection
404 );
40512µs23µs _storeAttribute( 'dataColorListRef',
406 _arrayRefFromParam( $inParams->{datacolor} ),
407 $inCollection );
40811µs11µs _storeAttribute( 'tableCaption', $inParams->{caption}, $inCollection );
409
410 # remove empty attributes
411119µs while ( my ( $key, $value ) = each %{$inCollection} ) {
412 delete $inCollection->{$key} if !defined $value || $value eq '';
413 }
414
41516µs16µs _debugData( '_parseAttributes result:', $inCollection );
# spent 6µs making 1 call to Foswiki::Plugins::TablePlugin::Core::_debugData
416}
417
418=pod
419
420_getIncludeParams( $includeTopic ) -> \%params
421
422From $includeTopic read the first TABLE tag and return its parameters.
423
424=cut
425
426sub _getIncludeParams {
427 my ($inIncludeTopic) = @_;
428
429 my ( $includeWeb, $includeTopic ) =
430 Foswiki::Func::normalizeWebTopicName( $Foswiki::Plugins::TablePlugin::web,
431 $inIncludeTopic );
432
433 _debug("_getIncludeParams:$inIncludeTopic");
434 _debug("\t includeTopic=$includeTopic") if $includeTopic;
435
436 if ( !Foswiki::Func::topicExists( $includeWeb, $includeTopic ) ) {
437 _debug("TablePlugin: included topic $inIncludeTopic does not exist.");
438 return ( undef,
439'%MAKETEXT{"Warning: \'include\' topic <nop>[_1] does not exist!" args="'
440 . "$includeWeb.$includeTopic"
441 . '"}%' );
442 }
443 else {
444
445 my $text = Foswiki::Func::readTopicText( $includeWeb, $includeTopic );
446
447 if ( $text =~ m/$PATTERN_TABLE/s ) {
448 _debug("\t PATTERN_TABLE=$PATTERN_TABLE; 1=$1");
449 my $paramString = $1;
450
451 if ( $includeWeb ne $Foswiki::Plugins::TablePlugin::web
452 || $includeTopic ne $Foswiki::Plugins::TablePlugin::topic )
453 {
454
455 # expand common vars, except oneself to prevent recursion
456 $paramString =
457 Foswiki::Func::expandCommonVariables( $paramString,
458 $includeTopic, $includeWeb );
459 }
460 my %params = Foswiki::Func::extractParameters($paramString);
461 return ( \%params, undef );
462 }
463 else {
464 return ( undef,
465'%MAKETEXT{"Warning: table definition in \'include\' topic [_1] does not exist!" args="'
466 . "$includeWeb.$includeTopic"
467 . '"}%' );
468 }
469 }
470}
471
472=pod
473
474_convertStringToDate ( $text ) -> $number
475
476Convert text to number if syntactically possible, otherwise return undef.
477Assumes that the text has been stripped from HTML markup.
478
479=cut
480
481sub _convertStringToDate {
482 my ($text) = @_;
483
484 return undef if !defined $text;
485 return undef if $text eq '';
486 return undef if ( $text =~ /^\s*$/ );
487
488 my $date = undef;
489
490 if ( $text =~ /^\s*-?[0-9]+(\.[0-9])*\s*$/ ) {
491 _debug("\t this is a number");
492 }
493 else {
494 try {
495 $date = Foswiki::Time::parseTime($text);
496 _debug("\t is a date");
497 }
498 catch Error::Simple with {
499
500 # nope, wasn't a date
501 _debug("\t $text is not a date");
502 };
503 }
504
505 return $date;
506}
507
508=pod
509
510_convertStringToNumber ( $text ) -> $number
511
512Convert text to number if syntactically possible, otherwise return undef.
513Assumes that the text has been stripped from HTML markup.
514
515=cut
516
517sub _convertStringToNumber {
518 my ($text) = @_;
519
520 return undef if !defined $text;
521 return undef if $text eq '';
522 return undef if ( $text =~ /^\s*$/ );
523
524 # very course testing on IP (could in fact be anything with n.n. syntax
525 if (
526 $text =~ m/
527 ^
528 \s* # any space
529 (?: # don't need to capture
530 [0-9]+ # digits
531 \. # dot
532 ) #
533 {2,} # repeat more than once: exclude decimal numbers
534 .*? # any string
535 $
536 /x
537 )
538 {
539 _debug("\t $text looks like an IP address, or something similar");
540
541 # should be sorted by text
542 return undef;
543 }
544
545 if (
546 $text =~ m/
547 ^
548 \s* # any space
549 ( #
550 -* # possible minus
551 [0-9]+ # digits
552 \.* # possible decimal
553 [0-9]* # possible fracture digits
554 ) # end capture of number
555 .*$ # any string
556 /x
557 )
558 {
559
560 _debug("\t $1 is a number");
561
562 # make sure to return a number, not a string
563 return $1 * 1.0;
564 }
565 return undef;
566}
567
568sub _processTableRow {
569 my ( $thePre, $theRow ) = @_;
570
571 $currTablePre = $thePre || '';
572 my $span = 0;
573 my $l1 = 0;
574 my $l2 = 0;
575
576 if ( !$insideTABLE ) {
577 @curTable = ();
578 @rowspan = ();
579
580 $tableCount++;
581 $currentSortDirection = $SORT_DIRECTION->{'NONE'};
582
583 if ( defined $requestedTable
584 && $requestedTable == $tableCount
585 && defined $sortColFromUrl )
586 {
587 $sortCol = $sortColFromUrl;
588 $sortCol = 0 unless ( $sortCol =~ m/^[0-9]+$/ );
589 $sortCol = $MAX_SORT_COLS if ( $sortCol > $MAX_SORT_COLS );
590 $currentSortDirection = _getCurrentSortDirection($up);
591 }
592 elsif ( defined $combinedTableAttrs->{initSort} ) {
593 $sortCol = $combinedTableAttrs->{initSort} - 1;
594 $sortCol = $MAX_SORT_COLS if ( $sortCol > $MAX_SORT_COLS );
595 $currentSortDirection =
596 _getCurrentSortDirection( $combinedTableAttrs->{initDirection} );
597 }
598 }
599
600 $theRow =~ s/\t/ /go; # change tabs to space
601 $theRow =~ s/\s*$//o; # remove trailing spaces
602 $theRow =~
603 s/(\|\|+)/'colspan'.$translationToken.length($1)."\|"/geo; # calc COLSPAN
604 my $colCount = 0;
605 my @row = ();
606 $span = 0;
607 my $value = '';
608
609 foreach ( split( /\|/, $theRow ) ) {
610 my $attr = {};
611 $span = 1;
612
613 # Item13309: adjust for ERP empty column
614 if ( !$tableSpecificAttrs->{sort_adjusted}
615 && $colCount == 0
616 && /erpJS_willDiscard/ )
617 {
618 if ( $combinedTableAttrs->{initSort} ) {
619 $combinedTableAttrs->{initSort}++;
620 $sortCol++;
621 }
622
623 $tableSpecificAttrs->{sort_adjusted} = 1;
624 }
625
626 #AS 25-5-01 Fix to avoid matching also single columns
627 if (s/colspan$translationToken([0-9]+)//) {
628 $span = $1;
629 $attr->{colspan} = $span;
630 }
631 s/^\s+$/ &nbsp; /o;
632 ( $l1, $l2 ) = ( 0, 0 );
633 if (/^(\s*).*?(\s*)$/) {
634 $l1 = length($1);
635 $l2 = length($2);
636 }
637 if ( $l1 >= 2 ) {
638 if ( $l2 <= 1 ) {
639 $attr->{style} = 'text-align:right';
640 }
641 else {
642 $attr->{style} = 'text-align:center';
643 }
644 }
645 if ( $span <= 2 ) {
646 $attr->{class} =
647 _appendColNumberCssClass( $attr->{class}, $colCount );
648 }
649
650 # html attribute: (column) width
651 if ( $combinedTableAttrs->{generateInlineMarkup}
652 && defined $combinedTableAttrs->{columnWidthsListRef} )
653 {
654 my @columnWidths = @{ $combinedTableAttrs->{columnWidthsListRef} };
655 if ( defined $columnWidths[$colCount]
656 && $columnWidths[$colCount]
657 && $span <= 2 )
658 {
659 $attr->{width} = $columnWidths[$colCount];
660 }
661 }
662
663 # END html attribute
664
665 if (/^(\s|<[^>]*>)*\^(\s|<[^>]*>)*$/) { # row span above
666 $rowspan[$colCount]++;
667 push @row, { text => $value, type => 'Y' };
668 }
669 else {
670 for ( my $col = $colCount ; $col < ( $colCount + $span ) ; $col++ )
671 {
672 if ( defined( $rowspan[$col] ) && $rowspan[$col] ) {
673 my $nRows = scalar(@curTable);
674 my $rspan = $rowspan[$col] + 1;
675 if ( $rspan > 1 ) {
676 $curTable[ $nRows - $rspan ][$col]->{attrs}->{rowspan} =
677 $rspan;
678 }
679 undef( $rowspan[$col] );
680 }
681 }
682
683 if (
684 (
685 (
686 defined $requestedTable
687 && $requestedTable == $tableCount
688 )
689 || defined $combinedTableAttrs->{initSort}
690 )
691 && defined $sortCol
692 && $colCount == $sortCol
693 )
694 {
695
696 # CSS class name
697 if ( $currentSortDirection == $SORT_DIRECTION->{'ASCENDING'} ) {
698 $attr->{class} =
699 _appendSortedAscendingCssClass( $attr->{class} );
700 }
701 if ( $currentSortDirection == $SORT_DIRECTION->{'DESCENDING'} )
702 {
703 $attr->{class} =
704 _appendSortedDescendingCssClass( $attr->{class} );
705 }
706 }
707 my $type = '';
708
709 # Fixup for EditRowPlugin - add ** if erpJS_sort
710 s/(.*)/*$1*/ if /erpJS_sort \{headrows: \d/;
711
712 if (/^\s*\*(.*)\*\s*$/) {
713 $value = $1;
714 $type = 'th';
715
716 # html attribute: align
717 if ( $combinedTableAttrs->{generateInlineMarkup}
718 && defined $combinedTableAttrs->{headerAlignListRef} )
719 {
720 my @headerAlign =
721 @{ $combinedTableAttrs->{headerAlignListRef} };
722 if (@headerAlign) {
723 my $align =
724 @headerAlign[ $colCount % ( $#headerAlign + 1 ) ];
725 $attr->{style} = "text-align:$align";
726 }
727 }
728
729 # END html attribute
730
731 # html attribute: valign
732 if ( $combinedTableAttrs->{generateInlineMarkup} ) {
733 if ( defined $combinedTableAttrs->{headerVAlign} ) {
734 $attr->{valign} = $combinedTableAttrs->{headerVAlign};
735 }
736 elsif ( defined $combinedTableAttrs->{vAlign} ) {
737 $attr->{valign} = $combinedTableAttrs->{vAlign};
738 }
739 }
740
741 # END html attribute
742 }
743 else {
744 if (/^\s*(.*?)\s*$/) { # strip white spaces
745 $_ = $1;
746 }
747 $value = $_;
748 $type = 'td';
749
750 # html attribute: align
751 if ( $combinedTableAttrs->{generateInlineMarkup}
752 && defined $combinedTableAttrs->{dataAlignListRef} )
753 {
754 my @dataAlign =
755 @{ $combinedTableAttrs->{dataAlignListRef} };
756 if (@dataAlign) {
757 my $align =
758 @dataAlign[ $colCount % ( $#dataAlign + 1 ) ];
759 $attr->{style} = "text-align:$align";
760 }
761 }
762
763 # END html attribute
764
765 # html attribute: valign
766 if ( $combinedTableAttrs->{generateInlineMarkup} ) {
767 if ( defined $combinedTableAttrs->{dataVAlign} ) {
768 $attr->{valign} = $combinedTableAttrs->{dataVAlign};
769 }
770 elsif ( defined $combinedTableAttrs->{vAlign} ) {
771 $attr->{valign} = $combinedTableAttrs->{vAlign};
772 }
773 }
774
775 # END html attribute
776 }
777
778 push @row, { text => $value, attrs => $attr, type => $type };
779 }
780 while ( $span > 1 ) {
781 push @row, { text => $value, type => 'X' };
782 $colCount++;
783 $span--;
784 }
785 $colCount++;
786 }
787 push @curTable, \@row;
788 return $currTablePre
789 . '<nop>'; # Avoid Foswiki converting empty lines to new paras
790}
791
792sub _headerRowCount {
793 my ($table) = @_;
794
795 my $headerCount = 0;
796 my $footerCount = 0;
797 my $endheader = 0;
798
799 # All cells in header are headings?
800 foreach my $row (@$table) {
801 my $isHeader = 1;
802 foreach my $cell (@$row) {
803 if ( $cell->{type} ne 'th' ) {
804 $isHeader = 0;
805 $endheader = 1;
806 $footerCount = 0 if $footerCount;
807 }
808 }
809 unless ($endheader) {
810 $headerCount++ if $isHeader;
811 }
812 else {
813 $footerCount++ if $isHeader;
814 }
815 }
816
817 # Some cells came after the footer - so there isn't one.
818 $footerCount = 0 if ( $endheader > 1 );
819
820 return ( $headerCount, $footerCount );
821}
822
823=pod
824
825_setSortTypeForCells ( $col, \@table )
826
827Sets a sort key for each cell.
828
829=cut
830
831sub _setSortTypeForCells {
832 my ( $col, $table ) = @_;
833
834 foreach my $row ( @{$table} ) {
835
836 my $rowText = _stripHtml( $row->[$col]->{text} );
837
838 my $num = _convertStringToNumber($rowText);
839 my $date = _convertStringToDate($rowText);
840
841 $row->[$col]->{sortText} = '';
842 $row->[$col]->{number} = 0;
843 $row->[$col]->{dateString} = '';
844
845 if ( defined $date ) {
846
847 # date has just converted to a number
848 $row->[$col]->{number} = $date;
849
850 # add dateString value in case dates are equal
851 $row->[$col]->{dateString} = $rowText;
852 }
853 elsif ( defined $num ) {
854 $row->[$col]->{number} = $num;
855
856# when sorting mixed numbers and text, make the text sort value as low as possible
857 $row->[$col]->{sortText} = ' ';
858 }
859 else {
860 $row->[$col]->{sortText} = lc $rowText;
861 }
862
863 }
864}
865
866# Remove HTML from text so it can be sorted
867sub _stripHtml {
868 my ($text) = @_;
869
870 return undef if !defined $text;
871 $text =~
872 s/\[\[[^\]]+\]\[([^\]]+)\]\]/$1/go; # extract label from [[...][...]] link
873
874 my $orgtext =
875 $text; # in case we will have removed all contents with stripping html
876 $text =~ s/<[^>]+>//go; # strip HTML
877 $text =~ s/\&nbsp;/ /go;
878 $text = _getImageTextForSorting($orgtext) if ( $text eq '' );
879 $text =~ s/[\[\]\*\|=_\&\<\>]/ /g; # remove Wiki formatting chars
880 $text =~ s/^ *//go; # strip leading space space
881
882 return $text;
883}
884
885=pod
886
887Retrieve text data from an image html tag to be used for sorting.
888First try the alt tag string. If not available, return the url string.
889If not available, return the original string.
890
891=cut
892
893sub _getImageTextForSorting {
894 my ($text) = @_;
895
896 # try to see _if_ there is any img data for sorting
897 my $hasImageTag = ( $text =~ m/\<\s*img([^>]+)>/ );
898 return $text if ( !$hasImageTag );
899
900 # first try to get the alt text
901 my $key = 'alt';
902 $text =~ m/$key=\s*[\"\']([^\"\']*)/;
903 return $1 if ( $1 ne '' );
904
905 # else
906
907 # no alt text; use the url
908 $key = 'url';
909 $text =~ m/$key=\s*[\"\']([^\"\']*)/;
910 return $1 if ( $1 ne '' );
911
912 # else
913
914 return $text;
915}
916
917=pod
918
919Appends $className to $classList, separated by a space.
920
921=cut
922
923sub _appendToClassList {
924 my ( $classList, $className ) = @_;
925 $classList = $classList ? $classList .= ' ' : '';
926 $classList .= $className;
927 return $classList;
928}
929
930sub _appendSortedCssClass {
931 my ($classList) = @_;
932
933 return _appendToClassList( $classList, 'foswikiSortedCol' );
934}
935
936sub _appendRowNumberCssClass {
937 my ( $classList, $colListName, $rowNum ) = @_;
938
939 my $rowClassName = 'foswikiTableRow' . $colListName . $rowNum;
940 return _appendToClassList( $classList, $rowClassName );
941}
942
943sub _appendColNumberCssClass {
944 my ( $classList, $colNum ) = @_;
945
946 my $colClassName = 'foswikiTableCol' . $colNum;
947 return _appendToClassList( $classList, $colClassName );
948}
949
950sub _appendFirstColumnCssClass {
951 my ($classList) = @_;
952
953 return _appendToClassList( $classList, 'foswikiFirstCol' );
954}
955
956sub _appendLastColumnCssClass {
957 my ($classList) = @_;
958
959 return _appendToClassList( $classList, 'foswikiLastCol' );
960}
961
962sub _appendLastRowCssClass {
963 my ($classList) = @_;
964
965 return _appendToClassList( $classList, 'foswikiLast' );
966}
967
968sub _appendSortedAscendingCssClass {
969 my ($classList) = @_;
970
971 return _appendToClassList( $classList, 'foswikiSortedAscendingCol' );
972}
973
974sub _appendSortedDescendingCssClass {
975 my ($classList) = @_;
976
977 return _appendToClassList( $classList, 'foswikiSortedDescendingCol' );
978}
979
980# The default sort direction.
981sub _getDefaultSortDirection {
982 return $SORT_DIRECTION->{'ASCENDING'};
983}
984
985# Gets the current sort direction.
986sub _getCurrentSortDirection {
987 my ($currentDirection) = @_;
988 $currentDirection = $SORT_DIRECTION->{'ASCENDING'}
989 unless defined $currentDirection && $currentDirection =~ m/[0-2]+/;
990 $currentDirection ||= _getDefaultSortDirection();
991 return $currentDirection;
992}
993
994# Gets the new sort direction (needed for sort button) based on the current sort
995# direction.
996sub _getNewSortDirection {
997 my ($currentDirection) = @_;
998 if ( !defined $currentDirection ) {
999 return _getDefaultSortDirection();
1000 }
1001 my $newDirection;
1002 if ( $currentDirection == $SORT_DIRECTION->{'ASCENDING'} ) {
1003 $newDirection = $SORT_DIRECTION->{'DESCENDING'};
1004 }
1005 elsif ( $currentDirection == $SORT_DIRECTION->{'DESCENDING'} ) {
1006 $newDirection = $SORT_DIRECTION->{'NONE'};
1007 }
1008 elsif ( $currentDirection == $SORT_DIRECTION->{'NONE'} ) {
1009 $newDirection = $SORT_DIRECTION->{'ASCENDING'};
1010 }
1011 else {
1012 $newDirection = _getDefaultSortDirection();
1013 }
1014
1015 return $newDirection;
1016}
1017
1018=pod
1019
1020_createCssStyles( $writeDefaults, $inAttrs ) -> ($id, @styles)
1021
1022Explicitly set styles override html styling (in this file marked with comment '# html attribute').
1023
1024=cut
1025
1026sub _createCssStyles {
1027 my ( $writeDefaults, $inAttrs ) = @_;
1028
1029 _debug("_createCssStyles; writeDefaults=$writeDefaults");
1030
1031 my $_styles = {};
1032 my $setAttribute = sub {
1033 my ( $tableSelector, $type, $rule ) = @_;
1034
1035 return if !$rule;
1036 $type ||= '#'; # for table selector only, if no type
1037 my $storedType = $_styles->{$tableSelector}->{$type} || '';
1038 if ( !defined $storedType ) {
1039 @{ $_styles->{$tableSelector}->{$type} } = ();
1040 }
1041 if ( $rule ne $storedType ) {
1042 push @{ $_styles->{$tableSelector}->{$type} }, $rule;
1043 }
1044 };
1045
1046 if ( $writeDefaults && !$didWriteDefaultStyle ) {
1047 my $tableSelector = '.foswikiTable';
1048 my $attr = 'padding-left:.3em; vertical-align:text-bottom';
1049 &$setAttribute( $tableSelector, '.tableSortIcon img', $attr );
1050
1051 if ( $inAttrs->{cellpadding} ) {
1052 my $attr =
1053 'padding:' . addDefaultSizeUnit( $inAttrs->{cellpadding} );
1054 &$setAttribute( $tableSelector, 'td', $attr );
1055 &$setAttribute( $tableSelector, 'th', $attr );
1056 }
1057 }
1058
1059 my $tableSelector;
1060 my $id;
1061 if ($writeDefaults) {
1062 $id = 'default';
1063 $tableSelector = ".foswikiTable";
1064 }
1065 else {
1066 $id = $inAttrs->{id};
1067 $tableSelector = ".foswikiTable#$id";
1068 }
1069
1070 # tablerules
1071 if ( $inAttrs->{tableRules} ) {
1072 my @rules = @{ $inAttrs->{tableRules} };
1073
1074 my $attr_td;
1075 my $attr_th;
1076 foreach my $rule (@rules) {
1077 $attr_td = $TABLE_RULES->{$rule}->{TD}
1078 if $TABLE_RULES->{$rule}->{TD};
1079 $attr_th = $TABLE_RULES->{$rule}->{TH}
1080 if $TABLE_RULES->{$rule}->{TH};
1081 }
1082 &$setAttribute( $tableSelector, 'th', $attr_th );
1083 &$setAttribute( $tableSelector, 'td', $attr_td );
1084 }
1085
1086 # tableframe
1087 if ( $inAttrs->{frame} ) {
1088 my $attr = $TABLE_FRAME->{ $inAttrs->{frame} };
1089 &$setAttribute( $tableSelector, '', $attr );
1090 }
1091
1092 # tableborder
1093 if ( defined $inAttrs->{border} ) {
1094 my $tableBorderWidth = $inAttrs->{border} || 0;
1095 my $attr = 'border-width:' . addDefaultSizeUnit($tableBorderWidth);
1096 &$setAttribute( $tableSelector, '', $attr );
1097 }
1098
1099 # tableBorderColor
1100 if ( defined $inAttrs->{tableBorderColor} ) {
1101 my $attr;
1102 $attr = 'border-color:' . $inAttrs->{tableBorderColor};
1103 &$setAttribute( $tableSelector, '', $attr );
1104 $attr = 'border-top-color:' . $inAttrs->{tableBorderColor};
1105 &$setAttribute( $tableSelector, '', $attr );
1106 $attr = 'border-bottom-color:' . $inAttrs->{tableBorderColor};
1107 &$setAttribute( $tableSelector, '', $attr );
1108 $attr = 'border-left-color:' . $inAttrs->{tableBorderColor};
1109 &$setAttribute( $tableSelector, '', $attr );
1110 $attr = 'border-right-color:' . $inAttrs->{tableBorderColor};
1111 &$setAttribute( $tableSelector, '', $attr );
1112 }
1113
1114 # cellSpacing
1115 if ( defined $inAttrs->{cellspacing} ) {
1116
1117 # do not use border-collapse:collapse
1118 my $attr = 'border-collapse:separate';
1119 &$setAttribute( $tableSelector, '', $attr );
1120 }
1121
1122 # cellpadding
1123 if ( defined $inAttrs->{cellpadding} ) {
1124 my $attr = 'padding:' . addDefaultSizeUnit( $inAttrs->{cellpadding} );
1125 &$setAttribute( $tableSelector, 'td', $attr );
1126 &$setAttribute( $tableSelector, 'th', $attr );
1127 }
1128
1129 # cellborder
1130 if ( defined $inAttrs->{cellBorder} ) {
1131 my $cellBorderWidth = $inAttrs->{cellBorder} || 0;
1132 my $attr = 'border-width:' . addDefaultSizeUnit($cellBorderWidth);
1133 &$setAttribute( $tableSelector, 'td', $attr );
1134 &$setAttribute( $tableSelector, 'th', $attr );
1135 }
1136
1137 # tablewidth
1138 if ( defined $inAttrs->{width} ) {
1139 my $width = addDefaultSizeUnit( $inAttrs->{width} );
1140 my $attr = 'width:' . $width;
1141 &$setAttribute( $tableSelector, '', $attr );
1142 }
1143
1144 # valign
1145 if ( defined $inAttrs->{vAlign} ) {
1146 my $attr = 'vertical-align:' . $inAttrs->{vAlign};
1147 &$setAttribute( $tableSelector, 'td', $attr );
1148 &$setAttribute( $tableSelector, 'th', $attr );
1149 }
1150
1151 # headerVAlign
1152 if ( defined $inAttrs->{headerVAlign} ) {
1153 my $attr = 'vertical-align:' . $inAttrs->{headerVAlign};
1154 &$setAttribute( $tableSelector, 'th', $attr );
1155 }
1156
1157 # dataVAlign
1158 if ( defined $inAttrs->{dataVAlign} ) {
1159 my $attr = 'vertical-align:' . $inAttrs->{dataVAlign};
1160 &$setAttribute( $tableSelector, 'td', $attr );
1161 }
1162
1163 # headerbg
1164 if ( defined $inAttrs->{headerBg} ) {
1165 my $color =
1166 ( $inAttrs->{headerBg} =~ /none/i )
1167 ? 'transparent'
1168 : $inAttrs->{headerBg};
1169 my $attr = 'background-color:' . $color;
1170 &$setAttribute( $tableSelector, 'th', $attr );
1171 }
1172
1173 # headerbgsorted
1174 if ( defined $inAttrs->{headerBgSorted} ) {
1175 my $color =
1176 ( $inAttrs->{headerBgSorted} =~ /none/i )
1177 ? 'transparent'
1178 : $inAttrs->{headerBgSorted};
1179 my $attr = 'background-color:' . $color;
1180 &$setAttribute( $tableSelector, 'th.foswikiSortedCol', $attr );
1181 }
1182
1183 # headercolor
1184 if ( defined $inAttrs->{headerColor} ) {
1185 my $attr = 'color:' . $inAttrs->{headerColor};
1186 &$setAttribute( $tableSelector, 'th', $attr );
1187 &$setAttribute( $tableSelector, 'th a:link', $attr );
1188 &$setAttribute( $tableSelector, 'th a:visited', $attr );
1189 &$setAttribute( $tableSelector, 'th a:xhover', $attr )
1190 ; # just to make sorting work: hover should be last. below we will remove the x again.
1191 if ( defined $inAttrs->{headerBg} ) {
1192 my $hoverBackgroundColor = $inAttrs->{headerBg};
1193 $attr = 'background-color:' . $hoverBackgroundColor;
1194 &$setAttribute( $tableSelector, 'th a:xhover', $attr );
1195 }
1196 }
1197
1198 # databg (array)
1199 if ( defined $inAttrs->{dataBgListRef} ) {
1200 my @dataBg = @{ $inAttrs->{dataBgListRef} };
1201 my $noneColor = ( $dataBg[0] =~ /none/i ) ? 'transparent' : '';
1202 my $count = 0;
1203 foreach my $color (@dataBg) {
1204 $color = $noneColor if $noneColor;
1205 next if !$color;
1206 my $rowSelector = 'foswikiTableRow' . 'dataBg' . $count;
1207 my $attr = "background-color:$color";
1208 &$setAttribute( $tableSelector, "tr.$rowSelector td", $attr );
1209 $count++;
1210 }
1211 }
1212
1213 # databgsorted (array)
1214 if ( defined $inAttrs->{dataBgSortedListRef} ) {
1215 my @dataBgSorted = @{ $inAttrs->{dataBgSortedListRef} };
1216 my $noneColor = ( $dataBgSorted[0] =~ /none/i ) ? 'transparent' : '';
1217 my $count = 0;
1218 foreach my $color (@dataBgSorted) {
1219 $color = $noneColor if $noneColor;
1220 next if !$color;
1221 my $rowSelector = 'foswikiTableRow' . 'dataBg' . $count;
1222 my $attr = "background-color:$color";
1223 &$setAttribute( $tableSelector,
1224 "tr.$rowSelector td.foswikiSortedCol", $attr );
1225 $count++;
1226 }
1227 }
1228
1229 # datacolor (array)
1230 if ( defined $inAttrs->{dataColorListRef} ) {
1231 my @dataColor = @{ $inAttrs->{dataColorListRef} };
1232 unless ( $dataColor[0] =~ /none/i ) {
1233 my $count = 0;
1234 foreach my $color (@dataColor) {
1235 next if !$color;
1236 my $rowSelector = 'foswikiTableRow' . 'dataColor' . $count;
1237 my $attr = "color:$color";
1238 &$setAttribute( $tableSelector, "tr.$rowSelector td", $attr );
1239 $count++;
1240 }
1241 }
1242 }
1243
1244 # columnwidths
1245 if ( defined $inAttrs->{columnWidthsListRef} ) {
1246 my @columnWidths = @{ $inAttrs->{columnWidthsListRef} };
1247 my $count = 0;
1248 foreach my $width (@columnWidths) {
1249 next if !$width;
1250 $width = addDefaultSizeUnit($width);
1251 my $colSelector = 'foswikiTableCol';
1252 $colSelector .= $count;
1253 my $attr = 'width:' . $width;
1254 &$setAttribute( $tableSelector, "td.$colSelector", $attr );
1255 &$setAttribute( $tableSelector, "th.$colSelector", $attr );
1256 $count++;
1257 }
1258 }
1259
1260 # headeralign
1261 if ( defined $inAttrs->{headerAlignListRef} ) {
1262 my @headerAlign = @{ $inAttrs->{headerAlignListRef} };
1263 if ( scalar(@headerAlign) == 1 ) {
1264 my $align = $headerAlign[0];
1265 my $attr = 'text-align:' . $align;
1266 &$setAttribute( $tableSelector, 'th', $attr );
1267 }
1268 else {
1269 my $count = 0;
1270 foreach my $align (@headerAlign) {
1271 next if !$align;
1272 my $colSelector = 'foswikiTableCol';
1273 $colSelector .= $count;
1274 my $attr = 'text-align:' . $align;
1275 &$setAttribute( $tableSelector, "th.$colSelector", $attr );
1276 $count++;
1277 }
1278 }
1279 }
1280
1281 # dataAlign
1282 if ( defined $inAttrs->{dataAlignListRef} ) {
1283 my @dataAlign = @{ $inAttrs->{dataAlignListRef} };
1284 if ( scalar(@dataAlign) == 1 ) {
1285 my $align = $dataAlign[0];
1286 my $attr = 'text-align:' . $align;
1287 &$setAttribute( $tableSelector, 'td', $attr );
1288 }
1289 else {
1290 my $count = 0;
1291 foreach my $align (@dataAlign) {
1292 next if !$align;
1293 my $colSelector = 'foswikiTableCol';
1294 $colSelector .= $count;
1295 my $attr = 'text-align:' . $align;
1296 &$setAttribute( $tableSelector, "td.$colSelector", $attr );
1297 $count++;
1298 }
1299 }
1300 }
1301
1302 my @styles = ();
1303 foreach my $tableSelector ( sort keys %{$_styles} ) {
1304 foreach my $selector ( sort keys %{ $_styles->{$tableSelector} } ) {
1305 my $selectors =
1306 join( '; ', @{ $_styles->{$tableSelector}->{$selector} } );
1307 $selector =~ s/xhover/hover/go; # remove sorting hack
1308 # TODO: optimize by combining identical rules
1309 if ( $selector eq '#' ) {
1310 push @styles, "$tableSelector {$selectors}";
1311 }
1312 else {
1313 push @styles, "$tableSelector $selector {$selectors}";
1314 }
1315 }
1316 }
1317
1318 return ( $id, @styles );
1319}
1320
1321sub _addHeadStyles {
1322 my ( $inId, @inStyles ) = @_;
1323
1324 return if !scalar(@inStyles);
1325
1326 $styles->{seendIds}->{$inId} = 1;
1327 if ( $inId eq $HEAD_ID_DEFAULT_STYLE ) {
1328 $styles->{$HEAD_ID_DEFAULT_STYLE}->{'default'} = \@inStyles;
1329 _writeStyleToHead( $HEAD_ID_DEFAULT_STYLE,
1330 $styles->{$HEAD_ID_DEFAULT_STYLE} );
1331 }
1332 else {
1333 $styles->{$HEAD_ID_SPECIFIC_STYLE}->{$inId} = \@inStyles;
1334 _writeStyleToHead( $HEAD_ID_SPECIFIC_STYLE,
1335 $styles->{$HEAD_ID_SPECIFIC_STYLE} );
1336 }
1337}
1338
1339sub _writeStyleToHead {
1340 my ( $inId, $inStyles ) = @_;
1341
1342 my @allStyles = ();
1343 foreach my $id ( sort keys %{$inStyles} ) {
1344 push @allStyles, @{ $inStyles->{$id} };
1345 }
1346 my $styleText = join( "\n", @allStyles );
1347
1348 my $header = <<EOS;
1349<style type="text/css" media="all">
1350$styleText
1351</style>
1352EOS
1353 Foswiki::Func::addToZone( "head", $inId, $header, $HEAD_ID_DEFAULT_STYLE );
1354}
1355
1356=pod
1357
1358StaticMethod addDefaultSizeUnit ($text) -> $text
1359
1360Adds size unit 'px' if this is missing from the size text.
1361
1362=cut
1363
1364sub addDefaultSizeUnit {
1365 my ($inSize) = @_;
1366
1367 my $unit = '';
1368 if ( $inSize =~ m/$PATTERN_ATTRIBUTE_SIZE/ ) {
1369 $unit = 'px' if !$2;
1370 }
1371 return "$inSize$unit";
1372}
1373
1374sub emitTable {
1375
1376 _addDefaultStyles();
1377
1378 _debug('emitTable');
1379
1380 #Validate headerrows/footerrows and modify if out of range
1381 if ( $combinedTableAttrs->{headerrows} > scalar(@curTable) ) {
1382 $combinedTableAttrs->{headerrows} =
1383 scalar(@curTable); # limit header to size of table!
1384 }
1385 if ( $combinedTableAttrs->{headerrows} + $combinedTableAttrs->{footerrows} >
1386 @curTable )
1387 {
1388 $combinedTableAttrs->{footerrows} =
1389 scalar(@curTable) -
1390 $combinedTableAttrs->{headerrows}; # and footer to whatever is left
1391 }
1392
1393 my $sortThisTable =
1394 ( !defined $combinedTableAttrs->{sortAllTables}
1395 || $combinedTableAttrs->{sortAllTables} == 0 )
1396 ? 0
1397 : $combinedTableAttrs->{sort};
1398
1399 if ( $combinedTableAttrs->{headerrows} == 0 ) {
1400 my ( $headerRowCount, $footerRowCount ) = _headerRowCount( \@curTable );
1401
1402 # override default setting with calculated header count
1403 $combinedTableAttrs->{headerrows} = $headerRowCount;
1404 $combinedTableAttrs->{footerrows} = $footerRowCount;
1405 }
1406
1407 my $tableTagAttributes = {};
1408 $tableTagAttributes->{class} = $combinedTableAttrs->{class};
1409 $tableTagAttributes->{border} = $combinedTableAttrs->{border};
1410 $tableTagAttributes->{cellspacing} = $combinedTableAttrs->{cellspacing};
1411 $tableTagAttributes->{cellpadding} = $combinedTableAttrs->{cellpadding};
1412 $tableTagAttributes->{id} = $combinedTableAttrs->{id}
1413 || undef;
1414 $tableTagAttributes->{summary} = $combinedTableAttrs->{summary};
1415 $tableTagAttributes->{frame} = $combinedTableAttrs->{frame};
1416 $tableTagAttributes->{rules} = $combinedTableAttrs->{rules};
1417 $tableTagAttributes->{width} = $combinedTableAttrs->{width};
1418
1419 # remove empty attributes
1420 while ( my ( $key, $value ) = each %{$tableTagAttributes} ) {
1421 delete $tableTagAttributes->{$key} if !defined $value || $value eq '';
1422 }
1423
1424 my $text = $currTablePre . CGI::start_table($tableTagAttributes);
1425 $text .= $currTablePre . CGI::caption( $combinedTableAttrs->{tableCaption} )
1426 if $combinedTableAttrs->{tableCaption};
1427
1428 # count the number of cols to prevent looping over non-existing columns
1429 my $maxCols = 0;
1430
1431 # Flush out any remaining rowspans
1432 for ( my $i = 0 ; $i < @rowspan ; $i++ ) {
1433 if ( defined( $rowspan[$i] ) && $rowspan[$i] ) {
1434 my $nRows = scalar(@curTable);
1435 my $rspan = $rowspan[$i] + 1;
1436 my $r = $nRows - $rspan;
1437 $curTable[$r][$i]->{attrs} ||= {};
1438 if ( $rspan > 1 ) {
1439 $curTable[$r][$i]->{attrs}->{rowspan} = $rspan;
1440 }
1441 }
1442 }
1443
1444 if (
1445 (
1446 $sortThisTable
1447 && defined $sortCol
1448 && defined $requestedTable
1449 && $requestedTable == $tableCount
1450 )
1451 || defined $combinedTableAttrs->{initSort}
1452 )
1453 {
1454
1455 # DG 08 Aug 2002: Allow multi-line headers
1456 my @header = splice( @curTable, 0, $combinedTableAttrs->{headerrows} );
1457
1458 # DG 08 Aug 2002: Skip sorting any trailers as well
1459 my @trailer = ();
1460 if ( $combinedTableAttrs->{footerrows}
1461 && scalar(@curTable) > $combinedTableAttrs->{footerrows} )
1462 {
1463 @trailer = splice( @curTable, -$combinedTableAttrs->{footerrows} );
1464 }
1465
1466 # Count the maximum number of columns of this table
1467 for my $row ( 0 .. $#curTable ) {
1468 my $thisRowMaxColCount = 0;
1469 for my $col ( 0 .. $#{ $curTable[$row] } ) {
1470 $thisRowMaxColCount++;
1471 }
1472 $maxCols = $thisRowMaxColCount
1473 if ( $thisRowMaxColCount > $maxCols );
1474 }
1475
1476 # Handle multi-row labels by killing rowspans in sorted tables
1477 for my $row ( 0 .. $#curTable ) {
1478 for my $col ( 0 .. $#{ $curTable[$row] } ) {
1479
1480 # SMELL: why do we need to specify a rowspan of 1?
1481 $curTable[$row][$col]->{attrs}->{rowspan} = 1;
1482 if ( $curTable[$row][$col]->{type} eq 'Y' ) {
1483 $curTable[$row][$col]->{text} =
1484 $curTable[ $row - 1 ][$col]->{text};
1485 $curTable[$row][$col]->{type} = 'td';
1486 }
1487 }
1488 }
1489
1490 # url requested sort on column beyond end of table. Force to last column
1491 $sortCol = 0 unless ( $sortCol =~ m/^[0-9]+$/ );
1492 $sortCol = $maxCols - 1 if ( $sortCol >= $maxCols );
1493
1494 # only get the column type if within bounds
1495 if ( $sortCol < $maxCols ) {
1496 _setSortTypeForCells( $sortCol, \@curTable );
1497 }
1498
1499 _debug("currentSortDirection:$currentSortDirection");
1500
1501 if ( $combinedTableAttrs->{sort}
1502 && $currentSortDirection == $SORT_DIRECTION->{'ASCENDING'} )
1503 {
1504 @curTable = sort {
1505 $a->[$sortCol]->{sortText} cmp $b->[$sortCol]->{sortText}
1506 || $a->[$sortCol]->{number} <=> $b->[$sortCol]->{number}
1507 || $a->[$sortCol]->{dateString}
1508 cmp $b->[$sortCol]->{dateString}
1509 } @curTable;
1510 }
1511 elsif ($combinedTableAttrs->{sort}
1512 && $currentSortDirection == $SORT_DIRECTION->{'DESCENDING'} )
1513 {
1514 @curTable = sort {
1515 $b->[$sortCol]->{sortText} cmp $a->[$sortCol]->{sortText}
1516 || $b->[$sortCol]->{number} <=> $a->[$sortCol]->{number}
1517 || $b->[$sortCol]->{dateString}
1518 cmp $a->[$sortCol]->{dateString}
1519 } @curTable;
1520 }
1521
1522 # DG 08 Aug 2002: Cleanup after the header/trailer splicing
1523 # this is probably awfully inefficient - but how big is a table?
1524 @curTable = ( @header, @curTable, @trailer );
1525 } # if defined $sortCol ...
1526
1527 my $rowCount = 0;
1528 my $numberOfRows = scalar(@curTable);
1529 my $dataColorCount = 0;
1530
1531 my @headerRowList = ();
1532 my @bodyRowList = ();
1533 my @footerRowList = ();
1534
1535 my $isPastHeaderRows = 0;
1536 my $singleIndent = "\n\t";
1537 my $doubleIndent = "\n\t\t";
1538 my $tripleIndent = "\n\t\t\t";
1539
1540 # Only *one* row of the table has sort links, and it will either
1541 # be the last row in the header or the first row in the footer.
1542 my $sortLinksWritten = 0;
1543
1544 foreach my $row (@curTable) {
1545 my $rowtext = '';
1546 my $colCount = 0;
1547
1548 # keep track of header cells: if all cells are header cells, do not
1549 # update the data color count
1550 my $headerCellCount = 0;
1551 my $numberOfCols = scalar(@$row);
1552 my $writingSortLinks = 0;
1553
1554 foreach my $fcell (@$row) {
1555
1556 # check if cell exists
1557 next if ( !$fcell || !$fcell->{type} );
1558
1559 my $tableAnchor = '';
1560 next
1561 if ( $fcell->{type} eq 'X' )
1562 ; # data was there so sort could work with col spanning
1563 my $type = $fcell->{type};
1564 my $cell = $fcell->{text};
1565 my $attr = $fcell->{attrs} || {};
1566
1567 my $newDirection;
1568 my $isSorted = 0;
1569
1570 if (
1571 $currentSortDirection != $SORT_DIRECTION->{'NONE'}
1572 && defined $sortCol
1573 && $colCount == $sortCol
1574
1575 # Removing the line below hides the marking of sorted columns
1576 # until the user clicks on a header (KJL)
1577 # && defined $requestedTable && $requestedTable == $tableCount
1578 # && $sortType ne ''
1579 )
1580 {
1581 $isSorted = 1;
1582 $newDirection = _getNewSortDirection($currentSortDirection);
1583 }
1584 else {
1585 $newDirection = _getDefaultSortDirection();
1586 }
1587
1588 if ( $type eq 'th' ) {
1589 $headerCellCount++;
1590
1591 # html attribute: bgcolor
1592 if ( $combinedTableAttrs->{generateInlineMarkup}
1593 && defined $combinedTableAttrs->{headerBg} )
1594 {
1595 $attr->{bgcolor} = $combinedTableAttrs->{headerBg}
1596 unless ( $combinedTableAttrs->{headerBg} =~ /none/i );
1597 }
1598
1599 # END html attribute
1600
1601 if ($isSorted) {
1602 if ( $currentSortDirection ==
1603 $SORT_DIRECTION->{'ASCENDING'} )
1604 {
1605 $tableAnchor = $CHAR_SORT_ASCENDING;
1606 }
1607 if ( $currentSortDirection ==
1608 $SORT_DIRECTION->{'DESCENDING'} )
1609 {
1610 $tableAnchor = $CHAR_SORT_DESCENDING;
1611 }
1612
1613 # html attribute: (sorted header cell) bgcolor
1614 # overrides earlier set bgcolor
1615 if ( $combinedTableAttrs->{generateInlineMarkup}
1616 && defined $combinedTableAttrs->{headerBgSorted} )
1617 {
1618 $attr->{bgcolor} = $combinedTableAttrs->{headerBgSorted}
1619 unless (
1620 $combinedTableAttrs->{headerBgSorted} =~ /none/i );
1621 }
1622
1623 # END html attribute
1624 }
1625
1626 if (
1627 defined $sortCol
1628 && $colCount == $sortCol
1629 && defined $requestedTable
1630 && $requestedTable == $tableCount
1631 && ( $combinedTableAttrs->{headerrows}
1632 || $combinedTableAttrs->{footerrows} )
1633 )
1634 {
1635
1636 $tableAnchor =
1637 CGI::a( { name => 'sorted_table' }, '<!-- -->' )
1638 . $tableAnchor;
1639 }
1640
1641 # html attribute: headercolor (font style)
1642 if ( $combinedTableAttrs->{generateInlineMarkup}
1643 && defined $combinedTableAttrs->{headerColor} )
1644 {
1645 my $fontStyle =
1646 { color => $combinedTableAttrs->{headerColor} };
1647 $cell = CGI::font( $fontStyle, $cell );
1648 }
1649
1650 # END html attribute
1651
1652 if (
1653 $sortThisTable
1654 && (
1655 ( $rowCount == $combinedTableAttrs->{headerrows} - 1 )
1656 || ( !$combinedTableAttrs->{headerrows}
1657 && $rowCount ==
1658 $numberOfRows - $combinedTableAttrs->{footerrows} )
1659 )
1660 && ( $writingSortLinks || !$sortLinksWritten )
1661 )
1662 {
1663 $writingSortLinks = 1;
1664 my $linkAttributes = {
1665 href => $url
1666 . 'sortcol='
1667 . $colCount
1668 . ';table='
1669 . $tableCount . ';up='
1670 . $newDirection
1671 . '#sorted_table',
1672 rel => 'nofollow',
1673 title => 'Sort by this column'
1674 };
1675
1676 if ( $cell =~ /\[\[|href/o ) {
1677 $cell .= CGI::a( $linkAttributes, $CHAR_SORT_BOTH )
1678 . $tableAnchor;
1679 }
1680 else {
1681 $cell = CGI::a( $linkAttributes, $cell ) . $tableAnchor;
1682 }
1683 }
1684
1685 }
1686 else {
1687
1688 $type = 'td' unless $type eq 'Y';
1689
1690 # html attribute: bgcolor
1691 if ( $combinedTableAttrs->{generateInlineMarkup} ) {
1692 if ( $isSorted
1693 && defined $combinedTableAttrs->{dataBgSortedListRef} )
1694 {
1695 my @dataBg =
1696 @{ $combinedTableAttrs->{dataBgSortedListRef} };
1697
1698 unless ( $dataBg[0] =~ /none/ ) {
1699 $attr->{bgcolor} =
1700 $dataBg[ $dataColorCount % ( $#dataBg + 1 ) ];
1701 }
1702 }
1703 elsif ( defined $combinedTableAttrs->{dataBgListRef} ) {
1704 my @dataBg = @{ $combinedTableAttrs->{dataBgListRef} };
1705 unless ( $dataBg[0] =~ /none/i ) {
1706 $attr->{bgcolor} =
1707 $dataBg[ $dataColorCount % ( $#dataBg + 1 ) ];
1708 }
1709 }
1710 }
1711
1712 # END html attribute
1713
1714 # html attribute: datacolor (font style)
1715 if ( $combinedTableAttrs->{generateInlineMarkup}
1716 && defined $combinedTableAttrs->{dataColorListRef} )
1717 {
1718 my @dataColor =
1719 @{ $combinedTableAttrs->{dataColorListRef} };
1720 my $color =
1721 $dataColor[ $dataColorCount % ( $#dataColor + 1 ) ];
1722 unless ( $color =~ /^(none)$/i ) {
1723 my $cellAttrs = { color => $color };
1724 $cell = CGI::font( $cellAttrs, ' ' . $cell . ' ' );
1725 }
1726 }
1727
1728 # END html attribute
1729
1730 } ###if( $type eq 'th' )
1731
1732 if ($isSorted) {
1733 $attr->{class} = _appendSortedCssClass( $attr->{class} );
1734 }
1735
1736 if ($writingSortLinks) {
1737 $sortLinksWritten = 1;
1738 }
1739
1740 my $isLastRow = ( $rowCount == $numberOfRows - 1 );
1741 if ( $attr->{rowspan} ) {
1742 $isLastRow =
1743 ( ( $rowCount + ( $attr->{rowspan} - 1 ) ) ==
1744 $numberOfRows - 1 );
1745 }
1746
1747 # CSS class name
1748 $attr->{class} = _appendFirstColumnCssClass( $attr->{class} )
1749 if $colCount == 0;
1750 my $isLastCol = ( $colCount == $numberOfCols - 1 );
1751 $attr->{class} = _appendLastColumnCssClass( $attr->{class} )
1752 if $isLastCol;
1753
1754 $attr->{class} = _appendLastRowCssClass( $attr->{class} )
1755 if $isLastRow;
1756
1757 $colCount++;
1758 next if ( $type eq 'Y' );
1759 my $fn = 'CGI::' . $type;
1760249µs240µs
# spent 26µs (12+14) within Foswiki::Plugins::TablePlugin::Core::BEGIN@1760 which was called: # once (12µs+14µs) by Foswiki::Plugins::TablePlugin::preRenderingHandler at line 1760
no strict 'refs';
# spent 26µs making 1 call to Foswiki::Plugins::TablePlugin::Core::BEGIN@1760 # spent 14µs making 1 call to strict::unimport
1761 $rowtext .= "$tripleIndent" . &$fn( $attr, " $cell " );
176221.25ms228µs
# spent 19µs (9+9) within Foswiki::Plugins::TablePlugin::Core::BEGIN@1762 which was called: # once (9µs+9µs) by Foswiki::Plugins::TablePlugin::preRenderingHandler at line 1762
use strict 'refs';
# spent 19µs making 1 call to Foswiki::Plugins::TablePlugin::Core::BEGIN@1762 # spent 9µs making 1 call to strict::import
1763 } # foreach my $fcell ( @$row )
1764
1765 # assign css class names to tr
1766 # based on settings: dataBg, dataBgSorted
1767 my $trClassName = '';
1768
1769 # just 2 css names is too limited, but we will keep it for compatibility
1770 # with existing style sheets
1771 my $rowTypeName =
1772 ( $rowCount % 2 ) ? 'foswikiTableEven' : 'foswikiTableOdd';
1773 $trClassName = _appendToClassList( $trClassName, $rowTypeName );
1774
1775 if ( $combinedTableAttrs->{dataBgSortedListRef} ) {
1776 my @dataBgSorted = @{ $combinedTableAttrs->{dataBgSortedListRef} };
1777 my $modRowNum = $dataColorCount % ( $#dataBgSorted + 1 );
1778 $trClassName =
1779 _appendRowNumberCssClass( $trClassName, 'dataBgSorted',
1780 $modRowNum );
1781 }
1782 if ( $combinedTableAttrs->{dataBgListRef} ) {
1783 my @dataBg = @{ $combinedTableAttrs->{dataBgListRef} };
1784 my $modRowNum = $dataColorCount % ( $#dataBg + 1 );
1785 $trClassName =
1786 _appendRowNumberCssClass( $trClassName, 'dataBg', $modRowNum );
1787 }
1788 if ( $combinedTableAttrs->{dataColorListRef} ) {
1789 my @dataColor = @{ $combinedTableAttrs->{dataColorListRef} };
1790 my $modRowNum = $dataColorCount % ( $#dataColor + 1 );
1791 $trClassName =
1792 _appendRowNumberCssClass( $trClassName, 'dataColor', $modRowNum );
1793 }
1794 $rowtext .= $doubleIndent;
1795 my $rowHTML =
1796 $doubleIndent . CGI::Tr( { class => $trClassName }, $rowtext );
1797
1798 my $isHeaderRow =
1799 $rowCount <
1800 $combinedTableAttrs->{headerrows}; #( $headerCellCount == $colCount );
1801 my $isFooterRow =
1802 ( ( $numberOfRows - $rowCount ) <=
1803 $combinedTableAttrs->{footerrows} );
1804
1805 if ( !$isHeaderRow && !$isFooterRow ) {
1806
1807 # don't include non-adjacent header rows to the top block of header rows
1808 $isPastHeaderRows = 1;
1809 }
1810
1811 if ($isFooterRow) {
1812 push @footerRowList, $rowHTML;
1813 }
1814 elsif ( $isHeaderRow && !$isPastHeaderRows ) {
1815 push( @headerRowList, $rowHTML );
1816 }
1817 else {
1818 push @bodyRowList, $rowHTML;
1819 $dataColorCount++;
1820 }
1821
1822 if ($isHeaderRow) {
1823
1824 # reset data color count to start with first color after
1825 # each table heading
1826 $dataColorCount = 0;
1827 }
1828
1829 $rowCount++;
1830 } # foreach my $row ( @curTable )
1831
1832 my $thead =
1833 "$singleIndent<thead>"
1834 . join( "", @headerRowList )
1835 . "$singleIndent</thead>";
1836 $text .= $currTablePre . $thead if scalar(@headerRowList);
1837
1838 my $tfoot =
1839 "$singleIndent<tfoot>"
1840 . join( "", @footerRowList )
1841 . "$singleIndent</tfoot>";
1842 $text .= $currTablePre . $tfoot if scalar(@footerRowList);
1843
1844 my $tbody;
1845 if ( scalar(@bodyRowList) ) {
1846 $tbody =
1847 "$singleIndent<tbody>"
1848 . join( "", @bodyRowList )
1849 . "$singleIndent</tbody>";
1850 }
1851 else {
1852
1853 # A HTML table requires a body, which cannot be empty (Item8991).
1854 # So we provide one, but prevent it from being displayed.
1855 $tbody =
1856"$singleIndent<tbody>$doubleIndent<tr style=\"display:none;\">$tripleIndent<td></td>$doubleIndent</tr>$singleIndent</tbody>\n";
1857 }
1858
1859 if ( scalar(@messages) ) {
1860 $text =
1861 '<span class="foswikiAlert">'
1862 . Foswiki::Func::expandCommonVariables( join( "\n", @messages ) )
1863 . '</span>' . "\n"
1864 . $text;
1865 }
1866
1867 $text .= $currTablePre . $tbody;
1868 $text .= $currTablePre . CGI::end_table() . "\n";
1869
1870 return $text;
1871}
1872
1873
# spent 1.54ms (658µs+881µs) within Foswiki::Plugins::TablePlugin::Core::handler which was called 5 times, avg 308µs/call: # 5 times (658µs+881µs) by Foswiki::Plugins::TablePlugin::preRenderingHandler at line 83 of /var/www/foswikidev/core/lib/Foswiki/Plugins/TablePlugin.pm, avg 308µs/call
sub handler {
1874 ### my ( $text, $removed ) = @_;
1875
187659µs532µs _debug('handler');
# spent 32µs making 5 calls to Foswiki::Plugins::TablePlugin::Core::_debug, avg 6µs/call
1877
187851µs unless ($Foswiki::Plugins::TablePlugin::initialised) {
18791200ns $insideTABLE = 0;
1880
1881 # Even if $tableCount is initialized already at plugin init
1882 # we need to reset it again each time preRenderingHandler
1883 # calls this handler sub. Important for initialiseWhenRender API
18841100ns $tableCount = 0;
1885
188611µs14µs my $cgi = Foswiki::Func::getCgiQuery();
# spent 4µs making 1 call to Foswiki::Func::getCgiQuery
18871200ns return unless $cgi;
1888
1889 # Copy existing values
18901300ns my ( @origSort, @origTable, @origUp );
189113µs123µs @origSort = $cgi->multi_param('sortcol');
# spent 23µs making 1 call to Foswiki::Request::multi_param
189212µs115µs @origTable = $cgi->multi_param('table');
# spent 15µs making 1 call to Foswiki::Request::multi_param
189311µs114µs @origUp = $cgi->multi_param('up'); # NOTE: internal parameter
# spent 14µs making 1 call to Foswiki::Request::multi_param
189413µs17µs $cgi->delete( 'sortcol', 'table', 'up' );
# spent 7µs making 1 call to Foswiki::Request::delete
189513µs1133µs $url = $cgi->url( -absolute => 1, -path => 1 ) . '?';
# spent 133µs making 1 call to Foswiki::Request::url
189612µs175µs my $queryString = $cgi->query_string();
# spent 75µs making 1 call to Foswiki::Request::queryString
18971700ns if ($queryString) {
1898 $url .= $queryString . ';';
1899 }
1900
1901 # Restore parameters, so we don't interfere on the remaining execution
19021300ns $cgi->param( -name => 'sortcol', -value => \@origSort ) if @origSort;
19031200ns $cgi->param( -name => 'table', -value => \@origTable ) if @origTable;
19041100ns $cgi->param( -name => 'up', -value => \@origUp ) if @origUp;
1905
190611µs112µs $sortColFromUrl =
# spent 12µs making 1 call to Foswiki::Request::param
1907 $cgi->param('sortcol'); # zero based: 0 is first column
19081200ns if ( defined $sortColFromUrl && $sortColFromUrl !~ m/^[0-9]+$/ ) {
1909 $sortColFromUrl = 0;
1910 }
1911
191211µs112µs $requestedTable = $cgi->param('table');
# spent 12µs making 1 call to Foswiki::Request::param
19131400ns $requestedTable = 0
1914 unless ( defined $requestedTable && $requestedTable =~ m/^[0-9]+$/ );
1915
191611µs112µs $up = $cgi->param('up');
# spent 12µs making 1 call to Foswiki::Request::param
1917
19181200ns $sortTablesInText = 0;
19191100ns $sortAttachments = 0;
192012µs124µs my $tmp = Foswiki::Func::getPreferencesValue('TABLEPLUGIN_SORT')
# spent 24µs making 1 call to Foswiki::Func::getPreferencesValue
1921 || 'all';
192212µs if ( !$tmp || $tmp =~ /^all$/oi ) {
19231200ns $sortTablesInText = 1;
19241300ns $sortAttachments = 1;
1925 }
1926 elsif ( $tmp =~ /^attachments$/oi ) {
1927 $sortAttachments = 1;
1928 }
1929
193012µs1305µs _initDefaults(); # first time
# spent 305µs making 1 call to Foswiki::Plugins::TablePlugin::Core::_initDefaults
193111µs $Foswiki::Plugins::TablePlugin::initialised = 1;
1932 }
1933
193452µs $insideTABLE = 0;
1935
193655µs my $defaultSort = $combinedTableAttrs->{sortAllTables};
1937
193851µs my $acceptable = $combinedTableAttrs->{sortAllTables};
19395188µs my @lines = split( /\r?\n/, $_[0] );
194057µs for (@lines) {
1941220315µs if (
1942s/$PATTERN_TABLE/_parseTableSpecificTableAttributes(Foswiki::Func::extractParameters($1))/se
1943 )
1944 {
1945 $acceptable = 1;
1946 }
1947 elsif (s/^(\s*)\|(.*\|\s*)$/_processTableRow($1,$2)/eo) {
1948 $insideTABLE = 1;
1949 }
1950 elsif ($insideTABLE) {
1951 $_ = emitTable() . $_;
1952 $insideTABLE = 0;
1953
1954 $combinedTableAttrs->{sortAllTables} = $defaultSort;
1955 $acceptable = $defaultSort;
1956
1957 # prepare for next table
1958 _resetReusedVariables();
1959 }
1960 }
1961530µs $_[0] = join( "\n", @lines );
1962
196351µs if ($insideTABLE) {
1964 $_[0] .= emitTable();
1965 }
1966
1967 # prepare for next table
1968533µs5213µs _resetReusedVariables();
# spent 213µs making 5 calls to Foswiki::Plugins::TablePlugin::Core::_resetReusedVariables, avg 43µs/call
1969}
1970
1971=pod
1972
1973_mergeHashes (\%a, \%b ) -> \%merged
1974
1975Merges 2 hash references.
1976
1977=cut
1978
1979
# spent 139µs within Foswiki::Plugins::TablePlugin::Core::_mergeHashes which was called 6 times, avg 23µs/call: # 5 times (122µs+0s) by Foswiki::Plugins::TablePlugin::Core::_resetReusedVariables at line 180, avg 24µs/call # once (16µs+0s) by Foswiki::Plugins::TablePlugin::Core::_initDefaults at line 165
sub _mergeHashes {
198063µs my ( $A, $B ) = @_;
1981
198268µs my %merged = ();
1983610µs while ( my ( $k, $v ) = each(%$A) ) {
1984 $merged{$k} = $v;
1985 }
19866107µs while ( my ( $k, $v ) = each(%$B) ) {
1987 $merged{$k} = $v;
1988 }
1989619µs return \%merged;
1990}
1991
1992=pod
1993
1994=cut
1995
1996
# spent 3µs within Foswiki::Plugins::TablePlugin::Core::_cleanParamValue which was called 2 times, avg 2µs/call: # once (2µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 348 # once (1µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 354
sub _cleanParamValue {
19972600ns my ($inValue) = @_;
1998
19992300ns return undef if !$inValue;
2000
20012700ns $inValue =~ s/ //go; # remove spaces
200227µs return $inValue;
2003}
2004
2005=pod
2006
2007=cut
2008
2009
# spent 12µs within Foswiki::Plugins::TablePlugin::Core::_arrayRefFromParam which was called 6 times, avg 2µs/call: # once (4µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 398 # once (3µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 400 # once (2µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 383 # once (2µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 405 # once (1µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 386 # once (1µs+0s) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 389
sub _arrayRefFromParam {
201063µs my ($inValue) = @_;
2011
2012613µs return undef if !$inValue;
2013
20142700ns $inValue =~ s/ //go; # remove spaces
201523µs my @list = split( /,/, $inValue );
201626µs return \@list;
2017}
2018
2019=pod
2020
2021Shorthand debugging call.
2022
2023=cut
2024
2025
# spent 78µs (53+26) within Foswiki::Plugins::TablePlugin::Core::_debug which was called 13 times, avg 6µs/call: # 5 times (23µs+9µs) by Foswiki::Plugins::TablePlugin::Core::handler at line 1876, avg 6µs/call # 5 times (17µs+10µs) by Foswiki::Plugins::TablePlugin::Core::_resetReusedVariables at line 178, avg 5µs/call # once (6µs+3µs) by Foswiki::Plugins::TablePlugin::Core::_init at line 90 # once (3µs+2µs) by Foswiki::Plugins::TablePlugin::Core::_initDefaults at line 154 # once (3µs+1µs) by Foswiki::Plugins::TablePlugin::Core::_parseDefaultAttributes at line 209
sub _debug {
20261345µs1326µs return Foswiki::Plugins::TablePlugin::debug( 'TablePlugin::Core', @_ );
# spent 26µs making 13 calls to Foswiki::Plugins::TablePlugin::debug, avg 2µs/call
2027}
2028
2029
# spent 15µs (8+7) within Foswiki::Plugins::TablePlugin::Core::_debugData which was called 2 times, avg 7µs/call: # once (4µs+4µs) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 250 # once (4µs+2µs) by Foswiki::Plugins::TablePlugin::Core::_parseAttributes at line 415
sub _debugData {
203029µs27µs return Foswiki::Plugins::TablePlugin::debugData( 'TablePlugin::Core', @_ );
# spent 7µs making 2 calls to Foswiki::Plugins::TablePlugin::debugData, avg 3µs/call
2031}
2032
2033117µs1;
2034__END__