File Coverage

blib/lib/HTML/LinkList.pm
Criterion Covered Total %
statement 256 281 91.1
branch 103 134 76.8
condition 44 81 54.3
subroutine 21 21 100.0
pod 18 18 100.0
total 442 535 82.6


line stmt bran cond sub pod time code
1             package HTML::LinkList;
2 6     6   139768 use strict;
  6         14  
  6         218  
3 6     6   37 use warnings;
  6         13  
  6         391  
4              
5             =head1 NAME
6              
7             HTML::LinkList - Create a 'smart' list of HTML links.
8              
9             =head1 VERSION
10              
11             This describes version B<0.1503> of HTML::LinkList.
12              
13             =cut
14              
15             our $VERSION = '0.1503';
16              
17             =head1 SYNOPSIS
18              
19             use HTML::LinkList qw(link_list);
20              
21             # default formatting
22             my $html_links = link_list(current_url=>$url,
23             urls=>\@links_in_order,
24             labels=>\%labels,
25             descriptions=>\%desc);
26              
27             # paragraph with ' :: ' separators
28             my $html_links = link_list(current_url=>$url,
29             urls=>\@links_in_order,
30             labels=>\%labels,
31             descriptions=>\%desc,
32             links_head=>'

',

33             links_foot=>'

',
34             pre_item=>'',
35             post_item=>''
36             pre_active_item=>'',
37             post_active_item=>'',
38             item_sep=>" :: ");
39              
40             # multi-level list
41             my $html_links = link_tree(
42             current_url=>$url,
43             link_tree=>\@list_of_lists,
44             labels=>\%labels,
45             descriptions=>\%desc);
46              
47              
48             =head1 DESCRIPTION
49              
50             This module contains a number of functions for taking sets of URLs and
51             labels and creating suitably formatted HTML. These links are "smart"
52             because, if given the url of the current page, if any of the links in
53             the list equal it, that item in the list will be formatted as a special
54             label, not as a link; this is a Good Thing, since the user would be
55             confused by clicking on a link back to the current page.
56              
57             While many website systems have plugins for "smart" navbars, they are
58             specialized for that system only, and can't be reused elsewhere, forcing
59             people to reinvent the wheel. I hereby present one wheel, free to be
60             reused by anybody; just the simple functions, a backend, which can be
61             plugged into whatever system you want.
62              
63             The default format for the HTML is to make an unordered list, but there
64             are many options, enabling one to have a flatter layout with any
65             separators you desire, or a more complicated list with differing
66             formats for different levels.
67              
68             The "link_list" function uses a simple list of links -- good for a
69             simple navbar.
70              
71             The "link_tree" function takes a set of nested links and makes the HTML
72             for them -- good for making a table of contents, or a more complicated
73             navbar.
74              
75             The "full_tree" function takes a list of paths and makes a full tree of
76             all the pages and index-pages in those paths -- good for making a site
77             map.
78              
79             The "breadcrumb_trail" function takes a url and makes a "breadcrumb trail"
80             from it.
81              
82             The "nav_tree" function creates a set of nested links to be
83             used as a multi-level navbar; one can give it a list of paths
84             (as for full_tree) and it will only show the links related
85             to the current URL.
86              
87             =cut
88              
89             =head1 FUNCTIONS
90              
91             To export a function, add it to the 'use' call.
92              
93             use HTML::LinkList qw(link_list);
94              
95             To export all functions do:
96              
97             use HTML::LinkList ':all';
98              
99             =cut
100              
101 6     6   6448 use Data::Dumper;
  6         63285  
  6         31531  
