blib/lib/HTML/TagCloud.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 104 | 127 | 81.8 |
branch | 26 | 36 | 72.2 |
condition | 2 | 6 | 33.3 |
subroutine | 16 | 19 | 84.2 |
pod | 9 | 9 | 100.0 |
total | 157 | 197 | 79.7 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | package HTML::TagCloud; | ||||||
2 | 1 | 1 | 894 | use strict; | |||
1 | 3 | ||||||
1 | 45 | ||||||
3 | 1 | 1 | 6 | use warnings; | |||
1 | 3 | ||||||
1 | 71 | ||||||
4 | our $VERSION = '0.38'; | ||||||
5 | |||||||
6 | 1 | 1 | 6 | use constant EMPTY_STRING => q{}; | |||
1 | 2 | ||||||
1 | 1535 | ||||||
7 | |||||||
8 | sub new { | ||||||
9 | 9 | 9 | 1 | 5769 | my $class = shift; | ||
10 | 9 | 54 | my $self = { | ||||
11 | counts => {}, | ||||||
12 | urls => {}, | ||||||
13 | category_for => {}, | ||||||
14 | categories => [], | ||||||
15 | levels => 24, | ||||||
16 | distinguish_adjacent_tags => 0, | ||||||
17 | @_ | ||||||
18 | }; | ||||||
19 | 9 | 26 | bless $self, $class; | ||||
20 | 9 | 19 | return $self; | ||||
21 | } | ||||||
22 | |||||||
23 | sub add { | ||||||
24 | 359 | 359 | 1 | 2846 | my ( $self, $tag, $url, $count, $category ) = @_; | ||
25 | 359 | 572 | $self->{counts}->{$tag} = $count; | ||||
26 | 359 | 527 | $self->{urls}->{$tag} = $url; | ||||
27 | 359 | 50 | 33 | 305 | if ( scalar @{ $self->{categories} } > 0 && defined $category ) { | ||
359 | 987 | ||||||
28 | 0 | 0 | $self->{category_for}->{$tag} = $category; | ||||
29 | } | ||||||
30 | } | ||||||
31 | |||||||
32 | sub add_static { | ||||||
33 | 10 | 10 | 1 | 49 | my ( $self, $tag, $count, $category ) = @_; | ||
34 | 10 | 22 | $self->{counts}->{$tag} = $count; | ||||
35 | |||||||
36 | 10 | 50 | 33 | 10 | if ( scalar @{ $self->{categories} } > 0 && defined $category ) { | ||
10 | 43 | ||||||
37 | 0 | 0 | $self->{category_for}->{$tag} = $category; | ||||
38 | } | ||||||
39 | } | ||||||
40 | |||||||
41 | sub css { | ||||||
42 | 3 | 3 | 1 | 30 | my ($self) = @_; | ||
43 | 3 | 7 | my $css = q( | ||||
44 | #htmltagcloud { | ||||||
45 | text-align: center; | ||||||
46 | line-height: 1; | ||||||
47 | } | ||||||
48 | ); | ||||||
49 | 3 | 11 | foreach my $level ( 0 .. $self->{levels} ) { | ||||
50 | 75 | 100 | 137 | if ( $self->{distinguish_adjacent_tags} ) { | |||
51 | 25 | 43 | $css .= $self->_css_for_tag( $level, 'even' ); | ||||
52 | 25 | 42 | $css .= $self->_css_for_tag( $level, 'odd' ); | ||||
53 | } | ||||||
54 | else { | ||||||
55 | 50 | 78 | $css .= $self->_css_for_tag( $level, q{} ); | ||||
56 | } | ||||||
57 | } | ||||||
58 | 3 | 27 | return $css; | ||||
59 | } | ||||||
60 | |||||||
61 | sub _css_for_tag { | ||||||
62 | 100 | 100 | 127 | my ( $self, $level, $subclass ) = @_; | |||
63 | 100 | 113 | my $font = 12 + $level; | ||||
64 | 100 | 313 | return <<"END_OF_TAG"; | ||||
65 | span.tagcloud${level}${subclass} {font-size: ${font}px;} | ||||||
66 | span.tagcloud${level}${subclass} a {text-decoration: none;} | ||||||
67 | END_OF_TAG | ||||||
68 | } | ||||||
69 | |||||||
70 | sub tags { | ||||||
71 | 15 | 15 | 1 | 17 | my ( $self, $limit ) = @_; | ||
72 | 15 | 28 | my $counts = $self->{counts}; | ||||
73 | 15 | 21 | my $urls = $self->{urls}; | ||||
74 | 15 | 22 | my $category_for = $self->{category_for}; | ||||
75 | 15 | 50 | 309 | my @tags = sort { $counts->{$b} <=> $counts->{$a} || $a cmp $b } keys %$counts; | |||
17732 | 34295 | ||||||
76 | 15 | 100 | 205 | @tags = splice( @tags, 0, $limit ) if defined $limit; | |||
77 | |||||||
78 | 15 | 100 | 40 | return unless scalar @tags; | |||
79 | |||||||
80 | 14 | 62 | my $min = log( $counts->{ $tags[-1] } ); | ||||
81 | 14 | 30 | my $max = log( $counts->{ $tags[0] } ); | ||||
82 | 14 | 16 | my $factor; | ||||
83 | |||||||
84 | # special case all tags having the same count | ||||||
85 | 14 | 100 | 45 | if ( $max - $min == 0 ) { | |||
86 | 9 | 14 | $min = $min - $self->{levels}; | ||||
87 | 9 | 12 | $factor = 1; | ||||
88 | } | ||||||
89 | else { | ||||||
90 | 5 | 15 | $factor = $self->{levels} / ( $max - $min ); | ||||
91 | } | ||||||
92 | |||||||
93 | 14 | 100 | 36 | if ( scalar @tags < $self->{levels} ) { | |||
94 | 13 | 28 | $factor *= ( scalar @tags / $self->{levels} ); | ||||
95 | } | ||||||
96 | 14 | 18 | my @tag_items; | ||||
97 | 14 | 160 | foreach my $tag ( sort @tags ) { | ||||
98 | 402 | 358 | my $tag_item; | ||||
99 | 402 | 657 | $tag_item->{name} = $tag; | ||||
100 | 402 | 526 | $tag_item->{count} = $counts->{$tag}; | ||||
101 | 402 | 604 | $tag_item->{url} = $urls->{$tag}; | ||||
102 | 402 | 797 | $tag_item->{level} | ||||
103 | = int( ( log( $tag_item->{count} ) - $min ) * $factor ); | ||||||
104 | 402 | 476 | $tag_item->{category} = $category_for->{$tag}; | ||||
105 | 402 | 578 | push @tag_items, $tag_item; | ||||
106 | } | ||||||
107 | 14 | 168 | return @tag_items; | ||||
108 | } | ||||||
109 | |||||||
110 | sub html { | ||||||
111 | 15 | 15 | 1 | 4902 | my ( $self, $limit ) = @_; | ||
112 | 15 | 60 | my $html | ||||
113 | 15 | 50 | 17 | = scalar @{ $self->{categories} } > 0 | |||
114 | ? $self->html_with_categories($limit) | ||||||
115 | : $self->html_without_categories($limit); | ||||||
116 | 15 | 257 | return $html; | ||||
117 | } | ||||||
118 | |||||||
119 | sub html_without_categories { | ||||||
120 | 15 | 15 | 1 | 20 | my ( $self, $limit ) = @_; | ||
121 | 15 | 31 | my $html = $self->_html_for( [ $self->tags($limit) ] ); | ||||
122 | } | ||||||
123 | |||||||
124 | sub _html_for { | ||||||
125 | 15 | 15 | 21 | my ( $self, $tags_ref ) = @_; | |||
126 | 15 | 22 | my $ntags = scalar( @{$tags_ref} ); | ||||
15 | 19 | ||||||
127 | 15 | 100 | 43 | return EMPTY_STRING if $ntags == 0; | |||
128 | |||||||
129 | # Format the HTML division. | ||||||
130 | 14 | 100 | 72 | my $html | |||
131 | = $ntags == 1 | ||||||
132 | ? $self->_html_for_single_tag($tags_ref) | ||||||
133 | : $self->_html_for_multiple_tags($tags_ref); | ||||||
134 | |||||||
135 | 14 | 38 | return $html; | ||||
136 | } | ||||||
137 | |||||||
138 | sub _html_for_single_tag { | ||||||
139 | 3 | 3 | 6 | my ( $self, $tags_ref ) = @_; | |||
140 | |||||||
141 | # Format the contents of the div. | ||||||
142 | 3 | 4 | my $tag_ref = $tags_ref->[0]; | ||||
143 | 3 | 7 | my $html = $self->_format_span( @{$tag_ref}{qw(name url)}, 1, 1 ); | ||||
3 | 12 | ||||||
144 | |||||||
145 | 3 | 10 | return qq{ $html \n}; |
||||
146 | } | ||||||
147 | |||||||
148 | sub _html_for_multiple_tags { | ||||||
149 | 11 | 11 | 17 | my ( $self, $tags_ref ) = @_; | |||
150 | |||||||
151 | # Format the contents of the div. | ||||||
152 | 11 | 16 | my $html = EMPTY_STRING; | ||||
153 | 11 | 12 | my $is_even = 1; | ||||
154 | 11 | 24 | foreach my $tag ( @{$tags_ref} ) { | ||||
11 | 20 | ||||||
155 | 399 | 1030 | my $span | ||||
156 | 399 | 429 | = $self->_format_span( @{$tag}{qw(name url level)}, $is_even ); | ||||
157 | 399 | 788 | $html .= "$span\n"; | ||||
158 | 399 | 574 | $is_even = !$is_even; | ||||
159 | } | ||||||
160 | 11 | 66 | $html = qq{ |
||||
161 | $html}; | ||||||
162 | 11 | 56 | return $html; | ||||
163 | } | ||||||
164 | |||||||
165 | sub html_with_categories { | ||||||
166 | 0 | 0 | 1 | 0 | my ( $self, $limit ) = @_; | ||
167 | |||||||
168 | # Get the collection of tags, organized by category. | ||||||
169 | 0 | 0 | my $tags_by_category_ref = $self->_tags_by_category($limit); | ||||
170 | 0 | 0 | 0 | return EMPTY_STRING if !defined $tags_by_category_ref; | |||
171 | |||||||
172 | # Format the HTML document. | ||||||
173 | 0 | 0 | my $html = EMPTY_STRING; | ||||
174 | 0 | 0 | CATEGORY: | ||||
175 | 0 | 0 | for my $category ( @{ $self->{categories} } ) { | ||||
176 | 0 | 0 | my $tags_ref = $tags_by_category_ref->{$category}; | ||||
177 | 0 | 0 | $html .= $self->_html_for_category( $category, $tags_ref ); | ||||
178 | } | ||||||
179 | |||||||
180 | 0 | 0 | return $html; | ||||
181 | } | ||||||
182 | |||||||
183 | sub _html_for_category { | ||||||
184 | 0 | 0 | 0 | my ( $self, $category, $tags_ref ) = @_; | |||
185 | |||||||
186 | # Format the HTML. | ||||||
187 | 0 | 0 | my $html | ||||
188 | = qq{ } |
||||||
189 | . $self->_html_for($tags_ref) | ||||||
190 | . qq{}; | ||||||
191 | |||||||
192 | 0 | 0 | return $html; | ||||
193 | } | ||||||
194 | |||||||
195 | sub _tags_by_category { | ||||||
196 | 0 | 0 | 0 | my ( $self, $limit ) = @_; | |||
197 | |||||||
198 | # Get the tags. | ||||||
199 | 0 | 0 | my @tags = $self->tags($limit); | ||||
200 | 0 | 0 | 0 | return if scalar @tags == 0; | |||
201 | |||||||
202 | # Build the categorized collection of tags. | ||||||
203 | 0 | 0 | my %tags_by_category; | ||||
204 | 0 | 0 | for my $tag_ref (@tags) { | ||||
205 | 0 | 0 | 0 | my $category | |||
206 | = defined $tag_ref->{category} | ||||||
207 | ? $tag_ref->{category} | ||||||
208 | : '__unknown__'; | ||||||
209 | 0 | 0 | push @{ $tags_by_category{$category} }, $tag_ref; | ||||
0 | 0 | ||||||
210 | } | ||||||
211 | |||||||
212 | 0 | 0 | return \%tags_by_category; | ||||
213 | } | ||||||
214 | |||||||
215 | sub html_and_css { | ||||||
216 | 1 | 1 | 1 | 1233 | my ( $self, $limit ) = @_; | ||
217 | 1 | 6 | my $html = qq{"; | ||||
218 | 1 | 3 | $html .= $self->html($limit); | ||||
219 | 1 | 8 | return $html; | ||||
220 | } | ||||||
221 | |||||||
222 | sub _format_span { | ||||||
223 | 402 | 402 | 613 | my ( $self, $name, $url, $level, $is_even ) = @_; | |||
224 | 402 | 469 | my $subclass = q{}; | ||||
225 | 402 | 100 | 783 | if ( $self->{distinguish_adjacent_tags} ) { | |||
226 | 10 | 100 | 22 | $subclass = $is_even ? 'even' : 'odd'; | |||
227 | } | ||||||
228 | 402 | 610 | my $span_class = qq{tagcloud$level$subclass}; | ||||
229 | 402 | 1597 | my $span = qq{}; | ||||
230 | 402 | 100 | 770 | if ( defined $url ) { | |||
231 | 392 | 705 | $span .= qq{}; | ||||
232 | } | ||||||
233 | 402 | 447 | $span .= $name; | ||||
234 | 402 | 100 | 687 | if ( defined $url ) { | |||
235 | 392 | 438 | $span .= qq{}; | ||||
236 | } | ||||||
237 | 402 | 803 | $span .= qq{}; | ||||
238 | } | ||||||
239 | |||||||
240 | 1; | ||||||
241 | |||||||
242 | __END__ |