mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-14 12:08:20 +00:00
399 lines
12 KiB
Perl
399 lines
12 KiB
Perl
|
###############################################################################
|
||
|
#
|
||
|
# Package: NaturalDocs::Builder::HTML
|
||
|
#
|
||
|
###############################################################################
|
||
|
#
|
||
|
# A package that generates output in HTML.
|
||
|
#
|
||
|
# All functions are called with Package->Function() notation.
|
||
|
#
|
||
|
###############################################################################
|
||
|
|
||
|
# This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure
|
||
|
# Natural Docs is licensed under the GPL
|
||
|
|
||
|
|
||
|
use strict;
|
||
|
use integer;
|
||
|
|
||
|
package NaturalDocs::Builder::HTML;
|
||
|
|
||
|
use base 'NaturalDocs::Builder::HTMLBase';
|
||
|
|
||
|
|
||
|
###############################################################################
|
||
|
# Group: Implemented Interface Functions
|
||
|
|
||
|
|
||
|
#
|
||
|
# Function: INIT
|
||
|
#
|
||
|
# Registers the package with <NaturalDocs::Builder>.
|
||
|
#
|
||
|
sub INIT
|
||
|
{
|
||
|
NaturalDocs::Builder->Add(__PACKAGE__);
|
||
|
};
|
||
|
|
||
|
|
||
|
#
|
||
|
# Function: CommandLineOption
|
||
|
#
|
||
|
# Returns the option to follow -o to use this package. In this case, "html".
|
||
|
#
|
||
|
sub CommandLineOption
|
||
|
{
|
||
|
return 'HTML';
|
||
|
};
|
||
|
|
||
|
|
||
|
#
|
||
|
# Function: BuildFile
|
||
|
#
|
||
|
# Builds the output file from the parsed source file.
|
||
|
#
|
||
|
# Parameters:
|
||
|
#
|
||
|
# sourcefile - The <FileName> of the source file.
|
||
|
# parsedFile - An arrayref of the source file as <NaturalDocs::Parser::ParsedTopic> objects.
|
||
|
#
|
||
|
sub BuildFile #(sourceFile, parsedFile)
|
||
|
{
|
||
|
my ($self, $sourceFile, $parsedFile) = @_;
|
||
|
|
||
|
my $outputFile = $self->OutputFileOf($sourceFile);
|
||
|
|
||
|
|
||
|
# 99.99% of the time the output directory will already exist, so this will actually be more efficient. It only won't exist
|
||
|
# if a new file was added in a new subdirectory and this is the first time that file was ever parsed.
|
||
|
if (!open(OUTPUTFILEHANDLE, '>' . $outputFile))
|
||
|
{
|
||
|
NaturalDocs::File->CreatePath( NaturalDocs::File->NoFileName($outputFile) );
|
||
|
|
||
|
open(OUTPUTFILEHANDLE, '>' . $outputFile)
|
||
|
or die "Couldn't create output file " . $outputFile . "\n";
|
||
|
};
|
||
|
|
||
|
print OUTPUTFILEHANDLE
|
||
|
|
||
|
|
||
|
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" '
|
||
|
. '"http://www.w3.org/TR/REC-html40/strict.dtd">' . "\n\n"
|
||
|
|
||
|
. '<html><head>'
|
||
|
|
||
|
. (NaturalDocs::Settings->CharSet() ?
|
||
|
'<meta http-equiv="Content-Type" content="text/html; charset=' . NaturalDocs::Settings->CharSet() . '">' : '')
|
||
|
|
||
|
. '<title>'
|
||
|
. $self->BuildTitle($sourceFile)
|
||
|
. '</title>'
|
||
|
|
||
|
. '<link rel="stylesheet" type="text/css" href="' . $self->MakeRelativeURL($outputFile, $self->MainCSSFile(), 1) . '">'
|
||
|
|
||
|
. '<script language=JavaScript src="' . $self->MakeRelativeURL($outputFile, $self->MainJavaScriptFile(), 1) . '">'
|
||
|
. '</script>'
|
||
|
. '<script language=JavaScript src="' . $self->MakeRelativeURL($outputFile, $self->SearchDataJavaScriptFile(), 1) . '">'
|
||
|
. '</script>'
|
||
|
|
||
|
. '</head><body class="ContentPage" onLoad="NDOnLoad()">'
|
||
|
. $self->OpeningBrowserStyles()
|
||
|
|
||
|
. $self->StandardComments()
|
||
|
|
||
|
. "\n\n\n"
|
||
|
. $self->BuildContent($sourceFile, $parsedFile)
|
||
|
. "\n\n\n"
|
||
|
. $self->BuildFooter()
|
||
|
. "\n\n\n"
|
||
|
. $self->BuildMenu($sourceFile, undef)
|
||
|
. "\n\n\n"
|
||
|
. $self->BuildToolTips()
|
||
|
. "\n\n\n"
|
||
|
. '<div id=MSearchResultsWindow>'
|
||
|
. '<iframe src="" frameborder=0 name=MSearchResults id=MSearchResults></iframe>'
|
||
|
. '<a href="javascript:searchPanel.CloseResultsWindow()" id=MSearchResultsWindowClose>Close</a>'
|
||
|
. '</div>'
|
||
|
. "\n\n\n"
|
||
|
|
||
|
. $self->ClosingBrowserStyles()
|
||
|
. '</body></html>';
|
||
|
|
||
|
|
||
|
close(OUTPUTFILEHANDLE);
|
||
|
};
|
||
|
|
||
|
|
||
|
#
|
||
|
# Function: BuildIndex
|
||
|
#
|
||
|
# Builds an index for the passed type.
|
||
|
#
|
||
|
# Parameters:
|
||
|
#
|
||
|
# type - The <TopicType> to limit the index to, or undef if none.
|
||
|
#
|
||
|
sub BuildIndex #(type)
|
||
|
{
|
||
|
my ($self, $type) = @_;
|
||
|
|
||
|
my $indexTitle = $self->IndexTitleOf($type);
|
||
|
|
||
|
my $startIndexPage =
|
||
|
|
||
|
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" '
|
||
|
. '"http://www.w3.org/TR/REC-html40/strict.dtd">' . "\n\n"
|
||
|
|
||
|
. '<html><head>'
|
||
|
|
||
|
. (NaturalDocs::Settings->CharSet() ?
|
||
|
'<meta http-equiv="Content-Type" content="text/html; charset=' . NaturalDocs::Settings->CharSet() . '">' : '')
|
||
|
|
||
|
. '<title>'
|
||
|
. $indexTitle;
|
||
|
|
||
|
if (defined NaturalDocs::Menu->Title())
|
||
|
{ $startIndexPage .= ' - ' . $self->StringToHTML(NaturalDocs::Menu->Title()); };
|
||
|
|
||
|
$startIndexPage .=
|
||
|
'</title>'
|
||
|
|
||
|
. '<link rel="stylesheet" type="text/css" href="' . $self->MakeRelativeURL($self->IndexDirectory(),
|
||
|
$self->MainCSSFile()) . '">'
|
||
|
|
||
|
. '<script language=JavaScript src="' . $self->MakeRelativeURL($self->IndexDirectory(),
|
||
|
$self->MainJavaScriptFile()) . '"></script>'
|
||
|
. '<script language=JavaScript src="' . $self->MakeRelativeURL($self->IndexDirectory(),
|
||
|
$self->SearchDataJavaScriptFile()) . '">'
|
||
|
. '</script>'
|
||
|
|
||
|
. '</head><body class="IndexPage" onLoad="NDOnLoad()">'
|
||
|
. $self->OpeningBrowserStyles()
|
||
|
|
||
|
. $self->StandardComments()
|
||
|
|
||
|
. "\n\n\n"
|
||
|
|
||
|
. '<div id=Index>'
|
||
|
. '<div class=IPageTitle>'
|
||
|
. $indexTitle
|
||
|
. '</div>';
|
||
|
|
||
|
my $endIndexPage =
|
||
|
'</div><!--Index-->'
|
||
|
|
||
|
. "\n\n\n"
|
||
|
. $self->BuildFooter()
|
||
|
. "\n\n\n"
|
||
|
. $self->BuildMenu(undef, $type)
|
||
|
. "\n\n\n"
|
||
|
. '<div id=MSearchResultsWindow>'
|
||
|
. '<iframe src="" frameborder=0 name=MSearchResults id=MSearchResults></iframe>'
|
||
|
. '<a href="javascript:searchPanel.CloseResultsWindow()" id=MSearchResultsWindowClose>Close</a>'
|
||
|
. '</div>'
|
||
|
. "\n\n\n"
|
||
|
|
||
|
. $self->ClosingBrowserStyles()
|
||
|
. '</body></html>';
|
||
|
|
||
|
|
||
|
my $startSearchResultsPage =
|
||
|
|
||
|
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" '
|
||
|
. '"http://www.w3.org/TR/REC-html40/strict.dtd">' . "\n\n"
|
||
|
|
||
|
. '<html><head>'
|
||
|
|
||
|
. (NaturalDocs::Settings->CharSet() ?
|
||
|
'<meta http-equiv="Content-Type" content="text/html; charset=' . NaturalDocs::Settings->CharSet() . '">' : '')
|
||
|
|
||
|
. '<link rel="stylesheet" type="text/css" href="' . $self->MakeRelativeURL($self->SearchResultsDirectory(),
|
||
|
$self->MainCSSFile()) . '">'
|
||
|
|
||
|
. '<script language=JavaScript src="' . $self->MakeRelativeURL($self->SearchResultsDirectory(),
|
||
|
$self->MainJavaScriptFile()) . '"></script>'
|
||
|
|
||
|
. '</head><body class="PopupSearchResultsPage" onLoad="NDOnLoad()">'
|
||
|
. $self->OpeningBrowserStyles()
|
||
|
|
||
|
. $self->StandardComments()
|
||
|
|
||
|
. "\n\n\n"
|
||
|
|
||
|
. '<div id=Index>';
|
||
|
|
||
|
|
||
|
my $endSearchResultsPage =
|
||
|
'</div>'
|
||
|
. $self->ClosingBrowserStyles()
|
||
|
. '</body></html>';
|
||
|
|
||
|
my $indexContent = NaturalDocs::SymbolTable->Index($type);
|
||
|
my $pageCount = $self->BuildIndexPages($type, $indexContent, $startIndexPage, $endIndexPage,
|
||
|
$startSearchResultsPage, $endSearchResultsPage);
|
||
|
$self->PurgeIndexFiles($type, $indexContent, $pageCount + 1);
|
||
|
};
|
||
|
|
||
|
|
||
|
#
|
||
|
# Function: UpdateMenu
|
||
|
#
|
||
|
# Updates the menu in all the output files that weren't rebuilt. Also generates index.html.
|
||
|
#
|
||
|
sub UpdateMenu
|
||
|
{
|
||
|
my $self = shift;
|
||
|
|
||
|
|
||
|
# Update the menu on unbuilt files.
|
||
|
|
||
|
my $filesToUpdate = NaturalDocs::Project->UnbuiltFilesWithContent();
|
||
|
|
||
|
foreach my $sourceFile (keys %$filesToUpdate)
|
||
|
{
|
||
|
$self->UpdateFile($sourceFile);
|
||
|
};
|
||
|
|
||
|
|
||
|
# Update the menu on unchanged index files.
|
||
|
|
||
|
my $indexes = NaturalDocs::Menu->Indexes();
|
||
|
|
||
|
foreach my $index (keys %$indexes)
|
||
|
{
|
||
|
if (!NaturalDocs::SymbolTable->IndexChanged($index))
|
||
|
{
|
||
|
$self->UpdateIndex($index);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
|
||
|
# Update index.html
|
||
|
|
||
|
my $firstMenuEntry = $self->FindFirstFile();
|
||
|
my $indexFile = NaturalDocs::File->JoinPaths( NaturalDocs::Settings->OutputDirectoryOf($self), 'index.html' );
|
||
|
|
||
|
# We have to check because it's possible that there may be no files with Natural Docs content and thus no files on the menu.
|
||
|
if (defined $firstMenuEntry)
|
||
|
{
|
||
|
open(INDEXFILEHANDLE, '>' . $indexFile)
|
||
|
or die "Couldn't create output file " . $indexFile . ".\n";
|
||
|
|
||
|
print INDEXFILEHANDLE
|
||
|
'<html><head>'
|
||
|
. '<meta http-equiv="Refresh" CONTENT="0; URL='
|
||
|
. $self->MakeRelativeURL( NaturalDocs::File->JoinPaths( NaturalDocs::Settings->OutputDirectoryOf($self), 'index.html'),
|
||
|
$self->OutputFileOf($firstMenuEntry->Target()), 1 ) . '">'
|
||
|
. '</head></html>';
|
||
|
|
||
|
close INDEXFILEHANDLE;
|
||
|
}
|
||
|
|
||
|
elsif (-e $indexFile)
|
||
|
{
|
||
|
unlink($indexFile);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
###############################################################################
|
||
|
# Group: Support Functions
|
||
|
|
||
|
|
||
|
#
|
||
|
# Function: UpdateFile
|
||
|
#
|
||
|
# Updates an output file. Replaces the menu, HTML title, and footer. It opens the output file, makes the changes, and saves it
|
||
|
# back to disk, which is much quicker than rebuilding the file from scratch if these were the only things that changed.
|
||
|
#
|
||
|
# Parameters:
|
||
|
#
|
||
|
# sourceFile - The source <FileName>.
|
||
|
#
|
||
|
# Dependencies:
|
||
|
#
|
||
|
# - Requires <Builder::BuildMenu()> to surround its content with the exact strings "<div id=Menu>" and "</div><!--Menu-->".
|
||
|
# - Requires <Builder::BuildFooter()> to surround its content with the exact strings "<div id=Footer>" and
|
||
|
# "</div><!--Footer-->".
|
||
|
#
|
||
|
sub UpdateFile #(sourceFile)
|
||
|
{
|
||
|
my ($self, $sourceFile) = @_;
|
||
|
|
||
|
my $outputFile = $self->OutputFileOf($sourceFile);
|
||
|
|
||
|
if (open(OUTPUTFILEHANDLE, '<' . $outputFile))
|
||
|
{
|
||
|
my $content;
|
||
|
|
||
|
read(OUTPUTFILEHANDLE, $content, -s OUTPUTFILEHANDLE);
|
||
|
close(OUTPUTFILEHANDLE);
|
||
|
|
||
|
|
||
|
$content =~ s{<title>[^<]*<\/title>}{'<title>' . $self->BuildTitle($sourceFile) . '</title>'}e;
|
||
|
|
||
|
$content =~ s/<div id=Menu>.*?<\/div><!--Menu-->/$self->BuildMenu($sourceFile, undef)/es;
|
||
|
|
||
|
$content =~ s/<div id=Footer>.*?<\/div><!--Footer-->/$self->BuildFooter()/e;
|
||
|
|
||
|
|
||
|
open(OUTPUTFILEHANDLE, '>' . $outputFile);
|
||
|
print OUTPUTFILEHANDLE $content;
|
||
|
close(OUTPUTFILEHANDLE);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
|
||
|
#
|
||
|
# Function: UpdateIndex
|
||
|
#
|
||
|
# Updates an index's output file. Replaces the menu and footer. It opens the output file, makes the changes, and saves it
|
||
|
# back to disk, which is much quicker than rebuilding the file from scratch if these were the only things that changed.
|
||
|
#
|
||
|
# Parameters:
|
||
|
#
|
||
|
# type - The index <TopicType>, or undef if none.
|
||
|
#
|
||
|
sub UpdateIndex #(type)
|
||
|
{
|
||
|
my ($self, $type) = @_;
|
||
|
|
||
|
my $page = 1;
|
||
|
|
||
|
my $outputFile = $self->IndexFileOf($type, $page);
|
||
|
|
||
|
my $newMenu = $self->BuildMenu(undef, $type);
|
||
|
my $newFooter = $self->BuildFooter();
|
||
|
|
||
|
while (-e $outputFile)
|
||
|
{
|
||
|
open(OUTPUTFILEHANDLE, '<' . $outputFile)
|
||
|
or die "Couldn't open output file " . $outputFile . ".\n";
|
||
|
|
||
|
my $content;
|
||
|
|
||
|
read(OUTPUTFILEHANDLE, $content, -s OUTPUTFILEHANDLE);
|
||
|
close(OUTPUTFILEHANDLE);
|
||
|
|
||
|
|
||
|
$content =~ s/<div id=Menu>.*?<\/div><!--Menu-->/$newMenu/es;
|
||
|
|
||
|
$content =~ s/<div id=Footer>.*<\/div><!--Footer-->/$newFooter/e;
|
||
|
|
||
|
|
||
|
open(OUTPUTFILEHANDLE, '>' . $outputFile)
|
||
|
or die "Couldn't save output file " . $outputFile . ".\n";
|
||
|
|
||
|
print OUTPUTFILEHANDLE $content;
|
||
|
close(OUTPUTFILEHANDLE);
|
||
|
|
||
|
$page++;
|
||
|
$outputFile = $self->IndexFileOf($type, $page);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
|
||
|
1;
|