package DocSet::Source::HTML;
use strict;
use warnings;
use DocSet::Util;
use vars qw(@ISA);
require DocSet::Doc;
@ISA = qw(DocSet::Doc);
use constant ENCODE_CHARS => '<>&" ';
sub retrieve_meta_data {
my ($self) = @_;
$self->parse;
use Pod::POM::View::HTML;
my $mode = 'Pod::POM::View::HTML';
#print Pod::POM::View::HTML->print($pom);
my $title = $self->{parsed_tree}->{title};
$self->{meta} =
{
title => $title,
stitle => $title, # stitle is the same as title in docs
abstract => $self->{parsed_tree}->{abstract} || '',
link => $self->{rel_dst_path},
};
# there is no autogenerated TOC for HTML files
}
my %linkElements = ( # from HTML::Element.pm
body => 'background',
base => 'href',
a => 'href',
img => [qw(src lowsrc usemap)], # lowsrc is a Netscape invention
form => 'action',
input => 'src',
'link' => 'href', # need quoting since link is a perl builtin
frame => 'src',
applet => 'codebase',
area => 'href',
);
my %tag_attr;
for my $tag (keys %linkElements) {
my $tagval = $linkElements{$tag};
for my $attr (ref $tagval ? @$tagval : $tagval) {
$tag_attr{"$tag $attr"}++;
}
}
sub parse {
my ($self) = @_;
# already parsed
return if exists $self->{parsed_tree} && $self->{parsed_tree};
require HTML::Parser;
require HTML::Entities;
my $new_content;
# this parsing is for fixing up unsafe chars in URLs
{
# accum_h(self, $text)
sub accum_h {
my $self = shift;
#print "[ @_ ]";
$self->{content} .= join '', @_;
}
# encode unsafe chars in the URL attributes
sub start_h {
my ($self, $tagname, $attr, $text) = @_;
# store away the HTML as is
unless ($linkElements{$tagname}) {
accum_h($self, $text);
return;
}
# escape those that include link elements
accum_h($self, qq{<$tagname});
for (keys %$attr) {
accum_h($self, qq{ $_="});
my $val = $attr->{$_};
if ($tag_attr{"$tagname $_"}) {
$val = HTML::Entities::encode($val, ENCODE_CHARS);
}
accum_h($self, qq{$val"});
}
accum_h($self, qq{>});
}
sub end_h {
my ($self, $tagname) = @_;
accum_h($self, "$tagname>");
}
sub text_h {
my ($self, $text) = @_;
accum_h($self, $text);
}
my $p = HTML::Parser->new(
api_version => 3,
start_h => [\&start_h, "self, tagname, attr, text"],
end_h => [\&end_h, "self, tagname"],
text_h => [\&text_h, "self, text"],
);
# Parse document text chunk by chunk
$p->parse(${ $self->{content} });
$p->eof;
$new_content = $p->{content};
$self->{content} = \$new_content;
#print $new_content, "\n\n\n";
}
{
# this parsing extracts the following elements and makes them
# available to templates as:
# meta.title
# head.meta.* (+ renames: description -> abstract)
# head.base
# head.link
# body
# init
my $start_h = sub {
my ($self, $tagname, $attr, $text) = @_;
my $meta = $self->{parsed_tree}{head}{meta};
# special treatment
if ($tagname eq 'meta' && exists $attr->{name} &&
lc $attr->{name} eq 'description') {
$self->{parsed_tree}{abstract} = $attr->{content};
}
elsif ($tagname eq 'meta' && exists $attr->{content}) {
# note: doesn't take into account the 'scheme' attr,
# but that one isn't used much
if (exists $attr->{name}) {
$meta->{name}{ $attr->{name} } = $attr->{content};
}
elsif (exists $attr->{'http-equiv'}) {
$meta->{'http-equiv'}{ $attr->{'http-equiv'} }
= $attr->{content};
}
else {
# unsupported head element?
}
}
elsif ($tagname eq 'base') {
# there is usually only one