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