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

Filename/var/www/foswikidev/core/lib/Foswiki/Plugins/ChecklistPlugin.pm
StatementsExecuted 506 statements in 12.1ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
10811581µs581µsFoswiki::Plugins::ChecklistPlugin::::commonTagsHandlerFoswiki::Plugins::ChecklistPlugin::commonTagsHandler
1022198µs587µsFoswiki::Plugins::ChecklistPlugin::::postRenderingHandlerFoswiki::Plugins::ChecklistPlugin::postRenderingHandler
51138µs425µsFoswiki::Plugins::ChecklistPlugin::::endRenderingHandlerFoswiki::Plugins::ChecklistPlugin::endRenderingHandler
11116µs60µsFoswiki::Plugins::ChecklistPlugin::::initPluginFoswiki::Plugins::ChecklistPlugin::initPlugin
11116µs178µsFoswiki::Plugins::ChecklistPlugin::::BEGIN@24Foswiki::Plugins::ChecklistPlugin::BEGIN@24
1119µs13µsFoswiki::Plugins::ChecklistPlugin::::BEGIN@36Foswiki::Plugins::ChecklistPlugin::BEGIN@36
1119µs21µ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::::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::::handleAllTagsFoswiki::Plugins::ChecklistPlugin::handleAllTags
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::::initDefaultsFoswiki::Plugins::ChecklistPlugin::initDefaults
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# Copyright (C) 2009-2015 Foswiki Contributors
7#
8# This program is free software; you can redistribute it and/or
9# modify it under the terms of the GNU General Public License
10# as published by the Free Software Foundation; either version 2
11# of the License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details, published at
17# http://www.gnu.org/copyleft/gpl.html
18#
19
20# =========================
21package Foswiki::Plugins::ChecklistPlugin;
22
23# =========================
2417µs1162µs
# spent 178µs (16+162) within Foswiki::Plugins::ChecklistPlugin::BEGIN@24 which was called: # once (16µs+162µs) by Foswiki::Plugin::BEGIN@2.6 at line 33
use vars qw(
# spent 162µs making 1 call to vars::import
25 $installWeb $pluginName
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
33127µs1178µs);
# spent 178µs making 1 call to Foswiki::Plugins::ChecklistPlugin::BEGIN@24
34
35225µs234µs
# spent 21µs (9+12) within Foswiki::Plugins::ChecklistPlugin::BEGIN@35 which was called: # once (9µs+12µs) by Foswiki::Plugin::BEGIN@2.6 at line 35
use strict;
# spent 21µs making 1 call to Foswiki::Plugins::ChecklistPlugin::BEGIN@35 # spent 12µs making 1 call to strict::import
3627.59ms217µs
# spent 13µs (9+4) within Foswiki::Plugins::ChecklistPlugin::BEGIN@36 which was called: # once (9µs+4µs) by Foswiki::Plugin::BEGIN@2.6 at line 36
use warnings;
# spent 13µs making 1 call to Foswiki::Plugins::ChecklistPlugin::BEGIN@36 # spent 4µs making 1 call to warnings::import
37
381700nsour $VERSION = '1.200';
391200nsour $RELEASE = '25 Jul 2015';
401200nsour $NO_PREFS_IN_TOPIC = 1;
41
421300nsmy $defaultsSet = 0;
431100nsmy $debug;
44
451300ns$pluginName = 'ChecklistPlugin'; # Name of this Plugin
46
47# =========================
48
# spent 60µs (16+44) within Foswiki::Plugins::ChecklistPlugin::initPlugin which was called: # once (16µs+44µs) by Foswiki::Plugin::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Plugin.pm:257] at line 250 of /var/www/foswikidev/core/lib/Foswiki/Plugin.pm
sub initPlugin {
4912µs ( $topic, $web, $user, $installWeb ) = @_;
50
51 # check for Plugins.pm versions
52120µs114µs if ( $Foswiki::Plugins::VERSION < 1.021 ) {
# spent 14µs making 1 call to version::vxs::VCMP
53 Foswiki::Func::writeWarning(
54 "Version mismatch between $pluginName and Plugins.pm");
55 return 0;
56 }
57
58 # Get plugin debug flag
5912µs130µs $debug = Foswiki::Func::getPreferencesFlag("CHECKLISTPLUGIN_DEBUG");
# spent 30µs making 1 call to Foswiki::Func::getPreferencesFlag
60
61 # Plugin correctly initialized
621600ns Foswiki::Func::writeDebug(
63 "- Foswiki::Plugins::${pluginName}::initPlugin( $web.$topic ) is OK")
64 if $debug;
65
661300ns $defaultsSet = 0;
6714µs return 1;
68}
69
70# =========================
71
# spent 581µs within Foswiki::Plugins::ChecklistPlugin::commonTagsHandler which was called 108 times, avg 5µs/call: # 108 times (581µs+0s) by Foswiki::Plugin::invoke at line 310 of /var/www/foswikidev/core/lib/Foswiki/Plugin.pm, avg 5µs/call
sub commonTagsHandler {
72### my ( $text, $topic, $web ) = @_; # do not uncomment, use $_[0], $_[1]... instead
73
7410816µs Foswiki::Func::writeDebug(
75 "- ${pluginName}::commonTagsHandler( $_[2].$_[1] )")
76 if $debug;
77
78 # This is the place to define customized tags and variables
79 # Called by Foswiki::handleCommonTags, after %INCLUDE:"..."%
80
81 local (
82108157µs %namedDefaults, %itemStatesRead, %namedIds, %namedResetIds,
83 @unknownParams, $initText, $resetDone, $stateChangeDone,
84 $saveDone, $idMapRef, $idOrderRef, %itemsCollected,
85 $dryrun
86 );
87
8810878µs $initText = $_[0] if $_[0] =~ /\%(CLI|CHECKLIST)/;
891084.00ms return unless $initText;
90
91 &initDefaults( $web, $topic );
92
93 $idMapRef = {};
94 $idOrderRef = {};
95 %namedIds = ();
96 %namedResetIds = ();
97
98 $resetDone = 0;
99 $stateChangeDone = 0;
100 $saveDone = 0;
101
102 $dryrun = 0;
103
104 %namedDefaults = ();
105 %itemStatesRead = ();
106 %itemsCollected = ();
107
108 my $scr;
109 if ( $Foswiki::Plugins::VERSION < 2.3 ) {
110 $scr =
111"<script src='%PUBURLPATH/%SYSTEMWEB%/$pluginName/itemstatechange.js'></script>";
112 }
113 else {
114 $scr =
115"<script src='%PUBURLPATH{topic=\"%SYSTEMWEB%.$pluginName\" \"itemstatechange.js\"}%'></script>";
116 }
117 Foswiki::Func::addToZone( "script", "checklistplugin", $scr );
118
119 &handleAllTags(@_);
120}
121
122# =========================
123sub handleAllTags {
124
125 ### my ( $text, $topic, $web ) = @_; # do not uncomment, use $_[0], $_[1]... instead
126 #
127
128 $_[0] =~
129s/%CHECKLISTSTART%(.*?)%CHECKLISTEND%/&handleAutoChecklist("",$1,$_[0])/sge;
130 $_[0] =~
131s/%CHECKLISTSTART{(.*?)}%(.*?)%CHECKLISTEND%/&handleAutoChecklist($1,$2,$_[0])/sge;
132 $_[0] =~ s/%CHECKLIST%/&handleChecklist("",$_[0])/ge;
133 $_[0] =~ s/%CHECKLIST{(.*?)}%/&handleChecklist($1,$_[0])/sge;
134 $_[0] =~ s/%CLI({(.*?)})?%/&handleChecklistItem($2,$_[0],$-[0],$+[0])/sge;
135
136 ##$_[0] =~ s/([^\n\%]*)%CLI({(.*?)})?%([^\n\%]*)/$1.&handleChecklistItem($3,$_[0],$1,$4).$4/sge;
137}
138
139# =========================
140sub initDefaults {
141 my ( $web, $topic ) = @_;
142
143 return if $defaultsSet;
144
145 $defaultsSet = 1;
146 Foswiki::Func::writeDebug("- ${pluginName}::initDefaults") if $debug;
147
148 my $pubUrlPath = Foswiki::Func::getPubUrlPath();
149 %globalDefaults = (
150 'id' => undef,
151 'name' => '_default',
152 'states' => 'todo|done',
153 'stateicons' => ':-I|:ok:',
154 'text' => '',
155 'reset' => undef,
156 'showlegend' => 0,
157 'anchors' => 1,
158 'unknownparamsmsg' =>
159'%RED% Sorry, some parameters are unknown: %UNKNOWNPARAMSLIST% %ENDCOLOR% <br/> Allowed parameters are (see %SYSTEMWEB%.ChecklistPlugin topic for more details): %KNOWNPARAMSLIST%',
160 'clipos' => 'right',
161 'pos' => 'bottom',
162 'statetopic' => $topic . 'ChecklistItemState',
163 'notify' => 0,
164 'static' => 0,
165 'useajax' => 1,
166 'tooltip' =>
167'Click me to change my state from \'%STATE%\' to \'%NEXTSTATE%\' <br/>t: %TIMESTAMP%',
168 'tooltipbgcolor' => '%WEBBGCOLOR%',
169 'descr' => undef,
170 '_DEFAULT' => undef,
171 'ajaxtopicstyle' => 'plain',
172 'descrcharlimit' => 100,
173 'template' => undef,
174 'statesel' => 0,
175 'tooltipfixleft' => '-163',
176 'tooltipfixtop' => '0',
177 'hide' => undef,
178 'log' => 0,
179 'logformat' =>
180" * %SERVERTIME% - %WIKIUSERNAME% - Item %CLIID%: from %STATE% to %NEXTSTATE% \n",
181 'logtopic' => $topic . 'ChecklistLog',
182 'logpos' => 'append',
183 'timestampformat' =>
184 '%SERVERTIME% - %WIKIUSERNAME%, last state: %STATE%',
185 );
186
187 @listOptions = ( 'states', 'stateicons' );
188 @renderedOptions = ( 'text', 'stateicons', 'reset', 'hide' );
189
190 @filteredOptions = ( 'id', 'name', 'states' );
191
192 @flagOptions = (
193 'showlegend', 'anchors', 'notify', 'static',
194 'useajax', 'statesel', 'log'
195 );
196
197 @ignoreNamedDefaults = ( 'showlegend', 'reset', 'hide' );
198}
199
200# =========================
201sub initOptions() {
202 my ($attributes) = @_;
203 my %params = &Foswiki::Func::extractParameters($attributes);
204
205 my @allOptions = keys %globalDefaults;
206
207 # Check attributes:
208 @unknownParams = ();
209 foreach my $option ( keys %params ) {
210 push( @unknownParams, $option )
211 unless grep( /^\Q$option\E$/, @allOptions );
212 }
213 return 0 if $#unknownParams != -1;
214
215 my $name = &getName( \%params );
216
217 # handle _DEFAULT option (_DEFAULT = descr)
218 $params{'descr'} = $params{'_DEFAULT'} if defined $params{'_DEFAULT'};
219
220 # handle templates:
221 my $tmplName = $params{'template'};
222 $tmplName = $namedDefaults{$name}{'template'} unless defined $tmplName;
223 $tmplName =
224 ( &Foswiki::Func::getPreferencesValue("\U${pluginName}_TEMPLATE\E")
225 || undef )
226 unless defined $tmplName;
227
228 # Setup options (attributes>named defaults>plugin preferences>global defaults):
229 %options = ();
230 foreach my $option (@allOptions) {
231 my $v = $params{$option};
232 $v = $namedDefaults{$name}{$option} unless defined $v;
233 if ( ( defined $tmplName ) && ( !defined $v ) ) {
234 $v = (
235 &Foswiki::Func::getPreferencesFlag(
236 "\U${pluginName}_TEMPLATE_${tmplName}_${option}\E")
237 || undef
238 ) if grep /^\Q$option\E$/, @flagOptions;
239 $v = (
240 &Foswiki::Func::getPreferencesValue(
241 "\U${pluginName}_TEMPLATE_${tmplName}_${option}\E")
242 || undef
243 ) unless defined $v;
244 $v = undef if ( defined $v ) && ( $v eq "" );
245 }
246
247 if ( defined $v ) {
248 if ( grep /^\Q$option\E$/, @flagOptions ) {
249 $options{$option} = ( $v !~ /(false|no|off|0|disable)/i );
250 }
251 else {
252 $options{$option} = $v;
253 }
254 }
255 else {
256 if ( grep /^\Q$option\E$/, @flagOptions ) {
257 $v = (
258 Foswiki::Func::getPreferencesFlag(
259 "\U${pluginName}_$option\E")
260 || undef
261 );
262 }
263 else {
264 $v = Foswiki::Func::getPreferencesValue(
265 "\U${pluginName}_$option\E");
266 }
267 $v = undef if ( defined $v ) && ( $v eq "" );
268 $options{$option} = ( defined $v ? $v : $globalDefaults{$option} );
269 }
270 }
271
272 # Render some options:
273 foreach my $option (@renderedOptions) {
274 next unless defined $options{$option};
275 if ( $options{$option} !~ /^(\s|\&nbsp\;)*$/ ) {
276 $options{$option} =~ s/(<nop>|!)//sg;
277 $options{$option} =
278 &Foswiki::Func::expandCommonVariables( $options{$option}, $topic,
279 $web );
280 if ( grep /^\Q$option\E$/, @listOptions ) {
281 my @newlist = ();
282 foreach my $i ( split /\|/, $options{$option} ) {
283 my $newval = &Foswiki::Func::renderText( $i, $web );
284 $newval =~ s/\|/\&brvbar\;/sg;
285 push @newlist, $newval;
286 }
287 $options{$option} = join( '|', @newlist );
288 }
289 else {
290 $options{$option} =
291 &Foswiki::Func::renderText( $options{$option}, $web );
292 }
293 }
294 }
295
296 # filter some options:
297 foreach my $option (@filteredOptions) {
298 next unless defined $options{$option};
299 if ( grep /^\Q$option\E$/, @listOptions ) {
300 my @newlist = ();
301 foreach my $i ( split /\|/, $options{$option} ) {
302 my $newval = &substIllegalChars($i);
303 $newval =~ s/\|/\&brvbar\;/sg;
304 push @newlist, $newval;
305 }
306 $options{$option} = join( '|', @newlist );
307 }
308 else {
309 $options{$option} = &substIllegalChars( $options{$option} );
310 }
311 }
312
313 return 1;
314}
315
316# =========================
317sub initNamedDefaults {
318 my ($attributes) = @_;
319
320 my %params = Foswiki::Func::extractParameters($attributes);
321
322 my $name = &getName( \%params );
323
324 my $tmplName =
325 ( defined $params{'template'} ? $params{'template'} : undef );
326 $tmplName =
327 ( &Foswiki::Func::getPreferencesValue("\U${pluginName}_TEMPLATE\E")
328 || undef )
329 unless defined $tmplName;
330
331 # create named defaults (attributes>named defaults>global defaults):
332 foreach my $default ( keys %globalDefaults ) {
333 next if grep( /^\Q$default\E$/, @ignoreNamedDefaults );
334 $namedDefaults{$name}{$default} = $params{$default}
335 if defined $params{$default};
336 $namedDefaults{$name}{$default} = (
337 &Foswiki::Func::getPreferencesValue(
338 "\U${pluginName}_TEMPLATE_${tmplName}_${default}\E")
339 || undef
340 )
341 unless ( !defined $tmplName )
342 || ( defined $params{$default} );
343
344 }
345}
346
347# =========================
348sub initStates {
349 my ($query) = @_;
350 if (
351 ( !defined $itemsCollected{"$web.$topic"} )
352 && ( ( defined $query->param('clpsc') )
353 || ( defined $query->param('clreset') ) )
354 )
355 {
356 $itemsCollected{"$web.$topic"} = 1;
357 &collectAllChecklistItems();
358 }
359
360 # read item states:
361 if ( !$itemStatesRead{ $options{'name'} } ) {
362 $itemStatesRead{ $options{'name'} } = 1;
363 &readChecklistItemStateTopic($idMapRef);
364 }
365}
366
367# =========================
368sub renderLegend {
369 my $query = &Foswiki::Func::getCgiQuery();
370 my @states = split /\|/, $options{'states'};
371 my @icons = split /\|/, $options{'stateicons'};
372 my $legend .= qq@<noautolink>@;
373 $legend .= qq@(@;
374 foreach my $state (@states) {
375 my $icon = shift @icons;
376 my ($iconsrc) = &getImageSrc($icon);
377 my $heState = &htmlEncode($state);
378 $iconsrc = "" unless defined $iconsrc;
379 $legend .= $query->img(
380 { src => $iconsrc, alt => $heState, title => $heState } );
381 $legend .= qq@ - $heState @;
382 }
383 $legend .= qq@) @;
384 $legend .= qq@</noautolink>@;
385 return $legend;
386}
387
388# =========================
389sub handleChecklist {
390 my ( $attributes, $refText ) = @_;
391
392 Foswiki::Func::writeDebug(
393 "- ${pluginName}::handleChecklist($attributes,...refText...)")
394 if $debug;
395
396 my $text = "";
397
398 &initNamedDefaults($attributes);
399
400 local (%options);
401 return &createUnknownParamsMessage() unless &initOptions($attributes);
402
403 my $query = &Foswiki::Func::getCgiQuery();
404 my %params = &Foswiki::Func::extractParameters($attributes);
405 my $name = &getName( \%params );
406
407 my @states = split /\|/, $options{'states'};
408 my @icons = split /\|/, $options{'stateicons'};
409
410 if ( ( defined $query->param('clreset') ) && ( !$resetDone ) ) {
411 &initStates($query);
412 my $n = $query->param('clreset');
413 my $s =
414 ( defined $query->param('clresetst') )
415 ? $query->param('clresetst')
416 : $states[0];
417 if ( ( $options{'name'} eq $n ) && ( grep( /^\Q$s\E$/s, @states ) ) ) {
418 &doChecklistItemStateReset( $n, $s, $refText );
419 $resetDone = 1;
420 }
421 }
422
423 return "" if $dryrun;
424
425 my $legend = $options{'showlegend'} ? &renderLegend() : "";
426
427 if ( defined $options{'reset'} && !$options{'static'} ) {
428 $namedResetIds{$name}++;
429 my $reset = $options{'reset'};
430 my $state = ( split /\|/, $options{'states'} )[0];
431
432 if ( $reset =~ /\@(\S+)/s ) {
433 $state = $1;
434 $reset =~ s/\@\S+//s;
435 }
436
437 my ($imgsrc) = &getImageSrc($reset);
438 $imgsrc = "" unless defined $imgsrc;
439
440 my $title = $reset;
441 $title =~ s/<\S+[^>]*\>//sg; # strip HTML
442 $title = &htmlEncode($title);
443
444 my $action = &createResetAction( $name, $state );
445
446 $text .= qq@<noautolink>@;
447
448 $text .= $query->a( { name => "reset${name}" }, '&nbsp;' )
449 if $options{'anchors'} && !$options{'useajax'};
450 $text .= $legend;
451 my $linktext = "";
452 my $imgparams = { title => $title, alt => $title, border => 0 };
453 $$imgparams{src} = $imgsrc
454 if ( defined $imgsrc ); # && ($imgsrc!~/^\s*$/s);
455 $linktext .= $query->img($imgparams);
456 $linktext .= qq@ ${title}@
457 if ( $title !~ /^\s*$/i ) && ( $imgsrc ne "" );
458 $action = "javascript:submitItemStateChange('$action');"
459 if $options{'useajax'} && ( $state ne 'STATESEL' );
460 my $id = &urlEncode( "${name}_${state}_" . $namedResetIds{$name} );
461
462 if ( $state eq 'STATESEL' ) {
463 $text .=
464 &createHiddenDirectResetSelectionDiv( $namedResetIds{$name},
465 $name, \@states, \@icons );
466 $action =
467"javascript:clpTooltipShow('CLP_SM_DIV_RESET_${name}_$namedResetIds{$name}', 'CLP_A_$id',"
468 . ( 10 + int( $options{'tooltipfixleft'} ) ) . ","
469 . ( 10 + int( $options{'tooltipfixtop'} ) )
470 . ",true);";
471 }
472 $text .=
473 $query->a( { href => $action, id => 'CLP_A_' . $id }, $linktext );
474
475 $text .= qq@</noautolink>@;
476 }
477 else {
478 $text .= $legend;
479 }
480 if ( defined $options{hide} ) {
481 my $state = "";
482 $state = $1 if ( $options{hide} =~ s/\@(\S+)//g );
483 $state = "" if $state eq $options{hide};
484 $text .= $query->a(
485 {
486 href =>
487 "javascript: clpHideShowToggle('$options{name}','$state')"
488 },
489 $options{hide}
490 );
491 }
492
493 return $text;
494}
495
496# =========================
497sub createResetAction {
498 my ( $name, $state ) = @_;
499 my $action = &Foswiki::Func::getViewUrl( $web, $topic );
500 $action =~ s/#.*$//s;
501 $action .= &getUniqueUrlParam($action);
502
503 $action .= ( $action =~ /\?/ ? ';' : '?' );
504 $action .= "clreset=" . &urlEncode($name);
505 $action .= ";clresetst=" . &urlEncode($state);
506 $action .= ';skin=' . &urlEncode( $options{'ajaxtopicstyle'} )
507 if $options{'useajax'};
508
509 $action .= "#reset${name}" if $options{'anchors'} && !$options{'useajax'};
510 return $action;
511}
512
513# =========================
514sub createHiddenDirectResetSelectionDiv {
515 my ( $id, $name, $statesRef, $iconsRef ) = @_;
516 my $selTxt = "";
517 my $query = &Foswiki::Func::getCgiQuery();
518 $selTxt = $query->sup(
519 $query->a(
520 {
521 -href =>
522 "javascript:clpTooltipHide('CLP_SM_DIV_RESET_${name}_$id');"
523 },
524 '[X]'
525 )
526 );
527 for ( my $i = 0 ; $i <= $#$statesRef ; $i++ ) {
528 my $s = $$statesRef[$i];
529 my $action = &createResetAction( $name, $s );
530 $action =
531"javascript:submitItemStateChange('$action');clpTooltipHide('CLP_SM_DIV_RESET_${name}_$id');"
532 if $options{'useajax'};
533 my $imgsrc = ( &getImageSrc( $$iconsRef[$i] ) )[0];
534 my $imgalt = ( defined $imgsrc ) ? "" : $s;
535 $imgsrc = "" unless defined $imgsrc;
536 $selTxt .= $query->a(
537 {
538 -href => $action,
539 -title => $s,
540 -style => 'vertical-align:bottom;'
541 },
542 $query->img(
543 {
544 src => $imgsrc,
545 alt => $imgalt,
546 border => 0,
547 style => 'cursor:move;vertical-align:bottom'
548 }
549 )
550 );
551 $selTxt .= '&nbsp;';
552 }
553
554 return $query->div(
555 {
556 -id => "CLP_SM_DIV_RESET_${name}_$id",
557 -style =>
558"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'};"
559 },
560 $selTxt
561 );
562}
563
564# =========================
565sub substAttributes {
566 my ( $attributes, $p ) = @_;
567
568 my %attrHash = &Foswiki::Func::extractParameters($attributes);
569 my %pHash = ( defined $p ? &Foswiki::Func::extractParameters($p) : () );
570
571 foreach my $a ( keys %attrHash ) {
572 $pHash{$a} = $attrHash{$a};
573 }
574 my $attr = "";
575 foreach my $a ( keys %pHash ) {
576 $attr .= ' ' . $a . '="' . $pHash{$a} . '"';
577 }
578
579 return '%CLI{' . $attr . '}%';
580}
581
582# =========================
583sub substItemLine {
584 my ( $l, $attribs ) = @_;
585 if ( $l =~ s/(\s+)\#(\S+)/$1/ ) {
586 $attribs .= " id=\"$2\"";
587 }
588
589 $idOffset++;
590
591 $namedIds{ $options{name} } = 0 unless defined $namedIds{ $options{name} };
592
593 my $id =
594 "CLP_HIDE_ID_"
595 . $options{name}
596 . ( $namedIds{ $options{name} } + $idOffset );
597 my $name = "CLP_HIDE_NAME_" . $options{name};
598 my @states = split /\|/, $options{'states'};
599 my $state =
600 $$idMapRef{ $options{name} }{ $namedIds{ $options{name} } + $idOffset }
601 {state};
602 $state = $states[0] unless defined $state;
603 my $class = "clp_hide_" . $options{name} . "_" . $state;
604
605 if ( $l =~ /\%CLI{.*?}\%/ ) {
606 $l =~ s/\%CLI{(.*?)}\%/\%CLI{$1 $attribs}\%/g;
607 $l =~ s/^/<span id="$id" name="$name" class="$class">/;
608 $l =~ s/$/<\/span>/;
609 }
610 else {
611 if ( lc( $options{'clipos'} ) eq 'left' ) {
612 ###$l=~s/^(\s+[\d\*]+)/"$1 \%CLI{$attribs}% "/e;
613 $l =~
614s/^(\s+[\d\*]+)(.*)$/"$1 <span id=\"$id\" name=\"$name\" class=\"$class\">\%CLI{$attribs}\% $2<\/span>"/e;
615 }
616 else {
617 ###$l=~s/^(\s+[\d\*]+.*?)$/"$1 \%CLI{$attribs}%"/e;
618 $l =~
619s/^(\s+[\d\*]+)(.*?)$/"$1 <span id=\"$id\" name=\"$name\" class=\"$class\">$2 \%CLI{$attribs}\%<\/span>"/e;
620 }
621 }
622
623 return $l;
624}
625
626# =========================
627sub handleAutoChecklist {
628 my ( $attributes, $text ) = @_;
629
630 Foswiki::Func::writeDebug(
631 "- ${pluginName}::handleAutoChecklist($attributes,...text...)")
632 if $debug;
633
634 &initNamedDefaults($attributes);
635
636 local (%options);
637 local ($idOffset);
638 return &createUnknownParamsMessage() unless &initOptions($attributes);
639
640 initStates( Foswiki::Func::getCgiQuery() );
641
642 handleStateChanges();
643
644 $text =~ s/\%CLI(\{([^\}]*)\})?\%/&substAttributes($attributes, $2)/meg;
645 $text =~ s/^(\s+[\d\*]+.*?)$/&substItemLine($1,$attributes)/meg;
646 $text =~
647 s/([^\n]+?\s+)\#(\S+)/$1.&substAttributes($attributes, "id=\"$2\"")/meg;
648
649 if ( lc( $options{'pos'} ) eq 'top' ) {
650 $text = "\%CHECKLIST{$attributes}\%\n$text";
651 }
652 else {
653 $text .= "\n\%CHECKLIST{$attributes}\%";
654 }
655
656 return $text;
657
658}
659
660# =========================
661sub handleChecklistItem {
662 my ( $attributes, $text, $startOffset, $endOffset ) = @_;
663
664 Foswiki::Func::writeDebug(
665 "- ${pluginName}::handleChecklistItem($attributes)")
666 if $debug;
667
668 local (%options);
669 return &createUnknownParamsMessage() unless &initOptions($attributes);
670
671 my $query = &Foswiki::Func::getCgiQuery();
672
673 &initStates($query);
674
675 $namedIds{ $options{'name'} }++ unless defined $options{'id'};
676
677 &handleDescription( $text, $startOffset, $endOffset );
678
679 my $name = $options{'name'};
680 my $id = $options{'id'} ? $options{'id'} : $namedIds{$name};
681 my $last = $$idMapRef{$name}{$id}{'state'};
682
683 if ( ( defined $query->param('clpsc') ) && ( !$stateChangeDone ) ) {
684 my ( $id, $name, $lastState, $nextstate ) = (
685 $query->param('clpsc'), $query->param('clpscn'),
686 $query->param('clpscls'), $query->param('clpscns')
687 );
688 if ( $options{'name'} eq $name ) {
689 &doChecklistItemStateChange( $id, $name, $lastState, $text,
690 $nextstate );
691 $stateChangeDone = 1;
692 }
693 }
694
695 my $state =
696 ( defined $$idMapRef{$name}{$id}{'state'} )
697 ? $$idMapRef{$name}{$id}{'state'}
698 : ( split( /\|/, $options{'states'} ) )[0];
699 my $timestamp =
700 ( defined $$idMapRef{$name}{$id}{'timestamp'} )
701 ? $$idMapRef{$name}{$id}{'timestamp'}
702 : getLogEntry( $options{timestampformat}, $id, $name, $last, $state );
703
704 $$idMapRef{$name}{$id}{'state'} = $state
705 unless defined $$idMapRef{$name}{$id}{'state'};
706 $$idMapRef{$name}{$id}{'descr'} = $options{'descr'}
707 if defined $options{'descr'};
708 $$idMapRef{$name}{$id}{'timestamp'} = $timestamp;
709
710 push( @{ $$idOrderRef{$name} }, $id )
711 unless grep( /^\Q$id\E$/, @{ $$idOrderRef{$name} } );
712
713 return "" if $dryrun;
714
715 return &renderChecklistItem();
716
717}
718
719# =========================
720sub handleDescription {
721 my ( $text, $startOffset, $endOffset ) = @_;
722
723 my $si = $startOffset - $options{'descrcharlimit'};
724 $si = 0 if ( $si < 0 );
725 my $textBefore = substr( $text, $si, $startOffset - $si );
726 my $textAfter = substr( $text, $endOffset + 1, $options{'descrcharlimit'} );
727
728 $textBefore =~ /([^>\n\%]*)$/;
729 $textBefore = $1 if defined $1;
730
731 $textAfter =~ /^([^<\n\%]*)/;
732 $textAfter = $1 if defined $1;
733
734 my $descr = $$idMapRef{ $options{'name'} }{
735 $options{'id'}
736 ? $options{'id'}
737 : $namedIds{ $options{'name'} }
738 }{'descr'};
739 unless ( ( defined $options{'descr'} )
740 || ( ( defined $descr ) && ( $descr !~ /^\s*$/ ) ) )
741 {
742 $options{'descr'} = $options{'text'}
743 if ( defined $options{'text'} ) && ( $options{'text'} !~ /^\s*$/s );
744
745 my $text = $textBefore;
746 $text .= " ... " if $textBefore !~ /^\s*$/;
747 $text .= $textAfter;
748 $text .= " ..." if $textAfter !~ /^\s*$/;
749 $options{'descr'} = $text unless defined $options{'descr'};
750
751 $options{'descr'} =~ s/^\s{3,}[\*\d]//sg; ## remove lists
752 $options{'descr'} =~ s/\|/ /sg; ## remove tables
753 $options{'descr'} =~ s/<[\/]?[^>]+>/ /sg; ## remove HTML tags
754 $options{'descr'} =~ s/\%\w+[^\%]*\%/ /sg; ## remove variables
755
756 $options{'descr'} =~ s/\s{2,}/ /g; ## remove multiple spaces
757 $options{'descr'} =~ s/^\s*//g;
758 $options{'descr'} =~ s/\s*$//g;
759
760 }
761 $options{'descr'} =
762 substr( $options{'descr'}, 0, $options{'descrcharlimit'} )
763 if ( defined $options{'descr'} )
764 && ( length( $options{'descr'} ) > $options{'descrcharlimit'} );
765}
766
767# =========================
768sub getNextState {
769 my ( $name, $lastState ) = @_;
770 my @states = split /\|/, $options{'states'};
771 my @icons = split /\|/, $options{'stateicons'};
772
773 $lastState = $states[0] if !defined $lastState;
774
775 my $state = $states[0];
776 my $icon = $icons[0];
777 for ( my $i = 0 ; $i <= $#states ; $i++ ) {
778 if ( $states[$i] eq $lastState ) {
779 $state = ( $i < $#states ) ? $states[ $i + 1 ] : $states[0];
780 $icon = ( $i < $#states ) ? $icons[ $i + 1 ] : $icons[0];
781 last;
782 }
783 }
784 Foswiki::Func::writeDebug(
785 "- ${pluginName}::getNextState($name, $lastState)=$state; allstates="
786 . $options{states} )
787 if $debug;
788
789 return ( $state, $icon );
790
791}
792
793# =========================
794sub checkChangeAccessPermission {
795 my ( $name, $text ) = @_;
796 my $ret = 1;
797
798 my $perm = 'CHANGE';
799 my $checkTopic = $topic;
800 unless ( &Foswiki::Func::topicExists( $web, &getClisTopicName($name) ) ) {
801 $perm = 'CREATE';
802 $checkTopic = &getClisTopicName($name);
803 $text = undef;
804 }
805
806 my $mainWebName = &Foswiki::Func::getMainWebname();
807 my $user = Foswiki::Func::getWikiName();
808 $user = "$mainWebName.$user" unless $user =~ m/^$mainWebName\./;
809
810 if (
811 !&Foswiki::Func::checkAccessPermission(
812 $perm, $user, $text, $checkTopic, $web
813 )
814 )
815 {
816 $ret = 0;
817
818 eval { require Foswiki::AccessControlException; };
819 if ($@) {
820 Foswiki::Func::redirectCgiQuery(
821 Foswiki::Func::getCgiQuery(),
822 Foswiki::Func::getOopsUrl(
823 $web, $checkTopic, "oopsaccesschange"
824 )
825 );
826 }
827 else {
828 require Error;
829 throw Foswiki::AccessControlException( $perm,
830 $Foswiki::Plugins::SESSION->{user},
831 $checkTopic, $web, 'denied' );
832 }
833 }
834 return $ret;
835}
836
837# =========================
838sub extractPerms {
839 my ($text) = @_;
840 my $perms;
841
842 $text = "" unless defined $text;
843 $perms =
844 join( "\n", grep /^\s+\*\s*Set (ALLOW|DENY).+/i, split( /\n/, $text ) );
845
846 return $perms;
847}
848
849# =========================
850sub doChecklistItemStateReset {
851 my ( $n, $state, $text ) = @_;
852 Foswiki::Func::writeDebug(
853 "- ${pluginName}::doChecklistItemStateReset($n,$state,...text...)")
854 if $debug;
855
856 # access granted?
857 return if !&checkChangeAccessPermission( $n, $text );
858
859 if ( !defined $state ) {
860 my @states = split /\|/, $options{'states'};
861 $state = $states[0];
862 }
863 foreach my $id ( keys %{ $$idMapRef{$n} } ) {
864 $$idMapRef{$n}{$id}{'timestamp'} =
865 getLogEntry( $options{timestampformat},
866 $id, $n, $$idMapRef{$n}{$id}{'state'}, $state );
867 $$idMapRef{$n}{$id}{'state'} = $state;
868 }
869 saveLog( 'reset', $n, 'any', $state ) if $options{log} && !$saveDone;
870 &saveChecklistItemStateTopic( $n, &extractPerms($text) )
871 if ( !$saveDone ) && ( ( $saveDone = !$saveDone ) );
872}
873
874# =========================
875sub doChecklistItemStateChange {
876 my ( $id, $n, $lastState, $text, $nextstate ) = @_;
877 Foswiki::Func::writeDebug(
878"- ${pluginName}::doChecklistItemStateChange($id,$n,$lastState,...text...)"
879 ) if $debug;
880
881 # access granted?
882 return if !&checkChangeAccessPermission( $n, $text );
883
884 # reload?
885 return
886 if ( ( defined $$idMapRef{$n}{$id}{'state'} )
887 && ( $$idMapRef{$n}{$id}{'state'} ne $lastState ) );
888
889 my $rns = (
890 defined $nextstate
891 ? $nextstate
892 : ( &getNextState( $n, $$idMapRef{$n}{$id}{'state'} ) )[0]
893 );
894
895 $$idMapRef{$n}{$id}{'state'} = $rns;
896 $$idMapRef{$n}{$id}{'timestamp'} =
897 getLogEntry( $options{timestampformat}, $id, $n, $lastState, $nextstate );
898
899 &saveLog( $id, $n, $lastState, $rns ) if $options{log} && !$saveDone;
900 &saveChecklistItemStateTopic( $n, &extractPerms($text) )
901 if ( !$saveDone ) && ( ( $saveDone = !$saveDone ) );
902}
903
904# =========================
905sub createAction {
906 my ( $id, $name, $state, $nextstate ) = @_;
907 my $action = Foswiki::Func::getViewUrl( $web, $topic );
908
909 # remove anchor:
910 $action =~ s/#.*$//i;
911
912 $action .= getUniqueUrlParam($action);
913
914 $action .= ( $action =~ /\?/ ) ? ";" : "?";
915 $action .= "clpsc=" . &urlEncode("$id");
916 $action .= ";clpscn=" . &urlEncode($name);
917 $action .= ";clpscls=" . &urlEncode($state);
918 $action .= ";clpscns=" . &urlEncode($nextstate) if defined $nextstate;
919 $action .= ';skin=' . &urlEncode( $options{'ajaxtopicstyle'} )
920 if $options{'useajax'};
921
922 my $query = &Foswiki::Func::getCgiQuery();
923 my %queryVars = $query->Vars();
924 foreach my $p ( keys %queryVars ) {
925 $action .= ";$p=" . &urlEncode( $queryVars{$p} )
926 unless ( $p =~ /^(clp.*|clreset.*|contenttype|skin)$/i )
927 || ( !$queryVars{$p} );
928 }
929 $action .= "#$name$id" if $options{'anchors'} && ( !$options{'useajax'} );
930
931 return $action;
932}
933
934# =========================
935sub createTitle {
936 my ( $name, $state, $icon, $statesRef, $nextstate, $nextstateicon, $tId,
937 $timestamp )
938 = @_;
939 ( $nextstate, $nextstateicon ) = &getNextState( $name, $state )
940 unless defined $nextstate;
941 my $query = &Foswiki::Func::getCgiQuery();
942 my $title = $options{'tooltip'};
943 $title = $state unless defined $title;
944 $title =~ s/\%STATE\%/$state/sg;
945 $title =~ s/\%NEXTSTATE\%/$nextstate/esg;
946 $title =~ s/\%STATECOUNT\%/($#$statesRef+1)/esg;
947 $title =~ s/\%STATES\%/join(", ",@{$statesRef})/esg;
948 $title =~ s/\%LEGEND\%/&renderLegend()/esg;
949 $title =~
950s/\%STATEICON\%/$query->img({alt=>$state,src=>(&getImageSrc($icon))[0]})/esg;
951 $title =~
952s/\%NEXTSTATEICON\%/$query->img({alt=>$nextstate,src=>(&getImageSrc($nextstateicon))[0]})/esg;
953 $title =~ s/\%TIMESTAMP\%/$timestamp/esg;
954 return $title;
955}
956
957# =========================
958sub renderChecklistItem {
959 Foswiki::Func::writeDebug("- ${pluginName}::renderChecklistItem()")
960 if $debug;
961 my $query = &Foswiki::Func::getCgiQuery();
962 my $text = "";
963 my $name = $options{'name'};
964
965 my @states = split /\|/, $options{'states'};
966 my @icons = split /\|/, $options{'stateicons'};
967
968 my $tId = $options{'id'} ? $options{'id'} : $namedIds{$name};
969
970 my $timestamp = $$idMapRef{$name}{$tId}{'timestamp'};
971 $timestamp = "" unless defined $timestamp;
972
973 my $state =
974 ( defined $$idMapRef{$name}{$tId}{'state'} )
975 ? $$idMapRef{$name}{$tId}{'state'}
976 : $states[0];
977 my $icon = $icons[0];
978
979 for ( my $i = 0 ; $i <= $#states ; $i++ ) {
980 if ( $states[$i] eq $state ) {
981 $icon = $icons[$i];
982 last;
983 }
984 }
985
986 my ( $iconsrc, $textBef, $textAft ) = &getImageSrc($icon);
987
988 my $stId = &substIllegalChars($tId); # substituted tId
989 my $heState = &htmlEncode($state); # HTML encoded state
990 my $ueState = &urlEncode($state); # URL encoded state
991 my $uetId = &urlEncode($tId); # URL encoded tId
992
993 my $action = &createAction( $stId, $name, $state );
994
995 $text .= qq@<noautolink>@;
996
997 $text .= $query->comment('CLTABLEPLUGINSORTFIX:');
998 $text .= $query->div(
999 {
1000 -style =>
1001 "visibility:hidden;position:absolute;top:0;left:0;z-index:2;"
1002 },
1003 $heState
1004 );
1005 $text .= $query->comment(':CLTABLEPLUGINSORTFIX');
1006
1007 $text .= $query->a( { name => "$name$uetId" }, '&nbsp;' )
1008 if $options{'anchors'} && !$options{'useajax'};
1009
1010 my $linktext = "";
1011 if ( lc( $options{'clipos'} ) ne 'left' ) {
1012 $linktext .= $options{'text'} . ' '
1013 unless $options{'text'} =~ /^(\s|\&nbsp\;)*$/;
1014 }
1015
1016 my $title =
1017 &createTitle( $name, $state, $icon, \@states, undef, undef, $tId,
1018 $timestamp );
1019
1020 $linktext .= qq@$textBef@ if $textBef;
1021 my $imgalt = ( !defined $iconsrc ) ? $state : "";
1022 $iconsrc = "" unless defined $iconsrc;
1023 $linktext .= $query->img(
1024 {
1025 -name => "CLP_IMG_$name$uetId",
1026 -src => $iconsrc,
1027 -border => 0,
1028 -alt => $imgalt
1029 }
1030 );
1031 $linktext .= qq@$textAft@ if $textAft;
1032 if ( lc( $options{'clipos'} ) eq 'left' ) {
1033 $linktext .= ' ' . $options{'text'}
1034 unless $options{'text'} =~ /^(\s|\&nbsp\;)*$/;
1035 }
1036
1037 my ( $onmouseover, $onmouseout ) = ( "", "" );
1038 $action = "javascript:submitItemStateChange('$action');"
1039 if $options{'useajax'};
1040 $onmouseover =
1041 "clpTooltipShow('CLP_TT_$name$uetId','CLP_A_$name$uetId',"
1042 . ( 20 + int( $options{'tooltipfixleft'} ) ) . ","
1043 . ( 20 + int( $options{'tooltipfixtop'} ) )
1044 . ",true);";
1045 $onmouseout = "clpTooltipHide('CLP_TT_$name$uetId');";
1046 $text .= $query->div(
1047 {
1048 -id => "CLP_TT_$name$uetId",
1049 -style =>
1050"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'};"
1051 },
1052 $title
1053 );
1054 if ( $options{'statesel'} && ( !$options{'static'} ) ) {
1055 $action =
1056"javascript:clpTooltipShow('CLP_SM_DIV_$name$uetId','CLP_A_$name$uetId',"
1057 . ( 10 + int( $options{'tooltipfixleft'} ) ) . ","
1058 . ( 10 + int( $options{'tooltipfixtop'} ) )
1059 . ",true);";
1060 $text .= &createHiddenDirectSelectionDiv( $uetId, $name, $state, $icon,
1061 \@states, \@icons, $tId, $timestamp );
1062 }
1063 $action = "javascript:;" if $options{'static'};
1064 $text .= $query->a(
1065 {
1066 -onmouseover => $onmouseover,
1067 -onmouseout => $onmouseout,
1068 -id => "CLP_A_$name$uetId",
1069 -name => "CLP_A_$name$uetId",
1070 -href => $action
1071 },
1072 $linktext
1073 );
1074
1075 $text .= qq@</noautolink>@;
1076
1077 return $text;
1078}
1079
1080# =========================
1081sub createHiddenDirectSelectionDiv {
1082 my ( $id, $name, $state, $icon, $statesRef, $iconsRef, $tId, $timestamp ) =
1083 @_;
1084 my $text = "";
1085
1086 my $query = &Foswiki::Func::getCgiQuery();
1087 my $sl = "";
1088 $sl .= $query->sup(
1089 $query->a(
1090 {
1091 -href => "javascript:clpTooltipHide('CLP_SM_DIV_$name$id');",
1092 -title => 'close'
1093 },
1094 '[X]'
1095 )
1096 );
1097 for ( my $i = 0 ; $i <= $#$statesRef ; $i++ ) {
1098 my ( $s, $ic ) = ( $$statesRef[$i], $$iconsRef[$i] );
1099 my $action = &createAction( $id, $name, $state, $s );
1100 my $title =
1101 &createTitle( $name, $state, $icon, $statesRef, $s, $ic, $tId,
1102 $timestamp );
1103 my $submitAction = "";
1104 if ( $options{'useajax'} ) {
1105 $submitAction =
1106"submitItemStateChange('$action');clpTooltipHide('CLP_SM_DIV_$name$id');";
1107 $action = "javascript:$submitAction";
1108 }
1109 $text .= $query->div(
1110 {
1111 -id => "CLP_SM_TT_$name${id}_$i",
1112 -style =>
1113"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'};"
1114 },
1115 $title
1116 );
1117 my $imgsrc = ( &getImageSrc($ic) )[0];
1118 my $imgalt = ( defined $imgsrc ) ? "" : $s;
1119 $imgsrc = "" if !defined $imgsrc;
1120 $sl .= $query->a(
1121 {
1122 -id => "CLP_SM_A_$name${id}_$i",
1123 -href => "$action",
1124 -style => 'vertical-align:bottom;',
1125 -onmouseover =>
1126"clpTooltipShow('CLP_SM_TT_$name${id}_$i','CLP_SM_IMG_$name${id}_$i',"
1127 . ( 20 + int( $options{'tooltipfixleft'} ) ) . ","
1128 . ( 20 + int( $options{'tooltipfixtop'} ) ) . ");",
1129 -onmouseout => "clpTooltipHide('CLP_SM_TT_$name${id}_$i');",
1130 },
1131 $query->img(
1132 {
1133 src => $imgsrc,
1134 id => "CLP_SM_IMG_$name${id}_$i",
1135 alt => $imgalt,
1136 border => 0,
1137 style => 'vertical-align:bottom;cursor:move;'
1138 }
1139 )
1140 );
1141 $sl .= '&nbsp;';
1142 }
1143
1144 $text .= $query->div(
1145 {
1146 -id => "CLP_SM_DIV_$name$id",
1147 -style =>
1148"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'};"
1149 },
1150 $sl
1151 );
1152
1153 return $text;
1154}
1155
1156# =========================
1157sub getUniqueUrlParam {
1158 my ($url) = @_;
1159 my $r = 0;
1160 $r = rand(1000) while ( $r <= 100 );
1161 return ( ( $url =~ /\?/ ) ? '&' : '?' ) . 'clpid=' . time() . int($r);
1162}
1163
1164# =========================
1165sub urlEncode {
1166 my ($txt) = @_;
1167 $txt = Foswiki::urlEncode($txt) if defined $txt;
1168 return $txt;
1169}
1170
1171# =========================
1172sub htmlEncode {
1173 my ($txt) = @_;
1174 return "" unless defined $txt;
1175 $txt = Foswiki::entityEncode($txt);
1176
1177 return $txt;
1178}
1179
1180# ========================
1181sub substIllegalChars {
1182 my ($txt) = @_;
1183 return $txt if ( $txt =~ m/^[$Foswiki::regex{mixedAlphaNum}\-._]+$/ );
1184
1185 # strip out anything not-matching
1186 $txt = join( '',
1187 grep( /[$Foswiki::regex{mixedAlphaNum}\-._]/, split( '', $txt ) ) )
1188 if defined $txt;
1189 return $txt;
1190}
1191
1192# ========================
1193sub getImageSrc {
1194 my ($txt) = @_;
1195 my ( $src, $b, $a ) = ( undef, undef, undef );
1196 if ( $txt =~
1197/^(?:<span.*?>)?([^<]*)<img[^>]+?src=(["'])([^\2'">]+?)\2[^>]*>(.*)(?:<\/span>)?$/is
1198 )
1199 {
1200 ##$src=$1;
1201 ( $b, $src, $a ) = ( $1, $3, $4 );
1202 }
1203 return ( $src, $b, $a );
1204}
1205
1206# =========================
1207sub readChecklistItemStateTopic {
1208 my ($idMapRef) = @_;
1209 my $clisTopicName = $options{'statetopic'};
1210 Foswiki::Func::writeDebug(
1211"- ${pluginName}::readChecklistItemStateTopic($topic, $web): $clisTopicName"
1212 ) if $debug;
1213
1214 my $clisTopic = Foswiki::Func::readTopicText( $web, $clisTopicName );
1215
1216 if ( $clisTopic =~ /^http.*?\/oops/ ) {
1217 Foswiki::Func::redirectCgiQuery( Foswiki::Func::getCgiQuery(),
1218 $clisTopic );
1219 return;
1220 }
1221
1222 foreach my $line ( split /[\r\n]+/, $clisTopic ) {
1223 if ( $line =~
1224/^\s*\|\s*([^\|\*\s]*)\s*\|\s*([^\|\*\s]*)\s*\|\s*([^\|\s]*)\s*\|(\s*([^\|]+)\s*\|)?(\s*([^\|]+)\s*\|)?\s*$/
1225 )
1226 {
1227 my ( $name, $id, $state, $descr, $timestamp ) =
1228 ( $1, $2, $3, $5, $7 );
1229 $$idMapRef{$name}{$id}{'state'} = $state;
1230 $$idMapRef{$name}{$id}{'descr'} = $descr;
1231 $$idMapRef{$name}{$id}{'timestamp'} = $timestamp;
1232 push( @{ $$idOrderRef{$name} }, $id )
1233 unless grep( /^\Q$id\E$/, @{ $$idOrderRef{$name} } );
1234 }
1235 }
1236}
1237
1238# =========================
1239sub getClisTopicName {
1240 my ($name) = @_;
1241 return $namedDefaults{$name}{'statetopic'}
1242 ? $namedDefaults{$name}{'statetopic'}
1243 : $globalDefaults{'statetopic'};
1244}
1245
1246# =========================
1247sub getName {
1248 my ($paramsRef) = @_;
1249 my $name = &substIllegalChars( $$paramsRef{'name'} )
1250 if defined $$paramsRef{'name'};
1251 $name = $globalDefaults{'name'} unless defined $name;
1252 return $name;
1253}
1254
1255# =========================
1256sub getLogEntry {
1257 my ( $format, $id, $n, $laststate, $nextstate ) = @_;
1258 my $logentry =
1259 Foswiki::Func::expandCommonVariables( $format, $options{logtopic}, $web );
1260
1261 my @states = split /\|/, $options{'states'};
1262 $logentry =~ s/%CLIID%/$id/g;
1263 $logentry =~ s/%STATE%/(defined $laststate?$laststate:$states[0])/eg;
1264 $logentry =~ s/%NEXTSTATE%/$nextstate/g;
1265
1266 return $logentry;
1267}
1268
1269# =========================
1270sub saveLog {
1271 my ( $id, $n, $laststate, $nextstate ) = @_;
1272
1273 my $oopsUrl =
1274 &Foswiki::Func::setTopicEditLock( $web, $options{logtopic}, 1 );
1275 if ($oopsUrl) {
1276 &Foswiki::Func::redirectCgiQuery( Foswiki::Func::getCgiQuery(),
1277 $oopsUrl );
1278 return;
1279 }
1280
1281 my $logtopictext = Foswiki::Func::readTopicText( $web, $options{logtopic} );
1282 if ( $logtopictext =~ /^http.*?\/oops/ ) {
1283 Foswiki::Func::redirectCgiQuery( Foswiki::Func::getCgiQuery(),
1284 $logtopictext );
1285 return;
1286 }
1287 checkChangeAccessPermission( $options{logtopic}, $logtopictext ) || return;
1288
1289 my $logentry =
1290 getLogEntry( $options{logformat}, $id, $n, $laststate, $nextstate );
1291
1292 my $meta = "";
1293 while ( $logtopictext =~ s /(%META(:[^{]+){[^}]+}%)//s ) {
1294 $meta .= $1;
1295 }
1296 $logtopictext .= $logentry if $options{logpos} !~ /prepend/i;
1297 $logtopictext = $logentry . $logtopictext if $options{logpos} =~ /prepend/i;
1298
1299 Foswiki::Func::saveTopicText( $web, $options{logtopic},
1300 "$meta\n$logtopictext", 1, !$options{'notify'} );
1301 Foswiki::Func::setTopicEditLock( $web, $options{logtopic}, 0 );
1302
1303}
1304
1305# =========================
1306sub saveChecklistItemStateTopic {
1307 my ( $name, $perm ) = @_;
1308 return if $name eq "";
1309 my $clisTopicName = &getClisTopicName($name);
1310
1311 Foswiki::Func::writeDebug(
1312 "- ${pluginName}::saveChecklistItemStateTopic($name): $clisTopicName, "
1313 . $namedDefaults{$name}{'statetopic'} )
1314 if $debug;
1315 my $oopsUrl = &Foswiki::Func::setTopicEditLock( $web, $clisTopicName, 1 );
1316 if ($oopsUrl) {
1317 &Foswiki::Func::redirectCgiQuery( Foswiki::Func::getCgiQuery(),
1318 $oopsUrl );
1319 return;
1320 }
1321 my $installWeb = $Foswiki::cfg{SystemWebName};
1322 my $topicText = "";
1323 $topicText .=
1324"%RED% WARNING! THIS TOPIC IS GENERATED BY $installWeb.$pluginName PLUGIN. DO NOT EDIT THIS TOPIC (except table data)!%ENDCOLOR%\n";
1325 $topicText .=
1326 qq@%BR%Back to the \[\[$web.$topic\]\[checklist topic $topic\]\].\n\n@;
1327 foreach my $n ( sort keys %{$idMapRef} ) {
1328 next
1329 if ( $clisTopicName ne $globalDefaults{'statetopic'} )
1330 && ( ( !defined $namedDefaults{$n}{'statetopic'} )
1331 || ( $clisTopicName ne $namedDefaults{$n}{'statetopic'} ) );
1332 next
1333 if ( ( $namedDefaults{$n}{'statetopic'} )
1334 && ( $clisTopicName ne $namedDefaults{$n}{'statetopic'} ) );
1335
1336 my $states = ( $name eq $n ) ? $options{'states'} : undef;
1337 $states = $namedDefaults{$n}{'states'}
1338 unless defined $states && $states ne "";
1339 $states = &Foswiki::Func::getPreferencesValue("\U$pluginName\E_STATES")
1340 unless defined $states && $states ne "";
1341 $states = $globalDefaults{'states'}
1342 unless defined $states && $states ne "";
1343 my $statesel = join ", ", ( split /\|/, $states );
1344 $topicText .= "\n";
1345 $topicText .=
1346qq@%EDITTABLE{format="|text,20,$n|text,10,|select,1,$statesel|textarea,2,|"}%\n@;
1347 $topicText .= qq@%TABLE{footerrows="1"}%\n@;
1348 $topicText .= "|*context*|*id*|*state*|*description*|*timestamp*|\n";
1349
1350 ###foreach my $id (sort keys %{ $$idMapRef{$n}}) {
1351 ###foreach my $id (@{ $$idOrderRef{$n}}) {
1352 my @arr =
1353 $#{ $$idOrderRef{$n} } != -1
1354 ? @{ $$idOrderRef{$n} }
1355 : sort( keys( %{ $$idMapRef{$n} } ) );
1356 foreach my $id (@arr) {
1357 $topicText .= "|$n|"
1358 . &htmlEncode($id) . "|"
1359 . &htmlEncode( $$idMapRef{$n}{$id}{'state'} ) . '| '
1360 . &htmlEncode( $$idMapRef{$n}{$id}{'descr'} ) . '| '
1361 . &htmlEncode( $$idMapRef{$n}{$id}{'timestamp'} ) . " |\n";
1362 }
1363 $topicText .=
1364qq@| *$n* | *statistics:* | *%CALC{"\$COUNTITEMS(R2:C\$COLUMN()..R\$ROW(-1):C\$COLUMN())"}%* | *entries: %CALC{"\$ROW(-2)"}%* ||\n@;
1365 }
1366 if ($perm) {
1367 $topicText .= "\nAccess rights inherited from $web.$topic:\n\n";
1368 $topicText .= "\n$perm\n" if $perm;
1369 }
1370 $topicText .= "\n-- $installWeb.$pluginName - "
1371 . &Foswiki::Func::formatTime( time(), "rcs" ) . "\n";
1372 Foswiki::Func::saveTopicText( $web, $clisTopicName, $topicText, 1,
1373 !$options{'notify'} );
1374 Foswiki::Func::setTopicEditLock( $web, $clisTopicName, 0 );
1375}
1376
1377# =========================
1378sub createUnknownParamsMessage {
1379 my $msg = "";
1380 $msg =
1381 Foswiki::Func::getPreferencesValue("\U$pluginName\E_UNKNOWNPARAMSMSG")
1382 || undef;
1383 $msg = $globalDefaults{'unknownparamsmsg'} unless defined $msg;
1384 $msg =~ s/\%UNKNOWNPARAMSLIST\%/join(', ', sort @unknownParams)/eg;
1385 $msg =~ s/\%KNOWNPARAMSLIST\%/join(', ', sort keys %globalDefaults)/eg;
1386
1387 return $msg;
1388}
1389
1390# =========================
1391sub collectAllChecklistItems {
1392 ## never ever local($initText, $idMapRef, $idOrderRef, %itemsCollected, %itemStatesRead, $web, $topic)
1393 local ( $dryrun, %namedDefaults, %namedIds, %namedResetIds, @unknownParams,
1394 $resetDone, $stateChangeDone, $saveDone );
1395
1396 Foswiki::Func::writeDebug("- ${pluginName}::collectAllChecklistItems()")
1397 if $debug;
1398
1399 my $text = $initText;
1400
1401 # prevent changes:
1402 $resetDone = 1;
1403 $stateChangeDone = 1;
1404
1405 # prevent rendering:
1406 $dryrun = 1;
1407
1408 &handleAllTags( $text, $topic, $web );
1409
1410 Foswiki::Func::writeDebug(
1411 "- ${pluginName}::collectAllChecklistItems() done!")
1412 if $debug;
1413}
1414
1415# =========================
1416
# spent 587µs (198+390) within Foswiki::Plugins::ChecklistPlugin::postRenderingHandler which was called 10 times, avg 59µs/call: # 5 times (114µs+273µs) by Foswiki::Plugins::ChecklistPlugin::endRenderingHandler at line 1427, avg 78µs/call # 5 times (83µs+116µs) by Foswiki::Plugin::invoke at line 310 of /var/www/foswikidev/core/lib/Foswiki/Plugin.pm, avg 40µs/call
sub postRenderingHandler {
14171015µs1055µs my $query = Foswiki::Func::getCgiQuery();
# spent 55µs making 10 calls to Foswiki::Func::getCgiQuery, avg 6µs/call
14181032µs if ( defined $query ) {
14191027µs10229µs my $startTag = $query->comment('CLTABLEPLUGINSORTFIX:');
# spent 133µs making 9 calls to CGI::comment, avg 15µs/call # spent 96µs making 1 call to CGI::AUTOLOAD
14201015µs1085µs my $endTag = $query->comment(':CLTABLEPLUGINSORTFIX');
# spent 85µs making 10 calls to CGI::comment, avg 8µs/call
14211074µs $_[0] =~ s/\Q$startTag\E.*?\Q$endTag\E//sg;
1422 }
1423}
1424
1425# =========================
1426
# spent 425µs (38+388) within Foswiki::Plugins::ChecklistPlugin::endRenderingHandler which was called 5 times, avg 85µs/call: # 5 times (38µs+388µs) by Foswiki::Plugin::invoke at line 310 of /var/www/foswikidev/core/lib/Foswiki/Plugin.pm, avg 85µs/call
sub endRenderingHandler {
1427520µs5388µs return postRenderingHandler(@_);
# spent 388µs making 5 calls to Foswiki::Plugins::ChecklistPlugin::postRenderingHandler, avg 78µs/call
1428}
1429
1430# =========================
1431sub handleStateChanges {
1432
1433 my ($text) = @_;
1434 my $query = &Foswiki::Func::getCgiQuery();
1435 if ( ( defined $query->param('clpsc') ) && ( !$stateChangeDone ) ) {
1436 my ( $id, $name, $lastState, $nextstate ) = (
1437 $query->param('clpsc'), $query->param('clpscn'),
1438 $query->param('clpscls'), $query->param('clpscns')
1439 );
1440 if ( $options{'name'} eq $name ) {
1441 &doChecklistItemStateChange( $id, $name, $lastState, $text,
1442 $nextstate );
1443 $stateChangeDone = 1;
1444 }
1445 }
1446 my @states = split /\|/, $options{'states'};
1447 if ( ( defined $query->param('clreset') ) && ( !$resetDone ) ) {
1448 my $n = $query->param('clreset');
1449 my $s =
1450 ( defined $query->param('clresetst') )
1451 ? $query->param('clresetst')
1452 : $states[0];
1453 if ( ( $options{'name'} eq $n ) && ( grep( /^\Q$s\E$/s, @states ) ) ) {
1454 &doChecklistItemStateReset( $n, $s, $text );
1455 $resetDone = 1;
1456 }
1457 }
1458}
145914µs1;
1460