Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions doc/plugins/from_html.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!--
/**
* Copyright (c) 2014 Steven Spungin (TwelveTone LLC) steven@twelvetone.tv
*
* Licensed under the MIT License.
* http://opensource.org/licenses/mit-license
*/
-->

# from_html Plugin CSS Support
This document lists the CSS styles supported by the from_html jsPDF plugin.
Each style indicates restrictions and issues.
This file is intended for development purposes and may not be up to date.
Refer to the source code for the lastest developments.

# Implemented

* margin
* margin-top
* margin-right
* margin-left
* margin-bottom
* padding
* padding-top
* padding-right
* padding-left
* padding-bottom
* font-family
* font-style
* text-align
* font-size
* line-height
* display
* float
* clear
* page-break-before
> Only _always_ is implemented.

# Implemented But Not Merged
* color

# Not Implemented
* page-break-after
8 changes: 8 additions & 0 deletions jspdf.plugin.from_html.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@
css["padding-left"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-left")) || 0;
css["padding-right"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-right")) || 0;

css["page-break-before"] = computedCSSElement("page-break-before") || "auto";

//float and clearing of floats
css["float"] = FloatMap[computedCSSElement("cssFloat")] || "none";
css["clear"] = ClearMap[computedCSSElement("clear")] || "none";
Expand Down Expand Up @@ -838,6 +840,12 @@
paragraphspacing_after = ((blockstyle["margin-bottom"] || 0) + (blockstyle["padding-bottom"] || 0)) * fontToUnitRatio;
this.priorMarginBottom = blockstyle["margin-bottom"] || 0;

if (blockstyle['page-break-before'] === 'always'){
this.pdf.addPage();
this.y = 0;
paragraphspacing_before = ((blockstyle["margin-top"] || 0) + (blockstyle["padding-top"] || 0)) * fontToUnitRatio;
}

out = this.pdf.internal.write;
i = void 0;
l = void 0;
Expand Down
75 changes: 75 additions & 0 deletions test/test_from_html_css_page_breaks.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<!doctype html>
<!--
/**
* jsPDF Test HTML PlugIn
* Copyright (c) 2014 Steven Spungin (TwelveTone LLC) steven@twelvetone.tv
*
* Licensed under the MIT License.
* http://opensource.org/licenses/mit-license
*/
-->

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">

<title>Test HTML</title>

<!-- Required Files -->
<script type="text/javascript" src="../jspdf.js"></script>
<!-- Plugin Dependencies -->
<script type="text/javascript" src="../jspdf.plugin.standard_fonts_metrics.js"></script>
<script type="text/javascript" src="../jspdf.plugin.split_text_to_size.js"></script>
<script type="text/javascript" src="../jspdf.plugin.from_html.js"></script>
<!-- Plugin To Test -->
<script type="text/javascript" src="test_harness.js"></script>
<!-- Test Dependencies -->

<script>
pdf_test_harness.onload = function(harness) {
var pdf = new jsPDF('p', 'pt', 'letter');
var ta = document.getElementById('textarea');

pdf.fromHTML(ta.value, 0, 0);

ta.onkeyup = function(){
var pdf = new jsPDF('p', 'pt', 'letter');
pdf.fromHTML(ta.value, 0, 0);
harness.setPdf(pdf);
}

harness.header.style.left='300px';
harness.body.style.left='300px';

return pdf;
}


</script>

</head>

<body style='background-color: silver; margin: 0;'>
<textarea id='textarea' style='position:fixed;left:0;width:290px;height:100%'>

<html>
<head>
<style>
.break{
page-break-before:always;
}
body{
font-size:2em;
}
</style>
</head>
<body>
<div>page 1 <em>ok?</em></div>
<div class='break'>page 2</div>
<div class='break' style='margin-top:1in'>page 3</div>
</body>
</html>

</textarea>
</body>
</html>
147 changes: 147 additions & 0 deletions test/test_harness.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
onload = function() {

var harness = new pdf_test_harness();

var body = document.getElementsByTagName('body')[0];
body.style.display = 'flex';

var div = document.createElement('div');
div.setAttribute('style', 'position:fixed;height:20px;left:0;right:0;background:lightblue');
body.appendChild(div);
harness.header = div;

var div2 = document.createElement('div');
div2.setAttribute('style', 'position:fixed;display:flex;top:20px; bottom:0;left:0;right:0');
body.appendChild(div2);
harness.body = div2;

var btn1 = document.createElement('input');
btn1.setAttribute('type', 'radio');
btn1.setAttribute('name', 'view');
div.appendChild(btn1);
btn1.checked = true;

var lbl1 = document.createElement('label');
lbl1.setAttribute('for', 'btn1');
lbl1.innerHTML = 'PDF'
div.appendChild(lbl1);

var btn2 = document.createElement('input');
btn2.setAttribute('type', 'radio');
btn2.setAttribute('name', 'view');
div.appendChild(btn2);

var lbl2 = document.createElement('label');
lbl2.setAttribute('for', 'btn2');
lbl2.innerHTML = 'Source'
div.appendChild(lbl2);

var btn3 = document.createElement('input');
btn3.setAttribute('type', 'radio');
btn3.setAttribute('name', 'view');
div.appendChild(btn3);

var lbl3 = document.createElement('label');
lbl3.setAttribute('for', 'btn3');
lbl3.innerHTML = 'Both'
div.appendChild(lbl3);

harness.source = document.createElement('pre');
harness.source.setAttribute('style', 'margin-top:0;width:100%;height:100%;position:absolute;top:0px;bottom:0px;overflow:auto');
div2.appendChild(harness.source);

harness.iframe = document.createElement('iframe');
harness.iframe.setAttribute('style', 'width:100%;height:100%;position:absolute;overflow:auto;top:0px;bottom:0px');
div2.appendChild(harness.iframe);

if (pdf_test_harness.onload) {
harness.pdf = pdf_test_harness.onload(harness);
if (harness.message){
var popup = document.createElement('div');
popup.setAttribute('style', 'position:fixed;margin:auto;top:50px;background-color:beige;padding:1em;border:1px solid black');
popup.innerHTML = harness.message;
body.appendChild(popup);
popup.onclick = function(){
popup.parentNode.removeChild(popup);
}

}
}

harness.render('pdf');

btn1.onclick = function() {
harness.render('pdf');
}
btn2.onclick = function() {
harness.render('source');
}
btn3.onclick = function() {
harness.render('both');
}
}

pdf_test_harness = function(pdf) {
this.pdf = pdf;
this.onload = undefined;
this.iframe = undefined;

this.entityMap = {
"&" : "&amp;",
"<" : "&lt;",
">" : "&gt;",
'"' : '&quot;',
"'" : '&#39;',
"/" : '&#x2F;'
};

this.escapeHtml = function(string) {
return String(string).replace(/[&<>"'\/]/g, function(s) {
return this.entityMap[s];
}.bind(this));
};

this.getParameterByName = function(name) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), results = regex.exec(location.search);
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
};

this.setPdf = function(pdf) {
this.pdf = pdf;
this.rendered = undefined;
this.render(this.view);
};

// generate the pdf, the source code, or both
this.render = function(view) {
this.view = view;
//Current code only lets us render one time.
if (!this.rendered) {
this.rendered = this.pdf.output('datauristring');
this.iframe.src = this.rendered;
var raw = this.pdf.output();
raw = this.escapeHtml(raw);
this.source.innerHTML = raw;
}
if ('pdf' === view) {
this.source.style.display = 'none';
this.iframe.style.display = 'block';
this.iframe.style.width = '100%';
} else if ('source' === view) {
this.iframe.style.display = 'none';
this.source.style.display = 'block';
this.source.style.width = '100%';
}

if ('both' === view) {
raw = this.escapeHtml(raw);
this.iframe.style.width = '50%';
this.iframe.style.position = 'relative';
this.iframe.style.display = 'inline-block';
this.source.style.width = '50%';
this.source.style.position = 'relative';
this.source.style.display = 'inline-block';
}
}
}