about summary refs log tree commit diff
path: root/docs/tool/Modules/NaturalDocs/Builder/HTML.pm
diff options
context:
space:
mode:
Diffstat (limited to 'docs/tool/Modules/NaturalDocs/Builder/HTML.pm')
-rw-r--r--docs/tool/Modules/NaturalDocs/Builder/HTML.pm398
1 files changed, 398 insertions, 0 deletions
diff --git a/docs/tool/Modules/NaturalDocs/Builder/HTML.pm b/docs/tool/Modules/NaturalDocs/Builder/HTML.pm
new file mode 100644
index 00000000..95f31b5a
--- /dev/null
+++ b/docs/tool/Modules/NaturalDocs/Builder/HTML.pm
@@ -0,0 +1,398 @@
+###############################################################################
+#
+#   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;