Implementation of exporting submitters and recommendation

The user can choose the option to export the informtion about submitters and the recommendation including the extension of motions to the 'table of contents'.
This commit is contained in:
GabrielMeyer 2019-06-04 14:41:12 +02:00 committed by Emanuel Schütze
parent 35c8dc97f5
commit 26cc6556a0
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",
)