Idea: Page to Print, Page to PDF, Page to Email, Page to Content actions

I’m sure there are bigger issues the Skuid team is tackling, but I’ll continue to post my “practical wish list”: It would be neat if there was an action that would convert a Skuid page to PDF/HTML and allow it to be presented for printing, uploaded into content like the Skuid upload component does, or sent through email. Then you could build custom email templates right in Skuid that leverage Skuid models, UI fields, etc… If you build email templates in Salesforce, I can’t easily get… Say a table of my top 5 opportunities that all begin with the letter j and have addresses in Alaska with summary totals of vaious fields displayed in decorative boxes at the top of the template and headers and footers that match my theme. If I could build email/PDF templates in Skuid as regular pages, I could rule the world (I may be exaggerating)

Yes.  Often discussed.  But every time our devs point out a big bundle of complexity that would have to be resolved.  Definitely on our roadmap, definitely not in the immedate future. 

As I have said before, it is a lot easier to have the ideas than to build them. I’ll keep having ideas. You guys do the hard part! :wink:

We’ve been able to achieve this using DocRaptor
http://docraptor.com/

Awesome! I’ll give it a look. Thanks Mansour

We are taking a look at Doc Raptor thanks to this thread.  Can anyone tell me the basics on how to do it via Skuid?

Hi Folks,

The solution Mansour is referring to goes a little something like this:

  1. Sign up for Docraptor and get your API Key

  2. Wrap what you’re interested in turning a PDF using the ‘Wrapper’ component and give it a unique id.

  3. Add a custom Inline Javascript snippet that we’ll attach to a button (or some other trigger for that matter)

``

var params = arguments[0], $ = skuid.$;

