~kosova/+junk/tuxfamily-twiki

« back to all changes in this revision

Viewing changes to foswiki/lib/Foswiki/Plugins/CommentPlugin/Comment.pm

  • Committer: James Michael DuPont
  • Date: 2009-07-18 19:58:49 UTC
  • Revision ID: jamesmikedupont@gmail.com-20090718195849-vgbmaht2ys791uo2
added foswiki

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Plugin for Foswiki - The Free and Open Source Wiki, http://foswiki.org/
 
2
#
 
3
# Copyright (C) 2004 Crawford Currie
 
4
# Copyright (C) 2001-2006 Foswiki Contributors.
 
5
# All Rights Reserved. Foswiki Contributors
 
6
# are listed in the AUTHORS file in the root of this distribution.
 
7
# NOTE: Please extend that file, not this notice.
 
8
#
 
9
# This program is free software; you can redistribute it and/or
 
10
# modify it under the terms of the GNU General Public License
 
11
# as published by the Free Software Foundation; either version 2
 
12
# of the License, or (at your option) any later version. For
 
13
# more details read LICENSE in the root of this distribution.
 
14
#
 
15
# This program is distributed in the hope that it will be useful,
 
16
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
18
#
 
19
# For licensing info read LICENSE file in the Foswiki root.
 
20
#
 
21
# Comment Foswiki plugin
 
22
# Original author David Weller, reimplemented by Peter Masiar
 
23
# and again by Crawford Currie
 
24
#
 
25
# This version is specific to Foswiki::Plugins::VERSION > 1.026
 
26
 
 
27
use strict;
 
28
 
 
29
use Foswiki;
 
30
use Foswiki::Plugins;
 
31
use Foswiki::Store;
 
32
use Foswiki::Attrs;
 
33
use CGI qw( -any );
 
34
 
 
35
package Foswiki::Plugins::CommentPlugin::Comment;
 
36
 
 
37
# PUBLIC save the given comment.
 
38
sub save {
 
39
 
 
40
    #my ( $text, $topic, $web ) = @_;
 
41
 
 
42
    my $wikiName = Foswiki::Func::getWikiName();
 
43
    if (
 
44
        !Foswiki::Func::checkAccessPermission(
 
45
            'change', $wikiName, '', $_[1], $_[2]
 
46
        )
 
47
      )
 
48
    {
 
49
 
 
50
        # user has no permission to change the topic
 
51
        throw Foswiki::OopsException(
 
52
            'accessdenied',
 
53
            def   => 'topic_access',
 
54
            web   => $_[2],
 
55
            topic => $_[1]
 
56
        );
 
57
    }
 
58
    else {
 
59
        _buildNewTopic(@_);
 
60
    }
 
61
}
 
62
 
 
63
# PUBLIC STATIC convert COMMENT statements to form prompts
 
64
sub prompt {
 
65
 
 
66
    #my ( $previewing, $text, $web, $topic ) = @_;
 
67
 
 
68
    my $defaultType =
 
69
      Foswiki::Func::getPreferencesValue('COMMENTPLUGIN_DEFAULT_TYPE')
 
70
      || 'above';
 
71
 
 
72
    my $message = '';
 
73
 
 
74
    # Is commenting disabled?
 
75
    my $disable = '';
 
76
    if ( $_[0] ) {
 
77
 
 
78
        # We are in Preview mode
 
79
        $message = "(Edit - Preview)";
 
80
        $disable = 'disabled';
 
81
    }
 
82
 
 
83
    my $idx = 0;
 
84
    $_[1] =~
 
85
s/%COMMENT({.*?})?%/_handleInput($1,$_[2],$_[3],\$idx,$message,$disable,$defaultType)/eg;
 
86
}
 
87
 
 
88
=pod
 
89
 
 
90
Parses a templatetopic attribute and returns a "Web.Topic" string.
 
91
 
 
92
=cut
 
93
 
 
94
sub _getTemplateLocation {
 
95
    my ( $attrtemplatetopic, $web ) = @_;
 
96
 
 
97
    my $templatetopic = '';
 
98
    my $templateweb = $web || '';
 
99
    if ($attrtemplatetopic) {
 
100
        my ( $templocweb, $temploctopic ) =
 
101
          Foswiki::Func::normalizeWebTopicName( $templateweb,
 
102
            $attrtemplatetopic );
 
103
        $templatetopic = "$templocweb.$temploctopic";
 
104
    }
 
105
    return $templatetopic;
 
106
}
 
107
 
 
108
# PRIVATE generate an input form for a %COMMENT tag
 
