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 |
||||||
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__ |