var downloadPDF = function(url, data, method){
  //url and data options required
  if( url && data ){
    $('
' + '').appendTo('body'); //credentials $('form#dr\_submission').append(''); $('form#dr\_submission textarea[name=user\_credentials]').val(data.user\_credentials);
//doc values  
for(var key in data.doc) {  
  $('form#dr\_submission').append('<textarea name="doc['+key+']"></textarea>');  
  $('form#dr\_submission textarea[name="doc['+key+']"]').val(data.doc[key]);  
}  

//submit the form  
if(confirm("Submit Form")) {$('form#dr\_submission').submit().remove(); }  

};
};

// setup the string represeting the html we want to submit
var content = $(‘#pdf-export’).html();

var data = {
doc: {
test: true,
document_type: ‘pdf’,
name: ‘test.pdf’,
document_content: content,
strict: ‘none’
},
user_credentials: “”
};

// this drops a form on the page and submits, which will result in a download dialog popping up
downloadPDF(“https://docraptor.com/docs”;, data);

4) Run Multiple actions on button click, and trigger the snippet

  1. Preview the page, click your new button and you should be prompted to download the pdf.

It will likely take a few tries to get the page looking the way you’d like, so keep at it. If the styles aren’t showing up, it means that Docraptor can’t access the .css and you’ll have to inject the stylesheet directly into the ‘content’ variable you send over. Fortunately you can set ‘test: true,’ (See the bolded above) and not incur an costs while you tweak it.

Henry,
Thank you very much! Have it working.

FYI - I had to chnage the last line of code to:

downloadPDF("<a title="Link https//docraptorcom/docs" href="https://docraptor.com/docs%22" rel="nofollow" target="_blank">https://docraptor.com/docs"</a>, data);

That semicolon in there was throwing an error.

Question - had any success attaching the prodcued pdf back to a record in salesfroce (easily/automatically)?

Thank you,
Daniel

I was actually just able to get that working with Zapier a few days ago. Some issues arise with the asynchronous nature of the generation that has spotty results. I’m actually currently discussing a ticket with them.

One more question for the docraptor experts… How do I get local css on my page? I use a skuid custom theme, and I opened the static resource and see all the files in the zip. I opened the skuidtheme file and copied all the text into a new css resource on my document skuid page, and then applied the css to my wrapper that is the content for my document. It didn’t work. :frowning: Am I close, or what else can I do to “send css to docraptor?”

Hi Chandra,

You can inject the css from a different location with an ‘Inline’ Javascript snippet like this:

(function(skuid){ var $ = skuid.$; $(document.body).one('pageload',function(){ //Change the static resource to the org's static resource location TODO: Dynamically set this $.when($.get("/resource/###############/<THEME_NAME>/skuidtheme.css")) .done(function(response) { // Create style tag to inject var style = $('<style />'); style.append(response); //inject it into the page style.appendTo($('#pdf-export')); }); }); })(skuid);

Henry - this worked perfectly.  Thank so much!  Please tell me you are going to Dreamforce or something, and I will buy you a beer or 12.  

Last question (haha)… I have a record detail page and want my user to click the “print doc” button.  The document layout (in my pdf wrapper) is not the same as the detail page.  I don’t want the user to see the wrapper/pdf but if I hide it with conditional rendering, then the pdf ends up blank.  What do you do with your wrapper/pdf on your detail page so it loads on your page, but the users don’t see it?

Chandra if I find myself in San Fransisco for Dreamforce I’ll certainly take you up on the beer offering!

As for hiding your print button, you can either put the button outside of the wrapper of id ‘pdf-export’ or do the following.

  1. Create a UI only checkbox called ‘hideprintbutton’ or something like that.
  2. Put a render condition on the button on the ‘hideprintbutton’ being true.
  3. Then perform the following ‘multiple actions’ on the button click:

We currently perform the latter option and it works very nicely. Hope this does the trick for you too!

Worked again!!  :)))

New problem - page loading in the skuidtheme.css has caused this portion of the Theme to apply to my whole page, so that means my pages are missing the skuidicon.css portion of the Theme.  So no icons on my page.  :(

I moved this problem to a more detail new thread here:
http://community.skuid.com/skuid/topics/embed-css-into-wrapper-component-page?rfm=1&topic_submi…

#Mansourisagenius

so, yeah #Mansourisagenius. DocRaptor is pretty amazing too. I’ve been implementing this today, and their tech support said that the above snippet I was using was old, that they’ve got a JS library now, so it’s better to reference that.

So, step 1, create an external snippet with this url: http://docraptor.com/docraptor-1.0.0.js
(or download that and upload as a static resource)

step 2, create an new snippet, remove all the standard code skuid adds in, then use this:

function downloadPDF() { DocRaptor.createAndDownloadDoc("YOUR_API_KEY_HERE", { test: true, document_type: 'pdf', name: 'test.pdf', document_content: document.querySelector('#pdf-export').innerHTML, strict: 'none', javascript: 'true', prince_options: { // if you want relative links to work baseurl: 'YOUR_SALESFORCE_BASE_URL' } }); } downloadPDF();

Everything else about the inlineJS to append your them to the wrapper is key, as is naming your wrapper with a unique id “pdf-export”.

also, in the inlineJS to append the theme css, you can add extra styles. for example, I had trouble adding the docrapter-specific @page selector to my theme (that controls landscape vs. portrait, and other page sizes), so I added it directly in the inlineJS, as such:

 var style2 = $('<style> @page { size : US-Legal landscape } </style>');
                style2.appendTo($('#pdf-export'));

Great stuff!  We have several doc raptor docs incorporated into our skuid processes.  I did a new one this morning using the new DocRaptor library.  Worked great!

Thanks for the update on this!

You’re welcome Chandra! Thank YOU for all the formatting tips you shared. Any chance you could share the apex code you used to grab the document that DocRaptor created and attach it back to a record in Salesforce? Did you have to run the async call to DocRaptor and get the callback_url?

ok, here we go. First, the apex class which is generic and will attach to any record id that you pass it. So we use this class for lots of objects.
/*—=============================================================================
— Program Name : AFLattachAsPDF

— Program Description : This APEX class attaches pdf documents from given url
— to the record specified.

— Date Written : 25-Jun-2016
—=============================================================================*/
global class AFLattachAsPDF{
webservice static void attachAsPDF(string downloadURL, ID theId, string theName){
Http h = new Http();
HttpRequest req = new HttpRequest();
string theURL = downloadURL;
req.setEndpoint(theURL);
req.setMethod(‘GET’);
//another example would be ‘image/jpeg’
req.setHeader(‘Content-Type’, ‘application/pdf’);
req.setCompressed(true);
req.setTimeout(60000);
HttpResponse res = null;
res = h.send(req);
//next three lines for dealing with error situations
//string responseValue = ‘’;
//responseValue = res.getBody();
//system.debug('Response Body for File: ’ + responseValue);
blob thePDF = res.getBodyAsBlob();

    Attachment attachment = new Attachment();
    attachment.Body = thePDF;
    attachment.Name = theName + '.pdf';
    attachment.ContentType = 'application/pdf';
    attachment.ParentId = theId;
  insert attachment;

}
}

Then, the Skuid snippet that runs. It has the DocRaptor call, brings in our special custom Skuid theme that we use just for documents, polls docraptor checking for completion of the pdf, creates a document name and passes all the info to the apex class (the url exposed by DocRaptor, the Id to attach the pdf to and the document name you want.)

This example is from our Quote page where the user clicks a button which calls the document skuid page in a pop up window, and this snippet runs on page load. Once the document is done, the window closes and poof the pdf is attached to the quote.

var params = arguments[0],
$ = skuid.$;

var quoteModel = skuid.model.getModel(‘quote’);
var quoteRow = quoteModel.getFirstRow();
var quoteNum = quoteModel.getFieldValue(quoteRow,‘Name’);
var quoteRev = quoteModel.getFieldValue(quoteRow, ‘Quote_Revision__c’);
var docName = quoteNum + ‘R’ + quoteRev;
var docURL;

// pull in the Skuid theme to apply to the page
$.get(“/resource/yourthemepath/yourthemename/skuidtheme.css”,function(response){
// Create style tag to inject
var style = $(‘’);
style.append(response);
// apply a custom border to a dynamically created table
style.append(‘table, th, td {border: 1px solid black;border-collapse: collapse;padding: 1px;text-align: left;}thead {background-color: #000000;color: #FFFFFF;}’);

//inject it into the page
style.appendTo($(‘#pdf-export’));

function checkDocumentStatus(id){
$(‘.status span’).html(‘Polling…’);
$.ajax({
type: ‘GET’,
url: ‘https://docraptor.com/status/’+id,
dataType: ‘JSON’,
beforeSend: function(req) {
req.setRequestHeader(‘Authorization’, ‘Basic ’ + btoa(‘YOUR ACCESS CODE’));
},
success: function(data){
if(data.status == ‘queued’ || data.status == “working”){
// wait 1 second, check again
setTimeout(checkDocumentStatus, 1000, id);
}else if(data.status == ‘completed’){
$(’.status span’).html(‘Completed’);
$(‘.url span’).html(data.download_url);
docURL = data.download_url;
try{
var attName = quoteModel.getFieldValue(quoteRow, ‘Name’) + ‘R’ + quoteModel.getFieldValue(quoteRow, ‘Quote_Revision__c’);
var result = sforce.apex.execute(‘AFLattachAsPDF’, ‘attachAsPDF’, {downloadURL: docURL, theId: quoteModel.getFieldValue(quoteRow, ‘Id’), theName: attName});
skuid.model.updateData(
[quoteModel]
,function(){

quoteModel.save();
});

window.close();

}catch(e){
alert(e);
}
//window.prompt(‘Download URL’, data.download_url);
}else{
$(‘.status span’).html(data.status);
}
}
});
}


function makeDocument(content){
$(‘.status span’).html(‘Requested’);

content = content || ‘’;

$.ajax({
type: ‘POST’,
url: ‘https://docraptor.com/docs’,
data: JSON.stringify({
‘type’: ‘pdf’,
‘document_content’: content,
‘name’: docName,
//‘test’: true,
‘async’: true,
//‘pipeline’: 6,
‘prince_options’: {
‘media’: ‘print’,
‘owner_password’: quoteNum,
‘disallow_modify’: true,
‘encrypt’: true,
‘key_bits’: ‘128’
}
}),
contentType: ‘application/json’,
dataType: ‘json’,
beforeSend: function(req) {
req.setRequestHeader(‘Authorization’, ‘Basic ’ + btoa(‘YOUR ACCESS CODE’));
},
// upon success of the ajax request
success: function(data){
$(’.status span’).html(‘request made’);
checkDocumentStatus(data.status_id);
}
});
}


//----------------------------------------------------------------------------------------------------

// setup the string represeting the html we want to submit
var content = $(‘#pdf-export’).html();

makeDocument(content);

});