109
sub _handleInput {
 
110
    my ( $attributes, $web, $topic, $pidx, $message, $disable, $defaultType ) =
 
111
      @_;
 
112
 
 
113
    $attributes =~ s/^{(.*)}$/$1/ if ($attributes);
 
114
 
 
115
    my $attrs = new Foswiki::Attrs( $attributes, 1 );
 
116
    my $type = $attrs->remove('type') || $attrs->remove('mode') || $defaultType;
 
117
    my $silent            = $attrs->remove('nonotify');
 
118
    my $location          = $attrs->remove('location');
 
119
    my $remove            = $attrs->remove('remove');
 
120
    my $nopost            = $attrs->remove('nopost');
 
121
    my $default           = $attrs->remove('default');
 
122
    my $attrtemplatetopic = $attrs->remove('templatetopic') || '';
 
123
    my $templatetopic     = _getTemplateLocation( $attrtemplatetopic, $web );
 
124
 
 
125
    $message ||= $default || '';
 
126
    $message ||= $default || '';
 
127
    $disable ||= '';
 
128
 
 
129
    # clean off whitespace
 
130
    $type =~ m/(\S*)/;
 
131
    $type = $1;
 
132
 
 
133
    # Expand the template in the context of the web where the comment
 
134
    # box is (not the target of the comment!)
 
135
    my $input = _getTemplate( "PROMPT:$type", $web, $topic, $templatetopic )
 
136
      || '';
 
137
    return $input if $input =~ m/^%RED%/so;
 
138
 
 
139
    # Expand special attributes as required
 
140
    $input =~ s/%([a-z]\w+)\|(.*?)%/_expandPromptParams($1, $2, $attrs)/ieg;
 
141
 
 
142
    # see if this comment is targeted at a different topic, and
 
143
    # change the url if it is.
 
144
    my $anchor = undef;
 
145
    my $target = $attrs->remove('target');
 
146
    if ($target) {
 
147
 
 
148
        # extract web and anchor
 
149
        if ( $target =~ s/^(\w+)\.// ) {
 
150
            $web = $1;
 
151
        }
 
152
        if ( $target =~ s/(#\w+)$// ) {
 
153
            $anchor = $1;
 
154
        }
 
155
        if ( $target ne '' ) {
 
156
            $topic = $target;
 
157
        }
 
158
    }
 
159
 
 
160
    my $url = '';
 
161
    if ( $disable eq '' ) {
 
162
        $url = Foswiki::Func::getScriptUrl( $web, $topic, 'save' );
 
163
    }
 
164
 
 
165
    my $noform = $attrs->remove('noform') || '';
 
166
    if ( $input !~ m/^%RED%/ ) {
 
167
        $input =~ s/%DISABLED%/$disable/g;
 
168
        $input =~ s/%MESSAGE%/$message/g;
 
169
        my $n = $$pidx + 0;
 
170
 
 
171
        if ( $disable eq '' ) {
 
172
            my $hiddenFields = "";
 
173
            $hiddenFields .=
 
174
              "\n" . CGI::hidden( -name => 'comment_action', -value => 'save' );
 
175
            $hiddenFields .=
 
176
              "\n" . CGI::hidden( -name => 'comment_type', -value => $type );
 
177
            if ( defined($silent) ) {
 
178
                $hiddenFields .=
 
179
                  "\n" . CGI::hidden( -name => 'comment_nonotify', value => 1 );
 
180
            }
 
181
            if ($templatetopic) {
 
182
                $hiddenFields .= "\n"
 
183
                  . CGI::hidden(
 
184
                    -name  => 'comment_templatetopic',
 
185
                    -value => $templatetopic
 
186
                  );
 
187
            }
 
188
            if ($location) {
 
189
                $hiddenFields .= "\n"
 
190
                  . CGI::hidden(
 
191
                    -name  => 'comment_location',
 
192
                    -value => $location
 
193
                  );
 
194
            }
 
195
            elsif ($anchor) {
 
196
                $hiddenFields .= "\n"
 
197
                  . CGI::hidden( -name => 'comment_anchor', -value => $anchor );
 
198
            }
 
199
            else {
 
200
                $hiddenFields .= "\n"
 
201
                  . CGI::hidden( -name => 'comment_index', -value => $$pidx );
 
202
            }
 
203
            if ($nopost) {
 
204
                $hiddenFields .= "\n"
 
205
                  . CGI::hidden( -name => 'comment_nopost', -value => $nopost );
 
206
            }
 
207
            if ($remove) {
 
208
                $hiddenFields .= "\n"
 
209
                  . CGI::hidden( -name => 'comment_remove', -value => $$pidx );
 
210
            }
 
211
            $input .= $hiddenFields;
 
212
        }
 
213
        if ($noform) {
 
214
            my $form =
 
215
              _getTemplate( "FORM:$type", $topic, $web, $templatetopic, 'off' )
 
216
              || '';
 
217
            if ($form) {
 
218
                $form =~ s/%COMMENTPROMPT%/$input/;
 
219
                $input = $form;
 
220
            }
 
221
        }
 
222
        unless ( $noform eq 'on' ) {
 
223
            $input = CGI::start_form(
 
224
                -name   => $type . $n,
 
225
                -id     => $type . $n,
 
226
                -action => $url,
 
227
                -method => 'post'
 
228
              )
 
229
              . $input
 
230
              . CGI::end_form();
 
231
        }
 
232
    }
 
233
    $$pidx++;
 
234
    return $input;
 
235
}
 
236
 
 
237
# PRIVATE get the given template and do standard expansions
 
238
sub _getTemplate {
 
239
    my ( $name, $topic, $web, $templatetopic, $warn ) = @_;
 
240
 
 
241
    $warn ||= '';
 
242
 
 
243
    # Get the templates.
 
244
    my $templateFile =
 
245
         $templatetopic
 
246
      || Foswiki::Func::getPreferencesValue('COMMENTPLUGIN_TEMPLATES')
 
247
      || 'comments';
 
248
 
 
249
    my $templates = Foswiki::Func::loadTemplate($templateFile);
 
250
    if ( !$templates ) {
 
251
        Foswiki::Func::writeWarning(
 
252
            "Could not read template file '$templateFile'");
 
253
        return;
 
254
    }
 
255
 
 
256
    my $t = Foswiki::Func::expandTemplate($name);
 
257
    return "%RED%No such template def TMPL:DEF{$name}%ENDCOLOR%"
 
258
      unless ( defined($t) && $t ne '' ) || $warn eq 'off';
 
259
 
 
260
    return $t;
 
261
}
 
262
 
 
263
# PRIVATE expand special %param|default% parameters in PROMPT template
 
264
sub _expandPromptParams {
 
265
    my ( $name, $default, $attrs ) = @_;
 
266
 
 
267
    my $val = $attrs->{$name};
 
268
    return $val if defined($val);
 
269
    return $default;
 
270
}
 
271
 
 
272
# PRIVATE STATIC Performs comment insertion in the topic.
 
273
sub _buildNewTopic {
 
274
 
 
275
    #my ( $text, $topic, $web ) = @_;
 
276
    my ( $topic, $web ) = ( $_[1], $_[2] );
 
277
 
 
278
    my $query = Foswiki::Func::getCgiQuery();
 
279
    return unless $query;
 
280
 
 
281
    my $type =
 
282
         $query->param('comment_type')
 
283
      || Foswiki::Func::getPreferencesValue('COMMENTPLUGIN_DEFAULT_TYPE')
 
284
      || 'above';
 
285
    my $index         = $query->param('comment_index') || 0;
 
286
    my $anchor        = $query->param('comment_anchor');
 
287
    my $location      = $query->param('comment_location');
 
288
    my $remove        = $query->param('comment_remove');
 
289
    my $nopost        = $query->param('comment_nopost');
 
290
    my $templatetopic = $query->param('comment_templatetopic') || '';
 
291
 
 
292
    my $output = _getTemplate( "OUTPUT:$type", $topic, $web, $templatetopic );
 
293
    if ( $output =~ m/^%RED%/ ) {
 
294
        die $output;
 
295
    }
 
296
 
 
297
    # Expand the template
 
298
    my $position = 'AFTER';
 
299
    if ( $output =~ s/%POS:(.*?)%//g ) {
 
300
        $position = $1;
 
301
    }
 
302
 
 
303
    # Expand common variables in the template, but don't expand other
 
304
    # tags.
 
305
    $output = Foswiki::Func::expandVariablesOnTopicCreation($output);
 
306
 
 
307
    $output = '' unless defined($output);
 
308
 
 
309
    # SMELL: Reverse the process that inserts meta-data just performed
 
310
    # by the Foswiki core, but this time without the support of the
 
311
    # methods in the core. Fortunately this will work even if there is
 
312
    # no embedded meta-data.
 
313
    # Note: because this is Dakar, and has sensible semantics for handling
 
314
    # the =text= parameter to =save=, there is no longer any need to re-read
 
315
    # the topic. The text is automatically defaulted to the existing topic
 
316
    # text if the =text= parameter isn't specified - which for comments,
 
317
    # it isn't.
 
318
    my $premeta  = '';
 
319
    my $postmeta = '';
 
320
    my $inpost   = 0;
 
321
    my $text     = '';
 
322
    foreach my $line ( split( /\r?\n/, $_[0] ) ) {
 
323
        if ( $line =~ /^%META:[A-Z]+{[^}]*}%/ ) {
 
324
            if ($inpost) {
 
325
                $postmeta .= $line . "\n";
 
326
            }
 
327
            else {
 
328
                $premeta .= $line . "\n";
 
329
            }
 
330
        }
 
331
        else {
 
332
            $text .= $line . "\n";
 
333
            $inpost = 1;
 
334
        }
 
335
    }
 
336
 
 
337
    #make sure the anchor or location exits
 
338
    if ( defined($location) and not( $text =~ /(?<!location\=\")($location)/ ) )
 
339
    {
 
340
        undef $location;
 
341
    }
 
342
    if ( defined($anchor) and not( $text =~ /^($anchor\s)/ ) ) {
 
343
        undef $anchor;
 
344
    }
 
345
 
 
346
    unless ($nopost) {
 
347
        if ( $position eq 'TOP' ) {
 
348
            $text = $output . $text;
 
349
        }
 
350
        elsif ( $position eq 'BOTTOM' ) {
 
351
 
 
352
            # Awkward newlines here, to avoid running into meta-data.
 
353
            # This should _not_ be a problem.
 
354
            $text =~ s/[\r\n]+$//;
 
355
            $text .= "\n" unless $output =~ m/^\n/s;
 
356
            $text .= $output;
 
357
            $text .= "\n" unless $text   =~ m/\n$/s;
 
358
        }
 
359
        else {
 
360
            if ($location) {
 
361
                if ( $position eq 'BEFORE' ) {
 
362
                    $text .= $output
 
363
                      unless (
 
364
                        $text =~ s/(?<!location\=\")($location)/$output$1/m );
 
365
                }
 
366
                else {    # AFTER
 
367
                    $text .= $output
 
368
                      unless (
 
369
                        $text =~ s/(?<!location\=\")($location)/$1$output/m );
 
370
 
 
371
                }
 
372
                $text .= "\n" unless $text =~ m/\n$/s;
 
373
            }
 
374
            elsif ($anchor) {
 
375
 
 
376
                # position relative to anchor
 
377
                if ( $position eq 'BEFORE' ) {
 
378
                    $text .= $output
 
379
                      unless ( $text =~ s/^($anchor\s)/$output$1/m );
 
380
                }
 
381
                else {    # AFTER
 
382
                    $text .= $output
 
383
                      unless ( $text =~ s/^($anchor\s)/$1$output/m );
 
384
                }
 
385
                $text .= "\n" unless $text =~ m/\n$/s;
 
386
            }
 
387
            else {
 
388
 
 
389
                # Position relative to index'th comment
 
390
                my $idx = 0;
 
391
                unless (
 
392
                    $text =~ s((%COMMENT({.*?})?%.*\n))
 
393
                          (&_nth($1,\$idx,$position,$index,$output))eg
 
394
                  )
 
395
                {
 
396
 
 
397
                    # If there was a problem adding relative to the comment,
 
398
                    # add to the end of the topic
 
399
                    $text .= $output;
 
400
                }
 
401
                $text .= "\n" unless $text =~ m/\n$/s;
 
402
            }
 
403
        }
 
404
    }
 
405
 
 
406
    if ( defined $remove ) {
 
407
 
 
408
        # remove the index'th comment box
 
409
        my $idx = 0;
 
410
        $text =~ s/(%COMMENT({.*?})?%)/_remove_nth($1,\$idx,$remove)/eg;
 
411
    }
 
412
 
 
413
    $_[0] = $premeta . $text . $postmeta;
 
414
}
 
415
 
 
416
# PRIVATE embed output if this comment is the interesting one
 
417
sub _nth {
 
418
    my ( $tag, $pidx, $position, $index, $output ) = @_;
 
419
 
 
420
    if ( $$pidx == $index ) {
 
421
        if ( $position eq 'BEFORE' ) {
 
422
            $tag = $output . $tag;
 
423
        }
 
424
        else {    # AFTER
 
425
            $tag .= $output;
 
426
        }
 
427
    }
 
428
    $$pidx++;
 
429
    return $tag;
 
430
}
 
431
 
 
432
# PRIVATE remove the nth comment box
 
433
sub _remove_nth {
 
434
    my ( $tag, $pidx, $index ) = @_;
 
435
    $tag = '' if ( $$pidx == $index );
 
436
    $$pidx++;
 
437
    return $tag;
 
438
}
 
439
 
 
440
1;