blib/lib/HTML/LinkList.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 281 | 307 | 91.5 |
branch | 134 | 168 | 79.7 |
condition | 60 | 96 | 62.5 |
subroutine | 21 | 21 | 100.0 |
pod | 18 | 18 | 100.0 |
total | 514 | 610 | 84.2 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | package HTML::LinkList; | ||||||
2 | $HTML::LinkList::VERSION = '0.1701'; | ||||||
3 | 5 | 5 | 106380 | use strict; | |||
5 | 12 | ||||||
5 | 134 | ||||||
4 | 5 | 5 | 25 | use warnings; | |||
5 | 9 | ||||||
5 | 212 | ||||||
5 | |||||||
6 | =head1 NAME | ||||||
7 | |||||||
8 | HTML::LinkList - Create a 'smart' list of HTML links. | ||||||
9 | |||||||
10 | =head1 VERSION | ||||||
11 | |||||||
12 | version 0.1701 | ||||||
13 | |||||||
14 | =head1 SYNOPSIS | ||||||
15 | |||||||
16 | use HTML::LinkList qw(link_list); | ||||||
17 | |||||||
18 | # default formatting | ||||||
19 | my $html_links = link_list(current_url=>$url, | ||||||
20 | urls=>\@links_in_order, | ||||||
21 | labels=>\%labels, | ||||||
22 | descriptions=>\%desc); | ||||||
23 | |||||||
24 | # paragraph with ' :: ' separators | ||||||
25 | my $html_links = link_list(current_url=>$url, | ||||||
26 | urls=>\@links_in_order, | ||||||
27 | labels=>\%labels, | ||||||
28 | descriptions=>\%desc, | ||||||
29 | links_head=>' ', |
||||||
30 | links_foot=>'', | ||||||
31 | pre_item=>'', | ||||||
32 | post_item=>'' | ||||||
33 | pre_active_item=>'', | ||||||
34 | post_active_item=>'', | ||||||
35 | item_sep=>" :: "); | ||||||
36 | |||||||
37 | # multi-level list | ||||||
38 | my $html_links = link_tree( | ||||||
39 | current_url=>$url, | ||||||
40 | link_tree=>\@list_of_lists, | ||||||
41 | labels=>\%labels, | ||||||
42 | descriptions=>\%desc); | ||||||
43 | |||||||
44 | |||||||
45 | =head1 DESCRIPTION | ||||||
46 | |||||||
47 | This module contains a number of functions for taking sets of URLs and | ||||||
48 | labels and creating suitably formatted HTML. These links are "smart" | ||||||
49 | because, if given the url of the current page, if any of the links in | ||||||
50 | the list equal it, that item in the list will be formatted as a special | ||||||
51 | label, not as a link; this is a Good Thing, since the user would be | ||||||
52 | confused by clicking on a link back to the current page. | ||||||
53 | |||||||
54 | While many website systems have plugins for "smart" navbars, they are | ||||||
55 | specialized for that system only, and can't be reused elsewhere, forcing | ||||||
56 | people to reinvent the wheel. I hereby present one wheel, free to be | ||||||
57 | reused by anybody; just the simple functions, a backend, which can be | ||||||
58 | plugged into whatever system you want. | ||||||
59 | |||||||
60 | The default format for the HTML is to make an unordered list, but there | ||||||
61 | are many options, enabling one to have a flatter layout with any | ||||||
62 | separators you desire, or a more complicated list with differing | ||||||
63 | formats for different levels. | ||||||
64 | |||||||
65 | The "link_list" function uses a simple list of links -- good for a | ||||||
66 | simple navbar. | ||||||
67 | |||||||
68 | The "link_tree" function takes a set of nested links and makes the HTML | ||||||
69 | for them -- good for making a table of contents, or a more complicated | ||||||
70 | navbar. | ||||||
71 | |||||||
72 | The "full_tree" function takes a list of paths and makes a full tree of | ||||||
73 | all the pages and index-pages in those paths -- good for making a site | ||||||
74 | map. | ||||||
75 | |||||||
76 | The "breadcrumb_trail" function takes a url and makes a "breadcrumb trail" | ||||||
77 | from it. | ||||||
78 | |||||||
79 | The "nav_tree" function creates a set of nested links to be | ||||||
80 | used as a multi-level navbar; one can give it a list of paths | ||||||
81 | (as for full_tree) and it will only show the links related | ||||||
82 | to the current URL. | ||||||
83 | |||||||
84 | =cut | ||||||
85 | |||||||
86 | =head1 FUNCTIONS | ||||||
87 | |||||||
88 | To export a function, add it to the 'use' call. | ||||||
89 | |||||||
90 | use HTML::LinkList qw(link_list); | ||||||
91 | |||||||
92 | To export all functions do: | ||||||
93 | |||||||
94 | use HTML::LinkList ':all'; | ||||||
95 | |||||||
96 | =cut | ||||||
97 | |||||||
98 | 5 | 5 | 4849 | use Data::Dumper; | |||
5 | 50764 | ||||||
5 | 25524 | ||||||
99 | require Exporter; | ||||||
100 | |||||||
101 | our @ISA = qw(Exporter); | ||||||
102 | |||||||
103 | |||||||
104 | # Items which are exportable. | ||||||
105 | # | ||||||
106 | # This allows declaration use HTML::LinkList ':all'; | ||||||
107 | # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK | ||||||
108 | # will save memory. | ||||||
109 | our %EXPORT_TAGS = ( 'all' => [ qw( | ||||||
110 | link_list | ||||||
111 | link_tree | ||||||
112 | full_tree | ||||||
113 | breadcrumb_trail | ||||||
114 | nav_tree | ||||||
115 | ) ] ); | ||||||
116 | |||||||
117 | our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); | ||||||
118 | |||||||
119 | # Items to export into callers namespace by default. Note: do not export | ||||||
120 | # names by default without a very good reason. Use EXPORT_OK instead. | ||||||
121 | # Do not simply export all your public functions/methods/constants. | ||||||
122 | |||||||
123 | our @EXPORT = qw( | ||||||
124 | |||||||
125 | ); | ||||||
126 | |||||||
127 | =head2 link_list | ||||||
128 | |||||||
129 | $links = link_list( | ||||||
130 | current_url=>$url, | ||||||
131 | urls=>\@links_in_order, | ||||||
132 | labels=>\%labels, | ||||||
133 | descriptions=>\%desc, | ||||||
134 | pre_desc=>' ', | ||||||
135 | post_desc=>'', | ||||||
136 | links_head=>'
|
||||||
137 | links_foot=>'', | ||||||
138 | pre_item=>' |
||||||
139 | post_item=>'' | ||||||
140 | pre_active_item=>'', | ||||||
141 | post_active_item=>'', | ||||||
142 | item_sep=>"\n"); | ||||||
143 | |||||||
144 | Generates a simple list of links, from list of urls | ||||||
145 | (and optional labels) taking into account of the "current" URL. | ||||||
146 | |||||||
147 | This provides a large number of options to customize the appearance | ||||||
148 | of the list. The default setup is for a simple UL list, but setting | ||||||
149 | the options can enable you to make it something other than a list | ||||||
150 | altogether, or add in CSS styles or classes to make it look just | ||||||
151 | like you want. | ||||||
152 | |||||||
153 | Required: | ||||||
154 | |||||||
155 | =over | ||||||
156 | |||||||
157 | =item urls | ||||||
158 | |||||||
159 | The urls in the order you want them displayed. If this list | ||||||
160 | is empty, then nothing will be generated. | ||||||
161 | |||||||
162 | =back | ||||||
163 | |||||||
164 | Options: | ||||||
165 | |||||||
166 | =over | ||||||
167 | |||||||
168 | =item current_url | ||||||
169 | |||||||
170 | The link to the current page. If one of the links equals this, | ||||||
171 | then that is deemed to be the "active" link and is just displayed | ||||||
172 | as a label rather than a link. | ||||||
173 | |||||||
174 | =item descriptions | ||||||
175 | |||||||
176 | Optional hash of descriptions, to put next to the links. The keys | ||||||
177 | of this hash are the urls. | ||||||
178 | |||||||
179 | =item hide_ext | ||||||
180 | |||||||
181 | If a site is hiding link extensions (such as using MultiViews with | ||||||
182 | Apache) you may wish to hide the extensions (while using the full URLs | ||||||
183 | to check various things). (default: 0 (false)) | ||||||
184 | |||||||
185 | =item item_sep | ||||||
186 | |||||||
187 | String to put between items. | ||||||
188 | |||||||
189 | =item labels | ||||||
190 | |||||||
191 | A hash whose keys are links and whose values are labels. | ||||||
192 | These are the labels for the links; if no label | ||||||
193 | is given, then the last part of the link is used | ||||||
194 | for the label, with some formatting. | ||||||
195 | |||||||
196 | =item links_head | ||||||
197 | |||||||
198 | String to begin the list with. | ||||||
199 | |||||||
200 | =item links_foot | ||||||
201 | |||||||
202 | String to end the list with. | ||||||
203 | |||||||
204 | =item pre_desc | ||||||
205 | |||||||
206 | String to prepend to each description. | ||||||
207 | |||||||
208 | =item post_desc | ||||||
209 | |||||||
210 | String to append to each description. | ||||||
211 | |||||||
212 | =item pre_item | ||||||
213 | |||||||
214 | String to prepend to each item. | ||||||
215 | |||||||
216 | =item post_item | ||||||
217 | |||||||
218 | String to append to each item. | ||||||
219 | |||||||
220 | =item pre_active_item | ||||||
221 | |||||||
222 | An additional string to put in front of each "active" item, after pre_item. | ||||||
223 | The "active" item is the link which matches 'current_url'. | ||||||
224 | |||||||
225 | =item pre_item_active | ||||||
226 | |||||||
227 | INSTEAD of the "pre_item" string, use this string for active items | ||||||
228 | |||||||
229 | =item post_active_item | ||||||
230 | |||||||
231 | An additional string to append to each active item, before post_item. | ||||||
232 | |||||||
233 | =item prefix_url | ||||||
234 | |||||||
235 | A prefix to prepend to all the links. (default: empty string) | ||||||
236 | |||||||
237 | =back | ||||||
238 | |||||||
239 | =cut | ||||||
240 | sub link_list { | ||||||
241 | 3 | 3 | 1 | 2153 | my %args = ( | ||
242 | current_url=>'', | ||||||
243 | prefix_url=>'', | ||||||
244 | labels=>undef, | ||||||
245 | urls=>undef, | ||||||
246 | links_head=>'
|
||||||
247 | links_foot=>"\n", | ||||||
248 | pre_item=>' |
||||||
249 | post_item=>'', | ||||||
250 | pre_active_item=>'', | ||||||
251 | post_active_item=>'', | ||||||
252 | pre_current_parent=>'', | ||||||
253 | post_current_parent=>'', | ||||||
254 | item_sep=>"\n", | ||||||
255 | hide_ext=>0, | ||||||
256 | @_ | ||||||
257 | ); | ||||||
258 | |||||||
259 | 3 | 5 | my @link_order = @{$args{urls}}; | ||||
3 | 11 | ||||||
260 | 3 | 50 | 33 | 27 | if (!defined $args{urls} | ||
261 | 3 | 10 | or !@{$args{urls}}) | ||||
262 | { | ||||||
263 | 0 | 0 | return ''; | ||||
264 | } | ||||||
265 | my %format = (exists $args{format} | ||||||
266 | 3 | 50 | 73 | ? %{$args{format}} | |||
0 | 0 | ||||||
267 | : make_default_format(%args)); | ||||||
268 | # correct the current_url | ||||||
269 | 3 | 14 | $args{current_url} = make_canonical($args{current_url}); | ||||
270 | 3 | 14 | my %current_parents = extract_current_parents(%args); | ||||
271 | 3 | 8 | my @items = (); | ||||
272 | 3 | 6 | foreach my $link (@link_order) | ||||
273 | { | ||||||
274 | my $label = (exists $args{labels}->{$link} | ||||||
275 | 15 | 100 | 36 | ? $args{labels}->{$link} : ''); | |||
276 | 15 | 65 | my $item = make_item(%args, | ||||
277 | format=>\%format, | ||||||
278 | current_parents=>\%current_parents, | ||||||
279 | this_link=>$link, | ||||||
280 | this_label=>$label); | ||||||
281 | 15 | 45 | push @items, $item; | ||||
282 | } | ||||||
283 | 3 | 9 | my $list = join($format{item_sep}, @items); | ||||
284 | return ($list | ||||||
285 | ? join('', $args{links_head}, $list, $args{links_foot}) | ||||||
286 | 3 | 50 | 29 | : ''); | |||
287 | } # link_list | ||||||
288 | |||||||
289 | =head2 link_tree | ||||||
290 | |||||||
291 | $links = link_tree( | ||||||
292 | current_url=>$url, | ||||||
293 | link_tree=>\@list_of_lists, | ||||||
294 | labels=>\%labels, | ||||||
295 | descriptions=>\%desc, | ||||||
296 | pre_desc=>' ', | ||||||
297 | post_desc=>'', | ||||||
298 | links_head=>'
|
||||||
299 | links_foot=>'', | ||||||
300 | subtree_head=>'
|
||||||
301 | subtree_foot=>'', | ||||||
302 | pre_item=>' |
||||||
303 | post_item=>'' | ||||||
304 | pre_active_item=>'', | ||||||
305 | post_active_item=>'', | ||||||
306 | item_sep=>"\n", | ||||||
307 | tree_sep=>"\n", | ||||||
308 | formats=>\%formats); | ||||||
309 | |||||||
310 | Generates nested lists of links from a list of lists of links. | ||||||
311 | This is useful for things such as table-of-contents or | ||||||
312 | site maps. | ||||||
313 | |||||||
314 | By default, this will return UL lists, but this is highly | ||||||
315 | configurable. | ||||||
316 | |||||||
317 | Required: | ||||||
318 | |||||||
319 | =over | ||||||
320 | |||||||
321 | =item link_tree | ||||||
322 | |||||||
323 | A list of lists of urls, in the order you want them displayed. | ||||||
324 | If a url is not in this list, it will not be displayed. | ||||||
325 | |||||||
326 | =back | ||||||
327 | |||||||
328 | Options: | ||||||
329 | |||||||
330 | =over | ||||||
331 | |||||||
332 | =item current_url | ||||||
333 | |||||||
334 | The link to the current page. If one of the links equals this, | ||||||
335 | then that is deemed to be the "active" link and is just displayed | ||||||
336 | as a label rather than a link. | ||||||
337 | |||||||
338 | =item descriptions | ||||||
339 | |||||||
340 | Optional hash of descriptions, to put next to the links. The keys | ||||||
341 | of this hash are the urls. | ||||||
342 | |||||||
343 | =item exclude_root_parent | ||||||
344 | |||||||
345 | If this is true, then the "current_parent" display options are | ||||||
346 | not used for the "root" ("/") path, it isn't counted as a "parent" | ||||||
347 | of the current_url. | ||||||
348 | |||||||
349 | =item formats | ||||||
350 | |||||||
351 | A reference to a hash containing advanced format settings. For example: | ||||||
352 | |||||||
353 | my %formats = ( | ||||||
354 | # level 1 and onwards | ||||||
355 | '1' => { | ||||||
356 | tree_head=>"
|
||||||
357 | tree_foot=>"\n", | ||||||
358 | }, | ||||||
359 | # level 2 and onwards | ||||||
360 | '2' => { | ||||||
361 | tree_head=>"
|
||||||
362 | tree_foot=>"\n", | ||||||
363 | }, | ||||||
364 | # level 3 and onwards | ||||||
365 | '3' => { | ||||||
366 | pre_item=>'(', | ||||||
367 | post_item=>')', | ||||||
368 | item_sep=>",\n", | ||||||
369 | tree_sep=>' -> ', | ||||||
370 | tree_head=>" \n", |
||||||
371 | tree_foot=>"", | ||||||
372 | } | ||||||
373 | ); | ||||||
374 | |||||||
375 | The formats hash enables you to control the formatting on a per-level basis. | ||||||
376 | Each key of the hash corresponds to a level-number; the sub-hashes contain | ||||||
377 | format arguments which will apply from that level onwards. If an argument | ||||||
378 | isn't given in the sub-hash, then it will fall back to the previous level | ||||||
379 | (or to the default, if there is no setting for that format-argument | ||||||
380 | for a previous level). | ||||||
381 | |||||||
382 | The only difference between the names of the arguments in the sub-hash and | ||||||
383 | in the global format arguments is that instead of 'subtree_head' and subtree_foot' | ||||||
384 | it uses 'tree_head' and 'tree_foot'. | ||||||
385 | |||||||
386 | =item hide_ext | ||||||
387 | |||||||
388 | If a site is hiding link extensions (such as using MultiViews with | ||||||
389 | Apache) you may wish to hide the extensions (while using the full URLs | ||||||
390 | to check various things). (default: 0 (false)) | ||||||
391 | |||||||
392 | =item item_sep | ||||||
393 | |||||||
394 | The string to separate each item. | ||||||
395 | |||||||
396 | =item labels | ||||||
397 | |||||||
398 | A hash whose keys are links and whose values are labels. | ||||||
399 | These are the labels for the links; if no label | ||||||
400 | is given, then the last part of the link is used | ||||||
401 | for the label, with some formatting. | ||||||
402 | |||||||
403 | =item links_head | ||||||
404 | |||||||
405 | The string to prepend the top-level tree with. | ||||||
406 | (default:
|
||||||
407 | |||||||
408 | =item links_foot | ||||||
409 | |||||||
410 | The string to append to the top-level tree. | ||||||
411 | (default: ) | ||||||
412 | |||||||
413 | =item pre_desc | ||||||
414 | |||||||
415 | String to prepend to each description. | ||||||
416 | |||||||
417 | =item post_desc | ||||||
418 | |||||||
419 | String to append to each description. | ||||||
420 | |||||||
421 | =item pre_item | ||||||
422 | |||||||
423 | String to prepend to each item. | ||||||
424 | (default: |
||||||
425 | |||||||
426 | =item post_item | ||||||
427 | |||||||
428 | String to append to each item. | ||||||
429 | (default: ) | ||||||
430 | |||||||
431 | =item pre_active_item | ||||||
432 | |||||||
433 | An additional string to put in front of each "active" item, after pre_item. | ||||||
434 | The "active" item is the link which matches 'current_url'. | ||||||
435 | (default: ) | ||||||
436 | |||||||
437 | =item pre_item_active | ||||||
438 | |||||||
439 | INSTEAD of the "pre_item" string, use this string for active items | ||||||
440 | |||||||
441 | =item post_active_item | ||||||
442 | |||||||
443 | An additional string to append to each active item, before post_item. | ||||||
444 | (default: ) | ||||||
445 | |||||||
446 | =item pre_current_parent | ||||||
447 | |||||||
448 | An additional string to put in front of a link which is a parent | ||||||
449 | of the 'current_url' link, after pre_item. | ||||||
450 | |||||||
451 | =item pre_item_current_parent | ||||||
452 | |||||||
453 | INSTEAD of the "pre_item" string, use this for links which are parents | ||||||
454 | of the 'current_url' link. | ||||||
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 | 1484 | 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 | 11 | $args{current_url} = make_canonical($args{current_url}); | ||||
506 | 3 | 17 | my %current_parents = extract_current_parents(%args); | ||||
507 | |||||||
508 | 3 | 8 | $args{tree_depth} = 0; | ||||
509 | 3 | 6 | $args{end_depth} = 0; | ||||
510 | |||||||
511 | 3 | 50 | 33 | 11 | if (defined $args{link_tree} | ||
512 | 3 | 14 | and @{$args{link_tree}}) | ||||
513 | { | ||||||
514 | 3 | 18 | 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 | 17 | my $list = traverse_lol(\@link_tree, | ||||
518 | %args, | ||||||
519 | formats=>\%formats, | ||||||
520 | current_format=>\%default_format, | ||||||
521 | current_parents=>\%current_parents); | ||||||
522 | 3 | 50 | 27 | 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 | 6 | 6 | 1 | 5046 | 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 | 6 | 21 | $args{current_url} = make_canonical($args{current_url}); | ||||
696 | 6 | 39 | my %current_parents = extract_current_parents(%args); | ||||
697 | |||||||
698 | # set the root label | ||||||
699 | 6 | 100 | 29 | if (!$args{labels}->{'/'}) | |||
700 | { | ||||||
701 | 2 | 4 | $args{labels}->{'/'} = 'Home'; | ||||
702 | } | ||||||
703 | 6 | 13 | my @path_list = (); | ||||
704 | 6 | 50 | 15 | if ($args{preserve_paths}) | |||
705 | { | ||||||
706 | 0 | 0 | @path_list = filter_out_paths(%args, paths=>$args{paths}); | ||||
707 | } | ||||||
708 | else | ||||||
709 | { | ||||||
710 | @path_list = extract_all_paths(paths=>$args{paths}, | ||||||
711 | 6 | 14 | preserve_order=>$args{preserve_order}); | ||||
712 | 6 | 46 | @path_list = filter_out_paths(%args, paths=>\@path_list); | ||||
713 | } | ||||||
714 | 6 | 51 | my @list_of_lists = build_lol(%args, paths=>\@path_list, | ||||
715 | depth=>0); | ||||||
716 | 6 | 20 | $args{tree_depth} = 0; | ||||
717 | 6 | 13 | $args{end_depth} = 0; | ||||
718 | |||||||
719 | 6 | 30 | my %default_format = make_default_format(%args); | ||||
720 | 6 | 44 | my %formats = make_extra_formats(%args); | ||||
721 | 6 | 45 | my $list = traverse_lol(\@list_of_lists, | ||||
722 | %args, | ||||||
723 | formats=>\%formats, | ||||||
724 | current_format=>\%default_format, | ||||||
725 | current_parents=>\%current_parents); | ||||||
726 | 6 | 50 | 68 | 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 | 750 | 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 | 8 | if (!$args{labels}->{'/'}) | |||
828 | { | ||||||
829 | 1 | 3 | $args{labels}->{'/'} = 'Home'; | ||||
830 | } | ||||||
831 | |||||||
832 | # make a list of paths consisting only of the current_url | ||||||
833 | 2 | 4 | my @paths = ($args{current_url}); | ||||
834 | 2 | 6 | my @path_list = extract_all_paths(paths=>\@paths); | ||||
835 | 2 | 12 | @path_list = filter_out_paths(%args, paths=>\@path_list); | ||||
836 | 2 | 15 | my @list_of_lists = build_lol(%args, paths=>\@path_list, | ||||
837 | depth=>0); | ||||||
838 | 2 | 6 | $args{tree_depth} = 0; | ||||
839 | 2 | 3 | $args{end_depth} = 0; | ||||
840 | |||||||
841 | 2 | 12 | my %default_format = make_default_format(%args); | ||||
842 | 2 | 19 | my %formats = make_extra_formats(%args); | ||||
843 | 2 | 14 | my $list = traverse_lol(\@list_of_lists, | ||||
844 | %args, | ||||||
845 | formats=>\%formats, | ||||||
846 | current_format=>\%default_format, | ||||||
847 | ); | ||||||
848 | 2 | 50 | 23 | 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 | 13 | 13 | 1 | 14693 | 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 | 13 | 46 | $args{current_url} = make_canonical($args{current_url}); | ||||
1025 | 13 | 43 | my $current_is_index = ($args{current_url} =~ m!/$!o); | ||||
1026 | 13 | 100 | my %current_parents = extract_current_parents(%args); | ||||
1027 | |||||||
1028 | # set the end depth if is not 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 | 13 | 60 | my $current_url_depth = path_depth($args{current_url}); | ||||
1032 | $args{end_depth} = ($current_is_index | ||||||
1033 | ? $current_url_depth + 1 : $current_url_depth) | ||||||
1034 | 13 | 100 | 55 | if (!defined $args{end_depth}); | |||
50 | |||||||
1035 | |||||||
1036 | # set the root label | ||||||
1037 | 13 | 100 | 37 | if (!$args{labels}->{'/'}) | |||
1038 | { | ||||||
1039 | 1 | 3 | $args{labels}->{'/'} = 'Home'; | ||||
1040 | } | ||||||
1041 | 13 | 23 | my @path_list = (); | ||||
1042 | 13 | 50 | 27 | if ($args{preserve_paths}) | |||
1043 | { | ||||||
1044 | 0 | 0 | @path_list = filter_out_paths(%args, paths=>$args{paths}); | ||||
1045 | } | ||||||
1046 | else | ||||||
1047 | { | ||||||
1048 | @path_list = extract_all_paths(paths=>$args{paths}, | ||||||
1049 | 13 | 48 | preserve_order=>$args{preserve_order}); | ||||
1050 | 13 | 118 | @path_list = filter_out_paths(%args, paths=>\@path_list); | ||||
1051 | } | ||||||
1052 | 13 | 172 | my @list_of_lists = build_lol(%args, paths=>\@path_list, | ||||
1053 | depth=>0); | ||||||
1054 | 13 | 50 | $args{tree_depth} = 0; | ||||
1055 | |||||||
1056 | 13 | 86 | my %default_format = make_default_format(%args); | ||||
1057 | 13 | 118 | my %formats = make_extra_formats(%args); | ||||
1058 | 13 | 112 | my $list = traverse_lol(\@list_of_lists, | ||||
1059 | %args, | ||||||
1060 | formats=>\%formats, | ||||||
1061 | current_format=>\%default_format, | ||||||
1062 | current_parents=>\%current_parents); | ||||||
1063 | 13 | 50 | 230 | 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 | 185 | 185 | 1 | 2232 | 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 | 185 | 360 | my $link = $args{this_link}; | ||||
1153 | 185 | 262 | my $prefix_url = $args{prefix_url}; | ||||
1154 | 185 | 260 | my $label = $args{this_label}; | ||||
1155 | 185 | 209 | my %format = %{$args{format}}; | ||||
185 | 1163 | ||||||
1156 | |||||||
1157 | 185 | 100 | 578 | if (!$label) | |||
1158 | { | ||||||
1159 | 147 | 50 | 359 | $label = $link if !$label; | |||
1160 | 147 | 100 | 791 | if ($link =~ /([-\w]+)\.\w+$/o) # file | |||
50 | |||||||
1161 | { | ||||||
1162 | 39 | 91 | $label = $1; | ||||
1163 | } | ||||||
1164 | elsif ($link =~ /([-\w]+)\/?$/o) # dir | ||||||
1165 | { | ||||||
1166 | 108 | 292 | $label = $1; | ||||
1167 | } | ||||||
1168 | else # give up | ||||||
1169 | { | ||||||
1170 | 0 | 0 | $label = $link; | ||||
1171 | 0 | 0 | $label =~ s#/# :: #go; | ||||
1172 | } | ||||||
1173 | |||||||
1174 | # prettify | ||||||
1175 | 147 | 254 | $label =~ s#_# #go; | ||||
1176 | 147 | 203 | $label =~ s#-# #go; | ||||
1177 | 147 | 787 | $label =~ s/(\b[a-z][-\w]+)/\u\L$1/go; | ||||
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 | 185 | 272 | my $display_link = $link; | ||||
1183 | 185 | 50 | 414 | if ($args{hide_ext}) | |||
1184 | { | ||||||
1185 | 0 | 0 | 0 | if ($link =~ /(.*)\.[-\w]+$/o) # file | |||
1186 | { | ||||||
1187 | 0 | 0 | $display_link = $1; | ||||
1188 | } | ||||||
1189 | } | ||||||
1190 | 185 | 251 | my $item = ''; | ||||
1191 | 185 | 221 | my $desc = ''; | ||||
1192 | 185 | 0 | 33 | 590 | if (exists $args{descriptions}->{$link} | ||
33 | |||||||
1193 | and defined $args{descriptions}->{$link} | ||||||
1194 | and $args{descriptions}->{$link}) | ||||||
1195 | { | ||||||
1196 | $desc = join('', $format{pre_desc}, | ||||||
1197 | $args{descriptions}->{$link}, | ||||||
1198 | 0 | 0 | $format{post_desc}); | ||||
1199 | } | ||||||
1200 | 185 | 100 | 66 | 437 | if (link_is_active(this_link=>$link, | ||
50 | 66 | ||||||
100 | |||||||
1201 | current_url=>$args{current_url})) | ||||||
1202 | { | ||||||
1203 | $item = join('', $format{pre_item_active}, | ||||||
1204 | $format{pre_active_item}, | ||||||
1205 | $label, | ||||||
1206 | $format{post_active_item}, | ||||||
1207 | 15 | 50 | $desc, | ||||
1208 | ); | ||||||
1209 | } | ||||||
1210 | elsif ($args{no_link}) | ||||||
1211 | { | ||||||
1212 | $item = join('', $format{pre_item}, | ||||||
1213 | 0 | 0 | $label, | ||||
1214 | $desc); | ||||||
1215 | } | ||||||
1216 | elsif ($args{current_url} | ||||||
1217 | and exists $args{current_parents}->{$link} | ||||||
1218 | and $args{current_parents}->{$link}) | ||||||
1219 | { | ||||||
1220 | $item = join('', $format{pre_item_current_parent}, | ||||||
1221 | $format{pre_current_parent}, | ||||||
1222 | '', | ||||||
1223 | $label, '', | ||||||
1224 | $format{post_current_parent}, | ||||||
1225 | 10 | 39 | $desc); | ||||
1226 | } | ||||||
1227 | else | ||||||
1228 | { | ||||||
1229 | $item = join('', $format{pre_item}, | ||||||
1230 | 160 | 459 | '', | ||||
1231 | $label, '', | ||||||
1232 | $desc); | ||||||
1233 | } | ||||||
1234 | 185 | 100 | 441 | if (!$args{defer_post_item}) | |||
1235 | { | ||||||
1236 | 15 | 34 | $item = join('', $item, $format{post_item}); | ||||
1237 | } | ||||||
1238 | 185 | 1426 | 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 | 708 | 708 | 1 | 923 | my $url = shift; | ||
1251 | |||||||
1252 | 708 | 100 | 1431 | return $url if (!$url); | |||
1253 | 687 | 100 | 3632 | if ($url =~ m{^/index\.\w+$}o) | |||
50 | |||||||
100 | |||||||
1254 | { | ||||||
1255 | 1 | 2 | $url = '/'; | ||||
1256 | } | ||||||
1257 | elsif ($url =~ m{^(.*/)index\.\w+$}o) | ||||||
1258 | { | ||||||
1259 | 0 | 0 | $url = $1; | ||||
1260 | } | ||||||
1261 | elsif ($url =~ m{/[-\w]+$}o) # no dots; a directory | ||||||
1262 | { | ||||||
1263 | 13 | 33 | $url = join('', $url, '/'); # add the slash | ||||
1264 | } | ||||||
1265 | 687 | 1254 | 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 | 50 | 50 | 1 | 67 | my $url = shift; | ||
1280 | |||||||
1281 | 50 | 50 | 101 | return $url if (!$url); | |||
1282 | 50 | 86 | $url = make_canonical($url); | ||||
1283 | 50 | 100 | 66 | 351 | if ($url =~ m{^(.*)/[-\w]+\.\w+$}o) | ||
100 | |||||||
1284 | { | ||||||
1285 | 15 | 39 | $url = $1; | ||||
1286 | } | ||||||
1287 | elsif ($url ne '/' and $url =~ m{/$}o) | ||||||
1288 | { | ||||||
1289 | 31 | 58 | chop $url; | ||||
1290 | } | ||||||
1291 | 50 | 109 | 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 | 35 | 35 | 1 | 51 | my $url = shift; | ||
1304 | |||||||
1305 | 35 | 100 | 80 | return $url if (!$url); | |||
1306 | 30 | 67 | $url = get_index_path($url); | ||||
1307 | 30 | 100 | 115 | if ($url =~ m#^(.*)/[-\w]+$#o) | |||
1308 | { | ||||||
1309 | 27 | 66 | $url = $1; | ||||
1310 | } | ||||||
1311 | 30 | 63 | 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 | 541 | 541 | 1 | 720 | my $url = shift; | ||
1323 | |||||||
1324 | 541 | 100 | 1098 | return 0 if ($url eq '/'); # root is zero | |||
1325 | 512 | 100 | 1446 | if ($url =~ m!/$!o) # remove trailing / | |||
1326 | { | ||||||
1327 | 295 | 542 | chop $url; | ||||
1328 | } | ||||||
1329 | 512 | 881 | return scalar ($url =~ tr!/!/!); | ||||
1330 | } # path_depth | ||||||
1331 | |||||||
1332 | =head2 link_is_active | ||||||
1333 | |||||||
1334 | if (link_is_active(this_link=>$link, current_url=>$url)) | ||||||
1335 | ... | ||||||
1336 | |||||||
1337 | Check if the given link is "active", that is, if it | ||||||
1338 | matches the 'current_url'. | ||||||
1339 | |||||||
1340 | =cut | ||||||
1341 | sub link_is_active { | ||||||
1342 | 185 | 185 | 1 | 592 | my %args = ( | ||
1343 | this_link=>'', | ||||||
1344 | current_url=>'', | ||||||
1345 | @_ | ||||||
1346 | ); | ||||||
1347 | # if there is no current link, is not active. | ||||||
1348 | 185 | 100 | 728 | return 0 if (!$args{current_url}); | |||
1349 | |||||||
1350 | 108 | 217 | my $link = make_canonical($args{this_link}); | ||||
1351 | |||||||
1352 | 108 | 100 | 344 | return 1 if ($link eq $args{current_url}); | |||
1353 | 93 | 621 | 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 | 86 | 86 | 1 | 202 | my $lol_ref = shift; | ||
1374 | 86 | 900 | my %args = ( | ||||
1375 | current_url=>'', | ||||||
1376 | labels=>undef, | ||||||
1377 | prefix_url=>'', | ||||||
1378 | hide_ext=>0, | ||||||
1379 | @_ | ||||||
1380 | ); | ||||||
1381 | |||||||
1382 | 86 | 144 | my $tree_depth = $args{tree_depth}; | ||||
1383 | my %format = ( | ||||||
1384 | 86 | 757 | %{$args{current_format}}, | ||||
1385 | (exists $args{formats}->{$tree_depth} | ||||||
1386 | 86 | 100 | 102 | ? %{$args{formats}->{$tree_depth}} | |||
8 | 49 | ||||||
1387 | : ()) | ||||||
1388 | ); | ||||||
1389 | 86 | 209 | my @items = (); | ||||
1390 | 86 | 106 | while (@{$lol_ref}) | ||||
258 | 633 | ||||||
1391 | { | ||||||
1392 | 187 | 224 | my $ll = shift @{$lol_ref}; | ||||
187 | 308 | ||||||
1393 | 187 | 100 | 408 | if (!ref $ll) # an item | |||
1394 | { | ||||||
1395 | 170 | 210 | my $link = $ll; | ||||
1396 | my $label = (exists $args{labels}->{$link} | ||||||
1397 | 170 | 100 | 418 | ? $args{labels}->{$link} : ''); | |||
1398 | 170 | 1049 | my $item = make_item(this_link=>$link, | ||||
1399 | this_label=>$label, | ||||||
1400 | defer_post_item=>1, | ||||||
1401 | %args, | ||||||
1402 | format=>\%format); | ||||||
1403 | |||||||
1404 | 170 | 100 | 786 | if (ref $lol_ref->[0]) # next one is a list | |||
1405 | { | ||||||
1406 | 45 | 59 | $ll = shift @{$lol_ref}; | ||||
45 | 88 | ||||||
1407 | 45 | 316 | my $sublist = traverse_lol($ll, %args, | ||||
1408 | tree_depth=>$tree_depth + 1, | ||||||
1409 | current_format=>\%format); | ||||||
1410 | 45 | 202 | $item = join($format{tree_sep}, $item, $sublist); | ||||
1411 | } | ||||||
1412 | 170 | 404 | $item = join('', $item, $format{post_item}); | ||||
1413 | 170 | 350 | push @items, $item; | ||||
1414 | } | ||||||
1415 | else # a reference to a list | ||||||
1416 | { | ||||||
1417 | 17 | 100 | 66 | 93 | if (defined $args{start_depth} | ||
1418 | && $args{tree_depth} < $args{start_depth}) | ||||||
1419 | { | ||||||
1420 | 15 | 105 | return traverse_lol($ll, %args, current_format=>\%format); | ||||
1421 | } | ||||||
1422 | else | ||||||
1423 | { | ||||||
1424 | 2 | 13 | my $sublist = traverse_lol($ll, %args, | ||||
1425 | tree_depth=>$tree_depth + 1, | ||||||
1426 | current_format=>\%format); | ||||||
1427 | 2 | 8 | my $item = join($format{tree_sep}, $format{pre_item}, $sublist); | ||||
1428 | 2 | 6 | $item = join('', $item, $format{post_item}); | ||||
1429 | 2 | 4 | push @items, $item; | ||||
1430 | } | ||||||
1431 | } | ||||||
1432 | } | ||||||
1433 | 71 | 202 | my $list = join($format{item_sep}, @items); | ||||
1434 | return join('', | ||||||
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 | 71 | 50 | 66 | 1025 | ); | ||
50 | 66 | ||||||
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 | 21 | 21 | 1 | 77 | my %args = ( | ||
1469 | paths=>undef, | ||||||
1470 | preserve_order=>0, | ||||||
1471 | @_ | ||||||
1472 | ); | ||||||
1473 | |||||||
1474 | 21 | 37 | my %paths = (); | ||||
1475 | # keep track of the order of the paths in the list of paths | ||||||
1476 | 21 | 34 | my $order = 1; | ||||
1477 | 21 | 29 | foreach my $path (@{$args{paths}}) | ||||
21 | 61 | ||||||
1478 | { | ||||||
1479 | 186 | 477 | my @path_split = split('/', $path); | ||||
1480 | # first path as-is | ||||||
1481 | 186 | 428 | $paths{$path} = $order; | ||||
1482 | 186 | 213 | pop @path_split; | ||||
1483 | 186 | 424 | while (@path_split) | ||||
1484 | { | ||||||
1485 | # these paths are index-pages. should end in '/' | ||||||
1486 | 383 | 637 | 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 | 383 | 100 | 893 | $paths{$newpath} = $order if (!exists $paths{$newpath}); | |||
1490 | 383 | 945 | pop @path_split; | ||||
1491 | } | ||||||
1492 | 186 | 100 | 538 | $order++ if ($args{preserve_order}); | |||
1493 | } | ||||||
1494 | return sort { | ||||||
1495 | 21 | 100 | 154 | return $a cmp $b if ($paths{$a} == $paths{$b}); | |||
687 | 1486 | ||||||
1496 | 525 | 852 | 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 | 25 | 25 | 1 | 222 | my %args = ( | ||
1521 | current_url=>undef, | ||||||
1522 | exclude_root_parent=>0, | ||||||
1523 | @_ | ||||||
1524 | ); | ||||||
1525 | |||||||
1526 | 25 | 48 | my %paths = (); | ||||
1527 | 25 | 100 | 87 | if ($args{current_url}) | |||
1528 | { | ||||||
1529 | 14 | 26 | my $current_url = $args{current_url}; | ||||
1530 | 14 | 55 | my @path_split = split('/', $current_url); | ||||
1531 | 14 | 20 | pop @path_split; # remove the current url | ||||
1532 | 14 | 40 | while (@path_split) | ||||
1533 | { | ||||||
1534 | # these paths are index-pages. should end in '/' | ||||||
1535 | 25 | 59 | my $newpath = join('/', @path_split, ''); | ||||
1536 | 25 | 48 | $paths{$newpath} = 1; | ||||
1537 | 25 | 70 | pop @path_split; | ||||
1538 | } | ||||||
1539 | 14 | 100 | 55 | if ($args{exclude_root_parent}) | |||
1540 | { | ||||||
1541 | 2 | 5 | delete $paths{"/"}; | ||||
1542 | } | ||||||
1543 | } | ||||||
1544 | |||||||
1545 | 25 | 146 | 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 | 78 | 78 | 1 | 969 | 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 | 78 | 130 | my $paths_ref = $args{paths}; | ||||
1581 | 78 | 108 | my $depth = $args{depth}; | ||||
1582 | |||||||
1583 | 78 | 116 | my @list_of_lists = (); | ||||
1584 | 78 | 96 | while (@{$paths_ref}) | ||||
289 | 739 | ||||||
1585 | { | ||||||
1586 | 238 | 364 | my $path = $paths_ref->[0]; | ||||
1587 | 238 | 398 | my $can_path = make_canonical($path); | ||||
1588 | 238 | 452 | my $path_depth = path_depth($can_path); | ||||
1589 | 238 | 548 | my $path_is_index = ($can_path =~ m#/$#o); | ||||
1590 | 238 | 100 | 511 | if ($path_depth == $depth) | |||
100 | |||||||
50 | |||||||
1591 | { | ||||||
1592 | 154 | 173 | shift @{$paths_ref}; # use this path | ||||
154 | 274 | ||||||
1593 | 154 | 314 | push @list_of_lists, $path; | ||||
1594 | } | ||||||
1595 | elsif ($path_depth > $depth) | ||||||
1596 | { | ||||||
1597 | 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 | 57 | 441 | )]; | ||||
1606 | } | ||||||
1607 | elsif ($path_depth < $depth) | ||||||
1608 | { | ||||||
1609 | 27 | 247 | return @list_of_lists; | ||||
1610 | } | ||||||
1611 | } | ||||||
1612 | # prepend the given list to the top level | ||||||
1613 | 51 | 100 | 66 | 151 | if (defined $args{prepend_list} and @{$args{prepend_list}}) | ||
3 | 14 | ||||||
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 | 3 | 50 | 33 | 21 | if ($#list_of_lists == 0 | ||
1618 | and ref($list_of_lists[0]) eq "ARRAY") | ||||||
1619 | { | ||||||
1620 | 3 | 5 | unshift @{$list_of_lists[0]}, @{$args{prepend_list}}; | ||||
3 | 6 | ||||||
3 | 10 | ||||||
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 | 51 | 50 | 33 | 132 | 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 | 51 | 381 | 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 | 21 | 21 | 1 | 279 | 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 | 21 | 43 | my $paths_ref = $args{paths}; | ||||
1675 | 21 | 35 | my $hide = $args{hide}; | ||||
1676 | 21 | 33 | my $nohide = $args{nohide}; | ||||
1677 | |||||||
1678 | 21 | 33 | my %canon_paths = (); | ||||
1679 | 21 | 31 | my @wantedpaths1 = (); | ||||
1680 | 21 | 35 | my %path_depth = (); | ||||
1681 | |||||||
1682 | # filter out common things | ||||||
1683 | # remember canonical paths and path depths | ||||||
1684 | 21 | 45 | foreach my $path (@{$paths_ref}) | ||||
21 | 44 | ||||||
1685 | { | ||||||
1686 | 260 | 481 | my $can_path = make_canonical($path); | ||||
1687 | 260 | 485 | my $path_depth = path_depth($can_path); | ||||
1688 | 260 | 50 | 33 | 2164 | if ($hide and $nohide | ||
50 | 33 | ||||||
100 | 0 | ||||||
100 | 33 | ||||||
33 | |||||||
100 | |||||||
1689 | and not($path =~ /$nohide/) | ||||||
1690 | and $path =~ /$hide/) | ||||||
1691 | { | ||||||
1692 | # skip this one | ||||||
1693 | } | ||||||
1694 | elsif ($hide and !$nohide and $path =~ /$hide/) | ||||||
1695 | { | ||||||
1696 | # skip this one | ||||||
1697 | } | ||||||
1698 | elsif ($path_depth < $args{start_depth}) | ||||||
1699 | { | ||||||
1700 | # skip this one | ||||||
1701 | } | ||||||
1702 | elsif ($args{end_depth} | ||||||
1703 | and $path_depth > $args{end_depth}) | ||||||
1704 | { | ||||||
1705 | # skip this one | ||||||
1706 | } | ||||||
1707 | else | ||||||
1708 | { | ||||||
1709 | 213 | 318 | $path_depth{$path} = $path_depth; | ||||
1710 | 213 | 317 | $canon_paths{$path} = $can_path; | ||||
1711 | 213 | 445 | push @wantedpaths1, $path; | ||||
1712 | } | ||||||
1713 | } | ||||||
1714 | |||||||
1715 | 21 | 45 | my @wantedpaths = (); | ||||
1716 | 21 | 100 | 44 | if ($args{current_url}) | |||
1717 | { | ||||||
1718 | 15 | 27 | my $current_url = $args{current_url}; | ||||
1719 | 15 | 33 | my $current_url_depth = path_depth($args{current_url}); | ||||
1720 | 15 | 50 | my $current_url_is_index = ($args{current_url} =~ m{/$}o); | ||||
1721 | |||||||
1722 | my $parent = make_canonical($current_url_is_index | ||||||
1723 | ? get_index_parent($args{current_url}) | ||||||
1724 | : get_index_path($args{current_url}) | ||||||
1725 | 15 | 100 | 64 | ); | |||
1726 | 15 | 40 | my $parent_depth = path_depth($parent); | ||||
1727 | 15 | 100 | 52 | my $grandparent = ($parent_depth == 1 | |||
1728 | ? '/' | ||||||
1729 | : make_canonical(get_index_parent($parent))); | ||||||
1730 | 15 | 100 | 42 | my $greatgrandparent = ($parent_depth <= 1 | |||
100 | |||||||
1731 | ? '' | ||||||
1732 | : ($parent_depth == 2 | ||||||
1733 | ? '/' | ||||||
1734 | : make_canonical(get_index_parent($grandparent)) | ||||||
1735 | ) | ||||||
1736 | ); | ||||||
1737 | 15 | 42 | my $current_index_path = get_index_path($args{current_url}); | ||||
1738 | 15 | 35 | my $current_index_parent = get_index_parent($args{current_url}); | ||||
1739 | |||||||
1740 | 15 | 100 | 66 | 77 | if ($args{navbar_type} eq 'breadcrumb') | ||
100 | |||||||
1741 | { | ||||||
1742 | 2 | 5 | foreach my $path (@wantedpaths1) | ||||
1743 | { | ||||||
1744 | 20 | 34 | my $pd = $path_depth{$path}; | ||||
1745 | # a breadcrumb-navbar shows the parent, self, | ||||||
1746 | # and the children the parent | ||||||
1747 | 20 | 100 | 100 | 376 | if ($pd <= $current_url_depth | ||
50 | 100 | ||||||
100 | 100 | ||||||
100 | 100 | ||||||
1748 | and $args{current_url} =~ /^$path/) | ||||||
1749 | { | ||||||
1750 | 3 | 10 | push @wantedpaths, $path; | ||||
1751 | } | ||||||
1752 | elsif ($path eq $args{current_url}) | ||||||
1753 | { | ||||||
1754 | 0 | 0 | push @wantedpaths, $path; | ||||
1755 | } | ||||||
1756 | elsif ($pd >= $current_url_depth | ||||||
1757 | and $path =~ m{^${current_url}}) | ||||||
1758 | { | ||||||
1759 | 3 | 8 | push @wantedpaths, $path; | ||||
1760 | } | ||||||
1761 | elsif ($parent | ||||||
1762 | and $pd >= $current_url_depth | ||||||
1763 | and $path =~ m{^$parent}) | ||||||
1764 | { | ||||||
1765 | 2 | 6 | push @wantedpaths, $path; | ||||
1766 | } | ||||||
1767 | } | ||||||
1768 | } | ||||||
1769 | elsif ($args{navbar_type} or $args{do_navbar}) | ||||||
1770 | { | ||||||
1771 | # Rules for navbars: | ||||||
1772 | # * if I am a leaf node, see my (great)uncles and siblings | ||||||
1773 | # * if have children, use the same data as my parent, | ||||||
1774 | # plus my immediate children | ||||||
1775 | 11 | 23 | foreach my $path (@wantedpaths1) | ||||
1776 | { | ||||||
1777 | 134 | 195 | my $pd = $path_depth{$path}; | ||||
1778 | 134 | 50 | 294 | if ($pd > $current_url_depth + 1) | |||
1779 | { | ||||||
1780 | 0 | 0 | next; | ||||
1781 | } | ||||||
1782 | 134 | 100 | 100 | 1584 | if ($pd == $current_url_depth + 1 | ||
100 | 100 | ||||||
100 | 100 | ||||||
100 | 100 | ||||||
100 | |||||||
66 | |||||||
1783 | and $path =~ m{^${current_url}}) | ||||||
1784 | { | ||||||
1785 | 19 | 50 | push @wantedpaths, $path; | ||||
1786 | } | ||||||
1787 | elsif ($pd == $current_url_depth | ||||||
1788 | and $path =~ m{^${parent}}) | ||||||
1789 | { | ||||||
1790 | 35 | 76 | push @wantedpaths, $path; | ||||
1791 | } | ||||||
1792 | elsif ($grandparent | ||||||
1793 | and $pd == $parent_depth | ||||||
1794 | and $path =~ m{^$grandparent}) | ||||||
1795 | { | ||||||
1796 | 24 | 99 | push @wantedpaths, $path; | ||||
1797 | } | ||||||
1798 | elsif ($greatgrandparent | ||||||
1799 | and $pd == $parent_depth - 1 | ||||||
1800 | and $path =~ m{^$greatgrandparent}) | ||||||
1801 | { | ||||||
1802 | 9 | 24 | push @wantedpaths, $path; | ||||
1803 | } | ||||||
1804 | } | ||||||
1805 | } | ||||||
1806 | else | ||||||
1807 | { | ||||||
1808 | 2 | 5 | push @wantedpaths, @wantedpaths1; | ||||
1809 | } | ||||||
1810 | } | ||||||
1811 | else | ||||||
1812 | { | ||||||
1813 | 6 | 18 | push @wantedpaths, @wantedpaths1; | ||||
1814 | } | ||||||
1815 | 21 | 250 | return @wantedpaths; | ||||
1816 | } # filter_out_paths | ||||||
1817 | |||||||
1818 | =head2 make_default_format | ||||||
1819 | |||||||
1820 | my %default_format = make_default_format(%args); | ||||||
1821 | |||||||
1822 | Make the default format hash from the args. | ||||||
1823 | Returns a hash of format options. | ||||||
1824 | |||||||
1825 | =cut | ||||||
1826 | sub make_default_format { | ||||||
1827 | 27 | 27 | 1 | 370 | my %args = ( | ||
1828 | links_head=>'
|
||||||
1829 | links_foot=>"\n", | ||||||
1830 | subtree_head=>'
|
||||||
1831 | subtree_foot=>"\n", | ||||||
1832 | last_subtree_head=>'
|
||||||
1833 | last_subtree_foot=>"\n", | ||||||
1834 | pre_item=>' |
||||||
1835 | post_item=>'', | ||||||
1836 | pre_active_item=>'', | ||||||
1837 | post_active_item=>'', | ||||||
1838 | pre_current_parent=>'', | ||||||
1839 | post_current_parent=>'', | ||||||
1840 | item_sep=>"\n", | ||||||
1841 | tree_sep=>"\n", | ||||||
1842 | @_ | ||||||
1843 | ); | ||||||
1844 | my %default_format = ( | ||||||
1845 | pre_item=>$args{pre_item}, | ||||||
1846 | post_item=>$args{post_item}, | ||||||
1847 | pre_active_item=>$args{pre_active_item}, | ||||||
1848 | post_active_item=>$args{post_active_item}, | ||||||
1849 | pre_current_parent=>$args{pre_current_parent}, | ||||||
1850 | post_current_parent=>$args{post_current_parent}, | ||||||
1851 | pre_desc=>$args{pre_desc}, | ||||||
1852 | post_desc=>$args{post_desc}, | ||||||
1853 | item_sep=>$args{item_sep}, | ||||||
1854 | tree_sep=>$args{tree_sep}, | ||||||
1855 | tree_head=>$args{links_head}, | ||||||
1856 | tree_foot=>$args{links_foot}, | ||||||
1857 | pre_item_active=>($args{pre_item_active} | ||||||
1858 | ? $args{pre_item_active} | ||||||
1859 | : $args{pre_item}), | ||||||
1860 | pre_item_current_parent=> | ||||||
1861 | ($args{pre_item_current_parent} | ||||||
1862 | ? $args{pre_item_current_parent} | ||||||
1863 | 27 | 50 | 363 | : $args{pre_item}), | |||
100 | |||||||
1864 | ); | ||||||
1865 | 27 | 319 | return %default_format; | ||||
1866 | } # make_default_format | ||||||
1867 | |||||||
1868 | =head2 make_extra_formats | ||||||
1869 | |||||||
1870 | my %formats = make_extra_formats(%args); | ||||||
1871 | |||||||
1872 | Transforms the subtree_head and subtree_foot into the "formats" | ||||||
1873 | method of formatting. | ||||||
1874 | Returns a hash of hashes of format options. | ||||||
1875 | |||||||
1876 | =cut | ||||||
1877 | sub make_extra_formats { | ||||||
1878 | 24 | 24 | 1 | 331 | my %args = ( | ||
1879 | formats=>undef, | ||||||
1880 | links_head=>'
|
||||||
1881 | links_foot=>"\n", | ||||||
1882 | subtree_head=>'
|
||||||
1883 | subtree_foot=>"\n", | ||||||
1884 | last_subtree_head=>'
|
||||||
1885 | last_subtree_foot=>"\n", | ||||||
1886 | pre_item=>' |
||||||
1887 | post_item=>'', | ||||||
1888 | pre_item_active=>' |
||||||
1889 | pre_item_current_parent=>' |
||||||
1890 | pre_active_item=>'', | ||||||
1891 | post_active_item=>'', | ||||||
1892 | pre_current_parent=>'', | ||||||
1893 | post_current_parent=>'', | ||||||
1894 | item_sep=>"\n", | ||||||
1895 | tree_sep=>"\n", | ||||||
1896 | @_ | ||||||
1897 | ); | ||||||
1898 | 24 | 43 | my %formats = (); | ||||
1899 | 24 | 100 | 69 | if (defined $args{formats}) | |||
1900 | { | ||||||
1901 | 2 | 4 | %formats = %{$args{formats}}; | ||||
2 | 8 | ||||||
1902 | } | ||||||
1903 | 24 | 100 | 66 | 141 | if ($args{links_head} ne $args{subtree_head} | ||
1904 | || $args{links_foot} ne $args{subtree_foot}) | ||||||
1905 | { | ||||||
1906 | 2 | 50 | 6 | if (!exists $formats{1}) | |||
1907 | { | ||||||
1908 | 2 | 4 | $formats{1} = {}; | ||||
1909 | } | ||||||
1910 | 2 | 4 | $formats{1}->{tree_head} = $args{subtree_head}; | ||||
1911 | 2 | 4 | $formats{1}->{tree_foot} = $args{subtree_foot}; | ||||
1912 | } | ||||||
1913 | 24 | 129 | return %formats; | ||||
1914 | } # make_extra_formats | ||||||
1915 | |||||||
1916 | =head1 REQUIRES | ||||||
1917 | |||||||
1918 | Test::More | ||||||
1919 | |||||||
1920 | =head1 INSTALLATION | ||||||
1921 | |||||||
1922 | To install this module, run the following commands: | ||||||
1923 | |||||||
1924 | perl Build.PL | ||||||
1925 | ./Build | ||||||
1926 | ./Build test | ||||||
1927 | ./Build install | ||||||
1928 | |||||||
1929 | Or, if you're on a platform (like DOS or Windows) that doesn't like the | ||||||
1930 | "./" notation, you can do this: | ||||||
1931 | |||||||
1932 | perl Build.PL | ||||||
1933 | perl Build | ||||||
1934 | perl Build test | ||||||
1935 | perl Build install | ||||||
1936 | |||||||
1937 | In order to install somewhere other than the default, such as | ||||||
1938 | in a directory under your home directory, like "/home/fred/perl" | ||||||
1939 | go | ||||||
1940 | |||||||
1941 | perl Build.PL --install_base /home/fred/perl | ||||||
1942 | |||||||
1943 | as the first step instead. | ||||||
1944 | |||||||
1945 | This will install the files underneath /home/fred/perl. | ||||||
1946 | |||||||
1947 | You will then need to make sure that you alter the PERL5LIB variable to | ||||||
1948 | find the modules. | ||||||
1949 | |||||||
1950 | Therefore you will need to change the PERL5LIB variable to add | ||||||
1951 | /home/fred/perl/lib | ||||||
1952 | |||||||
1953 | PERL5LIB=/home/fred/perl/lib:${PERL5LIB} | ||||||
1954 | |||||||
1955 | =head1 SEE ALSO | ||||||
1956 | |||||||
1957 | perl(1). | ||||||
1958 | |||||||
1959 | =head1 BUGS | ||||||
1960 | |||||||
1961 | Please report any bugs or feature requests to the author. | ||||||
1962 | |||||||
1963 | =head1 AUTHOR | ||||||
1964 | |||||||
1965 | Kathryn Andersen (RUBYKAT) | ||||||
1966 | perlkat AT katspace dot com | ||||||
1967 | http://www.katspace.com/tools/html_linklist/ | ||||||
1968 | |||||||
1969 | =head1 COPYRIGHT AND LICENCE | ||||||
1970 | |||||||
1971 | Copyright (c) 2006 by Kathryn Andersen | ||||||
1972 | |||||||
1973 | This program is free software; you can redistribute it and/or modify it | ||||||
1974 | under the same terms as Perl itself. | ||||||
1975 | |||||||
1976 | =cut | ||||||
1977 | |||||||
1978 | 1; # End of HTML::LinkList | ||||||
1979 | __END__ |