suggested plugin: blocks (free relationships)
[ikiwiki.git] / doc / todo / flexible_relationships_between_pages / blocks.pm.mdwn
1 #!/usr/bin/perl
2 # Ikiwiki "blocks" relationship plugin.
3 package IkiWiki::Plugin::blocks;
4
5 use warnings;
6 use strict;
7 use IkiWiki 3.00;
8
9 sub import {
10         hook(type => "getsetup", id => "blocks", call => \&getsetup);
11         hook(type => "checkconfig", id => "skeleton", call => \&checkconfig);
12 }
13
14 sub getsetup () {
15         return
16                 plugin => {
17                         safe => 1,
18                         rebuild => 1,
19                 },
20                 blocks_names => {
21                         type => "string",
22                         example => "blocks/blockedby",
23                         description => "comma separated list of defined relationship pairs, the forward and backward name separated by a slash",
24                         safe => 1,
25                         rebuild => 1,
26                 },
27 }
28
29 sub checkconfig () {
30         my $blocksnames;
31         if (defined $config{blocks_names}) {
32                 $blocksnames = $config{blocks_names};
33         } else {
34                 $blocksnames = "blocks/blockedby";
35         }
36
37         while ( $blocksnames =~ /([^ ]+)/g )
38         {
39                 if ( $1 =~ m@([a-zA-Z0-9]+)(/([a-zA-Z0-9]+))?@ )
40                 {
41                         my $from = $1;
42                         my $to = $3;
43                         hook(
44                                 type => "preprocess",
45                                 shortcut => 1, # gets interpreted by listdirectives; see doc/bugs/cannot_preview_shortcuts.mdwn / ikiwiki commit 354d22e2
46                                 no_override => 1,
47                                 id => $from,
48                                 scan => 1,
49                                 call => sub { preprocess_blocks($from, 1, @_); }
50                         );
51                         if ($to)
52                         {
53                                 hook(
54                                         type => "preprocess",
55                                         shortcut => 1,
56                                         no_override => 1,
57                                         id => $to,
58                                         scan => 1,
59                                         call => sub { preprocess_blocks($from, 0, @_); }
60                                 );
61                         }
62
63                         my $backward_match; my $backward_name;
64                         my $forward_match; my $forward_name;
65
66                         $backward_match = sub ($$;@) {
67                                 my $page=shift;
68                                 my $glob=shift;
69                                 return IkiWiki::PageSpec::match_backlink($page, $glob, linktype => $from, @_);
70                         };
71
72                         $backward_name = "IkiWiki::PageSpec::match_$from";
73
74                         if ($to)
75                         {
76                                 $forward_match = sub ($$;@) {
77                                         my $page=shift;
78                                         my $glob=shift;
79                                         return IkiWiki::PageSpec::match_link($page, $glob, linktype => $from, @_);
80                                 };
81
82                                 $forward_name = "IkiWiki::PageSpec::match_$to";
83                         }
84
85                         {
86                                 no strict 'refs';
87
88                                 if ($to)
89                                 {
90                                         *$forward_name = $forward_match;
91                                 }
92                                 *$backward_name = $backward_match;
93                         }
94                 } else {
95                         error gettext("Malformed option in blocks_names");
96                 }
97         }
98 }
99
100 sub preprocess_blocks ($$@) {
101         # with flip=0, the directive occurring on page A pointing at page B
102         # means that A $relation B, with flip=1, it means B $relation A
103         my $relation = shift;
104         my $flip = shift;
105
106         if (! @_) {
107                 return "";
108         }
109         my %params=@_;
110         my $page = $params{page};
111         delete $params{page};
112         delete $params{destpage};
113         delete $params{preview};
114
115         foreach my $blocks (keys %params) {
116                 $blocks=linkpage($blocks);
117                 
118                 # hidden WikiLink
119                 if ( $flip == 0 ) {
120                         add_link($page, $blocks, $relation);
121                 } else {
122                         add_link($blocks, $page, $relation);
123                 }
124         }
125                 
126         return "";
127 }
128
129 1