diff --git a/doc/plugins/from_html.md b/doc/plugins/from_html.md new file mode 100644 index 000000000..ad7468e77 --- /dev/null +++ b/doc/plugins/from_html.md @@ -0,0 +1,43 @@ + + +# 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 \ No newline at end of file diff --git a/jspdf.plugin.from_html.js b/jspdf.plugin.from_html.js index 79395fcd9..9142c27f9 100644 --- a/jspdf.plugin.from_html.js +++ b/jspdf.plugin.from_html.js @@ -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"; @@ -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; diff --git a/test/test_from_html_css_page_breaks.html b/test/test_from_html_css_page_breaks.html new file mode 100644 index 000000000..dd62b69c7 --- /dev/null +++ b/test/test_from_html_css_page_breaks.html @@ -0,0 +1,75 @@ + + + + + + + +Test HTML + + + + + + + + + + + + + + + + + + + diff --git a/test/test_harness.js b/test/test_harness.js new file mode 100644 index 000000000..b95456939 --- /dev/null +++ b/test/test_harness.js @@ -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 = { + "&" : "&", + "<" : "<", + ">" : ">", + '"' : '"', + "'" : ''', + "/" : '/' + }; + + 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'; + } + } +} \ No newline at end of file