Flexbox Usage Partially(?) Works In iTextPDF - itext7

I am using ITextPDF to create a report. And since the report is going to be a very complex one, I want to use an HTML template which I am creating to create the pdf. But when it comes to flex-box, it only partially works.
What I mean with partially is, when I use below code;
private string HTML = $#"
<!DOCTYPE html>
<html lang=""tr"">
<head>
<meta charset = ""UTF-8"">
<meta http-equiv=""X-UA-Compatible"" content=""IE=edge"">
<meta name = ""viewport"" content=""width=device-width, initial-scale=1.0"">
<title>Print</title>
<link rel=""stylesheet"" href=""https://cdn.jsdelivr.net/npm/bootstrap#4.6.0/dist/css/bootstrap.min.css"">
</head>
<body>
<div class=""d-flex align-items-center justify-content-center bg-primary"">
<div>abcçde</div>
<div>ABCÇDEF</div>
</div>
</body>
</html>
";
public void GeneratePDF()
{
using(var memoryStream = new MemoryStream())
{
using (var pdfWriter = new PdfWriter(Guid.NewGuid().ToString()+".pdf"))
{
pdfWriter.SetCloseStream(false);
HtmlConverter.ConvertToPdf(this.HTML, pdfWriter);
var pdfStream = pdfWriter.GetOutputStream();
pdfStream.Position = 0;
pdfStream.CopyTo(memoryStream);
var result = memoryStream.ToArray();
pdfStream.Dispose();
}
}
}
The justify-content-center works on-point as can be seen below;
But when I change it to justify-content-between it doesn't work;
I also tried to give each div float values, without adding bootstrap.min.css and it doesn't work that way either.
Why would it work with justify-content-center and not justify-content-between?

As mentioned in one of the question's comments, as for now iText provides only initial flex support. Specifying justify-content-between class actualy means setting justify-content:space-between, and thie value is not supported: you could see it from the log message which is thrown while processing such an html:
com.itextpdf.html2pdf.css.apply.util.FlexApplierUtil WARN Flex related property justify-content: space-between is not supported yet.
As a workaround, one indeed could use floats. For example, divs of the following html are processed as expected:
<!DOCTYPE html>
<html lang="tr">
<body>
<div>
<div style="float: left;">abcçde</div>
<div style="float: right">ABCÇDEF</div>
</div>
</body>
</html>

Also flex-direction:column doesn't work

Related

Custom Web Component image not showing

I have been working through a yt tutorial on Web Components by Brad Traversy, a great teacher with great content, as I'm sure many of you already know :)
I've gotten up to the 17 minute mark, though the problem I'm having is that the images are not displaying as they are in the tutorial...
They are being added to the document flow... I can tell this because the layout re-adjusts to accommodate the space for an image... it's just that the image is not displayed...
Just for comparison, I added a image of a similar nature directly in the html and it works fine.
Anyway, here is my code...
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web Components Example</title>
<style>
h3 {
color: purple;
}
</style>
</head>
<body>
<h3>Hello World... where's the images?!?!?</h3>
<!-- <user-card name="you oddo" avatar="https://randomuser.me/api/portraits/men/1.jpg"></user-card> -->
<user-card name="huik popp" avatar="38.jpg"></user-card>
<user-card name="som otha"></user-card>
<img src="95.jpg">
<style>h3 {color: green}</style>
<script src="userCard.js"></script>
</body>
</html>
and the Javascript...
UserCard.js:
const template = document.createElement('template');
template.innerHTML = `
<style>
h3 {
color: coral;
}
</style>
<div class="user-card">
<img />
<div>
<h3></h3>
</div>
</div>
`;
class UserCard extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open'});
this.shadowRoot.appendChild(template.content.cloneNode(true));
this.shadowRoot.querySelector('h3').innerText = this.getAttribute('name');
this.shadowRoot.querySelector('img').innerText = this.getAttribute('avatar');
}
}
window.customElements.define('user-card', UserCard);
I'd appreciate any help with this very much. I've been enjoying following along with this tutorial so far and well, would like to keep up with how things look in the video.
Many thanks.
I'm answering my question here...
In userCard.js, I have:
this.shadowRoot.querySelector('img').innerText = this.getAttribute('avatar');
It should be:
this.shadowRoot.querySelector('img').src = this.getAttribute('avatar');
Tell Brad he can shorten the code to:
class UserCard extends HTMLElement {
constructor() {
super()
.attachShadow({ mode: 'open'})
.innerHTML = `
<style>
h3 {
color: coral;
}
</style>
<div class="user-card">
<img />
<div>
<h3></h3>
</div>
</div>
`;
...
}
);