102             require Exporter;
103              
104             our @ISA = qw(Exporter);
105              
106              
107             # Items which are exportable.
108             #
109             # This allows declaration use HTML::LinkList ':all';
110             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
111             # will save memory.
112             our %EXPORT_TAGS = ( 'all' => [ qw(
113             link_list
114             link_tree
115             full_tree
116             breadcrumb_trail
117             nav_tree
118             ) ] );
119              
120             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
121              
122             # Items to export into callers namespace by default. Note: do not export
123             # names by default without a very good reason. Use EXPORT_OK instead.
124             # Do not simply export all your public functions/methods/constants.
125              
126             our @EXPORT = qw(
127            
128             );
129              
130             =head2 link_list
131              
132             $links = link_list(
133             current_url=>$url,
134             urls=>\@links_in_order,
135             labels=>\%labels,
136             descriptions=>\%desc,
137             pre_desc=>' ',
138             post_desc=>'',
139             links_head=>'
    ',
140             links_foot=>'',
141             pre_item=>'
  • ',
  • 142             post_item=>''
    143             pre_active_item=>'',
    144             post_active_item=>'',
    145             item_sep=>"\n");
    146              
    147             Generates a simple list of links, from list of urls
    148             (and optional labels) taking into account of the "current" URL.
    149              
    150             This provides a large number of options to customize the appearance
    151             of the list. The default setup is for a simple UL list, but setting
    152             the options can enable you to make it something other than a list
    153             altogether, or add in CSS styles or classes to make it look just
    154             like you want.
    155              
    156             Required:
    157              
    158             =over
    159              
    160             =item urls
    161              
    162             The urls in the order you want them displayed. If this list
    163             is empty, then nothing will be generated.
    164              
    165             =back
    166              
    167             Options:
    168              
    169             =over
    170              
    171             =item current_url
    172              
    173             The link to the current page. If one of the links equals this,
    174             then that is deemed to be the "active" link and is just displayed
    175             as a label rather than a link.
    176              
    177             =item descriptions
    178              
    179             Optional hash of descriptions, to put next to the links. The keys
    180             of this hash are the urls.
    181              
    182             =item hide_ext
    183              
    184             If a site is hiding link extensions (such as using MultiViews with
    185             Apache) you may wish to hide the extensions (while using the full URLs
    186             to check various things). (default: 0 (false))
    187              
    188             =item item_sep
    189              
    190             String to put between items.
    191              
    192             =item labels
    193              
    194             A hash whose keys are links and whose values are labels.
    195             These are the labels for the links; if no label
    196             is given, then the last part of the link is used
    197             for the label, with some formatting.
    198              
    199             =item links_head
    200              
    201             String to begin the list with.
    202              
    203             =item links_foot
    204              
    205             String to end the list with.
    206              
    207             =item pre_desc
    208              
    209             String to prepend to each description.
    210              
    211             =item post_desc
    212              
    213             String to append to each description.
    214              
    215             =item pre_item
    216              
    217             String to prepend to each item.
    218              
    219             =item post_item
    220              
    221             String to append to each item.
    222              
    223             =item pre_active_item
    224              
    225             An additional string to put in front of each "active" item, after pre_item.
    226             The "active" item is the link which matches 'current_url'.
    227              
    228             =item post_active_item
    229              
    230             An additional string to append to each active item, before post_item.
    231              
    232             =item prefix_url
    233              
    234             A prefix to prepend to all the links. (default: empty string)
    235              
    236             =back
    237              
    238             =cut
    239             sub link_list {
    240 3     3 1 2251 my %args = (
    241             current_url=>'',
    242             prefix_url=>'',
    243             labels=>undef,
    244             urls=>undef,
    245             links_head=>'
      ',
    246             links_foot=>"\n",
    247             pre_item=>'
  • ',
  • 248             post_item=>'',
    249             pre_active_item=>'',
    250             post_active_item=>'',
    251             pre_current_parent=>'',
    252             post_current_parent=>'',
    253             item_sep=>"\n",
    254             hide_ext=>0,
    255             @_
    256             );
    257              
    258 3         5 my @link_order = @{$args{urls}};
      3         12  
    259 3 50 33     12 if (!defined $args{urls}
      3         9  
    260             or !@{$args{urls}})
    261             {
    262 0         0 return '';
    263             }
    264 0         0 my %format = (exists $args{format}
    265 3 50       29 ? %{$args{format}}
    266             : (
    267             pre_item=>$args{pre_item},
    268             post_item=>$args{post_item},
    269             pre_active_item=>$args{pre_active_item},
    270             post_active_item=>$args{post_active_item},
    271             pre_current_parent=>$args{pre_current_parent},
    272             post_current_parent=>$args{post_current_parent},
    273             pre_desc=>$args{pre_desc},
    274             post_desc=>$args{post_desc},
    275             item_sep=>$args{item_sep},
    276             ));
    277             # correct the current_url
    278 3         9 $args{current_url} = make_canonical($args{current_url});
    279 3         17 my %current_parents = extract_current_parents(%args);
    280 3         7 my @items = ();
    281 3         4 foreach my $link (@link_order)
    282             {
    283 15 100       37 my $label = (exists $args{labels}->{$link}
    284             ? $args{labels}->{$link} : '');
    285 15         64 my $item = make_item(%args,
    286             format=>\%format,
    287             current_parents=>\%current_parents,
    288             this_link=>$link,
    289             this_label=>$label);
    290 15         58 push @items, $item;
    291             }
    292 3         10 my $list = join($format{item_sep}, @items);
    293 3 50       28 return ($list
    294             ? join('', $args{links_head}, $list, $args{links_foot})
    295             : '');
    296             } # link_list
    297              
    298             =head2 link_tree
    299              
    300             $links = link_tree(
    301             current_url=>$url,
    302             link_tree=>\@list_of_lists,
    303             labels=>\%labels,
    304             descriptions=>\%desc,
    305             pre_desc=>' ',
    306             post_desc=>'',
    307             links_head=>'
      ',
    308             links_foot=>'',
    309             subtree_head=>'
      ',
    310             subtree_foot=>'',
    311             pre_item=>'
  • ',
  • 312             post_item=>''
    313             pre_active_item=>'',
    314             post_active_item=>'',
    315             item_sep=>"\n",
    316             tree_sep=>"\n",
    317             formats=>\%formats);
    318              
    319             Generates nested lists of links from a list of lists of links.
    320             This is useful for things such as table-of-contents or
    321             site maps.
    322              
    323             By default, this will return UL lists, but this is highly
    324             configurable.
    325              
    326             Required:
    327              
    328             =over
    329              
    330             =item link_tree
    331              
    332             A list of lists of urls, in the order you want them displayed.
    333             If a url is not in this list, it will not be displayed.
    334              
    335             =back
    336              
    337             Options:
    338              
    339             =over
    340              
    341             =item current_url
    342              
    343             The link to the current page. If one of the links equals this,
    344             then that is deemed to be the "active" link and is just displayed
    345             as a label rather than a link.
    346              
    347             =item descriptions
    348              
    349             Optional hash of descriptions, to put next to the links. The keys
    350             of this hash are the urls.
    351              
    352             =item exclude_root_parent
    353              
    354             If this is true, then the "current_parent" display options are
    355             not used for the "root" ("/") path, it isn't counted as a "parent"
    356             of the current_url.
    357              
    358             =item formats
    359              
    360             A reference to a hash containing advanced format settings. For example:
    361              
    362             my %formats = (
    363             # level 1 and onwards
    364             '1' => {
    365             tree_head=>"
      ",
    366             tree_foot=>"\n",
    367             },
    368             # level 2 and onwards
    369             '2' => {
    370             tree_head=>"
      ",
    371             tree_foot=>"\n",
    372             },
    373             # level 3 and onwards
    374             '3' => {
    375             pre_item=>'(',
    376             post_item=>')',
    377             item_sep=>",\n",
    378             tree_sep=>' -> ',
    379             tree_head=>"
    \n",
    380             tree_foot=>"",
    381             }
    382             );
    383              
    384             The formats hash enables you to control the formatting on a per-level basis.
    385             Each key of the hash corresponds to a level-number; the sub-hashes contain
    386             format arguments which will apply from that level onwards. If an argument
    387             isn't given in the sub-hash, then it will fall back to the previous level
    388             (or to the default, if there is no setting for that format-argument
    389             for a previous level).
    390              
    391             The only difference between the names of the arguments in the sub-hash and
    392             in the global format arguments is that instead of 'subtree_head' and subtree_foot'
    393             it uses 'tree_head' and 'tree_foot'.
    394              
    395             =item hide_ext
    396              
    397             If a site is hiding link extensions (such as using MultiViews with
    398             Apache) you may wish to hide the extensions (while using the full URLs
    399             to check various things). (default: 0 (false))
    400              
    401             =item item_sep
    402              
    403             The string to separate each item.
    404              
    405             =item labels
    406              
    407             A hash whose keys are links and whose values are labels.
    408             These are the labels for the links; if no label
    409             is given, then the last part of the link is used
    410             for the label, with some formatting.
    411              
    412             =item links_head
    413              
    414             The string to prepend the top-level tree with.
    415             (default:
      )
    416              
    417             =item links_foot
    418              
    419             The string to append to the top-level tree.
    420             (default: )
    421              
    422             =item pre_desc
    423              
    424             String to prepend to each description.
    425              
    426             =item post_desc
    427              
    428             String to append to each description.
    429              
    430             =item pre_item
    431              
    432             String to prepend to each item.
    433             (default:
  • )
  • 434              
    435             =item post_item
    436              
    437             String to append to each item.
    438             (default: )
    439              
    440             =item pre_active_item
    441              
    442             An additional string to put in front of each "active" item, after pre_item.
    443             The "active" item is the link which matches 'current_url'.
    444             (default: )
    445              
    446             =item post_active_item
    447              
    448             An additional string to append to each active item, before post_item.
    449             (default: )
    450              
    451             =item pre_current_parent
    452              
    453             An additional string to put in front of a link which is a parent
    454             of the 'current_url' link, after pre_item.
    455              
    456             =item post_current_parent
    457              
    458             An additional string to append to a link which is a parent
    459             of the 'current_url' link, before post_item.
    460              
    461             =item prefix_url
    462              
    463             A prefix to prepend to all the links. (default: empty string)
    464              
    465             =item subtree_head
    466              
    467             The string to prepend to lower-level trees.
    468             (default:
      )
    469              
    470             =item subtree_foot
    471              
    472             The string to append to lower-level trees.
    473             (default: )
    474              
    475             =item tree_sep
    476              
    477             The string to separate each tree.
    478              
    479             =back
    480              
    481             =cut
    482             sub link_tree {
    483 3     3 1 2170 my %args = (
    484             current_url=>'',
    485             prefix_url=>'',
    486             link_tree=>undef,
    487             links_head=>'
      ',
    488             links_foot=>"\n",
    489             subtree_head=>'
      ',
    490             subtree_foot=>"\n",
    491             last_subtree_head=>'
      ',
    492             last_subtree_foot=>"\n",
    493             pre_item=>'
  • ',
  • 494             post_item=>'',
    495             pre_active_item=>'',
    496             post_active_item=>'',
    497             pre_current_parent=>'',
    498             post_current_parent=>'',
    499             item_sep=>"\n",
    500             tree_sep=>"\n",
    501             @_
    502             );
    503              
    504             # correct the current_url
    505 3         9 $args{current_url} = make_canonical($args{current_url});
    506 3         17 my %current_parents = extract_current_parents(%args);
    507              
    508 3         7 $args{tree_depth} = 0;
    509 3         4 $args{end_depth} = 0;
    510              
    511 3 50 33     11 if (defined $args{link_tree}
      3         15  
    512             and @{$args{link_tree}})
    513             {
    514 3         15 my %default_format = make_default_format(%args);
    515 3         21 my %formats = make_extra_formats(%args);
    516 3         8 my @link_tree = @{$args{link_tree}};
      3         8  
    517 3         19 my $list = traverse_lol(\@link_tree,
    518             %args,
    519             formats=>\%formats,
    520             current_format=>\%default_format,
    521             current_parents=>\%current_parents);
    522 3 50       23 return $list if $list;
    523             }
    524 0         0 return '';
    525             } # link_tree
    526              
    527             =head2 full_tree
    528              
    529             $links = full_tree(
    530             paths=>\@list_of_paths,
    531             labels=>\%labels,
    532             descriptions=>\%desc,
    533             hide=>$hide_regex,
    534             nohide=>$nohide_regex,
    535             start_depth=>0,
    536             end_depth=>0,
    537             top_level=>0,
    538             preserve_order=>0,
    539             preserve_paths=>0,
    540             ...
    541             );
    542              
    543             Given a set of paths this will generate a tree of links in the style of
    544             I. This will figure out all the intermediate paths and construct
    545             the nested structure for you, clustering parents and children together.
    546              
    547             The formatting options are as for L.
    548              
    549             Required:
    550              
    551             =over
    552              
    553             =item paths
    554              
    555             A reference to a list of paths: that is, URLs relative to the top
    556             of the site.
    557              
    558             For example, if the full URL is http://www.example.com/foo.html
    559             then the path is /foo.html
    560              
    561             If the full URL is http://www.example.com/~frednurk/foo.html
    562             then the path is /foo.html
    563              
    564             This does not require that every possible path be given; all the intermediate
    565             paths will be figured out from the list.
    566              
    567             =back
    568              
    569             Options:
    570              
    571             =over
    572              
    573             =item append_list
    574              
    575             Array of paths to append to the top-level links. They are used
    576             as-is, and are not part of the processing done to the "paths" list
    577             of paths. (see L)
    578              
    579             =item descriptions
    580              
    581             Optional hash of descriptions, to put next to the links. The keys
    582             of this hash are the paths.
    583              
    584             =item end_depth
    585              
    586             End your tree at this depth. If zero, then go all the way.
    587             (see L)
    588              
    589             =item exclude_root_parent
    590              
    591             If this is true, then the "current_parent" display options are
    592             not used for the "root" ("/") path, it isn't counted as a "parent"
    593             of the current_url.
    594              
    595             =item hide
    596              
    597             If the path matches this string, don't include it in the tree.
    598              
    599             =item hide_ext
    600              
    601             If a site is hiding link extensions (such as using MultiViews with
    602             Apache) you may wish to hide the extensions (while using the full URLs
    603             to check various things). (default: 0 (false))
    604              
    605             =item labels
    606              
    607             Hash containing replacement labels for one or more paths.
    608             If no label is given for '/' (the root path) then 'Home' will
    609             be used.
    610              
    611             =item last_subtree_head
    612              
    613             The string to prepend to the last lower-level tree.
    614             Only used if end_depth is not zero.
    615              
    616             =item last_subtree_foot
    617              
    618             The string to append to the last lower-level tree.
    619             Only used if end_depth is not zero.
    620              
    621             =item nohide
    622              
    623             If the path matches this string, it will be included even if it matches
    624             the 'hide' string.
    625              
    626             =item prefix_url
    627              
    628             A prefix to prepend to all the links. (default: empty string)
    629              
    630             =item prepend_list
    631              
    632             Array of paths to prepend to the top-level links. They are used
    633             as-is, and are not part of the processing done to the "paths" list
    634             of paths.
    635              
    636             =item preserve_order
    637              
    638             Preserve the ordering of the paths in the input list of paths;
    639             otherwise the links will be sorted alphabetically. Note that if
    640             preserve_order is true, the structure is at the whims of the order
    641             of the original list of paths, and so could end up odd-looking.
    642             (default: false)
    643              
    644             =item preserve_paths
    645              
    646             Do not extract intermediate paths or reorder the input list of paths.
    647             This speeds things up, but assumes that the input paths are complete
    648             and in good order.
    649             (default: false)
    650              
    651             =item start_depth
    652              
    653             Start your tree at this depth. Zero is the root, level 1 is the
    654             files/sub-folders in the root, and so on.
    655             (default: 0)
    656              
    657             =item top_level
    658              
    659             Decide which level is the "top" level. Useful when you
    660             set the start_depth to something greater than 1.
    661              
    662             =back
    663              
    664             =cut
    665             sub full_tree {
    666 5     5 1 4076 my %args = (
    667             paths=>undef,
    668             current_url=>'',
    669             links_head=>'
      ',
    670             links_foot=>"\n",
    671             subtree_head=>'
      ',
    672             subtree_foot=>"\n",
    673             last_subtree_head=>'
      ',
    674             last_subtree_foot=>"\n",
    675             pre_item=>'
  • ',
  • 676             post_item=>'',
    677             pre_active_item=>'',
    678             post_active_item=>'',
    679             pre_current_parent=>'',
    680             post_current_parent=>'',
    681             item_sep=>"\n",
    682             tree_sep=>"\n",
    683             hide=>'',
    684             nohide=>'',
    685             preserve_order=>0,
    686             preserve_paths=>0,
    687             labels=>{},
    688             start_depth=>0,
    689             end_depth=>0,
    690             top_level=>0,
    691             @_
    692             );
    693              
    694             # correct the current_url
    695 5         19 $args{current_url} = make_canonical($args{current_url});
    696 5         31 my %current_parents = extract_current_parents(%args);
    697              
    698             # set the root label
    699 5 100       23 if (!$args{labels}->{'/'})
    700             {
    701 1         3 $args{labels}->{'/'} = 'Home';
    702             }
    703 5         9 my @path_list = ();
    704 5 50       14 if ($args{preserve_paths})
    705             {
    706 0         0 @path_list = filter_out_paths(%args, paths=>$args{paths});
    707             }
    708             else
    709             {
    710 5         17 @path_list = extract_all_paths(paths=>$args{paths},
    711             preserve_order=>$args{preserve_order});
    712 5         36 @path_list = filter_out_paths(%args, paths=>\@path_list);
    713             }
    714 5         37 my @list_of_lists = build_lol(%args, paths=>\@path_list,
    715             depth=>0);
    716 5         14 $args{tree_depth} = 0;
    717 5         6 $args{end_depth} = 0;
    718              
    719 5         29 my %default_format = make_default_format(%args);
    720 5         38 my %formats = make_extra_formats(%args);
    721 5         35 my $list = traverse_lol(\@list_of_lists,
    722             %args,
    723             formats=>\%formats,
    724             current_format=>\%default_format,
    725             current_parents=>\%current_parents);
    726 5 50       52 return $list if $list;
    727              
    728 0         0 return '';
    729             } # full_tree
    730              
    731             =head2 breadcrumb_trail
    732              
    733             $links = breadcrumb_trail(
    734             current_url=>$url,
    735             labels=>\%labels,
    736             descriptions=>\%desc,
    737             links_head=>'

    ',

    738             links_foot=>"\n

    ",
    739             subtree_head=>'',
    740             subtree_foot=>"\n",
    741             pre_item=>'',
    742             post_item=>'',
    743             pre_active_item=>'',
    744             post_active_item=>'',
    745             item_sep=>"\n",
    746             tree_sep=>' > ',
    747             ...
    748             );
    749              
    750             Given the current url, make a breadcrumb trail from it.
    751             By default, this is laid out with '>' separators, but it can
    752             be set up to give a nested set of UL lists (as for L).
    753              
    754             The formatting options are as for L.
    755              
    756             Required:
    757              
    758             =over
    759              
    760             =item current_url
    761              
    762             The current url to be made into a breadcrumb-trail.
    763              
    764             =back
    765              
    766             Options:
    767              
    768             =over
    769              
    770             =item descriptions
    771              
    772             Optional hash of descriptions, to put next to the links. The keys
    773             of this hash are the urls.
    774              
    775             =item exclude_root_parent
    776              
    777             If this is true, then the "current_parent" display options are
    778             not used for the "root" ("/") path, it isn't counted as a "parent"
    779             of the current_url.
    780              
    781             =item hide_ext
    782              
    783             If a site is hiding link extensions (such as using MultiViews with
    784             Apache) you may wish to hide the extensions (while using the full URLs
    785             to check various things). (default: 0 (false))
    786              
    787             =item labels
    788              
    789             Hash containing replacement labels for one or more URLS.
    790             If no label is given for '/' (the root path) then 'Home' will
    791             be used.
    792              
    793             =back
    794              
    795             =cut
    796             sub breadcrumb_trail {
    797 2     2 1 1227 my %args = (
    798             current_url=>'',
    799             links_head=>'

    ',

    800             links_foot=>"\n

    ",
    801             subtree_head=>'',
    802             subtree_foot=>'',
    803             last_subtree_head=>'{',
    804             last_subtree_foot=>'}',
    805             pre_item=>'',
    806             post_item=>'',
    807             pre_active_item=>'',
    808             post_active_item=>'',
    809             pre_current_parent=>'',
    810             post_current_parent=>'',
    811             item_sep=>"\n",
    812             tree_sep=>' > ',
    813             hide=>'',
    814             nohide=>'',
    815             labels=>{},
    816             paths=>[],
    817             start_depth=>0,
    818             end_depth=>undef,
    819             top_level=>0,
    820             @_
    821             );
    822              
    823             # correct the current_url
    824 2         8 $args{current_url} = make_canonical($args{current_url});
    825              
    826             # set the root label
    827 2 100       7 if (!$args{labels}->{'/'})
    828             {
    829 1         2 $args{labels}->{'/'} = 'Home';
    830             }
    831              
    832             # make a list of paths consisting only of the current_url
    833 2         5 my @paths = ($args{current_url});
    834 2         5 my @path_list = extract_all_paths(paths=>\@paths);
    835 2         13 @path_list = filter_out_paths(%args, paths=>\@path_list);
    836 2         12 my @list_of_lists = build_lol(%args, paths=>\@path_list,
    837             depth=>0);
    838 2         5 $args{tree_depth} = 0;
    839 2         3 $args{end_depth} = 0;
    840              
    841 2         13 my %default_format = make_default_format(%args);
    842 2         12 my %formats = make_extra_formats(%args);
    843 2         12 my $list = traverse_lol(\@list_of_lists,
    844             %args,
    845             formats=>\%formats,
    846             current_format=>\%default_format,
    847             );
    848 2 50       26 return $list if $list;
    849              
    850 0         0 return '';
    851             } # breadcrumb_trail
    852              
    853             =head2 nav_tree
    854              
    855             $links = nav_tree(
    856             paths=>\@list_of_paths,
    857             labels=>\%labels,
    858             current_url=>$url,
    859             hide=>$hide_regex,
    860             nohide=>$nohide_regex,
    861             preserve_order=>1,
    862             descriptions=>\%desc,
    863             ...
    864             );
    865              
    866             This takes a list of links, and the current URL, and makes a nested navigation
    867             tree, consisting of (a) the top-level links (b) the links leading to the
    868             current URL (c) the links on the same level as the current URL,
    869             (d) the related links just above this level, depending on whether
    870             this is an index-page or a content page.
    871              
    872             Optionally one can hide links which match match the 'hide' option.
    873              
    874             The formatting options are as for L, with some additions.
    875              
    876             Required:
    877              
    878             =over
    879              
    880             =item current_url
    881              
    882             The link to the current page. If one of the links equals this, then that
    883             is deemed to be the "active" link and is just displayed as a label rather
    884             than a link. This is also used to determine which links to show and which
    885             ones to filter out.
    886              
    887             =item paths
    888              
    889             A reference to a list of paths: that is, URLs relative to the top
    890             of the site.
    891              
    892             For example, if the full URL is http://www.example.com/foo.html
    893             then the path is /foo.html
    894              
    895             This does not require that every possible path be given; all the intermediate
    896             paths will be figured out from the list.
    897              
    898             =back
    899              
    900             Options:
    901              
    902             =over
    903              
    904             =item append_list
    905              
    906             Array of paths to append to the top-level links. They are used
    907             as-is, and are not part of the processing done to the "paths" list
    908             of paths. (see L)
    909              
    910             =item descriptions
    911              
    912             Optional hash of descriptions, to put next to the links. The keys
    913             of this hash are the paths.
    914              
    915             =item end_depth
    916              
    917             End your tree at this depth. If zero, then go all the way.
    918             By default this is set to the depth of the current_url.
    919              
    920             =item exclude_root_parent
    921              
    922             If this is true, then the "current_parent" display options are
    923             not used for the "root" ("/") path, it isn't counted as a "parent"
    924             of the current_url.
    925              
    926             =item hide
    927              
    928             If a path matches this string, don't include it in the tree.
    929              
    930             =item hide_ext
    931              
    932             If a site is hiding link extensions (such as using MultiViews with
    933             Apache) you may wish to hide the extensions (while using the full URLs
    934             to check various things). (default: 0 (false))
    935              
    936             =item labels
    937              
    938             Hash containing replacement labels for one or more paths.
    939             If no label is given for '/' (the root path) then 'Home' will
    940             be used.
    941              
    942             =item last_subtree_head
    943              
    944             The string to prepend to the last lower-level tree.
    945              
    946             =item last_subtree_foot
    947              
    948             The string to append to the last lower-level tree.
    949              
    950             =item nohide
    951              
    952             If the path matches this string, it will be included even if it matches
    953             the 'hide' string.
    954              
    955             =item prefix_url
    956              
    957             A prefix to prepend to all the links. (default: empty string)
    958              
    959             =item prepend_list
    960              
    961             Array of paths to prepend to the top-level links. They are used
    962             as-is, and are not part of the processing done to the "paths" list
    963             of paths.
    964              
    965             =item preserve_order
    966              
    967             Preserve the ordering of the paths in the input list of paths;
    968             otherwise the links will be sorted alphabetically.
    969             (default: true)
    970              
    971             =item preserve_paths
    972              
    973             Do not extract intermediate paths or reorder the input list of paths.
    974             This speeds things up, but assumes that the input paths are complete
    975             and in good order.
    976             (default: false)
    977              
    978             =item start_depth
    979              
    980             Start your tree at this depth. Zero is the root, level 1 is the
    981             files/sub-folders in the root, and so on.
    982             (default: 1)
    983              
    984             =item top_level
    985              
    986             Decide which level is the "top" level. Useful when you
    987             set the start_depth to something greater than 1.
    988              
    989             =back
    990              
    991             =cut
    992             sub nav_tree {
    993 11     11 1 10753 my %args = (
    994             paths=>undef,
    995             current_url=>'',
    996             links_head=>'
      ',
    997             links_foot=>"\n",
    998             subtree_head=>'
      ',
    999             subtree_foot=>"\n",
    1000             last_subtree_head=>'
      ',
    1001             last_subtree_foot=>"\n",
    1002             pre_item=>'
  • ',
  • 1003             post_item=>'',
    1004             pre_active_item=>'',
    1005             post_active_item=>'',
    1006             pre_current_parent=>'',
    1007             post_current_parent=>'',
    1008             item_sep=>"\n",
    1009             tree_sep=>"\n",
    1010             hide=>'',
    1011             nohide=>'',
    1012             preserve_order=>1,
    1013             preserve_paths=>0,
    1014             include_home=>0,
    1015             labels=>{},
    1016             start_depth=>1,
    1017             end_depth=>undef,
    1018             top_level=>1,
    1019             navbar_type=>'normal',
    1020             @_
    1021             );
    1022              
    1023             # correct the current_url
    1024 11         35 $args{current_url} = make_canonical($args{current_url});
    1025 11         27 my $current_is_index = ($args{current_url} =~ m#/$#);
    1026 11         67 my %current_parents = extract_current_parents(%args);
    1027              
    1028             # set the end depth if isn't already set
    1029             # if this is an index-page, then make the depth its depth + 1
    1030             # if this is a content-page, make the depth its depth
    1031 11         41 my $current_url_depth = path_depth($args{current_url});
    1032 11 100       52 $args{end_depth} = ($current_is_index
        50          
    1033             ? $current_url_depth + 1 : $current_url_depth)
    1034             if (!defined $args{end_depth});
    1035              
    1036             # set the root label
    1037 11 100       25 if (!$args{labels}->{'/'})
    1038             {
    1039 1         2 $args{labels}->{'/'} = 'Home';
    1040             }
    1041 11         14 my @path_list = ();
    1042 11 50       20 if ($args{preserve_paths})
    1043             {
    1044 0         0 @path_list = filter_out_paths(%args, paths=>$args{paths});
    1045             }
    1046             else
    1047             {
    1048 11         27 @path_list = extract_all_paths(paths=>$args{paths},
    1049             preserve_order=>$args{preserve_order});
    1050 11         85 @path_list = filter_out_paths(%args, paths=>\@path_list);
    1051             }
    1052 11         87 my @list_of_lists = build_lol(%args, paths=>\@path_list,
    1053             depth=>0);
    1054 11         40 $args{tree_depth} = 0;
    1055              
    1056 11         62 my %default_format = make_default_format(%args);
    1057 11         90 my %formats = make_extra_formats(%args);
    1058 11         82 my $list = traverse_lol(\@list_of_lists,
    1059             %args,
    1060             formats=>\%formats,
    1061             current_format=>\%default_format,
    1062             current_parents=>\%current_parents);
    1063 11 50       149 return $list if $list;
    1064              
    1065 0         0 return '';
    1066             } # nav_tree
    1067              
    1068             =head1 Private Functions
    1069              
    1070             These functions cannot be exported.
    1071              
    1072             =head2 make_item
    1073              
    1074             $item = make_item(
    1075             this_label=>$label,
    1076             this_link=>$link,
    1077             hide_ext=>0,
    1078             current_url=>$url,
    1079             current_parents=>\%current_parents,
    1080             descriptions=>\%desc,
    1081             format=>\%format,
    1082             );
    1083              
    1084             %format = (
    1085             pre_desc=>' ',
    1086             post_desc=>'',
    1087             pre_item=>'
  • ',
  • 1088             post_item=>''
    1089             pre_active_item=>'',
    1090             post_active_item=>'',
    1091             pre_current_parent=>'',
    1092             post_current_parent=>'',
    1093             item_sep=>"\n");
    1094             );
    1095              
    1096             Format a link item.
    1097              
    1098             See L for the formatting options.
    1099              
    1100             =over
    1101              
    1102             =item this_label
    1103              
    1104             The label of the required link. If there is no label,
    1105             this uses the base-name of the last part of the link,
    1106             capitalizing it and replacing underscores and dashes with spaces.
    1107              
    1108             =item this_link
    1109              
    1110             The URL of the required link.
    1111              
    1112             =item current_url
    1113              
    1114             The link to the current page. If one of the links equals this,
    1115             then that is deemed to be the "active" link and is just displayed
    1116             as a label rather than a link.
    1117              
    1118             =item current_parents
    1119              
    1120             URLs of the parents of the current item.
    1121              
    1122             =item descriptions
    1123              
    1124             Optional hash of descriptions, to put next to the links. The keys
    1125             of this hash are the links (not the labels).
    1126              
    1127             =item defer_post_item
    1128              
    1129             Don't add the 'post_item' string if this is true.
    1130             (needed for nested lists)
    1131             (default: false)
    1132              
    1133             =item no_link
    1134              
    1135             Don't make a link for this, just a label.
    1136              
    1137             =back
    1138              
    1139             =cut
    1140             sub make_item {
    1141 153     153 1 1716 my %args = (
    1142             this_link=>'',
    1143             this_label=>'',
    1144             hide_ext=>0,
    1145             current_url=>'',
    1146             current_parents=>{},
    1147             prefix_url=>'',
    1148             defer_post_item=>0,
    1149             no_link=>0,
    1150             @_
    1151             );
    1152 153         262 my $link = $args{this_link};
    1153 153         171 my $prefix_url = $args{prefix_url};
    1154 153         179 my $label = $args{this_label};
    1155 153         146 my %format = %{$args{format}};
      153         770  
    1156              
    1157 153 100       366 if (!$label)
    1158             {
    1159 118 50       261 $label = $link if !$label;
    1160 118 100       567 if ($link =~ /([-\w]+)\.\w+$/) # file
        50          
    1161             {
    1162 31         64 $label = $1;
    1163             }
    1164             elsif ($link =~ /([-\w]+)\/?$/) # dir
    1165             {
    1166 87         179 $label = $1;
    1167             }
    1168             else # give up
    1169             {
    1170 0         0 $label = $link;
    1171 0         0 $label =~ s#/# :: #g;
    1172             }
    1173            
    1174             # prettify
    1175 118         188 $label =~ s#_# #g;
    1176 118         128 $label =~ s#-# #g;
    1177 118         550 $label =~ s/([-\w]+)/\u\L$1/g;
    1178             }
    1179             # if we are hiding the extensions of files
    1180             # we need to display an extensionless link
    1181             # while doing checks with the original link
    1182 153         212 my $display_link = $link;
    1183 153 50       295 if ($args{hide_ext})
    1184             {
    1185 0 0       0 if ($link =~ /(.*)\.[-\w]+$/) # file
    1186             {
    1187 0         0 $display_link = $1;
    1188             }
    1189             }
    1190 153         153 my $item = '';
    1191 153         153 my $desc = '';
    1192 153 0 33     482 if (exists $args{descriptions}->{$link}
          33        
    1193             and defined $args{descriptions}->{$link}
    1194             and $args{descriptions}->{$link})
    1195             {
    1196 0         0 $desc = join('', $format{pre_desc},
    1197             $args{descriptions}->{$link},
    1198             $format{post_desc});
    1199             }
    1200 153 100 100     287 if (link_is_active(this_link=>$link,
        50 66        
        100          
    1201             current_url=>$args{current_url}))
    1202             {
    1203 13         38 $item = join('', $format{pre_item},
    1204             $format{pre_active_item},
    1205             $label,
    1206             $format{post_active_item},
    1207             $desc,
    1208             );
    1209             }
    1210             elsif ($args{no_link})
    1211             {
    1212 0         0 $item = join('', $format{pre_item},
    1213             $label,
    1214             $desc);
    1215             }
    1216             elsif ($args{current_url}
    1217             and exists $args{current_parents}->{$link}
    1218             and $args{current_parents}->{$link})
    1219             {
    1220 7         25 $item = join('', $format{pre_item},
    1221             $format{pre_current_parent},
    1222             '',
    1223             $label, '',
    1224             $format{post_current_parent},
    1225             $desc);
    1226             }
    1227             else
    1228             {
    1229 133         323 $item = join('', $format{pre_item},
    1230             '',
    1231             $label, '',
    1232             $desc);
    1233             }
    1234 153 100       290 if (!$args{defer_post_item})
    1235             {
    1236 15         30 $item = join('', $item, $format{post_item});
    1237             }
    1238 153         967 return $item;
    1239             } # make_item
    1240              
    1241             =head2 make_canonical
    1242              
    1243             my $new_url = make_canonical($url);
    1244              
    1245             Make a URL canonical; remove the 'index.*' and add on a needed
    1246             '/' -- this assumes that directory names never have a '.' in them.
    1247              
    1248             =cut
    1249             sub make_canonical {
    1250 607     607 1 658 my $url = shift;
    1251              
    1252 607 100       1027 return $url if (!$url);
    1253 597 100       2714 if ($url =~ m#^(/)index\.\w+$#)
        50          
        50          
    1254             {
    1255 1         3 $url = $1;
    1256             }
    1257             elsif ($url =~ m#^(.*/)index\.\w+$#)
    1258             {
    1259 0         0 $url = $1;
    1260             }
    1261             elsif ($url =~ m#/[-\w]+$#) # no dots; a directory
    1262             {
    1263 0         0 $url .= '/'; # add the slash
    1264             }
    1265 597         899 return $url;
    1266             } # make_canonical
    1267            
    1268             =head2 get_index_path
    1269              
    1270             my $new_url = get_index_path($url);
    1271              
    1272             Get the "index" part of this path. That is, if this path
    1273             is not for an index-page, then get the parent index-page
    1274             path for this path.
    1275             (Removes the trailing slash).
    1276              
    1277             =cut
    1278             sub get_index_path {
    1279 31     31 1 48 my $url = shift;
    1280              
    1281 31 100       63 return $url if (!$url);
    1282 26         58 $url = make_canonical($url);
    1283 26 100       118 if ($url =~ m#^(.*)/[-\w]+\.\w+$#)
        100          
    1284             {
    1285 8         18 $url = $1;
    1286             }
    1287             elsif ($url ne '/')
    1288             {
    1289 16         75 $url =~ s#/$##;
    1290             }
    1291 26         48 return $url;
    1292             } # get_index_path
    1293              
    1294             =head2 get_index_parent
    1295              
    1296             my $new_url = get_index_parent($url);
    1297              
    1298             Get the parent of the "index" part of this path.
    1299             (Removes the trailing slash).
    1300              
    1301             =cut
    1302             sub get_index_parent {
    1303 18     18 1 25 my $url = shift;
    1304              
    1305 18 100       42 return $url if (!$url);
    1306 13         19 $url = get_index_path($url);
    1307 13 100       50 if ($url =~ m#^(.*)/[-\w]+$#)
    1308             {
    1309 12         24 $url = $1;
    1310             }
    1311 13         22 return $url;
    1312             } # get_index_parent
    1313            
    1314             =head2 path_depth
    1315              
    1316             my $depth = path_depth($url);
    1317              
    1318             Calculate the "depth" of the given path.
    1319              
    1320             =cut
    1321             sub path_depth {
    1322 451     451 1 569 my $url = shift;
    1323              
    1324 451 100       795 return 0 if ($url eq '/'); # root is zero
    1325 426         772 $url =~ s#/$##; # remove trailing /
    1326 426         984 $url =~ s#^/##; # remove leading /
    1327 426         935 my @url = split('/', $url);
    1328 426         810 return scalar @url;
    1329             } # path_depth
    1330            
    1331             =head2 link_is_active
    1332              
    1333             if (link_is_active(this_link=>$link, current_url=>$url))
    1334             ...
    1335              
    1336             Check if the given link is "active", that is, if it
    1337             matches the 'current_url'.
    1338              
    1339             =cut
    1340             sub link_is_active {
    1341 153     153 1 434 my %args = (
    1342             this_link=>'',
    1343             current_url=>'',
    1344             @_
    1345             );
    1346 153         291 my $link = make_canonical($args{this_link});
    1347 153         226 my $current_url = $args{current_url};
    1348              
    1349             # if there is no current link, is not active.
    1350 153 100       504 return 0 if (!$current_url);
    1351              
    1352 88 100       179 return 1 if ($link eq $current_url);
    1353 75         528 return 0;
    1354              
    1355             } # link_is_active
    1356              
    1357             =head2 traverse_lol
    1358              
    1359             $links = traverse_lol(\@list_of_lists,
    1360             labels=>\%labels,
    1361             tree_depth=>$depth
    1362             current_format=>\%format,
    1363             ...
    1364             );
    1365              
    1366             Traverse the list of lists (of urls) to produce
    1367             a nested collection of links.
    1368              
    1369             This consumes the list_of_lists!
    1370              
    1371             =cut
    1372             sub traverse_lol {
    1373 72     72 1 95 my $lol_ref = shift;
    1374 72         728 my %args = (
    1375             current_url=>'',
    1376             labels=>undef,
    1377             prefix_url=>'',
    1378             hide_ext=>0,
    1379             @_
    1380             );
    1381              
    1382 72         92 my $tree_depth = $args{tree_depth};
    1383 72         548 my %format = (
    1384 8         44 %{$args{current_format}},
    1385             (exists $args{formats}->{$tree_depth}
    1386 72 100       71 ? %{$args{formats}->{$tree_depth}}
    1387             : ())
    1388             );
    1389 72         144 my @items = ();
    1390 72         68 while (@{$lol_ref})
      212         441  
    1391             {
    1392 153         150 my $ll = shift @{$lol_ref};
      153         216  
    1393 153 100       296 if (!ref $ll) # an item
    1394             {
    1395 138         148 my $link = $ll;
    1396 138 100       272 my $label = (exists $args{labels}->{$link}
    1397             ? $args{labels}->{$link} : '');
    1398 138         816 my $item = make_item(this_link=>$link,
    1399             this_label=>$label,
    1400             defer_post_item=>1,
    1401             %args,
    1402             format=>\%format);
    1403              
    1404 138 100       483 if (ref $lol_ref->[0]) # next one is a list
    1405             {
    1406 36         35 $ll = shift @{$lol_ref};
      36         59  
    1407 36         252 my $sublist = traverse_lol($ll, %args,
    1408             tree_depth=>$tree_depth + 1,
    1409             current_format=>\%format);
    1410 36         143 $item = join($format{tree_sep}, $item, $sublist);
    1411             }
    1412 138         275 $item = join('', $item, $format{post_item});
    1413 138         253 push @items, $item;
    1414             }
    1415             else # a reference to a list
    1416             {
    1417 15 100 66     74 if (defined $args{start_depth}
    1418             && $args{tree_depth} < $args{start_depth})
    1419             {
    1420 13         141 return traverse_lol($ll, %args, current_format=>\%format);
    1421             }
    1422             else
    1423             {
    1424 2         10 my $sublist = traverse_lol($ll, %args,
    1425             tree_depth=>$tree_depth + 1,
    1426             current_format=>\%format);
    1427 2         6 my $item = join($format{tree_sep}, $format{pre_item}, $sublist);
    1428 2         5 $item = join('', $item, $format{post_item});
    1429 2         3 push @items, $item;
    1430             }
    1431             }
    1432             }
    1433 59         132 my $list = join($format{item_sep}, @items);
    1434 59 50 66     793 return join('',
        50 66        
    1435             (($args{end_depth} && $tree_depth == $args{end_depth} )
    1436             ? $args{last_subtree_head}
    1437             : $format{tree_head}),
    1438             $list,
    1439             (($args{end_depth} && $tree_depth == $args{end_depth} )
    1440             ? $args{last_subtree_foot}
    1441             : $format{tree_foot})
    1442             );
    1443             } # traverse_lol
    1444              
    1445             =head2 extract_all_paths
    1446              
    1447             my @all_paths = extract_all_paths(paths=>\@paths,
    1448             preserve_order=>0);
    1449              
    1450             Extract all possible paths out of a list of paths.
    1451             Thus, if one has
    1452              
    1453             /foo/bar/baz.html
    1454              
    1455             then that would make
    1456              
    1457             /
    1458             /foo/
    1459             /foo/bar/
    1460             /foo/bar/baz.html
    1461              
    1462             If 'preserve_order' is true, this preserves the ordering of
    1463             the paths in the input list; otherwise the output paths
    1464             are sorted alphabetically.
    1465              
    1466             =cut
    1467             sub extract_all_paths {
    1468 18     18 1 57 my %args = (
    1469             paths=>undef,
    1470             preserve_order=>0,
    1471             @_
    1472             );
    1473            
    1474 18         26 my %paths = ();
    1475             # keep track of the order of the paths in the list of paths
    1476 18         20 my $order = 1;
    1477 18         19 foreach my $path (@{$args{paths}})
      18         37  
    1478             {
    1479 151         379 my @path_split = split('/', $path);
    1480             # first path as-is
    1481 151         270 $paths{$path} = $order;
    1482 151         219 pop @path_split;
    1483 151         299 while (@path_split)
    1484             {
    1485             # these paths are index-pages. should end in '/'
    1486 305         454 my $newpath = join('/', @path_split, '');
    1487             # give this path the same order-num as the full path
    1488             # but only if it hasn't already been added
    1489 305 100       608 $paths{$newpath} = $order if (!exists $paths{$newpath});
    1490 305         562 pop @path_split;
    1491             }
    1492 151 100       341 $order++ if ($args{preserve_order});
    1493             }
    1494 579 100       1240 return sort {
    1495 18         109 return $a cmp $b if ($paths{$a} == $paths{$b});
    1496 446         635 return $paths{$a} <=> $paths{$b};
    1497             } keys %paths;
    1498             } # extract_all_paths
    1499              
    1500             =head2 extract_current_parents
    1501              
    1502             my %current_parents = extract_current_parents(current_url=>$url,
    1503             exclude_root_parent=>0);
    1504              
    1505             Extract the "parent" paths of the current url
    1506              
    1507             /foo/bar/baz.html
    1508              
    1509             then that would make
    1510              
    1511             /
    1512             /foo/
    1513             /foo/bar/
    1514              
    1515             If 'exclude_root_parent' is true, then the '/' is excluded from the
    1516             list of parents.
    1517              
    1518             =cut
    1519             sub extract_current_parents {
    1520 22     22 1 206 my %args = (
    1521             current_url=>undef,
    1522             exclude_root_parent=>0,
    1523             @_
    1524             );
    1525            
    1526 22         40 my %paths = ();
    1527 22 100       58 if ($args{current_url})
    1528             {
    1529 12         18 my $current_url = $args{current_url};
    1530 12         40 my @path_split = split('/', $current_url);
    1531 12         20 pop @path_split; # remove the current url
    1532 12         26 while (@path_split)
    1533             {
    1534             # these paths are index-pages. should end in '/'
    1535 19         43 my $newpath = join('/', @path_split, '');
    1536 19         24 $paths{$newpath} = 1;
    1537 19         44 pop @path_split;
    1538             }
    1539 12 100       30 if ($args{exclude_root_parent})
    1540             {
    1541 1         3 delete $paths{"/"};
    1542             }
    1543             }
    1544              
    1545 22         122 return %paths;
    1546             } # extract_current_parents
    1547              
    1548             =head2 build_lol
    1549              
    1550             my @lol = build_lol(
    1551             paths=>\@paths,
    1552             current_url=>$url,
    1553             navbar_type=>'',
    1554             );
    1555              
    1556             Build a list of lists of paths, given a simple list of paths.
    1557             Assumes that this list has already been filtered.
    1558              
    1559             =over
    1560              
    1561             =item paths
    1562              
    1563             Reference to list of paths; this is consumed.
    1564              
    1565             =back
    1566              
    1567             =cut
    1568             sub build_lol {
    1569 64     64 1 755 my %args = (
    1570             paths=>undef,
    1571             depth=>0,
    1572             start_depth=>0,
    1573             end_depth=>0,
    1574             current_url=>'',
    1575             navbar_type=>'',
    1576             prepend_list=>undef,
    1577             append_list=>undef,
    1578             @_
    1579             );
    1580 64         92 my $paths_ref = $args{paths};
    1581 64         88 my $depth = $args{depth};
    1582              
    1583 64         77 my @list_of_lists = ();
    1584 64         72 while (@{$paths_ref})
      233         474  
    1585             {
    1586 189         242 my $path = $paths_ref->[0];
    1587 189         291 my $can_path = make_canonical($path);
    1588 189         348 my $path_depth = path_depth($can_path);
    1589 189         377 my $path_is_index = ($can_path =~ m#/$#);
    1590 189 100       358 if ($path_depth == $depth)
        100          
        50          
    1591             {
    1592 123         101 shift @{$paths_ref}; # use this path
      123         162  
    1593 123         221 push @list_of_lists, $path;
    1594             }
    1595             elsif ($path_depth > $depth)
    1596             {
    1597 46         340 push @list_of_lists, [build_lol(
    1598             %args,
    1599             prepend_list=>undef,
    1600             append_list=>undef,
    1601             paths=>$paths_ref,
    1602             depth=>$path_depth,
    1603             navbar_type=>$args{navbar_type},
    1604             current_url=>$args{current_url},
    1605             )];
    1606             }
    1607             elsif ($path_depth < $depth)
    1608             {
    1609 20         159 return @list_of_lists;
    1610             }
    1611             }
    1612             # prepend the given list to the top level
    1613 44 100 66     107 if (defined $args{prepend_list} and @{$args{prepend_list}})
      2         8  
    1614             {
    1615             # if the list of lists is a single item which is a list
    1616             # then add the extra list to that item
    1617 2 50 33     18 if ($#list_of_lists == 0
    1618             and ref($list_of_lists[0]) eq "ARRAY")
    1619             {
    1620 2         4 unshift @{$list_of_lists[0]}, @{$args{prepend_list}};
      2         3  
      2         6  
    1621             }
    1622             else
    1623             {
    1624 0         0 unshift @list_of_lists, @{$args{prepend_list}};
      0         0  
    1625             }
    1626             }
    1627             # append the given list to the top level
    1628 44 50 33     102 if (defined $args{append_list} and @{$args{append_list}})
      0         0  
    1629             {
    1630             # if the list of lists is a single item which is a list
    1631             # then add the extra list to that item
    1632 0 0 0     0 if ($#list_of_lists == 0
    1633             and ref($list_of_lists[0]) eq "ARRAY")
    1634             {
    1635 0         0 push @{$list_of_lists[0]}, @{$args{append_list}};
      0         0  
      0         0  
    1636             }
    1637             else
    1638             {
    1639 0         0 push @list_of_lists, @{$args{append_list}};
      0         0  
    1640             }
    1641             }
    1642 44         316 return @list_of_lists;
    1643             } # build_lol
    1644              
    1645             =head2 filter_out_paths
    1646              
    1647             my @filtered_paths = filter_out_paths(
    1648             paths=>\@paths,
    1649             current_url=>$url,
    1650             hide=>$hide,
    1651             nohide=>$nohide,
    1652             start_depth=>$start_depth,
    1653             end_depth=>$end_depth,
    1654             top_level=>$top_level,
    1655             navbar_type=>'',
    1656             );
    1657              
    1658             Filter out the paths we don't want from our list of paths.
    1659             Returns a list of the paths we want.
    1660              
    1661             =cut
    1662             sub filter_out_paths {
    1663 18     18 1 219 my %args = (
    1664             paths=>undef,
    1665             start_depth=>0,
    1666             end_depth=>0,
    1667             top_level=>0,
    1668             current_url=>'',
    1669             navbar_type=>'',
    1670             hide=>'',
    1671             nohide=>'',
    1672             @_
    1673             );
    1674 18         31 my $paths_ref = $args{paths};
    1675 18         23 my $hide = $args{hide};
    1676 18         28 my $nohide = $args{nohide};
    1677 18         53 my $current_url_depth = path_depth($args{current_url});
    1678 18         68 my $current_url_is_index = ($args{current_url} =~ m#/$#);
    1679             # the current-url dir is the current url without the filename
    1680 18         42 my $current_index_path = get_index_path($args{current_url});
    1681 18         32 my $current_index_path_depth = path_depth($current_index_path);
    1682 18         40 my $current_index_parent = get_index_parent($args{current_url});
    1683              
    1684 18         28 my @wantedpaths = ();
    1685 18         20 foreach my $path (@{$paths_ref})
      18         36  
    1686             {
    1687 215         368 my $can_path = make_canonical($path);
    1688 215         333 my $path_depth = path_depth($can_path);
    1689 215         398 my $path_is_index = ($can_path =~ m#/$#);
    1690 215 50 33     4948 if ($hide and $nohide
        50 33        
        100 0        
        100 33        
        100 33        
        100 100        
          66        
          66        
          100        
          66        
          66        
          66        
          100        
    1691             and not($path =~ /$nohide/)
    1692             and $path =~ /$hide/)
    1693             {
    1694             # skip this one
    1695             }
    1696             elsif ($hide and !$nohide and $path =~ /$hide/)
    1697             {
    1698             # skip this one
    1699             }
    1700             elsif ($path_depth < $args{start_depth})
    1701             {
    1702             # skip this one
    1703             }
    1704             elsif ($args{end_depth}
    1705             and $path_depth > $args{end_depth})
    1706             {
    1707             # skip this one
    1708             }
    1709             # a breadcrumb-navbar shows the parent, self,
    1710             # and the children of dirs or siblings of non-dirs
    1711             elsif ($args{navbar_type} eq 'breadcrumb'
    1712             and $args{current_url}
    1713             and !(
    1714             ($path_depth <= $current_url_depth
    1715             and $args{current_url} =~ /^$path/)
    1716             or (
    1717             $path eq $args{current_url}
    1718             )
    1719             or (
    1720             $current_url_is_index
    1721             and $path_depth >= $current_url_depth
    1722             and $path =~ /^$current_index_path\//
    1723             )
    1724             or (
    1725             !$current_url_is_index
    1726             and $path_depth >= $current_url_depth
    1727             and $path =~ /^$current_index_parent\//
    1728             )
    1729             )
    1730             )
    1731             {
    1732             # skip this one
    1733             }
    1734             # a navbar shows the parent, the children
    1735             # and the current level
    1736             # and the top level (if we are starting at $top_level)
    1737             # and the siblings of one's parent if one is a contents-page
    1738             # or siblings of oneself if one is an index-page
    1739             elsif (($args{navbar_type}
    1740             or $args{do_navbar}) # backwards compatibility
    1741             and $args{current_url}
    1742             and !(
    1743             ($path_depth <= $current_url_depth
    1744             and $args{current_url} =~ /^$path/)
    1745             or (
    1746             $path eq $args{current_url}
    1747             )
    1748             or (
    1749             $path_depth >= $current_url_depth
    1750             and $path =~ /^$current_index_path\//
    1751             )
    1752             or (
    1753             $args{start_depth} == $args{top_level}
    1754             and $path_depth == $args{start_depth}
    1755             )
    1756             or (
    1757             !$current_url_is_index
    1758             and $path_depth == $current_url_depth - 1
    1759             and $path =~ /^$current_index_parent\//
    1760             )
    1761             or (
    1762             $current_url_is_index
    1763             and $path_depth == $current_url_depth
    1764             and $path =~ /^$current_index_parent\//
    1765             )
    1766             )
    1767             )
    1768             {
    1769             # skip this one
    1770             }
    1771             else
    1772             {
    1773             # keep this path
    1774 123         287 push @wantedpaths, $path;
    1775             }
    1776             }
    1777 18         147 return @wantedpaths;
    1778             } # filter_out_paths
    1779              
    1780             =head2 make_default_format
    1781              
    1782             my %default_format = make_default_format(%args);
    1783              
    1784             Make the default format hash from the args.
    1785             Returns a hash of format options.
    1786              
    1787             =cut
    1788             sub make_default_format {
    1789 21     21 1 267 my %args = (
    1790             links_head=>'
      ',
    1791             links_foot=>"\n",
    1792             subtree_head=>'
      ',
    1793             subtree_foot=>"\n",
    1794             last_subtree_head=>'
      ',
    1795             last_subtree_foot=>"\n",
    1796             pre_item=>'
  • ',
  • 1797             post_item=>'',
    1798             pre_active_item=>'',
    1799             post_active_item=>'',
    1800             pre_current_parent=>'',
    1801             post_current_parent=>'',
    1802             item_sep=>"\n",
    1803             tree_sep=>"\n",
    1804             @_
    1805             );
    1806 21         151 my %default_format = (
    1807             pre_item=>$args{pre_item},
    1808             post_item=>$args{post_item},
    1809             pre_active_item=>$args{pre_active_item},
    1810             post_active_item=>$args{post_active_item},
    1811             pre_current_parent=>$args{pre_current_parent},
    1812             post_current_parent=>$args{post_current_parent},
    1813             pre_desc=>$args{pre_desc},
    1814             post_desc=>$args{post_desc},
    1815             item_sep=>$args{item_sep},
    1816             tree_sep=>$args{tree_sep},
    1817             tree_head=>$args{links_head},
    1818             tree_foot=>$args{links_foot},
    1819             );
    1820 21         215 return %default_format;
    1821             } # make_default_format
    1822              
    1823             =head2 make_extra_formats
    1824              
    1825             my %formats = make_extra_formats(%args);
    1826              
    1827             Transforms the subtree_head and subtree_foot into the "formats"
    1828             method of formatting.
    1829             Returns a hash of hashes of format options.
    1830              
    1831             =cut
    1832             sub make_extra_formats {
    1833 21     21 1 243 my %args = (
    1834             formats=>undef,
    1835             links_head=>'
      ',
    1836             links_foot=>"\n",
    1837             subtree_head=>'
      ',
    1838             subtree_foot=>"\n",
    1839             last_subtree_head=>'
      ',
    1840             last_subtree_foot=>"\n",
    1841             pre_item=>'
  • ',
  • 1842             post_item=>'',
    1843             pre_active_item=>'',
    1844             post_active_item=>'',
    1845             pre_current_parent=>'',
    1846             post_current_parent=>'',
    1847             item_sep=>"\n",
    1848             tree_sep=>"\n",
    1849             @_
    1850             );
    1851 21         36 my %formats = ();
    1852 21 100       52 if (defined $args{formats})
    1853             {
    1854 2         3 %formats = %{$args{formats}};
      2         8  
    1855             }
    1856 21 100 66     119 if ($args{links_head} ne $args{subtree_head}
    1857             || $args{links_foot} ne $args{subtree_foot})
    1858             {
    1859 2 50       5 if (!exists $formats{1})
    1860             {
    1861 2         4 $formats{1} = {};
    1862             }
    1863 2         4 $formats{1}->{tree_head} = $args{subtree_head};
    1864 2         3 $formats{1}->{tree_foot} = $args{subtree_foot};
    1865             }
    1866 21         94 return %formats;
    1867             } # make_extra_formats
    1868              
    1869             =head1 REQUIRES
    1870              
    1871             Test::More
    1872              
    1873             =head1 INSTALLATION
    1874              
    1875             To install this module, run the following commands:
    1876              
    1877             perl Build.PL
    1878             ./Build
    1879             ./Build test
    1880             ./Build install
    1881              
    1882             Or, if you're on a platform (like DOS or Windows) that doesn't like the
    1883             "./" notation, you can do this:
    1884              
    1885             perl Build.PL
    1886             perl Build
    1887             perl Build test
    1888             perl Build install
    1889              
    1890             In order to install somewhere other than the default, such as
    1891             in a directory under your home directory, like "/home/fred/perl"
    1892             go
    1893              
    1894             perl Build.PL --install_base /home/fred/perl
    1895              
    1896             as the first step instead.
    1897              
    1898             This will install the files underneath /home/fred/perl.
    1899              
    1900             You will then need to make sure that you alter the PERL5LIB variable to
    1901             find the modules.
    1902              
    1903             Therefore you will need to change the PERL5LIB variable to add
    1904             /home/fred/perl/lib
    1905              
    1906             PERL5LIB=/home/fred/perl/lib:${PERL5LIB}
    1907              
    1908             =head1 SEE ALSO
    1909              
    1910             perl(1).
    1911              
    1912             =head1 BUGS
    1913              
    1914             Please report any bugs or feature requests to the author.
    1915              
    1916             =head1 AUTHOR
    1917              
    1918             Kathryn Andersen (RUBYKAT)
    1919             perlkat AT katspace dot com
    1920             http://www.katspace.com/tools/html_linklist/
    1921              
    1922             =head1 COPYRIGHT AND LICENCE
    1923              
    1924             Copyright (c) 2006 by Kathryn Andersen
    1925              
    1926             This program is free software; you can redistribute it and/or modify it
    1927             under the same terms as Perl itself.
    1928              
    1929             =cut
    1930              
    1931             1; # End of HTML::LinkList
    1932             __END__