~kosova/+junk/tuxfamily-twiki

« back to all changes in this revision

Viewing changes to foswiki/lib/Foswiki/Plugins/TwistyPlugin.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) Michael Daum
 
4
# Copyright (C) Arthur Clemens, arthur@visiblearea.com
 
5
# Copyright (C) Rafael Alvarez, soronthar@sourceforge.net
 
6
#
 
7
# This program is free software; you can redistribute it and/or
 
8
# modify it under the terms of the GNU General Public License
 
9
# as published by the Free Software Foundation; either version 2
 
10
# of the License, or (at your option) any later version.
 
11
#
 
12
# This program is distributed in the hope that it will be useful,
 
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
# GNU General Public License for more details, published at
 
16
# http://www.gnu.org/copyleft/gpl.html
 
17
#
 
18
 
 
19
=begin TML
 
20
 
 
21
---+ package TwistyPlugin
 
22
 
 
23
=cut
 
24
 
 
25
package Foswiki::Plugins::TwistyPlugin;
 
26
 
 
27
use Foswiki::Func;
 
28
use CGI::Cookie;
 
29
use strict;
 
30
 
 
31
use vars
 
32
  qw( $VERSION $RELEASE $pluginName @modes $doneHeader $doneDefaults $twistyCount
 
33
  $prefMode $prefShowLink $prefHideLink $prefRemember);
 
34
 
 
35
# This should always be $Rev: 3417 (2009-04-12) $ so that Foswiki can determine the checked-in
 
36
# status of the plugin. It is used by the build automation tools, so
 
37
# you should leave it alone.
 
38
$VERSION = '$Rev: 3417 (2009-04-12) $';
 
39
 
 
40
# This is a free-form string you can use to "name" your own plugin version.
 
41
# It is *not* used by the build automation tools, but is reported as part
 
42
# of the version number in PLUGINDESCRIPTIONS.
 
43
$RELEASE = '1.5.2';
 
44
 
 
45
$pluginName = 'TwistyPlugin';
 
46
 
 
47
my $TWISTYPLUGIN_COOKIE_PREFIX  = "TwistyPlugin_";
 
48
my $TWISTYPLUGIN_CONTENT_HIDDEN = 0;
 
49
my $TWISTYPLUGIN_CONTENT_SHOWN  = 1;
 
50
 
 
51
#there is no need to document this.
 
52
sub initPlugin {
 
53
    my ( $topic, $web, $user, $installWeb ) = @_;
 
54
 
 
55
    # check for Plugins.pm versions
 
56
    if ( $Foswiki::Plugins::VERSION < 1.1 ) {
 
57
        Foswiki::Func::writeWarning(
 
58
            "Version mismatch between $pluginName and Plugins.pm");
 
59
        return 0;
 
60
    }
 
61
 
 
62
    $doneDefaults = 0;
 
63
    $doneHeader   = 0;
 
64
    $twistyCount  = 0;
 
65
 
 
66
    Foswiki::Func::registerTagHandler( 'TWISTYSHOW',      \&_TWISTYSHOW );
 
67
    Foswiki::Func::registerTagHandler( 'TWISTYHIDE',      \&_TWISTYHIDE );
 
68
    Foswiki::Func::registerTagHandler( 'TWISTYBUTTON',    \&_TWISTYBUTTON );
 
69
    Foswiki::Func::registerTagHandler( 'TWISTY',          \&_TWISTY );
 
70
    Foswiki::Func::registerTagHandler( 'ENDTWISTY',       \&_ENDTWISTYTOGGLE );
 
71
    Foswiki::Func::registerTagHandler( 'TWISTYTOGGLE',    \&_TWISTYTOGGLE );
 
72
    Foswiki::Func::registerTagHandler( 'ENDTWISTYTOGGLE', \&_ENDTWISTYTOGGLE );
 
73
 
 
74
    return 1;
 
75
}
 
