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