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