Filename | /var/www/foswikidev/core/lib/Foswiki/Plugins/ChecklistPlugin.pm |
Statements | Executed 506 statements in 12.1ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
108 | 1 | 1 | 581µs | 581µs | commonTagsHandler | Foswiki::Plugins::ChecklistPlugin::
10 | 2 | 2 | 198µs | 587µs | postRenderingHandler | Foswiki::Plugins::ChecklistPlugin::
5 | 1 | 1 | 38µs | 425µs | endRenderingHandler | Foswiki::Plugins::ChecklistPlugin::
1 | 1 | 1 | 16µs | 60µs | initPlugin | Foswiki::Plugins::ChecklistPlugin::
1 | 1 | 1 | 16µs | 178µs | BEGIN@24 | Foswiki::Plugins::ChecklistPlugin::
1 | 1 | 1 | 9µs | 13µs | BEGIN@36 | Foswiki::Plugins::ChecklistPlugin::
1 | 1 | 1 | 9µs | 21µs | BEGIN@35 | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | checkChangeAccessPermission | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | collectAllChecklistItems | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | createAction | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | createHiddenDirectResetSelectionDiv | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | createHiddenDirectSelectionDiv | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | createResetAction | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | createTitle | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | createUnknownParamsMessage | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | doChecklistItemStateChange | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | doChecklistItemStateReset | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | extractPerms | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | getClisTopicName | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | getImageSrc | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | getLogEntry | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | getName | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | getNextState | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | getUniqueUrlParam | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | handleAllTags | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | handleAutoChecklist | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | handleChecklist | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | handleChecklistItem | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | handleDescription | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | handleStateChanges | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | htmlEncode | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | initDefaults | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | initNamedDefaults | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | initOptions | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | initStates | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | readChecklistItemStateTopic | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | renderChecklistItem | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | renderLegend | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | saveChecklistItemStateTopic | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | saveLog | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | substAttributes | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | substIllegalChars | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | substItemLine | Foswiki::Plugins::ChecklistPlugin::
0 | 0 | 0 | 0s | 0s | urlEncode | Foswiki::Plugins::ChecklistPlugin::
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 | # ========================= | ||||
21 | package Foswiki::Plugins::ChecklistPlugin; | ||||
22 | |||||
23 | # ========================= | ||||
24 | 1 | 7µs | 1 | 162µ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 # 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 | ||||
33 | 1 | 27µs | 1 | 178µs | ); # spent 178µs making 1 call to Foswiki::Plugins::ChecklistPlugin::BEGIN@24 |
34 | |||||
35 | 2 | 25µs | 2 | 34µ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 # spent 21µs making 1 call to Foswiki::Plugins::ChecklistPlugin::BEGIN@35
# spent 12µs making 1 call to strict::import |
36 | 2 | 7.59ms | 2 | 17µ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 # spent 13µs making 1 call to Foswiki::Plugins::ChecklistPlugin::BEGIN@36
# spent 4µs making 1 call to warnings::import |
37 | |||||
38 | 1 | 700ns | our $VERSION = '1.200'; | ||
39 | 1 | 200ns | our $RELEASE = '25 Jul 2015'; | ||
40 | 1 | 200ns | our $NO_PREFS_IN_TOPIC = 1; | ||
41 | |||||
42 | 1 | 300ns | my $defaultsSet = 0; | ||
43 | 1 | 100ns | my $debug; | ||
44 | |||||
45 | 1 | 300ns | $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 | ||||
49 | 1 | 2µs | ( $topic, $web, $user, $installWeb ) = @_; | ||
50 | |||||
51 | # check for Plugins.pm versions | ||||
52 | 1 | 20µs | 1 | 14µ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 | ||||
59 | 1 | 2µs | 1 | 30µs | $debug = Foswiki::Func::getPreferencesFlag("CHECKLISTPLUGIN_DEBUG"); # spent 30µs making 1 call to Foswiki::Func::getPreferencesFlag |
60 | |||||
61 | # Plugin correctly initialized | ||||
62 | 1 | 600ns | Foswiki::Func::writeDebug( | ||
63 | "- Foswiki::Plugins::${pluginName}::initPlugin( $web.$topic ) is OK") | ||||
64 | if $debug; | ||||
65 | |||||
66 | 1 | 300ns | $defaultsSet = 0; | ||
67 | 1 | 4µ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 | ||||
72 | ### my ( $text, $topic, $web ) = @_; # do not uncomment, use $_[0], $_[1]... instead | ||||
73 | |||||
74 | 108 | 16µ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 ( | ||||
82 | 108 | 157µs | %namedDefaults, %itemStatesRead, %namedIds, %namedResetIds, | ||
83 | @unknownParams, $initText, $resetDone, $stateChangeDone, | ||||
84 | $saveDone, $idMapRef, $idOrderRef, %itemsCollected, | ||||
85 | $dryrun | ||||
86 | ); | ||||
87 | |||||
88 | 108 | 78µs | $initText = $_[0] if $_[0] =~ /\%(CLI|CHECKLIST)/; | ||
89 | 108 | 4.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 | # ========================= | ||||
123 | sub handleAllTags { | ||||
124 | |||||
125 | ### my ( $text, $topic, $web ) = @_; # do not uncomment, use $_[0], $_[1]... instead | ||||
126 | # | ||||
127 | |||||
128 | $_[0] =~ | ||||
129 | s/%CHECKLISTSTART%(.*?)%CHECKLISTEND%/&handleAutoChecklist("",$1,$_[0])/sge; | ||||
130 | $_[0] =~ | ||||
131 | s/%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 | # ========================= | ||||
140 | sub 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 | # ========================= | ||||
201 | sub 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|\ \;)*$/ ) { | ||||
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/\|/\¦\;/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/\|/\¦\;/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 | # ========================= | ||||
317 | sub 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 | # ========================= | ||||
348 | sub 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 | # ========================= | ||||
368 | sub 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 | # ========================= | ||||
389 | sub 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}" }, ' ' ) | ||||
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 | # ========================= | ||||
497 | sub 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 | # ========================= | ||||
514 | sub 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 .= ' '; | ||||
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 | # ========================= | ||||
565 | sub 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 | # ========================= | ||||
583 | sub 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 =~ | ||||
614 | s/^(\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 =~ | ||||
619 | s/^(\s+[\d\*]+)(.*?)$/"$1 <span id=\"$id\" name=\"$name\" class=\"$class\">$2 \%CLI{$attribs}\%<\/span>"/e; | ||||
620 | } | ||||
621 | } | ||||
622 | |||||
623 | return $l; | ||||
624 | } | ||||
625 | |||||
626 | # ========================= | ||||
627 | sub 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 | # ========================= | ||||
661 | sub 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 | # ========================= | ||||
720 | sub 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 | # ========================= | ||||
768 | sub 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 | # ========================= | ||||
794 | sub 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 | # ========================= | ||||
838 | sub 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 | # ========================= | ||||
850 | sub 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 | # ========================= | ||||
875 | sub 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 | # ========================= | ||||
905 | sub 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 | # ========================= | ||||
935 | sub 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 =~ | ||||
950 | s/\%STATEICON\%/$query->img({alt=>$state,src=>(&getImageSrc($icon))[0]})/esg; | ||||
951 | $title =~ | ||||
952 | s/\%NEXTSTATEICON\%/$query->img({alt=>$nextstate,src=>(&getImageSrc($nextstateicon))[0]})/esg; | ||||
953 | $title =~ s/\%TIMESTAMP\%/$timestamp/esg; | ||||
954 | return $title; | ||||
955 | } | ||||
956 | |||||
957 | # ========================= | ||||
958 | sub 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" }, ' ' ) | ||||
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|\ \;)*$/; | ||||
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|\ \;)*$/; | ||||
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 | # ========================= | ||||
1081 | sub 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 .= ' '; | ||||
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 | # ========================= | ||||
1157 | sub 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 | # ========================= | ||||
1165 | sub urlEncode { | ||||
1166 | my ($txt) = @_; | ||||
1167 | $txt = Foswiki::urlEncode($txt) if defined $txt; | ||||
1168 | return $txt; | ||||
1169 | } | ||||
1170 | |||||
1171 | # ========================= | ||||
1172 | sub htmlEncode { | ||||
1173 | my ($txt) = @_; | ||||
1174 | return "" unless defined $txt; | ||||
1175 | $txt = Foswiki::entityEncode($txt); | ||||
1176 | |||||
1177 | return $txt; | ||||
1178 | } | ||||
1179 | |||||
1180 | # ======================== | ||||
1181 | sub 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 | # ======================== | ||||
1193 | sub 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 | # ========================= | ||||
1207 | sub 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 | # ========================= | ||||
1239 | sub getClisTopicName { | ||||
1240 | my ($name) = @_; | ||||
1241 | return $namedDefaults{$name}{'statetopic'} | ||||
1242 | ? $namedDefaults{$name}{'statetopic'} | ||||
1243 | : $globalDefaults{'statetopic'}; | ||||
1244 | } | ||||
1245 | |||||
1246 | # ========================= | ||||
1247 | sub 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 | # ========================= | ||||
1256 | sub 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 | # ========================= | ||||
1270 | sub 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 | # ========================= | ||||
1306 | sub 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 .= | ||||
1346 | qq@%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 .= | ||||
1364 | qq@| *$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 | # ========================= | ||||
1378 | sub 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 | # ========================= | ||||
1391 | sub 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 | ||||
1417 | 10 | 15µs | 10 | 55µs | my $query = Foswiki::Func::getCgiQuery(); # spent 55µs making 10 calls to Foswiki::Func::getCgiQuery, avg 6µs/call |
1418 | 10 | 32µs | if ( defined $query ) { | ||
1419 | 10 | 27µs | 10 | 229µ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 |
1420 | 10 | 15µs | 10 | 85µs | my $endTag = $query->comment(':CLTABLEPLUGINSORTFIX'); # spent 85µs making 10 calls to CGI::comment, avg 8µs/call |
1421 | 10 | 74µ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 | ||||
1427 | 5 | 20µs | 5 | 388µs | return postRenderingHandler(@_); # spent 388µs making 5 calls to Foswiki::Plugins::ChecklistPlugin::postRenderingHandler, avg 78µs/call |
1428 | } | ||||
1429 | |||||
1430 | # ========================= | ||||
1431 | sub 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 | } | ||||
1459 | 1 | 4µs | 1; | ||
1460 |