← Index
NYTProf Performance Profile   « line view »
For ./view
  Run on Fri Jul 31 19:05:14 2015
Reported on Fri Jul 31 19:08:10 2015

Filename/var/www/foswiki11/lib/Foswiki/Plugins/ChecklistPlugin.pm
StatementsExecuted 323 statements in 8.38ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
1311638µs937µsFoswiki::Plugins::ChecklistPlugin::::commonTagsHandlerFoswiki::Plugins::ChecklistPlugin::commonTagsHandler
1311299µs299µsFoswiki::Plugins::ChecklistPlugin::::handleAllTagsFoswiki::Plugins::ChecklistPlugin::handleAllTags
511137µs433µsFoswiki::Plugins::ChecklistPlugin::::postRenderingHandlerFoswiki::Plugins::ChecklistPlugin::postRenderingHandler
11167µs71µsFoswiki::Plugins::ChecklistPlugin::::initDefaultsFoswiki::Plugins::ChecklistPlugin::initDefaults
11137µs249µsFoswiki::Plugins::ChecklistPlugin::::initPluginFoswiki::Plugins::ChecklistPlugin::initPlugin
11118µs214µsFoswiki::Plugins::ChecklistPlugin::::BEGIN@23Foswiki::Plugins::ChecklistPlugin::BEGIN@23
1119µs22µsFoswiki::Plugins::ChecklistPlugin::::BEGIN@35Foswiki::Plugins::ChecklistPlugin::BEGIN@35
0000s0sFoswiki::Plugins::ChecklistPlugin::::checkChangeAccessPermissionFoswiki::Plugins::ChecklistPlugin::checkChangeAccessPermission
0000s0sFoswiki::Plugins::ChecklistPlugin::::collectAllChecklistItemsFoswiki::Plugins::ChecklistPlugin::collectAllChecklistItems
0000s0sFoswiki::Plugins::ChecklistPlugin::::createActionFoswiki::Plugins::ChecklistPlugin::createAction
0000s0sFoswiki::Plugins::ChecklistPlugin::::createHiddenDirectResetSelectionDivFoswiki::Plugins::ChecklistPlugin::createHiddenDirectResetSelectionDiv
0000s0sFoswiki::Plugins::ChecklistPlugin::::createHiddenDirectSelectionDivFoswiki::Plugins::ChecklistPlugin::createHiddenDirectSelectionDiv
0000s0sFoswiki::Plugins::ChecklistPlugin::::createResetActionFoswiki::Plugins::ChecklistPlugin::createResetAction
0000s0sFoswiki::Plugins::ChecklistPlugin::::createTitleFoswiki::Plugins::ChecklistPlugin::createTitle
0000s0sFoswiki::Plugins::ChecklistPlugin::::createUnknownParamsMessageFoswiki::Plugins::ChecklistPlugin::createUnknownParamsMessage
0000s0sFoswiki::Plugins::ChecklistPlugin::::doChecklistItemStateChangeFoswiki::Plugins::ChecklistPlugin::doChecklistItemStateChange
0000s0sFoswiki::Plugins::ChecklistPlugin::::doChecklistItemStateResetFoswiki::Plugins::ChecklistPlugin::doChecklistItemStateReset
0000s0sFoswiki::Plugins::ChecklistPlugin::::endRenderingHandlerFoswiki::Plugins::ChecklistPlugin::endRenderingHandler
0000s0sFoswiki::Plugins::ChecklistPlugin::::extractPermsFoswiki::Plugins::ChecklistPlugin::extractPerms
0000s0sFoswiki::Plugins::ChecklistPlugin::::getClisTopicNameFoswiki::Plugins::ChecklistPlugin::getClisTopicName
0000s0sFoswiki::Plugins::ChecklistPlugin::::getImageSrcFoswiki::Plugins::ChecklistPlugin::getImageSrc
0000s0sFoswiki::Plugins::ChecklistPlugin::::getLogEntryFoswiki::Plugins::ChecklistPlugin::getLogEntry
0000s0sFoswiki::Plugins::ChecklistPlugin::::getNameFoswiki::Plugins::ChecklistPlugin::getName
0000s0sFoswiki::Plugins::ChecklistPlugin::::getNextStateFoswiki::Plugins::ChecklistPlugin::getNextState
0000s0sFoswiki::Plugins::ChecklistPlugin::::getUniqueUrlParamFoswiki::Plugins::ChecklistPlugin::getUniqueUrlParam
0000s0sFoswiki::Plugins::ChecklistPlugin::::handleAutoChecklistFoswiki::Plugins::ChecklistPlugin::handleAutoChecklist
0000s0sFoswiki::Plugins::ChecklistPlugin::::handleChecklistFoswiki::Plugins::ChecklistPlugin::handleChecklist
0000s0sFoswiki::Plugins::ChecklistPlugin::::handleChecklistItemFoswiki::Plugins::ChecklistPlugin::handleChecklistItem
0000s0sFoswiki::Plugins::ChecklistPlugin::::handleDescriptionFoswiki::Plugins::ChecklistPlugin::handleDescription
0000s0sFoswiki::Plugins::ChecklistPlugin::::handleStateChangesFoswiki::Plugins::ChecklistPlugin::handleStateChanges
0000s0sFoswiki::Plugins::ChecklistPlugin::::htmlEncodeFoswiki::Plugins::ChecklistPlugin::htmlEncode
0000s0sFoswiki::Plugins::ChecklistPlugin::::initNamedDefaultsFoswiki::Plugins::ChecklistPlugin::initNamedDefaults
0000s0sFoswiki::Plugins::ChecklistPlugin::::initOptionsFoswiki::Plugins::ChecklistPlugin::initOptions
0000s0sFoswiki::Plugins::ChecklistPlugin::::initStatesFoswiki::Plugins::ChecklistPlugin::initStates
0000s0sFoswiki::Plugins::ChecklistPlugin::::readChecklistItemStateTopicFoswiki::Plugins::ChecklistPlugin::readChecklistItemStateTopic
0000s0sFoswiki::Plugins::ChecklistPlugin::::renderChecklistItemFoswiki::Plugins::ChecklistPlugin::renderChecklistItem
0000s0sFoswiki::Plugins::ChecklistPlugin::::renderLegendFoswiki::Plugins::ChecklistPlugin::renderLegend
0000s0sFoswiki::Plugins::ChecklistPlugin::::saveChecklistItemStateTopicFoswiki::Plugins::ChecklistPlugin::saveChecklistItemStateTopic
0000s0sFoswiki::Plugins::ChecklistPlugin::::saveLogFoswiki::Plugins::ChecklistPlugin::saveLog
0000s0sFoswiki::Plugins::ChecklistPlugin::::substAttributesFoswiki::Plugins::ChecklistPlugin::substAttributes
0000s0sFoswiki::Plugins::ChecklistPlugin::::substIllegalCharsFoswiki::Plugins::ChecklistPlugin::substIllegalChars
0000s0sFoswiki::Plugins::ChecklistPlugin::::substItemLineFoswiki::Plugins::ChecklistPlugin::substItemLine
0000s0sFoswiki::Plugins::ChecklistPlugin::::urlEncodeFoswiki::Plugins::ChecklistPlugin::urlEncode
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1# Plugin for Foswiki - The Free and Open Source Wiki, http://foswiki.org/
2#
3# Copyright (C) 2000-2003 Andrea Sterbini, a.sterbini@flashnet.it
4# Copyright (C) 2001-2004 Peter Thoeny, peter@thoeny.com
5# Copyright (C) 2005-2009 Daniel Rohde
6#
7# This program is free software; you can redistribute it and/or
8# modify it under the terms of the GNU General Public License
9# as published by the Free Software Foundation; either version 2
10# of the License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details, published at
16# http://www.gnu.org/copyleft/gpl.html
17#
18
19# =========================
20package Foswiki::Plugins::ChecklistPlugin;
21
22# =========================
2317µs1196µs
# spent 214µs (18+196) within Foswiki::Plugins::ChecklistPlugin::BEGIN@23 which was called: # once (18µs+196µs) by Foswiki::Plugin::BEGIN@2.7 at line 33
use vars qw(
# spent 196µs making 1 call to vars::import
24 $installWeb $VERSION $RELEASE $REVISION $pluginName
25 $debug %FoswikiCompatibility
26 %globalDefaults @renderedOptions @flagOptions @filteredOptions @listOptions @ignoreNamedDefaults
27 %options @unknownParams
28 %namedDefaults %namedIds $idMapRef $idOrderRef %namedResetIds %itemStatesRead
29 $resetDone $stateChangeDone $saveDone
30 $initText %itemsCollected $dryrun
31 $web $topic $user
32 $idOffset
33128µs1214µs );
# spent 214µs making 1 call to Foswiki::Plugins::ChecklistPlugin::BEGIN@23
34
3527.22ms234µs
# spent 22µs (9+12) within Foswiki::Plugins::ChecklistPlugin::BEGIN@35 which was called: # once (9µs+12µs) by Foswiki::Plugin::BEGIN@2.7 at line 35
use strict;
# spent 22µs making 1 call to Foswiki::Plugins::ChecklistPlugin::BEGIN@35 # spent 12µs making 1 call to strict::import
36####use warnings;
37
3811µs$FoswikiCompatibility{endRenderingHandler} = 1.1;
39
401400ns$VERSION = '$Rev: 5335 (2009-10-21) $';
41
421400ns$RELEASE = 'Cairo, Dakar, Edinburgh, ...';
43
44
451200ns$REVISION = '1.026'; #dro# added timestamp feature requested by TWiki:Main.VickiBrown; fixed uninitialized value bugs;
46#$REVISION = '1.025'; #dro# added documentation requested by TWiki:Main.PeterThoeny; added hide entries feature requested by Christian Holzmann; added log feature requested by TWiki:Main.VickiBrown
47#$REVISION = '1.024'; #dro# fixed missing ')' in generated JavaScript commands
48#$REVISION = '1.023'; #dro# fixed minor anchor link bug reported by TWiki:Main.KeithHelfrich; fixed tooltip position bug
49#$REVISION = '1.022'; #dro# improved AJAX performance; added new feature (state selection for reset button); fixed %TOC% bug reported by TWiki:Main.HelenJohnstone; fixed some minor and major bugs (mod_perl, description stripping, static feature, 'text' icons); removed useforms feature
50#$REVISION = '1.021'; #dro# fixed some major bug (mod_perl, plugin preferences); improved performance (AJAX); fixed minor IE caching bug (AJAX related); added new attributes (tooltip, descr, template, statesel) requested by TWiki:Main.KeithHelfrich; fixed installation instructions bug reported by TWiki:Main.KeithHelfrich
51#$REVISION = '1.020'; #dro# added AJAX feature (useajax attribute) requested by TWiki:Main.ShayPierce and TWiki:Main.KeithHelfrich
52#$REVISION = '1.019'; #dro# fixed major default options bug reported by TWiki:Main.RichardHitier
53#$REVISION = '1.018'; #dro# fixed notification bug reported by TWiki:Main.JosMaccabiani; fixed a minor whitespace bug; add static attribute
54#$REVISION = '1.017'; #dro# fixed access right bug; disabled change/create mail notification (added attribute: notify)
55#$REVISION = '1.016'; #dro# fixed access right bug reported by TWiki:Main.SaschaVogt
56#$REVISION = '1.015'; #dro# fixed mod_perl preload bug (removed 'use warnings;') reported by Foswiki:Main.KennethLavrsen
57#$REVISION = '1.014'; #dro# fixed mod_perl bug; fixed deprecated handler problem
58#$REVISION = '1.013'; #dro# fixed anchor bug; fixed multiple save bug (performance improvement); fixed reset bugs in named checklists
59#$REVISION = '1.012'; #dro# fixed a minor statetopic bug; improved autogenerated checklists (item insertion without state lost); improved docs
60#$REVISION = '1.011'; #dro# fixed documentation; fixed reset bug (that comes with URL parameter bug fix); added statetopic attribute
61#$REVISION = '1.010'; #dro# fixed URL parameter bugs (preserve URL parameters; URL encoding); used CGI module to generate HTML; fixed table sorting bug in a ChecklistItemState topic
62#$REVISION = '1.009'; #dro# fixed stateicons handling; fixed TablePlugin sorting problem
63#$REVISION = '1.008'; #dro# fixed docs; changed default text positioning (text attribute); allowed common variable usage in stateicons attribute; fixed multiple checklists bugs
64#$REVISION = '1.007'; #dro# added new feature (CHECKLISTSTART/END tags, attributes: clipos, pos); fixed bugs
65#$REVISION = '1.006'; #dro# added new attribute (useforms); fixed legend bug; fixed HTML encoding bug
66#$REVISION = '1.005'; #dro# fixed major bug (edit lock); fixed html encoding; improved doc
67#$REVISION = '1.004'; #dro# added unknown parameter handling (new attribute: unknownparamsmsg); added 'set to a given state' feature; changed reset behavior; fixed typos
68#$VERSION = '1.003'; #dro# added attributes (showlegend, anchors); fixed states bug (illegal characters in states option); improved documentation; fixed typos; fixed some minor bugs
69#$VERSION = '1.002'; #dro# fixed cache problems; fixed HTML/URL encoding bugs; fixed reload bug; fixed reset image button bug; added anchors
70#$VERSION = '1.001'; #dro# added new features ('reset','text' attributes); fixed 'name' attribute bug; fixed documentation bugs
71#$VERSION = '1.000'; #dro# initial version
72
731200ns$pluginName = 'ChecklistPlugin'; # Name of this Plugin
74
75# =========================
76sub initPlugin
77
# spent 249µs (37+211) within Foswiki::Plugins::ChecklistPlugin::initPlugin which was called: # once (37µs+211µs) by Foswiki::Plugin::__ANON__[/var/www/foswiki11/lib/Foswiki/Plugin.pm:241] at line 234 of /var/www/foswiki11/lib/Foswiki/Plugin.pm
{
7813µs ( $topic, $web, $user, $installWeb ) = @_;
79
80 # check for Plugins.pm versions
81121µs113µs if( $Foswiki::Plugins::VERSION < 1.021 ) {
# spent 13µs making 1 call to version::vxs::VCMP
82 Foswiki::Func::writeWarning( "Version mismatch between $pluginName and Plugins.pm" );
83 return 0;
84 }
85
86 # Get plugin debug flag
8714µs1127µs $debug = Foswiki::Func::getPluginPreferencesFlag( "DEBUG" );
# spent 127µs making 1 call to Foswiki::Func::getPluginPreferencesFlag
88
89 # XXX
90 ####$debug = 1;
91
9216µs171µs &initDefaults($web, $topic);
# spent 71µs making 1 call to Foswiki::Plugins::ChecklistPlugin::initDefaults
93
94 # Plugin correctly initialized
951300ns Foswiki::Func::writeDebug( "- Foswiki::Plugins::${pluginName}::initPlugin( $web.$topic ) is OK" ) if $debug;
9616µs return 1;
97}
98
99# =========================
100sub commonTagsHandler
101
# spent 937µs (638+299) within Foswiki::Plugins::ChecklistPlugin::commonTagsHandler which was called 13 times, avg 72µs/call: # 13 times (638µs+299µs) by Foswiki::Plugin::invoke at line 294 of /var/www/foswiki11/lib/Foswiki/Plugin.pm, avg 72µs/call
{
102### my ( $text, $topic, $web ) = @_; # do not uncomment, use $_[0], $_[1]... instead
103
104135µs Foswiki::Func::writeDebug( "- ${pluginName}::commonTagsHandler( $_[2].$_[1] )" ) if $debug;
105
106 # This is the place to define customized tags and variables
107 # Called by Foswiki::handleCommonTags, after %INCLUDE:"..."%
108
1091360µs local(%namedDefaults, %itemStatesRead, %namedIds, %namedResetIds, @unknownParams, $initText, $resetDone,$stateChangeDone,$saveDone,$idMapRef,$idOrderRef, %itemsCollected, $dryrun);
110
1111369µs $initText = $_[0] if $_[0] =~ /\%(CLI|CHECKLIST)/;
112
113138µs $idMapRef = { };
114137µs $idOrderRef = { };
1151311µs %namedIds = ( );
116133µs %namedResetIds = ( );
117
118134µs $resetDone = 0;
119132µs $stateChangeDone = 0;
120132µs $saveDone = 0;
121
122132µs $dryrun = 0;
123
124136µs %namedDefaults = ( );
125133µs %itemStatesRead = ( );
126136µs %itemsCollected = ( );
127
128
12913314µs $_[0] =~ s/<\/head>/<script src="%PUBURL%\/%SYSTEMWEB%\/$pluginName\/itemstatechange.js" language="javascript" type="text\/javascript"><\/script><\/head>/is unless ($_[0]=~/itemstatechange.js/);
1301383µs13299µs &handleAllTags(@_);
# spent 299µs making 13 calls to Foswiki::Plugins::ChecklistPlugin::handleAllTags, avg 23µs/call
131}
132
133# =========================
134
# spent 299µs within Foswiki::Plugins::ChecklistPlugin::handleAllTags which was called 13 times, avg 23µs/call: # 13 times (299µs+0s) by Foswiki::Plugins::ChecklistPlugin::commonTagsHandler at line 130, avg 23µs/call
sub handleAllTags {
135
136 ### my ( $text, $topic, $web ) = @_; # do not uncomment, use $_[0], $_[1]... instead
137 #
138
139
1401335µs $_[0] =~ s/%CHECKLISTSTART%(.*?)%CHECKLISTEND%/&handleAutoChecklist("",$1,$_[0])/sge;
1411336µs $_[0] =~ s/%CHECKLISTSTART{(.*?)}%(.*?)%CHECKLISTEND%/&handleAutoChecklist($1,$2,$_[0])/sge;
1421343µs $_[0] =~ s/%CHECKLIST%/&handleChecklist("",$_[0])/ge;
1431342µs $_[0] =~ s/%CHECKLIST{(.*?)}%/&handleChecklist($1,$_[0])/sge;
14413173µs $_[0] =~ s/%CLI({(.*?)})?%/&handleChecklistItem($2,$_[0],$-[0],$+[0])/sge;
145
146 ##$_[0] =~ s/([^\n\%]*)%CLI({(.*?)})?%([^\n\%]*)/$1.&handleChecklistItem($3,$_[0],$1,$4).$4/sge;
147}
148
149# =========================
150
# spent 71µs (67+4) within Foswiki::Plugins::ChecklistPlugin::initDefaults which was called: # once (67µs+4µs) by Foswiki::Plugins::ChecklistPlugin::initPlugin at line 92
sub initDefaults {
15112µs my ($web, $topic) = @_;
1521500ns Foswiki::Func::writeDebug("- ${pluginName}::initDefaults") if $debug;
153
15414µs14µs my $pubUrlPath = Foswiki::Func::getPubUrlPath();
# spent 4µs making 1 call to Foswiki::Func::getPubUrlPath
155145µs %globalDefaults = (
156 'id' => undef,
157 'name' => '_default',
158 'states' => 'todo|done',
159 'stateicons' =>':-I|:ok:',
160 'text' => '',
161 'reset' => undef,
162 'showlegend' => 0,
163 'anchors' => 1,
164 'unknownparamsmsg' => '%RED% Sorry, some parameters are unknown: %UNKNOWNPARAMSLIST% %ENDCOLOR% <br/> Allowed parameters are (see %SYSTEMWEB%.ChecklistPlugin topic for more details): %KNOWNPARAMSLIST%',
165 'clipos'=> 'right',
166 'pos'=>'bottom',
167 'statetopic'=> $topic.'ChecklistItemState',
168 'notify'=> 0,
169 'static'=> 0,
170 'useajax'=>1,
171 'tooltip'=>'Click me to change my state from \'%STATE%\' to \'%NEXTSTATE%\' <br/>t: %TIMESTAMP%',
172 'tooltipbgcolor'=>'%WEBBGCOLOR%',
173 'descr' => undef,
174 '_DEFAULT' => undef,
175 'ajaxtopicstyle'=>'plain',
176 'descrcharlimit'=>100,
177 'template' => undef,
178 'statesel' => 0,
179 'tooltipfixleft' => '-163',
180 'tooltipfixtop' => '0',
181 'hide'=> undef,
182 'log'=> 0,
183 'logformat'=>" * %SERVERTIME% - %WIKIUSERNAME% - Item %CLIID%: from %STATE% to %NEXTSTATE% \n",
184 'logtopic'=>$topic.'ChecklistLog',
185 'logpos' => 'append',
186 'timestampformat' => '%SERVERTIME% - %WIKIUSERNAME%, last state: %STATE%',
187 );
188
18912µs @listOptions = ('states','stateicons');
19012µs @renderedOptions = ( 'text', 'stateicons', 'reset', 'hide' );
191
19211µs @filteredOptions = ( 'id', 'name', 'states');
193
19412µs @flagOptions = ('showlegend', 'anchors', 'notify', 'static' , 'useajax', 'statesel', 'log');
195
19618µs @ignoreNamedDefaults = ('showlegend','reset','hide');
197}
198
199# =========================
200sub initOptions() {
201 my ($attributes) = @_;
202 my %params = &Foswiki::Func::extractParameters($attributes);
203
204 my @allOptions = keys %globalDefaults;
205
206 # Check attributes:
207 @unknownParams= ( );
208 foreach my $option (keys %params) {
209 push (@unknownParams, $option) unless grep(/^\Q$option\E$/, @allOptions);
210 }
211 return 0 if $#unknownParams != -1;
212
213 my $name = &getName(\%params);
214
215 # handle _DEFAULT option (_DEFAULT = descr)
216 $params{'descr'} = $params{'_DEFAULT'} if defined $params{'_DEFAULT'};
217
218 # handle templates:
219 my $tmplName = $params{'template'};
220 $tmplName = $namedDefaults{$name}{'template'} unless defined $tmplName;
221 $tmplName = ( &Foswiki::Func::getPreferencesValue("\U${pluginName}_TEMPLATE\E") || undef) unless defined $tmplName;
222
223 # Setup options (attributes>named defaults>plugin preferences>global defaults):
224 %options = ( );
225 foreach my $option (@allOptions) {
226 my $v = $params{$option};
227 $v = $namedDefaults{$name}{$option} unless defined $v;
228 if ((defined $tmplName)&&(!defined $v)) {
229 $v = (&Foswiki::Func::getPreferencesFlag("\U${pluginName}_TEMPLATE_${tmplName}_${option}\E") || undef) if grep /^\Q$option\E$/, @flagOptions;
230 $v = (&Foswiki::Func::getPreferencesValue("\U${pluginName}_TEMPLATE_${tmplName}_${option}\E") || undef) unless defined $v;
231 $v = undef if (defined $v) && ($v eq "");
232 }
233
234 if (defined $v) {
235 if (grep /^\Q$option\E$/, @flagOptions) {
236 $options{$option} = ($v!~/(false|no|off|0|disable)/i);
237 } else {
238 $options{$option} = $v;
239 }
240 } else {
241 if (grep /^\Q$option\E$/, @flagOptions) {
242 $v = ( Foswiki::Func::getPreferencesFlag("\U${pluginName}_$option\E") || undef );
243 } else {
244 $v = Foswiki::Func::getPreferencesValue("\U${pluginName}_$option\E");
245 }
246 $v = undef if (defined $v) && ($v eq "");
247 $options{$option}= (defined $v?$v:$globalDefaults{$option});
248 }
249 }
250
251 # Render some options:
252 foreach my $option (@renderedOptions) {
253 next unless defined $options{$option};
254 if ($options{$option} !~ /^(\s|\&nbsp\;)*$/) {
255 $options{$option}=~s/(<nop>|!)//sg;
256 $options{$option}=&Foswiki::Func::expandCommonVariables($options{$option},$topic, $web);
257 if (grep /^\Q$option\E$/,@listOptions) {
258 my @newlist = ( );
259 foreach my $i (split /\|/,$options{$option}) {
260 my $newval=&Foswiki::Func::renderText($i, $web);
261 $newval=~s/\|/\&brvbar\;/sg;
262 push @newlist, $newval;
263 }
264 $options{$option}=join('|',@newlist);
265 } else {
266 $options{$option}=&Foswiki::Func::renderText($options{$option}, $web);
267 }
268 }
269 }
270
271 # filter some options:
272 foreach my $option (@filteredOptions) {
273 next unless defined $options{$option};
274 if (grep /^\Q$option\E$/,@listOptions) {
275 my @newlist = ( ) ;
276 foreach my $i (split /\|/, $options{$option}) {
277 my $newval = &substIllegalChars($i);
278 $newval=~s/\|/\&brvbar\;/sg;
279 push @newlist, $newval;
280 }
281 $options{$option}=join('|',@newlist);
282 } else {
283 $options{$option}=&substIllegalChars($options{$option});
284 }
285 }
286
- -
289 return 1;
290}
291# =========================
292sub initNamedDefaults {
293 my ($attributes) = @_;
294
295 my %params = Foswiki::Func::extractParameters($attributes);
296
297 my $name = &getName(\%params);
298
299 my $tmplName = (defined $params{'template'}?$params{'template'}:undef);
300 $tmplName = ( &Foswiki::Func::getPreferencesValue("\U${pluginName}_TEMPLATE\E") || undef) unless defined $tmplName;
301 # create named defaults (attributes>named defaults>global defaults):
302 foreach my $default (keys %globalDefaults) {
303 next if grep(/^\Q$default\E$/,@ignoreNamedDefaults);
304 $namedDefaults{$name}{$default}= $params{$default} if defined $params{$default};
305 $namedDefaults{$name}{$default}= (&Foswiki::Func::getPreferencesValue("\U${pluginName}_TEMPLATE_${tmplName}_${default}\E") || undef) unless (!defined $tmplName) || (defined $params{$default});
306
307 }
308}
309# =========================
310sub initStates {
311 my ($query) = @_;
312 if ((!defined $itemsCollected{"$web.$topic"}) &&((defined $query->param('clpsc'))||(defined $query->param('clreset')))) {
313 $itemsCollected{"$web.$topic"}=1;
314 &collectAllChecklistItems() ;
315 }
316 # read item states:
317 if (! $itemStatesRead{$options{'name'}}) {
318 $itemStatesRead{$options{'name'}} = 1;
319 &readChecklistItemStateTopic($idMapRef);
320 }
321}
322# =========================
323sub renderLegend {
324 my $query = &Foswiki::Func::getCgiQuery();
325 my @states = split /\|/, $options{'states'};
326 my @icons = split /\|/, $options{'stateicons'};
327 my $legend.=qq@<noautolink>@;
328 $legend.=qq@(@;
329 foreach my $state (@states) {
330 my $icon = shift @icons;
331 my ($iconsrc) = &getImageSrc($icon);
332 my $heState = &htmlEncode($state);
333 $iconsrc="" unless defined $iconsrc;
334 $legend.=$query->img({src=>$iconsrc, alt=>$heState, title=>$heState});
335 $legend.=qq@ - $heState @;
336 }
337 $legend.=qq@) @;
338 $legend.=qq@</noautolink>@;
339 return $legend;
340}
341# =========================
342sub handleChecklist {
343 my ($attributes, $refText) = @_;
344
345 Foswiki::Func::writeDebug("- ${pluginName}::handleChecklist($attributes,...refText...)") if $debug;
346
347 my $text="";
348
349 &initNamedDefaults($attributes);
350
351 local(%options);
352 return &createUnknownParamsMessage() unless &initOptions($attributes);
353
354 my $query = &Foswiki::Func::getCgiQuery();
355 my %params = &Foswiki::Func::extractParameters($attributes);
356 my $name = &getName(\%params);
357
358 my @states = split /\|/, $options{'states'};
359 my @icons = split /\|/, $options{'stateicons'};
360
361
362 if ((defined $query->param('clreset'))&&(!$resetDone)) {
363 &initStates($query);
364 my $n=$query->param('clreset');
365 my $s=(defined $query->param('clresetst'))?$query->param('clresetst'):$states[0];
366 if (($options{'name'} eq $n)&&(grep(/^\Q$s\E$/s, @states))) {
367 &doChecklistItemStateReset($n,$s,$refText);
368 $resetDone=1;
369 }
370 }
371
372 return "" if $dryrun;
373
374 my $legend = $options{'showlegend'}?&renderLegend():"";
375
376 if (defined $options{'reset'} && !$options{'static'}) {
377 $namedResetIds{$name}++;
378 my $reset = $options{'reset'};
379 my $state = (split /\|/, $options{'states'})[0];
380
381 if ($reset=~/\@(\S+)/s) {
382 $state=$1;
383 $reset=~s/\@\S+//s;
384 }
385
386 my ($imgsrc) = &getImageSrc($reset);
387 $imgsrc="" unless defined $imgsrc;
388
389 my $title=$reset;
390 $title=~s/<\S+[^>]*\>//sg; # strip HTML
391 $title=&htmlEncode($title);
392
393 my $action = &createResetAction($name, $state);
394
395 $text.=qq@<noautolink>@;
396
397 $text.=$query->a({name=>"reset${name}"}, '&nbsp;') if $options{'anchors'} && !$options{'useajax'};
398 $text.=$legend;
399 my $linktext="";
400 my $imgparams = {title=>$title, alt=>$title, border=>0};
401 $$imgparams{src}=$imgsrc if (defined $imgsrc ); # && ($imgsrc!~/^\s*$/s);
402 $linktext.=$query->img($imgparams);
403 $linktext.=qq@ ${title}@ if ($title!~/^\s*$/i)&&($imgsrc ne "");
404 $action="javascript:submitItemStateChange('$action');" if $options{'useajax'} && ($state ne 'STATESEL');
405 my $id = &urlEncode("${name}_${state}_".$namedResetIds{$name});
406 if ($state eq 'STATESEL') {
407 $text.=&createHiddenDirectResetSelectionDiv($namedResetIds{$name},$name,\@states,\@icons);
408 $action="javascript:clpTooltipShow('CLP_SM_DIV_RESET_${name}_$namedResetIds{$name}', 'CLP_A_$id',".(10+int($options{'tooltipfixleft'})).",".(10+int($options{'tooltipfixtop'})).",true);";
409 }
410 $text.=$query->a({href=>$action,id=>'CLP_A_'.$id}, $linktext);
411
412 $text.=qq@</noautolink>@;
413 } else {
414 $text.=$legend;
415 }
416 if (defined $options{hide}) {
417 my $state="";
418 $state = $1 if ($options{hide}=~s/\@(\S+)//g);
419 $state = "" if $state eq $options{hide};
420 $text .= $query->a({href=>"javascript: clpHideShowToggle('$options{name}','$state')"}, $options{hide});
421 }
422
423 return $text;
424}
425# =========================
426sub createResetAction {
427 my ($name, $state) = @_;
428 my $action=&Foswiki::Func::getViewUrl($web,$topic);
429 $action=~s/#.*$//s;
430 $action.=&getUniqueUrlParam($action);
431
432 $action.=($action=~/\?/?';':'?');
433 $action.="clreset=".&urlEncode($name);
434 $action.=";clresetst=".&urlEncode($state);
435 $action.=';skin='.&urlEncode($options{'ajaxtopicstyle'}) if $options{'useajax'};
436
437 $action.="#reset${name}" if $options{'anchors'} && !$options{'useajax'};
438 return $action;
439}
440# =========================
441sub createHiddenDirectResetSelectionDiv {
442 my ($id, $name, $statesRef, $iconsRef) = @_;
443 my $selTxt ="";
444 my $query = &Foswiki::Func::getCgiQuery();
445 $selTxt=$query->sup($query->a({-href=>"javascript:clpTooltipHide('CLP_SM_DIV_RESET_${name}_$id');"},'[X]'));
446 for (my $i=0; $i<=$#$statesRef; $i++) {
447 my $s = $$statesRef[$i];
448 my $action = &createResetAction($name, $s);
449 $action="javascript:submitItemStateChange('$action');clpTooltipHide('CLP_SM_DIV_RESET_${name}_$id');" if $options{'useajax'};
450 my $imgsrc = (&getImageSrc($$iconsRef[$i]))[0];
451 my $imgalt = (defined $imgsrc)?"":$s;
452 $imgsrc="" unless defined $imgsrc;
453 $selTxt.=$query->a({-href=>$action,-title=>$s,-style=>'vertical-align:bottom;'},
454 $query->img({src=>$imgsrc,alt=>$imgalt,border=>0,style=>'cursor:move;vertical-align:bottom'}));
455 $selTxt.='&nbsp;';
456 }
457
458 return $query->div({-id=>"CLP_SM_DIV_RESET_${name}_$id",
459 -style=>"visibility:hidden;position:absolute;top:0;left:0;z-index:2;font: normal 8pt sans-serif;padding: 3px; border: solid 1px; background-color: $options{'tooltipbgcolor'};" }, $selTxt);
460}
461# =========================
462sub substAttributes {
463 my ($attributes, $p) = @_;
464
465 my %attrHash = &Foswiki::Func::extractParameters($attributes);
466 my %pHash = (defined $p?&Foswiki::Func::extractParameters($p):());
467
468 foreach my $a (keys %attrHash) {
469 $pHash{$a}=$attrHash{$a};
470 }
471 my $attr ="";
472 foreach my $a (keys %pHash) {
473 $attr .= ' '.$a.'="'.$pHash{$a}.'"';
474 }
475
476 return '%CLI{'.$attr.'}%';
477}
478# =========================
479sub substItemLine {
480 my ($l,$attribs)=@_;
481 if ($l=~s/(\s+)\#(\S+)/$1/) {
482 $attribs.=" id=\"$2\"";
483 }
484
485 $idOffset++;
486
487 $namedIds{$options{name}} = 0 unless defined $namedIds{$options{name}};
488
489 my $id = "CLP_HIDE_ID_".$options{name}.($namedIds{$options{name}} + $idOffset);
490 my $name = "CLP_HIDE_NAME_".$options{name};
491 my @states = split /\|/, $options{'states'};
492 my $state = $$idMapRef{$options{name}}{$namedIds{$options{name}}+$idOffset}{state};
493 $state = $states[0] unless defined $state;
494 my $class = "clp_hide_".$options{name}."_".$state;
495
496 if ($l=~/\%CLI{.*?}\%/) {
497 $l=~s/\%CLI{(.*?)}\%/\%CLI{$1 $attribs}\%/g;
498 $l=~s/^/<span id="$id" name="$name" class="$class">/;
499 $l=~s/$/<\/span>/;
500 } else {
501 if (lc($options{'clipos'}) eq 'left') {
502 ###$l=~s/^(\s+[\d\*]+)/"$1 \%CLI{$attribs}% "/e;
503 $l=~s/^(\s+[\d\*]+)(.*)$/"$1 <span id=\"$id\" name=\"$name\" class=\"$class\">\%CLI{$attribs}\% $2<\/span>"/e;
504 } else {
505 ###$l=~s/^(\s+[\d\*]+.*?)$/"$1 \%CLI{$attribs}%"/e;
506 $l=~s/^(\s+[\d\*]+)(.*?)$/"$1 <span id=\"$id\" name=\"$name\" class=\"$class\">$2 \%CLI{$attribs}\%<\/span>"/e;
507 }
508 }
509
510 return $l;
511};
512# =========================
513sub handleAutoChecklist {
514 my ($attributes, $text) = @_;
515
516 Foswiki::Func::writeDebug("- ${pluginName}::handleAutoChecklist($attributes,...text...)") if $debug;
517
518 &initNamedDefaults($attributes);
519
520 local(%options); local($idOffset);
521 return &createUnknownParamsMessage() unless &initOptions($attributes);
522
523 initStates(Foswiki::Func::getCgiQuery());
524
525 handleStateChanges();
526
527
528 $text=~s/\%CLI(\{([^\}]*)\})?\%/&substAttributes($attributes, $2)/meg;
529 $text=~s/^(\s+[\d\*]+.*?)$/&substItemLine($1,$attributes)/meg;
530 $text=~s/([^\n]+?\s+)\#(\S+)/$1.&substAttributes($attributes, "id=\"$2\"")/meg;
531
532 if (lc($options{'pos'}) eq 'top' ) {
533 $text="\%CHECKLIST{$attributes}\%\n$text";
534 } else {
535 $text.="\n\%CHECKLIST{$attributes}\%";
536 }
537
538 return $text;
539
540}
541# =========================
542sub handleChecklistItem {
543 my ($attributes, $text,$startOffset,$endOffset) = @_;
544
545 Foswiki::Func::writeDebug("- ${pluginName}::handleChecklistItem($attributes)") if $debug;
546
547 local(%options);
548 return &createUnknownParamsMessage() unless &initOptions($attributes);
549
550 my $query = &Foswiki::Func::getCgiQuery();
551
552 &initStates($query);
553
554 $namedIds{$options{'name'}}++ unless defined $options{'id'};
555
556 &handleDescription($text, $startOffset, $endOffset);
557
558 my $name = $options{'name'};
559 my $id = $options{'id'}?$options{'id'}:$namedIds{$name};
560 my $last = $$idMapRef{$name}{$id}{'state'};
561
562 if ((defined $query->param('clpsc'))&&(!$stateChangeDone)) {
563 my ($id,$name,$lastState,$nextstate) = ($query->param('clpsc'),$query->param('clpscn'),$query->param('clpscls'),$query->param('clpscns'));
564 if ($options{'name'} eq $name) {
565 &doChecklistItemStateChange($id, $name, $lastState, $text, $nextstate) ;
566 $stateChangeDone=1;
567 }
568 }
569
570 my $state = (defined $$idMapRef{$name}{$id}{'state'}) ? $$idMapRef{$name}{$id}{'state'} : (split(/\|/, $options{'states'}))[0];
571 my $timestamp = (defined $$idMapRef{$name}{$id}{'timestamp'}) ? $$idMapRef{$name}{$id}{'timestamp'} : getLogEntry($options{timestampformat},$id,$name,$last, $state);
572
573 $$idMapRef{$name}{$id}{'state'}=$state unless defined $$idMapRef{$name}{$id}{'state'};
574 $$idMapRef{$name}{$id}{'descr'}=$options{'descr'} if defined $options{'descr'};
575 $$idMapRef{$name}{$id}{'timestamp'}=$timestamp;
576
577 push(@{$$idOrderRef{$name}}, $id) unless grep(/^\Q$id\E$/,@{$$idOrderRef{$name}});
578
579 return "" if $dryrun;
580
581 return &renderChecklistItem();
582
583}
584# =========================
585sub handleDescription {
586 my ($text, $startOffset, $endOffset) = @_;
587
588 my $si = $startOffset - $options{'descrcharlimit'};
589 $si = 0 if ($si < 0);
590 my $textBefore = substr( $text, $si, $startOffset-$si);
591 my $textAfter = substr($text, $endOffset+1, $options{'descrcharlimit'});
592
593 $textBefore =~ /([^>\n\%]*)$/;
594 $textBefore = $1 if defined $1;
595
596 $textAfter =~ /^([^<\n\%]*)/;
597 $textAfter = $1 if defined $1;
598
599 my $descr = $$idMapRef{$options{'name'}}{$options{'id'}?$options{'id'}:$namedIds{$options{'name'}}}{'descr'};
600 unless ( (defined $options{'descr'}) || ((defined $descr)&&($descr!~/^\s*$/))) {
601 $options{'descr'}=$options{'text'} if (defined $options{'text'})&&($options{'text'}!~/^\s*$/s);
602
603 my $text = $textBefore;
604 $text.=" ... " if $textBefore !~ /^\s*$/;
605 $text.=$textAfter;
606 $text.=" ..." if $textAfter !~ /^\s*$/;
607 $options{'descr'}=$text unless defined $options{'descr'};
608
609 $options{'descr'}=~s/^\s{3,}[\*\d]//sg; ## remove lists
610 $options{'descr'}=~s/\|/ /sg; ## remove tables
611 $options{'descr'}=~s/<[\/]?[^>]+>/ /sg; ## remove HTML tags
612 $options{'descr'}=~s/\%\w+[^\%]*\%/ /sg; ## remove variables
613
614 $options{'descr'}=~s/\s{2,}/ /g; ## remove multiple spaces
615 $options{'descr'}=~s/^\s*//g;
616 $options{'descr'}=~s/\s*$//g;
617
618
619 };
620 $options{'descr'}=substr($options{'descr'},0,$options{'descrcharlimit'})
621 if (defined $options{'descr'})&&(length($options{'descr'})>$options{'descrcharlimit'});
622}
623
624# =========================
625sub getNextState {
626 my ($name, $lastState) = @_;
627 my @states = split /\|/, $options{'states'};
628 my @icons = split /\|/, $options{'stateicons'};
629
630 $lastState=$states[0] if ! defined $lastState;
631
632 my $state = $states[0];
633 my $icon = $icons[0];
634 for (my $i=0; $i<=$#states; $i++) {
635 if ($states[$i] eq $lastState) {
636 $state=($i<$#states)?$states[$i+1]:$states[0];
637 $icon=($i<$#states)?$icons[$i+1]:$icons[0];
638 last;
639 }
640 }
641 Foswiki::Func::writeDebug("- ${pluginName}::getNextState($name, $lastState)=$state; allstates=".$options{states}) if $debug;
642
643 return ($state, $icon);
644
645}
646# =========================
647sub checkChangeAccessPermission {
648 my ($name, $text) = @_;
649 my $ret = 1;
650
651 my $perm = 'CHANGE';
652 my $checkTopic = $topic;
653 unless (&Foswiki::Func::topicExists($web, &getClisTopicName($name))) {
654 $perm='CREATE';
655 $checkTopic = &getClisTopicName($name);
656 $text = undef;
657 }
658
659
660 my $mainWebName=&Foswiki::Func::getMainWebname();
661 my $user =Foswiki::Func::getWikiName();
662 $user = "$mainWebName.$user" unless $user =~ m/^$mainWebName\./;
663
664 if ( ! &Foswiki::Func::checkAccessPermission($perm, $user, $text, $checkTopic, $web)) {
665 $ret = 0;
666
667 eval { require Foswiki::AccessControlException; };
668 if ($@) {
669 Foswiki::Func::redirectCgiQuery(Foswiki::Func::getCgiQuery(),Foswiki::Func::getOopsUrl($web,$checkTopic,"oopsaccesschange"));
670 } else {
671 require Error;
672 throw Foswiki::AccessControlException(
673 $perm,
674 $Foswiki::Plugins::SESSION->{user},
675 $checkTopic, $web, 'denied'
676 );
677 }
678 }
679 return $ret;
680}
681# =========================
682sub extractPerms {
683 my ($text) = @_;
684 my $perms;
685
686 $text="" unless defined $text;
687 $perms=join("\n",grep /^\s+\*\s*Set (ALLOW|DENY).+/i,split(/\n/,$text));
688
689 return $perms;
690}
691# =========================
692sub doChecklistItemStateReset {
693 my ($n, $state, $text) = @_;
694 Foswiki::Func::writeDebug("- ${pluginName}::doChecklistItemStateReset($n,$state,...text...)") if $debug;
695
696 # access granted?
697 return if ! &checkChangeAccessPermission($n, $text);
698
699 if (!defined $state) {
700 my @states=split /\|/, $options{'states'};
701 $state=$states[0];
702 }
703 foreach my $id (keys %{$$idMapRef{$n}}) {
704 $$idMapRef{$n}{$id}{'timestamp'}=getLogEntry($options{timestampformat},$id,$n,$$idMapRef{$n}{$id}{'state'}, $state);
705 $$idMapRef{$n}{$id}{'state'}=$state;
706 }
707 saveLog('reset', $n, 'any', $state) if $options{log} && !$saveDone;
708 &saveChecklistItemStateTopic($n,&extractPerms($text)) if (!$saveDone) && (($saveDone=!$saveDone));
709}
710# =========================
711sub doChecklistItemStateChange {
712 my ($id, $n, $lastState, $text, $nextstate) = @_;
713 Foswiki::Func::writeDebug("- ${pluginName}::doChecklistItemStateChange($id,$n,$lastState,...text...)") if $debug;
714
715 # access granted?
716 return if ! &checkChangeAccessPermission($n, $text);
717
718 # reload?
719 return if ((defined $$idMapRef{$n}{$id}{'state'})&&($$idMapRef{$n}{$id}{'state'} ne $lastState));
720
721 my $rns = (defined $nextstate?$nextstate:(&getNextState($n, $$idMapRef{$n}{$id}{'state'}))[0]);
722
723 $$idMapRef{$n}{$id}{'state'}=$rns;
724 $$idMapRef{$n}{$id}{'timestamp'}=getLogEntry($options{timestampformat},$id, $n, $lastState, $nextstate);
725
726 &saveLog($id, $n, $lastState, $rns) if $options{log} && !$saveDone;
727 &saveChecklistItemStateTopic($n,&extractPerms($text)) if (!$saveDone) && (($saveDone=!$saveDone));
728}
729# =========================
730sub createAction {
731 my ($id, $name, $state, $nextstate) = @_;
732 my $action=Foswiki::Func::getViewUrl($web,$topic);
733
734 # remove anchor:
735 $action=~s/#.*$//i;
736
737 $action.=getUniqueUrlParam($action);
738
739 $action.=($action=~/\?/)?";":"?";
740 $action.="clpsc=".&urlEncode("$id");
741 $action.=";clpscn=".&urlEncode($name);
742 $action.=";clpscls=".&urlEncode($state);
743 $action.=";clpscns=".&urlEncode($nextstate) if defined $nextstate;
744 $action.=';skin='.&urlEncode($options{'ajaxtopicstyle'}) if $options{'useajax'};
745
746 my $query = &Foswiki::Func::getCgiQuery();
747 my %queryVars = $query->Vars();
748 foreach my $p (keys %queryVars) {
749 $action.=";$p=".&urlEncode($queryVars{$p})
750 unless ($p =~ /^(clp.*|clreset.*|contenttype|skin)$/i)||(!$queryVars{$p});
751 }
752 $action.="#$name$id" if $options{'anchors'} && (!$options{'useajax'});
753
754 return $action;
755}
756# =========================
757sub createTitle {
758 my ($name,$state,$icon,$statesRef, $nextstate, $nextstateicon, $tId, $timestamp) = @_;
759 ($nextstate, $nextstateicon) = &getNextState($name,$state) unless defined $nextstate;
760 my $query = &Foswiki::Func::getCgiQuery();
761 my $title = $options{'tooltip'};
762 $title = $state unless defined $title;
763 $title =~ s/\%STATE\%/$state/sg;
764 $title =~ s/\%NEXTSTATE\%/$nextstate/esg;
765 $title =~ s/\%STATECOUNT\%/($#$statesRef+1)/esg;
766 $title =~ s/\%STATES\%/join(", ",@{$statesRef})/esg;
767 $title =~ s/\%LEGEND\%/&renderLegend()/esg;
768 $title =~ s/\%STATEICON\%/$query->img({alt=>$state,src=>(&getImageSrc($icon))[0]})/esg;
769 $title =~ s/\%NEXTSTATEICON\%/$query->img({alt=>$nextstate,src=>(&getImageSrc($nextstateicon))[0]})/esg;
770 $title =~ s/\%TIMESTAMP\%/$timestamp/esg;
771 return $title;
772}
773# =========================
774sub renderChecklistItem {
775 Foswiki::Func::writeDebug("- ${pluginName}::renderChecklistItem()") if $debug;
776 my $query = &Foswiki::Func::getCgiQuery();
777 my $text = "";
778 my $name = $options{'name'};
779
780 my @states = split /\|/, $options{'states'};
781 my @icons = split /\|/, $options{'stateicons'};
782
783 my $tId = $options{'id'}?$options{'id'}:$namedIds{$name};
784
785 my $timestamp = $$idMapRef{$name}{$tId}{'timestamp'};
786 $timestamp = "" unless defined $timestamp;
787
788 my $state = (defined $$idMapRef{$name}{$tId}{'state'}) ? $$idMapRef{$name}{$tId}{'state'} : $states[0];
789 my $icon = $icons[0];
790
791 for (my $i=0; $i<=$#states; $i++) {
792 if ($states[$i] eq $state) {
793 $icon=$icons[$i];
794 last;
795 }
796 }
797
798 my ($iconsrc,$textBef,$textAft)=&getImageSrc($icon);
799
800 my $stId = &substIllegalChars($tId); # substituted tId
801 my $heState = &htmlEncode($state); # HTML encoded state
802 my $ueState = &urlEncode($state); # URL encoded state
803 my $uetId = &urlEncode($tId); # URL encoded tId
804
805
806 my $action = &createAction($stId, $name, $state);
807
808 $text.=qq@<noautolink>@;
809
810 $text.=$query->comment('CLTABLEPLUGINSORTFIX:');
811 $text.=$query->div({-style=>"visibility:hidden;position:absolute;top:0;left:0;z-index:2;" },$heState);
812 $text.=$query->comment(':CLTABLEPLUGINSORTFIX');
813
814 $text.=$query->a({name=>"$name$uetId"}, '&nbsp;') if $options{'anchors'} && !$options{'useajax'};
815
816 my $linktext="";
817 if (lc($options{'clipos'}) ne 'left') {
818 $linktext.=$options{'text'}.' ' unless $options{'text'} =~ /^(\s|\&nbsp\;)*$/;
819 }
820
821 my $title = &createTitle($name, $state, $icon, \@states, undef,undef,$tId, $timestamp);
822
823 $linktext.=qq@$textBef@ if $textBef;
824 my $imgalt = (!defined $iconsrc)?$state:"";
825 $iconsrc = "" unless defined $iconsrc;
826 $linktext.=$query->img({-name=>"CLP_IMG_$name$uetId", -src=>$iconsrc, -border=>0, -alt=>$imgalt});
827 $linktext.=qq@$textAft@ if $textAft;
828 if (lc($options{'clipos'}) eq 'left') {
829 $linktext.=' '.$options{'text'} unless $options{'text'} =~ /^(\s|\&nbsp\;)*$/;
830 }
831
832 my ($onmouseover, $onmouseout)=("","");
833 $action="javascript:submitItemStateChange('$action');" if $options{'useajax'};
834 $onmouseover="clpTooltipShow('CLP_TT_$name$uetId','CLP_A_$name$uetId',".(20+int($options{'tooltipfixleft'})).",".(20+int($options{'tooltipfixtop'})).",true);";
835 $onmouseout="clpTooltipHide('CLP_TT_$name$uetId');";
836 $text .= $query->div({-id=>"CLP_TT_$name$uetId",-style=>"visibility:hidden;position:absolute;top:0;left:0;z-index:2;font: normal 8pt sans-serif;padding: 3px; border: solid 1px; background-color: $options{'tooltipbgcolor'};"},$title);
837 if ($options{'statesel'} && (!$options{'static'})) {
838 $action="javascript:clpTooltipShow('CLP_SM_DIV_$name$uetId','CLP_A_$name$uetId',".(10+int($options{'tooltipfixleft'})).",".(10+int($options{'tooltipfixtop'})).",true);";
839 $text .= &createHiddenDirectSelectionDiv($uetId, $name, $state, $icon, \@states, \@icons, $tId, $timestamp);
840 }
841 $action = "javascript:;" if $options{'static'};
842 $text .= $query->a({-onmouseover=>$onmouseover,-onmouseout=>$onmouseout,-id=>"CLP_A_$name$uetId",-name=>"CLP_A_$name$uetId",-href=>$action}, $linktext);
843
844 $text.=qq@</noautolink>@;
845
846 return $text;
847}
848# =========================
849sub createHiddenDirectSelectionDiv {
850 my ($id, $name, $state, $icon, $statesRef, $iconsRef, $tId, $timestamp) = @_;
851 my $text ="";
852
853 my $query = &Foswiki::Func::getCgiQuery();
854 my $sl="";
855 $sl.=$query->sup($query->a({-href=>"javascript:clpTooltipHide('CLP_SM_DIV_$name$id');", -title=>'close'},'[X]'));
856 for (my $i=0; $i<=$#$statesRef; $i++) {
857 my ($s, $ic) = ($$statesRef[$i], $$iconsRef[$i]);
858 my $action = &createAction($id, $name, $state, $s);
859 my $title = &createTitle($name,$state,$icon,$statesRef, $s, $ic, $tId, $timestamp);
860 my $submitAction = "";
861 if ($options{'useajax'}) {
862 $submitAction = "submitItemStateChange('$action');clpTooltipHide('CLP_SM_DIV_$name$id');";
863 $action="javascript:$submitAction";
864 }
865 $text .= $query->div({-id=>"CLP_SM_TT_$name${id}_$i",-style=>"visibility:hidden;position:absolute;top:0;left:0;z-index:3;font: normal 8pt sans-serif;padding: 3px; border: solid 1px; background-color: $options{'tooltipbgcolor'};"},$title);
866 my $imgsrc = (&getImageSrc($ic))[0];
867 my $imgalt = (defined $imgsrc)?"":$s;
868 $imgsrc="" if !defined $imgsrc;
869 $sl.=$query->a({
870 -id=>"CLP_SM_A_$name${id}_$i",
871 -href=>"$action",
872 -style=>'vertical-align:bottom;',
873 -onmouseover=>"clpTooltipShow('CLP_SM_TT_$name${id}_$i','CLP_SM_IMG_$name${id}_$i',".(20+int($options{'tooltipfixleft'})).",".(20+int($options{'tooltipfixtop'})).");",
874 -onmouseout=>"clpTooltipHide('CLP_SM_TT_$name${id}_$i');",
875 },
876 $query->img({src=>$imgsrc,id=>"CLP_SM_IMG_$name${id}_$i",alt=>$imgalt,border=>0,style=>'vertical-align:bottom;cursor:move;'}));
877 $sl.='&nbsp;';
878 }
879
880 $text.= $query->div({-id=>"CLP_SM_DIV_$name$id",
881 -style=>"visibility:hidden;position:absolute;top:0;left:0;z-index:2;font: normal 8pt sans-serif;padding: 3px; border: solid 1px; background-color: $options{'tooltipbgcolor'};"}, $sl);
882
883 return $text;
884}
885# =========================
886sub getUniqueUrlParam {
887 my ($url) = @_;
888 my $r = 0;
889 $r = rand(1000) while ($r <= 100);
890 return (($url=~/\?/)?'&':'?').'clpid='.time().int($r);
891}
892# =========================
893sub urlEncode {
894 my ($txt)=@_;
895 $txt=~s/([^A-Za-z0-9\$\-\_\.\+\!\*\'\(\)\,])/sprintf("%%%02X", ord($1))/seg if defined $txt;
896 return $txt;
897}
898# =========================
899sub htmlEncode {
900 my ($txt)=@_;
901 return "" unless defined $txt;
902 $txt=~s/(["<>])/sprintf("&#%02X;", ord($1))/seg;
903
904 return $txt;
905}
906# ========================
907sub substIllegalChars {
908 my ($txt) = @_;
909 $txt=~s/[^A-Za-z0-9\-\.\_]//sg if defined $txt;
910 return $txt;
911}
912# ========================
913sub getImageSrc {
914 my ($txt)=@_;
915 my ($src,$b,$a) = (undef, undef, undef);
916 ##if ($txt=~/$(.*?)img[^>]+?src="([^">]+?)"[^>]*(.*)$/is) {
917 if ($txt=~/^([^<]*)<img[^>]+?src="([^">]+?)"[^>]*>(.*)$/is) {
918 ##$src=$1;
919 ($b,$src,$a)=($1,$2,$3);
920 }
921 return ($src,$b,$a);
922}
923
- -
926# =========================
927sub readChecklistItemStateTopic {
928 my ($idMapRef) = @_;
929 my $clisTopicName = $options{'statetopic'};
930 Foswiki::Func::writeDebug("- ${pluginName}::readChecklistItemStateTopic($topic, $web): $clisTopicName") if $debug;
931
932 my $clisTopic = Foswiki::Func::readTopicText($web, $clisTopicName);
933
934 if ($clisTopic =~ /^http.*?\/oops/) {
935 Foswiki::Func::redirectCgiQuery(Foswiki::Func::getCgiQuery(), $clisTopic);
936 return;
937 }
938
939 foreach my $line (split /[\r\n]+/, $clisTopic) {
940 if ($line =~ /^\s*\|\s*([^\|\*\s]*)\s*\|\s*([^\|\*\s]*)\s*\|\s*([^\|\s]*)\s*\|(\s*([^\|]+)\s*\|)?(\s*([^\|]+)\s*\|)?\s*$/) {
941 my ($name,$id,$state,$descr,$timestamp) = ($1,$2,$3,$5,$7);
942 $$idMapRef{$name}{$id}{'state'}=$state;
943 $$idMapRef{$name}{$id}{'descr'}=$descr;
944 $$idMapRef{$name}{$id}{'timestamp'}=$timestamp;
945 push(@{$$idOrderRef{$name}}, $id) unless grep(/^\Q$id\E$/,@{$$idOrderRef{$name}});
946 }
947 }
948}
949# =========================
950sub getClisTopicName {
951 my ($name) = @_;
952 return $namedDefaults{$name}{'statetopic'}?$namedDefaults{$name}{'statetopic'}:$globalDefaults{'statetopic'};
953}
954# =========================
955sub getName {
956 my($paramsRef) = @_;
957 my $name=&substIllegalChars($$paramsRef{'name'}) if defined $$paramsRef{'name'};
958 $name=$globalDefaults{'name'} unless defined $name;
959 return $name;
960}
961# =========================
962sub getLogEntry {
963 my ($format, $id, $n, $laststate, $nextstate) = @_;
964 my $logentry = Foswiki::Func::expandCommonVariables($format, $options{logtopic}, $web);
965
966 my @states = split /\|/, $options{'states'};
967 $logentry =~ s/%CLIID%/$id/g;
968 $logentry =~ s/%STATE%/(defined $laststate?$laststate:$states[0])/eg;
969 $logentry =~ s/%NEXTSTATE%/$nextstate/g;
970
971 return $logentry;
972}
973# =========================
974sub saveLog {
975 my ($id, $n, $laststate, $nextstate) = @_;
976
977 my $oopsUrl = &Foswiki::Func::setTopicEditLock($web, $options{logtopic}, 1);
978 if ($oopsUrl) {
979 &Foswiki::Func::redirectCgiQuery(Foswiki::Func::getCgiQuery(), $oopsUrl);
980 return;
981 }
982
983 my $logtopictext = Foswiki::Func::readTopicText($web, $options{logtopic});
984 if ($logtopictext =~ /^http.*?\/oops/) {
985 Foswiki::Func::redirectCgiQuery(Foswiki::Func::getCgiQuery(), $logtopictext);
986 return;
987 }
988 checkChangeAccessPermission($options{logtopic}, $logtopictext) || return;
989
990
991 my $logentry = getLogEntry($options{logformat}, $id, $n, $laststate, $nextstate);
992
993 my $meta = "";
994 while ($logtopictext =~s /(%META(:[^{]+){[^}]+}%)//s) {
995 $meta.=$1;
996 }
997 $logtopictext .= $logentry if $options{logpos} !~ /prepend/i;
998 $logtopictext = $logentry . $logtopictext if $options{logpos} =~ /prepend/i;
999
1000 Foswiki::Func::saveTopicText($web, $options{logtopic}, "$meta\n$logtopictext", 1, !$options{'notify'});
1001 Foswiki::Func::setTopicEditLock($web, $options{logtopic}, 0);
1002
1003
1004}
1005# =========================
1006sub saveChecklistItemStateTopic {
1007 my ($name,$perm) = @_;
1008 return if $name eq "";
1009 my $clisTopicName = &getClisTopicName($name);
1010
1011 Foswiki::Func::writeDebug("- ${pluginName}::saveChecklistItemStateTopic($name): $clisTopicName, ".$namedDefaults{$name}{'statetopic'}) if $debug;
1012 my $oopsUrl = &Foswiki::Func::setTopicEditLock($web, $clisTopicName, 1);
1013 if ($oopsUrl) {
1014 &Foswiki::Func::redirectCgiQuery(Foswiki::Func::getCgiQuery(), $oopsUrl);
1015 return;
1016 }
1017 my $installWeb = $Foswiki::cfg{SystemWebName};
1018 my $topicText = "";
1019 $topicText.="%RED% WARNING! THIS TOPIC IS GENERATED BY $installWeb.$pluginName PLUGIN. DO NOT EDIT THIS TOPIC (except table data)!%ENDCOLOR%\n";
1020 $topicText.=qq@%BR%Back to the \[\[$web.$topic\]\[checklist topic $topic\]\].\n\n@;
1021 foreach my $n ( sort keys %{ $idMapRef } ) {
1022 next if ($clisTopicName ne $globalDefaults{'statetopic'})&&((!defined $namedDefaults{$n}{'statetopic'})||($clisTopicName ne $namedDefaults{$n}{'statetopic'}));
1023 next if (($namedDefaults{$n}{'statetopic'})&&($clisTopicName ne $namedDefaults{$n}{'statetopic'}));
1024
1025 my $states = ($name eq $n)?$options{'states'}:undef;
1026 $states = $namedDefaults{$n}{'states'} unless defined $states && $states ne "";
1027 $states = &Foswiki::Func::getPreferencesValue("\U$pluginName\E_STATES") unless defined $states && $states ne "";
1028 $states = $globalDefaults{'states'} unless defined $states && $states ne "";
1029 my $statesel = join ", ", (split /\|/, $states);
1030 $topicText.="\n";
1031 $topicText.=qq@%EDITTABLE{format="|text,20,$n|text,10,|select,1,$statesel|textarea,2,|"}%\n@;
1032 $topicText.=qq@%TABLE{footerrows="1"}%\n@;
1033 $topicText.="|*context*|*id*|*state*|*description*|*timestamp*|\n";
1034
1035 ###foreach my $id (sort keys %{ $$idMapRef{$n}}) {
1036 ###foreach my $id (@{ $$idOrderRef{$n}}) {
1037 my @arr = $#{$$idOrderRef{$n}}!=-1 ? @{$$idOrderRef{$n}} : sort(keys(%{$$idMapRef{$n}}));
1038 foreach my $id (@arr) {
1039 $topicText.="|$n|".&htmlEncode($id)."|".&htmlEncode($$idMapRef{$n}{$id}{'state'})
1040 .'| '.&htmlEncode($$idMapRef{$n}{$id}{'descr'})
1041 .'| '.&htmlEncode($$idMapRef{$n}{$id}{'timestamp'})
1042 ." |\n";
1043 }
1044 $topicText.=qq@| *$n* | *statistics:* | *%CALC{"\$COUNTITEMS(R2:C\$COLUMN()..R\$ROW(-1):C\$COLUMN())"}%* | *entries: %CALC{"\$ROW(-2)"}%* ||\n@;
1045 }
1046 if ($perm) {
1047 $topicText.="\nAccess rights inherited from $web.$topic:\n\n";
1048 $topicText.="\n$perm\n" if $perm;
1049 }
1050 $topicText.="\n-- $installWeb.$pluginName - ".&Foswiki::Func::formatTime(time(), "rcs")."\n";
1051 Foswiki::Func::saveTopicText($web, $clisTopicName, $topicText, 1, !$options{'notify'});
1052 Foswiki::Func::setTopicEditLock($web, $clisTopicName, 0);
1053}
1054# =========================
1055sub createUnknownParamsMessage {
1056 my $msg="";
1057 $msg = Foswiki::Func::getPreferencesValue('UNKNOWNPARAMSMSG') || undef;
1058 $msg = $globalDefaults{'unknownparamsmsg'} unless defined $msg;
1059 $msg =~ s/\%UNKNOWNPARAMSLIST\%/join(', ', sort @unknownParams)/eg;
1060 $msg =~ s/\%KNOWNPARAMSLIST\%/join(', ', sort keys %globalDefaults)/eg;
1061
1062 return $msg;
1063}
1064# =========================
1065sub collectAllChecklistItems {
1066 ## never ever local($initText, $idMapRef, $idOrderRef, %itemsCollected, %itemStatesRead, $web, $topic)
1067 local($dryrun, %namedDefaults, %namedIds, %namedResetIds, @unknownParams, $resetDone,$stateChangeDone,$saveDone );
1068
1069 Foswiki::Func::writeDebug( "- ${pluginName}::collectAllChecklistItems()" ) if $debug;
1070
1071 my $text = $initText;
1072
1073 # prevent changes:
1074 $resetDone=1; $stateChangeDone=1;
1075
1076 # prevent rendering:
1077 $dryrun=1;
1078
1079 &handleAllTags($text, $topic, $web);
1080
1081 Foswiki::Func::writeDebug( "- ${pluginName}::collectAllChecklistItems() done!" ) if $debug;
1082}
1083# =========================
1084
# spent 433µs (137+296) within Foswiki::Plugins::ChecklistPlugin::postRenderingHandler which was called 5 times, avg 87µs/call: # 5 times (137µs+296µs) by Foswiki::Plugin::invoke at line 294 of /var/www/foswiki11/lib/Foswiki/Plugin.pm, avg 87µs/call
sub postRenderingHandler {
108558µs538µs my $query = Foswiki::Func::getCgiQuery();
# spent 38µs making 5 calls to Foswiki::Func::getCgiQuery, avg 8µs/call
1086522µs if (defined $query) {
1087521µs5183µs my $startTag=$query->comment('CLTABLEPLUGINSORTFIX:');
# spent 92µs making 1 call to CGI::AUTOLOAD # spent 90µs making 4 calls to CGI::comment, avg 23µs/call
1088511µs556µs my $endTag=$query->comment(':CLTABLEPLUGINSORTFIX');
# spent 56µs making 5 calls to CGI::comment, avg 11µs/call
1089533µs $_[0]=~s/\Q$startTag\E.*?\Q$endTag\E//sg;
1090 }
1091}
1092# =========================
1093sub endRenderingHandler {
1094 return postRenderingHandler( @_ );
1095}
1096# =========================
1097sub handleStateChanges {
1098
1099 my ($text) = @_;
1100 my $query = &Foswiki::Func::getCgiQuery();
1101 if ((defined $query->param('clpsc'))&&(!$stateChangeDone)) {
1102 my ($id,$name,$lastState,$nextstate) = ($query->param('clpsc'),$query->param('clpscn'),$query->param('clpscls'),$query->param('clpscns'));
1103 if ($options{'name'} eq $name) {
1104 &doChecklistItemStateChange($id, $name, $lastState, $text, $nextstate) ;
1105 $stateChangeDone=1;
1106 }
1107 }
1108 my @states = split /\|/, $options{'states'};
1109 if ((defined $query->param('clreset'))&&(!$resetDone)) {
1110 my $n=$query->param('clreset');
1111 my $s=(defined $query->param('clresetst'))?$query->param('clresetst'):$states[0];
1112 if (($options{'name'} eq $n)&&(grep(/^\Q$s\E$/s, @states))) {
1113 &doChecklistItemStateReset($n,$s,$text);
1114 $resetDone=1;
1115 }
1116 }
1117}
111814µs1;
1119