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

Filename/var/www/foswiki11/lib/Foswiki/Plugins/MultiTopicSavePlugin.pm
StatementsExecuted 28 statements in 2.58ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
11158µs223µsFoswiki::Plugins::MultiTopicSavePlugin::::initPluginFoswiki::Plugins::MultiTopicSavePlugin::initPlugin
11116µs26µsFoswiki::Plugins::MultiTopicSavePlugin::::BEGIN@31Foswiki::Plugins::MultiTopicSavePlugin::BEGIN@31
11116µs55µsFoswiki::Plugins::MultiTopicSavePlugin::::BEGIN@26Foswiki::Plugins::MultiTopicSavePlugin::BEGIN@26
11114µs27µsFoswiki::Plugins::MultiTopicSavePlugin::::BEGIN@22Foswiki::Plugins::MultiTopicSavePlugin::BEGIN@22
11113µs1.94msFoswiki::Plugins::MultiTopicSavePlugin::::BEGIN@28Foswiki::Plugins::MultiTopicSavePlugin::BEGIN@28
1119µs26µsFoswiki::Plugins::MultiTopicSavePlugin::::BEGIN@33Foswiki::Plugins::MultiTopicSavePlugin::BEGIN@33
1114µs4µsFoswiki::Plugins::MultiTopicSavePlugin::::BEGIN@24Foswiki::Plugins::MultiTopicSavePlugin::BEGIN@24
1114µs4µsFoswiki::Plugins::MultiTopicSavePlugin::::BEGIN@25Foswiki::Plugins::MultiTopicSavePlugin::BEGIN@25
0000s0sFoswiki::Plugins::MultiTopicSavePlugin::::_MULTITOPICSAVEENDFORMFoswiki::Plugins::MultiTopicSavePlugin::_MULTITOPICSAVEENDFORM
0000s0sFoswiki::Plugins::MultiTopicSavePlugin::::_MULTITOPICSAVEINPUTFoswiki::Plugins::MultiTopicSavePlugin::_MULTITOPICSAVEINPUT
0000s0sFoswiki::Plugins::MultiTopicSavePlugin::::_MULTITOPICSAVEMESSAGEFoswiki::Plugins::MultiTopicSavePlugin::_MULTITOPICSAVEMESSAGE
0000s0sFoswiki::Plugins::MultiTopicSavePlugin::::_MULTITOPICSAVESTARTFORMFoswiki::Plugins::MultiTopicSavePlugin::_MULTITOPICSAVESTARTFORM
0000s0sFoswiki::Plugins::MultiTopicSavePlugin::::_MULTITOPICSAVESUBMITFoswiki::Plugins::MultiTopicSavePlugin::_MULTITOPICSAVESUBMIT
0000s0sFoswiki::Plugins::MultiTopicSavePlugin::::_encodeHTMLEntitiesFoswiki::Plugins::MultiTopicSavePlugin::_encodeHTMLEntities
0000s0sFoswiki::Plugins::MultiTopicSavePlugin::::_encodeValueFoswiki::Plugins::MultiTopicSavePlugin::_encodeValue
0000s0sFoswiki::Plugins::MultiTopicSavePlugin::::_fetchFormFieldValueFoswiki::Plugins::MultiTopicSavePlugin::_fetchFormFieldValue
0000s0sFoswiki::Plugins::MultiTopicSavePlugin::::_topicLockFoswiki::Plugins::MultiTopicSavePlugin::_topicLock
0000s0sFoswiki::Plugins::MultiTopicSavePlugin::::restMultiTopicSaveFoswiki::Plugins::MultiTopicSavePlugin::restMultiTopicSave
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1# See bottom of file for default license and copyright information
2
3=begin TML
4
5---+ package MultiTopicSavePlugin
6
7This plugin enables saving content incl form data to multiple topics using
8only a single submit.
9
10It is typically used where you list content of a number of topics in a formatted
11search which present the content as an HTML form with fields for each topic.
12
13A submit button makes a rest call that causes this plugin to save the changed
14date to all the topics listed.
15
16=cut
17
18# change the package name!!!
19package Foswiki::Plugins::MultiTopicSavePlugin;
20
21# Always use strict to enforce variable scoping
22232µs239µs
# spent 27µs (14+13) within Foswiki::Plugins::MultiTopicSavePlugin::BEGIN@22 which was called: # once (14µs+13µs) by Foswiki::Plugin::BEGIN@2.23 at line 22
use strict;
# spent 27µs making 1 call to Foswiki::Plugins::MultiTopicSavePlugin::BEGIN@22 # spent 13µs making 1 call to strict::import
23
24220µs14µs
# spent 4µs within Foswiki::Plugins::MultiTopicSavePlugin::BEGIN@24 which was called: # once (4µs+0s) by Foswiki::Plugin::BEGIN@2.23 at line 24
use Foswiki::Func (); # The plugins API
# spent 4µs making 1 call to Foswiki::Plugins::MultiTopicSavePlugin::BEGIN@24
25222µs14µs
# spent 4µs within Foswiki::Plugins::MultiTopicSavePlugin::BEGIN@25 which was called: # once (4µs+0s) by Foswiki::Plugin::BEGIN@2.23 at line 25
use Foswiki::Plugins (); # For the API version
# spent 4µs making 1 call to Foswiki::Plugins::MultiTopicSavePlugin::BEGIN@25
26256µs293µs
# spent 55µs (16+39) within Foswiki::Plugins::MultiTopicSavePlugin::BEGIN@26 which was called: # once (16µs+39µs) by Foswiki::Plugin::BEGIN@2.23 at line 26
use Foswiki::Request;
# spent 55µs making 1 call to Foswiki::Plugins::MultiTopicSavePlugin::BEGIN@26 # spent 39µs making 1 call to CGI::import
27
28
# spent 1.94ms (13µs+1.93) within Foswiki::Plugins::MultiTopicSavePlugin::BEGIN@28 which was called: # once (13µs+1.93ms) by Foswiki::Plugin::BEGIN@2.23 at line 35
BEGIN {
29 # Backwards compatibility for Foswiki 1.1.x
30110µs11.93ms unless ( Foswiki::Request->can('multi_param') ) {
# spent 1.93ms making 1 call to CGI::can
31241µs236µs
# spent 26µs (16+10) within Foswiki::Plugins::MultiTopicSavePlugin::BEGIN@31 which was called: # once (16µs+10µs) by Foswiki::Plugin::BEGIN@2.23 at line 31
no warnings 'redefine';
# spent 26µs making 1 call to Foswiki::Plugins::MultiTopicSavePlugin::BEGIN@31 # spent 10µs making 1 call to warnings::unimport
3212µs *Foswiki::Request::multi_param = \&Foswiki::Request::param;
33225µs243µs
# spent 26µs (9+17) within Foswiki::Plugins::MultiTopicSavePlugin::BEGIN@33 which was called: # once (9µs+17µs) by Foswiki::Plugin::BEGIN@2.23 at line 33
use warnings 'redefine';
# spent 26µs making 1 call to Foswiki::Plugins::MultiTopicSavePlugin::BEGIN@33 # spent 17µs making 1 call to warnings::import
34 }
3512.32ms11.94ms}
# spent 1.94ms making 1 call to Foswiki::Plugins::MultiTopicSavePlugin::BEGIN@28
36
37# $VERSION should always be in the format$Rev: 9013 (2010-09-12) $ so that Foswiki can
38# determine the checked-in status of the extension.
391700nsour $VERSION = '1.10';
40
41# $RELEASE is used in the "Find More Extensions" automation in configure.
421300nsour $RELEASE = '1.10';
43
44# Short description of this plugin
45# One line description, is shown in the %SYSTEMWEB%.TextFormattingRules topic:
461200nsour $SHORTDESCRIPTION =
47 'Save form data to multiple topics in one single submission';
48
49# No preferences set in the plugin topic.
501200nsour $NO_PREFS_IN_TOPIC = 1;
51
52=begin TML
53
54---++ initPlugin($topic, $web, $user) -> $boolean
55 * =$topic= - the name of the topic in the current CGI query
56 * =$web= - the name of the web in the current CGI query
57 * =$user= - the login name of the user
58 * =$installWeb= - the name of the web the plugin topic is in
59 (usually the same as =$Foswiki::cfg{SystemWebName}=)
60
61Called to initialise the plugin. If everything is OK, should return
62a non-zero value. On non-fatal failure, should write a message
63using =Foswiki::Func::writeWarning= and return 0. In this case
64%<nop>FAILEDPLUGINS% will indicate which plugins failed.
65
66In the case of a catastrophic failure that will prevent the whole
67installation from working safely, this handler may use 'die', which
68will be trapped and reported in the browser.
69
70__Note:__ Please align macro names with the Plugin name, e.g. if
71your Plugin is called !FooBarPlugin, name macros FOOBAR and/or
72FOOBARSOMETHING. This avoids namespace issues.
73
74=cut
75
76
# spent 223µs (58+165) within Foswiki::Plugins::MultiTopicSavePlugin::initPlugin which was called: # once (58µs+165µs) by Foswiki::Plugin::__ANON__[/var/www/foswiki11/lib/Foswiki/Plugin.pm:241] at line 234 of /var/www/foswiki11/lib/Foswiki/Plugin.pm
sub initPlugin {
7712µs my ( $topic, $web, $user, $installWeb ) = @_;
78
79 # check for Plugins.pm versions
80116µs19µs if ( $Foswiki::Plugins::VERSION < 2.0 ) {
# spent 9µs making 1 call to version::vxs::VCMP
81 Foswiki::Func::writeWarning( 'Version mismatch between ',
82 __PACKAGE__, ' and Plugins.pm' );
83 return 0;
84 }
85
86 # Example code of how to get a preference value, register a macro
87 # handler and register a RESTHandler (remove code you do not need)
88
89 # Set your per-installation plugin configuration in LocalSite.cfg,
90 # like this:
91 # $Foswiki::cfg{Plugins}{EmptyPlugin}{ExampleSetting} = 1;
92 # See %SYSTEMWEB%.DevelopingPlugins#ConfigSpec for information
93 # on integrating your plugin configuration with =configure=.
94
95 # Always provide a default in case the setting is not defined in
96 # LocalSite.cfg. See %SYSTEMWEB%.Plugins for help in adding your plugin
97 # configuration to the =configure= interface.
98 # my $setting = $Foswiki::cfg{Plugins}{EmptyPlugin}{ExampleSetting} || 0;
99
100 # Register the _EXAMPLETAG function to handle %EXAMPLETAG{...}%
101 # This will be called whenever %EXAMPLETAG% or %EXAMPLETAG{...}% is
102 # seen in the topic text.
10314µs127µs Foswiki::Func::registerTagHandler( 'MULTITOPICSAVESUBMIT',
# spent 27µs making 1 call to Foswiki::Func::registerTagHandler
104 \&_MULTITOPICSAVESUBMIT
105 );
106
10712µs121µs Foswiki::Func::registerTagHandler( 'MULTITOPICSAVEINPUT',
# spent 21µs making 1 call to Foswiki::Func::registerTagHandler
108 \&_MULTITOPICSAVEINPUT
109 );
11014µs121µs Foswiki::Func::registerTagHandler( 'MULTITOPICSAVEMESSAGE',
# spent 21µs making 1 call to Foswiki::Func::registerTagHandler
111 \&_MULTITOPICSAVEMESSAGE
112 );
113
11413µs121µs Foswiki::Func::registerTagHandler( 'MULTITOPICSAVESTARTFORM',
# spent 21µs making 1 call to Foswiki::Func::registerTagHandler
115 \&_MULTITOPICSAVESTARTFORM
116 );
117
11813µs134µs Foswiki::Func::registerTagHandler( 'MULTITOPICSAVEENDFORM',
# spent 34µs making 1 call to Foswiki::Func::registerTagHandler
119 \&_MULTITOPICSAVEENDFORM
120 );
121
122 # Allow a sub to be called from the REST interface
123 # using the provided alias
12415µs132µs Foswiki::Func::registerRESTHandler( 'multitopicsave',
# spent 32µs making 1 call to Foswiki::Func::registerRESTHandler
125 \&restMultiTopicSave,
126 authenticate => 1,
127 http_allow => 'POST',
128 validate => 0
129 );
130
131 # Plugin correctly initialized
13217µs return 1;
133}
134
135=begin TML
136
137---++ _topicLock($web, $topic, $mode) -> ($success, $message)
138
139This is the which will lock or unlock a topic
140
141The parameter is:
142 * =$session= - The Foswiki object associated to this session.
143 * =$mode= - "locked" or "released", default "released"
144
145The sub returns
146 * =$success= - 0 = failed, 1 = success
147 * =$message= - a message how it went.
148
149Note: Message from this sub is not yet used in the plugin. Nice to have
150
151=cut
152
153sub _topicLock {
154 my ($web, $topic, $mode) = @_;
155
156 $mode ||= "released";
157
158 my $currentWikiName = Foswiki::Func::getWikiName( );
159
160 my $message = '';
161
162 unless ( Foswiki::Func::topicExists( $web, $topic ) ) {
163 $message .= "Topic $web.$topic does not exist\n\n";
164 return ( 0, $message );
165 }
166
167 # Is it locked?
168 my ($oopsUrl, $loginName, $unlockTime) =
169 Foswiki::Func::checkTopicEditLock( $web, $topic, undef );
170
171 my $lockedWikiName = Foswiki::Func::getWikiName( $loginName );
172
173 # We cannot lock or unlock if locked by someone else
174 if ( $unlockTime && ( $lockedWikiName ne $currentWikiName ) ) {
175 $message .= "Topic $web.$topic was not $mode. " .
176 "It is being edited by !$lockedWikiName";
177
178 return ( 0, $message );
179 }
180
181 # We cannot lock or unlock unless we have access rights
182 unless ( Foswiki::Func::checkAccessPermission( 'CHANGE', $currentWikiName,
183 undef, $topic, $web ) ) {
184
185 $message .= "Topic $web.$topic was not $mode " .
186 "due to lack of access rights\n\n";
187
188 return ( 0, $message );
189 }
190
191 # Success, we can lock or release
192 Foswiki::Func::setTopicEditLock( $web, $topic, ($mode eq 'locked') );
193
194 $message .= "Topic $web.$topic was $mode.";
195
196 return ( 1, $message );
197}
198
199
200=begin TML
201
202---++ _fetchFormFieldValue($field, $web, $topic) -> $value
203
204Fetch the raw unrendered content of a formfield
205
206The parameter is:
207 * =$field= - Field name to fetch.
208 * =$web= - Web name of topic
209 * =$topic= - Topic name
210
211The sub returns
212 * String - The raw content in the field
213 * Returns '' if topic does not exist or no access rights
214
215=cut
216
217sub _fetchFormFieldValue {
218 my ($field, $web, $topic) = @_;
219
220 my $currentWikiName = Foswiki::Func::getWikiName( );
221
222 unless ( Foswiki::Func::checkAccessPermission( 'VIEW', $currentWikiName,
223 undef, $topic, $web ) ) {
224 return '';
225 }
226
227 my ( $meta, undef ) = Foswiki::Func::readTopic( $web, $topic );
228 if ( $field eq 'text' ) { return $meta->text; }
229 my $value = $meta->get( 'FIELD', $field );
230
231 my $returnvalue = defined $value ? $value->{'value'} : '';
232
233 return $returnvalue;
234}
235
236=begin TML
237
238---++ _encodeValue($value) -> $value
239
240This function returns the input string encoded for view in TML tables
241We encode the most common destroyers of TML tables:
242newlines and vertical bars
243
244=cut
245
246sub _encodeValue {
247 my ( $value ) = @_;
248 $value =~ s/\r?\n/<br \/>/gs;
249 my $bar = '&#124;';
250 $value =~ s/\|/$bar/g;
251 return $value
252}
253
254=begin TML
255
256---++ _encodeHTMLEntities($value) -> $value
257
258This function encodes special characters to html entities
259so values can be used in input fields in edit mode
260
261=cut
262
263sub _encodeHTMLEntities {
264 my ( $value ) = @_;
265 $value =~ s/'/&#39;/g;
266 $value =~ s/</&lt;/g;
267 $value =~ s/>/&gt;/g;
268 return $value;
269}
270
271# The function used to handle the %MULTITOPICSAVESUBMIT{...}% macro
272sub _MULTITOPICSAVESUBMIT {
273 my($session, $params, $theTopic, $theWeb) = @_;
274 # $session - a reference to the Foswiki session object (if you don't know
275 # what this is, just ignore it)
276 # $params= - a reference to a Foswiki::Attrs object containing
277 # parameters.
278 # This can be used as a simple hash that maps parameter names
279 # to values, with _DEFAULT being the name for the default
280 # (unnamed) parameter.
281 # returnweb = the web we want to return to after submit (optional)
282 # returntopic = the topic we want to return to after submit
283 # can be web.topic format
284 # $theTopic - name of the topic in the query
285 # $theWeb - name of the web in the query
286 # Return: the result of processing the macro. This will replace the
287 # macro call in the final text.
288
289 # For example, %EXAMPLETAG{'hamburger' sideorder="onions"}%
290 # $params->{_DEFAULT} will be 'hamburger'
291 # $params->{sideorder} will be 'onions'
292
293 # We cannot use the rest parameter endPoint because we need to return
294 # to the submit with the URLPARAM MULTITOPICSAVEMESSAGE set.
295
296 my $web = defined $params->{returnweb} ? $params->{returnweb} : $theWeb;
297 my $topic = defined $params->{returntopic} ? $params->{returntopic} : $theTopic;
298 # If returnweb was undefined and returntopic is web.topic form the result
299 # is as expected web.topic.
300 ($web, $topic) = Foswiki::Func::normalizeWebTopicName($web, $topic);
301
302 my $result = "<input type='hidden' name='redirectweb' value='$web' />" .
303 "<input type='hidden' name='redirecttopic' value='$topic' />" .
304 "<input type='hidden' name='topic' value='$web.$topic' />" .
305 "<input type='submit' class='foswikiButton' value='";
306 $result .= $params->{_DEFAULT} || "Submit All Changes";
307 $result .= "' />";
308
309 return $result;
310
311}
312
313# The function used to handle the %MULTITOPICSAVEINPUT{...}% macro
314sub _MULTITOPICSAVEINPUT {
315 my($session, $params, $theTopic, $theWeb) = @_;
316 # $session - a reference to the Foswiki session object (if you don't know
317 # what this is, just ignore it)
318 # $params= - a reference to a Foswiki::Attrs object containing
319 # parameters.
320 # This can be used as a simple hash that maps parameter names
321 # to values, with _DEFAULT being the name for the default
322 # (unnamed) parameter.
323 # $theTopic - name of the topic in the query
324 # $theWeb - name of the web in the query
325 # Return: the result of processing the macro. This will replace the
326 # macro call in the final text.
327
328 # For example, %EXAMPLETAG{'hamburger' sideorder="onions"}%
329 # $params->{_DEFAULT} will be 'hamburger'
330 # INPUT will be 'onions'
331
332 my $result = '';
333 my $type = lc ( $params->{type} ) || 'text';
334 my $size = $params->{size}; # No default here
335 my $multiple = $params->{multiple} || 0;
336 my $field = $params->{_DEFAULT};
337 my $targetWeb = $params->{web} || $theWeb;
338 my $targetTopic = $params->{topic} || $theTopic;
339 my $currentWikiName = Foswiki::Func::getWikiName( );
340 my $placeholder = $params->{placeholder};
341
342 ( $targetWeb, $targetTopic ) =
343 Foswiki::Func::normalizeWebTopicName( $targetWeb, $targetTopic );
344
345 my $topicFQN = "$targetWeb.$targetTopic"; # Topic fully qualified name
346
347 # Special field text is the topic text and must always be textarea
348 $type = 'textarea' if ( $field eq 'text');
349
350 # Delay means we escape with $percnt and $quot
351 # We cannot replace inside _RAW because that also replace quotes in values
352 my $delay = $params->{delay};
353 if ( $delay && ( $delay =~ /\d+/ ) && $delay-- > 0 ) {
354 $result = "\$percntMULTITOPICSAVEINPUT{";
355 $result .= "\$quot$field\$quot ";
356
357 foreach my $key ( keys %$params ) {
358 next if ($key eq '_RAW' || $key eq '_DEFAULT');
359
360 if ( $key eq 'delay' ) {
361 $result .= "delay=\$quot$delay\$quot ";
362 next;
363 }
364
365 $result .= "$key=\$quot" . $params->{$key} . "\$quot ";
366 }
367 $result .= "}\$percnt";
368 return $result
369 }
370
371 # if value is not defined we set it to the string $value
372 my $value = defined $params->{value} ? $params->{value} : '$value';
373
374 # Substitute the string '$value' by $value. This enables the user to
375 # Prefix and suffix the existing value
376 $value =~
377 s/\$value/_fetchFormFieldValue( $field, $targetWeb, $targetTopic )/ge;
378
379 # If edit mode is defined and set to off - just return the value
380 my $editmode = defined $params->{editmode} ?
381 Foswiki::Func::isTrue( $params->{editmode} ) : 1;
382
383 my $lockmode = defined $params->{lockmode} ?
384 Foswiki::Func::isTrue( $params->{lockmode} ) : 0;
385
386 # encodeview is designed to be used in TML tables and encode the most
387 # destroyers of TML tables, newlines and vertical bars
388 my $encodeview = defined $params->{encodeview} ?
389 Foswiki::Func::isTrue( $params->{encodeview} ) : 1;
390
391 if ( $currentWikiName eq $Foswiki::cfg{DefaultUserWikiName} ) {
392 $value = _encodeValue($value) if $encodeview;
393 return $value;
394 }
395
396 if ( $editmode ) {
397 # if lockmode is enabled we lock topic when in edit mode and
398 # return the value if the lock failed since we cannot edit
399 # Otherwise input fields need special characters html encoded
400 if ( $lockmode ) {
401 unless ( (_topicLock( $targetWeb, $targetTopic, 'locked' ))[0] ) {
402 $value = _encodeValue($value) if $encodeview;
403 return $value;
404 }
405 }
406 $value = _encodeHTMLEntities( $value );
407 }
408 else {
409 # if lockmode is enabled we release topic lease when in non-edit mode
410 _topicLock( $targetWeb, $targetTopic, 'released' )
411 if $lockmode;
412 return '' if ( $type eq 'hidden' );
413 $value = _encodeValue($value) if $encodeview;
414 return $value;
415 }
416
417 # We assume leading and trailing spaces around option values are unwanted
418 my @options = ();
419 if ( defined $params->{options} ) {
420 @options = map { s/^\s*(.*?)\s*$/$1/; $_; }
421 split( /\s*,\s*/, $params->{options} );
422 }
423
424 # Render the field for editing depending on field type
425 if ( $type eq 'text' ) {
426 $result = "<input class='foswikiInputField' type='text' ";
427 $size = 10 if ( !$size || $size < 1 );
428 $result .= "size='$size' ";
429 $result .= "name='multitopicsavefield{$topicFQN}{$field}' ";
430 $result .= "placeholder='$placeholder' " if defined $placeholder;
431 $result .= "value='" . $value . "' />";
432 }
433 elsif ( $type eq 'textarea' ) {
434 $result = "<textarea class='foswikiTextarea' ";
435 my ($cols, $rows) = ( 40, 5 );
436 if ( defined $size ) {
437 if ( $size =~ m/(\d+)[xX](\d+)/ ) {
438 ($cols, $rows) = ( $1, $2 );
439 }
440 }
441 $result .= "cols='$cols' rows='$rows' ";
442 $result .= "name='multitopicsavefield{$topicFQN}{$field}'>";
443 $result .= "$value";
444 $result .= "</textarea>"
445 }
446 elsif ( $type eq 'radio' || $type eq 'checkbox' ) {
447 my @values
448 = map { s/^\s*(.*?)\s*$/$1/; $_; } split( /\s*,\s*/, $value );
449 my $initcounter = defined $size ? $size : 1;
450 my $counter = $initcounter;
451 $result = "<table style='border:none;border-style:none;border-width:0;padding-top:0;'>";
452 foreach my $option ( @options ) {
453 $result .= "<tr>" if ( $counter == $initcounter );
454 $result .= "<td style='border:none;border-style:none;border-width:0;padding-top:0;'><input type='$type' ";
455 $result .= "name='multitopicsavefield{$topicFQN}{$field}' ";
456 $result .= "value='" . $option . "' ";
457 if ( $type eq 'radio' && $option eq $value ) {
458 $result .= "checked='checked' ";
459 }
460 if ( $type eq 'checkbox' && grep (/^$option$/, @values ) ) {
461 $result .= "checked='checked' ";
462 }
463 $result .= "/> $option </td>";
464 unless ( --$counter ) {
465 $result .= "</tr> ";
466 $counter = $initcounter;
467 }
468 }
469 $result .= "</tr>" if ( $counter != $initcounter );
470 $result .= "</table>";
471
472 # We need a dummy hidden field to be able to send
473 # none of the checkboxes selected from the browser
474 $result .= "<input type='hidden' name='multitopicsavefield{$topicFQN}{$field}' value='' />"
475 if ($type eq 'checkbox');
476 }
477 elsif ( $type eq 'select' ) {
478 my @values =
479 map { s/^\s*(.*?)\s*$/$1/; $_; } split( /\s*,\s*/, $value );
480
481 $result = "<select "
482 . "name='multitopicsavefield{$topicFQN}{$field}' "
483 . "class='foswikiSelect' ";
484
485 $result .= "multiple='multiple' "
486 if Foswiki::Func::isTrue( $multiple );
487
488 $result .= "size='$size'"
489 if defined $size;
490
491 $result .= ">";
492
493 foreach my $option ( @options ) {
494 $result .= "<option class='foswikiOption' ";
495
496 if ( grep (/^$option$/, @values ) ) {
497 $result .= "selected='selected' ";
498 }
499
500 $result .= ">" . $option . "</option>";
501 }
502
503 $result .= "</select>";
504
505 # We need a dummy hidden field to be able to send
506 # none of the checkboxes selected from the browser
507 $result .= "<input type='hidden' name='multitopicsavefield{$topicFQN}{$field}' value='' />";
508 }
509 elsif ( $type eq 'hidden' ) {
510 $result = "<input type='hidden' ";
511 $result .= "name='multitopicsavefield{$topicFQN}{$field}' ";
512 $result .= "value='" . $value . "' />";
513 }
514 # else if the type is unknown we return nothing
515
516 return $result;
517}
518
519
520# The function used to handle the %MULTITOPICSAVEMESSAGE% macro
521sub _MULTITOPICSAVEMESSAGE {
522 my($session, $params, $theTopic, $theWeb) = @_;
523 # $session - a reference to the Foswiki session object (if you don't know
524 # what this is, just ignore it)
525 # $params= - a reference to a Foswiki::Attrs object containing
526 # parameters.
527 # This can be used as a simple hash that maps parameter names
528 # to values, with _DEFAULT being the name for the default
529 # (unnamed) parameter.
530 # $theTopic - name of the topic in the query
531 # $theWeb - name of the web in the query
532 # Return: the result of processing the macro. This will replace the
533 # macro call in the final text.
534
535 # For example, %EXAMPLETAG{'hamburger' sideorder="onions"}%
536 # $params->{_DEFAULT} will be 'hamburger'
537 # $params->{sideorder} will be 'onions'
538
539 return "%URLPARAM{\"MULTITOPICSAVEMESSAGE\"}%";
540}
541
542
543# The function used to handle the %MULTITOPICSAVESTARTFORM% macro
544sub _MULTITOPICSAVESTARTFORM {
545 my($session, $params, $theTopic, $theWeb) = @_;
546
547 my $result = "<form action='%SCRIPTURL{\"rest\"}%/" .
548 "MultiTopicSavePlugin/multitopicsave' method='post'>";
549 return $result;
550
551}
552
553
554# The function used to handle the %MULTITOPICSAVEENDFORM% macro
555sub _MULTITOPICSAVEENDFORM {
556 my($session, $params, $theTopic, $theWeb) = @_;
557
558 return "</form>";
559}
560
561
562=begin TML
563
564---++ restMultiTopicSave($session) -> $text
565
566This is the sub which is called called by the =rest= script with multitopicsave.
567
568The parameter is:
569 * =$session= - The Foswiki object associated to this session.
570
571Additional parameters can be recovered via the query object in the $session, for example:
572
573my $query = $session->{request};
574my $web = $query->{param}->{web}[0];
575
576For more information, check %SYSTEMWEB%.CommandAndCGIScripts#rest
577
578For information about handling error returns from REST handlers, see
579Foswiki::Support.Faq1
580
581*Since:* Foswiki::Plugins::VERSION 2.0
582
583=cut
584
585sub restMultiTopicSave {
586 my ($session) = @_;
587
588 my $query = Foswiki::Func::getCgiQuery();
589
590 my $redirecttopic = $query->param('redirecttopic') || '';
591 my $redirectweb = $query->param('redirectweb') || '';
592 my $sessionweb = $session->{webName};
593 my $sessiontopic = $session->{topicName};
594 my %parameters = ();
595 my $currentWikiName = Foswiki::Func::getWikiName( );
596
597 ( $redirectweb, $redirecttopic ) =
598 Foswiki::Func::normalizeWebTopicName( $redirectweb, $redirecttopic );
599
600 my $url = Foswiki::Func::getScriptUrl( $redirectweb, $redirecttopic, 'view' );
601 my $message = '';
602
603 if ( $currentWikiName eq $Foswiki::cfg{DefaultUserWikiName} ) {
604 $message = "Only authenticated users are allowed to save multiple topics\n\n";
605 $query->param(-name => 'MULTITOPICSAVEMESSAGE', -value => "$message");
606 Foswiki::Func::redirectCgiQuery( undef, $url, 1 );
607 return undef;
608 }
609
610 # First we put all the multitopicsavefield parameters in a hash
611 # parameters{topicname}{field}=value where value can be an array of
612 # values from select fields
613 foreach my $key ( $query->param() ) {
614 if ( $key =~ /^multitopicsavefield{(.*?)}{(.*?)}$/ ) {
615
616 my $topic = $1;
617 my $fieldName = $2;
618 my @fieldValues = $query->multi_param($key);
619
620 # Remove empty values, they are most likely dummy values used
621 # to indicate that no value in a multiple checkbox or select
622 # is selected
623 @fieldValues = grep( /.+/, @fieldValues);
624 $parameters{$topic}{$fieldName} = join(", ", @fieldValues );
625 }
626 }
627
628 # Now we traverse each topic and save all the parameters for
629 # each topic if they have changed.
630
631 my $topicsavecounter = 0;
632
633 foreach my $topickey ( keys %parameters ) {
634
635 my $saveThisTopic = 0; # if 1 access is checked and granted
636
637 my ( $web, $topic ) =
638 Foswiki::Func::normalizeWebTopicName( '', $topickey );
639
640 my ( $meta, $text ) = Foswiki::Func::readTopic( $web, $topic );
641
642 foreach my $fieldName ( keys %{$parameters{$topickey}} ) {
643 my $value = $parameters{$topickey}{$fieldName};
644 my $oldValue;
645
646 if ( $fieldName eq 'text' ) {
647 $oldValue = $text;
648
649 # Remove carriage returns because the Store also does that
650 # The normal storage of a topic always leaves at least one new line
651 $value =~ s/\r//g;
652 $value = "\n" if ( $value eq '' );
653 }
654 else {
655 my $fieldhashref = $meta->get( 'FIELD', $fieldName );
656
657 $oldValue = $fieldhashref ?
658 $meta->get( 'FIELD', $fieldName )->{'value'} :
659 '';
660 }
661
662 # Note: We can actually find and store fields that are not in the
663 # form definition topic. Let us call this a feature. Could be
664 # useful for finding old formfields in topics after form is altered
665 if ( $oldValue ne $value ) {
666 # OK we want to save to the topic. If we already decided we can
667 # save we do not need to check again
668 unless ( $saveThisTopic ||
669 Foswiki::Func::checkAccessPermission(
670 'CHANGE', $currentWikiName,
671 undef, $topic, $web
672 )
673 )
674 {
675 $message .=
676 "Topic $web.$topic was not saved due to lack " .
677 "of access rights\n\n";
678 last;
679 }
680 unless ( $saveThisTopic ) {
681 my ($oopsUrl, $loginName, $unlockTime) =
682 Foswiki::Func::checkTopicEditLock( $web, $topic, undef );
683 my $lockedWikiName = Foswiki::Func::getWikiName( $loginName );
684 if ( $unlockTime &&
685 ( $lockedWikiName ne $currentWikiName ) ) {
686 $message .=
687 "Topic $web.$topic was not saved because it is" .
688 "currently being edited by !$lockedWikiName\n\n";
689 last;
690 }
691 }
692 if ( $fieldName eq 'text' ) {
693 $text = $value;
694 }
695 else {
696 $meta->putKeyed( 'FIELD', { name => $fieldName, value => $value } );
697 }
698
699 $saveThisTopic = 1;
700 }
701 }
702
703 if ( $saveThisTopic ) {
704 Foswiki::Func::saveTopic($web, $topic, $meta, $text);
705
706 #We need to avoid leaving many topics in locked state.
707 Foswiki::Func::setTopicEditLock( $web, $topic, 0 );
708
709 $topicsavecounter++;
710 }
711 }
712
713 $message .= "Number of topics changed: $topicsavecounter";
714
715 $query->param(-name => 'MULTITOPICSAVEMESSAGE', -value => "$message");
716 Foswiki::Func::redirectCgiQuery( undef, $url, 1 );
717 return undef;
718}
719
72013µs1;
721
722__END__