Create PDF in Struts from data on screen - struts

I am able to create a simple pdf using iText api inside a struts action class.
The data that should be passed into the pdf is generated on screen based on user search parameters.
What I am wondering is how I can pass the data into the struts action so it can be displayed in the pdf?
Thanks in advance.

Similar question is already here. You just need to transfer everything that is on the page to struts action. I would do it like so:
JSP:
<div id="content">
wrap everything generated in here
</div>
<html:hidden styleId="hiddenHtml" name="hiddenHtml"/>
<html:submit onclick="setContentAsParam();">Export PDF</html:submit>
JS:
function setContentAsParam() {
document.getElementById('hiddenHtml').value = document.getElementById('content').innerHTML
}
This will set all the HTML to a action class property hiddenHtml. Get back if anything won't work, I wrote this out of my head without a test :)

Related

How to integer an oembed javascript tag inside a VueJs component?

I have an "embed" field used by my users for transform a simple link to a rich content link (link with image, title, description, etc.).
Example:
Note: I use this library to get all link information: oscarotero/Embed
As you can see, when you provide an url (a twitter tweet by example), the "code" parameter contain the HTML and script tags to include on my frontend:
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">I am so hopelessly in love with #ChucklefishLTD ‘s spooky logo pic.twitter.com/2KtjCNOOUl</p>— Tom Slayed 🔪😱 (#TomJamesSlade) October 12, 2020</blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
The problem is with VueJs and the script tag. When my ajax call is OK, I store all embed informations like that:
this.preview = response.embed
And inside my component, I display the html code with the "v-html" VueJs directive
<div v-if="preview['code']" v-html="preview['code']"></div>
The html is displayed :
The script tag is visible inside the code inspector :
But the script is not loaded :
I have the same problem with all oembed url who provide a javascript tag inside the response.
Note: If I try to load the script directly inside the component, VueJs return this error:
VueCompilerError: Tags with side effect ( and ) are ignored in client component templates
A solution on google is to use the "mounted" event, but it's not compatible with my context.
Because the script I have to load is received from an api and can be different each time depending of the link.
it's bit late but here is an option: The api gives you the possibility to not send the script tag, so you can include it on your own in the html before. Add to the url a omit_script=true and it's gone in the result.
Then you can insert the twitter block. Maybe you have to call twttr.widgets.load() to initialize the tweet.
Edit: Since you're using the plugin, this should be working
$embed = new Embed();
$result = $embed->get('https://www.instagram.com/p/B_C0wheCa4V/');
$result->setSettings([
'oembed:query_parameters' => ['omit_script' => true]
]);
$oembed = $info->getOEmbed();

jquery featherlight on dynamic content from DataTalbes

