summaryrefslogtreecommitdiff
path: root/IkiWiki/Plugin/map.pm
blob: 5b6a843e7ae2680d654317fc35368190c2d9d087 (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}='';
  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 keys %mapitems) {
  69. my @linktext = (length $mapitems{$item} ? (linktext => $mapitems{$item}) : ());
  70. $item=~s/^\Q$common_prefix\E\///
  71. if defined $common_prefix && length $common_prefix;
  72. my $depth = ($item =~ tr/\//\//) + 1;
  73. my $baseitem=IkiWiki::dirname($item);
  74. while (length $parent && length $baseitem && $baseitem !~ /^\Q$parent\E(\/|$)/) {
  75. $parent=IkiWiki::dirname($parent);
  76. last if !$dummy && length $parent && $baseitem =~ /^\Q$parent\E(\/|$)/;
  77. $indent--;
  78. $map .= "</li>\n";
  79. if ($indent > 0) {
  80. $map .= "</ul>\n";
  81. }
  82. }
  83. $dummy=0;
  84. while ($depth < $indent) {
  85. $indent--;
  86. $map .= "</li>\n";
  87. if ($indent > 0) {
  88. $map .= "</ul>\n";
  89. }
  90. }
  91. my @bits=split("/", $item);
  92. my $p="";
  93. $p.="/".shift(@bits) for 1..$indent;
  94. while ($depth > $indent) {
  95. $indent++;
  96. if ($indent > 1) {
  97. $map .= "<ul>\n";
  98. }
  99. if ($depth > $indent) {
  100. $dummy=1;
  101. $p.="/".shift(@bits);
  102. $map .= "<li>"
  103. .htmllink($params{page}, $params{destpage},
  104. $p, class => "mapparent",
  105. noimageinline => 1)
  106. ."\n";
  107. $openli=1;
  108. }
  109. else {
  110. $openli=0;
  111. }
  112. }
  113. $map .= "</li>\n" if $openli;
  114. $map .= "<li>"
  115. .htmllink($params{page}, $params{destpage},
  116. "/".$common_prefix."/".$item,
  117. @linktext,
  118. class => "mapitem", noimageinline => 1)
  119. ."\n";
  120. $openli=1;
  121. $parent=$item;
  122. }
  123. while ($indent > 0) {
  124. $indent--;
  125. $map .= "</li>\n</ul>\n";
  126. }
  127. $map .= "</div>\n";
  128. return $map;
  129. } # }}}
  130. 1