76
 
 
77
sub _setDefaults {
 
78
    return if $doneDefaults;
 
79
    $doneDefaults = 1;
 
80
 
 
81
    $prefMode =
 
82
         Foswiki::Func::getPreferencesValue('TWISTYMODE')
 
83
      || Foswiki::Func::getPluginPreferencesValue('TWISTYMODE')
 
84
      || 'span';
 
85
    $prefShowLink =
 
86
         Foswiki::Func::getPreferencesValue('TWISTYSHOWLINK')
 
87
      || Foswiki::Func::getPluginPreferencesValue('TWISTYSHOWLINK')
 
88
      || '';
 
89
    $prefHideLink =
 
90
         Foswiki::Func::getPreferencesValue('TWISTYHIDELINK')
 
91
      || Foswiki::Func::getPluginPreferencesValue('TWISTYHIDELINK')
 
92
      || '';
 
93
    $prefRemember =
 
94
         Foswiki::Func::getPreferencesValue('TWISTYREMEMBER')
 
95
      || Foswiki::Func::getPluginPreferencesValue('TWISTYREMEMBER')
 
96
      || '';
 
97
 
 
98
}
 
99
 
 
100
sub _addHeader {
 
101
    return if $doneHeader;
 
102
    $doneHeader = 1;
 
103
 
 
104
    # Untaint is required if use locale is on
 
105
    Foswiki::Func::loadTemplate(
 
106
        Foswiki::Sandbox::untaintUnchecked(lc($pluginName)) );
 
107
    my $header = Foswiki::Func::expandTemplate('twisty:header');
 
108
    Foswiki::Func::addToHEAD( $pluginName, $header );
 
109
}
 
110
 
 
111
sub _TWISTYSHOW {
 
112
    my ( $session, $params, $theTopic, $theWeb ) = @_;
 
113
    _setDefaults();
 
114
 
 
115
    my $mode = $params->{'mode'} || $prefMode;
 
116
    my $btn = _twistyBtn( 'show', @_ );
 
117
    return Foswiki::Func::decodeFormatTokens(
 
118
        _wrapInButtonHtml( $btn, $mode ) );
 
119
}
 
120
 
 
121
sub _TWISTYHIDE {
 
122
    my ( $session, $params, $theTopic, $theWeb ) = @_;
 
123
    _setDefaults();
 
124
    my $mode = $params->{'mode'} || $prefMode;
 
125
    my $btn = _twistyBtn( 'hide', @_ );
 
126
    return Foswiki::Func::decodeFormatTokens(
 
127
        _wrapInButtonHtml( $btn, $mode ) );
 
128
}
 
129
 
 
130
sub _TWISTYBUTTON {
 
131
    my ( $session, $params, $theTopic, $theWeb ) = @_;
 
132
    _setDefaults();
 
133
 
 
134
    my $mode = $params->{'mode'} || $prefMode;
 
135
    my $btnShow = _twistyBtn( 'show', @_ );
 
136
    my $btnHide = _twistyBtn( 'hide', @_ );
 
137
    my $prefix = $params->{'prefix'} || '';
 
138
    my $suffix = $params->{'suffix'} || '';
 
139
    my $btn    = $prefix . $btnShow . $btnHide . $suffix;
 
140
    return Foswiki::Func::decodeFormatTokens(
 
141
        _wrapInButtonHtml( $btn, $mode ) );
 
142
}
 
143
 
 
144
sub _TWISTY {
 
145
    my ( $session, $params, $theTopic, $theWeb ) = @_;
 
146
 
 
147
    _addHeader();
 
148
    $twistyCount++;
 
149
    my $id = $params->{'id'};
 
150
    if ( !defined $id || $id eq '' ) {
 
151
        $params->{'id'} = _createId( $params->{'id'}, $theWeb, $theTopic );
 
152
    }
 
153
    return _TWISTYBUTTON(@_) . _TWISTYTOGGLE(@_);
 
154
}
 
155
 
 
156
sub _TWISTYTOGGLE {
 
157
    my ( $session, $params, $theTopic, $theWeb ) = @_;
 
158
    my $id = $params->{'id'};
 
159
    if ( !defined $id || $id eq '' ) {
 
160
        return '';
 
161
    }
 
162
    _setDefaults();
 
163
    my $idTag = $id . 'toggle';
 
164
    my $mode = $params->{'mode'} || $prefMode;
 
165
    unshift @modes, $mode;
 
166
 
 
167
    my $isTrigger = 0;
 
168
    my $cookieState = _readCookie( $session, $idTag );
 
169
    my @propList =
 
170
      _createHtmlProperties( undef, $idTag, $mode, $params, $isTrigger,
 
171
        $cookieState );
 
172
    my $props = @propList ? " " . join( " ", @propList ) : '';
 
173
    my $modeTag = '<' . $mode . $props . '>';
 
174
    return Foswiki::Func::decodeFormatTokens(
 
175
        _wrapInContentHtmlOpen($mode) . $modeTag );
 
176
}
 
