| blib/lib/HTML/BBCode.pm | |||
|---|---|---|---|
| Criterion | Covered | Total | % | 
| statement | 161 | 170 | 94.7 | 
| branch | 78 | 88 | 88.6 | 
| condition | 37 | 44 | 84.0 | 
| subroutine | 17 | 18 | 94.4 | 
| pod | 2 | 2 | 100.0 | 
| total | 295 | 322 | 91.6 | 
| line | stmt | bran | cond | sub | pod | time | code | 
|---|---|---|---|---|---|---|---|
| 1 | package HTML::BBCode; | ||||||
| 2 | |||||||
| 3 | =head1 NAME | ||||||
| 4 | |||||||
| 5 | HTML::BBCode - Perl extension for converting BBcode to HTML. | ||||||
| 6 | |||||||
| 7 | =head1 SYNOPSIS | ||||||
| 8 | |||||||
| 9 | use HTML::BBCode; | ||||||
| 10 | |||||||
| 11 | my $bbc = HTML::BBCode->new( \%options ); | ||||||
| 12 | my $html = $bbc->parse($bbcode); | ||||||
| 13 | |||||||
| 14 | # Input | ||||||
| 15 | print $bbc->{bbcode}; | ||||||
| 16 | |||||||
| 17 | # Output | ||||||
| 18 | print $bbc->{html}; | ||||||
| 19 | |||||||
| 20 | =head1 DESCRIPTION | ||||||
| 21 | |||||||
| 22 | C | ||||||
| 23 | boards- to its HTML equivalent. | ||||||
| 24 | |||||||
| 25 | Please note that, although this was the first BBCode module, it's by | ||||||
| 26 | far not the best nor fastest. It's also not heavilly maintained, so | ||||||
| 27 | you might want to look at L | ||||||
| 28 | |||||||
| 29 | =head2 METHODS | ||||||
| 30 | |||||||
| 31 | The following methods can be used | ||||||
| 32 | |||||||
| 33 | =head3 new | ||||||
| 34 | |||||||
| 35 | my $bbc = HTML::BBCode->new({ | ||||||
| 36 | allowed_tags => [ @bbcode_tags ], | ||||||
| 37 | stripscripts => 1, | ||||||
| 38 | linebreaks => 1, | ||||||
| 39 | }); | ||||||
| 40 | |||||||
| 41 | C | ||||||
| 42 | passed to it. The object's default configuration allows all BBCode to | ||||||
| 43 | be converted to the default HTML. | ||||||
| 44 | |||||||
| 45 | =head4 options | ||||||
| 46 | |||||||
| 47 | =over 5 | ||||||
| 48 | |||||||
| 49 | =item allowed_tags | ||||||
| 50 | |||||||
| 51 | Defaults to all currently know C | ||||||
| 52 | b, u, i, color, size, quote, code, list, url, email, img. With this | ||||||
| 53 | option, you can specify what BBCode tags you would like to convert. | ||||||
| 54 | |||||||
| 55 | =item stripscripts | ||||||
| 56 | |||||||
| 57 | Enabled by default, this option will remove all the XSS trickery (and | ||||||
| 58 | thus is probably best not to turn it off). | ||||||
| 59 | |||||||
| 60 | =item no_html | ||||||
| 61 | |||||||
| 62 | This option has been removed since version 2.0 | ||||||
| 63 | |||||||
| 64 | =item no_jslink | ||||||
| 65 | |||||||
| 66 | This option has been removed since version 2.0 | ||||||
| 67 | |||||||
| 68 | =item linebreaks | ||||||
| 69 | |||||||
| 70 | Disabled by default. | ||||||
| 71 | |||||||
| 72 | When true, will substitute linebreaks into HTML (' ') | ||||||
| 73 | |||||||
| 74 | =back | ||||||
| 75 | |||||||
| 76 | =head3 parse | ||||||
| 77 | |||||||
| 78 | my $html = $bbc->parse($bbcode); | ||||||
| 79 | |||||||
| 80 | Parses text supplied as a single scalar string and returns the HTML as | ||||||
| 81 | a single scalar string. | ||||||
| 82 | |||||||
| 83 | =head1 CAVEAT: API CHANGES | ||||||
| 84 | |||||||
| 85 | Please do note that the C | ||||||
| 86 | the new method have been removed since version 2.0 due to the XSS protection | ||||||
| 87 | (provided by L | ||||||
| 88 | break your current scripts (if you used the C | ||||||
| 89 | |||||||
| 90 | =head1 SEE ALSO | ||||||
| 91 | |||||||
| 92 | =over 4 | ||||||
| 93 | |||||||
| 94 | =item * L | ||||||
| 95 | |||||||
| 96 | =item * L | ||||||
| 97 | |||||||
| 98 | =item * L | ||||||
| 99 | |||||||
| 100 | =back | ||||||
| 101 | |||||||
| 102 | =head1 BUGS | ||||||
| 103 | |||||||
| 104 | C | ||||||
| 105 | |||||||
| 106 | =head1 AUTHOR | ||||||
| 107 | |||||||
| 108 | Menno Blom, E | ||||||
| 109 | |||||||
| 110 | =head1 COPYRIGHT AND LICENSE | ||||||
| 111 | |||||||
| 112 | Copyright (C) 2004-2009 by Menno Blom | ||||||
| 113 | |||||||
| 114 | This library is free software; you can redistribute it and/or modify | ||||||
| 115 | it under the same terms as Perl itself. | ||||||
| 116 | |||||||
| 117 | =cut | ||||||
| 118 | #------------------------------------------------------------------------------# | ||||||
| 119 | 17 | 17 | 563844 | use strict; | |||
| 17 | 42 | ||||||
| 17 | 890 | ||||||
| 120 | 17 | 17 | 126 | use warnings; | |||
| 17 | 35 | ||||||
| 17 | 579 | ||||||
| 121 | 17 | 17 | 10255 | use HTML::BBCode::StripScripts; | |||
| 17 | 60 | ||||||
| 17 | 61218 | ||||||
| 122 | |||||||
| 123 | our $VERSION = '2.07'; | ||||||
| 124 | our @bbcode_tags = qw(code quote b u i color size list url email img); | ||||||
| 125 | |||||||
| 126 | sub new { | ||||||
| 127 | 24 | 24 | 1 | 260 | my ($class, $args) = @_; | ||
| 128 | 24 | 100 | 168 | $args ||= {}; | |||
| 129 | 24 | 50 | 122 | $class->_croak("Options must be a hash reference") | |||
| 130 | if ref($args) ne 'HASH'; | ||||||
| 131 | 24 | 61 | my $self = {}; | ||||
| 132 | 24 | 71 | bless $self, $class; | ||||
| 133 | 24 | 50 | 124 | $self->_init($args) or return undef; | |||
| 134 | |||||||
| 135 | 24 | 95 | return $self; | ||||
| 136 | } | ||||||
| 137 | |||||||
| 138 | sub _init { | ||||||
| 139 | 24 | 24 | 56 | my ($self, $args) = @_; | |||
| 140 | |||||||
| 141 | 24 | 399 | my %html_tags = ( | ||||
| 142 | code       => ' Code:'. | ||||||
| 143 | ' %s', | ||||||
| 144 | quote      => ' %s'. | ||||||
| 145 | ' %s', | ||||||
| 146 | b => '%s', | ||||||
| 147 | u => '%s', | ||||||
| 148 | i => '%s', | ||||||
| 149 | color => '%s', | ||||||
| 150 | size => '%s', | ||||||
| 151 | url => '%s', | ||||||
| 152 | email => '%s', | ||||||
| 153 | img        => ' | ||||||
| 154 | ul         => ' 
 | ||||||
| 155 | ol_number  => ' 
 | ||||||
| 156 | ol_alpha   => ' 
 | ||||||
| 157 | ); | ||||||
| 158 | |||||||
| 159 | 24 | 173 | my %options = ( | ||||
| 160 | allowed_tags=> \@bbcode_tags, | ||||||
| 161 | html_tags => \%html_tags, | ||||||
| 162 | stripscripts => 1, | ||||||
| 163 | linebreaks => 0, | ||||||
| 164 | 24 | 82 | %{ $args }, | ||||
| 165 | ); | ||||||
| 166 | 24 | 153 | $self->{options} = \%options; | ||||
| 167 | |||||||
| 168 | 24 | 1545 | $self->{'hss'} = HTML::BBCode::StripScripts->new({ | ||||
| 169 | Context => 'Flow', | ||||||
| 170 | AllowSrc => 1, | ||||||
| 171 | AllowMailto => 1, | ||||||
| 172 | AllowHref => 1, | ||||||
| 173 | AllowRelURL => 1, | ||||||
| 174 | EscapeFiltered => 1, | ||||||
| 175 | BanAllBut => [qr/a div img li ol span ul/], | ||||||
| 176 | Rules => { | ||||||
| 177 | br => 1, | ||||||
| 178 | img => { | ||||||
| 179 | required => ['src'], | ||||||
| 180 | 'src' => 1, | ||||||
| 181 | 'alt' => 1, | ||||||
| 182 | '*' => 0, | ||||||
| 183 | }, | ||||||
| 184 | a => { | ||||||
| 185 | required => ['href'], | ||||||
| 186 | 'href' => 1, | ||||||
| 187 | '*' => 0, | ||||||
| 188 | }, | ||||||
| 189 | img => { | ||||||
| 190 | 'src' => 1, | ||||||
| 191 | 'alt' => 1, | ||||||
| 192 | '*' => 0, | ||||||
| 193 | }, | ||||||
| 194 | div => { | ||||||
| 195 | class => qr{^bbcode_}, | ||||||
| 196 | '*' => 0, | ||||||
| 197 | }, | ||||||
| 198 | span => { | ||||||
| 199 | style => \&_filter_style, | ||||||
| 200 | '*' => 0, | ||||||
| 201 | }, | ||||||
| 202 | ol => { | ||||||
| 203 | style => qr/^list-style-type:lower-alpha$/, | ||||||
| 204 | '*' => 0, | ||||||
| 205 | }, | ||||||
| 206 | ul => 1, | ||||||
| 207 | li => 1, | ||||||
| 208 | } | ||||||
| 209 | }); | ||||||
| 210 | |||||||
| 211 | 24 | 8448 | return $self; | ||||
| 212 | } | ||||||
| 213 | |||||||
| 214 | # Parse the input! | ||||||
| 215 | sub parse { | ||||||
| 216 | 70 | 70 | 1 | 19090 | my ($self, $bbcode) = @_; | ||
| 217 | 70 | 100 | 215 | return if(!defined $bbcode); | |||
| 218 | |||||||
| 219 | 69 | 174 | $self->{_stack} = []; | ||||
| 220 | 69 | 160 | $self->{_in_code_block} = 0; | ||||
| 221 | 69 | 137 | $self->{_skip_nest} = ''; | ||||
| 222 | 69 | 115 | $self->{_nest_count} = 0; | ||||
| 223 | 69 | 107 | $self->{_nest_count_stack} = 0; | ||||
| 224 | 69 | 241 | $self->{_dont_nest} = ['code', 'url', 'email', 'img']; | ||||
| 225 | 69 | 154 | $self->{bbcode} = ''; | ||||
| 226 | 69 | 410 | $self->{html} = ''; | ||||
| 227 | |||||||
| 228 | 69 | 119 | $self->{bbcode} = $bbcode; | ||||
| 229 | 69 | 109 | my $input = $bbcode; | ||||
| 230 | |||||||
| 231 | main: | ||||||
| 232 | 69 | 89 | while(1) { | ||||
| 233 | # End tag | ||||||
| 234 | 374 | 100 | 2024 | if($input =~ /^(\[\/[^\]]+\])/s) { | |||
| 100 | |||||||
| 100 | |||||||
| 100 | |||||||
| 235 | 84 | 170 | my $end = lc $1; | ||||
| 236 | 84 | 100 | 66 | 1876 | if(($self->{_skip_nest} ne '' && $end ne "[/$self->{_skip_nest}]") || | ||
| 100 | |||||||
| 33 | |||||||
| 237 | ($self->{_in_code_block} && $end ne "[/code]")) { | ||||||
| 238 | 1 | 3 | _content($self, $end); | ||||
| 239 | } else { | ||||||
| 240 | 83 | 191 | _end_tag($self, $end); | ||||
| 241 | } | ||||||
| 242 | 84 | 181 | $input = $'; | ||||
| 243 | } | ||||||
| 244 | |||||||
| 245 | # Opening tag | ||||||
| 246 | elsif($input =~ /^(\[[^\]]+\])/s ) { | ||||||
| 247 | 100 | 100 | 233 | if($self->{_in_code_block}) { | |||
| 248 | 1 | 3 | _content($self, $1); | ||||
| 249 | } else { | ||||||
| 250 | 99 | 257 | _open_tag($self, $1); | ||||
| 251 | } | ||||||
| 252 | 100 | 233 | $input = $'; | ||||
| 253 | } | ||||||
| 254 | |||||||
| 255 | # None BBCode content till next tag | ||||||
| 256 | elsif($input =~ /^([^\[]+)/s) { | ||||||
| 257 | 118 | 245 | _content($self, $1); | ||||
| 258 | 118 | 239 | $input = $'; | ||||
| 259 | } | ||||||
| 260 | |||||||
| 261 | # BUG #14138 unmatched bracket, content till end of input | ||||||
| 262 | elsif($input =~ /^(.+)$/s) { | ||||||
| 263 | 3 | 7 | _content($self, $1); | ||||
| 264 | 3 | 7 | $input = $'; | ||||
| 265 | } | ||||||
| 266 | |||||||
| 267 | # Now what? | ||||||
| 268 | else { | ||||||
| 269 | 69 | 50 | 206 | last main if(!$input); # We're at the end now, stop parsing! | |||
| 270 | } | ||||||
| 271 | } | ||||||
| 272 | 69 | 110 | $self->{html} = join('', @{$self->{_stack}}); | ||||
| 69 | 215 | ||||||
| 273 | 69 | 100 | 330 | return $self->{options}->{stripscripts} ? $self->_stripscripts() : $self->{html}; | |||
| 274 | } | ||||||
| 275 | |||||||
| 276 | sub _open_tag { | ||||||
| 277 | 99 | 99 | 224 | my ($self, $open) = @_; | |||
| 278 | 99 | 523 | my ($tag, $rest) = $open =~ m/\[([^=\]]+)(.*)?\]/s; # Don't do this! ARGH! | ||||
| 279 | 99 | 184 | $tag = lc $tag; | ||||
| 280 | 99 | 100 | 100 | 241 | if(_dont_nest($self, $tag) && $tag eq 'img') { | ||
| 281 | 9 | 18 | $self->{_skip_nest} = $tag; | ||||
| 282 | } | ||||||
| 283 | 99 | 100 | 288 | if($self->{_skip_nest} eq $tag) { | |||
| 284 | 9 | 16 | $self->{_nest_count}++; | ||||
| 285 | 9 | 15 | $self->{_nest_count_stack}++; | ||||
| 286 | } | ||||||
| 287 | 99 | 100 | 216 | $self->{_in_code_block}++ if($tag eq 'code'); | |||
| 288 | 99 | 118 | push @{$self->{_stack}}, '['.$tag.$rest.']'; | ||||
| 99 | 369 | ||||||
| 289 | } | ||||||
| 290 | |||||||
| 291 | sub _content { | ||||||
| 292 | 123 | 123 | 259 | my ($self, $content) = @_; | |||
| 293 | 123 | 1284 | $content =~ s|\r*||gs; | ||||
| 294 | 123 | 100 | 100 | 484 | $content =~ s|\n| \n|gs if($self->{options}->{linebreaks} && | ||
| 295 | $self->{_in_code_block} == 0); | ||||||
| 296 | 123 | 154 | push @{$self->{_stack}}, $content; | ||||
| 123 | 373 | ||||||
| 297 | } | ||||||
| 298 | |||||||
| 299 | sub _end_tag { | ||||||
| 300 | 83 | 83 | 142 | my ($self, $end) = @_; | |||
| 301 | 83 | 97 | my ($tag, $arg); | ||||
| 302 | 83 | 157 | my @buf = ( $end ); | ||||
| 303 | |||||||
| 304 | 83 | 50 | 66 | 416 | if("[/$self->{_skip_nest}]" eq $end && $self->{_nest_count} > 1) { | ||
| 305 | 0 | 0 | push @{$self->{_stack}}, $end; | ||||
| 0 | 0 | ||||||
| 306 | 0 | 0 | $self->{_nest_count}--; | ||||
| 307 | 0 | 0 | return; | ||||
| 308 | } | ||||||
| 309 | |||||||
| 310 | 83 | 100 | 354 | $self->{_in_code_block} = 0 if($end eq '[/code]'); | |||
| 311 | |||||||
| 312 | # Loop through the stack | ||||||
| 313 | 83 | 113 | while(1) { | ||||
| 314 | 204 | 220 | my $item = pop(@{$self->{_stack}}); | ||||
| 204 | 391 | ||||||
| 315 | 204 | 330 | push @buf, $item; | ||||
| 316 | |||||||
| 317 | 204 | 100 | 566 | if(!defined $item) { | |||
| 318 | 2 | 100 | 7 | map { push @{$self->{_stack}}, $_ if($_) } reverse @buf; | |||
| 6 | 19 | ||||||
| 4 | 15 | ||||||
| 319 | 2 | 3 | last; | ||||
| 320 | } | ||||||
| 321 | |||||||
| 322 | |||||||
| 323 | 202 | 100 | 551 | if("[$self->{_skip_nest}]" eq "$item") { | |||
| 324 | 5 | 16 | $self->{_nest_count_stack}--; | ||||
| 325 | 5 | 50 | 18 | next if($self->{_nest_count_stack} > 0); | |||
| 326 | } | ||||||
| 327 | |||||||
| 328 | 202 | 100 | 100 | 609 | $self->{_nest_count}-- | ||
| 329 | if("[/$self->{_skip_nest}]" eq $end && $self->{_nest_count} > 0) ; | ||||||
| 330 | |||||||
| 331 | |||||||
| 332 | 202 | 100 | 829 | if($item =~ /\[([^=\]]+).*\]/s) { | |||
| 333 | 101 | 192 | $tag = $1; | ||||
| 334 | 101 | 100 | 66 | 571 | if ($tag && $end eq "[/$tag]") { | ||
| 335 | 81 | 100 | 99 | push @{$self->{_stack}}, (_is_allowed($self, $tag)) | |||
| 81 | 254 | ||||||
| 336 | ? _do_BB($self, @buf) | ||||||
| 337 | : reverse @buf; | ||||||
| 338 | # Clear the _skip_nest? | ||||||
| 339 | 81 | 100 | 66 | 469 | $self->{_skip_nest} = '' if(defined $self->{_skip_nest} && | ||
| 340 | $tag eq $self->{_skip_nest}); | ||||||
| 341 | 81 | 138 | last; | ||||
| 342 | } | ||||||
| 343 | } | ||||||
| 344 | } | ||||||
| 345 | 83 | 237 | $self->{_nest_count_stack} = 0; | ||||
| 346 | } | ||||||
| 347 | |||||||
| 348 | sub _do_BB { | ||||||
| 349 | 75 | 75 | 203 | my ($self, @buf) = @_; | |||
| 350 | 75 | 95 | my ($tag, $attr); | ||||
| 351 | 0 | 0 | my $html; | ||||
| 352 | |||||||
| 353 | # Get the opening tag | ||||||
| 354 | 75 | 233 | my $open = pop(@buf); | ||||
| 355 | # We prefer to read in non-reverse way | ||||||
| 356 | 75 | 120 | @buf = reverse @buf; | ||||
| 357 | # Closing tag is kinda useless, pop it | ||||||
| 358 | 75 | 93 | pop(@buf); | ||||
| 359 | # Rest should be content; | ||||||
| 360 | 75 | 176 | my $content = join(' ', @buf); | ||||
| 361 | |||||||
| 362 | # What are we dealing with anyway? Any attributes maybe? | ||||||
| 363 | 75 | 50 | 439 | if($open =~ /\[([^=\]]+)=?([^\]]+)?]/) { | |||
| 364 | 75 | 127 | $tag = $1; | ||||
| 365 | 75 | 146 | $attr = $2; | ||||
| 366 | } | ||||||
| 367 | |||||||
| 368 | # Kludgy way to handle specific BBCodes ... | ||||||
| 369 | 75 | 100 | 100 | 685 | if($tag eq 'quote') { | ||
| 100 | 100 | ||||||
| 100 | |||||||
| 100 | |||||||
| 100 | |||||||
| 370 | 8 | 100 | 64 | $html = sprintf($self->{options}->{html_tags}->{quote}, | |||
| 371 | ($attr) ? "$attr wrote:" | ||||||
| 372 | : "Quote:", | ||||||
| 373 | $content | ||||||
| 374 | ); | ||||||
| 375 | } elsif($tag eq 'code') { | ||||||
| 376 | 3 | 22 | $html = sprintf($self->{options}->{html_tags}->{code}, _code($content)); | ||||
| 377 | } elsif($tag eq 'list') { | ||||||
| 378 | 8 | 29 | $html = _list($self, $attr, $content); | ||||
| 379 | } elsif(($tag eq 'email' || $tag eq 'url') && !$attr) { | ||||||
| 380 | 4 | 24 | $html = sprintf($self->{options}->{html_tags}->{$tag}, $content,$content); | ||||
| 381 | } elsif ($attr) { | ||||||
| 382 | 24 | 159 | $html = sprintf($self->{options}->{html_tags}->{$tag}, $attr, $content); | ||||
| 383 | } else { | ||||||
| 384 | 28 | 145 | $html = sprintf($self->{options}->{html_tags}->{$tag}, $content); | ||||
| 385 | } | ||||||
| 386 | # Return ... | ||||||
| 387 | 75 | 224 | return $html; | ||||
| 388 | } | ||||||
| 389 | |||||||
| 390 | sub _is_allowed { | ||||||
| 391 | 81 | 81 | 126 | my ($self, $check) = @_; | |||
| 392 | 447 | 100 | 1258 | map { | |||
| 393 | 81 | 202 | return 1 if ($_ eq $check); | ||||
| 394 | 81 | 98 | } @{$self->{options}->{allowed_tags}}; | ||||
| 395 | 6 | 19 | return 0; | ||||
| 396 | } | ||||||
| 397 | |||||||
| 398 | sub _dont_nest { | ||||||
| 399 | 99 | 99 | 143 | my ($self, $check) = @_; | |||
| 400 | 345 | 100 | 1145 | map { | |||
| 401 | 99 | 228 | return 1 if($_ eq $check); | ||||
| 402 | 99 | 139 | } @{$self->{_dont_nest}}; | ||||
| 403 | 65 | 207 | return 0; | ||||
| 404 | } | ||||||
| 405 | |||||||
| 406 | sub _code { | ||||||
| 407 | 3 | 3 | 6 | my $code = shift; | |||
| 408 | 3 | 10 | $code =~ s|^\s+?[\n\r]+?||; | ||||
| 409 | 3 | 8 | $code =~ s|<|\<|g; | ||||
| 410 | 3 | 9 | $code =~ s|>|\>|g; | ||||
| 411 | 3 | 11 | $code =~ s|\[|\[|g; | ||||
| 412 | 3 | 12 | $code =~ s|\]|\]|g; | ||||
| 413 | 3 | 10 | $code =~ s| |\ |g; | ||||
| 414 | 3 | 9 | $code =~ s|\n| |g; | ||||
| 415 | 3 | 19 | return $code; | ||||
| 416 | } | ||||||
| 417 | |||||||
| 418 | sub _list { | ||||||
| 419 | 8 | 8 | 18 | my ($self, $attr, $content) = @_; | |||
| 420 | 8 | 18 | $content =~ s|^ [\s\r\n]*|\n|s; | ||||
| 421 | 8 | 43 | $content =~ s|\[\*\]([^\[]+)|_list_removelastbr($1)|egs; | ||||
| 18 | 65 | ||||||
| 422 | 8 | 20 | $content =~ s| $|\n|s; | ||||
| 423 | 8 | 100 | 23 | if($attr) { | |||
| 424 | 4 | 100 | 28 | return sprintf($self->{options}->{html_tags}->{ol_number}, $content) | |||
| 425 | if($attr =~ /^\d/); | ||||||
| 426 | 2 | 50 | 55 | return sprintf($self->{options}->{html_tags}->{ol_alpha}, $content) | |||
| 427 | if($attr =~ /^\D/); | ||||||
| 428 | } else { | ||||||
| 429 | 4 | 36 | return sprintf($self->{options}->{html_tags}->{ul}, $content); | ||||
| 430 | } | ||||||
| 431 | } | ||||||
| 432 | |||||||
| 433 | sub _list_removelastbr { | ||||||
| 434 | 18 | 18 | 38 | my $content = shift; | |||
| 435 | 18 | 32 | $content =~ s| [\s\r\n]*$||; | ||||
| 436 | 18 | 51 | $content =~ s|^\s*||; | ||||
| 437 | 18 | 71 | $content =~ s|\s*$||; | ||||
| 438 | 18 | 78 | return " | ||||
| 439 | } | ||||||
| 440 | |||||||
| 441 | sub _stripscripts { | ||||||
| 442 | 67 | 67 | 96 | my $self = shift; | |||
| 443 | 67 | 376 | $self->{'html'} = $self->{'hss'}->filter_html($self->{'html'}); | ||||
| 444 | 67 | 26575 | return $self->{'html'}; | ||||
| 445 | } | ||||||
| 446 | |||||||
| 447 | sub _filter_style { | ||||||
| 448 | 29 | 29 | 6236 | my ($filter, $tag, $attr_name, $attr_val) = @_; | |||
| 449 | 29 | 100 | 100 | 216 | if ($attr_val eq 'font-weight:bold' | ||
| 100 | |||||||
| 66 | |||||||
| 450 | or $attr_val eq 'text-decoration:underline' | ||||||
| 451 | or $attr_val eq 'font-style:italic' | ||||||
| 452 | or $attr_val eq 'list-style-type') { | ||||||
| 453 | 22 | 60 | return $attr_val; | ||||
| 454 | } | ||||||
| 455 | 7 | 100 | 43 | if ( my ($color) = $attr_val =~ /^color:(.*)/ ) { | |||
| 456 | 4 | 26 | my @html_color = qw/ | ||||
| 457 | black gray maroon red green lime olive yellow | ||||||
| 458 | navy blue purple fuchsia teal aqua silver white | ||||||
| 459 | /; | ||||||
| 460 | 4 | 50 | 16 | return $attr_val if $color =~ /^#[a-fA-F\d]{6}$/; | |||
| 461 | 4 | 50 | 16 | return $attr_val if $color =~ /^#[a-fA-F\d]{3}$/; | |||
| 462 | 4 | 50 | 10 | return $attr_val if grep { $color eq $_ } @html_color; | |||
| 64 | 121 | ||||||
| 463 | 0 | 0 | return undef; | ||||
| 464 | } | ||||||
| 465 | 3 | 100 | 16 | if ( $attr_val =~ /font-size:\d+px/ ) { | |||
| 466 | 2 | 7 | return $attr_val; | ||||
| 467 | } | ||||||
| 468 | 1 | 4 | return undef; | ||||
| 469 | } | ||||||
| 470 | |||||||
| 471 | sub _croak { | ||||||
| 472 | 0 | 0 | my ($class, @error) = @_; | ||||
| 473 | 0 | require Carp; | |||||
| 474 | 0 | Carp::croak(@error); | |||||
| 475 | } | ||||||
| 476 | |||||||
| 477 | 1; |