Thymeleaf switch statement including every case

I'm working on my first Spring MVC project and I got stuck at a problem. I have 3 types of users in my application: admin, employee and customer. Depending on the type of user, I would like to have a specific type of menu for each of them. I tried using a switch statement in my thymeleaf template but every case gets included in the output and I don't understand why.
This is the code for my method in the controller:
#RequestMapping(value = "list/{roleId}", method = RequestMethod.GET)
public String listFood(Model model, #PathVariable int roleId){
model.addAttribute("title", "Available Foods");
model.addAttribute("roleId", roleId);
model.addAttribute("foods", foodDao.findAll());
return "food/list";
}
And this is the code from the Thymeleaf template (each fragment will be included in the resulting page):
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org/">
<head th:replace="fragments :: head"></head>
<body class="container">
<h1 th:text="${title}">Food</h1>
<div th:switch="${roleId}">
<p th:case="0"><nav th:replace="admin-fragments :: navigation"></nav></p>
<p th:case="1"><nav th:replace="employee-fragments :: navigation"></nav></p>
<p th:case="2"><nav th:replace="customer-fragments :: navigation"></nav></p>
</div>
</body>
</html>
However, if I change the template to the following one then only the correct case will be included in the resulting page.
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org/">
<head th:replace="fragments :: head"></head>
<body class="container">
<h1 th:text="${title}">Food</h1>
<div th:switch="${roleId}">
<p th:case="0">User is an administrator</p>
<p th:case="1">User is an employee</p>
<p th:case="2">User is a customer</p>
</div>
</body>
</html>
Why isn't the switch from the first template behaving like the one in the second template? What should I change in the first template to be able to have a personalised menu for each type of user? Thank you!

Converting HTML with ordered list and div with itextpdf

I tried to convert a HTML page with ordered list and some div tags with itextpdf, but it does not seem to work. I created the following simple ordered list structure in HTML to demonstrate the problem:
<!DOCTYPE html>
<html>
<head>
<title>Insert title here</title>
</head>
<body>
<!-- <div> -->
<ol>
<li>A
<ol>
<li>AA</li>
<li>AB</li>
<li>AC
<ul>
<li>ACA</li>
<li>ACB</li>
</ul>
</li>
<li>AD
<ul>
<li>ADA</li>
<li>ADB</li>
</ul>
</li>
</ol>
</li>
</ol>
<!-- </div> -->
</body>
</html>
It works fine so far, and I get the correct, well formatted PDF. When, however, I remove the comment around the div tag, it does not work any more. I get all element of the ordered list in a single line, in the result PDF file like this:
A AAABAC ACAACBAD ADAADB
My method for the conversion looks like this:
private void convertHtmlToPdf(String htmlFilePath, String generatedPdfFilePath) throws IOException, FileNotFoundException, DocumentException {
String fileContent = FileUtils.readFileToString(new File(htmlFilePath));
OutputStream file = new FileOutputStream(new File(generatedPdfFilePath));
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, file);
document.open();
InputStream is = new ByteArrayInputStream(fileContent.getBytes());
XMLWorkerHelper.getInstance().parseXHtml(writer, document, is);
document.close();
file.close();
}
So it is the simplest conversion code. I don't use any CSS, or insert any pictures. In my real code however, I do need to use CSS for the conversion, and the formatting is defined via div elements. So I can not simple remove all the div-s to get the conversion working.
Is it a bug, in itextpdf, or I miss something? Has anybody any idea for a workaround, to deal with this problem?
I am using the actually latest (5.5.6) version of itextpdf.
<!DOCTYPE html>
<html>
<head>
<title>Insert title here</title>
</head>
<body>
<div>
<ol>
<li>A
<ol>
<li>AA</li>
<li>AB</li>
<li>AC
<ul>
<li>ACA</li>
<li>ACB</li>
</ul>
</li>
<li>AD
<ul>
<li>ADA</li>
<li>ADB</li>
</ul>
</li>
</ol>
</li>
</ol>
</div>
</body>
</html>
this code should be work try it

