html-to-pdfmake
Advanced tools
Comparing version 1.0.6 to 1.0.7
@@ -48,2 +48,4 @@ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.htmlToPdfmake = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ | ||
var inlineTags = [ 'p', 'li', 'span', 'strong', 'em', 'b', 'i', 'u' ]; | ||
/** | ||
@@ -59,4 +61,2 @@ * Takes an HTML string, converts to HTML using a DOM parser and recursivly parses | ||
// Cleanup of dirty html would happen here | ||
// Create a HTML DOM tree out of html string | ||
@@ -101,7 +101,4 @@ var parser = new wndw.DOMParser(); | ||
if (parentNodeName) { | ||
// do we have a default style to apply? | ||
// for 'p' we want to apply it from the parent | ||
if (parentNodeName !== 'p') { | ||
applyDefaultStyle(ret, parentNodeName); | ||
} | ||
// check if we have inherent styles to apply when a text is inside several <tag> | ||
applyParentsStyle(ret, element); | ||
@@ -113,2 +110,8 @@ // for links | ||
// for 'td' and 'th' we check if we have "rowspan" or "colspan" | ||
if (parentNodeName === "td" || parentNodeName === "th") { | ||
if (parentNode.getAttribute("rowspan")) ret.rowSpan = parentNode.getAttribute("rowspan")*1; | ||
if (parentNode.getAttribute("colspan")) ret.colSpan = parentNode.getAttribute("colspan")*1; | ||
} | ||
// is there any class to this element? | ||
@@ -137,4 +140,2 @@ cssClass = parentNode.getAttribute("class"); | ||
[].forEach.call(element.childNodes, function(child) { | ||
// for THEAD and TBODY we go straight to the TR | ||
//if (child.nodeName === "THEAD" || child.nodeName === "TBODY" || child.nodeName === "TFOOTER") continue; | ||
child = parseElement(child, element); | ||
@@ -176,5 +177,35 @@ if (child) { | ||
if (re.stack) { | ||
var td = [] | ||
re.stack.forEach(function(r) { | ||
var td = [], | ||
rowspan = {}; | ||
re.stack.forEach(function(r, indexRow) { | ||
if (r.stack) { | ||
// do we have a rowspan to apply from previous rows? | ||
if (rowspan[indexRow]) { | ||
// insert empty cell due to rowspan | ||
rowspan[indexRow].forEach(function(cell) { | ||
r.stack.splice(cell.index, 0, {text:'', style: ['html-td', 'html-tr'], colSpan:cell.colspan}); | ||
}); | ||
} | ||
// insert empty cells due to colspan | ||
r.stack.forEach(function(cell, index) { | ||
if (cell.colSpan > 1) { | ||
for (var i=0; i<cell.colSpan-1; i++) { | ||
r.stack.splice(index+1, 0, {text:'', style: ['html-td', 'html-tr']}) | ||
} | ||
} | ||
}) | ||
// check rowspan for the current row in order to then apply it to the next ones | ||
var indexCell = 0; | ||
r.stack.forEach(function(cell) { | ||
if (cell.rowSpan) { | ||
for (var i=0; i<cell.rowSpan; i++) { | ||
if (!rowspan[indexRow+i]) rowspan[indexRow+i] = []; | ||
// we also remember the colSpan for cells with both rowspan and colspan | ||
rowspan[indexRow+i].push({index:indexCell, colspan:cell.colSpan||1}); | ||
} | ||
} | ||
indexCell += cell.colSpan || 1; | ||
}); | ||
ret.table.body.push(r.stack) | ||
@@ -219,5 +250,9 @@ } else { | ||
// add a custom class to let the user customize the element | ||
// "tr" elements should always contain an array | ||
// "tr" elements should always contain an array | ||
if (ret.length === 1 && nodeName !== "tr") { | ||
ret=ret[0]; | ||
if (ret.text) { | ||
applyDefaultStyle(ret, nodeName); | ||
setComputedStyle(ret, element.getAttribute("style")); | ||
} | ||
ret.style = (ret.style||[]).concat(['html-'+nodeName]); | ||
@@ -227,7 +262,12 @@ // for TD and TH we want to include the style from TR | ||
} else { | ||
ret = (nodeName==='p' ? {text:ret} : {stack:ret}); | ||
// we apply the default style if it's a "p" | ||
if (nodeName === 'p') { | ||
applyDefaultStyle(ret, 'p'); | ||
var isInlineTag = (inlineTags.indexOf(nodeName) > -1); | ||
// if we have an inline tag, then we check if we have a non-inline tag in its section | ||
ret = (!isInlineTag || /{"(stack|table|ol|ul|image)"/.test(JSON.stringify(ret)) ? {stack:ret} : {text:ret}); | ||
// we apply the default style for the inline tags | ||
if (isInlineTag) { | ||
applyDefaultStyle(ret, nodeName); | ||
} | ||
ret.style = ['html-'+nodeName]; | ||
@@ -245,2 +285,13 @@ } | ||
} | ||
// retrieve the class from the parent | ||
cssClass = element.getAttribute("class"); | ||
if (cssClass && typeof ret === 'object') { | ||
// apply all the classes not there yet | ||
ret.style = (ret.style || []) | ||
.concat(cssClass.split(' ')) | ||
.filter(function (value, index, self) { | ||
return self.indexOf(value) === index; | ||
}); | ||
} | ||
} | ||
@@ -264,2 +315,26 @@ | ||
var applyParentsStyle = function(ret, node) { | ||
// while the parents are an inline tag, we want to apply the default style and the class to the children too | ||
var classes = [], defaultStyles = [], cssClass; | ||
var inlineParentNode=node.parentNode; | ||
while (inlineParentNode) { | ||
var defaultStyle = {}; | ||
var inlineParentNodeName=inlineParentNode.nodeName.toLowerCase(); | ||
if (inlineTags.indexOf(inlineParentNodeName) > -1) { | ||
cssClass = inlineParentNode.getAttribute("class"); | ||
classes = classes.concat(['html-'+inlineParentNodeName], cssClass||[]); | ||
applyDefaultStyle(defaultStyle, inlineParentNodeName); | ||
defaultStyles.push(defaultStyle); | ||
inlineParentNode=inlineParentNode.parentNode; | ||
} else break; | ||
} | ||
ret.style = (ret.style||[]).concat(classes); | ||
defaultStyles.forEach(function(defaultStyle) { | ||
for (var key in defaultStyle) { | ||
if (key.indexOf("margin") === -1 && ret[key] === undefined) ret[key] = defaultStyle[key]; | ||
} | ||
}) | ||
} | ||
/** | ||
@@ -266,0 +341,0 @@ * Transform a CSS expression (e.g. 'margin:10px') in the PDFMake version |
@@ -32,4 +32,4 @@ var pdfMake = require("pdfmake/build/pdfmake"); | ||
<ul> | ||
<li>Sub First item</li> | ||
<li>Sub Second item</li> | ||
<li>Sub First <b>bolded</b> item</li> | ||
<li>Sub Second <u>underlined</u> item</li> | ||
<li>With a sub sub unordered list: | ||
@@ -110,2 +110,39 @@ <ul style="background-color:yellow"> | ||
<table> | ||
<tr> | ||
<th>Col A</th> | ||
<th>Col B</th> | ||
<th>Col C</th> | ||
<th>Col D</th> | ||
</tr> | ||
<tr> | ||
<td>Cell A1</td> | ||
<td rowspan="2"> | ||
Cell B1 & B2 | ||
</td> | ||
<td>Cell C1</td> | ||
<td rowspan="2"> | ||
Cell D1 & D2 | ||
</td> | ||
</tr> | ||
<tr> | ||
<td>Cell A2</td> | ||
<td>Cell C2</td> | ||
</tr> | ||
<tr> | ||
<td>Cell A3</td> | ||
<td colspan="2">Cell B3 & C3</td> | ||
<td>Cell D3</td> | ||
</tr> | ||
<tr> | ||
<td rowspan="2" colspan="3"> | ||
Cell A4 & A5 & B4 & B5 & C4 & C5 | ||
</td> | ||
<td>Cell D4</td> | ||
</tr> | ||
<tr> | ||
<td>Cell D5</td> | ||
</tr> | ||
</table> | ||
<div style="margin-top:20px"> | ||
@@ -116,2 +153,4 @@ An image: <img width="54" style="height:70px" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEBLAEsAAD/7QPQUGhvdG9zaG9wIDMuMAA4QklNA+kKUHJpbnQgSW5mbwAAAAB4AAMAAABIAEgAAAAAAtgCKP/h/+IC+QJGA0cFKAP8AAIAAABIAEgAAAAAAtgCKAABAAAAZAAAAAEAAwMDAAAAAScPAAEAAQAAAAAAAAAAAAAAAGAIABkBkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOEJJTQPtClJlc29sdXRpb24AAAAAEAEsAAAAAQABASwAAAABAAE4QklNBA0YRlggR2xvYmFsIExpZ2h0aW5nIEFuZ2xlAAAAAAQAAAAeOEJJTQQZEkZYIEdsb2JhbCBBbHRpdHVkZQAAAAAEAAAAHjhCSU0D8wtQcmludCBGbGFncwAAAAkAAAAAAAAAAAEAOEJJTQQKDkNvcHlyaWdodCBGbGFnAAAAAAEAADhCSU0nEBRKYXBhbmVzZSBQcmludCBGbGFncwAAAAAKAAEAAAAAAAAAAjhCSU0D9RdDb2xvciBIYWxmdG9uZSBTZXR0aW5ncwAAAEgAL2ZmAAEAbGZmAAYAAAAAAAEAL2ZmAAEAoZmaAAYAAAAAAAEAMgAAAAEAWgAAAAYAAAAAAAEANQAAAAEALQAAAAYAAAAAAAE4QklNA/gXQ29sb3IgVHJhbnNmZXIgU2V0dGluZ3MAAABwAAD/////////////////////////////A+gAAAAA/////////////////////////////wPoAAAAAP////////////////////////////8D6AAAAAD/////////////////////////////A+gAADhCSU0ECAZHdWlkZXMAAAAAEAAAAAEAAAJAAAACQAAAAAA4QklNBB4NVVJMIG92ZXJyaWRlcwAAAAQAAAAAOEJJTQQaBlNsaWNlcwAAAABtAAAABgAAAAAAAAAAAAALiAAACMMAAAAGADYAMgAuADYAOAA0AAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAjDAAALiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4QklNBBQXTGF5ZXIgSUQgR2VuZXJhdG9yIEJhc2UAAAAEAAAAAThCSU0EIRpWZXJzaW9uIGNvbXBhdGliaWxpdHkgaW5mbwAAAABVAAAAAQEAAAAPAEEAZABvAGIAZQAgAFAAaABvAHQAbwBzAGgAbwBwAAAAEwBBAGQAbwBiAGUAIABQAGgAbwB0AG8AcwBoAG8AcAAgADYALgAwAAAAAQD/4gxQSUNDX1BST0ZJTEUAAQEAAAxATGlubwIQAABtbnRyUkdCIFhZWiAHzgACAAkABgAxAABhY3NwTVNGVAAAAABJRUMgc1JHQgAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLUhQICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFjcHJ0AAABUAAAADN3dHB0AAABhAAAABRia3B0AAABmAAAABRyWFlaAAABrAAAABRnWFlaAAABwAAAABRiWFlaAAAB1AAAABRkbW5kAAAB6AAAAHBkbWRkAAACWAAAAIh2dWVkAAAC4AAAAIZ2aWV3AAADaAAAACRsdW1pAAADjAAAABRtZWFzAAADoAAAACR0ZWNoAAADxAAAAAxyVFJDAAAD0AAACAxnVFJDAAAD0AAACAxiVFJDAAAD0AAACAxkZXNjAAAL3AAAAGN0ZXh0AAAAAENvcHlyaWdodCAoYykgMTk5OCBIZXdsZXR0LVBhY2thcmQgQ29tcGFueQAAWFlaIAAAAAAAAPNRAAEAAAABFsxYWVogAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAABvogAAOPUAAAOQWFlaIAAAAAAAAGKZAAC3hQAAGNpYWVogAAAAAAAAJKAAAA+EAAC2z2Rlc2MAAAAAAAAAFklFQyBodHRwOi8vd3d3LmllYy5jaAAAAAAAAAAAAAAAFklFQyBodHRwOi8vd3d3LmllYy5jaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkZXNjAAAAAAAAAC5JRUMgNjE5NjYtMi4xIERlZmF1bHQgUkdCIGNvbG91ciBzcGFjZSAtIHNSR0IAAAAAAAAAAAAAAC5JRUMgNjE5NjYtMi4xIERlZmF1bHQgUkdCIGNvbG91ciBzcGFjZSAtIHNSR0IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGVzYwAAAAAAAAAsUmVmZXJlbmNlIFZpZXdpbmcgQ29uZGl0aW9uIGluIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAALFJlZmVyZW5jZSBWaWV3aW5nIENvbmRpdGlvbiBpbiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZpZXcAAAAAABOk/gAUXy4AEM8UAAPtzAAEEwsAA1yeAAAAAVhZWiAAAAAAAEwJVgBQAAAAVx/nbWVhcwAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAo8AAAACc2lnIAAAAABDUlQgY3VydgAAAAAAAAQAAAAABQAKAA8AFAAZAB4AIwAoAC0AMgA3ADsAQABFAEoATwBUAFkAXgBjAGgAbQByAHcAfACBAIYAiwCQAJUAmgCfAKQAqQCuALIAtwC8AMEAxgDLANAA1QDbAOAA5QDrAPAA9gD7AQEBBwENARMBGQEfASUBKwEyATgBPgFFAUwBUgFZAWABZwFuAXUBfAGDAYsBkgGaAaEBqQGxAbkBwQHJAdEB2QHhAekB8gH6AgMCDAIUAh0CJgIvAjgCQQJLAlQCXQJnAnECegKEAo4CmAKiAqwCtgLBAssC1QLgAusC9QMAAwsDFgMhAy0DOANDA08DWgNmA3IDfgOKA5YDogOuA7oDxwPTA+AD7AP5BAYEEwQgBC0EOwRIBFUEYwRxBH4EjASaBKgEtgTEBNME4QTwBP4FDQUcBSsFOgVJBVgFZwV3BYYFlgWmBbUFxQXVBeUF9gYGBhYGJwY3BkgGWQZqBnsGjAadBq8GwAbRBuMG9QcHBxkHKwc9B08HYQd0B4YHmQesB78H0gflB/gICwgfCDIIRghaCG4IggiWCKoIvgjSCOcI+wkQCSUJOglPCWQJeQmPCaQJugnPCeUJ+woRCicKPQpUCmoKgQqYCq4KxQrcCvMLCwsiCzkLUQtpC4ALmAuwC8gL4Qv5DBIMKgxDDFwMdQyODKcMwAzZDPMNDQ0mDUANWg10DY4NqQ3DDd4N+A4TDi4OSQ5kDn8Omw62DtIO7g8JDyUPQQ9eD3oPlg+zD88P7BAJECYQQxBhEH4QmxC5ENcQ9RETETERTxFtEYwRqhHJEegSBxImEkUSZBKEEqMSwxLjEwMTIxNDE2MTgxOkE8UT5RQGFCcUSRRqFIsUrRTOFPAVEhU0FVYVeBWbFb0V4BYDFiYWSRZsFo8WshbWFvoXHRdBF2UXiReuF9IX9xgbGEAYZRiKGK8Y1Rj6GSAZRRlrGZEZtxndGgQaKhpRGncanhrFGuwbFBs7G2MbihuyG9ocAhwqHFIcexyjHMwc9R0eHUcdcB2ZHcMd7B4WHkAeah6UHr4e6R8THz4faR+UH78f6iAVIEEgbCCYIMQg8CEcIUghdSGhIc4h+yInIlUigiKvIt0jCiM4I2YjlCPCI/AkHyRNJHwkqyTaJQklOCVoJZclxyX3JicmVyaHJrcm6CcYJ0kneierJ9woDSg/KHEooijUKQYpOClrKZ0p0CoCKjUqaCqbKs8rAis2K2krnSvRLAUsOSxuLKIs1y0MLUEtdi2rLeEuFi5MLoIuty7uLyQvWi+RL8cv/jA1MGwwpDDbMRIxSjGCMbox8jIqMmMymzLUMw0zRjN/M7gz8TQrNGU0njTYNRM1TTWHNcI1/TY3NnI2rjbpNyQ3YDecN9c4FDhQOIw4yDkFOUI5fzm8Ofk6Njp0OrI67zstO2s7qjvoPCc8ZTykPOM9Ij1hPaE94D4gPmA+oD7gPyE/YT+iP+JAI0BkQKZA50EpQWpBrEHuQjBCckK1QvdDOkN9Q8BEA0RHRIpEzkUSRVVFmkXeRiJGZ0arRvBHNUd7R8BIBUhLSJFI10kdSWNJqUnwSjdKfUrESwxLU0uaS+JMKkxyTLpNAk1KTZNN3E4lTm5Ot08AT0lPk0/dUCdQcVC7UQZRUFGbUeZSMVJ8UsdTE1NfU6pT9lRCVI9U21UoVXVVwlYPVlxWqVb3V0RXklfgWC9YfVjLWRpZaVm4WgdaVlqmWvVbRVuVW+VcNVyGXNZdJ114XcleGl5sXr1fD19hX7NgBWBXYKpg/GFPYaJh9WJJYpxi8GNDY5dj62RAZJRk6WU9ZZJl52Y9ZpJm6Gc9Z5Nn6Wg/aJZo7GlDaZpp8WpIap9q92tPa6dr/2xXbK9tCG1gbbluEm5rbsRvHm94b9FwK3CGcOBxOnGVcfByS3KmcwFzXXO4dBR0cHTMdSh1hXXhdj52m3b4d1Z3s3gReG54zHkqeYl553pGeqV7BHtje8J8IXyBfOF9QX2hfgF+Yn7CfyN/hH/lgEeAqIEKgWuBzYIwgpKC9INXg7qEHYSAhOOFR4Wrhg6GcobXhzuHn4gEiGmIzokziZmJ/opkisqLMIuWi/yMY4zKjTGNmI3/jmaOzo82j56QBpBukNaRP5GokhGSepLjk02TtpQglIqU9JVflcmWNJaflwqXdZfgmEyYuJkkmZCZ/JpomtWbQpuvnByciZz3nWSd0p5Anq6fHZ+Ln/qgaaDYoUehtqImopajBqN2o+akVqTHpTilqaYapoum/adup+CoUqjEqTepqaocqo+rAqt1q+msXKzQrUStuK4trqGvFq+LsACwdbDqsWCx1rJLssKzOLOutCW0nLUTtYq2AbZ5tvC3aLfguFm40blKucK6O7q1uy67p7whvJu9Fb2Pvgq+hL7/v3q/9cBwwOzBZ8Hjwl/C28NYw9TEUcTOxUvFyMZGxsPHQce/yD3IvMk6ybnKOMq3yzbLtsw1zLXNNc21zjbOts83z7jQOdC60TzRvtI/0sHTRNPG1EnUy9VO1dHWVdbY11zX4Nhk2OjZbNnx2nba+9uA3AXcit0Q3ZbeHN6i3ynfr+A24L3hROHM4lPi2+Nj4+vkc+T85YTmDeaW5x/nqegy6LzpRunQ6lvq5etw6/vshu0R7ZzuKO6070DvzPBY8OXxcvH/8ozzGfOn9DT0wvVQ9d72bfb794r4Gfio+Tj5x/pX+uf7d/wH/Jj9Kf26/kv+3P9t//9kZXNjAAAAAAAAAAlzUkdCLmljYwAAAAAAAAAAAAAACXNSR0IuaWNjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+EEGWh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8APD94cGFja2V0IGJlZ2luPSfvu78nIGlkPSdXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQnPz4gPHg6eG1wbWV0YSB4bWxuczp4PSdhZG9iZTpuczptZXRhLycgeDp4bXB0az0nWE1QIHRvb2xraXQgMi45LTksIGZyYW1ld29yayAxLjYnPgo8cmRmOlJERiB4bWxuczpyZGY9J2h0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMnIHhtbG5zOmlYPSdodHRwOi8vbnMuYWRvYmUuY29tL2lYLzEuMC8nPgo8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0nJyB4bWxuczp4YXA9J2h0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8nIHhhcDpNZXRhZGF0YURhdGU9JzIwMTEtMDktMDJUMTU6Mzc6MzFaJy8+CjxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PScnIHhtbG5zOnhhcFJpZ2h0cz0naHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3JpZ2h0cy8nIHhhcFJpZ2h0czpNYXJrZWQ9J0ZhbHNlJy8+CjxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PScnIHhtbG5zOm1ibj0naHR0cDovL25zLmludGVyd292ZW4uY29tL21lZGlhYmluLzEuMC8nPjxtYm46dGFnPiNNQiU6e0VBMkI2MDc3LTEwODAtNDJGNi1BQzZCLUVEMTkyQTRFOTI2RX1TUE1JQVBQMDA6JU1CIzwvbWJuOnRhZz48L3JkZjpEZXNjcmlwdGlvbj4KPHJkZjpEZXNjcmlwdGlvbiBJRD0naHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3JpZ2h0cy8nPjxpWDpjaGFuZ2VzPjxyZGY6QmFnPjxyZGY6bGk+TWFya2VkLDIwMTEtMDktMDJUMTU6Mzc6MzFaLDIsYzwvcmRmOmxpPjwvcmRmOkJhZz48L2lYOmNoYW5nZXM+PC9yZGY6RGVzY3JpcHRpb24+PHJkZjpEZXNjcmlwdGlvbiBJRD0naHR0cDovL25zLmludGVyd292ZW4uY29tL21lZGlhYmluLzEuMC8nPjxpWDpjaGFuZ2VzPjxyZGY6QmFnPjxyZGY6bGk+dGFnLDIwMTEtMDktMDJUMTU6Mzc6MzFaLDEsYzwvcmRmOmxpPjwvcmRmOkJhZz48L2lYOmNoYW5nZXM+PC9yZGY6RGVzY3JpcHRpb24+PC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KPD94cGFja2V0IGVuZD0ndyc/Pv/bAEMAAwICAwICAwMDAwQDAwQFCAUFBAQFCgcHBggMCgwMCwoLCw0OEhANDhEOCwsQFhARExQVFRUMDxcYFhQYEhQVFP/bAEMBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIAEEAMQMBIgACEQEDEQH/xAAbAAACAgMBAAAAAAAAAAAAAAAABgUIAwQHAv/EAD8QAAECBAQCBgUHDQAAAAAAAAECAwAEBREGEiExQWEHExQiUXEVMjOBkQgjNFKys9IWQlRiY3OSk6GxwdHw/8QAGAEAAwEBAAAAAAAAAAAAAAAAAQIEAwX/xAAbEQADAQEBAQEAAAAAAAAAAAAAAQIRIRIxQf/aAAwDAQACEQMRAD8AUcVUqorrdVcFVngO1vGwmnLDvq/WhUmKfVCnu1eoDXhOO/ih3xLOZKvUgDcKmXftmFdc2jMRwEc+fhQz1h/AddxAzNuprdUQ0yLZkTjm/wDFwhZxPRqhQWQynEdcW8VWDnpB0k8LAZo7b0Z1GWZw5OMrl1KdfWS28T3R4mITG3RqH1tz7jym1K1yqABItra+w584Kpp4BrUVwXU8TInlMjE9XaUBey513QeYVGwzX8TyuZZxPUXgAdFTrv4oZulDC6MP9mm2FtgOIzKYIUVj32srzv8ACOe+kW3WkhTSm3FBfIaRTNt9Rg5Xxlzfyqqn6bM/z1/7giDzJ/4wRD6K/Ig4qrakVqpZhYCae+2qFlytoUCSTa+tuAjPi+bzVupJuPpb33ioUpp7KkgHeN5XDJs7rhvpKoNCwTIzz7E51TUyZR4yqQvvg+sM1tLEXHC8ZcSYxZr9dbmGHVuSqUXX3dU+GnwiMwRjLD9XlpbD8i2ahKy8l1c6Vy5SM6k3Wq+1hYJGtzGjW6lgySp89K4YrkumZSPnWmmwFeQBhM6HSD6TqvNzqBKpak35hDQF3FlITfUKBB35a8vCOAvOTCqqsTDgdU2lQBB024Q2V5lyZptSqaq8EstvCXTKuLzOuulOYWTvlHj4nlCtKyTqW3pl6/fTYX3Om8VQsRjT0uL1PnBEhkP1YIh4VlbsYVJasRVMJO04994qOm9D/Q8jEcg1XMQN9dT30ns0olRGcbZ1kG9t7J+McKxhW+x4kq6X2lIcTOP2RxV84r4CO7/J16ZJNODpmlVp5EimRKlyyzdQW2o+oNzmBvp4GKrVTPCeWm+ktjroLw09WGqnK1B7DDQTlmkSNkoWgfnBPBXlvvFf8WY0oq69UWqTKr9HSjZlKY2o513Ju48pXFajx5w9/KI6VpartSrVBm3yF5m3szRQCCOF453g6jppEol9TPaJx4erpZsczBhNTtArNxC7TcOTM6HJ2YzsAHRZGpJ4czyjeep8zTpAIed6xNjpxRyhrmnA7UG231pDgGZDRNykeNht5xiqpZEs6lSkL7h0UOUP66LhavLyMEbWVH1IIgLOlO63T5esY3rL02VvtomXQACbKIWdCf8AAiUl3kNBhpgIbZOqEoFhby98aVef6iu1RKDa068d/wBoqIdc+pnJ1ZzkXKQpXEnaOi02RakecUTTbVZlkrCXG23UrUhWotziUcxG603ll05lq0QkWELlUYbeC3Xni+8rU2sLnhtGamTDbMukqUkvZbEk/wBoLngN6SjbpkWXFO5lzDurjwOpPhyAiJnJpCQtLStCDfKs/wBdo8vVBalHKpJ5XjWDC5x463Ub6Ei8NENsFUki+HZ1+EETPYFcoI5+FQ4z30qZ/eL+0Y0V+0MEEYDfppv+0iMd398EEMKzwNzGWT9vBBGi+CssBBBBHOKj/9k="> | ||
<p style="text-align: center;"> <span style="font-size: 14px;"><em><strong>Bold italic centered text</strong></em></span> </p> | ||
<span class="a">text "bold" <span class="b">text "bold & italic" <span class="c">text "bold & italic & red"</span> text "bold & italic"</span> text "bold"</span> | ||
`, window); | ||
@@ -132,2 +171,15 @@ | ||
color:'purple' | ||
}, | ||
'html-strong':{ | ||
color:'purple' | ||
}, | ||
'a':{ | ||
bold:true | ||
}, | ||
'b':{ | ||
italics: true | ||
}, | ||
'c':{ | ||
color:'red', | ||
italics: false | ||
} | ||
@@ -134,0 +186,0 @@ } |
107
index.js
@@ -47,2 +47,4 @@ // source: https://github.com/OpenSlides/OpenSlides/blob/f4f8b8422f9b3fbab58e35ac3f8f870d35813b7d/client/src/app/core/ui-services/html-to-pdf.service.ts | ||
var inlineTags = [ 'p', 'li', 'span', 'strong', 'em', 'b', 'i', 'u' ]; | ||
/** | ||
@@ -58,4 +60,2 @@ * Takes an HTML string, converts to HTML using a DOM parser and recursivly parses | ||
// Cleanup of dirty html would happen here | ||
// Create a HTML DOM tree out of html string | ||
@@ -96,11 +96,8 @@ var parser = new wndw.DOMParser(); | ||
if (element.textContent) { | ||
text = element.textContent.replace(/\n(\s+)?/g, "").trim(); | ||
text = element.textContent.replace(/\n(\s+)?/g, ""); | ||
if (text) { | ||
ret = {'text': text}; | ||
if (parentNodeName) { | ||
// do we have a default style to apply? | ||
// for 'p' we want to apply it from the parent | ||
if (parentNodeName !== 'p') { | ||
applyDefaultStyle(ret, parentNodeName); | ||
} | ||
// check if we have inherent styles to apply when a text is inside several <tag> | ||
applyParentsStyle(ret, element); | ||
@@ -112,2 +109,8 @@ // for links | ||
// for 'td' and 'th' we check if we have "rowspan" or "colspan" | ||
if (parentNodeName === "td" || parentNodeName === "th") { | ||
if (parentNode.getAttribute("rowspan")) ret.rowSpan = parentNode.getAttribute("rowspan")*1; | ||
if (parentNode.getAttribute("colspan")) ret.colSpan = parentNode.getAttribute("colspan")*1; | ||
} | ||
// is there any class to this element? | ||
@@ -136,4 +139,2 @@ cssClass = parentNode.getAttribute("class"); | ||
[].forEach.call(element.childNodes, function(child) { | ||
// for THEAD and TBODY we go straight to the TR | ||
//if (child.nodeName === "THEAD" || child.nodeName === "TBODY" || child.nodeName === "TFOOTER") continue; | ||
child = parseElement(child, element); | ||
@@ -175,5 +176,35 @@ if (child) { | ||
if (re.stack) { | ||
var td = [] | ||
re.stack.forEach(function(r) { | ||
var td = [], | ||
rowspan = {}; | ||
re.stack.forEach(function(r, indexRow) { | ||
if (r.stack) { | ||
// do we have a rowspan to apply from previous rows? | ||
if (rowspan[indexRow]) { | ||
// insert empty cell due to rowspan | ||
rowspan[indexRow].forEach(function(cell) { | ||
r.stack.splice(cell.index, 0, {text:'', style: ['html-td', 'html-tr'], colSpan:cell.colspan}); | ||
}); | ||
} | ||
// insert empty cells due to colspan | ||
r.stack.forEach(function(cell, index) { | ||
if (cell.colSpan > 1) { | ||
for (var i=0; i<cell.colSpan-1; i++) { | ||
r.stack.splice(index+1, 0, {text:'', style: ['html-td', 'html-tr']}) | ||
} | ||
} | ||
}) | ||
// check rowspan for the current row in order to then apply it to the next ones | ||
var indexCell = 0; | ||
r.stack.forEach(function(cell) { | ||
if (cell.rowSpan) { | ||
for (var i=0; i<cell.rowSpan; i++) { | ||
if (!rowspan[indexRow+i]) rowspan[indexRow+i] = []; | ||
// we also remember the colSpan for cells with both rowspan and colspan | ||
rowspan[indexRow+i].push({index:indexCell, colspan:cell.colSpan||1}); | ||
} | ||
} | ||
indexCell += cell.colSpan || 1; | ||
}); | ||
ret.table.body.push(r.stack) | ||
@@ -218,7 +249,5 @@ } else { | ||
// add a custom class to let the user customize the element | ||
// "tr" elements should always contain an array | ||
// "tr" elements should always contain an array | ||
if (ret.length === 1 && nodeName !== "tr") { | ||
ret=ret[0]; | ||
// check if we have a default css style to apply when a text is inside several <tag> | ||
// e.g. <strong><em>text</em></strong> | ||
if (ret.text) { | ||
@@ -232,7 +261,12 @@ applyDefaultStyle(ret, nodeName); | ||
} else { | ||
ret = (nodeName==='p' ? {text:ret} : {stack:ret}); | ||
// we apply the default style if it's a "p" | ||
if (nodeName === 'p') { | ||
applyDefaultStyle(ret, 'p'); | ||
var isInlineTag = (inlineTags.indexOf(nodeName) > -1); | ||
// if we have an inline tag, then we check if we have a non-inline tag in its section | ||
ret = (!isInlineTag || /{"(stack|table|ol|ul|image)"/.test(JSON.stringify(ret)) ? {stack:ret} : {text:ret}); | ||
// we apply the default style for the inline tags | ||
if (isInlineTag) { | ||
applyDefaultStyle(ret, nodeName); | ||
} | ||
ret.style = ['html-'+nodeName]; | ||
@@ -250,2 +284,13 @@ } | ||
} | ||
// retrieve the class from the parent | ||
cssClass = element.getAttribute("class"); | ||
if (cssClass && typeof ret === 'object') { | ||
// apply all the classes not there yet | ||
ret.style = (ret.style || []) | ||
.concat(cssClass.split(' ')) | ||
.filter(function (value, index, self) { | ||
return self.indexOf(value) === index; | ||
}); | ||
} | ||
} | ||
@@ -269,2 +314,26 @@ | ||
var applyParentsStyle = function(ret, node) { | ||
// while the parents are an inline tag, we want to apply the default style and the class to the children too | ||
var classes = [], defaultStyles = [], cssClass; | ||
var inlineParentNode=node.parentNode; | ||
while (inlineParentNode) { | ||
var defaultStyle = {}; | ||
var inlineParentNodeName=inlineParentNode.nodeName.toLowerCase(); | ||
if (inlineTags.indexOf(inlineParentNodeName) > -1) { | ||
cssClass = inlineParentNode.getAttribute("class"); | ||
classes = classes.concat(['html-'+inlineParentNodeName], cssClass||[]); | ||
applyDefaultStyle(defaultStyle, inlineParentNodeName); | ||
defaultStyles.push(defaultStyle); | ||
inlineParentNode=inlineParentNode.parentNode; | ||
} else break; | ||
} | ||
ret.style = (ret.style||[]).concat(classes); | ||
defaultStyles.forEach(function(defaultStyle) { | ||
for (var key in defaultStyle) { | ||
if (key.indexOf("margin") === -1 && ret[key] === undefined) ret[key] = defaultStyle[key]; | ||
} | ||
}) | ||
} | ||
/** | ||
@@ -271,0 +340,0 @@ * Transform a CSS expression (e.g. 'margin:10px') in the PDFMake version |
{ | ||
"name": "html-to-pdfmake", | ||
"version": "1.0.6", | ||
"version": "1.0.7", | ||
"description": "Convert HTML code to PDFMake", | ||
@@ -9,3 +9,4 @@ "main": "index.js", | ||
"test": "node test/unit.js", | ||
"browser": "browserify index.js --standalone htmlToPdfmake > docs/browser.js" | ||
"browser": "browserify index.js --standalone htmlToPdfmake > docs/browser.js", | ||
"publish": "npm run browser && npm publish" | ||
}, | ||
@@ -27,3 +28,4 @@ "repository": { | ||
"simple-test-framework": "^0.1.7" | ||
} | ||
}, | ||
"dependencies": {} | ||
} |
@@ -327,2 +327,76 @@ var htmlToPdfMake = require('../index.js'); | ||
test("table (rowspan/colspan)", function(t) { | ||
var html = `<table> | ||
<tr> | ||
<th>Col A</th> | ||
<th>Col B</th> | ||
<th>Col C</th> | ||
<th>Col D</th> | ||
</tr> | ||
<tr> | ||
<td>Cell A1</td> | ||
<td rowspan="2"> | ||
Cell B1 & B2 | ||
</td> | ||
<td>Cell C1</td> | ||
<td rowspan="2"> | ||
Cell D1 & D2 | ||
</td> | ||
</tr> | ||
<tr> | ||
<td>Cell A2</td> | ||
<td>Cell C2</td> | ||
</tr> | ||
<tr> | ||
<td>Cell A3</td> | ||
<td colspan="2">Cell B3 & C3</td> | ||
<td>Cell D3</td> | ||
</tr> | ||
<tr> | ||
<td rowspan="2" colspan="3"> | ||
Cell A4 & A5 & B4 & B5 & C4 & C5 | ||
</td> | ||
<td>Cell D4</td> | ||
</tr> | ||
<tr> | ||
<td>Cell D5</td> | ||
</tr> | ||
</table>`; | ||
var ret = htmlToPdfMake(html, window); | ||
t.check(Array.isArray(ret) && ret.length===1, "return is OK"); | ||
ret = ret[0]; | ||
t.check( | ||
ret.table && | ||
Array.isArray(ret.table.body) && | ||
ret.table.body.length === 6 && | ||
ret.table.body[1][0].text === "Cell A1" && | ||
ret.table.body[1][0].style[0] === 'html-td' && | ||
ret.table.body[1][0].style[1] === 'html-tr' && | ||
ret.table.body[1][1].text === "Cell B1 & B2" && | ||
ret.table.body[1][2].text === "Cell C1" && | ||
ret.table.body[1][3].text === "Cell D1 & D2" && | ||
ret.table.body[2][0].text === "Cell A2" && | ||
ret.table.body[2][1].text === "" && | ||
ret.table.body[2][2].text === "Cell C2" && | ||
ret.table.body[2][3].text === "" && | ||
ret.table.body[3][0].text === "Cell A3" && | ||
ret.table.body[3][1].text === "Cell B3 & C3" && | ||
ret.table.body[3][2].text === "" && | ||
ret.table.body[3][3].text === "Cell D3" && | ||
ret.table.body[4][0].text === "Cell A4 & A5 & B4 & B5 & C4 & C5" && | ||
ret.table.body[4][1].text === "" && | ||
ret.table.body[4][2].text === "" && | ||
ret.table.body[4][3].text === "Cell D4" && | ||
ret.table.body[5][0].text === "" && | ||
ret.table.body[5][1].text === "" && | ||
ret.table.body[5][2].text === "" && | ||
ret.table.body[5][3].text === "Cell D5" && | ||
Array.isArray(ret.style) && | ||
ret.style[0] === 'html-table', | ||
"table (rowspan/colspan)"); | ||
t.finish(); | ||
}) | ||
test("img",function(t) { | ||
@@ -343,3 +417,3 @@ var ret = htmlToPdfMake('<img width="10" style="height:10px" src="data:image/jpeg;base64,...encodedContent...">', window); | ||
test("cascade_tags", function(t) { | ||
var ret = htmlToPdfMake('<p style="text-align: center;"> <span style="font-size: 14px;"><em><strong>test</strong></em></span> </p>', window); | ||
var ret = htmlToPdfMake('<p style="text-align: center;"><span style="font-size: 14px;"><em><strong>test</strong></em></span></p>', window); | ||
t.check(Array.isArray(ret) && ret.length===1, "return is OK"); | ||
@@ -346,0 +420,0 @@ ret = ret[0]; |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
104983
12
1448