I am using jquery featherlight (https://github.com/noelboss/featherlight) after trying to get jquery lightbox (https://lokeshdhakar.com/projects/lightbox2/) to work. I am using DataTables to generate a list. One of the items in the table is a link to a php page that returns links. The problem is I am calling an external PHP page that generates a list of links. So my link code is like this:
<i class="fas fa-link fa-lg"></i>
The page "lenker.php" does a search and outputs html code. It looks fine in the chrome inspector. But the popup is empty. If I link to another page with the code hardcoded it shows fine. Why does it not show when it is generated on the fly? The html code looks just fine like this:
<div><a class="external" href="http://databank.artsdatabanken.no/FremmedArt2012/N63753" data-featherlight="ajax">fremmedartsvurdering 2012 for edelgran</a></div>
<div><a class="external" href="http://eol.org/pages/1033070" data-featherlight="ajax">edelgran hos Encyclopedia of Life</a></div>
<div><a class="external" href="http://linnaeus.nrm.se/flora/barr/pina/abies/abiealb.html" data-featherlight="ajax">edelgran i Virtuella floran, Sverige</a></div>
but the popup opens and then resizes to almost nothing since there is no content. Featherlight does not need any other initialization since it looks for data-featherlight="ajax".
Is the problem that datatable is dynamic content?
jQuery ajax expects one object so I solved this with enclosing my content in one DIV.

how to create a pdf editor for grails

In my Grails project I'm using the PDF plugin to generate PDFs from gsp page.
It works well, but I would like to add more functionalities to users, so I would like to allow user to edit the PDF basic template (defined in a gsp page), in particular I would like to allow the editing of the text inside the template and store it somewhere.
Anybody knows how could it be done?
If you only want to change the text, you could store the edited text in a database with the user id and loading it into the gsp page instead of the standard text.
If you also want to change the style of the page you could try to store the whole gsp page in the database and let the user editing it with an HTML Editor.
that's how i would start with, maybe someone has an better idea
The underlying components of the pdf plugin don't strictly require a .gsp file. It simply uses .gsps rendered as strings and feeds those into the flyingsaucer lib. So you could use a WYSIWYG type editor to allow users to create html snippets, save those strings somehow and then feed those though to the flyingsaucer libs yourself. just look into the included service methods of the plugin for an example. That might sound scary, but it really isn't very complicated.
You might want to wrap the user generated content with some of your own HTML markup for sanity and styling purposes of course, but the idea you are going for is entirely doable.
You could have a GSP that behaves of two different ways. First of all the GSP will be rendered in a Editable state. In this state the user could do some edits in some parts of the GSP. After that, the GSP will be rendered in a Preview state, where user could check the modifications that he has done in the previous step (nothing can be edited in this state). Finally, the GSP will be rendered as a PDF (using Grails Rendering Plugin).
Note that user will not edit the GSP itself. You need to allow him to edit through HTML elements as Text Areas, for instance. In this case we're using an WYSWYG editor. This editor allows the user to put text as Bold, Italic, etc.
Therefore, the most important step of this solution is to distinguish the two states in the same GSP. To do that you can use a boolean variable (called editing, for instance). This variable, if true, will render the GSP with the elements that will allow him to perform changes in the document. For other side, if the editing variable is false, the GSP will be rendered just with texts, not allowing any kind of editing.
The user could Check or Uncheck checkboxes (to show or hide some part of the document) and write or change texts in the Text Areas elements.
Below I'll show how this solution works.
GSP
The GSP is a template GSP and is called _quote.gsp
The piece of code below shows the use of the editing variable. Note that if editing = true, then a textarea is rendered and user can edit the text. There is a standard text that can be changed.
The post variable keeps what user has done after the editing phase. We use JQuery serialize to get all paramaters and pass it to a Grails Controller.
<p>
<g:if test="${editing}">
<pgs:textArea html="true" autosize="true" name="fraseInicial" rows="2" cols="80">
${post?.fraseInicial?post.fraseInicial:"Conforme sua solicitação, a empresa tem a satisfação de informar-lhe os métodos e preços."}
</pgs:textArea>
</g:if>
<g:else>
${post.fraseInicial}
</g:else>
</p>
pgs:textArea is a specific taglib of this system and is used to render a WYSWYG editor, you can replace it for a simple TextArea HTML element.
An example with checkbox:
<g:if test="${editing || post.temPrazoAnalise}">
<h1>
Teste teste
</h1>
<g:if test="${editing}"><g:checkBox name="temPrazoAnalise" value="${!post?true:post?.temPrazoAnalise == null?false:true}"/></g:if>
<g:if test="${editing || post.temPrazoAnalise}">
<p>Teste teste teste </p>
</g:if>
</g:if>
Controller
The previewQuote() is called from an AJAX call that serializes (via JQuery) all parameters of GSP.
The back() action allows the user to back to the editing state from the preview state. This is the reason why we set session["paramsReport"] = params inside previewQuote(). Doing this way it's possible to use session["paramsReport"] inside back() and restore the values changed by the user.
def editQuote() {
def quote = Quote.get(params.id)
render(template: "/quote/report/quote", model: [editing:true, quote:quote])
}
def previewQuote() {
Quote quote = Quote.get(params.id)
session["paramsReport"] = params
render(template: "/quote/report/quote", model: [quote:quote, post:params])
}
def back() {
def quote = Quote.get(params.id)
if (session["paramsReport"]) {
render(template: "/quote/report/quote", model: [editing:true, post:session["paramsReport"], quote:quote])
}
}
def generateQuote() {
Quote quote = Quote.get(params.id)
def f = new File(grailsApplication.mainContext.servletContext.getRealPath("/app/temp/${quote.code}.pdf"))
if (f.exists())
f.delete()
f.withOutputStream { os ->
pdfRenderingService.render([template: '/quote/report/quote', model: [quote:this, post:session["paramsReport"], pdf:true]], os)
}
}
This solution was developed by wanderson-santos (https://stackoverflow.com/users/128857/wanderson-santos) and me.
I hope you understand the overall idea of the solution. I understand that could be a bit complicated at a first view. Anyway, is a solution that allows flexibility for this kind of requirement (i.e. allow the user to customize a report before the PDF is generated).

MVC helper inside a template

I am trying to use a kendo MVC helper inside a template (remote template file loaded like: http://docs.kendoui.com/howto/load-templates-external-files#remote-templates. I have a controller that sends to the client the generated markup)
My template file is something like:
<script id="my-pager-template" type="text/x-kendo-template">
My pager
#(Html.Kendo().ListView<Business.Data.MyPage>()
.Name("myPagerListView")
.TagName("div")
.ClientTemplateId("my-pager-item-template")
.DataSource(dataSource => dataSource.Read(read =>
read.Action("GetMyPages","Page")
)
).ToClientTemplate())
</script>
<script id="my-pager-item-template" type="text/x-kendo-template" >
<div class="k-button" data-pager-item-pageid="${PageID}" data-pager-item-pagename="${Name}">
<span>${ButtonText}</span>
</div>
</script>
But the generated markup is giving me an Uncaught SyntaxError: Unexpected token < in my browser console (chrome).
The markup generated by the helper is like this:
<div id="myPagerListView"></div>
<script>
jQuery(function(){jQuery("\#myPagerListView").kendoListView({"dataSource":{"transport":{"prefix":"","read":{"url":"/Page/GetMyPages"}},"serverPaging":true,"serverSorting":true,"serverFiltering":true,"serverGrouping":true,"serverAggregates":true,"type":"aspnetmvc-ajax","filter":[],"schema":{"data":"Data","total":"Total","errors":"Errors","model":{"fields":{"PageID":{"type":"number"},"Name":{"type":"string"},"ButtonText":{"type":"string"}}}}},"template":kendo.template($('\#my-pager-item-template').html())});});
<\/script>
</script>
Can I use kendo helpers this way?
(In this post, it says that it can be used: Can I use Kendo MVC helpers inside templates?)
I got that message a lot of times, your code is fine, the problem comes retrieving the data, kendo deserialize what it recieves from read.Action("GetMyPages","Page"), you probably are retrieving an HTML page instead of a json, so it tries to serialize something like "<html ...." and here you got the error, just check the url on chrome to check if you recive an json
i mean check http://yourdomain.com/Pages/GetPages/ (or the routing according to your app), you probably get an HTML page
I had this exact issue also. I have come to realise (over the past 3 hours :( ) that this is because I was using ajax then the jquery html function to load the template file and that the error was happening with in jquery's function as it tried to parse than execute the template file which has been mangled for an unknown reason by kendo. (escaping that script tag and in my case inserting buttons in that space). Fortunatly when kendo Its self tries to use the template it does work.
To get around this problem I rendered the partial view directly on the page.
Hope this helps.

DHTML - Change text on page using input field

I need to create a code to change an example text to a user-defined value when the user types in an input field (Similar to the preview field when writing a question on Stack Overflow).
This needs to be achieved without the use of HTML5 or Flash as the users will be running IE8, not all will have Flash plug-ins installed.
As such I have started by looking at DHTML to achieve the desired effect. Currently I can change the example text when a user types in the input field but only to a pre-defined value ("Example" in the code below), how should I edit this code to display the user-defined value?
JS
function changetext(id)
{
id.innerHTML="Example";
}
HTML
<form>
Content:<input type="text" id="input" onkeyup="changetext(preview)" />
</form>
<p id="preview">No content found</p>
You need to have something like this in the function:
function changetext(id){
var info = document.getElementById('input').value();
id.innerHTML = info;
}
This js is not fully correct. I would highly recommend you start using a javascript library like jQuery. It makes this a menial task.
Edited:
jQuery will work in IE8 just fine. in jQuery you will not need to attach js to your input. The code would look like this.
$('#input').click(function(){
$('#preview).html(this.val());
});
It is a lot cleaner and doesnt have js in the html.