Fixed dynamic pdf header/footer and table border (Fixed #2923).

Updated pdfmake to 0.1.25.
Fixed some pdf style issues.
Updated gulp watch task.
This commit is contained in:
Emanuel Schütze 2017-02-01 16:53:01 +01:00
parent bcff33330c
commit 3d60238ce1
6 changed files with 103 additions and 70 deletions

View File

@ -34,7 +34,7 @@
"ngstorage": "~0.3.11", "ngstorage": "~0.3.11",
"ngBootbox": "~0.1.3", "ngBootbox": "~0.1.3",
"papaparse": "~4.1.2", "papaparse": "~4.1.2",
"pdfmake": "0.1.23", "pdfmake": "0.1.25",
"roboto-fontface": "~0.6.0" "roboto-fontface": "~0.6.0"
}, },
"overrides": { "overrides": {

View File

@ -228,9 +228,13 @@ gulp.task('default', [
*/ */
// Watches changes in JavaScript and templates. // Watches changes in JavaScript and templates.
gulp.task('watch', ['js', 'templates'], function () { gulp.task('watch', ['js', 'templates', 'pdf-worker'], function () {
gulp.watch(path.join('openslides', '*', 'static', 'js', '**', '*.js'), ['js']); gulp.watch([
path.join('openslides', '*', 'static', 'js', '**', '*.js'),
'!' + path.join('openslides', 'core', 'static', 'js', 'core', 'pdf-worker.js')
], ['js']);
gulp.watch(path.join('openslides', '*', 'static', 'templates', '**', '*.html'), ['templates']); gulp.watch(path.join('openslides', '*', 'static', 'templates', '**', '*.html'), ['templates']);
gulp.watch(path.join('openslides', 'core', 'static', 'js', 'core', 'pdf-worker.js'), ['pdf-worker']);
}); });
// Extracts translatable strings using angular-gettext and saves them in file // Extracts translatable strings using angular-gettext and saves them in file

View File

@ -30,6 +30,72 @@ pdfMake.fonts = {
// Create PDF on message and return the base64 decoded document // Create PDF on message and return the base64 decoded document
self.addEventListener('message', function(e) { self.addEventListener('message', function(e) {
var data = JSON.parse(e.data); var data = JSON.parse(e.data);
// Workaround for using dynamic footer with page number.
// TODO: Needs improvement of pdfmake's web worker support.
// see https://github.com/bpampuch/pdfmake/issues/38
if (data.footerTpl) {
data.footer = function (currentPage, pageCount) {
var footerText = data.footerTpl.text
.replace('{{currentPage}}', currentPage)
.replace('{{pageCount}}', pageCount);
return {
text: footerText,
alignment: data.footerTpl.alignment,
fontSize: data.footerTpl.fontSize,
color: data.footerTpl.color
};
};
}
// Workaround for using table layout functions.
// TODO: Needs improvement of pdfmake's web worker support.
// Currently only functions are allowed for 'layout'.
// But functions cannot be passed to workers (via JSON).
//
// ballot paper crop marks
for (var i = 0; i < data.content.length; i++) {
if (data.content[i].layout === "{{ballot-placeholder-to-insert-functions-here}}") {
data.content[i].layout = {
hLineWidth: function(i, node) {
if (i === 0){
return 0;
} else if (i === node.table.body.length) {
if (node.rowsperpage && node.rowsperpage > i) {
return 0.5;
} else {
return 0;
}
} else {
return 0.5;
}
},
vLineWidth: function(i, node) {
return (i === 0 || i === node.table.widths.length) ? 0 : 0.5;
},
hLineColor: function() {
return 'gray';
},
vLineColor: function() {
return 'gray';
}
};
}
// motion meta table border lines
if (data.content[i].layout === "{{motion-placeholder-to-insert-functions-here}}") {
data.content[i].layout = {
hLineWidth: function(i, node) {
return (i === 0 || i === node.table.body.length) ? 0 : 0.5;
},
vLineWidth: function() {
return 0;
},
hLineColor: function() {
return 'white';
}
};
}
}
var pdf = pdfMake.createPdf(data); var pdf = pdfMake.createPdf(data);
pdf.getBase64(function (base64) { pdf.getBase64(function (base64) {
self.postMessage(base64); self.postMessage(base64);

View File

@ -84,40 +84,7 @@ angular.module('OpenSlidesApp.core.pdf', [])
// crop marks for ballot papers // crop marks for ballot papers
PDFLayout.getBallotLayoutLines = function() { PDFLayout.getBallotLayoutLines = function() {
return { return '{{ballot-placeholder-to-insert-functions-here}}';
hLineWidth: function(i, node) {
if (i === 0){
return 0;
} else if (i === node.table.body.length) {
if (node.rowsperpage && node.rowsperpage > i) {
return 0.5;
} else {
return 0;
}
} else {
return 0.5;
}
},
vLineWidth: function(i, node) {
return (i === 0 || i === node.table.widths.length) ? 0 : 0.5;
},
hLineColor: function(i, node) {
if (i === 0){
return 'none';
} else if (i === node.table.body.length) {
if (node.rowsperpage && node.rowsperpage > i) {
return 'gray';
} else {
return 'none';
}
} else {
return 'gray';
}
},
vLineColor: function(i, node) {
return (i === 0 || i === node.table.widths.length) ? 'none' : 'gray';
},
};
}; };
return PDFLayout; return PDFLayout;
@ -161,8 +128,7 @@ angular.module('OpenSlidesApp.core.pdf', [])
*/ */
var createInstance = function(contentProvider) { var createInstance = function(contentProvider) {
// PDF header // PDF header
var header = function() { var getHeader = function() {
var date = new Date();
var columns = []; var columns = [];
// add here your custom logo (which has to be added to a custom vfs_fonts.js) // add here your custom logo (which has to be added to a custom vfs_fonts.js)
@ -196,14 +162,17 @@ angular.module('OpenSlidesApp.core.pdf', [])
}; };
}; };
// PDF footer // PDF footer
var footer = function(currentPage, pageCount) { // Used placeholder for currentPage and pageCount which
// are replaced by dynamic footer function in pdf-worker.js.
var getFooter = function() {
return { return {
alignment: 'center', alignment: 'center',
fontSize: 8, fontSize: 8,
color: '#555', color: '#555',
text: gettextCatalog.getString('Page') + ' ' + currentPage.toString() + text: gettextCatalog.getString('Page') +
' / ' + pageCount.toString() ' {{currentPage}} / {{pageCount}}'
}; };
}; };
// Generates the document(definition) for pdfMake // Generates the document(definition) for pdfMake
@ -211,13 +180,13 @@ angular.module('OpenSlidesApp.core.pdf', [])
var content = contentProvider.getContent(); var content = contentProvider.getContent();
return { return {
pageSize: 'A4', pageSize: 'A4',
pageMargins: [80, 90, 80, 60], pageMargins: [80, 90, 80, 100],
defaultStyle: { defaultStyle: {
font: 'PdfFont', font: 'PdfFont',
fontSize: 10 fontSize: 10
}, },
header: header, header: getHeader(),
footer: noFooter ? '' : footer, footerTpl: noFooter ? '' : getFooter(),
content: content, content: content,
styles: { styles: {
title: { title: {
@ -393,12 +362,12 @@ angular.module('OpenSlidesApp.core.pdf', [])
"u": ["text-decoration:underline"], "u": ["text-decoration:underline"],
"em": ["font-style:italic"], "em": ["font-style:italic"],
"i": ["font-style:italic"], "i": ["font-style:italic"],
"h1": ["font-size:30"], "h1": ["font-size:14", "font-weight:bold"],
"h2": ["font-size:28"], "h2": ["font-size:12", "font-weight:bold"],
"h3": ["font-size:26"], "h3": ["font-size:10", "font-weight:bold"],
"h4": ["font-size:24"], "h4": ["font-size:10", "font-style:italic"],
"h5": ["font-size:22"], "h5": ["font-size:10"],
"h6": ["font-size:20"], "h6": ["font-size:10"],
"a": ["color:blue", "text-decoration:underline"], "a": ["color:blue", "text-decoration:underline"],
"del": ["color:red", "text-decoration:line-through"], "del": ["color:red", "text-decoration:line-through"],
"ins": ["color:green", "text-decoration:underline"] "ins": ["color:green", "text-decoration:underline"]
@ -563,6 +532,8 @@ angular.module('OpenSlidesApp.core.pdf', [])
case "h5": case "h5":
case "h6": case "h6":
currentParagraph = create("text"); currentParagraph = create("text");
currentParagraph.marginBottom = 4;
currentParagraph.marginTop = 10;
/* falls through */ /* falls through */
case "a": case "a":
currentParagraph = parseChildren(alreadyConverted, element, currentParagraph, styles.concat(elementStyles[nodeName]), diff_mode); currentParagraph = parseChildren(alreadyConverted, element, currentParagraph, styles.concat(elementStyles[nodeName]), diff_mode);
@ -666,6 +637,7 @@ angular.module('OpenSlidesApp.core.pdf', [])
//in case of inline-line-numbers and the os-line-break class ignore the break //in case of inline-line-numbers and the os-line-break class ignore the break
if (!(lineNumberMode == "inline" && element.getAttribute("class") == "os-line-break")) { if (!(lineNumberMode == "inline" && element.getAttribute("class") == "os-line-break")) {
currentParagraph = create("text"); currentParagraph = create("text");
currentParagraph.lineHeight = 1.25;
alreadyConverted.push(currentParagraph); alreadyConverted.push(currentParagraph);
} }
break; break;
@ -680,7 +652,8 @@ angular.module('OpenSlidesApp.core.pdf', [])
break; break;
case "p": case "p":
currentParagraph = create("text"); currentParagraph = create("text");
currentParagraph.margin = [0,5]; currentParagraph.marginTop = 8;
currentParagraph.lineHeight = 1.25;
var stackP = create("stack"); var stackP = create("stack");
stackP.stack.push(currentParagraph); stackP.stack.push(currentParagraph);
ComputeStyle(stackP, styles); ComputeStyle(stackP, styles);

View File

@ -40,7 +40,7 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
metaTableBody.push([ metaTableBody.push([
{ {
text: gettextCatalog.getString('Submitters') + ':', text: gettextCatalog.getString('Submitters') + ':',
style: ['bold', 'grey'] style: ['bold', 'grey'],
}, },
{ {
text: submitters, text: submitters,
@ -79,8 +79,7 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
metaTableBody.push([ metaTableBody.push([
{ {
text: gettextCatalog.getString('Category') + ':', text: gettextCatalog.getString('Category') + ':',
style: ['bold', 'grey'] style: ['bold', 'grey'] },
},
{ {
text: motion.category.name, text: motion.category.name,
style: 'grey' style: 'grey'
@ -216,26 +215,17 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
} }
// build table // build table
// Used placeholder for 'layout' functions whiche are
// replaced by lineWitdh/lineColor function in pfd-worker.js.
// TODO: Remove placeholder and us static values for LineWidth and LineColor
// if pdfmake has fixed this.
var metaTableJsonString = { var metaTableJsonString = {
table: { table: {
widths: ['30%','70%'], widths: ['30%','70%'],
body: metaTableBody, body: metaTableBody,
}, },
margin: [0, 0, 0, 20], margin: [0, 0, 0, 20],
layout: { layout: '{{motion-placeholder-to-insert-functions-here}}'
hLineWidth: function(i, node) {
return (i === 0 || i === node.table.body.length) ? 0 : 0.5;
},
vLineWidth: function(i, node) {
return (i === 0 || i === node.table.widths.length) ? 0 : 0;
},
hLineColor: function(i, node) {
return (i === 0 || i === node.table.body.length) ? '' : 'white';
},
vLineColor: function(i, node) {
return (i === 0 || i === node.table.widths.length) ? '' : 'white';
}
}
}; };
return metaTableJsonString; return metaTableJsonString;
}; };

View File

@ -2,7 +2,7 @@ import bleach
allowed_tags = [ allowed_tags = [
'a', 'img', # links and images 'a', 'img', # links and images
'p', 'span', 'blockquote', # text layout 'br', 'p', 'span', 'blockquote', # text layout
'strike', 'strong', 'u', 'em', 'sup', 'sub', 'pre', # text formatting 'strike', 'strong', 'u', 'em', 'sup', 'sub', 'pre', # text formatting
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', # headings 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', # headings
'ol', 'ul', 'li', # lists 'ol', 'ul', 'li', # lists