File Coverage

blib/lib/Wiki/Toolkit/Formatter/UseMod.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


","");
line stmt bran cond sub pod time code
1             package Wiki::Toolkit::Formatter::UseMod;
2              
3 14     14   237369 use strict;
  14         38  
  14         658  
4              
5 14     14   172 use vars qw( $VERSION @_links_found );
  14         26  
  14         1067  
6             $VERSION = '0.24';
7              
8 14     14   13635 use URI::Escape;
  14         24585  
  14         1355  
9 14     14   15782 use Text::WikiFormat as => 'wikiformat';
  14         196431  
  14         114  
10 14     14   15088 use HTML::PullParser;
  14         161174  
  14         653  
11 14     14   34424 use URI::Find::Delimited;
  0            
  0            
12              
13             =head1 NAME
14              
15             Wiki::Toolkit::Formatter::UseMod - UseModWiki-style formatting for Wiki::Toolkit
16              
17             =head1 DESCRIPTION
18              
19             A formatter backend for L that supports UseMod-style formatting.
20              
21             =head1 SYNOPSIS
22              
23             use Wiki::Toolkit::Formatter::UseMod;
24              
25             # Instantiate - see below for parameter details.
26             my $formatter = Wiki::Toolkit::Formatter::UseMod->new( %config );
27              
28             # Format some text.
29             my $cooked = $formatter->format($raw);
30              
31             # Find out which other nodes that text would link to.
32             my @links_to = $formatter->find_internal_links($raw);
33              
34             =head1 METHODS
35              
36             =over 4
37              
38             =item B
39              
40             my $formatter = Wiki::Toolkit::Formatter::UseMod->new(
41             extended_links => 0, # $FreeLinks
42             implicit_links => 1, # $WikiLinks
43             force_ucfirst_nodes => 1, # $FreeUpper
44             use_headings => 1, # $UseHeadings
45             allowed_tags => [qw(b i)], # defaults to none
46             macros => {},
47             pass_wiki_to_macros => 0,
48             node_prefix => 'wiki.pl?',
49             node_suffix => '',
50             edit_prefix => 'wiki.pl?action=edit;id=',
51             edit_suffix => '',
52             munge_urls => 0,
53             external_link_class => 'external',
54             );
55              
56             Parameters will default to the values shown above (apart from
57             C, which defaults to allowing no tags, and
58             C, which defaults to false).
59              
60             =over 4
61              
62             =item B
63              
64             C, C, C and C
65             allow you to control the URLs generated for links to other wiki pages.
66             So for example with the defaults given above, a link to the Home node
67             will have the URL C and a link to the edit form for the
68             Home node will have the URL C
69              
70             (Note that of course the URLs that you wish to have generated will
71             depend on how your wiki application processes its CGI parameters - you
72             can't just put random stuff in there and hope it works!)
73              
74             =item B
75              
76             If you wish to have greater control over the links, you may use the
77             C parameter. The value of this should be a
78             subroutine reference. This sub will be called on each internal link
79             after all other formatting and munging I URL escaping has been
80             applied. It will be passed the node name as its first parameter and
81             should return a node name. Note that this will affect the URLs of
82             internal links, but not the link text.
83              
84             Example:
85              
86             # The formatter munges links so node names are ucfirst.
87             # Ensure 'state51' always appears in lower case in node names.
88             munge_node_name => sub {
89             my $node_name = shift;
90             $node_name =~ s/State51/state51/g;
91             return $node_name;
92             }
93              
94             B This is I usage and you should only do it if you
95             I know what you're doing. Consider in particular whether and
96             how your munged nodes are going to be treated by C.
97              
98             =item B
99              
100             By default, we emulate the UseModWiki behaviour of formatting external
101             links with hardcoded square brackets around them. If you would
102             instead prefer to control this with CSS, supply the
103             C parameter to C<< ->new >> - the value of this
104             parameter will be used as the class applied to the link (so it should
105             be a valid CSS class name). Controlling the appearance with CSS is
106             our recommended method, but the default is as described for reasons of
107             backward compatibility.
108              
109             =item B
110              
111             If you set C to true, then your URLs will be more
112             user-friendly, for example
113              
114             http://example.com/wiki.cgi?Mailing_List_Managers
115              
116             rather than
117              
118             http://example.com/wiki.cgi?Mailing%20List%20Managers
119              
120             The former behaviour is the actual UseMod behaviour, but requires a
121             little fiddling about in your code (see C),
122             so the default is to B munge URLs.
123              
124             =item B
125              
126             Be aware that macros are processed I filtering out disallowed
127             HTML tags and I transforming from wiki markup into HTML. They
128             are also not called in any particular order.
129              
130             The keys of macros should be either regexes or strings. The values can
131             be strings, or, if the corresponding key is a regex, can be coderefs.
132             The coderef will be called with the first nine substrings captured by
133             the regex as arguments. I would like to call it with all captured
134             substrings but apparently this is complicated.
135              
136             You may wish to have access to the overall wiki object in the subs
137             defined in your macro. To do this:
138              
139             =over
140              
141             =item *
142              
143             Pass the wiki object to the C<< ->formatter >> call as described below.
144              
145             =item *
146              
147             Pass a true value in the C parameter when calling
148             C<< ->new >>.
149              
150             =back
151              
152             If you do this, then I coderefs will be called with the wiki object
153             as the first parameter, followed by the first nine captured substrings
154             as described above. Note therefore that setting C
155             may cause backwards compatibility issues.
156              
157             =back
158              
159             Macro examples:
160              
161             # Simple example - substitute a little search box for '@SEARCHBOX'
162              
163             macros => {
164              
165             '@SEARCHBOX' =>
166             qq(
167            
168            
169             ),
170             }
171              
172             # More complex example - substitute a list of all nodes in a
173             # category for '@INDEX_LINK [[Category Foo]]'
174              
175             pass_wiki_to_macros => 1,
176             macros => {
177             qr/\@INDEX_LINK\s+\[\[Category\s+([^\]]+)]]/ =>
178             sub {
179             my ($wiki, $category) = @_;
180             my @nodes = $wiki->list_nodes_by_metadata(
181             metadata_type => "category",
182             metadata_value => $category,
183             ignore_case => 1,
184             );
185             my $return = "\n";
186             foreach my $node ( @nodes ) {
187             $return .= "* "
188             . $wiki->formatter->format_link(
189             wiki => $wiki,
190             link => $node,
191             )
192             . "\n";
193             }
194             return $return;
195             },
196             }
197              
198              
199             =cut
200              
201             sub new {
202             my ($class, @args) = @_;
203             my $self = {};
204             bless $self, $class;
205             $self->_init(@args) or return undef;
206             return $self;
207             }
208              
209             sub _init {
210             my ($self, %args) = @_;
211              
212             # Store the parameters or their defaults.
213             my %defs = ( extended_links => 0,
214             implicit_links => 1,
215             force_ucfirst_nodes => 1,
216             use_headings => 1,
217             allowed_tags => [],
218             macros => {},
219             pass_wiki_to_macros => 0,
220             node_prefix => 'wiki.pl?',
221             node_suffix => '',
222             edit_prefix => 'wiki.pl?action=edit;id=',
223             edit_suffix => '',
224             munge_urls => 0,
225             munge_node_name => undef,
226             external_link_class => undef,
227             );
228              
229             my %collated = (%defs, %args);
230             foreach my $k (keys %defs) {
231             $self->{"_".$k} = $collated{$k};
232             }
233             return $self;
234             }
235              
236             =item B
237              
238             my $html = $formatter->format($submitted_content, $wiki);
239              
240             Escapes any tags which weren't specified as allowed on creation, then
241             interpolates any macros, then translates the raw Wiki language
242             supplied into HTML.
243              
244             A L object can be supplied as an optional second parameter.
245             This object will be used to determine whether a linked-to node exists
246             or not, and alter the presentation of the link accordingly. This is
247             only really in here for use when this method is being called from
248             within L.
249              
250             =cut
251              
252             sub format {
253             my ($self, $raw, $wiki) = @_;
254             $raw =~ s/\r\n/\n/sg; # CGI newline is \r\n not \n
255             my $safe = "";
256              
257             my %allowed = map {lc($_) => 1, "/".lc($_) => 1} @{$self->{_allowed_tags}};
258              
259             # Parse the HTML - even if we're not allowing any tags, because we're
260             # using a custom escaping routine rather than CGI.pm
261             my $parser = HTML::PullParser->new(doc => $raw,
262             start => '"TAG", tag, text',
263             end => '"TAG", tag, text',
264             text => '"TEXT", tag, text');
265             while (my $token = $parser->get_token) {
266             my ($flag, $tag, $text) = @$token;
267             if ($flag eq "TAG" and !defined $allowed{lc($tag)}) {
268             $safe .= $self->_escape_HTML($text);
269             } else {
270             $safe .= $text;
271             }
272             }
273              
274             # Now do any inline links.
275             my $callback = sub {
276             my ($open, $close, $url, $title, $whitespace) = @_;
277             $title ||= $url;
278             if ( $open && $close ) {
279             return $self->make_external_link( title => $title, url => $url );
280             } else {
281             return $open
282             . $self->make_external_link( title => $title, url => $url )
283             . $close;
284             }
285             };
286            
287             my $finder = URI::Find::Delimited->new( ignore_quoted => 1, callback => $callback );
288             $finder->find(\$safe);
289              
290             # Now process any macros.
291             my %macros = %{$self->{_macros}};
292             foreach my $key (keys %macros) {
293             my $value = $macros{$key};
294             if ( ref $value && ref $value eq 'CODE' ) {
295             if ( $self->{_pass_wiki_to_macros} and $wiki ) {
296             $safe=~ s/$key/$value->($wiki, $1, $2, $3, $4, $5, $6, $7, $8, $9)/eg;
297             } else {
298             $safe=~ s/$key/$value->($1, $2, $3, $4, $5, $6, $7, $8, $9)/eg;
299             }
300             } else {
301             $safe =~ s/$key/$value/g;
302             }
303             }
304              
305             # Finally set up config and call Text::WikiFormat.
306             my %format_opts = $self->_format_opts;
307             my %format_tags = (
308             # chromatic made most of the regex below. I will document it when
309             # I understand it properly.
310             indent => qr/^(?:\t+|\s{4,}|\s*\*?(?=\**\*+))/,
311             newline => "", # avoid bogus
312             paragraph => [ "

", "

\n", "", "\n", 1 ], # no bogus
313             extended_link_delimiters => [ '[[', ']]' ],
314             blocks => {
315             ordered => qr/^\s*([\d]+)\.\s*/,
316             unordered => qr/^\s*\*\s*/,
317             definition => qr/^:\s*/,
318             pre => qr/^\s+/,
319             table => qr/^\|\|/,
320             },
321             definition => [ "
\n", "
\n", "
 ", "
\n" ],
322             pre => [ "
\n", "
\n", "", "\n" ],
323             table => [ qq|\n|, "
\n",
324             sub {
325             my $line = shift;
326             $line =~ s/\|\|$/<\/td>/;
327             $line =~ s/\|\|/<\/td>/g;
328             return ("
$line","
329             },
330             ],
331             # we don't label unordered lists as "not indented" so we can nest them.
332             indented => {
333             definition => 0,
334             ordered => 0,
335             pre => 0,
336             table => 0,
337             },
338             blockorder => [ qw( header line ordered unordered code definition pre table paragraph )],
339             nests => { map { $_ => 1} qw( ordered unordered ) },
340             link => sub {
341             my $link = shift;
342             return $self->format_link(
343             link => $link,
344             wiki => $wiki,
345             );
346             },
347             );
348              
349             return wikiformat($safe, \%format_tags, \%format_opts );
350             }
351              
352             sub _format_opts {
353             my $self = shift;
354             return (
355             extended => $self->{_extended_links},
356             prefix => $self->{_node_prefix},
357             implicit_links => $self->{_implicit_links}
358             );
359             }
360              
361             =item B
362              
363             my $string = $formatter->format_link(
364             link => "Home Node",
365             wiki => $wiki,
366             );
367              
368             An internal method exposed to make it easy to go from eg
369              
370             * Foo
371             * Bar
372              
373             to
374              
375             * Foo
376             * Bar
377              
378             See Macro Examples above for why you might find this useful.
379              
380             C should be something that would go inside your extended link
381             delimiters. C is optional but should be a L object.
382             If you do supply C then the method will be able to check whether
383             the node exists yet or not and so will call C<< ->make_edit_link >>
384             instead of C<< ->make_internal_link >> where appropriate. If you don't
385             supply C then C<< ->make_internal_link >> will be called always.
386              
387             This method used to be private so may do unexpected things if you use
388             it in a way that I haven't tested yet.
389              
390             =cut
391              
392             sub format_link {
393             my ($self, %args) = @_;
394             my $link = $args{link};
395             my %opts = $self->_format_opts;
396             my $wiki = $args{wiki};
397              
398             my $title;
399             ($link, $title) = split(/\|/, $link, 2) if $opts{extended};
400             $title =~ s/^\s*// if $title; # strip leading whitespace
401             $title ||= $link;
402              
403             if ( $self->{_force_ucfirst_nodes} ) {
404             $link = $self->_do_freeupper($link);
405             }
406             $link = $self->_munge_spaces($link);
407              
408             $link = $self->{_munge_node_name}($link)
409             if $self->{_munge_node_name};
410              
411             if (!$link) {
412             return "[Undefined link '$title']";
413             }
414              
415             my $editlink_not_link = 0;
416             # See whether the linked-to node exists, if we can.
417             if ( $wiki && !$wiki->node_exists( $link ) ) {
418             $editlink_not_link = 1;
419             }
420              
421             $link =~ s/ /_/g if $self->{_munge_urls};
422             $link = uri_escape( $link );
423              
424             if ( $editlink_not_link ) {
425             my $prefix = $self->{_edit_prefix};
426             my $suffix = $self->{_edit_suffix};
427             return $self->make_edit_link(
428             title => $title,
429             url => $prefix.$link.$suffix,
430             );
431             } else {
432             my $prefix = $self->{_node_prefix};
433             my $suffix = $self->{_node_suffix};
434             return $self->make_internal_link(
435             title => $title,
436             url => $prefix.$link.$suffix,
437             );
438             }
439             }
440              
441             # CGI.pm is sometimes awkward about actually performing CGI::escapeHTML
442             # if there's a previous instantiation - in the calling script, for example.
443             # So just do it here.
444             sub _escape_HTML {
445             my ($self, $text) = @_;
446             $text =~ s{&}{&}gso;
447             $text =~ s{<}{<}gso;
448             $text =~ s{>}{>}gso;
449             $text =~ s{"}{"}gso;
450             return $text;
451             }
452              
453             =item B
454            
455             my @links_to = $formatter->find_internal_links( $content );
456            
457             Returns a list of all nodes that the supplied content links to.
458            
459             =cut
460            
461             sub find_internal_links {
462             my ($self, $raw) = @_;
463            
464             @_links_found = ();
465            
466             my %format_opts = $self->_format_opts;
467              
468             my %format_tags = ( extended_link_delimiters => [ '[[', ']]' ],
469             link => sub {
470             my $link = shift;
471             my %opts = $self->_format_opts;
472             my $title;
473             ($link, $title) = split(/\|/, $link, 2)
474             if $opts{extended};
475             if ( $self->{_force_ucfirst_nodes} ) {
476             $link = $self->_do_freeupper($link);
477             }
478             $link = $self->{_munge_node_name}($link)
479             if $self->{_munge_node_name};
480             $link = $self->_munge_spaces($link);
481             push @Wiki::Toolkit::Formatter::UseMod::_links_found,
482             $link;
483             return ""; # don't care about output
484             }
485             );
486              
487             my $foo = wikiformat($raw, \%format_tags, \%format_opts);
488              
489             my @links = @_links_found;
490             @_links_found = ();
491             return @links;
492             }
493              
494              
495             =item B
496              
497             use URI::Escape;
498             $param = $formatter->node_name_to_node_param( "Recent Changes" );
499             my $url = "wiki.pl?" . uri_escape($param);
500              
501             In usemod, the node name is encoded prior to being used as part of the
502             URL. This method does this encoding (essentially, whitespace is munged
503             into underscores). In addition, if C is in action
504             then the node names will be forced ucfirst if they weren't already.
505              
506             Note that unless C was set to true when C was called,
507             this method will do nothing.
508              
509             =cut
510              
511             sub node_name_to_node_param {
512             my ($self, $node_name) = @_;
513             return $node_name unless $self->{_munge_urls};
514             my $param = $node_name;
515             $param = $self->_munge_spaces($param);
516             $param = $self->_do_freeupper($param) if $self->{_force_ucfirst_nodes};
517             $param =~ s/ /_/g;
518              
519             return $param;
520             }
521              
522             =item B
523              
524             my $node = $q->param('node') || "";
525             $node = $formatter->node_param_to_node_name( $node );
526              
527             In usemod, the node name is encoded prior to being used as part of the
528             URL, so we must decode it before we can get back the original node name.
529              
530             Note that unless C was set to true when C was called,
531             this method will do nothing.
532              
533             =cut
534              
535             sub node_param_to_node_name {
536             my ($self, $param) = @_;
537             return $param unless $self->{_munge_urls};
538              
539             # Note that this might not give us back exactly what we started with,
540             # since in the encoding we collapse and trim whitespace; but this is
541             # how usemod does it (as of 0.92) and usemod is what we're emulating.
542             $param =~ s/_/ /g;
543              
544             return $param;
545             }
546              
547             sub _do_freeupper {
548             my ($self, $node) = @_;
549              
550             # This is the FreeUpper usemod behaviour, slightly modified from
551             # their regexp, as we need to do it before we check whether the
552             # node exists ie before we substitute the spaces with underscores.
553             $node = ucfirst($node);
554             $node =~ s|([- _.,\(\)/])([a-z])|$1.uc($2)|ge;
555              
556             return $node;
557             }
558              
559             sub _munge_spaces {
560             my ($self, $node) = @_;
561              
562             # Yes, we really do only munge spaces, not all whitespace. This is
563             # how usemod does it (as of 0.92).
564             $node =~ s/ +/ /g;
565             $node =~ s/^ //;
566             $node =~ s/ $//;
567              
568             return $node
569             }
570              
571             =back
572              
573             =head1 SUBCLASSING
574              
575             The following methods can be overridden to provide custom behaviour.
576              
577             =over
578              
579             =item B
580              
581             my $link = $self->make_edit_link(
582             title => "Home Page",
583             url => "http://example.com/?id=Home",
584             );
585              
586             This method will be passed a title and a url and should return an HTML
587             snippet. For example, you can add a C attribute to the link </td> </tr> <tr> <td class="h" > <a name="588">588</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> like so: </td> </tr> <tr> <td class="h" > <a name="589">589</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="590">590</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> sub make_edit_link { </td> </tr> <tr> <td class="h" > <a name="591">591</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> my ($self, %args) = @_; </td> </tr> <tr> <td class="h" > <a name="592">592</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> my $title = $args{title}; </td> </tr> <tr> <td class="h" > <a name="593">593</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> my $url = $args{url}; </td> </tr> <tr> <td class="h" > <a name="594">594</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> return qq|[$title]<a href="$url" title="create">?</a>|; </td> </tr> <tr> <td class="h" > <a name="595">595</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> } </td> </tr> <tr> <td class="h" > <a name="596">596</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="597">597</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =cut </td> </tr> <tr> <td class="h" > <a name="598">598</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="599">599</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> sub make_edit_link { </td> </tr> <tr> <td class="h" > <a name="600">600</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> my ($self, %args) = @_; </td> </tr> <tr> <td class="h" > <a name="601">601</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> return qq|[$args{title}]<a href="$args{url}">?</a>|; </td> </tr> <tr> <td class="h" > <a name="602">602</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> } </td> </tr> <tr> <td class="h" > <a name="603">603</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="604">604</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item B<make_internal_link> </td> </tr> <tr> <td class="h" > <a name="605">605</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="606">606</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> my $link = $self->make_internal_link( </td> </tr> <tr> <td class="h" > <a name="607">607</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> title => "Home Page", </td> </tr> <tr> <td class="h" > <a name="608">608</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> url => "http://example.com/?id=Home", </td> </tr> <tr> <td class="h" > <a name="609">609</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> ); </td> </tr> <tr> <td class="h" > <a name="610">610</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="611">611</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> This method will be passed a title and a url and should return an HTML </td> </tr> <tr> <td class="h" > <a name="612">612</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> snippet. For example, you can add a C<class> attribute to the link </td> </tr> <tr> <td class="h" > <a name="613">613</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> like so: </td> </tr> <tr> <td class="h" > <a name="614">614</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="615">615</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> sub make_internal_link { </td> </tr> <tr> <td class="h" > <a name="616">616</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> my ($self, %args) = @_; </td> </tr> <tr> <td class="h" > <a name="617">617</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> my $title = $args{title}; </td> </tr> <tr> <td class="h" > <a name="618">618</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> my $url = $args{url}; </td> </tr> <tr> <td class="h" > <a name="619">619</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> return qq|<a href="$url" class="internal">$title</a>|; </td> </tr> <tr> <td class="h" > <a name="620">620</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> } </td> </tr> <tr> <td class="h" > <a name="621">621</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="622">622</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =cut </td> </tr> <tr> <td class="h" > <a name="623">623</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="624">624</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> sub make_internal_link { </td> </tr> <tr> <td class="h" > <a name="625">625</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> my ($self, %args) = @_; </td> </tr> <tr> <td class="h" > <a name="626">626</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> return qq|<a href="$args{url}">$args{title}</a>|; </td> </tr> <tr> <td class="h" > <a name="627">627</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> } </td> </tr> <tr> <td class="h" > <a name="628">628</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="629">629</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item B<make_external_link> </td> </tr> <tr> <td class="h" > <a name="630">630</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="631">631</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> my $link = $self->make_external_link( </td> </tr> <tr> <td class="h" > <a name="632">632</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> title => "London Perlmongers", </td> </tr> <tr> <td class="h" > <a name="633">633</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> url => "http://london.pm.org", </td> </tr> <tr> <td class="h" > <a name="634">634</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> ); </td> </tr> <tr> <td class="h" > <a name="635">635</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="636">636</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> This method will be passed a title and a url and should return an HTML </td> </tr> <tr> <td class="h" > <a name="637">637</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> snippet. For example, you can add a little icon after each external </td> </tr> <tr> <td class="h" > <a name="638">638</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> link like so: </td> </tr> <tr> <td class="h" > <a name="639">639</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="640">640</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> sub make_external_link { </td> </tr> <tr> <td class="h" > <a name="641">641</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> my ($self, %args) = @_; </td> </tr> <tr> <td class="h" > <a name="642">642</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> my $title = $args{title}; </td> </tr> <tr> <td class="h" > <a name="643">643</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> my $url = $args{url}; </td> </tr> <tr> <td class="h" > <a name="644">644</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> return qq|<a href="$url">$title</a> <img src="external.gif">|; </td> </tr> <tr> <td class="h" > <a name="645">645</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> } </td> </tr> <tr> <td class="h" > <a name="646">646</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="647">647</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =cut </td> </tr> <tr> <td class="h" > <a name="648">648</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="649">649</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> sub make_external_link { </td> </tr> <tr> <td class="h" > <a name="650">650</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> my ($self, %args) = @_; </td> </tr> <tr> <td class="h" > <a name="651">651</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> my ($open, $close) = ( "[", "]" ); </td> </tr> <tr> <td class="h" > <a name="652">652</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> my $link_class = $self->{_external_link_class} || ""; </td> </tr> <tr> <td class="h" > <a name="653">653</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> if ( $args{title} eq $args{url} || $link_class ) { </td> </tr> <tr> <td class="h" > <a name="654">654</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> ($open, $close) = ( "", "" ); </td> </tr> <tr> <td class="h" > <a name="655">655</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> } </td> </tr> <tr> <td class="h" > <a name="656">656</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> my $ret = qq|$open<a href="$args{url}"| </td> </tr> <tr> <td class="h" > <a name="657">657</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> . ( $link_class ? qq| class="$link_class"| : "" ) </td> </tr> <tr> <td class="h" > <a name="658">658</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> . qq|>$args{title}</a>$close|; </td> </tr> <tr> <td class="h" > <a name="659">659</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> return $ret; </td> </tr> <tr> <td class="h" > <a name="660">660</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> } </td> </tr> <tr> <td class="h" > <a name="661">661</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="662">662</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =back </td> </tr> <tr> <td class="h" > <a name="663">663</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="664">664</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head1 AUTHOR </td> </tr> <tr> <td class="h" > <a name="665">665</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="666">666</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Kake Pugh (kake@earth.li) and the Wiki::Toolkit team. </td> </tr> <tr> <td class="h" > <a name="667">667</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="668">668</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head1 COPYRIGHT </td> </tr> <tr> <td class="h" > <a name="669">669</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="670">670</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Copyright (C) 2003-2004 Kake Pugh. All Rights Reserved. </td> </tr> <tr> <td class="h" > <a name="671">671</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Copyright (C) 2006-2012 the Wiki::Toolkit team. All Rights Reserved. </td> </tr> <tr> <td class="h" > <a name="672">672</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="673">673</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> This module is free software; you can redistribute it and/or modify it </td> </tr> <tr> <td class="h" > <a name="674">674</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> under the same terms as Perl itself. </td> </tr> <tr> <td class="h" > <a name="675">675</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="676">676</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head1 CREDITS </td> </tr> <tr> <td class="h" > <a name="677">677</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="678">678</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> The OpenGuides London team (L<http://openguides.org/london/>) sent </td> </tr> <tr> <td class="h" > <a name="679">679</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> some very helpful bug reports. A lot of the work of this module is </td> </tr> <tr> <td class="h" > <a name="680">680</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> done within chromatic's module, L<Text::WikiFormat>. </td> </tr> <tr> <td class="h" > <a name="681">681</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="682">682</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head1 CAVEATS </td> </tr> <tr> <td class="h" > <a name="683">683</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="684">684</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> This doesn't yet support all of UseMod's formatting features and </td> </tr> <tr> <td class="h" > <a name="685">685</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> options, by any means. This really truly I<is> a 0.* release. Please </td> </tr> <tr> <td class="h" > <a name="686">686</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> send bug reports, omissions, patches, and stuff, to me at </td> </tr> <tr> <td class="h" > <a name="687">687</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> C<kake@earth.li>. </td> </tr> <tr> <td class="h" > <a name="688">688</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="689">689</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head1 NOTE ON USEMOD COMPATIBILITY </td> </tr> <tr> <td class="h" > <a name="690">690</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="691">691</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> UseModWiki "encodes" node names before making them part of a URL, so </td> </tr> <tr> <td class="h" > <a name="692">692</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> for example a node about Wombat Defenestration will have a URL like </td> </tr> <tr> <td class="h" > <a name="693">693</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="694">694</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> http://example.com/wiki.cgi?Wombat_Defenestration </td> </tr> <tr> <td class="h" > <a name="695">695</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="696">696</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> So if we want to emulate a UseModWiki exactly, we need to munge back </td> </tr> <tr> <td class="h" > <a name="697">697</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> and forth between node names as titles, and node names as CGI params. </td> </tr> <tr> <td class="h" > <a name="698">698</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="699">699</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> my $formatter = Wiki::Toolkit::Formatter::UseMod->new( munge_urls => 1 ); </td> </tr> <tr> <td class="h" > <a name="700">700</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> my $node_param = $q->param('id') || $q->param('keywords') || ""; </td> </tr> <tr> <td class="h" > <a name="701">701</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> my $node_name = $formatter->node_param_to_node_name( $node_param ); </td> </tr> <tr> <td class="h" > <a name="702">702</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="703">703</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> use URI::Escape; </td> </tr> <tr> <td class="h" > <a name="704">704</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> my $url = "http://example.com/wiki.cgi?" </td> </tr> <tr> <td class="h" > <a name="705">705</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> . uri_escape( </td> </tr> <tr> <td class="h" > <a name="706">706</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> $formatter->node_name_to_node_param( "Wombat Defenestration" ) </td> </tr> <tr> <td class="h" > <a name="707">707</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> ); </td> </tr> <tr> <td class="h" > <a name="708">708</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="709">709</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head1 SEE ALSO </td> </tr> <tr> <td class="h" > <a name="710">710</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="711">711</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =over 4 </td> </tr> <tr> <td class="h" > <a name="712">712</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="713">713</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item * L<Wiki::Toolkit> </td> </tr> <tr> <td class="h" > <a name="714">714</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="715">715</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item * L<Text::WikiFormat> </td> </tr> <tr> <td class="h" > <a name="716">716</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="717">717</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item * UseModWiki (L<http://www.usemod.com/cgi-bin/wiki.pl>) </td> </tr> <tr> <td class="h" > <a name="718">718</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="719">719</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =back </td> </tr> <tr> <td class="h" > <a name="720">720</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="721">721</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =cut </td> </tr> <tr> <td class="h" > <a name="722">722</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="723">723</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> 1; </td> </tr> </table> </body> </html>