map: switch to use_pagespec
[ikiwiki] / IkiWiki / Plugin / map.pm
1 #!/usr/bin/perl
2 #
3 # Produce a hierarchical map of links.
4 #
5 # by Alessandro Dotti Contra <alessandro@hyboria.org>
6 #
7 # Revision: 0.2
8 package IkiWiki::Plugin::map;
9
10 use warnings;
11 use strict;
12 use IkiWiki 3.00;
13
14 sub import {
15         hook(type => "getsetup", id => "map", call => \&getsetup);
16         hook(type => "preprocess", id => "map", call => \&preprocess);
17 }
18
19 sub getsetup () {
20         return
21                 plugin => {
22                         safe => 1,
23                         rebuild => undef,
24                 },
25 }
26
27 sub preprocess (@) {
28         my %params=@_;
29         $params{pages}="*" unless defined $params{pages};
30         
31         # Needs to update whenever a page is added or removed (or in some
32         # cases, when its content changes, if show= is specified).
33         my $deptype=deptype(exists $params{show} ? "content" : "presence");
34         
35         my $common_prefix;
36
37         # Get all the items to map.
38         my %mapitems;
39         foreach my $page (use_pagespec($params{page}, $params{pages}, deptype => $deptype)) {
40                 if (exists $params{show} && 
41                     exists $pagestate{$page} &&
42                     exists $pagestate{$page}{meta}{$params{show}}) {
43                         $mapitems{$page}=$pagestate{$page}{meta}{$params{show}};
44                 }
45                 else {
46                         $mapitems{$page}='';
47                 }
48                 # Check for a common prefix.
49                 if (! defined $common_prefix) {
50                         $common_prefix=$page;
51                 }
52                 elsif (length $common_prefix &&
53                        $page !~ /^\Q$common_prefix\E(\/|$)/) {
54                         my @a=split(/\//, $page);
55                         my @b=split(/\//, $common_prefix);
56                         $common_prefix="";
57                         while (@a && @b && $a[0] eq $b[0]) {
58                                 if (length $common_prefix) {
59                                         $common_prefix.="/";
60                                 }
61                                 $common_prefix.=shift(@a);
62                                 shift @b;
63                         }
64                 }
65         }
66         
67         # Common prefix should not be a page in the map.
68         while (defined $common_prefix && length $common_prefix &&
69                exists $mapitems{$common_prefix}) {
70                 $common_prefix=IkiWiki::dirname($common_prefix);
71         }
72
73         # Create the map.
74         my $parent="";
75         my $indent=0;
76         my $openli=0;
77         my $addparent="";
78         my $map = "<div class='map'>\n";
79
80         if (! keys %mapitems) {
81                 # return empty div for empty map
82                 $map .= "</div>\n";
83                 return $map; 
84         } 
85         else {
86                 $map .= "<ul>\n";
87         }
88
89         foreach my $item (sort keys %mapitems) {
90                 my @linktext = (length $mapitems{$item} ? (linktext => $mapitems{$item}) : ());
91                 $item=~s/^\Q$common_prefix\E\///
92                         if defined $common_prefix && length $common_prefix;
93                 my $depth = ($item =~ tr/\//\//) + 1;
94                 my $baseitem=IkiWiki::dirname($item);
95                 while (length $parent && length $baseitem && $baseitem !~ /^\Q$parent\E(\/|$)/) {
96                         $parent=IkiWiki::dirname($parent);
97                         last if length $addparent && $baseitem =~ /^\Q$addparent\E(\/|$)/;
98                         $addparent="";
99                         $indent--;
100                         $map .= "</li>\n";
101                         if ($indent > 0) {
102                                 $map .= "</ul>\n";
103                         }
104                 }
105                 while ($depth < $indent) {
106                         $indent--;
107                         $map .= "</li>\n";
108                         if ($indent > 0) {
109                                 $map .= "</ul>\n";
110                         }
111                 }
112                 my @bits=split("/", $item);
113                 my $p="";
114                 $p.="/".shift(@bits) for 1..$indent;
115                 while ($depth > $indent) {
116                         $indent++;
117                         if ($indent > 1) {
118                                 $map .= "<ul>\n";
119                         }
120                         if ($depth > $indent) {
121                                 $p.="/".shift(@bits);
122                                 $addparent=$p;
123                                 $addparent=~s/^\///;
124                                 $map .= "<li>"
125                                         .htmllink($params{page}, $params{destpage},
126                                                  "/".$common_prefix.$p, class => "mapparent",
127                                                  noimageinline => 1)
128                                         ."\n";
129                                 $openli=1;
130                         }
131                         else {
132                                 $openli=0;
133                         }
134                 }
135                 $map .= "</li>\n" if $openli;
136                 $map .= "<li>"
137                         .htmllink($params{page}, $params{destpage}, 
138                                 "/".$common_prefix."/".$item,
139                                 @linktext,
140                                 class => "mapitem", noimageinline => 1)
141                         ."\n";
142                 $openli=1;
143                 $parent=$item;
144         }
145         while ($indent > 0) {
146                 $indent--;
147                 $map .= "</li>\n</ul>\n";
148         }
149         $map .= "</div>\n";
150         return $map;
151 }
152
153 1