blob: b554870cc5ccc95c8dbf49415cb2cf8b5ebf3ad0 [file] [log] [blame]
#--- TocInsertor.pm -----------------------------------------------------------
# function: Insert Table of Contents HTML::Toc, generated by
# HTML::TocGenerator.
# note: - The term 'propagate' is used as a shortcut for the process of
# both generating and inserting a ToC at the same time.
# - 'TIP' is an abbreviation of 'Toc Insertion Point'.
package HTML::TocInsertor;
use strict;
use FileHandle;
use HTML::TocGenerator;
BEGIN {
use vars qw(@ISA $VERSION);
$VERSION = '0.91';
@ISA = qw(HTML::TocGenerator);
}
# TocInsertionPoint (TIP) constants
use constant TIP_PREPOSITION_REPLACE => 'replace';
use constant TIP_PREPOSITION_BEFORE => 'before';
use constant TIP_PREPOSITION_AFTER => 'after';
use constant TIP_TOKEN_ID => 0;
use constant TIP_PREPOSITION => 1;
use constant TIP_INCLUDE_ATTRIBUTES => 2;
use constant TIP_EXCLUDE_ATTRIBUTES => 3;
use constant TIP_TOC => 4;
use constant MODE_DO_NOTHING => 0; # 0b00
use constant MODE_DO_INSERT => 1; # 0b01
use constant MODE_DO_PROPAGATE => 3; # 0b11
END {}
#--- HTML::TocInsertor::new() -------------------------------------------------
# function: Constructor.
sub new {
# Get arguments
my ($aType) = @_;
my $self = $aType->SUPER::new;
# TRUE if insertion point token must be output, FALSE if not
$self->{_doOutputInsertionPointToken} = 1;
# Reset batch variables
$self->_resetBatchVariables;
# Bias to not insert ToC
$self->{hti__Mode} = MODE_DO_NOTHING;
# TODO: Initialize output
return $self;
} # new()
#--- HTML::TocInsertor::_deinitializeOutput() ---------------------------------
# function: Deinitialize output.
sub _deinitializeOutput {
# Get arguments
my ($self) = @_;
# Filehandle is defined?
if (defined($self->{_outputFileHandle})) {
# Yes, filehandle is defined;
# Restore selected filehandle
select($self->{_oldFileHandle});
# Undefine filehandle, closing it automatically
undef $self->{_outputFileHandle};
}
} # _deinitializeOutput()
#--- HTML::TocInsertor::_initializeOutput() -----------------------------------
# function: Initialize output.
sub _initializeOutput {
# Get arguments
my ($self) = @_;
# Bias to write to outputfile
my $doOutputToFile = 1;
# Is output specified?
if (defined($self->{options}{'output'})) {
# Yes, output is specified;
# Indicate to not output to outputfile
$doOutputToFile = 0;
# Alias output reference
$self->{_output} = $self->{options}{'output'};
# Clear output
${$self->{_output}} = "";
}
# Is output file specified?
if (defined($self->{options}{'outputFile'})) {
# Yes, output file is specified;
# Indicate to output to outputfile
$doOutputToFile = 1;
# Open file
$self->{_outputFileHandle} =
new FileHandle ">" . $self->{options}{'outputFile'};
# Backup currently selected filehandle
$self->{_oldFileHandle} = select;
# Set new default filehandle
select($self->{_outputFileHandle});
}
# Alias output-to-file indicator
$self->{_doOutputToFile} = $doOutputToFile;
} # _initializeOutput()
#--- HTML::TocInsertor::_deinitializeInsertorBatch() --------------------------
# function: Deinitialize insertor batch.
sub _deinitializeInsertorBatch {
# Get arguments
my ($self) = @_;
# Indicate ToC insertion has finished
$self->{_isTocInsertionPointPassed} = 0;
# Write buffered output
$self->_writeBufferedOutput();
# Propagate?
if ($self->{hti__Mode} == MODE_DO_PROPAGATE) {
# Yes, propagate;
# Deinitialize generator batch
$self->_deinitializeGeneratorBatch();
}
else {
# No, insert only;
# Do general batch deinitialization
$self->_deinitializeBatch();
}
# Deinitialize output
$self->_deinitializeOutput();
# Indicate end of batch
$self->{hti__Mode} = MODE_DO_NOTHING;
# Reset batch variables
$self->_resetBatchVariables();
} # _deinitializeInsertorBatch()
#--- HTML::TocInsertor::_initializeInsertorBatch() ----------------------------
# function: Initialize insertor batch.
# args: - $aTocs: Reference to array of tocs.
# - $aOptions: optional options
sub _initializeInsertorBatch {
# Get arguments
my ($self, $aTocs, $aOptions) = @_;
# Add invocation options
$self->setOptions($aOptions);
# Option 'doGenerateToc' specified?
if (!defined($self->{options}{'doGenerateToc'})) {
# No, options 'doGenerateToc' not specified;
# Default to 'doGenerateToc'
$self->{options}{'doGenerateToc'} = 1;
}
# Propagate?
if ($self->{options}{'doGenerateToc'}) {
# Yes, propagate;
# Indicate mode
$self->{hti__Mode} = MODE_DO_PROPAGATE;
# Initialize generator batch
# NOTE: This method takes care of calling '_initializeBatch()'
$self->_initializeGeneratorBatch($aTocs);
}
else {
# No, insert;
# Indicate mode
$self->{hti__Mode} = MODE_DO_INSERT;
# Do general batch initialization
$self->_initializeBatch($aTocs);
}
# Initialize output
$self->_initializeOutput();
# Parse ToC insertion points
$self->_parseTocInsertionPoints();
} # _initializeInsertorBatch()
#--- HTML::TocInsertor::_insert() ---------------------------------------------
# function: Insert ToC in string.
# args: - $aString: Reference to string to parse.
# note: Used internally.
sub _insert {
# Get arguments
my ($self, $aString) = @_;
# Propagate?
if ($self->{options}{'doGenerateToc'}) {
# Yes, propagate;
# Generate & insert ToC
$self->_generate($aString);
}
else {
# No, just insert ToC
# Insert by parsing file
$self->parse($aString);
# Flush remaining buffered text
$self->eof();
}
} # _insert()
#--- HTML::TocInsertor::_insertIntoFile() -------------------------------------
# function: Do insert generated ToCs in file.
# args: - $aToc: (reference to array of) ToC object(s) to insert.
# - $aFile: (reference to array of) file(s) to parse for insertion
# points.
# - $aOptions: optional insertor options
# note: Used internally.
sub _insertIntoFile {
# Get arguments
my ($self, $aFile) = @_;
# Local variables;
my ($file, @files);
# Dereference array reference or make array of file specification
@files = (ref($aFile) =~ m/ARRAY/) ? @$aFile : ($aFile);
# Loop through files
foreach $file (@files) {
# Propagate?
if ($self->{options}{'doGenerateToc'}) {
# Yes, propagate;
# Generate and insert ToC
$self->_generateFromFile($file);
}
else {
# No, just insert ToC
# Insert by parsing file
$self->parse_file($file);
}
}
} # _insertIntoFile()
#--- HTML::TocInsertor::_parseTocInsertionPoints() ----------------------------
# function: Parse ToC insertion point specifier.
sub _parseTocInsertionPoints {
# Get arguments
my ($self) = @_;
# Local variables
my ($tipPreposition, $tipToken, $toc, $tokenTipParser);
# Create parser for TIP tokens
$tokenTipParser = HTML::_TokenTipParser->new(
$self->{_tokensTip}
);
# Loop through ToCs
foreach $toc (@{$self->{_tocs}}) {
# Split TIP in preposition and token
($tipPreposition, $tipToken) = split(
'\s+', $toc->{options}{'insertionPoint'}, 2
);
# Known preposition?
if (
($tipPreposition ne TIP_PREPOSITION_REPLACE) &&
($tipPreposition ne TIP_PREPOSITION_BEFORE) &&
($tipPreposition ne TIP_PREPOSITION_AFTER)
) {
# No, unknown preposition;
# Use default preposition
$tipPreposition = TIP_PREPOSITION_AFTER;
# Use entire 'insertionPoint' as token
$tipToken = $toc->{options}{'insertionPoint'};
}
# Indicate current ToC to parser
$tokenTipParser->setToc($toc);
# Indicate current preposition to parser
$tokenTipParser->setPreposition($tipPreposition);
# Parse ToC Insertion Point
$tokenTipParser->parse($tipToken);
# Flush remaining buffered text
$tokenTipParser->eof();
}
} # _parseTocInsertionPoints()
#--- HTML::TocInsertor::_processTokenAsInsertionPoint() -----------------------
# function: Check for token being a ToC insertion point (Tip) token and
# process it accordingly.
# args: - $aTokenType: type of token: start, end, comment or text.
# - $aTokenId: token id of currently parsed token
# - $aTokenAttributes: attributes of currently parsed token
# - $aOrigText: complete token
# returns: 1 if successful -- token is processed as insertion point, 0
# if not.
sub _processTokenAsInsertionPoint {
# Get arguments
my ($self, $aTokenType, $aTokenId, $aTokenAttributes, $aOrigText) = @_;
# Local variables
my ($i, $result, $tipToken, $tipTokenId, $tipTokens);
# Bias to token not functioning as a ToC insertion point (Tip) token
$result = 0;
# Alias ToC insertion point (Tip) array of right type
$tipTokens = $self->{_tokensTip}[$aTokenType];
# Loop through tipTokens
$i = 0;
while ($i < scalar @{$tipTokens}) {
# Aliases
$tipToken = $tipTokens->[$i];
$tipTokenId = $tipToken->[TIP_TOKEN_ID];
# Id & attributes match?
if (
($aTokenId =~ m/$tipTokenId/) && (
HTML::TocGenerator::_doesHashContainHash(
$aTokenAttributes, $tipToken->[TIP_INCLUDE_ATTRIBUTES], 0
) &&
HTML::TocGenerator::_doesHashContainHash(
$aTokenAttributes, $tipToken->[TIP_EXCLUDE_ATTRIBUTES], 1
)
)
) {
# Yes, id and attributes match;
# Process ToC insertion point
$self->_processTocInsertionPoint($tipToken);
# Indicate token functions as ToC insertion point
$result = 1;
# Remove Tip token, automatically advancing to next token
splice(@$tipTokens, $i, 1);
}
else {
# No, tag doesn't match ToC insertion point
# Advance to next start token
$i++;
}
}
# Token functions as ToC insertion point?
if ($result) {
# Yes, token functions as ToC insertion point;
# Process insertion point(s)
$self->_processTocInsertionPoints($aOrigText);
}
# Return value
return $result;
} # _processTokenAsInsertionPoint()
#--- HTML::TocInsertor::toc() -------------------------------------------------
# function: Toc processing method. Add toc reference to scenario.
# args: - $aScenario: Scenario to add ToC reference to.
# - $aToc: Reference to ToC to insert.
# note: The ToC hasn't been build yet; only a reference to the ToC to be
# build is inserted.
sub toc {
# Get arguments
my ($self, $aScenario, $aToc) = @_;
# Add toc to scenario
push(@$aScenario, $aToc);
} # toc()
#--- HTML::TocInsertor::_processTocInsertionPoint() ----------------------------
# function: Process ToC insertion point.
# args: - $aTipToken: Reference to token array item which matches the ToC
# insertion point.
sub _processTocInsertionPoint {
# Get arguments
my ($self, $aTipToken) = @_;
# Local variables
my ($tipToc, $tipPreposition);
# Aliases
$tipToc = $aTipToken->[TIP_TOC];
$tipPreposition = $aTipToken->[TIP_PREPOSITION];
SWITCH: {
# Replace token with ToC?
if ($tipPreposition eq TIP_PREPOSITION_REPLACE) {
# Yes, replace token;
# Indicate ToC insertion point has been passed
$self->{_isTocInsertionPointPassed} = 1;
# Add ToC reference to scenario reference by calling 'toc' method
$self->toc($self->{_scenarioAfterToken}, $tipToc);
#push(@{$self->{_scenarioAfterToken}}, $tipTokenToc);
# Indicate token itself must not be output
$self->{_doOutputInsertionPointToken} = 0;
last SWITCH;
}
# Output ToC before token?
if ($tipPreposition eq TIP_PREPOSITION_BEFORE) {
# Yes, output ToC before token;
# Indicate ToC insertion point has been passed
$self->{_isTocInsertionPointPassed} = 1;
# Add ToC reference to scenario reference by calling 'toc' method
$self->toc($self->{_scenarioBeforeToken}, $tipToc);
#push(@{$self->{_scenarioBeforeToken}}, $tipTokenToc);
last SWITCH;
}
# Output ToC after token?
if ($tipPreposition eq TIP_PREPOSITION_AFTER) {
# Yes, output ToC after token;
# Indicate ToC insertion point has been passed
$self->{_isTocInsertionPointPassed} = 1;
# Add ToC reference to scenario reference by calling 'toc' method
$self->toc($self->{_scenarioAfterToken}, $tipToc);
#push(@{$self->{_scenarioAfterToken}}, $tipTokenToc);
last SWITCH;
}
}
} # _processTocInsertionPoint()
#--- HTML::TocInsertor::_processTocInsertionPoints() --------------------------
# function: Process ToC insertion points
# args: - $aTokenText: Text of token which acts as insertion point for one
# or multiple ToCs.
sub _processTocInsertionPoints {
# Get arguments
my ($self, $aTokenText) = @_;
# Local variables
my ($outputPrefix, $outputSuffix);
# Extend scenario
push(@{$self->{_scenario}}, @{$self->{_scenarioBeforeToken}});
if ($outputPrefix = $self->{_outputPrefix}) {
push(@{$self->{_scenario}}, \$outputPrefix);
$self->{_outputPrefix} = "";
}
# Must insertion point token be output?
if ($self->{_doOutputInsertionPointToken}) {
# Yes, output insertion point token;
push(@{$self->{_scenario}}, \$aTokenText);
}
if ($outputSuffix = $self->{_outputSuffix}) {
push(@{$self->{_scenario}}, \$outputSuffix);
$self->{_outputSuffix} = "";
}
push(@{$self->{_scenario}}, @{$self->{_scenarioAfterToken}});
# Add new act to scenario for output to come
my $output = "";
push(@{$self->{_scenario}}, \$output);
# Write output, processing possible '_outputSuffix'
#$self->_writeOrBufferOutput("");
# Reset helper scenario's
$self->{_scenarioBeforeToken} = [];
$self->{_scenarioAfterToken} = [];
# Reset bias value to output insertion point token
$self->{_doOutputInsertionPointToken} = 1;
} # _processTocInsertionPoints()
#--- HTML::Toc::_resetBatchVariables() ----------------------------------------
# function: Reset batch variables.
sub _resetBatchVariables {
my ($self) = @_;
# Call ancestor
$self->SUPER::_resetBatchVariables();
# Array containing references to scalars. This array depicts the order
# in which output must be performed after the first ToC Insertion Point
# has been passed.
$self->{_scenario} = [];
# Helper scenario
$self->{_scenarioBeforeToken} = [];
# Helper scenario
$self->{_scenarioAfterToken} = [];
# Arrays containing start, end, comment, text & declaration tokens which
# must trigger the ToC insertion. Each array element may contain a
# reference to an array containing the following elements:
$self->{_tokensTip} = [
[], # TT_TOKENTYPE_START
[], # TT_TOKENTYPE_END
[], # TT_TOKENTYPE_COMMENT
[], # TT_TOKENTYPE_TEXT
[] # TT_TOKENTYPE_DECLARATION
];
# 1 if ToC insertion point has been passed, 0 if not
$self->{_isTocInsertionPointPassed} = 0;
# Tokens after ToC
$self->{outputBuffer} = "";
# Trailing text after parsed token
$self->{_outputSuffix} = "";
# Preceding text before parsed token
$self->{_outputPrefix} = "";
} # _resetBatchVariables()
#--- HTML::TocInsertor::_writeBufferedOutput() --------------------------------
# function: Write buffered output to output device(s).
sub _writeBufferedOutput {
# Get arguments
my ($self) = @_;
# Local variables
my ($scene);
# Must ToC be parsed?
if ($self->{options}{'parseToc'}) {
# Yes, ToC must be parsed;
# Parse ToC
#$self->parse($self->{toc});
# Output tokens after ToC
#$self->_writeOrBufferOutput($self->{outputBuffer});
}
else {
# No, ToC needn't be parsed;
# Output scenario
foreach $scene (@{$self->{_scenario}}) {
# Is scene a reference to a scalar?
if (ref($scene) eq "SCALAR") {
# Yes, scene is a reference to a scalar;
# Output scene
$self->_writeOutput($$scene);
}
else {
# No, scene must be reference to HTML::Toc;
# Output toc
$self->_writeOutput($scene->format());
}
}
}
} # _writeBufferedOutput()
#--- HTML::TocInsertor::_writeOrBufferOutput() --------------------------------
# function: Write processed HTML to output device(s).
# args: - aOutput: scalar to write
# note: If '_isTocInsertionPointPassed' text is buffered before being
# output because the ToC has to be generated before it can be output.
# Only after the entire data has been parsed, the ToC and the
# following text will be output.
sub _writeOrBufferOutput {
# Get arguments
my ($self, $aOutput) = @_;
# Add possible output prefix and suffix
$aOutput = $self->{_outputPrefix} . $aOutput . $self->{_outputSuffix};
# Clear output prefix and suffix
$self->{_outputPrefix} = "";
$self->{_outputSuffix} = "";
# Has ToC insertion point been passed?
if ($self->{_isTocInsertionPointPassed}) {
# Yes, ToC insertion point has been passed;
# Buffer output; add output to last '_scenario' item
my $index = scalar(@{$self->{_scenario}}) - 1;
${$self->{_scenario}[$index]} .= $aOutput;
}
else {
# No, ToC insertion point hasn't been passed;
# Write output
$self->_writeOutput($aOutput);
}
} # _writeOrBufferOutput()
#--- HTML::TocInsertor::_writeOutput() ----------------------------------------
# function: Write processed HTML to output device(s).
# args: - aOutput: scalar to write
sub _writeOutput {
# Get arguments
my ($self, $aOutput) = @_;
# Write output to scalar;
${$self->{_output}} .= $aOutput if (defined($self->{_output}));
# Write output to output file
print $aOutput if ($self->{_doOutputToFile})
} # _writeOutput()
#--- HTML::TocGenerator::anchorId() -------------------------------------------
# function: Anchor id processing method.
# args: - $aAnchorId
sub anchorId {
# Get arguments
my ($self, $aAnchorId) = @_;
# Indicate id must be added to start tag
$self->{_doAddAnchorIdToStartTag} = 1;
$self->{_anchorId} = $aAnchorId;
} # anchorId()
#--- HTML::TocInsertor::anchorNameBegin() -------------------------------------
# function: Process anchor name begin, generated by HTML::TocGenerator.
# args: - $aAnchorNameBegin: Anchor name begin tag to output.
# - $aToc: Reference to ToC to which anchorname belongs.
sub anchorNameBegin {
# Get arguments
my ($self, $aAnchorNameBegin, $aToc) = @_;
# Is another anchorName active?
if (defined($self->{_activeAnchorName})) {
# Yes, another anchorName is active;
# Show warning
print "Warn\n";
$self->_showWarning(
HTML::TocGenerator::WARNING_NESTED_ANCHOR_PS_WITHIN_PS,
[$aAnchorNameBegin, $self->{_activeAnchorName}]
);
}
# Store anchor name as output prefix
$self->{_outputPrefix} = $aAnchorNameBegin;
# Indicate active anchor name
$self->{_activeAnchorName} = $aAnchorNameBegin;
# Indicate anchor name end must be output
$self->{_doOutputAnchorNameEnd} = 1;
} # anchorNameBegin()
#--- HTML::TocInsertor::anchorNameEnd() ---------------------------------------
# function: Process anchor name end, generated by HTML::TocGenerator.
# args: - $aAnchorNameEnd: Anchor name end tag to output.
# - $aToc: Reference to ToC to which anchorname belongs.
sub anchorNameEnd {
# Get arguments
my ($self, $aAnchorNameEnd) = @_;
# Store anchor name as output prefix
$self->{_outputSuffix} .= $aAnchorNameEnd;
# Indicate deactive anchor name
$self->{_activeAnchorName} = undef;
} # anchorNameEnd()
#--- HTML::TocInsertor::comment() ---------------------------------------------
# function: Process comment.
# args: - $aComment: comment text with '<!--' and '-->' tags stripped off.
sub comment {
# Get arguments
my ($self, $aComment) = @_;
# Local variables
my ($tocInsertionPointToken, $doOutput, $origText);
# Allow ancestor to process the comment tag
$self->SUPER::comment($aComment);
# Assemble original comment
$origText = "<!--$aComment-->";
# Must ToCs be inserted?
if ($self->{hti__Mode} & MODE_DO_INSERT) {
# Yes, ToCs must be inserted;
# Processing comment as ToC insertion point is successful?
if (! $self->_processTokenAsInsertionPoint(
HTML::TocGenerator::TT_TOKENTYPE_COMMENT, $aComment, undef, $origText
)) {
# No, comment isn't a ToC insertion point;
# Output comment normally
$self->_writeOrBufferOutput($origText);
}
}
} # comment()
#--- HTML::TocInsertor::declaration() -----------------------------------------
# function: This function is called every time a declaration is encountered
# by HTML::Parser.
sub declaration {
# Get arguments
my ($self, $aDeclaration) = @_;
# Allow ancestor to process the declaration tag
$self->SUPER::declaration($aDeclaration);
# Must ToCs be inserted?
if ($self->{hti__Mode} & MODE_DO_INSERT) {
# Yes, ToCs must be inserted;
# Processing declaration as ToC insertion point is successful?
if (! $self->_processTokenAsInsertionPoint(
HTML::TocGenerator::TT_TOKENTYPE_DECLARATION, $aDeclaration, undef,
"<!$aDeclaration>"
)) {
# No, declaration isn't a ToC insertion point;
# Output declaration normally
$self->_writeOrBufferOutput("<!$aDeclaration>");
}
}
} # declaration()
#--- HTML::TocInsertor::end() -------------------------------------------------
# function: This function is called every time a closing tag is encountered
# by HTML::Parser.
# args: - $aTag: tag name (in lower case).
sub end {
# Get arguments
my ($self, $aTag, $aOrigText) = @_;
# Allow ancestor to process the end tag
$self->SUPER::end($aTag, $aOrigText);
# Must ToCs be inserted?
if ($self->{hti__Mode} & MODE_DO_INSERT) {
# Yes, ToCs must be inserted;
# Processing end tag as ToC insertion point is successful?
if (! $self->_processTokenAsInsertionPoint(
HTML::TocGenerator::TT_TOKENTYPE_END, $aTag, undef, $aOrigText
)) {
# No, end tag isn't a ToC insertion point;
# Output end tag normally
$self->_writeOrBufferOutput($aOrigText);
}
}
} # end()
#--- HTML::TocInsertor::insert() ----------------------------------------------
# function: Insert ToC in string.
# args: - $aToc: (reference to array of) ToC object to insert
# - $aString: string to insert ToC in
# - $aOptions: hash reference with optional insertor options
sub insert {
# Get arguments
my ($self, $aToc, $aString, $aOptions) = @_;
# Initialize TocInsertor batch
$self->_initializeInsertorBatch($aToc, $aOptions);
# Do insert Toc
$self->_insert($aString);
# Deinitialize TocInsertor batch
$self->_deinitializeInsertorBatch();
} # insert()
#--- HTML::TocInsertor::insertIntoFile() --------------------------------------
# function: Insert ToCs in file.
# args: - $aToc: (reference to array of) ToC object(s) to insert.
# - $aFile: (reference to array of) file(s) to parse for insertion
# points.
# - $aOptions: optional insertor options
sub insertIntoFile {
# Get arguments
my ($self, $aToc, $aFile, $aOptions) = @_;
# Initialize TocInsertor batch
$self->_initializeInsertorBatch($aToc, $aOptions);
# Do insert ToCs into file
$self->_insertIntoFile($aFile);
# Deinitialize TocInsertor batch
$self->_deinitializeInsertorBatch();
} # insertIntoFile()
#--- HTML::TocInsertor::number() ----------------------------------------------
# function: Process heading number generated by HTML::Toc.
# args: - $aNumber
sub number {
# Get arguments
my ($self, $aNumber) = @_;
# Store heading number as output suffix
$self->{_outputSuffix} .= $aNumber;
} # number()
#--- HTML::TocInsertor::propagateFile() ---------------------------------------
# function: Propagate ToC; generate & insert ToC, using file as input.
# args: - $aToc: (reference to array of) ToC object to insert
# - $aFile: (reference to array of) file to parse for insertion
# points.
# - $aOptions: optional insertor options
sub propagateFile {
# Get arguments
my ($self, $aToc, $aFile, $aOptions) = @_;
# Local variables;
my ($file, @files);
# Initialize TocInsertor batch
$self->_initializeInsertorBatch($aToc, $aOptions);
# Dereference array reference or make array of file specification
@files = (ref($aFile) =~ m/ARRAY/) ? @$aFile : ($aFile);
# Loop through files
foreach $file (@files) {
# Generate and insert ToC
$self->_generateFromFile($file);
}
# Deinitialize TocInsertor batch
$self->_deinitializeInsertorBatch();
} # propagateFile()
#--- HTML::TocInsertor::start() -----------------------------------------------
# function: This function is called every time an opening tag is encountered.
# args: - $aTag: tag name (in lower case).
# - $aAttr: reference to hash containing all tag attributes (in lower
# case).
# - $aAttrSeq: reference to array containing all tag attributes (in
# lower case) in the original order
# - $aOrigText: the original HTML text
sub start {
# Get arguments
my ($self, $aTag, $aAttr, $aAttrSeq, $aOrigText) = @_;
# Local variables
my ($doOutput, $i, $tocToken, $tag, $anchorId);
# Let ancestor process the start tag
$self->SUPER::start($aTag, $aAttr, $aAttrSeq, $aOrigText);
# Must ToC be inserted?
if ($self->{hti__Mode} & MODE_DO_INSERT) {
# Yes, ToC must be inserted;
# Processing start tag as ToC insertion point is successful?
if (! $self->_processTokenAsInsertionPoint(
HTML::TocGenerator::TT_TOKENTYPE_START, $aTag, $aAttr, $aOrigText
)) {
# No, start tag isn't a ToC insertion point;
# Add anchor id?
if ($self->{_doAddAnchorIdToStartTag}) {
# Yes, anchor id must be added;
# Reset indicator;
$self->{_doAddAnchorIdToStartTag} = 0;
# Alias anchor id
$anchorId = $self->{_anchorId};
# Attribute 'id' already exists?
if (defined($aAttr->{id})) {
# Yes, attribute 'id' already exists;
# Show warning
print STDERR "WARNING: Overwriting existing id attribute '" .
$aAttr->{id} . "' of tag $aOrigText\n";
# Add anchor id to start tag
$aOrigText =~ s/(id)=\S*([\s>])/$1=$anchorId$2/i;
}
else {
# No, attribute 'id' doesn't exist;
# Add anchor id to start tag
$aOrigText =~ s/>/ id=$anchorId>/;
}
}
# Output start tag normally
$self->_writeOrBufferOutput($aOrigText);
}
}
} # start()
#--- HTML::TocInsertor::text() ------------------------------------------------
# function: This function is called every time plain text is encountered.
# args: - @_: array containing data.
sub text {
# Get arguments
my ($self, $aText) = @_;
# Let ancestor process the text
$self->SUPER::text($aText);
# Must ToC be inserted?
if ($self->{hti__Mode} & MODE_DO_INSERT) {
# Yes, ToC must be inserted;
# Processing text as ToC insertion point is successful?
if (! $self->_processTokenAsInsertionPoint(
HTML::TocGenerator::TT_TOKENTYPE_TEXT, $aText, undef, $aText
)) {
# No, text isn't a ToC insertion point;
# Output text normally
$self->_writeOrBufferOutput($aText);
}
}
} # text()
#=== HTML::_TokenTipParser ====================================================
# function: Parse 'TIP tokens'. 'TIP tokens' mark HTML code which is to be
# used as the ToC Insertion Point.
# note: Used internally.
package HTML::_TokenTipParser;
BEGIN {
use vars qw(@ISA);
@ISA = qw(HTML::_TokenTocParser);
}
END {}
#--- HTML::_TokenTipParser::new() ---------------------------------------------
# function: Constructor
sub new {
# Get arguments
my ($aType, $aTokenArray) = @_;
# Create instance
my $self = $aType->SUPER::new;
# Reference token array
$self->{tokens} = $aTokenArray;
# Reference to last added token
$self->{_lastAddedToken} = undef;
$self->{_lastAddedTokenType} = undef;
# Return instance
return $self;
} # new()
#--- HTML::_TokenTipParser::_processAttributes() ------------------------------
# function: Process attributes.
# args: - $aAttributes: Attributes to parse.
sub _processAttributes {
# Get arguments
my ($self, $aAttributes) = @_;
# Local variables
my (%includeAttributes, %excludeAttributes);
# Parse attributes
$self->_parseAttributes(
$aAttributes, \%includeAttributes, \%excludeAttributes
);
# Include attributes are specified?
if (keys(%includeAttributes) > 0) {
# Yes, include attributes are specified;
# Store include attributes
@${$self->{_lastAddedToken}}[
HTML::TocInsertor::TIP_INCLUDE_ATTRIBUTES
] = \%includeAttributes;
}
# Exclude attributes are specified?
if (keys(%excludeAttributes) > 0) {
# Yes, exclude attributes are specified;
# Store exclude attributes
@${$self->{_lastAddedToken}}[
HTML::TocInsertor::TIP_EXCLUDE_ATTRIBUTES
] = \%excludeAttributes;
}
} # _processAttributes()
#--- HTML::_TokenTipParser::_processToken() -----------------------------------
# function: Process token.
# args: - $aTokenType: Type of token to process.
# - $aTag: Tag of token.
sub _processToken {
# Get arguments
my ($self, $aTokenType, $aTag) = @_;
# Local variables
my ($tokenArray, $index);
# Push element on array of update tokens
$index = push(@{$self->{tokens}[$aTokenType]}, []) - 1;
# Alias token array to add element to
$tokenArray = $self->{tokens}[$aTokenType];
# Indicate last updated token array element
$self->{_lastAddedTokenType} = $aTokenType;
$self->{_lastAddedToken} = \$$tokenArray[$index];
# Add fields
$$tokenArray[$index][HTML::TocInsertor::TIP_TOC] = $self->{_toc};
$$tokenArray[$index][HTML::TocInsertor::TIP_TOKEN_ID] = $aTag;
$$tokenArray[$index][HTML::TocInsertor::TIP_PREPOSITION] =
$self->{_preposition};
} # _processToken()
#--- HTML::_TokenTipParser::comment() -----------------------------------------
# function: Process comment.
# args: - $aComment: comment text with '<!--' and '-->' tags stripped off.
sub comment {
# Get arguments
my ($self, $aComment) = @_;
# Process token
$self->_processToken(HTML::TocGenerator::TT_TOKENTYPE_COMMENT, $aComment);
} # comment()
#--- HTML::_TokenTipParser::declaration() --------------------------------
# function: This function is called every time a markup declaration is
# encountered by HTML::Parser.
# args: - $aDeclaration: Markup declaration.
sub declaration {
# Get arguments
my ($self, $aDeclaration) = @_;
# Process token
$self->_processToken(
HTML::TocGenerator::TT_TOKENTYPE_DECLARATION, $aDeclaration
);
} # declaration()
#--- HTML::_TokenTipParser::end() ----------------------------------------
# function: This function is called every time a closing tag is encountered
# by HTML::Parser.
# args: - $aTag: tag name (in lower case).
sub end {
# Get arguments
my ($self, $aTag, $aOrigText) = @_;
# Process token
$self->_processToken(HTML::TocGenerator::TT_TOKENTYPE_END, $aTag);
} # end()
#--- HTML::_TokenTipParser->setPreposition() ----------------------------------
# function: Set current preposition.
sub setPreposition {
# Get arguments
my ($self, $aPreposition) = @_;
# Set current ToC
$self->{_preposition} = $aPreposition;
} # setPreposition()
#--- HTML::_TokenTipParser->setToc() ------------------------------------------
# function: Set current ToC.
sub setToc {
# Get arguments
my ($self, $aToc) = @_;
# Set current ToC
$self->{_toc} = $aToc;
} # setToc()
#--- HTML::_TokenTipParser::start() --------------------------------------
# function: This function is called every time an opening tag is encountered.
# args: - $aTag: tag name (in lower case).
# - $aAttr: reference to hash containing all tag attributes (in lower
# case).
# - $aAttrSeq: reference to array containing all attribute keys (in
# lower case) in the original order
# - $aOrigText: the original HTML text
sub start {
# Get arguments
my ($self, $aTag, $aAttr, $aAttrSeq, $aOrigText) = @_;
# Process token
$self->_processToken(HTML::TocGenerator::TT_TOKENTYPE_START, $aTag);
# Process attributes
$self->_processAttributes($aAttr);
} # start()
#--- HTML::_TokenTipParser::text() ---------------------------------------
# function: This function is called every time plain text is encountered.
# args: - @_: array containing data.
sub text {
# Get arguments
my ($self, $aText) = @_;
# Was token already created and is last added token of type 'text'?
if (
defined($self->{_lastAddedToken}) &&
$self->{_lastAddedTokenType} == HTML::TocGenerator::TT_TOKENTYPE_TEXT
) {
# Yes, token is already created;
# Add tag to existing token
@${$self->{_lastAddedToken}}[HTML::TocGenerator::TT_TAG_BEGIN] .= $aText;
}
else {
# No, token isn't created;
# Process token
$self->_processToken(HTML::TocGenerator::TT_TOKENTYPE_TEXT, $aText);
}
} # text()
1;