How can I add a dotted line between two texts with HTML2PDF - html2pdf

I'm trying to create a pricing recap at the end of a document I'm working on. I would like it to have a dotted line between the item on the left and the price on its right, very much like this :
However, this Index is generated with the createIndex function and I don't have the source HTML for this. And I've been trying since yesterday with differente HTML syntaxes to make it work but it is impossible. My best attempt so far is this one, but I can't automatically set the width of the dotted line :
<table style="width:100%;border-collapse: collapse;">
<tr>
<td style="width:40%;white-space:nowrap;">Item 1</td>
<td style="border-bottom:dotted 1px black;width:45%;"></td>
<td style="text-align:right;width:15%;white-space:nowrap;">Price 1€ HT</td>
</tr>
</table>
I really am stuck here, any advice would be welcome.

In this case you can use a little 'hack'. Unset the width of both texts (resolves to width: auto;) and set the width of the dotted line container to width: 99%;. For this to work you also need to set white-space: nowrap on the text elements, but you already did that.
<table style="width:100%;border-collapse: collapse;">
<tr>
<td style="white-space:nowrap;">Item 1</td>
<td style="border-bottom:dotted 1px black;width:99%"></td>
<td style="text-align:right;white-space:nowrap;">Price 1€ HT</td>
</tr>
</table>

Related

Powershell email sender with html body (htmlbody.Replace)

