package MojoMojo::Formatter::Wiki; use base qw/MojoMojo::Formatter/; use URI; =head1 NAME MojoMojo::Formatter::Wiki - Handle interpage linking. =head1 DESCRIPTION This formatter handles Wiki links using the [[explicit]] and ImplicitLink syntax. It will also indicate missing links with a question mark and a link to the edit page. In explicit mode, you can prefix the wikiword with an namespace, just like in a normal url. For example: [[../marcus]] or [[/oslo/vacation]]. =head1 METHODS =over 4 =item format_content_order Format order can be 1-99. The Wiki formatter runs on 30 =cut sub format_content_order { 30 } # explicit link regexes ## list of start-end delimiter pairs my @explicit_delims = ( qw{ \[\[ \]\] \(\( \)\) } ); my $explicit_separator = '\|'; sub _explicit_start_delims { my %delims = @explicit_delims; return keys %delims; } sub _explicit_end_delims { my %delims = @explicit_delims; return values %delims; } sub _generate_explicit_start { my $delims = join '|', _explicit_start_delims(); return qr{(?: $delims )}x; # non-capturing match } sub _generate_explicit_end { my $delims = join '|', _explicit_end_delims(); return qr{(?: $delims )}x; # non-capturing match } sub _generate_explicit_path { # non-greedily match characters that don't match the start-end and text delimiters my $delims = ( join '', _explicit_end_delims() ) . $explicit_separator; return qr{[^$delims]+?}; } sub _generate_explicit_text { # non-greedily match characters that don't match the start-end delimiters my $delims = join '', _explicit_end_delims(); return qr{[^$delims]+?}; } my $explicit_start = _generate_explicit_start(); my $explicit_end = _generate_explicit_end(); my $explicit_path = _generate_explicit_path(); my $explicit_text = _generate_explicit_text(); # implicit link (wikiword) regexes my $wikiword = qr{\b[A-Z][a-z]+[A-Z]\w*}; my $wikiword_escape = qr{\\}; sub _generate_non_wikiword_check { # we include '\/' to avoid wikiwords that are parts of urls # but why the question mark ('\?') at the end? my $non_wikiword_chars = ( join '', _explicit_start_delims() ) . $wikiword_escape . '\/' . '\?'; return qr{( ?]*>}sx ) { $$content =~ s{^.+?<\s*pre\b[^>]*>}{}sx; my ($inner) = $$content =~ m{^(.+?)<\s*/pre\s*>}sx; unless ($inner) { $res .=$part; last; } push @parts,$inner; $res .= $part . ''; $$content =~ s{^.+?<\s*/pre\s*>}{}sx; } $res .= $$content; return $res,@parts; } sub reinsert_pre { my ($content,@parts) = @_; foreach my $part (@parts) { $$content =~ s{}{
$part}sx; } return $$content; } =item format_content calls the formatter. Takes a ref to the content as well as the context object. =cut sub format_content { my ($class, $content, $c, $self) = @_; # Extract wikiwords, avoiding escaped and part of urls my @parts; ($$content,@parts)=strip_pre($content); $$content =~ s{ $non_wikiword_check ($wikiword) }{ $class->format_link($c, $1, $c->req->base,) }gex; # Remove escapes on escaped wikiwords. The escape means # that this wikiword is NOT a link to a wiki page. $$content =~ s{$wikiword_escape($wikiword)}{$1}g; # Do explicit links, e.g. [[ /path/to/page | link text ]] $$content =~ s{ $non_wikiword_check $explicit_start \s* ($explicit_path) \s* (?: $explicit_separator \s* ($explicit_text) \s* )? $explicit_end }{ $class->format_link($c, $1, $c->req->base, $2) }gex; $$content =~ s{ $non_wikiword_check ( $explicit_start \s* $explicit_path \s* (?: $explicit_separator \s* $explicit_text \s* )? $explicit_end) }{ $1 }gx; $$content=reinsert_pre($content,@parts); } =item format_link