!/usr/bin/perl

Ikiwiki "blocks" relationship plugin.

package IkiWiki::Plugin::blocks;

use warnings; use strict; use IkiWiki 3.00;

sub import { hook(type => "getsetup", id => "blocks", call => &getsetup); hook(type => "checkconfig", id => "skeleton", call => &checkconfig); }

sub getsetup () { return plugin => { safe => 1, rebuild => 1, }, blocks_names => { type => "string", example => "blocks/blockedby", description => "comma separated list of defined relationship pairs, the forward and backward name separated by a slash", safe => 1, rebuild => 1, }, }

sub checkconfig () { my $blocksnames; if (defined $config{blocks_names}) { $blocksnames = $config{blocks_names}; } else { $blocksnames = "blocks/blockedby"; }

while ( $blocksnames =~ /([^ ]+)/g )
{
    if ( $1 =~ m@([a-zA-Z0-9]+)(/([a-zA-Z0-9]+))?@ )
    {
        my $from = $1;
        my $to = $3;
        hook(
            type => "preprocess",
            shortcut => 1, # gets interpreted by listdirectives; see doc/bugs/cannot_preview_shortcuts.mdwn / ikiwiki commit 354d22e2
            no_override => 1,
            id => $from,
            scan => 1,
            call => sub { preprocess_blocks($from, 1, @_); }
        );
        if ($to)
        {
            hook(
                type => "preprocess",
                shortcut => 1,
                no_override => 1,
                id => $to,
                scan => 1,
                call => sub { preprocess_blocks($from, 0, @_); }
            );
        }

        my $backward_match; my $backward_name;
        my $forward_match; my $forward_name;

        $backward_match = sub ($$;@) {
            my $page=shift;
            my $glob=shift;
            return IkiWiki::PageSpec::match_backlink($page, $glob, linktype => $from, @_);
        };

        $backward_name = "IkiWiki::PageSpec::match_$from";

        if ($to)
        {
            $forward_match = sub ($$;@) {
                my $page=shift;
                my $glob=shift;
                return IkiWiki::PageSpec::match_link($page, $glob, linktype => $from, @_);
            };

            $forward_name = "IkiWiki::PageSpec::match_$to";
        }

        {
            no strict 'refs';

            if ($to)
            {
                *$forward_name = $forward_match;
            }
            *$backward_name = $backward_match;
        }
    } else {
        error gettext("Malformed option in blocks_names");
    }
}

}

sub preprocess_blocks ($$@) { # with flip=0, the directive occurring on page A pointing at page B # means that A $relation B, with flip=1, it means B $relation A my $relation = shift; my $flip = shift;

if (! @_) {
    return "";
}
my %params=@_;
my $page = $params{page};
delete $params{page};
delete $params{destpage};
delete $params{preview};

foreach my $blocks (keys %params) {
    $blocks=linkpage($blocks);

    # hidden WikiLink
    if ( $flip == 0 ) {
        add_link($page, $blocks, $relation);
    } else {
        add_link($blocks, $page, $relation);
    }
}

return "";

}

1