2019-01-24 14:40:05 +01:00
|
|
|
import { Injectable } from '@angular/core';
|
2019-06-28 13:39:16 +02:00
|
|
|
import { BehaviorSubject } from 'rxjs';
|
2019-01-24 14:40:05 +01:00
|
|
|
|
|
|
|
import { TranslateService } from '@ngx-translate/core';
|
|
|
|
|
2019-06-28 13:39:16 +02:00
|
|
|
import { CategoryRepositoryService } from 'app/core/repositories/motions/category-repository.service';
|
2019-01-31 13:40:27 +01:00
|
|
|
import { ConfigService } from 'app/core/ui-services/config.service';
|
2019-06-28 13:39:16 +02:00
|
|
|
import { MotionPdfService, InfoToExport } from './motion-pdf.service';
|
2019-06-04 14:41:12 +02:00
|
|
|
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
2019-06-28 13:39:16 +02:00
|
|
|
import { PdfError, PdfDocumentService, StyleType, BorderType } from 'app/core/ui-services/pdf-document.service';
|
|
|
|
import { ViewCategory } from '../models/view-category';
|
|
|
|
import { ViewMotion, LineNumberingMode, ChangeRecoMode } from '../models/view-motion';
|
2019-01-24 14:40:05 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Service to export a list of motions.
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
* ```ts
|
|
|
|
* const docDef = this.motionPdfCatalogService.motionListToDocDef(myListOfViewMotions);
|
|
|
|
* ```
|
|
|
|
*/
|
|
|
|
@Injectable({
|
|
|
|
providedIn: 'root'
|
|
|
|
})
|
|
|
|
export class MotionPdfCatalogService {
|
2019-06-28 13:39:16 +02:00
|
|
|
private categoryObserver: BehaviorSubject<ViewCategory[]>;
|
|
|
|
|
2019-01-24 14:40:05 +01:00
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
|
|
|
* @param translate handle translations
|
|
|
|
* @param configService read out config variables
|
|
|
|
* @param motionPdfService handle motion to pdf conversion
|
|
|
|
*/
|
|
|
|
public constructor(
|
|
|
|
private translate: TranslateService,
|
|
|
|
private configService: ConfigService,
|
2019-05-13 18:19:29 +02:00
|
|
|
private motionPdfService: MotionPdfService,
|
2019-06-04 14:41:12 +02:00
|
|
|
private pdfService: PdfDocumentService,
|
2019-06-28 13:39:16 +02:00
|
|
|
private motionRepo: MotionRepositoryService,
|
|
|
|
private categoryRepo: CategoryRepositoryService
|
|
|
|
) {
|
|
|
|
this.categoryObserver = this.categoryRepo.getViewModelListBehaviorSubject();
|
|
|
|
}
|
2019-01-24 14:40:05 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Converts the list of motions to pdfmake doc definition.
|
|
|
|
* Public entry point to conversion of multiple motions
|
|
|
|
*
|
|
|
|
* @param motions the list of view motions to convert
|
2019-02-11 17:11:35 +01:00
|
|
|
* @param lnMode
|
|
|
|
* @param crMode
|
|
|
|
* @param contentToExport
|
|
|
|
* @param infoToExport
|
|
|
|
* @param commentsToExport
|
2019-01-24 14:40:05 +01:00
|
|
|
* @returns pdfmake doc definition as object
|
|
|
|
*/
|
2019-01-25 17:03:05 +01:00
|
|
|
public motionListToDocDef(
|
|
|
|
motions: ViewMotion[],
|
|
|
|
lnMode?: LineNumberingMode,
|
|
|
|
crMode?: ChangeRecoMode,
|
|
|
|
contentToExport?: string[],
|
2019-02-11 17:11:35 +01:00
|
|
|
infoToExport?: InfoToExport[],
|
|
|
|
commentsToExport?: number[]
|
2019-01-25 17:03:05 +01:00
|
|
|
): object {
|
2019-01-24 14:40:05 +01:00
|
|
|
let doc = [];
|
|
|
|
const motionDocList = [];
|
|
|
|
|
|
|
|
for (let motionIndex = 0; motionIndex < motions.length; ++motionIndex) {
|
2019-04-26 15:34:27 +02:00
|
|
|
try {
|
|
|
|
const motionDocDef: any = this.motionPdfService.motionToDocDef(
|
|
|
|
motions[motionIndex],
|
|
|
|
lnMode,
|
|
|
|
crMode,
|
|
|
|
contentToExport,
|
|
|
|
infoToExport,
|
|
|
|
commentsToExport
|
|
|
|
);
|
2019-01-24 14:40:05 +01:00
|
|
|
|
2019-04-26 15:34:27 +02:00
|
|
|
// add id field to the first page of a motion to make it findable over TOC
|
|
|
|
motionDocDef[0].id = `${motions[motionIndex].id}`;
|
2019-01-24 14:40:05 +01:00
|
|
|
|
2019-04-26 15:34:27 +02:00
|
|
|
motionDocList.push(motionDocDef);
|
2019-01-24 14:40:05 +01:00
|
|
|
|
2019-04-26 15:34:27 +02:00
|
|
|
if (motionIndex < motions.length - 1) {
|
2019-05-13 18:19:29 +02:00
|
|
|
motionDocList.push(this.pdfService.getPageBreak());
|
2019-04-26 15:34:27 +02:00
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
const errorText = `${this.translate.instant('Error during PDF creation of motion:')} ${
|
|
|
|
motions[motionIndex].identifierOrTitle
|
|
|
|
}`;
|
|
|
|
console.error(`${errorText}\nDebugInfo:\n`, err);
|
|
|
|
throw new PdfError(errorText);
|
2019-01-24 14:40:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// print extra data (title, preamble, categories, toc) only if there are more than 1 motion
|
|
|
|
if (motions.length > 1) {
|
2019-05-13 18:19:29 +02:00
|
|
|
doc.push(
|
|
|
|
this.pdfService.createTitle('motions_export_title'),
|
|
|
|
this.pdfService.createPreamble('motions_export_preamble'),
|
|
|
|
this.createToc(motions)
|
|
|
|
);
|
2019-01-24 14:40:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
doc = doc.concat(motionDocList);
|
|
|
|
|
|
|
|
return doc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates the table of contents for the motion book.
|
|
|
|
* Considers sorting by categories and no sorting.
|
|
|
|
*
|
|
|
|
* @param motions The motions to add in the TOC
|
|
|
|
* @param sorting The optional sorting strategy
|
|
|
|
* @returns the table of contents as document definition
|
|
|
|
*/
|
|
|
|
private createToc(motions: ViewMotion[], sorting?: string): object {
|
|
|
|
const toc = [];
|
2019-06-28 13:39:16 +02:00
|
|
|
const categories = this.categoryObserver.value;
|
2019-01-24 14:40:05 +01:00
|
|
|
|
|
|
|
// Create the toc title
|
|
|
|
const tocTitle = {
|
|
|
|
text: this.translate.instant('Table of contents'),
|
|
|
|
style: 'heading2'
|
|
|
|
};
|
2019-06-04 14:41:12 +02:00
|
|
|
const exportSubmitterRecommendation = this.configService.instant<boolean>(
|
|
|
|
'motions_export_submitter_recommendation'
|
|
|
|
);
|
2019-01-24 14:40:05 +01:00
|
|
|
|
2019-06-04 14:41:12 +02:00
|
|
|
// Initialize the header and the layout for border-style.
|
|
|
|
const header = exportSubmitterRecommendation ? this.getTocHeaderDefinition() : undefined;
|
|
|
|
const layout = exportSubmitterRecommendation ? BorderType.LIGHT_HORIZONTAL_LINES : BorderType.DEFAULT;
|
2019-01-24 14:40:05 +01:00
|
|
|
|
2019-06-04 14:41:12 +02:00
|
|
|
if (categories && categories.length) {
|
2019-01-24 14:40:05 +01:00
|
|
|
const catTocBody = [];
|
2019-06-17 13:55:42 +02:00
|
|
|
for (const category of categories.sort((a, b) => a.weight - b.weight)) {
|
2019-01-24 14:40:05 +01:00
|
|
|
catTocBody.push({
|
|
|
|
table: {
|
|
|
|
body: [
|
|
|
|
[
|
|
|
|
{
|
2019-06-28 13:39:16 +02:00
|
|
|
text: category.getTitle(),
|
|
|
|
style: !!category.parent ? 'tocSubcategoryTitle' : 'tocCategoryTitle'
|
2019-01-24 14:40:05 +01:00
|
|
|
}
|
|
|
|
]
|
|
|
|
]
|
|
|
|
},
|
2019-06-04 14:41:12 +02:00
|
|
|
layout: exportSubmitterRecommendation ? 'lightHorizontalLines' : 'noBorders'
|
2019-01-24 14:40:05 +01:00
|
|
|
});
|
|
|
|
|
2019-06-28 13:39:16 +02:00
|
|
|
// find out if the category has any motions
|
|
|
|
const motionToCurrentCat = motions.filter(motionIn => category === motionIn.category);
|
|
|
|
|
|
|
|
if (motionToCurrentCat && motionToCurrentCat.length) {
|
|
|
|
const tocBody = [];
|
|
|
|
|
|
|
|
for (const motion of motionToCurrentCat) {
|
|
|
|
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
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
2019-06-04 14:41:12 +02:00
|
|
|
}
|
2019-05-13 18:19:29 +02:00
|
|
|
|
2019-06-28 13:39:16 +02:00
|
|
|
catTocBody.push(
|
|
|
|
this.pdfService.createTocTableDef(tocBody, StyleType.CATEGORY_SECTION, layout, header)
|
|
|
|
);
|
|
|
|
}
|
2019-01-24 14:40:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// handle those without category
|
|
|
|
const uncatTocBody = motions
|
|
|
|
.filter(motion => !motion.category)
|
2019-06-04 14:41:12 +02:00
|
|
|
.map(motion =>
|
|
|
|
this.pdfService.createTocLine(
|
|
|
|
`${motion.identifier ? motion.identifier : ''}`,
|
|
|
|
motion.title,
|
|
|
|
`${motion.id}`
|
|
|
|
)
|
|
|
|
);
|
2019-01-24 14:40:05 +01:00
|
|
|
|
|
|
|
// only push this array if there is at least one entry
|
|
|
|
if (uncatTocBody.length > 0) {
|
2019-05-13 18:19:29 +02:00
|
|
|
catTocBody.push(this.pdfService.createTocTableDef(uncatTocBody, StyleType.CATEGORY_SECTION));
|
2019-01-24 14:40:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
toc.push(catTocBody);
|
|
|
|
} else {
|
|
|
|
// all motions in the same table
|
2019-06-04 14:41:12 +02:00
|
|
|
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));
|
2019-01-24 14:40:05 +01:00
|
|
|
}
|
|
|
|
|
2019-05-13 18:19:29 +02:00
|
|
|
return [tocTitle, toc, this.pdfService.getPageBreak()];
|
2019-01-24 14:40:05 +01:00
|
|
|
}
|
|
|
|
|
2019-06-04 14:41:12 +02:00
|
|
|
/**
|
|
|
|
* 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' }
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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)
|
|
|
|
);
|
|
|
|
}
|
2019-01-24 14:40:05 +01:00
|
|
|
}
|