2015-10-28 11:10:36 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# DOC HTML PAGE MODULE
|
|
|
|
####################################################################################################################################
|
2020-03-10 21:41:56 +02:00
|
|
|
package pgBackRestDoc::Html::DocHtmlPage;
|
|
|
|
use parent 'pgBackRestDoc::Common::DocExecute';
|
2015-10-28 11:10:36 +02:00
|
|
|
|
|
|
|
use strict;
|
|
|
|
use warnings FATAL => qw(all);
|
|
|
|
use Carp qw(confess);
|
|
|
|
|
|
|
|
use Data::Dumper;
|
|
|
|
use Exporter qw(import);
|
|
|
|
our @EXPORT = qw();
|
|
|
|
|
2020-03-10 21:41:56 +02:00
|
|
|
use pgBackRestDoc::Common::DocConfig;
|
|
|
|
use pgBackRestDoc::Common::DocManifest;
|
|
|
|
use pgBackRestDoc::Common::DocRender;
|
|
|
|
use pgBackRestDoc::Html::DocHtmlBuilder;
|
|
|
|
use pgBackRestDoc::Html::DocHtmlElement;
|
|
|
|
use pgBackRestDoc::Common::Log;
|
|
|
|
use pgBackRestDoc::Common::String;
|
2015-10-28 11:10:36 +02:00
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# CONSTRUCTOR
|
|
|
|
####################################################################################################################################
|
|
|
|
sub new
|
|
|
|
{
|
|
|
|
my $class = shift; # Class name
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
2015-11-22 23:44:01 +02:00
|
|
|
$oManifest,
|
|
|
|
$strRenderOutKey,
|
2016-11-07 17:06:35 +02:00
|
|
|
$bMenu,
|
|
|
|
$bExe,
|
|
|
|
$bCompact,
|
|
|
|
$strCss,
|
|
|
|
$bPretty,
|
2015-10-28 11:10:36 +02:00
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
2016-05-26 15:09:42 +02:00
|
|
|
__PACKAGE__ . '->new', \@_,
|
2015-11-22 23:44:01 +02:00
|
|
|
{name => 'oManifest'},
|
|
|
|
{name => 'strRenderOutKey'},
|
2016-11-07 17:06:35 +02:00
|
|
|
{name => 'bMenu'},
|
|
|
|
{name => 'bExe'},
|
|
|
|
{name => 'bCompact'},
|
|
|
|
{name => 'strCss'},
|
|
|
|
{name => 'bPretty'},
|
2015-10-28 11:10:36 +02:00
|
|
|
);
|
|
|
|
|
2015-11-22 23:44:01 +02:00
|
|
|
# Create the class hash
|
|
|
|
my $self = $class->SUPER::new(RENDER_TYPE_HTML, $oManifest, $strRenderOutKey, $bExe);
|
|
|
|
bless $self, $class;
|
2015-10-28 11:10:36 +02:00
|
|
|
|
2016-11-07 17:06:35 +02:00
|
|
|
$self->{bMenu} = $bMenu;
|
|
|
|
$self->{bCompact} = $bCompact;
|
|
|
|
$self->{strCss} = $strCss;
|
|
|
|
$self->{bPretty} = $bPretty;
|
|
|
|
|
2015-10-28 11:10:36 +02:00
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
2015-11-22 23:44:01 +02:00
|
|
|
{name => 'self', value => $self}
|
2015-10-28 11:10:36 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# process
|
|
|
|
#
|
|
|
|
# Generate the site html
|
|
|
|
####################################################################################################################################
|
|
|
|
sub process
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
2016-05-26 15:09:42 +02:00
|
|
|
my $strOperation = logDebugParam(__PACKAGE__ . '->process');
|
2015-10-28 11:10:36 +02:00
|
|
|
|
|
|
|
# Working variables
|
|
|
|
my $oPage = $self->{oDoc};
|
2018-12-15 01:46:12 +02:00
|
|
|
my $oRender = $self->{oManifest}->renderGet(RENDER_TYPE_HTML);
|
2015-10-28 11:10:36 +02:00
|
|
|
|
|
|
|
# Initialize page
|
2016-11-17 23:35:11 +02:00
|
|
|
my $strTitle = $oPage->paramGet('title');
|
2015-10-28 11:10:36 +02:00
|
|
|
my $strSubTitle = $oPage->paramGet('subtitle', false);
|
|
|
|
|
2020-03-10 21:41:56 +02:00
|
|
|
my $oHtmlBuilder = new pgBackRestDoc::Html::DocHtmlBuilder(
|
2016-11-07 17:06:35 +02:00
|
|
|
$self->{oManifest}->variableReplace('{[project]}' . (defined($self->{oManifest}->variableGet('project-tagline')) ?
|
2019-06-25 23:27:19 +02:00
|
|
|
' - ' . $self->{oManifest}->variableGet('project-tagline') : '')),
|
2016-11-07 17:06:35 +02:00
|
|
|
$self->{oManifest}->variableReplace($strTitle . (defined($strSubTitle) ? " - ${strSubTitle}" : '')),
|
|
|
|
$self->{oManifest}->variableGet('project-favicon'),
|
|
|
|
$self->{oManifest}->variableGet('project-logo'),
|
|
|
|
$self->{oManifest}->variableReplace(trim($self->{oDoc}->fieldGet('description'))),
|
|
|
|
$self->{bPretty},
|
|
|
|
$self->{bCompact},
|
|
|
|
$self->{bCompact} ? $self->{strCss} : undef);
|
2015-10-28 11:10:36 +02:00
|
|
|
|
|
|
|
# Generate header
|
|
|
|
my $oPageHeader = $oHtmlBuilder->bodyGet()->addNew(HTML_DIV, 'page-header');
|
|
|
|
|
2016-05-16 23:01:48 +02:00
|
|
|
# add the logo to the header
|
|
|
|
if (defined($self->{oManifest}->variableGet('html-logo')))
|
|
|
|
{
|
|
|
|
$oPageHeader->
|
|
|
|
addNew(HTML_DIV, 'page-header-logo',
|
|
|
|
{strContent =>"{[html-logo]}"});
|
|
|
|
}
|
|
|
|
|
2015-10-28 11:10:36 +02:00
|
|
|
$oPageHeader->
|
|
|
|
addNew(HTML_DIV, 'page-header-title',
|
|
|
|
{strContent => $strTitle});
|
|
|
|
|
|
|
|
if (defined($strSubTitle))
|
|
|
|
{
|
|
|
|
$oPageHeader->
|
|
|
|
addNew(HTML_DIV, 'page-header-subtitle',
|
|
|
|
{strContent => $strSubTitle});
|
|
|
|
}
|
|
|
|
|
|
|
|
# Generate menu
|
2016-11-07 17:06:35 +02:00
|
|
|
if ($self->{bMenu})
|
2015-10-28 11:10:36 +02:00
|
|
|
{
|
2016-11-07 17:06:35 +02:00
|
|
|
my $oMenuBody = $oHtmlBuilder->bodyGet()->addNew(HTML_DIV, 'page-menu')->addNew(HTML_DIV, 'menu-body');
|
2015-10-28 11:10:36 +02:00
|
|
|
|
2018-12-15 01:46:12 +02:00
|
|
|
# Get the menu in the order listed in the manifest.xml
|
|
|
|
foreach my $strRenderOutKey (@{${$oRender}{stryOrder}})
|
2015-10-28 11:10:36 +02:00
|
|
|
{
|
2018-12-15 01:46:12 +02:00
|
|
|
# Do not output the menu item for the page the user is on (e.g. on Command page, the Command menu item will not appear)
|
|
|
|
if ($strRenderOutKey ne $self->{strRenderOutKey})
|
2016-11-07 17:06:35 +02:00
|
|
|
{
|
|
|
|
my $oRenderOut = $self->{oManifest}->renderOutGet(RENDER_TYPE_HTML, $strRenderOutKey);
|
|
|
|
|
2019-05-16 13:35:45 +02:00
|
|
|
if (defined($$oRenderOut{menu}))
|
|
|
|
{
|
|
|
|
$oMenuBody->addNew(HTML_DIV, 'menu')->addNew(
|
|
|
|
HTML_A, 'menu-link',
|
|
|
|
{strContent => $$oRenderOut{menu},
|
|
|
|
strRef => $strRenderOutKey eq 'index' ? '{[project-url-root]}' : "${strRenderOutKey}.html"});
|
|
|
|
}
|
2016-11-07 17:06:35 +02:00
|
|
|
}
|
2015-10-28 11:10:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Generate table of contents
|
|
|
|
my $oPageTocBody;
|
|
|
|
|
2016-11-07 17:06:35 +02:00
|
|
|
if ($self->{bToc})
|
2015-10-28 11:10:36 +02:00
|
|
|
{
|
|
|
|
my $oPageToc = $oHtmlBuilder->bodyGet()->addNew(HTML_DIV, 'page-toc');
|
|
|
|
|
2016-11-07 17:06:35 +02:00
|
|
|
$oPageToc->addNew(HTML_DIV, 'page-toc-header')->addNew(HTML_DIV, 'page-toc-title', {strContent => "Table of Contents"});
|
2015-10-28 11:10:36 +02:00
|
|
|
|
|
|
|
$oPageTocBody = $oPageToc->
|
|
|
|
addNew(HTML_DIV, 'page-toc-body');
|
|
|
|
}
|
|
|
|
|
|
|
|
# Generate body
|
|
|
|
my $oPageBody = $oHtmlBuilder->bodyGet()->addNew(HTML_DIV, 'page-body');
|
2016-11-07 17:06:35 +02:00
|
|
|
my $iSectionNo = 1;
|
2015-10-28 11:10:36 +02:00
|
|
|
|
|
|
|
# Render sections
|
|
|
|
foreach my $oSection ($oPage->nodeList('section'))
|
|
|
|
{
|
|
|
|
my ($oChildSectionElement, $oChildSectionTocElement) =
|
2016-11-07 17:06:35 +02:00
|
|
|
$self->sectionProcess($oSection, undef, "${iSectionNo}", 1);
|
2015-10-28 11:10:36 +02:00
|
|
|
|
|
|
|
$oPageBody->add($oChildSectionElement);
|
|
|
|
|
2016-09-04 15:27:56 +02:00
|
|
|
if (defined($oPageTocBody) && defined($oChildSectionTocElement))
|
2015-10-28 11:10:36 +02:00
|
|
|
{
|
|
|
|
$oPageTocBody->add($oChildSectionTocElement);
|
|
|
|
}
|
2016-11-07 17:06:35 +02:00
|
|
|
|
|
|
|
$iSectionNo++;
|
2015-10-28 11:10:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
my $oPageFooter = $oHtmlBuilder->bodyGet()->
|
|
|
|
addNew(HTML_DIV, 'page-footer',
|
2015-11-22 23:44:01 +02:00
|
|
|
{strContent => '{[html-footer]}'});
|
2015-10-28 11:10:36 +02:00
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'strHtml', value => $oHtmlBuilder->htmlGet(), trace => true}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# sectionProcess
|
|
|
|
####################################################################################################################################
|
|
|
|
sub sectionProcess
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$oSection,
|
|
|
|
$strAnchor,
|
2016-11-07 17:06:35 +02:00
|
|
|
$strSectionNo,
|
2015-10-28 11:10:36 +02:00
|
|
|
$iDepth
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
2016-05-26 15:09:42 +02:00
|
|
|
__PACKAGE__ . '->sectionProcess', \@_,
|
2015-10-28 11:10:36 +02:00
|
|
|
{name => 'oSection'},
|
|
|
|
{name => 'strAnchor', required => false},
|
2016-11-07 17:06:35 +02:00
|
|
|
{name => 'strSectionNo'},
|
2015-10-28 11:10:36 +02:00
|
|
|
{name => 'iDepth'}
|
|
|
|
);
|
|
|
|
|
2017-07-26 16:22:22 +02:00
|
|
|
if ($oSection->paramGet('log'))
|
|
|
|
{
|
|
|
|
&log(INFO, (' ' x ($iDepth + 1)) . 'process section: ' . $oSection->paramGet('path'));
|
|
|
|
}
|
2015-10-28 11:10:36 +02:00
|
|
|
|
|
|
|
if ($iDepth > 3)
|
|
|
|
{
|
|
|
|
confess &log(ASSERT, "section depth of ${iDepth} exceeds maximum");
|
|
|
|
}
|
|
|
|
|
|
|
|
# Working variables
|
2016-05-26 16:34:10 +02:00
|
|
|
$strAnchor =
|
|
|
|
($oSection->paramTest(XML_SECTION_PARAM_ANCHOR, XML_SECTION_PARAM_ANCHOR_VALUE_NOINHERIT) ? '' :
|
2016-11-23 00:29:24 +02:00
|
|
|
(defined($strAnchor) ? "${strAnchor}/" : '')) .
|
2016-05-26 16:34:10 +02:00
|
|
|
$oSection->paramGet('id');
|
2015-10-28 11:10:36 +02:00
|
|
|
|
|
|
|
# Create the section toc element
|
2020-03-10 21:41:56 +02:00
|
|
|
my $oSectionTocElement = new pgBackRestDoc::Html::DocHtmlElement(HTML_DIV, "section${iDepth}-toc");
|
2015-10-28 11:10:36 +02:00
|
|
|
|
|
|
|
# Create the section element
|
2020-03-10 21:41:56 +02:00
|
|
|
my $oSectionElement = new pgBackRestDoc::Html::DocHtmlElement(HTML_DIV, "section${iDepth}");
|
2015-10-28 11:10:36 +02:00
|
|
|
|
|
|
|
# Add the section anchor
|
|
|
|
$oSectionElement->addNew(HTML_A, undef, {strId => $strAnchor});
|
|
|
|
|
|
|
|
# Add the section title to section and toc
|
2016-11-07 17:06:35 +02:00
|
|
|
my $oSectionHeaderElement = $oSectionElement->addNew(HTML_DIV, "section${iDepth}-header");
|
2015-11-22 23:44:01 +02:00
|
|
|
my $strSectionTitle = $self->processText($oSection->nodeGet('title')->textGet());
|
2015-10-28 11:10:36 +02:00
|
|
|
|
2016-11-07 17:06:35 +02:00
|
|
|
if ($self->{bTocNumber})
|
|
|
|
{
|
|
|
|
$oSectionHeaderElement->addNew(HTML_DIV, "section${iDepth}-number", {strContent => $strSectionNo});
|
|
|
|
}
|
2015-10-28 11:10:36 +02:00
|
|
|
|
2016-11-07 17:06:35 +02:00
|
|
|
$oSectionHeaderElement->addNew(HTML_DIV, "section${iDepth}-title", {strContent => $strSectionTitle});
|
2015-10-28 11:10:36 +02:00
|
|
|
|
2016-11-07 17:06:35 +02:00
|
|
|
if ($self->{bTocNumber})
|
|
|
|
{
|
|
|
|
$oSectionTocElement->addNew(HTML_DIV, "section${iDepth}-toc-number", {strContent => $strSectionNo});
|
|
|
|
}
|
|
|
|
|
|
|
|
my $oTocSectionTitleElement = $oSectionTocElement->addNew(HTML_DIV, "section${iDepth}-toc-title");
|
|
|
|
|
|
|
|
$oTocSectionTitleElement->addNew(
|
|
|
|
HTML_A, undef,
|
|
|
|
{strContent => $strSectionTitle, strRef => "#${strAnchor}"});
|
2015-10-28 11:10:36 +02:00
|
|
|
|
|
|
|
# Add the section intro if it exists
|
|
|
|
if (defined($oSection->textGet(false)))
|
|
|
|
{
|
|
|
|
$oSectionElement->
|
|
|
|
addNew(HTML_DIV, "section-intro",
|
2015-11-22 23:44:01 +02:00
|
|
|
{strContent => $self->processText($oSection->textGet())});
|
2015-10-28 11:10:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# Add the section body
|
|
|
|
my $oSectionBodyElement = $oSectionElement->addNew(HTML_DIV, "section-body");
|
|
|
|
|
|
|
|
# Process each child
|
2016-11-07 17:06:35 +02:00
|
|
|
my $iSectionNo = 1;
|
2015-10-28 11:10:36 +02:00
|
|
|
|
|
|
|
foreach my $oChild ($oSection->nodeList())
|
|
|
|
{
|
2015-11-22 23:44:01 +02:00
|
|
|
&log(DEBUG, (' ' x ($iDepth + 2)) . 'process child ' . $oChild->nameGet());
|
2015-10-28 11:10:36 +02:00
|
|
|
|
|
|
|
# Execute a command
|
|
|
|
if ($oChild->nameGet() eq 'execute-list')
|
|
|
|
{
|
2018-06-12 19:43:15 +02:00
|
|
|
my $bShow = $oChild->paramTest('show', 'n') ? false : true;
|
|
|
|
my $oExecuteBodyElement;
|
2015-10-28 11:10:36 +02:00
|
|
|
my $bFirst = true;
|
2015-11-22 23:44:01 +02:00
|
|
|
my $strHostName = $self->{oManifest}->variableReplace($oChild->paramGet('host'));
|
2015-10-28 11:10:36 +02:00
|
|
|
|
2018-06-12 19:43:15 +02:00
|
|
|
if ($bShow)
|
|
|
|
{
|
|
|
|
my $oSectionBodyExecute = $oSectionBodyElement->addNew(HTML_DIV, "execute");
|
|
|
|
$oSectionBodyExecute->
|
|
|
|
addNew(HTML_DIV, "execute-title",
|
|
|
|
{strContent => "<span class=\"host\">${strHostName}</span> <b>⇒</b> " .
|
|
|
|
$self->processText($oChild->nodeGet('title')->textGet())});
|
|
|
|
$oExecuteBodyElement = $oSectionBodyExecute->addNew(HTML_DIV, "execute-body");
|
|
|
|
}
|
2015-10-28 11:10:36 +02:00
|
|
|
|
|
|
|
foreach my $oExecute ($oChild->nodeList('execute'))
|
|
|
|
{
|
2015-11-22 23:44:01 +02:00
|
|
|
my $bExeShow = !$oExecute->paramTest('show', 'n');
|
|
|
|
my $bExeExpectedError = defined($oExecute->paramGet('err-expect', false));
|
|
|
|
|
2018-06-12 19:43:15 +02:00
|
|
|
my ($strCommand, $strOutput) = $self->execute(
|
|
|
|
$oSection, $strHostName, $oExecute, {iIndent => $iDepth + 3, bShow => $bShow && $bExeShow});
|
2015-10-28 11:10:36 +02:00
|
|
|
|
2018-06-12 19:43:15 +02:00
|
|
|
if ($bShow && $bExeShow)
|
2015-10-28 11:10:36 +02:00
|
|
|
{
|
2015-11-22 23:44:01 +02:00
|
|
|
# Add continuation chars and proper spacing
|
|
|
|
$strCommand =~ s/\n/\n /smg;
|
|
|
|
|
2015-10-28 11:10:36 +02:00
|
|
|
$oExecuteBodyElement->
|
2015-11-22 23:44:01 +02:00
|
|
|
addNew(HTML_PRE, "execute-body-cmd",
|
|
|
|
{strContent => $strCommand, bPre => true});
|
|
|
|
|
|
|
|
my $strHighLight = $self->{oManifest}->variableReplace($oExecute->fieldGet('exe-highlight', false));
|
|
|
|
my $bHighLightFound = false;
|
2015-10-28 11:10:36 +02:00
|
|
|
|
|
|
|
if (defined($strOutput))
|
|
|
|
{
|
|
|
|
my $bHighLightOld;
|
|
|
|
my $strHighLightOutput;
|
|
|
|
|
2015-11-22 23:44:01 +02:00
|
|
|
if ($oExecute->fieldTest('exe-highlight-type', 'error'))
|
|
|
|
{
|
|
|
|
$bExeExpectedError = true;
|
|
|
|
}
|
|
|
|
|
2015-10-28 11:10:36 +02:00
|
|
|
foreach my $strLine (split("\n", $strOutput))
|
|
|
|
{
|
|
|
|
my $bHighLight = defined($strHighLight) && $strLine =~ /$strHighLight/;
|
|
|
|
|
|
|
|
if (defined($bHighLightOld) && $bHighLight != $bHighLightOld)
|
|
|
|
{
|
|
|
|
$oExecuteBodyElement->
|
2015-11-22 23:44:01 +02:00
|
|
|
addNew(HTML_PRE, 'execute-body-output' .
|
|
|
|
($bHighLightOld ? '-highlight' . ($bExeExpectedError ? '-error' : '') : ''),
|
|
|
|
{strContent => $strHighLightOutput, bPre => true});
|
2015-10-28 11:10:36 +02:00
|
|
|
|
|
|
|
undef($strHighLightOutput);
|
|
|
|
}
|
|
|
|
|
2015-11-22 23:44:01 +02:00
|
|
|
$strHighLightOutput .= (defined($strHighLightOutput) ? "\n" : '') . $strLine;
|
2015-10-28 11:10:36 +02:00
|
|
|
$bHighLightOld = $bHighLight;
|
|
|
|
|
|
|
|
$bHighLightFound = $bHighLightFound ? true : $bHighLight ? true : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (defined($bHighLightOld))
|
|
|
|
{
|
|
|
|
$oExecuteBodyElement->
|
2015-11-22 23:44:01 +02:00
|
|
|
addNew(HTML_PRE, 'execute-body-output' .
|
|
|
|
($bHighLightOld ? '-highlight' . ($bExeExpectedError ? '-error' : '') : ''),
|
|
|
|
{strContent => $strHighLightOutput, bPre => true});
|
2015-10-28 11:10:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$bFirst = true;
|
|
|
|
}
|
2015-11-22 23:44:01 +02:00
|
|
|
|
|
|
|
if ($self->{bExe} && $self->isRequired($oSection) && defined($strHighLight) && !$bHighLightFound)
|
|
|
|
{
|
|
|
|
confess &log(ERROR, "unable to find a match for highlight: ${strHighLight}");
|
|
|
|
}
|
2015-10-28 11:10:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$bFirst = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
# Add code block
|
|
|
|
elsif ($oChild->nameGet() eq 'code-block')
|
|
|
|
{
|
2016-08-02 18:49:39 +02:00
|
|
|
my $strValue = $oChild->valueGet();
|
|
|
|
|
|
|
|
# Trim linefeeds from the beginning and all whitespace from the end
|
|
|
|
$strValue =~ s/^\n+|\s+$//g;
|
|
|
|
|
|
|
|
# Find the line with the fewest leading spaces
|
|
|
|
my $iSpaceMin = undef;
|
|
|
|
|
|
|
|
foreach my $strLine (split("\n", $strValue))
|
|
|
|
{
|
|
|
|
$strLine =~ s/\s+$//;
|
|
|
|
|
|
|
|
my $iSpaceMinTemp = length($strLine) - length(trim($strLine));
|
|
|
|
|
|
|
|
if (!defined($iSpaceMin) || $iSpaceMinTemp < $iSpaceMin)
|
|
|
|
{
|
|
|
|
$iSpaceMin = $iSpaceMinTemp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Replace the leading spaces
|
|
|
|
$strValue =~ s/^( ){$iSpaceMin}//smg;
|
|
|
|
|
|
|
|
$oSectionBodyElement->addNew(
|
|
|
|
HTML_PRE, 'code-block', {strContent => $strValue, bPre => true});
|
2015-10-28 11:10:36 +02:00
|
|
|
}
|
2018-12-18 21:56:39 +02:00
|
|
|
# Add table
|
|
|
|
elsif ($oChild->nameGet() eq 'table')
|
|
|
|
{
|
|
|
|
my $oTableTitle;
|
|
|
|
if ($oChild->nodeTest('title'))
|
|
|
|
{
|
|
|
|
$oTableTitle = $oChild->nodeGet('title');
|
|
|
|
}
|
|
|
|
|
|
|
|
my $oTableElement = $oSectionBodyElement->addNew(HTML_TABLE, 'table');
|
|
|
|
my @oyColumn;
|
|
|
|
|
2018-12-20 23:20:54 +02:00
|
|
|
# If there is a title element then add it as the caption for the table
|
|
|
|
if (defined($oTableTitle))
|
|
|
|
{
|
|
|
|
# Print the label (e.g. Table 1:) in front of the title if one exists
|
|
|
|
my $strTableTitle = $oTableTitle->paramTest('label') ?
|
|
|
|
($oTableTitle->paramGet('label') . ': '. $self->processText($oTableTitle->textGet())) :
|
|
|
|
$self->processText($oTableTitle->textGet());
|
|
|
|
|
|
|
|
$oTableElement->addNew(HTML_TABLE_CAPTION, 'table-caption', {strContent => $strTableTitle});
|
|
|
|
}
|
|
|
|
|
2018-12-18 21:56:39 +02:00
|
|
|
# Build the header
|
|
|
|
if ($oChild->nodeTest('table-header'))
|
|
|
|
{
|
|
|
|
my $oHeader = $oChild->nodeGet('table-header');
|
|
|
|
@oyColumn = $oHeader->nodeList('table-column');
|
|
|
|
|
|
|
|
my $oHeaderRowElement = $oTableElement->addNew(HTML_TR, 'table-header-row');
|
|
|
|
|
|
|
|
foreach my $oColumn (@oyColumn)
|
|
|
|
{
|
|
|
|
# Each column can have different alignment properties - if not set, then default to align left
|
|
|
|
my $strAlign = $oColumn->paramGet("align", false, 'left');
|
|
|
|
my $bFill = $oColumn->paramTest('fill', 'y');
|
|
|
|
|
|
|
|
$oHeaderRowElement->addNew(
|
|
|
|
HTML_TH,
|
2019-05-15 19:04:56 +02:00
|
|
|
"table-header-${strAlign}" . ($bFill ? " table-header-fill" : ""),
|
2018-12-18 21:56:39 +02:00
|
|
|
{strContent => $self->processText($oColumn->textGet())});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Build the rows
|
|
|
|
foreach my $oRow ($oChild->nodeGet('table-data')->nodeList('table-row'))
|
|
|
|
{
|
|
|
|
my $oRowElement = $oTableElement->addNew(HTML_TR, 'table-row');
|
|
|
|
my @oRowCellList = $oRow->nodeList('table-cell');
|
|
|
|
|
|
|
|
for (my $iRowCellIdx = 0; $iRowCellIdx < @oRowCellList; $iRowCellIdx++)
|
|
|
|
{
|
|
|
|
my $oRowCell = $oRowCellList[$iRowCellIdx];
|
|
|
|
|
|
|
|
# If a header row was defined, then get the column alignment, else default to left
|
|
|
|
my $strAlign = @oyColumn > 0 ? $oyColumn[$iRowCellIdx]->paramGet("align", false, 'left') : 'left';
|
|
|
|
|
|
|
|
$oRowElement->addNew(
|
|
|
|
HTML_TD, "table-data-${strAlign}", {strContent => $self->processText($oRowCell->textGet())});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-10-28 11:10:36 +02:00
|
|
|
# Add descriptive text
|
|
|
|
elsif ($oChild->nameGet() eq 'p')
|
|
|
|
{
|
|
|
|
$oSectionBodyElement->
|
|
|
|
addNew(HTML_DIV, 'section-body-text',
|
2015-11-22 23:44:01 +02:00
|
|
|
{strContent => $self->processText($oChild->textGet())});
|
2015-10-28 11:10:36 +02:00
|
|
|
}
|
|
|
|
# Add option descriptive text
|
|
|
|
elsif ($oChild->nameGet() eq 'option-description')
|
|
|
|
{
|
|
|
|
my $strOption = $oChild->paramGet("key");
|
|
|
|
my $oDescription = ${$self->{oReference}->{oConfigHash}}{&CONFIG_HELP_OPTION}{$strOption}{&CONFIG_HELP_DESCRIPTION};
|
|
|
|
|
|
|
|
if (!defined($oDescription))
|
|
|
|
{
|
2016-06-12 15:01:56 +02:00
|
|
|
confess &log(ERROR, "unable to find ${strOption} option in sections - try adding option?");
|
|
|
|
}
|
|
|
|
|
|
|
|
$oSectionBodyElement->
|
|
|
|
addNew(HTML_DIV, 'section-body-text',
|
|
|
|
{strContent => $self->processText($oDescription)});
|
|
|
|
}
|
|
|
|
# Add cmd descriptive text
|
|
|
|
elsif ($oChild->nameGet() eq 'cmd-description')
|
|
|
|
{
|
|
|
|
my $strCommand = $oChild->paramGet("key");
|
|
|
|
my $oDescription = ${$self->{oReference}->{oConfigHash}}{&CONFIG_HELP_COMMAND}{$strCommand}{&CONFIG_HELP_DESCRIPTION};
|
|
|
|
|
|
|
|
if (!defined($oDescription))
|
|
|
|
{
|
|
|
|
confess &log(ERROR, "unable to find ${strCommand} command in sections - try adding command?");
|
2015-10-28 11:10:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$oSectionBodyElement->
|
|
|
|
addNew(HTML_DIV, 'section-body-text',
|
2015-11-22 23:44:01 +02:00
|
|
|
{strContent => $self->processText($oDescription)});
|
2015-10-28 11:10:36 +02:00
|
|
|
}
|
|
|
|
# Add/remove backrest config options
|
|
|
|
elsif ($oChild->nameGet() eq 'backrest-config')
|
|
|
|
{
|
2015-11-22 23:44:01 +02:00
|
|
|
my $oConfigElement = $self->backrestConfigProcess($oSection, $oChild, $iDepth + 3);
|
|
|
|
|
|
|
|
if (defined($oConfigElement))
|
|
|
|
{
|
|
|
|
$oSectionBodyElement->add($oConfigElement);
|
|
|
|
}
|
2015-10-28 11:10:36 +02:00
|
|
|
}
|
|
|
|
# Add/remove postgres config options
|
|
|
|
elsif ($oChild->nameGet() eq 'postgres-config')
|
|
|
|
{
|
2015-11-22 23:44:01 +02:00
|
|
|
my $oConfigElement = $self->postgresConfigProcess($oSection, $oChild, $iDepth + 3);
|
|
|
|
|
|
|
|
if (defined($oConfigElement))
|
|
|
|
{
|
|
|
|
$oSectionBodyElement->add($oConfigElement);
|
|
|
|
}
|
2015-10-28 11:10:36 +02:00
|
|
|
}
|
2016-05-26 15:34:03 +02:00
|
|
|
# Add a list
|
|
|
|
elsif ($oChild->nameGet() eq 'list')
|
|
|
|
{
|
|
|
|
my $oList = $oSectionBodyElement->addNew(HTML_UL, 'list-unordered');
|
|
|
|
|
|
|
|
foreach my $oListItem ($oChild->nodeList())
|
|
|
|
{
|
|
|
|
$oList->addNew(HTML_LI, 'list-unordered', {strContent => $self->processText($oListItem->textGet())});
|
|
|
|
}
|
|
|
|
}
|
2016-05-26 16:34:10 +02:00
|
|
|
# Add a subtitle
|
|
|
|
elsif ($oChild->nameGet() eq 'subtitle')
|
|
|
|
{
|
|
|
|
$oSectionBodyElement->
|
|
|
|
addNew(HTML_DIV, "section${iDepth}-subtitle",
|
|
|
|
{strContent => $self->processText($oChild->textGet())});
|
|
|
|
}
|
|
|
|
# Add a subsubtitle
|
|
|
|
elsif ($oChild->nameGet() eq 'subsubtitle')
|
|
|
|
{
|
|
|
|
$oSectionBodyElement->
|
|
|
|
addNew(HTML_DIV, "section${iDepth}-subsubtitle",
|
|
|
|
{strContent => $self->processText($oChild->textGet())});
|
|
|
|
}
|
2015-10-28 11:10:36 +02:00
|
|
|
# Add a subsection
|
|
|
|
elsif ($oChild->nameGet() eq 'section')
|
|
|
|
{
|
|
|
|
my ($oChildSectionElement, $oChildSectionTocElement) =
|
2016-11-07 17:06:35 +02:00
|
|
|
$self->sectionProcess($oChild, $strAnchor, "${strSectionNo}.${iSectionNo}", $iDepth + 1);
|
2015-10-28 11:10:36 +02:00
|
|
|
|
|
|
|
$oSectionBodyElement->add($oChildSectionElement);
|
2016-09-04 15:27:56 +02:00
|
|
|
|
|
|
|
if (defined($oChildSectionTocElement))
|
|
|
|
{
|
|
|
|
$oSectionTocElement->add($oChildSectionTocElement);
|
|
|
|
}
|
2016-11-07 17:06:35 +02:00
|
|
|
|
|
|
|
$iSectionNo++;
|
2015-10-28 11:10:36 +02:00
|
|
|
}
|
2018-12-30 16:40:20 +02:00
|
|
|
# Add an admonition (e.g. NOTE, WARNING, etc)
|
|
|
|
elsif ($oChild->nameGet() eq 'admonition')
|
|
|
|
{
|
|
|
|
my $oAdmonition = $oSectionBodyElement->addNew(HTML_DIV, 'admonition');
|
|
|
|
$oAdmonition->addNew(HTML_DIV, $oChild->paramGet('type'), {strContent => uc($oChild->paramGet('type')) . ": "});
|
|
|
|
$oAdmonition->addNew(HTML_DIV, $oChild->paramGet('type') . '-text',
|
|
|
|
{strContent => $self->processText($oChild->textGet())});
|
|
|
|
}
|
2015-11-22 23:44:01 +02:00
|
|
|
# Check if the child can be processed by a parent
|
|
|
|
else
|
2015-10-28 11:10:36 +02:00
|
|
|
{
|
2015-11-22 23:44:01 +02:00
|
|
|
$self->sectionChildProcess($oSection, $oChild, $iDepth + 1);
|
2015-10-28 11:10:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'oSectionElement', value => $oSectionElement, trace => true},
|
2016-09-04 15:27:56 +02:00
|
|
|
{name => 'oSectionTocElement', value => $oSection->paramTest('toc', 'n') ? undef : $oSectionTocElement, trace => true}
|
2015-10-28 11:10:36 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# backrestConfigProcess
|
|
|
|
####################################################################################################################################
|
|
|
|
sub backrestConfigProcess
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
2015-11-22 23:44:01 +02:00
|
|
|
$oSection,
|
2015-10-28 11:10:36 +02:00
|
|
|
$oConfig,
|
|
|
|
$iDepth
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
2016-05-26 15:09:42 +02:00
|
|
|
__PACKAGE__ . '->backrestConfigProcess', \@_,
|
2015-11-22 23:44:01 +02:00
|
|
|
{name => 'oSection'},
|
2015-10-28 11:10:36 +02:00
|
|
|
{name => 'oConfig'},
|
|
|
|
{name => 'iDepth'}
|
|
|
|
);
|
|
|
|
|
2015-11-22 23:44:01 +02:00
|
|
|
# Generate the config
|
|
|
|
my $oConfigElement;
|
|
|
|
my ($strFile, $strConfig, $bShow) = $self->backrestConfig($oSection, $oConfig, $iDepth);
|
2015-10-28 11:10:36 +02:00
|
|
|
|
2015-11-22 23:44:01 +02:00
|
|
|
if ($bShow)
|
2015-10-28 11:10:36 +02:00
|
|
|
{
|
2015-11-22 23:44:01 +02:00
|
|
|
my $strHostName = $self->{oManifest}->variableReplace($oConfig->paramGet('host'));
|
2015-10-28 11:10:36 +02:00
|
|
|
|
2015-11-22 23:44:01 +02:00
|
|
|
# Render the config
|
2020-03-10 21:41:56 +02:00
|
|
|
$oConfigElement = new pgBackRestDoc::Html::DocHtmlElement(HTML_DIV, "config");
|
2015-10-28 11:10:36 +02:00
|
|
|
|
2015-11-22 23:44:01 +02:00
|
|
|
$oConfigElement->
|
|
|
|
addNew(HTML_DIV, "config-title",
|
|
|
|
{strContent => "<span class=\"host\">${strHostName}</span>:<span class=\"file\">${strFile}</span>" .
|
|
|
|
" <b>⇒</b> " . $self->processText($oConfig->nodeGet('title')->textGet())});
|
2015-10-28 11:10:36 +02:00
|
|
|
|
2015-11-22 23:44:01 +02:00
|
|
|
my $oConfigBodyElement = $oConfigElement->addNew(HTML_DIV, "config-body");
|
|
|
|
#
|
|
|
|
# $oConfigBodyElement->
|
|
|
|
# addNew(HTML_DIV, "config-body-title",
|
|
|
|
# {strContent => "${strFile}:"});
|
2015-10-28 11:10:36 +02:00
|
|
|
|
2015-11-22 23:44:01 +02:00
|
|
|
$oConfigBodyElement->
|
|
|
|
addNew(HTML_DIV, "config-body-output",
|
|
|
|
{strContent => $strConfig});
|
|
|
|
}
|
2015-10-28 11:10:36 +02:00
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'oConfigElement', value => $oConfigElement, trace => true}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# postgresConfigProcess
|
|
|
|
####################################################################################################################################
|
|
|
|
sub postgresConfigProcess
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
2015-11-22 23:44:01 +02:00
|
|
|
$oSection,
|
2015-10-28 11:10:36 +02:00
|
|
|
$oConfig,
|
|
|
|
$iDepth
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
2016-05-26 15:09:42 +02:00
|
|
|
__PACKAGE__ . '->postgresConfigProcess', \@_,
|
2015-11-22 23:44:01 +02:00
|
|
|
{name => 'oSection'},
|
2015-10-28 11:10:36 +02:00
|
|
|
{name => 'oConfig'},
|
|
|
|
{name => 'iDepth'}
|
|
|
|
);
|
|
|
|
|
2015-11-22 23:44:01 +02:00
|
|
|
# Generate the config
|
|
|
|
my $oConfigElement;
|
|
|
|
my ($strFile, $strConfig, $bShow) = $self->postgresConfig($oSection, $oConfig, $iDepth);
|
2015-10-28 11:10:36 +02:00
|
|
|
|
2015-11-22 23:44:01 +02:00
|
|
|
if ($bShow)
|
2015-10-28 11:10:36 +02:00
|
|
|
{
|
2015-11-22 23:44:01 +02:00
|
|
|
# Render the config
|
|
|
|
my $strHostName = $self->{oManifest}->variableReplace($oConfig->paramGet('host'));
|
2020-03-10 21:41:56 +02:00
|
|
|
$oConfigElement = new pgBackRestDoc::Html::DocHtmlElement(HTML_DIV, "config");
|
2015-10-28 11:10:36 +02:00
|
|
|
|
2015-11-22 23:44:01 +02:00
|
|
|
$oConfigElement->
|
|
|
|
addNew(HTML_DIV, "config-title",
|
|
|
|
{strContent => "<span class=\"host\">${strHostName}</span>:<span class=\"file\">${strFile}</span>" .
|
|
|
|
" <b>⇒</b> " . $self->processText($oConfig->nodeGet('title')->textGet())});
|
2015-10-28 11:10:36 +02:00
|
|
|
|
2015-11-22 23:44:01 +02:00
|
|
|
my $oConfigBodyElement = $oConfigElement->addNew(HTML_DIV, "config-body");
|
2015-10-28 11:10:36 +02:00
|
|
|
|
2015-11-22 23:44:01 +02:00
|
|
|
# $oConfigBodyElement->
|
|
|
|
# addNew(HTML_DIV, "config-body-title",
|
|
|
|
# {strContent => "append to ${strFile}:"});
|
2015-10-28 11:10:36 +02:00
|
|
|
|
2015-11-22 23:44:01 +02:00
|
|
|
$oConfigBodyElement->
|
|
|
|
addNew(HTML_DIV, "config-body-output",
|
|
|
|
{strContent => defined($strConfig) ? $strConfig : '<No PgBackRest Settings>'});
|
2015-10-28 11:10:36 +02:00
|
|
|
|
2015-11-22 23:44:01 +02:00
|
|
|
$oConfig->fieldSet('actual-config', $strConfig);
|
2015-10-28 11:10:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'oConfigElement', value => $oConfigElement, trace => true}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
1;
|