177
 
 
178
sub _ENDTWISTYTOGGLE {
 
179
    my ( $session, $params, $theTopic, $theWeb ) = @_;
 
180
    my $mode = shift @modes;
 
181
 
 
182
    return
 
183
"<span class='foswikiAlert'>woops, ordering error: got an ENDTWISTY before seeing a TWISTY</span>"
 
184
      unless $mode;
 
185
 
 
186
    my $modeTag = ($mode) ? '</' . $mode . '>' : '';
 
187
    return $modeTag . _wrapInContentHtmlClose($mode);
 
188
}
 
189
 
 
190
sub _createId {
 
191
    my ( $rawId, $theWeb, $theTopic ) = @_;
 
192
 
 
193
    if ( !defined $rawId || $rawId eq '' ) {
 
194
        return 'twistyId' . $theWeb . $theTopic . $twistyCount;
 
195
    }
 
196
    return "twistyId$rawId";
 
197
}
 
198
 
 
199
sub _twistyBtn {
 
200
    my ( $twistyControlState, $session, $params, $theTopic, $theWeb ) = @_;
 
201
 
 
202
    _addHeader();
 
203
 
 
204
    # not used yet:
 
205
    #my $triangle_right = '&#9658;';
 
206
    #my $triangle_down = '&#9660;';
 
207
 
 
208
    my $id = $params->{'id'};
 
209
    if ( !defined $id || $id eq '' ) {
 
210
        return '';
 
211
    }
 
212
    my $idTag = $id . $twistyControlState if ($twistyControlState) || '';
 
213
 
 
214
    my $defaultLink =
 
215
      ( $twistyControlState eq 'show' ) ? $prefShowLink : $prefHideLink;
 
216
 
 
217
    # link="" takes precedence over showlink="" and hidelink=""
 
218
    my $link = $params->{'link'};
 
219
 
 
220
    if ( !defined $link ) {
 
221
 
 
222
        # if 'link' is not set, try 'showlink' / 'hidelink'
 
223
        $link = $params->{ $twistyControlState . 'link' };
 
224
    }
 
225
    if ( !defined $link ) {
 
226
        $link = $defaultLink || '';
 
227
    }
 
228
    my $linkClass = $params->{'linkclass'} ? " $params->{'linkclass'}" : '';
 
229
    my $img =
 
230
         $params->{ $twistyControlState . 'img' }
 
231
      || $params->{'img'}
 
232
      || '';
 
233
    my $imgright =
 
234
         $params->{ $twistyControlState . 'imgright' }
 
235
      || $params->{'imgright'}
 
236
      || '';
 
237
    my $imgleft =
 
238
         $params->{ $twistyControlState . 'imgleft' }
 
239
      || $params->{'imgleft'}
 
240
      || '';
 
241
    $img      =~ s/['\"]//go;
 
242
    $imgright =~ s/['\"]//go;
 
243
    $imgleft  =~ s/['\"]//go;
 
244
    my $imgTag =
 
245
      ( $img ne '' ) ? '<img src="' . $img . '" border="0" alt="" />' : '';
 
246
    my $imgRightTag =
 
247
      ( $imgright ne '' )
 
248
      ? '<img src="' . $imgright . '" border="0" alt="" />'
 
249
      : '';
 
250
    my $imgLeftTag =
 
251
      ( $imgleft ne '' )
 
252
      ? '<img src="' . $imgleft . '" border="0" alt="" />'
 
253
      : '';
 
254
    
 
255
    my $imgLinkTag =
 
256
        '<a href="#">'
 
257
      . $imgLeftTag
 
258
      . '<span class="foswikiLinkLabel foswikiUnvisited' . $linkClass . '">'
 
259
      . $link
 
260
      . '</span>'
 
261
      . $imgTag
 
262
      . $imgRightTag . '</a>';
 
263
 
 
264
    my $isTrigger = 1;
 
265
    my $props     = '';
 
266
 
 
267
    if ( $idTag && $params ) {
 
268
        my $cookieState = _readCookie( $session, $idTag );
 
269
        my @propList =
 
270
          _createHtmlProperties( $twistyControlState, $idTag, undef, $params,
 
271
            $isTrigger, $cookieState );
 
272
        $props = @propList ? " " . join( " ", @propList ) : '';
 
273
    }
 
274
    my $triggerTag = '<span' . $props . '>' . $imgLinkTag . '</span>';
 
275
    return $triggerTag;
 
276
}
 
277
 
 
278
sub _createHtmlProperties {
 
279
    my ( $twistyControlState, $idTag, $mode, $params, $isTrigger, $cookie ) =
 
280
      @_;
 
281
    my $class      = $params->{'class'}      || '';
 
282
    my $firststart = $params->{'firststart'} || '';
 
283
    my $firstStartHidden;
 
284
    $firstStartHidden = 1 if ( $firststart eq 'hide' );
 
285
    my $firstStartShown;
 
286
    $firstStartShown = 1 if ( $firststart eq 'show' );
 
287
    my $cookieShow;
 
288
    $cookieShow = 1 if defined $cookie && $cookie == 1;
 
289
    my $cookieHide;
 
290
    $cookieHide = 1 if defined $cookie && $cookie == 0;
 
291
    my $start = $params->{start} || '';
 
292
    my $startHidden;
 
293
    $startHidden = 1 if ( $start eq 'hide' );
 
294
    my $startShown;
 
295
    $startShown = 1 if ( $start eq 'show' );
 
296
 
 
297
    _setDefaults();
 
298
    my $remember = $params->{'remember'} || $prefRemember;
 
299
    my $noscript = $params->{'noscript'} || '';
 
300
    my $noscriptHide;
 
301
    $noscriptHide = 1 if ( $noscript eq 'hide' );
 
302
    $mode ||= $prefMode;
 
303
 
 
304
    my @classList = ();
 
305
    push( @classList, $class ) if $class && !$isTrigger;
 
306
    push( @classList, 'twistyRememberSetting' ) if ( $remember eq 'on' );
 
307
    push( @classList, 'twistyForgetSetting' )   if ( $remember eq 'off' );
 
308
    push( @classList, 'twistyStartHide' )       if $startHidden;
 
309
    push( @classList, 'twistyStartShow' )       if $startShown;
 
310
    push( @classList, 'twistyFirstStartHide' )  if $firstStartHidden;
 
311
    push( @classList, 'twistyFirstStartShow' )  if $firstStartShown;
 
312
 
 
313
    # Mimic the rules in twist.js, function _update()
 
314
    my $state = '';
 
315
    $state = $TWISTYPLUGIN_CONTENT_HIDDEN if $firstStartHidden;
 
316
    $state = $TWISTYPLUGIN_CONTENT_SHOWN  if $firstStartShown;
 
317
 
 
318
    # cookie setting may override  firstStartHidden and firstStartShown
 
319
    $state = $TWISTYPLUGIN_CONTENT_HIDDEN if $cookieHide;
 
320
    $state = $TWISTYPLUGIN_CONTENT_SHOWN  if $cookieShow;
 
321
 
 
322
    # startHidden and startShown may override cookie
 
323
    $state = $TWISTYPLUGIN_CONTENT_HIDDEN if $startHidden;
 
324
    $state = $TWISTYPLUGIN_CONTENT_SHOWN  if $startShown;
 
325
 
 
326
    # assume trigger should be hidden
 
327
    # unless explicitly said otherwise
 
328
    my $shouldHideTrigger = 1;
 
329
    if ($isTrigger) {
 
330
        push( @classList, 'twistyTrigger foswikiUnvisited' );
 
331
 
 
332
        if (   $state eq $TWISTYPLUGIN_CONTENT_SHOWN
 
333
            && $twistyControlState eq 'hide' )
 
334
        {
 
335
            $shouldHideTrigger = 0;
 
336
        }
 
337
        if (   $state eq $TWISTYPLUGIN_CONTENT_HIDDEN
 
338
            && $twistyControlState eq 'show' )
 
339
        {
 
340
            $shouldHideTrigger = 0;
 
341
        }
 
342
        push( @classList, 'twistyHidden' ) if $shouldHideTrigger;
 
343
    }
 
344
 
 
345
    # assume content should be hidden
 
346
    # unless explicitly said otherwise
 
347
    my $shouldHideContent = 1;
 
348
    if ( !$isTrigger ) {
 
349
        push( @classList, 'twistyContent' );
 
350
 
 
351
        if ( $state eq $TWISTYPLUGIN_CONTENT_SHOWN ) {
 
352
            $shouldHideContent = 0;
 
353
        }
 
354
        push( @classList, 'foswikiMakeHidden' ) if $shouldHideContent;
 
355
    }
 
356
 
 
357
    # deprecated
 
358
    # should be done by Foswiki template scripts instead
 
359
    if ( !$isTrigger && $noscriptHide ) {
 
360
        if ( $mode eq 'div' ) {
 
361
            push( @classList, 'foswikiMakeVisibleBlock' );
 
362
        }
 
363
        else {
 
364
            push( @classList, 'foswikiMakeVisibleInline' );
 
365
        }
 
366
    }
 
367
 
 
368
    # let javascript know we have set the state already
 
369
    push( @classList, 'twistyInited' . $state );
 
370
 
 
371
    my @propList = ();
 
372
    push( @propList, 'id="' . $idTag . '"' );
 
373
    my $classListString = join( " ", @classList );
 
374
    push( @propList, 'class="' . $classListString . '"' );
 
375
    return @propList;
 
376
}
 
377
 
 
378
=begin TML
 
379
 
 
380
Reads a setting from the FOSWIKIPREF cookie.
 
381
Returns:
 
382
   * 1 if the cookie has been set (meaning: show content)
 
383
   * 0 if the cookie is '0' (meaning: hide content)
 
384
   * undef if no cookie has been set
 
385
 
 
386
=cut
 
387
 
 
388
sub _readCookie {
 
389
    my ( $session, $idTag ) = @_;
 
390
 
 
391
    return '' if !$idTag;
 
392
 
 
393
    # which state do we use?
 
394
    my $cgi    = new CGI;
 
395
    my $cookie = $cgi->cookie('FOSWIKIPREF');
 
396
    my $tag    = $idTag;
 
397
    $tag =~ s/^(.*)(hide|show|toggle)$/$1/go;
 
398
    my $key = $TWISTYPLUGIN_COOKIE_PREFIX . $tag;
 
399
 
 
400
    return unless ( defined($key) && defined($cookie) );
 
401
 
 
402
    my $value = '';
 
403
    if ( $cookie =~ m/\b$key\=(.+?)\b/gi ) {
 
404
        $value = $1;
 
405
    }
 
406
 
 
407
    return if $value eq '';
 
408
    return ( $value eq '1' ) ? 1 : 0;
 
409
}
 
410
 
 
411
sub _wrapInButtonHtml {
 
412
    my ( $text, $mode ) = @_;
 
413
    return _wrapInContainerHideIfNoJavascripOpen($mode) . $text
 
414
      . _wrapInContainerDivIfNoJavascripClose($mode);
 
415
}
 
416
 
 
417
sub _wrapInContentHtmlOpen {
 
418
    my ($mode) = @_;
 
419
    return "<$mode class=\"twistyPlugin\">";
 
420
}
 
421
 
 
422
sub _wrapInContentHtmlClose {
 
423
    my ($mode) = @_;
 
424
    return "</$mode><!--/twistyPlugin-->";
 
425
}
 
426
 
 
427
sub _wrapInContainerHideIfNoJavascripOpen {
 
428
    my ($mode) = @_;
 
429
    return '<' . $mode . ' class="twistyPlugin foswikiMakeVisibleInline">';
 
430
}
 
431
 
 
432
sub _wrapInContainerDivIfNoJavascripClose {
 
433
    my ($mode) = @_;
 
434
    return '</' . $mode . '><!--/twistyPlugin foswikiMakeVisibleInline-->';
 
435
}
 
436
 
 
437
1;