Merge pull request #4766 from GabrielInTheWorld/pdf-make-enhancement

Implementation of exporting submitters and recommendation
This commit is contained in:
Emanuel Schütze 2019-06-14 14:17:13 +02:00 committed by GitHub
commit e2e5fe07d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 174 additions and 44 deletions

View File

@ -151,9 +151,11 @@ _('Number of all delegates');
_('Number of all participants');
_('Use the following custom number');
_('Custom number of ballot papers');
// subgroup export
_('Title for PDF and DOCX documents (all motions)');
_('Preamble text for PDF and DOCX documents (all motions)');
// subgroup PDF export
_('PDF export');
_('Title for PDF documents of motions');
_('Preamble text for PDF documents of motions');
_('Show submitters and recommendation in table of contents');
_('Sort categories by');
_('Sort motions by');
_('Include the sequential number in PDF and DOCX');

View File

@ -13,9 +13,20 @@ import { HttpService } from '../core-services/http.service';
*/
export enum StyleType {
DEFAULT = 'tocEntry',
SUBTITLE = 'subtitle',
SUB_ENTRY = 'tocSubEntry',
CATEGORY_SECTION = 'tocCategorySection'
}
/**
* Enumeration to describe the type of borders.
*/
export enum BorderType {
DEFAULT = 'noBorders',
LIGHT_HORIZONTAL_LINES = 'lightHorizontalLines',
HEADER_ONLY = 'headerLineOnly'
}
/**
* Custom PDF error class to handle errors in a safer way
*/
@ -445,9 +456,10 @@ export class PdfDocumentService {
* @returns an object that contains all pdf styles
*/
private getStandardPaperStyles(): object {
const pageSize = this.configService.instant('general_export_pdf_pagesize');
return {
title: {
fontSize: 18,
fontSize: pageSize === 'A5' ? 14 : 16,
margin: [0, 0, 0, 20],
bold: true
},
@ -475,12 +487,12 @@ export class PdfDocumentService {
fontSize: 8
},
heading2: {
fontSize: 14,
fontSize: pageSize === 'A5' ? 12 : 14,
margin: [0, 0, 0, 10],
bold: true
},
heading3: {
fontSize: 12,
fontSize: pageSize === 'A5' ? 10 : 12,
margin: [0, 10, 0, 0],
bold: true
},
@ -498,17 +510,25 @@ export class PdfDocumentService {
margin: [15, 5]
},
tocEntry: {
fontSize: 12,
fontSize: pageSize === 'A5' ? 10 : 11,
margin: [0, 0, 0, 0],
bold: false
},
tocHeaderRow: {
fontSize: 8,
italics: true
},
tocSubEntry: {
fontSize: pageSize === 'A5' ? 9 : 10,
color: '#404040'
},
tocCategoryEntry: {
fontSize: 12,
fontSize: pageSize === 'A5' ? 10 : 11,
margin: [10, 0, 0, 0],
bold: false
},
tocCategoryTitle: {
fontSize: 12,
fontSize: pageSize === 'A5' ? 10 : 11,
margin: [0, 0, 0, 4],
bold: true
},
@ -610,6 +630,7 @@ export class PdfDocumentService {
*/
public createTitle(configVariable: string): object {
const titleText = this.translate.instant(this.configService.instant<string>(configVariable));
return {
text: titleText,
style: 'title'
@ -647,13 +668,21 @@ export class PdfDocumentService {
* @param tocBody the body of the table
* @returns The table of contents as doc definition
*/
public createTocTableDef(tocBody: object, style: StyleType = StyleType.DEFAULT): object {
public createTocTableDef(
tocBody: object[],
style: StyleType = StyleType.DEFAULT,
borderStyle: BorderType = BorderType.DEFAULT,
...header: object[]
): object {
return {
table: {
headerRows: header[0] ? header.length : 0,
keepWithHeaderRows: header[0] ? header.length : 0,
dontBreakRows: true,
widths: ['auto', '*', 'auto'],
body: tocBody
body: header[0] ? [...header, ...tocBody] : tocBody
},
layout: 'noBorders',
layout: borderStyle,
style: style
};
}
@ -672,15 +701,16 @@ export class PdfDocumentService {
identifier: string,
title: string,
pageReference: string,
style: StyleType = StyleType.DEFAULT
): Object {
style: StyleType = StyleType.DEFAULT,
...subTitle: object[]
): Array<Object> {
return [
{
text: identifier,
style: style
},
{
text: title,
text: [title, ...subTitle],
style: 'tocEntry'
},
{
@ -690,4 +720,19 @@ export class PdfDocumentService {
}
];
}
/**
* Function to create an inline line in the toc.
*
* @param text The text for the line.
* @param bold Optional boolean, if the text should be bold - defaults to `false`.
*
* @returns {Object} An object for `DocDefinition` for `pdf-make`.
*/
public createTocLineInline(text: string): Object {
return {
text: '\n' + text,
style: StyleType.SUB_ENTRY
};
}
}

View File

@ -6,7 +6,8 @@ import { ViewMotion, LineNumberingMode, ChangeRecoMode } from '../models/view-mo
import { MotionPdfService, InfoToExport } from './motion-pdf.service';
import { ConfigService } from 'app/core/ui-services/config.service';
import { ViewCategory } from '../models/view-category';
import { PdfError, PdfDocumentService, StyleType } from 'app/core/ui-services/pdf-document.service';
import { PdfError, PdfDocumentService, StyleType, BorderType } from 'app/core/ui-services/pdf-document.service';
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
/**
* Service to export a list of motions.
@ -31,7 +32,8 @@ export class MotionPdfCatalogService {
private translate: TranslateService,
private configService: ConfigService,
private motionPdfService: MotionPdfService,
private pdfService: PdfDocumentService
private pdfService: PdfDocumentService,
private motionRepo: MotionRepositoryService
) {}
/**
@ -116,13 +118,15 @@ export class MotionPdfCatalogService {
text: this.translate.instant('Table of contents'),
style: 'heading2'
};
const exportSubmitterRecommendation = this.configService.instant<boolean>(
'motions_export_submitter_recommendation'
);
if (!sorting) {
sorting = this.configService.instant<string>('motions_export_category_sorting');
}
const exportCategory = sorting === 'identifier' || sorting === 'prefix';
// Initialize the header and the layout for border-style.
const header = exportSubmitterRecommendation ? this.getTocHeaderDefinition() : undefined;
const layout = exportSubmitterRecommendation ? BorderType.LIGHT_HORIZONTAL_LINES : BorderType.DEFAULT;
if (exportCategory && categories) {
if (categories && categories.length) {
const catTocBody = [];
for (const category of categories) {
// push the name of the category
@ -138,27 +142,38 @@ export class MotionPdfCatalogService {
]
]
},
layout: 'noBorders'
layout: exportSubmitterRecommendation ? 'lightHorizontalLines' : 'noBorders'
});
const tocBody = motions
.filter(motion => category === motion.category)
.map(motion =>
this.pdfService.createTocLine(
`${motion.identifier}`,
motion.title,
`${motion.id}`,
StyleType.CATEGORY_SECTION
)
);
const tocBody = [];
for (const motion of motions.filter(motionIn => category === motionIn.category)) {
if (exportSubmitterRecommendation) {
tocBody.push(this.appendSubmittersAndRecommendation(motion, StyleType.CATEGORY_SECTION));
} else {
tocBody.push(
this.pdfService.createTocLine(
`${motion.identifier ? motion.identifier : ''}`,
motion.title,
`${motion.id}`,
StyleType.CATEGORY_SECTION
)
);
}
}
catTocBody.push(this.pdfService.createTocTableDef(tocBody, StyleType.CATEGORY_SECTION));
catTocBody.push(this.pdfService.createTocTableDef(tocBody, StyleType.CATEGORY_SECTION, layout, header));
}
// handle those without category
const uncatTocBody = motions
.filter(motion => !motion.category)
.map(motion => this.pdfService.createTocLine(`${motion.identifier}`, motion.title, `${motion.id}`));
.map(motion =>
this.pdfService.createTocLine(
`${motion.identifier ? motion.identifier : ''}`,
motion.title,
`${motion.id}`
)
);
// only push this array if there is at least one entry
if (uncatTocBody.length > 0) {
@ -168,15 +183,46 @@ export class MotionPdfCatalogService {
toc.push(catTocBody);
} else {
// all motions in the same table
const tocBody = motions.map(motion =>
this.pdfService.createTocLine(`${motion.identifier}`, motion.title, `${motion.id}`)
);
toc.push(this.pdfService.createTocTableDef(tocBody, StyleType.CATEGORY_SECTION));
const tocBody = [];
for (const motion of motions) {
if (exportSubmitterRecommendation) {
tocBody.push(this.appendSubmittersAndRecommendation(motion));
} else {
tocBody.push(
this.pdfService.createTocLine(
`${motion.identifier ? motion.identifier : ''}`,
motion.title,
`${motion.id}`
)
);
}
}
toc.push(this.pdfService.createTocTableDef(tocBody, StyleType.CATEGORY_SECTION, layout, header));
}
return [tocTitle, toc, this.pdfService.getPageBreak()];
}
/**
* Function to get the definition for the header
* for exporting motion-list as PDF. Needed, if submitters
* and recommendation should also be exported to the `Table of Contents`.
*
* @returns {object} The DocDefinition for `pdfmake.js`.
*/
private getTocHeaderDefinition(): object {
return [
{ text: this.translate.instant('Identifier'), style: 'tocHeaderRow' },
{
text: `${this.translate.instant('Title')} · ${this.translate.instant(
'Submitters'
)} · ${this.translate.instant('Recommendation')}`,
style: 'tocHeaderRow'
},
{ text: this.translate.instant('Page'), style: 'tocHeaderRow', alignment: 'right' }
];
}
/**
* Extract the used categories from the given motion list.
*
@ -198,4 +244,31 @@ export class MotionPdfCatalogService {
return categories;
}
/**
* Creates lines for the `Table of contents` containing submitters and recommendation.
*
* @param motion The motion containing the information
* @param style Optional `StyleType`. Defaults to `tocEntry`.
*
* @returns {Array<Object>} An array containing the `DocDefinitions` for `pdf-make`.
*/
private appendSubmittersAndRecommendation(motion: ViewMotion, style: StyleType = StyleType.DEFAULT): Array<Object> {
const recommendation = this.motionRepo.getExtendedRecommendationLabel(motion);
let submitterList = '';
for (let i = 0; i < motion.submitters.length; ++i) {
submitterList +=
i !== motion.submitters.length - 1
? motion.submitters[i].getTitle() + ', '
: motion.submitters[i].getTitle();
}
return this.pdfService.createTocLine(
`${motion.identifier ? motion.identifier : ''}`,
motion.title,
`${motion.id}`,
style,
this.pdfService.createTocLineInline(submitterList),
this.pdfService.createTocLineInline(recommendation)
);
}
}

View File

@ -344,22 +344,32 @@ def get_config_variables():
validators=(MinValueValidator(1),),
)
# PDF and DOCX export
# PDF export
yield ConfigVariable(
name="motions_export_title",
default_value="Motions",
label="Title for PDF and DOCX documents (all motions)",
label="Title for PDF document of motions",
weight=370,
group="Motions",
subgroup="Export",
subgroup="PDF export",
)
yield ConfigVariable(
name="motions_export_preamble",
default_value="",
label="Preamble text for PDF and DOCX documents (all motions)",
label="Preamble text for PDF documents of motions",
weight=375,
group="Motions",
subgroup="Export",
subgroup="PDF export",
)
yield ConfigVariable(
name="motions_export_submitter_recommendation",
default_value=False,
label="Show submitters and recommendation in table of contents",
input_type="boolean",
weight=378,
group="Motions",
subgroup="PDF export",
)