7 Replies
Matthew Bibby

Thanks for sharing that Michael.

The downside of that workbook is that it's a printable HTML page, rather than a PDF. While many users can Save to PDF, it isn't an option for all.

Lately, I've been using PDFmake to generate PDF's. Here's some sample code from a recent project.

Assuming that you are publishing to an LMS and want to include the users name in the PDF, add the below JS to the slide where the PDF is generated (and set it to run when the timeline starts):

function findLMSAPI(win) {
if (win.hasOwnProperty("GetStudentID")) return win;
else if (win.parent == win) return null;
else return findLMSAPI(win.parent);
}
var lmsAPI = findLMSAPI(this);
var name = lmsAPI.GetStudentName();
var nameArray = name.split(',');
var firstName = nameArray[1];
var lastName = nameArray[0];
var fullName = firstName + ' ' + lastName;
var player = GetPlayer();
player.SetVar("printUserName",fullName);

You'll need a text variable in SL called printUserName to store the users name.

The below code assumes that you have eight text fields that you want to include in the PDF. These use the Storyline variables Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8

Then, drop this code into your project where you want to generate the PDF, e.g. when people hit a 'download PDF' button:

document.getElementById("download").addEventListener("click", pdf);
function pdf() {

//Get date
var d = new Date();
var date = d.getDate();
var month = d.getMonth() + 1;
var year = d.getFullYear();
var fullDate = date + '/' + month + '/' + year;

//Get variables from SL, this PDF expects the following text variables exist in SL: Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 printUserName
var player = opener?opener.GetPlayer():{} ;
var a01 = player.GetVar('Q1');
var a02 = player.GetVar('Q2');
var a03 = player.GetVar('Q3');
var a04 = player.GetVar('Q4');
var a05 = player.GetVar('Q5');
var a06 = player.GetVar('Q6');
var a07 = player.GetVar('Q7');
var a08 = player.GetVar('Q8');
var fullName = player.GetVar('printUserName');

//Check for empty vars, populates with "No responses provided." if variable is empty.
if (a01 === '') {
a01 = 'No response provided.';
}
if (a02 === '') {
a02 = 'No response provided.';
}
if (a03 === '') {
a03 = 'No response provided.';
}
if (a04 === '') {
a04 = 'No response provided.';
}
if (a05 === '') {
a05 = 'No response provided.';
}
if (a06 === '') {
a06 = 'No response provided.';
}
if (a07 === '') {
a07 = 'No response provided.';
}
if (a08 === '') {
a08 = 'No response provided.';
}

//Prepare PDF
var dd = {
footer: {
text: 'Prepared on ' + fullDate + ' for' + fullName + '.',
style: 'footer'
},
content: [{
text: 'Heading text goes here',
style: 'header'
},
{
text: fullName + "'s Responses",
style: 'subheader'
},
{
text: '\n\nStatic text goes here\n\n',
style: 'question'
},
a01 + '\n\n',
{
text: 'Static text\n\n',
style: 'question'
},
a02 + '\n\n',
{
text: 'Static text\n\n',
style: 'question'
},
a03 + '\n\n',
{
text: 'Static text\n\n',
style: 'question'
},
a04 + '\n\n',
{
text: 'Static text\n\n',
style: 'question'
},
a05 + '\n\n',
{
text: 'Static text\n\n',
style: 'question'
},
a06 + '\n\n',
{
text: 'Static text\n\n',
style: 'question'
},
a07 + '\n\n',
{
text: 'Static text\n\n',
style: 'question'
},
a08 + '\n\n',
],

//Style PDF
styles: {
header: {
fontSize: 16,
bold: true,
alignment: 'center'
},
subheader: {
bold: true,
alignment: 'center',
italics: true,
fontsize: 16
},
question: {
italics: true
},
footer: {
fontSize: 8,
italics: true,
alignment: 'center'
}
}
};

// Download PDF
pdfMake.createPdf(dd).download("File Name.pdf");
}

Then, after publishing, you'll need to add the following to the index_lms_flash.html, indes_lms_html5.html, story_html5.html and story_flash.html files. In theory, just the index files should suffice, but when troubleshooting I found that if they weren't also in the story files, IE would choke.

<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.38/pdfmake.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.38/vfs_fonts.js"></script>

Once all this is done, a PDF will be downloaded when triggered by the module.

It is possible to open or print the PDF rather download it in the background, but browser support varies.

And don't bother trying to get it working in IE9. Let's just say that's two days of frustration I'll never get back!! If you need an option for IE9, let me know, as you'll want to use the workbook method Michael linked above and move the download PDF option to inside the workbook and only show it to those using a modern browser. That way people using IE9 can print the workbook and others can choose to download the PDF. 

Hope that helps.

Thanks,
Matt

Lia Lee

Hi Matt, 

I have tried this tutorial and the original print to html tutorial and I can't figure out why my variables are not passing (or maybe they aren't storing). I have added the files to linters and combed the code side-by-side without any troubleshooting luck or obvious issues.

Only one DOM error on clientside in my code files: Uncaught DOMException: Blocked a frame with origin "null" from accessing a cross-origin frame.
at file:/process.js:4:32

Line 4 referenced:  var player = opener?opener.top.GetPlayer():{} ;

I then took your "pretty" story file and published with my code files and your example story file doesn't pass the variables when launching print.html. Next, I took your code files and published my story file and had the same result: now my story file doesn't pass variables even using your code. I tried using a newer version of Jquery, and ensured that the story file was updated to 360 format.

Would you have insight into a troubleshooting detail I may have overlooked?

Lia Lee