ASP.NET mvc 3 razor : Html Helper Extension Method - executed but dosen't print html

Hi I have problem with my html helper extension method in razor view engine. I want to render SideMenu if I have any nodes to print:
<!DOCTYPE html>
<html>
<head>
<title>#ViewBag.Title</title>
<link href="#Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
</head>
#using MyNamespace.Helpers
<body>
<div id = "page" style = "width: 90%; margin: 0 auto" class="pageSection">
<div id="logo" class="pageSection">aaaa</div>
<div id = "LeftMenuContainer">
#{ if (ViewBag.Menu.LeftMenu.Count > 0)
{
Html.RenderSideMenu((ICollection<MyNamespace.MenuNode>)(ViewBag.Menu.LeftMenu));
}
}
</div>
<div id="content" class="pageSection">#RenderBody()</div>
<div id="footer" class="pageSection"></div>
</div>
</body>
</html>
and here's my method:
public static MvcHtmlString RenderSideMenu(this HtmlHelper helper, ICollection<MenuNode> nodes)
{
string result = "<h3>Menu</h3>";
result += "<ul class=\"SideMenu\">";
foreach (var node in nodes)
result += MenuRenderEngine.RenderNode(node);
result += "</ul>";
return MvcHtmlString.Create(result);
}
The problem is that method is executed and returns well prepared string but doesn't print it in view so I'm confused what did I wrong?
Use # if you want to output the result on the page:
<div id = "LeftMenuContainer">
#if (ViewBag.Menu.LeftMenu.Count > 0)
{
#Html.RenderSideMenu((ICollection<MyNamespace.MenuNode>)(ViewBag.Menu.LeftMenu));
}
</div>
Also, as a side note, don't use ViewBag, use view models instead.

Add / Remove Elements Dynamically

Now i done the ADD /Remove Elements
How to add/remove elements dynamically, pease find the image attachment, which shows the better understand,
category which populate records from database category table, and when user select the particular category than sub category will populate from datbase sub category table,
am looking one jquery or some open which do this same work,
refer some good plugins,
How to add the element when i click the ADD Elment, please chekc my code below
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Untitled Document</title>
<script type="text/javascript" src="jquery-1.3.2.min.js"></script>
<script type="text/javascript" >
$(document).ready(function(){
var hdn_add_element_cnt = $("#hdn_add_element_cnt").val();
hdn_add_element_cnt = parseInt(hdn_add_element_cnt);
var app_str = "<div id=element_"+hdn_add_element_cnt+">New Element "+hdn_add_element_cnt+" Delete</div>";
$('#element_area').append(app_str);
$("#add_element").click(function(){
var hdn_add_element_cnt = $("#hdn_add_element_cnt").val();
hdn_add_element_cnt = parseInt(hdn_add_element_cnt);
hdn_add_element_cnt = hdn_add_element_cnt+1;
var app_str = "<div id=element_"+hdn_add_element_cnt+">New Element "+hdn_add_element_cnt+" Delete</div>";
$('#element_area').fadeIn(10000).append(app_str);
//Increment Elemenet ID Count +1
document.getElementById("hdn_add_element_cnt").value = hdn_add_element_cnt;
})
})
function delete_element(element_id_no){
var get_element_hidden_cnt = $("#hdn_add_element_cnt").val();
$("#element_"+element_id_no).fadeOut(100).remove();
}
</script>
</head>
<body>
<div style="width:500px; height:200px; background-color:#FF0000;">
<div id="add_element" style="width:400px; height:75px;">
ADD Element
</div>
<div id="element_area">
</div>
</div>
<input type="hidden" id="hdn_add_element_cnt" value="1" />
</body>
</html>
jQuery doesn't need plugins to do this. Standard functions work well:
.append() adds elements, so to add a <div> to the <body>, just do this:
$('body').append('<div id="foobar">This is my text</div>');
.remove() similarly removes elements, so to remove that <div> that you added, just do this:
$('#foobar').remove();
.html() and .text() can be used to set the contents of an element. .text() is usually for setting the displayed text, and .html() is for adding content elements:
$('#foobar').text('Hello');
$('#foobar').html('<h1 class="foo">Hello</h1>');
Your question is really vague, so I'm not sure what else to say.

Resources