package Pod::PseudoPod::DOM::Index;
# ABSTRACT: an index for a PPDOM Corpus
use strict;
use warnings;
use Moose;
has 'entries', is => 'ro', default => sub { {} };
has 'seen_entries', is => 'ro', default => sub { {} };
sub add_document
{
my ($self, $document) = @_;
my $seen_entries = $self->seen_entries;
$self->add_entry( $_ )
for $document->get_index_entries( $seen_entries );
}
sub add_entry
{
my ($self, $node) = @_;
my ($title, @subentries) = $node->get_key;
my $entry = $self->get_top_entry( $title );
$entry->add( $title, @subentries, $node );
}
sub get_top_entry
{
my ($self, $key) = @_;
my $entries = $self->entries;
my $top_key = $key =~ /(\w)/ ? $1 : substr $key, 0, 1;
return $entries->{uc $top_key}
||= Pod::PseudoPod::DOM::Index::TopEntryList->new( key => uc $top_key );
}
sub emit_index
{
my $self = shift;
my $entries = $self->entries;
my $heading = <<END_HTML_HEAD;
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="../css/style.css" type="text/css" />
</head>
<body>
<h1 id="index">Index</h1>
END_HTML_HEAD
my $footer = <<END_HTML_FOOTER;
</body>
</html>
END_HTML_FOOTER
return $heading
. join( "\n", map { $entries->{$_}->emit } sort keys %$entries )
. $footer;
}
__PACKAGE__->meta->make_immutable;
package Pod::PseudoPod::DOM::Index::EntryList;
use strict;
use warnings;
use Moose;
use HTML::Entities;
has 'key', is => 'ro', required => 1;
has 'contents', is => 'ro', default => sub { {} };
sub add
{
my ($self, $key) = splice @_, 0, 2;
my $contents = $self->contents;
my $node = pop @_;
my $elements = $contents->{$key} ||= [];
return $self->add_nested_entry( $key, $node, $elements, @_ ) if @_;
$self->add_entry( $key, $node, $elements );
}
sub add_nested_entry
{
my ($self, $key, $node, $elements, @path) = @_;
for my $element (@$elements)
{
next unless $element->isa( 'Pod::PseudoPod::DOM::Index::EntryList' );
$element->add( @path, $node );
return;
}
my $entry_list = Pod::PseudoPod::DOM::Index::EntryList->new( key => $key );
$entry_list->add( @path, $node );
push @{ $elements }, $entry_list;
}
sub add_entry
{
my ($self, $key, $node, $elements, @path) = @_;
for my $element (@$elements)
{
next unless $element->isa( 'Pod::PseudoPod::DOM::Index::Entry' );
$element->add_location( $node );
return;
}
my $entry = Pod::PseudoPod::DOM::Index::Entry->new( key => $key );
$entry->add_location( $node );
push @{ $elements }, $entry;
}
sub emit
{
my $self = shift;
my $key = encode_entities( $self->key );
return qq|$key\n| . $self->emit_contents;
}
sub sort_content_hash
{
my ($self, $hash) = @_;
return map { $_->[1] }
sort { $a->[0] cmp $b->[0] }
map { my $key = $_; $key =~ s/[^\w\s]//g; [ lc( $key ), $_ ] }
keys %$hash;
}
sub emit_contents
{
my $self = shift;
my $contents = $self->contents;
my $content = qq|<ul>\n|;
for my $key ($self->sort_content_hash( $contents ))
{
my @sorted = map { $_->[2] }
sort { $a->[0] cmp $b->[0] || $a->[1] cmp $b->[1] }
map {
my $title = $_->key;
$title =~ s/[^\w\s]//g;
[ lc( $title ), ref $_, $_ ]
}
@{ $contents->{$key} };
$content .= join "\n", map { '<li>' . $_->emit . "</li>\n" } @sorted;
}
return $content . qq|</ul>\n|;
}
__PACKAGE__->meta->make_immutable;
package Pod::PseudoPod::DOM::Index::Entry;
use strict;
use warnings;
use Moose;
use HTML::Entities;
has 'key', is => 'ro', required => 1;
has 'locations', is => 'ro', default => sub { [] };
sub emit
{
my $self = shift;
return encode_entities( $self->key ) . ' '
. join ' ', map { $_->emit } @{ $self->locations };
}
sub add_location
{
my ($self, $entry) = @_;
push @{ $self->locations },
Pod::PseudoPod::DOM::Index::Location->new( entry => $entry );
}
__PACKAGE__->meta->make_immutable;
package Pod::PseudoPod::DOM::Index::Location;
# ABSTRACT: represents a location to which an index entry points
use strict;
use warnings;
use Moose;
has 'entry', is => 'ro', required => 1;
sub emit
{
my $self = shift;
my $entry = $self->entry;
return '[' . $entry->emit_index_link . ']';
}
__PACKAGE__->meta->make_immutable;
package Pod::PseudoPod::DOM::Index::TopEntryList;
use strict;
use warnings;
use Moose;
use HTML::Entities;
extends 'Pod::PseudoPod::DOM::Index::EntryList';
sub emit
{
my $self = shift;
my $key = encode_entities( $self->key );
return qq|<h2>$key</h2>\n\n| . $self->emit_contents;
}
__PACKAGE__->meta->make_immutable;
__END__
=pod
=encoding UTF-8
=head1 NAME
Pod::PseudoPod::DOM::Index - an index for a PPDOM Corpus
=head1 VERSION
version 1.20210620.2040
=head1 AUTHOR
chromatic <chromatic@wgz.org>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2021 by chromatic.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut