Src/Plugins/OutHtml.Internal.ps1
#region OutHtml Private Functions function New-PScriboHtmlOption { <# .SYNOPSIS Sets the text plugin specific formatting/output options. .NOTES All plugin options should be prefixed with the plugin name. #> [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions','')] [OutputType([System.Collections.Hashtable])] param ( [Parameter(ValueFromPipelineByPropertyName)] [ValidateNotNull()] [System.Boolean] $NoPageLayoutStyle = $false ) process { return @{ NoPageLayoutStyle = $NoPageLayoutStyle; } } #end process } #end function New-PScriboHtmlOption function GetHtmlStyle { <# .SYNOPSIS Generates html stylesheet style attributes from a PScribo document style. #> [CmdletBinding()] [OutputType([System.String])] param ( ## PScribo document style [Parameter(Mandatory, ValueFromPipeline)] [System.Object] $Style ) process { $styleBuilder = New-Object -TypeName System.Text.StringBuilder; [ref] $null = $styleBuilder.AppendFormat(" font-family: '{0}';", $Style.Font -join "','"); ## Create culture invariant decimal https://github.com/iainbrighton/PScribo/issues/6 $invariantFontSize = ConvertToInvariantCultureString -Object ($Style.Size / 12) -Format 'f2'; [ref] $null = $styleBuilder.AppendFormat(' font-size: {0}em;', $invariantFontSize); [ref] $null = $styleBuilder.AppendFormat(' text-align: {0};', $Style.Align.ToLower()); if ($Style.Bold) { [ref] $null = $styleBuilder.Append(' font-weight: bold;'); } else { [ref] $null = $styleBuilder.Append(' font-weight: normal;'); } if ($Style.Italic) { [ref] $null = $styleBuilder.Append(' font-style: italic;'); } if ($Style.Underline) { [ref] $null = $styleBuilder.Append(' text-decoration: underline;'); } if ($Style.Color.StartsWith('#')) { [ref] $null = $styleBuilder.AppendFormat(' color: {0};', $Style.Color.ToLower()); } else { [ref] $null = $styleBuilder.AppendFormat(' color: #{0};', $Style.Color); } if ($Style.BackgroundColor) { if ($Style.BackgroundColor.StartsWith('#')) { [ref] $null = $styleBuilder.AppendFormat(' background-color: {0};', $Style.BackgroundColor.ToLower()); } else { [ref] $null = $styleBuilder.AppendFormat(' background-color: #{0};', $Style.BackgroundColor.ToLower()); } } return $styleBuilder.ToString(); } } #end function GetHtmlStyle function GetHtmlTableStyle { <# .SYNOPSIS Generates html stylesheet style attributes from a PScribo document table style. #> [CmdletBinding()] [OutputType([System.String])] param ( ## PScribo document table style [Parameter(Mandatory, ValueFromPipeline)] [System.Object] $TableStyle ) process { $tableStyleBuilder = New-Object -TypeName 'System.Text.StringBuilder'; [ref] $null = $tableStyleBuilder.AppendFormat(' padding: {0}em {1}em {2}em {3}em;', (ConvertToInvariantCultureString -Object (ConvertMmToEm $TableStyle.PaddingTop)), (ConvertToInvariantCultureString -Object (ConvertMmToEm $TableStyle.PaddingRight)), (ConvertToInvariantCultureString -Object (ConvertMmToEm $TableStyle.PaddingBottom)), (ConvertToInvariantCultureString -Object (ConvertMmToEm $TableStyle.PaddingLeft))), [ref] $null = $tableStyleBuilder.AppendFormat(' border-style: {0};', $TableStyle.BorderStyle.ToLower()); if ($TableStyle.BorderWidth -gt 0) { $invariantBorderWidth = ConvertToInvariantCultureString -Object (ConvertMmToEm $TableStyle.BorderWidth); [ref] $null = $tableStyleBuilder.AppendFormat(' border-width: {0}em;', $invariantBorderWidth); if ($TableStyle.BorderColor.Contains('#')) { [ref] $null = $tableStyleBuilder.AppendFormat(' border-color: {0};', $TableStyle.BorderColor); } else { [ref] $null = $tableStyleBuilder.AppendFormat(' border-color: #{0};', $TableStyle.BorderColor); } } [ref] $null = $tableStyleBuilder.Append(' border-collapse: collapse;'); ## <table align="center"> is deprecated in Html5 if ($TableStyle.Align -eq 'Center') { [ref] $null = $tableStyleBuilder.Append(' margin-left: auto; margin-right: auto;'); } elseif ($TableStyle.Align -eq 'Right') { [ref] $null = $tableStyleBuilder.Append(' margin-left: auto; margin-right: 0;'); } return $tableStyleBuilder.ToString(); } } #end function Outhtmltablestyle function GetHtmlTableDiv { <# .SYNOPSIS Generates Html <div style=..><table style=..> tags based upon table width, columns and indentation .NOTES A <div> is required to ensure that the table stays within the "page" boundaries/margins. #> param ( [Parameter(Mandatory, ValueFromPipeline)] [ValidateNotNull()] [System.Object] $Table ) process { $divBuilder = New-Object -TypeName 'System.Text.StringBuilder'; if ($Table.Tabs -gt 0) { $invariantMarginLeft = ConvertToInvariantCultureString -Object (ConvertMmToEm -Millimeter (12.7 * $Table.Tabs)); [ref] $null = $divBuilder.AppendFormat('<div style="margin-left: {0}em;">' -f $invariantMarginLeft); } else { [ref] $null = $divBuilder.Append('<div>' -f (ConvertMmToEm -Millimeter (12.7 * $Table.Tabs))); } if ($Table.List) { [ref] $null = $divBuilder.AppendFormat('<table class="{0}-list"', $Table.Style.ToLower()); } else { [ref] $null = $divBuilder.AppendFormat('<table class="{0}"', $Table.Style.ToLower()); } $styleElements = @(); if ($Table.Width -gt 0) { $styleElements += 'width:{0}%;' -f $Table.Width; } if ($Table.ColumnWidths) { $styleElements += 'table-layout: fixed;'; $styleElements += 'word-break: break-word;' } if ($styleElements.Count -gt 0) { [ref] $null = $divBuilder.AppendFormat(' style="{0}">', [String]::Join(' ', $styleElements)); } else { [ref] $null = $divBuilder.Append('>'); } return $divBuilder.ToString(); } } #end function GetHtmlTableDiv function GetHtmlTableColGroup { <# .SYNOPSIS Generates Html <colgroup> tags based on table column widths #> [CmdletBinding()] [OutputType([System.String])] param ( [Parameter(Mandatory, ValueFromPipeline)] [ValidateNotNull()] [System.Object] $Table ) process { $colGroupBuilder = New-Object -TypeName 'System.Text.StringBuilder'; if ($Table.ColumnWidths) { [ref] $null = $colGroupBuilder.Append('<colgroup>'); foreach ($columnWidth in $Table.ColumnWidths) { if ($null -eq $columnWidth) { [ref] $null = $colGroupBuilder.Append('<col />'); } else { [ref] $null = $colGroupBuilder.AppendFormat('<col style="max-width:{0}%; min-width:{0}%; width:{0}%" />', $columnWidth); } } [ref] $null = $colGroupBuilder.AppendLine('</colgroup>'); } return $colGroupBuilder.ToString(); } } #end function GetHtmlTableDiv function OutHtmlTOC { <# .SYNOPSIS Generates Html table of contents. #> [CmdletBinding()] [OutputType([System.String])] param ( [Parameter(Mandatory, ValueFromPipeline)] [System.Object] $TOC ) process { $tocBuilder = New-Object -TypeName 'System.Text.StringBuilder'; [ref] $null = $tocBuilder.AppendFormat('<h1 class="{0}">{1}</h1>', $TOC.ClassId, $TOC.Name); #[ref] $null = $tocBuilder.AppendLine('<table style="width: 100%;">'); [ref] $null = $tocBuilder.AppendLine('<table>'); foreach ($tocEntry in $Document.TOC) { $sectionNumberIndent = ' ' * $tocEntry.Level; if ($Document.Options['EnableSectionNumbering']) { [ref] $null = $tocBuilder.AppendFormat('<tr><td>{0}</td><td>{1}<a href="#{2}" style="text-decoration: none;">{3}</a></td></tr>', $tocEntry.Number, $sectionNumberIndent, $tocEntry.Id, $tocEntry.Name).AppendLine(); } else { [ref] $null = $tocBuilder.AppendFormat('<tr><td>{0}<a href="#{1}" style="text-decoration: none;">{2}</a></td></tr>', $sectionNumberIndent, $tocEntry.Id, $tocEntry.Name).AppendLine(); } } [ref] $null = $tocBuilder.AppendLine('</table>'); return $tocBuilder.ToString(); } #end process } #end function OutHtmlTOC function OutHtmlBlankLine { <# .SYNOPSIS Outputs html PScribo.Blankline. #> [CmdletBinding()] [OutputType([System.String])] param ( [Parameter(Mandatory, ValueFromPipeline)] [System.Object] $BlankLine ) process { $blankLineBuilder = New-Object -TypeName System.Text.StringBuilder; for ($i = 0; $i -lt $BlankLine.LineCount; $i++) { [ref] $null = $blankLineBuilder.Append('<br />'); } return $blankLineBuilder.ToString(); } #end process } #end function OutHtmlBlankLine function OutHtmlStyle { <# .SYNOPSIS Generates an in-line HTML CSS stylesheet from a PScribo document styles and table styles. #> [CmdletBinding()] [OutputType([System.String])] param ( ## PScribo document styles [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [System.Collections.Hashtable] $Styles, ## PScribo document tables styles [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [System.Collections.Hashtable] $TableStyles, ## Suppress page layout styling [Parameter(ValueFromPipelineByPropertyName)] [System.Management.Automation.SwitchParameter] $NoPageLayoutStyle ) process { $stylesBuilder = New-Object -TypeName 'System.Text.StringBuilder'; [ref] $null = $stylesBuilder.AppendLine('<style type="text/css">'); if (-not $NoPageLayoutStyle) { ## Add HTML page layout styling options, e.g. when emailing HTML documents [ref] $null = $stylesBuilder.AppendLine('html { height: 100%; -webkit-background-size: cover; -moz-background-size: cover; -o-background-size: cover; background-size: cover; background: #f8f8f8; }'); [ref] $null = $stylesBuilder.Append("page { background: white; width: $($Document.Options['PageWidth'])mm; display: block; margin-top: 1em; margin-left: auto; margin-right: auto; margin-bottom: 1em; "); [ref] $null = $stylesBuilder.AppendLine('border-style: solid; border-width: 1px; border-color: #c6c6c6; }'); [ref] $null = $stylesBuilder.AppendLine('@media print { body, page { margin: 0; box-shadow: 0; } }'); [ref] $null = $stylesBuilder.AppendLine('hr { margin-top: 1.0em; }'); } foreach ($style in $Styles.Keys) { ## Build style $htmlStyle = GetHtmlStyle -Style $Styles[$style]; [ref] $null = $stylesBuilder.AppendFormat(' .{0} {{{1} }}', $Styles[$style].Id, $htmlStyle).AppendLine(); } foreach ($tableStyle in $TableStyles.Keys) { $tStyle = $TableStyles[$tableStyle]; $tableStyleId = $tStyle.Id.ToLower(); $htmlTableStyle = GetHtmlTableStyle -TableStyle $tStyle; $htmlHeaderStyle = GetHtmlStyle -Style $Styles[$tStyle.HeaderStyle]; $htmlRowStyle = GetHtmlStyle -Style $Styles[$tStyle.RowStyle]; $htmlAlternateRowStyle = GetHtmlStyle -Style $Styles[$tStyle.AlternateRowStyle]; ## Generate Standard table styles [ref] $null = $stylesBuilder.AppendFormat(' table.{0} {{{1} }}', $tableStyleId, $htmlTableStyle).AppendLine(); [ref] $null = $stylesBuilder.AppendFormat(' table.{0} th {{{1}{2} }}', $tableStyleId, $htmlHeaderStyle, $htmlTableStyle).AppendLine(); [ref] $null = $stylesBuilder.AppendFormat(' table.{0} tr:nth-child(odd) td {{{1}{2} }}', $tableStyleId, $htmlRowStyle, $htmlTableStyle).AppendLine(); [ref] $null = $stylesBuilder.AppendFormat(' table.{0} tr:nth-child(even) td {{{1}{2} }}', $tableStyleId, $htmlAlternateRowStyle, $htmlTableStyle).AppendLine(); ## Generate List table styles [ref] $null = $stylesBuilder.AppendFormat(' table.{0}-list {{{1} }}', $tableStyleId, $htmlTableStyle).AppendLine(); [ref] $null = $stylesBuilder.AppendFormat(' table.{0}-list td:nth-child(1) {{{1}{2} }}', $tableStyleId, $htmlHeaderStyle, $htmlTableStyle).AppendLine(); [ref] $null = $stylesBuilder.AppendFormat(' table.{0}-list td:nth-child(2) {{{1}{2} }}', $tableStyleId, $htmlRowStyle, $htmlTableStyle).AppendLine(); } #end foreach style [ref] $null = $stylesBuilder.AppendLine('</style>'); return $stylesBuilder.ToString().TrimEnd(); } #end process } #end function OutHtmlStyle function OutHtmlSection { <# .SYNOPSIS Output formatted Html section. #> [CmdletBinding()] [OutputType([System.String])] param ( ## Section to output [Parameter(Mandatory, ValueFromPipeline)] [System.Object] $Section ) process { [System.Text.StringBuilder] $sectionBuilder = New-Object System.Text.StringBuilder; $encodedSectionName = [System.Net.WebUtility]::HtmlEncode($Section.Name); if ($Document.Options['EnableSectionNumbering']) { [string] $sectionName = '{0} {1}' -f $Section.Number, $encodedSectionName; } else { [string] $sectionName = '{0}' -f $encodedSectionName; } [int] $headerLevel = $Section.Number.Split('.').Count; ## Html <h5> is the maximum supported level if ($headerLevel -gt 6) { WriteLog -Message $localized.MaxHeadingLevelWarning -IsWarning; $headerLevel = 6; } if ([string]::IsNullOrEmpty($Section.Style)) { $className = $Document.DefaultStyle; } else { $className = $Section.Style; } [ref] $null = $sectionBuilder.AppendFormat('<a name="{0}"><h{1} class="{2}">{3}</h{1}></a>', $Section.Id, $headerLevel, $className, $sectionName.TrimStart()); foreach ($s in $Section.Sections.GetEnumerator()) { if ($s.Id.Length -gt 40) { $sectionId = '{0}[..]' -f $s.Id.Substring(0,36); } else { $sectionId = $s.Id; } $currentIndentationLevel = 1; if ($null -ne $s.PSObject.Properties['Level']) { $currentIndentationLevel = $s.Level +1; } WriteLog -Message ($localized.PluginProcessingSection -f $s.Type, $sectionId) -Indent $currentIndentationLevel; switch ($s.Type) { 'PScribo.Section' { [ref] $null = $sectionBuilder.Append((OutHtmlSection -Section $s)); } 'PScribo.Paragraph' { [ref] $null = $sectionBuilder.Append((OutHtmlParagraph -Paragraph $s)); } 'PScribo.LineBreak' { [ref] $null = $sectionBuilder.Append((OutHtmlLineBreak)); } 'PScribo.PageBreak' { [ref] $null = $sectionBuilder.Append((OutHtmlPageBreak)); } 'PScribo.Table' { [ref] $null = $sectionBuilder.Append((OutHtmlTable -Table $s)); } 'PScribo.BlankLine' { [ref] $null = $sectionBuilder.Append((OutHtmlBlankLine -BlankLine $s)); } Default { WriteLog -Message ($localized.PluginUnsupportedSection -f $s.Type) -IsWarning; } } #end switch } #end foreach return $sectionBuilder.ToString(); } #end process } # end function OutHtmlSection function GetHtmlParagraphStyle { <# .SYNOPSIS Generates html style attribute from PScribo paragraph style overrides. #> [CmdletBinding()] [OutputType([System.String])] param ( [Parameter(Mandatory, ValueFromPipeline)] [ValidateNotNull()] [System.Object] $Paragraph ) process { $paragraphStyleBuilder = New-Object -TypeName System.Text.StringBuilder; if ($Paragraph.Tabs -gt 0) { ## Default to 1/2in tab spacing $tabEm = ConvertToInvariantCultureString -Object (ConvertMmToEm -Millimeter (12.7 * $Paragraph.Tabs)) -Format 'f2'; [ref] $null = $paragraphStyleBuilder.AppendFormat(' margin-left: {0}em;', $tabEm); } if ($Paragraph.Font) { [ref] $null = $paragraphStyleBuilder.AppendFormat(" font-family: '{0}';", $Paragraph.Font -Join "','"); } if ($Paragraph.Size -gt 0) { ## Create culture invariant decimal https://github.com/iainbrighton/PScribo/issues/6 $invariantParagraphSize = ConvertToInvariantCultureString -Object ($Paragraph.Size / 12) -Format 'f2'; [ref] $null = $paragraphStyleBuilder.AppendFormat(' font-size: {0}em;', $invariantParagraphSize); } if ($Paragraph.Bold -eq $true) { [ref] $null = $paragraphStyleBuilder.Append(' font-weight: bold;'); } if ($Paragraph.Italic -eq $true) { [ref] $null = $paragraphStyleBuilder.Append(' font-style: italic;'); } if ($Paragraph.Underline -eq $true) { [ref] $null = $paragraphStyleBuilder.Append(' text-decoration: underline;'); } if (-not [System.String]::IsNullOrEmpty($Paragraph.Color) -and $Paragraph.Color.StartsWith('#')) { [ref] $null = $paragraphStyleBuilder.AppendFormat(' color: {0};', $Paragraph.Color.ToLower()); } elseif (-not [System.String]::IsNullOrEmpty($Paragraph.Color)) { [ref] $null = $paragraphStyleBuilder.AppendFormat(' color: #{0};', $Paragraph.Color.ToLower()); } return $paragraphStyleBuilder.ToString().TrimStart(); } #end process } #end function GetHtmlParagraphStyle function OutHtmlParagraph { <# .SYNOPSIS Output formatted Html paragraph. #> [CmdletBinding()] [OutputType([System.String])] param ( [Parameter(Mandatory, ValueFromPipeline)] [ValidateNotNull()] [System.Object] $Paragraph ) process { [System.Text.StringBuilder] $paragraphBuilder = New-Object -TypeName 'System.Text.StringBuilder'; $encodedText = [System.Net.WebUtility]::HtmlEncode($Paragraph.Text); if ([System.String]::IsNullOrEmpty($encodedText)) { $encodedText = [System.Net.WebUtility]::HtmlEncode($Paragraph.Id); } # $encodedText = $encodedText -replace [System.Environment]::NewLine, '<br />'; $encodedText = $encodedText.Replace([System.Environment]::NewLine, '<br />'); $customStyle = GetHtmlParagraphStyle -Paragraph $Paragraph; if ([System.String]::IsNullOrEmpty($Paragraph.Style) -and [System.String]::IsNullOrEmpty($customStyle)) { [ref] $null = $paragraphBuilder.AppendFormat('<div>{0}</div>', $encodedText); } elseif ([System.String]::IsNullOrEmpty($customStyle)) { [ref] $null = $paragraphBuilder.AppendFormat('<div class="{0}">{1}</div>', $Paragraph.Style, $encodedText); } else { [ref] $null = $paragraphBuilder.AppendFormat('<div style="{1}">{2}</div>', $Paragraph.Style, $customStyle, $encodedText); } return $paragraphBuilder.ToString(); } #end process } #end OutHtmlParagraph function GetHtmlTableList { <# .SYNOPSIS Generates list html <table> from a PScribo.Table row object. #> [CmdletBinding()] [OutputType([System.String])] param ( [Parameter(Mandatory, ValueFromPipeline)] [ValidateNotNull()] [System.Object] $Table, [Parameter(Mandatory)] [System.Object] $Row ) process { $listTableBuilder = New-Object -TypeName System.Text.StringBuilder; [ref] $null = $listTableBuilder.Append((GetHtmlTableDiv -Table $Table)); [ref] $null = $listTableBuilder.Append((GetHtmlTableColGroup -Table $Table)); [ref] $null = $listTableBuilder.Append('<tbody>'); for ($i = 0; $i -lt $Table.Columns.Count; $i++) { $propertyName = $Table.Columns[$i]; [ref] $null = $listTableBuilder.AppendFormat('<tr><td>{0}</td>', $propertyName); $propertyStyle = '{0}__Style' -f $propertyName; if ($row.PSObject.Properties[$propertyStyle]) { $propertyStyleHtml = (GetHtmlStyle -Style $Document.Styles[$Row.$propertyStyle]); if ([string]::IsNullOrEmpty($Row.$propertyName)) { [ref] $null = $listTableBuilder.AppendFormat('<td style="{0}"> </td></tr>', $propertyStyleHtml); } else { $encodedHtmlContent = [System.Net.WebUtility]::HtmlEncode($row.$propertyName); $encodedHtmlContent = $encodedHtmlContent.Replace([System.Environment]::NewLine, '<br />'); [ref] $null = $listTableBuilder.AppendFormat('<td style="{0}">{1}</td></tr>', $propertyStyleHtml, $encodedHtmlContent); } } else { if ([string]::IsNullOrEmpty($Row.$propertyName)) { [ref] $null = $listTableBuilder.Append('<td> </td></tr>'); } else { $encodedHtmlContent = [System.Net.WebUtility]::HtmlEncode($row.$propertyName); $encodedHtmlContent = $encodedHtmlContent.Replace([System.Environment]::NewLine, '<br />') [ref] $null = $listTableBuilder.AppendFormat('<td>{0}</td></tr>', $encodedHtmlContent); } } } #end for each property [ref] $null = $listTableBuilder.AppendLine('</tbody></table></div>'); return $listTableBuilder.ToString(); } #end process } #end function GetHtmlTableList function GetHtmlTable { <# .SYNOPSIS Generates html <table> from a PScribo.Table object. #> [CmdletBinding()] [OutputType([System.String])] param ( [Parameter(Mandatory, ValueFromPipeline)] [ValidateNotNull()] [System.Object] $Table ) process { $standardTableBuilder = New-Object -TypeName System.Text.StringBuilder; [ref] $null = $standardTableBuilder.Append((GetHtmlTableDiv -Table $Table)); [ref] $null = $standardTableBuilder.Append((GetHtmlTableColGroup -Table $Table)); ## Table headers [ref] $null = $standardTableBuilder.Append('<thead><tr>'); for ($i = 0; $i -lt $Table.Columns.Count; $i++) { [ref] $null = $standardTableBuilder.AppendFormat('<th>{0}</th>', $Table.Columns[$i]); } [ref] $null = $standardTableBuilder.Append('</tr></thead>'); ## Table body [ref] $null = $standardTableBuilder.AppendLine('<tbody>'); foreach ($row in $Table.Rows) { [ref] $null = $standardTableBuilder.Append('<tr>'); foreach ($propertyName in $Table.Columns) { $propertyStyle = '{0}__Style' -f $propertyName; $encodedHtmlContent = [System.Net.WebUtility]::HtmlEncode($row.$propertyName); #$encodedHtmlContent = $encodedHtmlContent -replace [System.Environment]::NewLine, '<br />'; $encodedHtmlContent = $encodedHtmlContent.Replace([System.Environment]::NewLine, '<br />'); if ($row.PSObject.Properties[$propertyStyle]) { ## Cell styles override row styles $propertyStyleHtml = (GetHtmlStyle -Style $Document.Styles[$row.$propertyStyle]).Trim(); [ref] $null = $standardTableBuilder.AppendFormat('<td style="{0}">{1}</td>', $propertyStyleHtml, $encodedHtmlContent); } elseif (($row.PSObject.Properties['__Style']) -and (-not [System.String]::IsNullOrEmpty($row.__Style))) { ## We have a row style $rowStyleHtml = (GetHtmlStyle -Style $Document.Styles[$row.__Style]).Trim(); [ref] $null = $standardTableBuilder.AppendFormat('<td style="{0}">{1}</td>', $rowStyleHtml, $encodedHtmlContent); } else { if ($null -ne $row.$propertyName) { ## Check that the property has a value [ref] $null = $standardTableBuilder.AppendFormat('<td>{0}</td>', $encodedHtmlContent); } else { [ref] $null = $standardTableBuilder.Append('<td> </td>'); } } #end if $row.PropertyStyle } #end foreach property [ref] $null = $standardTableBuilder.AppendLine('</tr>'); } #end foreach row [ref] $null = $standardTableBuilder.AppendLine('</tbody></table></div>'); return $standardTableBuilder.ToString(); } #end process } #end function GetHtmlTableList function OutHtmlTable { <# .SYNOPSIS Output formatted Html <table> from PScribo.Table object. .NOTES One table is output per table row with the -List parameter. #> [CmdletBinding()] [OutputType([System.String])] param ( [Parameter(Mandatory, ValueFromPipeline)] [ValidateNotNull()] [System.Object] $Table ) process { [System.Text.StringBuilder] $tableBuilder = New-Object -TypeName 'System.Text.StringBuilder'; if ($Table.List) { ## Create a table for each row for ($r = 0; $r -lt $Table.Rows.Count; $r++) { $row = $Table.Rows[$r]; if ($r -gt 0) { ## Add a space between each table to mirror Word output rendering [ref] $null = $tableBuilder.AppendLine('<p />'); } [ref] $null = $tableBuilder.Append((GetHtmlTableList -Table $Table -Row $row)); } #end foreach row } else { [ref] $null = $tableBuilder.Append((GetHtmlTable -Table $Table)); } #end if return $tableBuilder.ToString(); #Write-Output ($tableBuilder.ToString()) -NoEnumerate; } #end process } #end function outhtmltable function OutHtmlLineBreak { <# .SYNOPSIS Output formatted Html line break. #> [CmdletBinding()] [OutputType([System.String])] param ( ) process { return '<hr />'; } } #end function OutHtmlLineBreak function OutHtmlPageBreak { <# .SYNOPSIS Output formatted Html page break. #> [CmdletBinding()] [OutputType([System.String])] param ( ) process { [System.Text.StringBuilder] $pageBreakBuilder = New-Object 'System.Text.StringBuilder'; [ref] $null = $pageBreakBuilder.Append('</div></page>'); $topMargin = ConvertMmToEm $Document.Options['MarginTop']; $leftMargin = ConvertMmToEm $Document.Options['MarginLeft']; $bottomMargin = ConvertMmToEm $Document.Options['MarginBottom']; $rightMargin = ConvertMmToEm $Document.Options['MarginRight']; [ref] $null = $pageBreakBuilder.AppendFormat('<page><div class="{0}" style="padding-top: {1}em; padding-left: {2}em; padding-bottom: {3}em; padding-right: {4}em;">', $Document.DefaultStyle, $topMargin, $leftMargin, $bottomMargin, $rightMargin).AppendLine(); return $pageBreakBuilder.ToString(); } } #end function OutHtmlPageBreak #endregion OutHtml Private Functions # SIG # Begin signature block # MIIX1gYJKoZIhvcNAQcCoIIXxzCCF8MCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUdQ8o/fAHcqJWPz8/pVXeTiiG # MlqgghMJMIID7jCCA1egAwIBAgIQfpPr+3zGTlnqS5p31Ab8OzANBgkqhkiG9w0B # AQUFADCBizELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIG # A1UEBxMLRHVyYmFudmlsbGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhh # d3RlIENlcnRpZmljYXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcg # Q0EwHhcNMTIxMjIxMDAwMDAwWhcNMjAxMjMwMjM1OTU5WjBeMQswCQYDVQQGEwJV # UzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xMDAuBgNVBAMTJ1N5bWFu # dGVjIFRpbWUgU3RhbXBpbmcgU2VydmljZXMgQ0EgLSBHMjCCASIwDQYJKoZIhvcN # AQEBBQADggEPADCCAQoCggEBALGss0lUS5ccEgrYJXmRIlcqb9y4JsRDc2vCvy5Q # WvsUwnaOQwElQ7Sh4kX06Ld7w3TMIte0lAAC903tv7S3RCRrzV9FO9FEzkMScxeC # i2m0K8uZHqxyGyZNcR+xMd37UWECU6aq9UksBXhFpS+JzueZ5/6M4lc/PcaS3Er4 # ezPkeQr78HWIQZz/xQNRmarXbJ+TaYdlKYOFwmAUxMjJOxTawIHwHw103pIiq8r3 # +3R8J+b3Sht/p8OeLa6K6qbmqicWfWH3mHERvOJQoUvlXfrlDqcsn6plINPYlujI # fKVOSET/GeJEB5IL12iEgF1qeGRFzWBGflTBE3zFefHJwXECAwEAAaOB+jCB9zAd # BgNVHQ4EFgQUX5r1blzMzHSa1N197z/b7EyALt0wMgYIKwYBBQUHAQEEJjAkMCIG # CCsGAQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMBIGA1UdEwEB/wQIMAYB # Af8CAQAwPwYDVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NybC50aGF3dGUuY29tL1Ro # YXd0ZVRpbWVzdGFtcGluZ0NBLmNybDATBgNVHSUEDDAKBggrBgEFBQcDCDAOBgNV # HQ8BAf8EBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAXBgNVBAMTEFRpbWVTdGFtcC0y # MDQ4LTEwDQYJKoZIhvcNAQEFBQADgYEAAwmbj3nvf1kwqu9otfrjCR27T4IGXTdf # plKfFo3qHJIJRG71betYfDDo+WmNI3MLEm9Hqa45EfgqsZuwGsOO61mWAK3ODE2y # 0DGmCFwqevzieh1XTKhlGOl5QGIllm7HxzdqgyEIjkHq3dlXPx13SYcqFgZepjhq # IhKjURmDfrYwggSjMIIDi6ADAgECAhAOz/Q4yP6/NW4E2GqYGxpQMA0GCSqGSIb3 # DQEBBQUAMF4xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3Jh # dGlvbjEwMC4GA1UEAxMnU3ltYW50ZWMgVGltZSBTdGFtcGluZyBTZXJ2aWNlcyBD # QSAtIEcyMB4XDTEyMTAxODAwMDAwMFoXDTIwMTIyOTIzNTk1OVowYjELMAkGA1UE # BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMTQwMgYDVQQDEytT # eW1hbnRlYyBUaW1lIFN0YW1waW5nIFNlcnZpY2VzIFNpZ25lciAtIEc0MIIBIjAN # BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAomMLOUS4uyOnREm7Dv+h8GEKU5Ow # mNutLA9KxW7/hjxTVQ8VzgQ/K/2plpbZvmF5C1vJTIZ25eBDSyKV7sIrQ8Gf2Gi0 # jkBP7oU4uRHFI/JkWPAVMm9OV6GuiKQC1yoezUvh3WPVF4kyW7BemVqonShQDhfu # ltthO0VRHc8SVguSR/yrrvZmPUescHLnkudfzRC5xINklBm9JYDh6NIipdC6Anqh # d5NbZcPuF3S8QYYq3AhMjJKMkS2ed0QfaNaodHfbDlsyi1aLM73ZY8hJnTrFxeoz # C9Lxoxv0i77Zs1eLO94Ep3oisiSuLsdwxb5OgyYI+wu9qU+ZCOEQKHKqzQIDAQAB # o4IBVzCCAVMwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAO # BgNVHQ8BAf8EBAMCB4AwcwYIKwYBBQUHAQEEZzBlMCoGCCsGAQUFBzABhh5odHRw # Oi8vdHMtb2NzcC53cy5zeW1hbnRlYy5jb20wNwYIKwYBBQUHMAKGK2h0dHA6Ly90 # cy1haWEud3Muc3ltYW50ZWMuY29tL3Rzcy1jYS1nMi5jZXIwPAYDVR0fBDUwMzAx # oC+gLYYraHR0cDovL3RzLWNybC53cy5zeW1hbnRlYy5jb20vdHNzLWNhLWcyLmNy # bDAoBgNVHREEITAfpB0wGzEZMBcGA1UEAxMQVGltZVN0YW1wLTIwNDgtMjAdBgNV # HQ4EFgQURsZpow5KFB7VTNpSYxc/Xja8DeYwHwYDVR0jBBgwFoAUX5r1blzMzHSa # 1N197z/b7EyALt0wDQYJKoZIhvcNAQEFBQADggEBAHg7tJEqAEzwj2IwN3ijhCcH # bxiy3iXcoNSUA6qGTiWfmkADHN3O43nLIWgG2rYytG2/9CwmYzPkSWRtDebDZw73 # BaQ1bHyJFsbpst+y6d0gxnEPzZV03LZc3r03H0N45ni1zSgEIKOq8UvEiCmRDoDR # EfzdXHZuT14ORUZBbg2w6jiasTraCXEQ/Bx5tIB7rGn0/Zy2DBYr8X9bCT2bW+IW # yhOBbQAuOA2oKY8s4bL0WqkBrxWcLC9JG9siu8P+eJRRw4axgohd8D20UaF5Mysu # e7ncIAkTcetqGVvP6KUwVyyJST+5z3/Jvz4iaGNTmr1pdKzFHTx/kuDDvBzYBHUw # ggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7VvlVAIMA0GCSqGSIb3DQEBCwUAMGUx # CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 # dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9v # dCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEwMjIxMjAwMDBaMHIxCzAJBgNVBAYT # AlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2Vy # dC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNp # Z25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD407Mcfw4R # r2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx6nadBS63j/qSQ8Cl+YnUNxnXtqrw # nIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEjlpB3gvmhhCNmElQzUHSxKCa7JGnC # wlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJNYBi+qsSyrnAxZjNxPqxwoqvOf+l8 # y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2DZDv5LVOpKnqagqrhPOsZ061xPeM # 0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9hbFig3NBggfkOItqcyDQD2RzPJ6f # pjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1Ud # DwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDAzB5BggrBgEFBQcBAQRtMGsw # JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcw # AoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElE # Um9vdENBLmNydDCBgQYDVR0fBHoweDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNl # cnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDA6oDigNoY0aHR0cDov # L2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDBP # BgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93 # d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgBhv1sAzAdBgNVHQ4EFgQUWsS5eyoK # o6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8w # DQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi0RXILHwlKXaoHV0cLToaxO8wYdd+ # C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6ljlriXiSBThCk7j9xjmMOE0ut119E # efM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0kriTGxycqoSkoGjpxKAI8LpGjwCUR # 4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/PQMtARKUT8OZkDCUIQjKyNookAv4v # cn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d9gEgzpkxYz0IGhizgZtPxpMQBvwH # gfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJmoecYpJpkUe8wggU4MIIEIKADAgEC # AhAPxQCJrE9ObGzkCRS7EwyyMA0GCSqGSIb3DQEBCwUAMHIxCzAJBgNVBAYTAlVT # MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j # b20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25p # bmcgQ0EwHhcNMTcwNTI2MDAwMDAwWhcNMTkwOTI3MTIwMDAwWjB1MQswCQYDVQQG # EwJHQjETMBEGA1UECBMKR2Fyc2luZ3RvbjEPMA0GA1UEBxMGT3hmb3JkMR8wHQYD # VQQKExZWaXJ0dWFsIEVuZ2luZSBMaW1pdGVkMR8wHQYDVQQDExZWaXJ0dWFsIEVu # Z2luZSBMaW1pdGVkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnB1O # DV2jw/aMIUWnD9f9RCbAoiJ8LQcznYo42P22YEi6g7QY+kKmAzGgEhbsE4UVuGWS # el4y6FxGWq51SK5P/gqgZgzyP8FkIUzLxsCrtx9OBnsPPeL+/An5CpcsKsl2lCSz # NMwcz16hjcE0vCLio1NOcwvfO65qdNT2gRIEnIYhRX88dG3V30BH2aKWG5X9t1IW # RmozjZ8I7iLEoWFJWQSuICSGyvyiPqnXF3nxdroE8O4fc1U90x5qefX0RlwKeq47 # UFuI0Y/59pB3/jss5BYvAXp3g+6EKlDwgW1a/MLVsLQbdzlALFUv5YxEqkXA8IEM # xpwgBjm117SmyZ98QQIDAQABo4IBxTCCAcEwHwYDVR0jBBgwFoAUWsS5eyoKo6Xq # cQPAYPkt9mV1DlgwHQYDVR0OBBYEFL5NkOqMm0S8AyuXI1EZIdoK9DD/MA4GA1Ud # DwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzB3BgNVHR8EcDBuMDWgM6Ax # hi9odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLWNzLWcxLmNy # bDA1oDOgMYYvaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1j # cy1nMS5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAwEwKjAoBggrBgEFBQcCARYc # aHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBBAEwgYQGCCsGAQUF # BwEBBHgwdjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tME4G # CCsGAQUFBzAChkJodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRT # SEEyQXNzdXJlZElEQ29kZVNpZ25pbmdDQS5jcnQwDAYDVR0TAQH/BAIwADANBgkq # hkiG9w0BAQsFAAOCAQEAQC8qzSz1bIoEqbjDx3VtYDjtUjuFEVDFYi9+vREl6jM+ # iqOiNiwCXUkbxGTuDrWW9I1YOn8a7SCCYapZ+T0G3RMa+rQHXFYKbYTmXC3C41Cd # MQzZn4wTuGRNQLTgNSuclwMnNmFVe7K5S/0Dv+GaLSKuRLAxpcPxeTtmRZIIBXF7 # wwRS0+V28jB9VyeSOdqsPIFYf5GSfu7KcIhmNQ/DUroulaS5JIrPUhwkf1LZMm0B # /0adpaPbFy95M1emij96rrgy2hX8N/FrWBh13/81V6NO3b8mhCfjqb632dG4EUTi # FXDvqP2hpWw0nO/pFZsMsEK88eiV93XDDEG/MjAApzGCBDcwggQzAgEBMIGGMHIx # CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 # dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJ # RCBDb2RlIFNpZ25pbmcgQ0ECEA/FAImsT05sbOQJFLsTDLIwCQYFKw4DAhoFAKB4 # MBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQB # gjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkE # MRYEFFhtHvQbfLJk61+ZrMqx74oFQoBGMA0GCSqGSIb3DQEBAQUABIIBAI60KdZc # 3qy4glPfSV2PhhdV/MVWxvKL9OYyfrEaGZJLE4YrLshcrlS/DGdWigODUwn4SYV5 # MUMpvfahtIrXFRr3aUxVhQIAqtzB3Cz9PAHy9KRqUlT3VWo0L2llqGDMDxFU2xno # BPOu7hEVsctontABt0t5WKUxGdFbREtw44s+c401LNTZQmacggq1gfJTlCY3euva # Olr3hNhJgnzQ7RmRP49d+GPTiyppAZ6SnBAtxAxOyQe9q8HrHqDDh70O5eiYlNFI # FncR0HEY3IoxqVwNl/Scmkn4WOcftqX7fmHImrZdUDP/dRvBO3P7AL93PzPfxn8d # I/TNcHNpoPYzlEmhggILMIICBwYJKoZIhvcNAQkGMYIB+DCCAfQCAQEwcjBeMQsw # CQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xMDAuBgNV # BAMTJ1N5bWFudGVjIFRpbWUgU3RhbXBpbmcgU2VydmljZXMgQ0EgLSBHMgIQDs/0 # OMj+vzVuBNhqmBsaUDAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3 # DQEHATAcBgkqhkiG9w0BCQUxDxcNMTcxMTIwMjExMDIwWjAjBgkqhkiG9w0BCQQx # FgQUGjyTSHtIfU6RPEj2Qs4Kuv1i8/0wDQYJKoZIhvcNAQEBBQAEggEAZTigGG2U # i0nbijxDnIYh+E3eh8babvERoCo5z/fyMoPHKGI0xMaw4MPegNKSyMPeVdiza6E4 # t2f70QrX0yOAv+UkmklFvXIow098TGAiAp1x/lAaK+YjYB1I7bpuPyIkhp61FTj4 # viW/8i4PbfLdj55Wo4o3WJhR5S0d591nP1h7dL/7Z43PAaPu2PlNYfxlCQAIWwLn # wUjJKKg8znsuS22tra4iN/mLjgCv6kM8ozGzZf/Aeru3pkWn723BqM+1FZqet6Pe # xuRtNPC0mjDRtXt7zruOE5AcSBK6zhMmQUuU/OSGneM2YUh+HRY4MYlvCGW80LIM # X7Z5Y2xMefDsGg== # SIG # End signature block |