diff --git a/client/angular.json b/client/angular.json index d0072dcac..da3f7e2d5 100644 --- a/client/angular.json +++ b/client/angular.json @@ -31,7 +31,8 @@ { "glob": "**/*", "input": "node_modules/tinymce/plugins", "output": "/tinymce/plugins/" } ], "styles": ["src/styles.scss"], - "scripts": ["node_modules/tinymce/tinymce.min.js"] + "scripts": ["node_modules/tinymce/tinymce.min.js"], + "webWorkerTsConfig": "tsconfig.worker.json" }, "configurations": { "production": { diff --git a/client/src/app/core/ui-services/poll-pdf-service.ts b/client/src/app/core/pdf-services/base-poll-pdf-service.ts similarity index 100% rename from client/src/app/core/ui-services/poll-pdf-service.ts rename to client/src/app/core/pdf-services/base-poll-pdf-service.ts diff --git a/client/src/app/core/ui-services/html-to-pdf.service.spec.ts b/client/src/app/core/pdf-services/html-to-pdf.service.spec.ts similarity index 100% rename from client/src/app/core/ui-services/html-to-pdf.service.spec.ts rename to client/src/app/core/pdf-services/html-to-pdf.service.spec.ts diff --git a/client/src/app/core/ui-services/html-to-pdf.service.ts b/client/src/app/core/pdf-services/html-to-pdf.service.ts similarity index 100% rename from client/src/app/core/ui-services/html-to-pdf.service.ts rename to client/src/app/core/pdf-services/html-to-pdf.service.ts diff --git a/client/src/app/core/ui-services/pdf-document.service.spec.ts b/client/src/app/core/pdf-services/pdf-document.service.spec.ts similarity index 86% rename from client/src/app/core/ui-services/pdf-document.service.spec.ts rename to client/src/app/core/pdf-services/pdf-document.service.spec.ts index a3843c91c..99e0b6749 100644 --- a/client/src/app/core/ui-services/pdf-document.service.spec.ts +++ b/client/src/app/core/pdf-services/pdf-document.service.spec.ts @@ -2,7 +2,7 @@ import { inject, TestBed } from '@angular/core/testing'; import { E2EImportsModule } from 'e2e-imports.module'; -import { PdfDocumentService } from '../ui-services/pdf-document.service'; +import { PdfDocumentService } from './pdf-document.service'; describe('PdfDocumentService', () => { beforeEach(() => { diff --git a/client/src/app/core/ui-services/pdf-document.service.ts b/client/src/app/core/pdf-services/pdf-document.service.ts similarity index 86% rename from client/src/app/core/ui-services/pdf-document.service.ts rename to client/src/app/core/pdf-services/pdf-document.service.ts index 4b7ffbbbc..2894e34e3 100644 --- a/client/src/app/core/ui-services/pdf-document.service.ts +++ b/client/src/app/core/pdf-services/pdf-document.service.ts @@ -1,13 +1,15 @@ import { HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; +import { MatSnackBar } from '@angular/material'; import { TranslateService } from '@ngx-translate/core'; import { saveAs } from 'file-saver'; -import pdfMake from 'pdfmake/build/pdfmake'; +import { ProgressSnackBarComponent } from 'app/shared/components/progress-snack-bar/progress-snack-bar.component'; import { ExportFormData } from 'app/site/motions/modules/motion-list/components/motion-export-dialog/motion-export-dialog.component'; -import { ConfigService } from './config.service'; +import { ConfigService } from '../ui-services/config.service'; import { HttpService } from '../core-services/http.service'; +import { ProgressService } from '../ui-services/progress.service'; /** * Enumeration to define possible values for the styling. @@ -51,7 +53,7 @@ export class PdfError extends Error { * @example * ```ts * const motionContent = this.motionPdfService.motionToDocDef(this.motion); - * this.this.pdfDocumentService.open(motionContent); + * this.pdfDocumentService.download(motionContent, 'test.pdf'); * ``` */ @Injectable({ @@ -64,25 +66,6 @@ export class PdfDocumentService { */ private imageUrls: string[] = []; - /** - * Table layout that switches the background color every other row. - * @example - * ```ts - * layout: this.pdfDocumentService.switchColorTableLayout - * ``` - */ - public switchColorTableLayout = { - hLineWidth: rowIndex => { - return rowIndex === 1; - }, - vLineWidth: () => { - return 0; - }, - fillColor: rowIndex => { - return rowIndex % 2 === 0 ? '#EEEEEE' : null; - } - }; - /** * Constructor * @@ -93,7 +76,9 @@ export class PdfDocumentService { public constructor( private translate: TranslateService, private configService: ConfigService, - private httpService: HttpService + private httpService: HttpService, + private matSnackBar: MatSnackBar, + private progressService: ProgressService ) {} /** @@ -183,13 +168,9 @@ export class PdfDocumentService { customMargins?: [number, number, number, number], landscape?: boolean ): Promise { - this.initFonts(); this.imageUrls = imageUrls ? imageUrls : []; - pdfMake.vfs = await this.initVfs(); const pageSize = this.configService.instant('general_export_pdf_pagesize'); const defaultMargins = pageSize === 'A5' ? [45, 30, 45, 45] : [75, 90, 75, 75]; - // needs to be done before, cause the footer is async - this.loadFooterImages(); const result = { pageSize: pageSize || 'A4', pageOrientation: landscape ? 'landscape' : 'portrait', @@ -199,21 +180,12 @@ export class PdfDocumentService { fontSize: this.configService.instant('general_export_pdf_fontsize') }, header: this.getHeader(customMargins ? [customMargins[0], customMargins[2]] : null), - - // TODO: option for no footer, wherever this can be defined - footer: (currentPage, pageCount) => { - return this.getFooter( - currentPage, - pageCount, - customMargins ? [customMargins[0], customMargins[2]] : null, - exportInfo - ); - }, + // real footer gets created in the worker + tmpfooter: this.getFooter(customMargins ? [customMargins[0], customMargins[2]] : null, exportInfo), info: metadata, content: documentContent, styles: this.getStandardPaperStyles() }; - await this.loadAllImages(); return result; } @@ -226,9 +198,7 @@ export class PdfDocumentService { * @returns the pdf document definition ready to export */ private async getBallotPaper(documentContent: object, imageUrl?: string): Promise { - this.initFonts(); this.imageUrls = imageUrl ? [imageUrl] : []; - pdfMake.vfs = await this.initVfs(); const result = { pageSize: 'A4', pageMargins: [0, 0, 0, 0], @@ -239,21 +209,18 @@ export class PdfDocumentService { content: documentContent, styles: this.getBlankPaperStyles() }; - await this.loadAllImages(); return result; } /** - * Define the fonts + * Get pdfFonts from storage */ - private initFonts(): void { - pdfMake.fonts = { - PdfFont: { - normal: this.getFontName('font_regular'), - bold: this.getFontName('font_bold'), - italics: this.getFontName('font_italic'), - bolditalics: this.getFontName('font_bold_italic') - } + private getPdfFonts(): object { + return { + normal: this.getFontName('font_regular'), + bold: this.getFontName('font_bold'), + italics: this.getFontName('font_italic'), + bolditalics: this.getFontName('font_bold_italic') }; } @@ -341,14 +308,9 @@ export class PdfDocumentService { * @param lrMargin optionally overriding the margins * @returns the footer doc definition */ - private getFooter( - currentPage: number, - pageCount: number, - lrMargin?: [number, number], - exportInfo?: ExportFormData - ): object { + private getFooter(lrMargin?: [number, number], exportInfo?: ExportFormData): object { const columns = []; - const showPage = exportInfo && exportInfo.pdfOptions ? exportInfo.pdfOptions.includes('page') : true; + const showPageNr = exportInfo && exportInfo.pdfOptions ? exportInfo.pdfOptions.includes('page') : true; const showDate = exportInfo && exportInfo.pdfOptions ? exportInfo.pdfOptions.includes('date') : false; let logoContainerWidth: string; let pageNumberPosition: string; @@ -357,11 +319,10 @@ export class PdfDocumentService { const logoFooterRightUrl = this.configService.instant('logo_pdf_footer_R').path; let footerPageNumber = ''; - if (showPage) { - footerPageNumber += `${currentPage} / ${pageCount}`; - if (showDate) { - footerPageNumber += '\n'; - } + if (showPageNr) { + // footerPageNumber += `${currentPage} / ${pageCount}`; + // replace with `${currentPage} / ${pageCount}` in worker + footerPageNumber += `%PAGENR%`; } let footerDate = {}; @@ -402,11 +363,12 @@ export class PdfDocumentService { width: logoContainerWidth, alignment: 'left' }); + this.imageUrls.push(logoFooterLeftUrl); } // add the page number columns.push({ - text: [footerPageNumber, footerDate], + stack: [footerPageNumber, footerDate], style: 'footerPageNumber', alignment: pageNumberPosition }); @@ -419,6 +381,7 @@ export class PdfDocumentService { width: logoContainerWidth, alignment: 'right' }); + this.imageUrls.push(logoFooterRightUrl); } const margin = [lrMargin ? lrMargin[0] : 75, 0, lrMargin ? lrMargin[0] : 75, 10]; @@ -454,6 +417,7 @@ export class PdfDocumentService { this.createPdf(doc, filename); }); } + /** * Downloads a pdf with the ballot papet page definitions. * @@ -471,12 +435,57 @@ export class PdfDocumentService { * Triggers the actual page creation and saving. * * @param doc the finished layout - * @param filename the filename (without extension) to save as + * @param filetitle the filename (without extension) to save as */ - private createPdf(doc: object, filename: string): void { - pdfMake.createPdf(doc).getBlob(blob => { - saveAs(blob, `${filename}.pdf`, { autoBOM: true }); + private async createPdf(doc: object, filetitle: string): Promise { + const filename = `${filetitle}.pdf`; + + // set the required progress info + this.progressService.progressInfo = { + mode: 'determinate', + text: filename + }; + + // open progress bar + this.matSnackBar.openFromComponent(ProgressSnackBarComponent, { + duration: 0 }); + const fonts = this.getPdfFonts(); + const vfs = await this.initVfs(); + await this.loadAllImages(vfs); + + if (typeof Worker !== 'undefined') { + const worker = new Worker('./pdf-worker.worker', { + type: 'module' + }); + + // the result of the worker + worker.onmessage = ({ data }) => { + // if the worker returns a numbers, is always the progress + if (typeof data === 'number') { + // update progress + const progress = Math.ceil(data * 100); + this.progressService.progressAmount = progress; + } + + // if the worker returns an object, it's always the document + if (typeof data === 'object') { + // close progress bar + this.matSnackBar.dismiss(); + saveAs(data, filename, { autoBOM: true }); + } + }; + + worker.postMessage({ + doc: JSON.parse(JSON.stringify(doc)), + fonts: fonts, + vfs: vfs + }); + } else { + this.matSnackBar.open(this.translate.instant('Web workers are not supported on your browser.'), '', { + duration: 0 + }); + } } /** @@ -612,30 +621,13 @@ export class PdfDocumentService { }; } - /** - * Adds the footer images to the imageUrls-list, cause the create footer function is async and - * potentially called after loadAllImages was called. - */ - private loadFooterImages(): void { - const logoFooterLeftUrl = this.configService.instant('logo_pdf_footer_L').path; - const logoFooterRightUrl = this.configService.instant('logo_pdf_footer_R').path; - - if (logoFooterLeftUrl) { - this.imageUrls.push(logoFooterLeftUrl); - } - - if (logoFooterRightUrl) { - this.imageUrls.push(logoFooterRightUrl); - } - } - /** * Triggers the addition of all images found during creation(including header and footer) * to the vfs. */ - private async loadAllImages(): Promise { + private async loadAllImages(vfs: object): Promise { const promises = this.imageUrls.map(image => { - return this.addImageToVfS(image); + return this.addImageToVfS(image, vfs); }); await Promise.all(promises); } @@ -645,14 +637,14 @@ export class PdfDocumentService { * * @param url */ - private async addImageToVfS(url: string): Promise { + private async addImageToVfS(url: string, vfs: object): Promise { if (url.indexOf('/') === 0) { url = url.substr(1); } - if (!pdfMake.vfs[url]) { + if (!vfs[url]) { const base64 = await this.convertUrlToBase64(url); - pdfMake.vfs[url] = base64; + vfs[url] = base64; } } diff --git a/client/src/app/core/pdf-services/pdf-worker.worker.ts b/client/src/app/core/pdf-services/pdf-worker.worker.ts new file mode 100644 index 000000000..f1377cd69 --- /dev/null +++ b/client/src/app/core/pdf-services/pdf-worker.worker.ts @@ -0,0 +1,114 @@ +/// + +import pdfMake from 'pdfmake/build/pdfmake'; + +const osTableLayout = { + switchColorTableLayout: { + hLineWidth: rowIndex => { + return rowIndex === 1; + }, + vLineWidth: () => { + return 0; + }, + fillColor: rowIndex => { + return rowIndex % 2 === 0 ? '#EEEEEE' : null; + } + }, + metaboxLayout: { + fillColor: () => { + return '#dddddd'; + }, + hLineWidth: (i, node) => { + return i === 0 || i === node.table.body.length ? 0 : 0.5; + }, + vLineWidth: () => { + return 0; + }, + hLineColor: () => { + return 'white'; + } + } +}; + +function applyLayout(content: any): void { + for (const section of content) { + if (Array.isArray(section)) { + applyLayout(section); + } else { + if (!!section.layout) { + let layout: object; + switch (section.layout) { + case 'switchColorTableLayout': { + layout = osTableLayout.switchColorTableLayout; + break; + } + case 'metaboxLayout': { + layout = osTableLayout.metaboxLayout; + break; + } + } + + if (!!layout) { + section.layout = layout; + } + } + } + } +} + +/** + * Sets the internal PdfMake fonts and VFS + */ +function initPdfMake(data: any): void { + pdfMake.fonts = { + PdfFont: data.fonts + }; + + pdfMake.vfs = data.vfs; +} + +/** + * Replace the palceholder with actual page numbers + * @param data + */ +function addPageNumbers(data: any): void { + // to allow page numbers in every page, after the initial "%PAGENR%" placeholder was reset + let countPageNumbers = false; + + data.doc.footer = (currentPage, pageCount) => { + const footer = data.doc.tmpfooter; + // "%PAGENR% needs to be found once. After that, the same position should always update page numbers" + if (footer.columns[0].stack[0] === '%PAGENR%' || countPageNumbers) { + countPageNumbers = true; + footer.columns[0].stack[0] = `${currentPage} / ${pageCount}`; + } + return footer; + }; +} + +/** + * The actual web worker code + */ +addEventListener('message', ({ data }) => { + initPdfMake(data); + + applyLayout(data.doc.content); + + if (!!data.doc.tmpfooter) { + addPageNumbers(data); + } + + const pdfGenerator = pdfMake.createPdf(data.doc); + + pdfGenerator.getBlob( + blob => { + // post the result back to the main thread + postMessage(blob); + }, + { + progressCallback: progress => { + postMessage(progress); + } + } + ); +}); diff --git a/client/src/app/core/ui-services/progress.service.spec.ts b/client/src/app/core/ui-services/progress.service.spec.ts new file mode 100644 index 000000000..624832a2f --- /dev/null +++ b/client/src/app/core/ui-services/progress.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { ProgressService } from './progress.service'; + +describe('ProgressService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: ProgressService = TestBed.get(ProgressService); + expect(service).toBeTruthy(); + }); +}); diff --git a/client/src/app/core/ui-services/progress.service.ts b/client/src/app/core/ui-services/progress.service.ts new file mode 100644 index 000000000..01dfa7dd7 --- /dev/null +++ b/client/src/app/core/ui-services/progress.service.ts @@ -0,0 +1,63 @@ +import { Injectable } from '@angular/core'; + +import { Subject } from 'rxjs'; + +/** + * Determine the progress mode + */ +export type ProgressMode = 'determinate' | 'indeterminate' | 'buffer' | 'query'; + +/** + * Shape of the progress info + */ +export interface ProgressInfo { + mode: ProgressMode; + text?: string; +} + +/** + * Helper service to announce some sort of progress, determinate or indeterminate. + */ +@Injectable({ + providedIn: 'root' +}) +export class ProgressService { + /** + * Subject to get progress information + */ + private _progressInfo: Subject = new Subject(); + + /** + * Subject to get the progress amount + */ + private _progressAmount: Subject = new Subject(); + + /** + * Get the progress information as observable + */ + public get info(): Subject { + return this._progressInfo; + } + + /** + * Get the progres amount as observable + */ + public get amount(): Subject { + return this._progressAmount; + } + + /** + * Set the progress info. Usually only required once for every part if new information + */ + public set progressInfo(newInfo: ProgressInfo) { + setTimeout(() => this._progressInfo.next(newInfo)); + } + + /** + * Set the new progress amount. Can be called whenever new info about the progress + * is available. Required only if the ProgressMode is set to 'determinate' + */ + public set progressAmount(newAmount: number) { + this._progressAmount.next(newAmount); + } +} diff --git a/client/src/app/shared/components/progress-snack-bar/progress-snack-bar.component.html b/client/src/app/shared/components/progress-snack-bar/progress-snack-bar.component.html new file mode 100644 index 000000000..2c0641bf2 --- /dev/null +++ b/client/src/app/shared/components/progress-snack-bar/progress-snack-bar.component.html @@ -0,0 +1,6 @@ +
+ {{ message | translate }} +
+
+ +
diff --git a/client/src/app/shared/components/progress-snack-bar/progress-snack-bar.component.scss b/client/src/app/shared/components/progress-snack-bar/progress-snack-bar.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/client/src/app/shared/components/progress-snack-bar/progress-snack-bar.component.spec.ts b/client/src/app/shared/components/progress-snack-bar/progress-snack-bar.component.spec.ts new file mode 100644 index 000000000..ac2e7132a --- /dev/null +++ b/client/src/app/shared/components/progress-snack-bar/progress-snack-bar.component.spec.ts @@ -0,0 +1,26 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { E2EImportsModule } from 'e2e-imports.module'; + +import { ProgressSnackBarComponent } from './progress-snack-bar.component'; + +describe('ProgressSnackBarComponent', () => { + let component: ProgressSnackBarComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [E2EImportsModule] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ProgressSnackBarComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/client/src/app/shared/components/progress-snack-bar/progress-snack-bar.component.ts b/client/src/app/shared/components/progress-snack-bar/progress-snack-bar.component.ts new file mode 100644 index 000000000..df37bb22d --- /dev/null +++ b/client/src/app/shared/components/progress-snack-bar/progress-snack-bar.component.ts @@ -0,0 +1,110 @@ +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + OnDestroy, + OnInit, + ViewEncapsulation +} from '@angular/core'; + +import { Subscription } from 'rxjs'; +import { distinctUntilChanged } from 'rxjs/operators'; + +import { ProgressMode, ProgressService } from 'app/core/ui-services/progress.service'; + +/** + * Component to show the progress announced in the progress service in a snack bar + * component + */ +@Component({ + selector: 'os-progress-snack-bar', + templateUrl: './progress-snack-bar.component.html', + styleUrls: ['./progress-snack-bar.component.scss'], + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ProgressSnackBarComponent implements OnInit, OnDestroy { + /** + * Private declaration of the mode + */ + private _mode: ProgressMode = 'indeterminate'; + + /** + * Private declaration of the progress message + */ + private _message = ''; + + /** + * Private declaration of the value + */ + private _value = 0; + + /** + * The sub for the info + */ + private infoSubscription: Subscription; + + /** + * The sub for the amount + */ + private valueSubscription: Subscription; + + /** + * Public getter of the progress bar mode + */ + public get mode(): ProgressMode { + return this._mode; + } + + /** + * Public getter of the progress bar message. Will be trasnslated in the UIs + */ + public get message(): string { + return this._message; + } + + /** + * Public getter for the progress value + */ + public get value(): number { + return this._value; + } + + /** + * Declare the progressService + */ + public constructor(private progressService: ProgressService, private cd: ChangeDetectorRef) {} + + /** + * Get the progress subject and subscribe to the info subject + */ + public ngOnInit(): void { + this.infoSubscription = this.progressService.info.subscribe(info => { + this._message = info.text; + this._mode = info.mode; + this.cd.detectChanges(); + }); + + this.valueSubscription = this.progressService.amount.pipe(distinctUntilChanged()).subscribe(value => { + if (value - this._value >= 5 || value === 100) { + this._value = value; + this.cd.detectChanges(); + } + }); + } + + /** + * clear the Subscriptions + */ + public ngOnDestroy(): void { + if (this.infoSubscription) { + this.infoSubscription.unsubscribe(); + this.infoSubscription = null; + } + + if (this.valueSubscription) { + this.valueSubscription.unsubscribe(); + this.valueSubscription = null; + } + } +} diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts index 1435f132f..144440517 100644 --- a/client/src/app/shared/shared.module.ts +++ b/client/src/app/shared/shared.module.ts @@ -96,6 +96,7 @@ import { AgendaContentObjectFormComponent } from './components/agenda-content-ob import { ExtensionFieldComponent } from './components/extension-field/extension-field.component'; import { AttachmentControlComponent } from './components/attachment-control/attachment-control.component'; import { RoundedInputComponent } from './components/rounded-input/rounded-input.component'; +import { ProgressSnackBarComponent } from './components/progress-snack-bar/progress-snack-bar.component'; /** * Share Module for all "dumb" components and pipes. @@ -274,7 +275,8 @@ import { RoundedInputComponent } from './components/rounded-input/rounded-input. AgendaContentObjectFormComponent, ExtensionFieldComponent, AttachmentControlComponent, - RoundedInputComponent + RoundedInputComponent, + ProgressSnackBarComponent ], providers: [ { provide: DateAdapter, useClass: OpenSlidesDateAdapter }, @@ -283,14 +285,16 @@ import { RoundedInputComponent } from './components/rounded-input/rounded-input. SortingTreeComponent, SortFilterBarComponent, SortBottomSheetComponent, - DecimalPipe + DecimalPipe, + ProgressSnackBarComponent ], entryComponents: [ SortBottomSheetComponent, C4DialogComponent, PromptDialogComponent, ChoiceDialogComponent, - ProjectionDialogComponent + ProjectionDialogComponent, + ProgressSnackBarComponent ] }) export class SharedModule {} diff --git a/client/src/app/site/agenda/components/agenda-list/agenda-list.component.ts b/client/src/app/site/agenda/components/agenda-list/agenda-list.component.ts index dd86f8fb1..09826f501 100644 --- a/client/src/app/site/agenda/components/agenda-list/agenda-list.component.ts +++ b/client/src/app/site/agenda/components/agenda-list/agenda-list.component.ts @@ -12,13 +12,13 @@ import { AgendaFilterListService } from '../../services/agenda-filter-list.servi import { AgendaPdfService } from '../../services/agenda-pdf.service'; import { OperatorService } from 'app/core/core-services/operator.service'; import { StorageService } from 'app/core/core-services/storage.service'; +import { PdfDocumentService } from 'app/core/pdf-services/pdf-document.service'; import { ItemRepositoryService } from 'app/core/repositories/agenda/item-repository.service'; import { ListOfSpeakersRepositoryService } from 'app/core/repositories/agenda/list-of-speakers-repository.service'; import { TopicRepositoryService } from 'app/core/repositories/topics/topic-repository.service'; import { _ } from 'app/core/translate/translation-marker'; import { ConfigService } from 'app/core/ui-services/config.service'; import { DurationService } from 'app/core/ui-services/duration.service'; -import { PdfDocumentService } from 'app/core/ui-services/pdf-document.service'; import { PromptService } from 'app/core/ui-services/prompt.service'; import { ViewportService } from 'app/core/ui-services/viewport.service'; import { ColumnRestriction } from 'app/shared/components/list-view-table/list-view-table.component'; diff --git a/client/src/app/site/assignments/services/assignment-pdf-export.service.ts b/client/src/app/site/assignments/services/assignment-pdf-export.service.ts index 914d98979..56c6285fe 100644 --- a/client/src/app/site/assignments/services/assignment-pdf-export.service.ts +++ b/client/src/app/site/assignments/services/assignment-pdf-export.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; -import { PdfDocumentService, PdfError } from 'app/core/ui-services/pdf-document.service'; +import { PdfDocumentService, PdfError } from 'app/core/pdf-services/pdf-document.service'; import { AssignmentPdfService } from './assignment-pdf.service'; import { ViewAssignment } from '../models/view-assignment'; diff --git a/client/src/app/site/assignments/services/assignment-pdf.service.ts b/client/src/app/site/assignments/services/assignment-pdf.service.ts index 26d30091c..473f0c7d2 100644 --- a/client/src/app/site/assignments/services/assignment-pdf.service.ts +++ b/client/src/app/site/assignments/services/assignment-pdf.service.ts @@ -2,8 +2,7 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; -import { HtmlToPdfService } from 'app/core/ui-services/html-to-pdf.service'; -import { PdfDocumentService } from 'app/core/ui-services/pdf-document.service'; +import { HtmlToPdfService } from 'app/core/pdf-services/html-to-pdf.service'; import { PollVoteValue } from 'app/core/ui-services/poll.service'; import { AssignmentPollService } from './assignment-poll.service'; import { ViewAssignment } from '../models/view-assignment'; @@ -34,7 +33,6 @@ export class AssignmentPdfService { public constructor( private translate: TranslateService, private pollService: AssignmentPollService, - private pdfDocumentService: PdfDocumentService, private htmlToPdfService: HtmlToPdfService ) {} @@ -265,7 +263,7 @@ export class AssignmentPdfService { headerRows: 1, body: pollTableBody }, - layout: this.pdfDocumentService.switchColorTableLayout + layout: 'switchColorTableLayout' }); } } diff --git a/client/src/app/site/assignments/services/assignment-poll-pdf.service.ts b/client/src/app/site/assignments/services/assignment-poll-pdf.service.ts index 962df2e0c..621aafa8f 100644 --- a/client/src/app/site/assignments/services/assignment-poll-pdf.service.ts +++ b/client/src/app/site/assignments/services/assignment-poll-pdf.service.ts @@ -2,11 +2,11 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; +import { AbstractPollData, BallotCountChoices, PollPdfService } from 'app/core/pdf-services/base-poll-pdf-service'; +import { PdfDocumentService } from 'app/core/pdf-services/pdf-document.service'; import { AssignmentRepositoryService } from 'app/core/repositories/assignments/assignment-repository.service'; import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service'; import { ConfigService } from 'app/core/ui-services/config.service'; -import { PdfDocumentService } from 'app/core/ui-services/pdf-document.service'; -import { AbstractPollData, BallotCountChoices, PollPdfService } from 'app/core/ui-services/poll-pdf-service'; import { AssignmentPollMethod } from './assignment-poll.service'; import { ViewAssignmentPoll } from '../models/view-assignment-poll'; diff --git a/client/src/app/site/motions/modules/motion-list/components/motion-list/motion-list.component.ts b/client/src/app/site/motions/modules/motion-list/components/motion-list/motion-list.component.ts index 9b6e76e73..29c0ff36a 100644 --- a/client/src/app/site/motions/modules/motion-list/components/motion-list/motion-list.component.ts +++ b/client/src/app/site/motions/modules/motion-list/components/motion-list/motion-list.component.ts @@ -8,13 +8,13 @@ import { TranslateService } from '@ngx-translate/core'; import { PblColumnDefinition } from '@pebula/ngrid'; import { StorageService } from 'app/core/core-services/storage.service'; +import { PdfError } from 'app/core/pdf-services/pdf-document.service'; import { CategoryRepositoryService } from 'app/core/repositories/motions/category-repository.service'; import { MotionBlockRepositoryService } from 'app/core/repositories/motions/motion-block-repository.service'; import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service'; import { WorkflowRepositoryService } from 'app/core/repositories/motions/workflow-repository.service'; import { TagRepositoryService } from 'app/core/repositories/tags/tag-repository.service'; import { ConfigService } from 'app/core/ui-services/config.service'; -import { PdfError } from 'app/core/ui-services/pdf-document.service'; import { ColumnRestriction } from 'app/shared/components/list-view-table/list-view-table.component'; import { infoDialogSettings, largeDialogSettings } from 'app/shared/utils/dialog-settings'; import { BaseListViewComponent } from 'app/site/base/base-list-view'; diff --git a/client/src/app/site/motions/services/motion-pdf-catalog.service.ts b/client/src/app/site/motions/services/motion-pdf-catalog.service.ts index 2982b6497..f55a8961a 100644 --- a/client/src/app/site/motions/services/motion-pdf-catalog.service.ts +++ b/client/src/app/site/motions/services/motion-pdf-catalog.service.ts @@ -3,10 +3,10 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { BehaviorSubject } from 'rxjs'; +import { BorderType, PdfDocumentService, PdfError, StyleType } from 'app/core/pdf-services/pdf-document.service'; import { CategoryRepositoryService } from 'app/core/repositories/motions/category-repository.service'; import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service'; import { ConfigService } from 'app/core/ui-services/config.service'; -import { BorderType, PdfDocumentService, PdfError, StyleType } from 'app/core/ui-services/pdf-document.service'; import { ExportFormData } from '../modules/motion-list/components/motion-export-dialog/motion-export-dialog.component'; import { MotionPdfService } from './motion-pdf.service'; import { ViewCategory } from '../models/view-category'; diff --git a/client/src/app/site/motions/services/motion-pdf-export.service.ts b/client/src/app/site/motions/services/motion-pdf-export.service.ts index 835cf803e..9b25a00bb 100644 --- a/client/src/app/site/motions/services/motion-pdf-export.service.ts +++ b/client/src/app/site/motions/services/motion-pdf-export.service.ts @@ -2,8 +2,8 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; +import { PdfDocumentService } from 'app/core/pdf-services/pdf-document.service'; import { ConfigService } from 'app/core/ui-services/config.service'; -import { PdfDocumentService } from 'app/core/ui-services/pdf-document.service'; import { PersonalNoteContent } from 'app/shared/models/users/personal-note'; import { ExportFormData } from '../modules/motion-list/components/motion-export-dialog/motion-export-dialog.component'; import { MotionPdfCatalogService } from './motion-pdf-catalog.service'; diff --git a/client/src/app/site/motions/services/motion-pdf.service.ts b/client/src/app/site/motions/services/motion-pdf.service.ts index 2f6804fe9..e5747a99c 100644 --- a/client/src/app/site/motions/services/motion-pdf.service.ts +++ b/client/src/app/site/motions/services/motion-pdf.service.ts @@ -2,14 +2,14 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; +import { HtmlToPdfService } from 'app/core/pdf-services/html-to-pdf.service'; +import { PdfDocumentService } from 'app/core/pdf-services/pdf-document.service'; import { ChangeRecommendationRepositoryService } from 'app/core/repositories/motions/change-recommendation-repository.service'; import { MotionCommentSectionRepositoryService } from 'app/core/repositories/motions/motion-comment-section-repository.service'; import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service'; import { StatuteParagraphRepositoryService } from 'app/core/repositories/motions/statute-paragraph-repository.service'; import { ConfigService } from 'app/core/ui-services/config.service'; -import { HtmlToPdfService } from 'app/core/ui-services/html-to-pdf.service'; import { LinenumberingService } from 'app/core/ui-services/linenumbering.service'; -import { PdfDocumentService } from 'app/core/ui-services/pdf-document.service'; import { CalculablePollKey } from 'app/core/ui-services/poll.service'; import { ViewUnifiedChange, ViewUnifiedChangeType } from 'app/shared/models/motions/view-unified-change'; import { getRecommendationTypeName } from 'app/shared/utils/recommendation-type-names'; @@ -547,21 +547,7 @@ export class MotionPdfService { body: metaTableBody }, margin: [0, 0, 0, 20], - // That did not work too well in the past. Perhaps substitution by a pdfWorker the worker will be necessary - layout: { - fillColor: () => { - return '#dddddd'; - }, - hLineWidth: (i, node) => { - return i === 0 || i === node.table.body.length ? 0 : 0.5; - }, - vLineWidth: () => { - return 0; - }, - hLineColor: () => { - return 'white'; - } - } + layout: 'metaboxLayout' }; } } @@ -776,7 +762,7 @@ export class MotionPdfService { dontBreakRows: true, body: callListTableBody.concat(callListRows) }, - layout: this.pdfDocumentService.switchColorTableLayout + layout: 'switchColorTableLayout' }; return [title, table]; } diff --git a/client/src/app/site/motions/services/motion-poll-pdf.service.ts b/client/src/app/site/motions/services/motion-poll-pdf.service.ts index 5f7bcfa48..a67998eda 100644 --- a/client/src/app/site/motions/services/motion-poll-pdf.service.ts +++ b/client/src/app/site/motions/services/motion-poll-pdf.service.ts @@ -2,11 +2,11 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; +import { AbstractPollData, PollPdfService } from 'app/core/pdf-services/base-poll-pdf-service'; +import { PdfDocumentService } from 'app/core/pdf-services/pdf-document.service'; import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service'; import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service'; import { ConfigService } from 'app/core/ui-services/config.service'; -import { PdfDocumentService } from 'app/core/ui-services/pdf-document.service'; -import { AbstractPollData, PollPdfService } from 'app/core/ui-services/poll-pdf-service'; import { MotionPoll } from 'app/shared/models/motions/motion-poll'; type BallotCountChoices = 'NUMBER_OF_DELEGATES' | 'NUMBER_OF_ALL_PARTICIPANTS' | 'CUSTOM_NUMBER'; diff --git a/client/src/app/site/users/services/user-pdf-export.service.ts b/client/src/app/site/users/services/user-pdf-export.service.ts index beebbecad..a2941c966 100644 --- a/client/src/app/site/users/services/user-pdf-export.service.ts +++ b/client/src/app/site/users/services/user-pdf-export.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; -import { PdfDocumentService } from 'app/core/ui-services/pdf-document.service'; +import { PdfDocumentService } from 'app/core/pdf-services/pdf-document.service'; import { UserPdfService } from './user-pdf.service'; import { ViewUser } from '../models/view-user'; diff --git a/client/src/app/site/users/services/user-pdf.service.ts b/client/src/app/site/users/services/user-pdf.service.ts index e93130c83..ebf11cd50 100644 --- a/client/src/app/site/users/services/user-pdf.service.ts +++ b/client/src/app/site/users/services/user-pdf.service.ts @@ -3,7 +3,6 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { ConfigService } from 'app/core/ui-services/config.service'; -import { PdfDocumentService } from 'app/core/ui-services/pdf-document.service'; import { ViewUser } from '../models/view-user'; /** @@ -25,13 +24,8 @@ export class UserPdfService { * * @param translate handle translations * @param configService Read config variables - * @param pdfDocumentService Global PDF Functions */ - public constructor( - private translate: TranslateService, - private configService: ConfigService, - private pdfDocumentService: PdfDocumentService - ) {} + public constructor(private translate: TranslateService, private configService: ConfigService) {} /** * Converts a user to PdfMake doc definition, containing access information @@ -254,7 +248,7 @@ export class UserPdfService { headerRows: 1, body: userTableBody.concat(this.getListUsers(users)) }, - layout: this.pdfDocumentService.switchColorTableLayout + layout: 'switchColorTableLayout' }; } diff --git a/client/tsconfig.app.json b/client/tsconfig.app.json index d3351bee9..82447ca06 100644 --- a/client/tsconfig.app.json +++ b/client/tsconfig.app.json @@ -8,5 +8,5 @@ "enableIvy": false }, "include": ["src/**/*.ts"], - "exclude": ["src/test.ts", "**/*.spec.ts"] + "exclude": ["src/test.ts", "**/*.spec.ts", "src/**/*.worker.ts"] } diff --git a/client/tsconfig.worker.json b/client/tsconfig.worker.json new file mode 100644 index 000000000..1c8cc55ed --- /dev/null +++ b/client/tsconfig.worker.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/worker", + "lib": [ + "es2018", + "webworker" + ], + "types": [] + }, + "include": [ + "src/**/*.worker.ts" + ] +}