I'm currently a C# dotnet automation engineer. One of my tests results output is via email. My tests results output goes through powershell. I'm fairly new to email templates and HTML in general.
It's a simple HTML body with variables that I replace with $EmailBody= $EmailBody.Replace("PassedTests",$Passed) function etc
The whole premise: my script replaces Total tests/Passed/Failed/Skipped with data that I extract from a .trx file after the test run.
My extraction code:
$PassedTests = $testResultsXml.TestRun.ResultSummary.Counters.Passed
$FailedTests = $testResultsXml.TestRun.ResultSummary.Counters.Failed
$SkippedTests = $testResultsXml.TestRun.ResultSummary.Counters.Skipped
$OnlyFailed = $testResultsXml.TestRun.Results.UnitTestResult | Where-Object { $_.outcome -eq "Failed" }
$FailedTestsName = $OnlyFailed.TestName
I have the "Error list" table (picture below) that shows test names if there are any failed tests that in the HTML body
#</td>
</tr>
<!--end img-->
<tr>
<td height="15"></td>
</tr>
<!--title-->
<tr align="center">
<td align="center" style="font-family:
'Open Sans', Arial, sans-serif; font-size:16px;color:#3b3b3b;font-weight: bold;">**ERROR LIST**</td>
</tr>
<!--end title-->
<tr>
<td height="10"></td>
</tr>
<!--content-->
<tr align="center">
<td align="center" style="font-family: 'Open Sans', Arial, sans-serif; font-size:12px;color:#7f8c8d;line-height: 24px;">NoErrors</td>
</tr>
<!--end content-->
</table>
</td>
</tr>
<tr>
<td height="30"></td>
</tr>
</table>
Now the main question is: is it somehow possible to ONLY show the "Error list" table only IF there are any failed tests? If there are no failed tests it would be great for that table not to be shown at all.
Any kind of help would be greatly appreciated. Thanks!
$EmailBody= $EmailBody.Replace("PassedTests",$Passed)
$EmailBody= $EmailBody.Replace("FailedTests",$Failed)
$EmailBody= $EmailBody.Replace("SkippedTests",$Skipped)
$EmailBody= $EmailBody.Replace("ErrorList",$FailedTestsName)
$Emailattachment = "\TestResults.trx"
You are on the good path.
You just need to extend what you are doing.
Remove the thing that might or might not be in the email (The "errors list" section as it won't be there if there are no error)
Put the section your removed in its own variable
Add a placeholder in your main html template at the location where it is supposed to be (just like you do already so we can do a replace in the html template.
From there, the logic is :
If there are 0 errors, you replace the placeholder from the main template by an empty string (you don't want that placeholder to appear in the final email)
If there are 1 or more error, instead of replacing by your error list, you build a new variable that contain the section you want to append, then you replace its loop by the errors content and finally you replace the placeholder by that section (which contains the error loop)
That would look something like this.
$EmailBody = #'
</td>
</tr>
<!--end img-->
<tr>
<td height="15"></td>
</tr>
**ErrorsTable**
'#
$ErrorListBody = #'
<!--title-->
<tr align="center">
<td align="center" style="font-family:
'Open Sans', Arial, sans-serif; font-size:16px;color:#3b3b3b;font-weight: bold;">**ERROR LIST**</td>
</tr>
<!--end title-->
<tr>
<td height="10"></td>
</tr>
<!--content-->
<tr align="center">
<td align="center" style="font-family: 'Open Sans', Arial, sans-serif; font-size:12px;color:#7f8c8d;line-height: 24px;">NoErrors</td>
</tr>
<!--end content-->
</table>
</td>
</tr>
<tr>
<td height="30"></td>
</tr>
</table>
'#
if ($FailedTests.Count -gt 0) {
# inserting errors to the `$ErrorListBody` html segment
$ErrorsHtml = $ErrorListBody.Replace("ErrorList", $FailedTestsName)
# inserting the html segment into the main email
$EmailBody = $EmailBody.Replace("**ErrorsTable**", $ErrorsHtml)
} else {
# Removing the placeholder from the main template.
$EmailBody = $EmailBody.Replace("**ErrorsTable**", '')
}

Html email and fluid table with changing borders

I have some design requirements for an email template where I have two "challenges":
two columns need to flip to one column
some visible border lines need to be switched from vertical to horizontal
The following shows how it should look (2 columns on the left for desktop, 1 column on the right for mobile):
The whole email is based on responsive tables and the two-column part is implemented as follows right now:
<table cellpadding="5" cellspacing="0"
style="background-color:#F6F6F6; font-size: 14px; color:#58595b; width:100%; border-collapse:collapse;">
<tr><td align="center" valign="top" height="10" colspan=2 style="line-height: 10px; font-size: 10px;"> </td></tr>
<tr>
<td valign="top" style="border-right: 1.5px solid; border-color: #d0d0d0; padding-right:40px; text-align:right; width:42%; vertical-align:top;">
Start point
</td>
<td valign="top" style="padding-left:40px; vertical-align:top;">
<strong>Fri, January 12, 2023 12:00</strong>
<br />
Harbour, Seatown
</td>
</tr>
<tr><td align="center" valign="top" height="10" colspan=2 style="line-height: 10px; font-size: 10px;"> </td></tr>
<tr>
<td valign="top" style="border-right: 1.5px solid; border-color: #d0d0d0; padding-right:40px; text-align:right; width:42%; vertical-align:top;">
End point
</td>
<td valign="top" style="padding-left:40px; vertical-align:top;">
<strong>So, January 18, 2023 10:00</strong>
<br />
Central Station, Capital
</td>
</tr>
<tr><td align="center" valign="top" height="10" colspan=2 style="line-height: 10px; font-size: 10px;"> </td></tr>
</table>
I tried the approach with having a left and a right table (explained here) but the problem is that I do not use fixed widths.
How could I achieve the required design with a responsive mail template?
You will need to use the technique as outlined in the link, but if you want to use percentages instead of fixed widths, then use width="50%".
This is because the technique works on the basic fundamentals of HTML, that if a block doesn't fit in the space available, it will automatically shift underneath.
So to enable the stacking without a fixed pixel width, you will need to add a #media query to force the stacking (otherwise it would not stack).
e.g.
#media (max-width: 620px)
.table-left,.table-right {
width: 100% !important;
}
(The article you link to is a bit outdated: don't use [class=...], just write it out normally. Gmail may strip the entire <style> section if it doesn't like something in it, and this is one of those things it doesn't like.)
I prefer an override (max-width, and !important) because you want everything possible inline, and only to use embedded styles where strictly necessary.
But that's also why it's best to use a fixed pixel width, because some email clients do not respect your embedded styles (styles in the <head>). GANGA emails (one form of Gmail account) fall into this category. Those email clients would not stack even though they may need to, if you fully rely on the #media query for the stacking.
To override the border, put a style on the <td>, and reference it in the #media query, e.g.
#media (max-width: 620px)
.border {
border-right:none!important;
}
.border-top {
border-bottom:1.5px solid #d0d0d0 !important;
}
As one doesn't have the same border structure (they don't both need border-bottom), one of the <td>s will need a different class. Here, I'm expecting the first one, i.e. <td class="border border-top">.

Freemarker Loop to write tables

This is for email coding.
Seems simple in my head, but I have assigned a set of data to a freemarker variable
[#assign LOOP_TAB]${list.creative!'000000'}[/#assign]
Where list.creative contains either 1-5
I then want to write the correspsonding amount of simple HTML tables to my template
<!--Begin TEXT BOX-->
[#list 0..LOOP_TAB?length-1 as i]
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td align="left" valign="top" style="font-size: 14px; font-family: Arial, Helvetica, sans-serif; line-height: 20px; color: #000000;"><br>Loop Table Structure.<br><br></td>
</tr>
</tbody>
</table>[/#list]
Its sort of working, but im getting two tables by default, and never teh right amount of tables when i test on 2, or 4, or 1
Let me rename LOOP_TAB to numberOfTabs. So, if that's a number, and not a string, then:
[#list 1 ..< numberOfTabs!0 as _]
<table width="100%" border="0" cellspacing="0" cellpadding="0">
...
</table>
[/#list]
If numberOfTabs is a string, and you can't fix the data-model, then use (numberOfTabs?number)!0 instead of numberOfTabs!0.
Some further notes:
[#assign LOOP_TAB]${list.creative!'000000'}[/#assign] can be simply written as [#assign LOOP_TAB = list.creative!'000000']. But you don't need this at all, as you have seen.
?length gives the length of the strings in characters, so, it has returned the length of the string in LOOP_TABS.
from .. to gives an inclusive range, furthermore 0 .. -1 will give [0, -1], instead of the empty sequence that you wanted. Therefore you need from ..< to, which has exclusive end.
I used _ as loop variable only to signify that you don't actually read it anywhere. It's not special otherwise.

GWT - Flex Table Fixed Header Doesn't Match Data Columns

I'm using two flex tables. One for header and one for data.
The one for data is wrapped with a scroll panel.
The size of my columns is presented with percentage and this is where my problem begins:
I set the width of both tables to 100%.
The thing is that the scrollbar isn't always visible. It's visible only when required.
So when the scrollbar is shown - there's a gap between the width of the header and the width of the data area inside the scrollpanel. (since the scrollbar itself has width of 16px)
This way, the titles of the columns, doesn't match precisely the data columns.
Any suggestions?
Thanks in advance!
Based on your comment from my other answer you are left with having to code. I have solved this sort of problem in the past by using a shim column. I wouldn't call it elegant but it did the trick. Basically, you have an extra column in your header at the end that acts as a shim for the scrollbar. When the scrollbar is being displayed then the shim column is displayed with the exact width of the scrollbar. When there is no scrollbar you hide the shim.
Setup your layout with the additional column. Style it however you want. I usually make it so it blends in with the adjoining column so the user doesn't see a little square when it is being displayed.
Add all your data rows to the content table as you normally would. Make sure the content table and all its tr/td are added to the DOM.
Once the data is added then test whether the scrollbar is visible. You can do this by checking if the scroll height is greater then the offset height.
ScrollPanel scrollPanel;
Element scrollElem = scrollPanel.getElement();
if (scrollElem.getScrollHeight() > scrollElem.getOffsetHeight()) {
// scrollbar is visible
}
If the scrollbar is displayed then show your shim column, otherwise hide it.
if (scrollElem.getScrollHeight() > scrollElem.getOffsetHeight()) {
// scrollbar is visible - show shim column
shimColumnTD.getStyle().setDisplay(Display.BLOCK);
}
else {
// scrollbar not visible - hide shim column
shimColumnTD.getStyle().setDisplay(Display.NONE);
}
Determine the width of the shim column so that it matches the width of the scrollbar. If you go look inside the below method you can see how it does this.
// calculate the width of the scrollbar for the given browser
int shimWidth = AbstractNativeScrollbar.getNativeScrollbarWidth();
Obviously, this is just all pseudo but it should lead you in the right direction. Good luck...
There are a lot of possible things you can do to keep columns in sync, but most of them requires active layout and/or preview resize events.
I guess that, for your use case, is much simpler and (performance wise) far faster to either:
shrink both tables a bit, to always accomodate the space for the scrollbar (or even remove the scrollbars at all, keeping the scrolling behavior functionality). Both solutions are generally achieved by using a pair of nested div, with the second one wider enough to hide/accomodate the scrollbar;
wrap your second table into a panel that does not shrink the content when it overflows. In GWT you can do that natively using a CustomScrollPanel (instead a ScrollPanel). Just pay attention that is a RequiresResize panel that needs either an interrupted chain of ProvidesResize containers, or an explict size.
Side note: If you ever need to calculate the size of the native scrollbars in a cross browser solution, just use AbstractNativeScrollbar.getNativeScrollbarHeight() (and/or the width one).
A common trick for this sort of thing that avoids complex code and layout is to simply fix the widths of all your columns except the last one. The last column will auto adjust and you won't have to worry about the scrollbar at all.
Here is a jsfiddle sample along with some sample html/css to show you what I mean. The caveat is that all of the columns have to have width (they cannot be percentages) except the last one.
jsfiddle example
CSS:
.container {
width: 500px;
border: 1px solid red;
}
.content-wrapper {
overflow: auto;
height: 75px;
}
table {
width: 100%;
border-collapse: collapse;
}
col {
width: 100px;
}
col:last-child {
width: auto;
}
.container td {
border: 1px solid green;
}
HTML:
<div class="container">
<div class="header-wrapper">
<table class="header">
<colgroup>
<col/>
<col/>
<col/>
<col/>
<col/>
</colgroup>
<tr>
<td>Column A</td>
<td>Column B</td>
<td>Column C</td>
<td>Column D</td>
<td>Column E</td>
</tr>
</table>
</div>
<div class="content-wrapper">
<table class="content">
<colgroup>
<col/>
<col/>
<col/>
<col/>
<col/>
</colgroup>
<tr>
<td>Row 1/A</td>
<td>Row 1/B</td>
<td>Row 1/C</td>
<td>Row 1/D</td>
<td>Row 1/E</td>
</tr>
<tr>
<td>Row 2/A</td>
<td>Row 2/B</td>
<td>Row 2/C</td>
<td>Row 2/D</td>
<td>Row 2/E</td>
</tr>
<tr>
<td>Row 3/A</td>
<td>Row 3/B</td>
<td>Row 3/C</td>
<td>Row 3/D</td>
<td>Row 3/E</td>
</tr>
<tr>
<td>Row 4/A</td>
<td>Row 4/B</td>
<td>Row 4/C</td>
<td>Row 4/D</td>
<td>Row 4/E</td>
</tr>
<tr>
<td>Row 5/A</td>
<td>Row 5/B</td>
<td>Row 5/C</td>
<td>Row 5/D</td>
<td>Row 5/E</td>
</tr>
</table>
</div
</div>

Issue with image in table using GMail online client

I am creating an email template to use in Pardot. I have coded the email up. It works fine in OSX Mail, Outlook 07 +, Opera Mail, however GMail is being a real pain. It is adding some weird height or something to the tr or td in my table.
Any suggestions?
<table border="0" cellpadding="0" cellspacing="0" width="228">
<tbody>
<tr valign="bottom">
<td valign="bottom"><span pardot-region=""><img src="widget_top.jpg" alt="Placeholder"></span></td>
</tr>
<tr bgcolor="#ffd13f">
<td style="padding: 10px;">
<h2><span pardot-region="">Subheading span across one or two lines for best practice:</span></h2>
<span pardot-region=""><p><b>Date:</b> Thursday 29 November</p>
<p><b>Time:</b> 1.30pm (GMT)</p>
<p><b>Where:</b> Register online ></p>
<p><b>Topic:</b> Dynamic performance management</p>
<p><b>Presenters:</b> Octavius Black, CEO and Sebastian Bailey, President</p></span>
</td>
</tr>
<tr valign="top">
<td valign="top"><span pardot-region=""><img src="widget_bottom.jpg" alt="Placeholder"></span></td>
</tr>
</tbody>
</table>
(this table is inside a set of tested tables).
Screen shot can be found here: http://i45.tinypic.com/15wzda9.png
Cheers :)
On the images you have to put (inline)
style="display:block;"
:)
display:block; is definitely needed. You probably should zero out everything in all img tags, and set width and heights also.
<img style="margin: 0; border: 0; padding: 0; display: block;" src="" width="600" height="150"
alt="">
Also, you don't need the spans inside the table cells. If you want to keep them, make sure they have margin and padding zero'd out there too.