Add pdf webworker and progress bar
Generate PDF in the background using webworker Shows a progress bar to estimate the PDF generation progress
This commit is contained in:
parent
2f7937a27d
commit
6123216afc
@ -31,7 +31,8 @@
|
|||||||
{ "glob": "**/*", "input": "node_modules/tinymce/plugins", "output": "/tinymce/plugins/" }
|
{ "glob": "**/*", "input": "node_modules/tinymce/plugins", "output": "/tinymce/plugins/" }
|
||||||
],
|
],
|
||||||
"styles": ["src/styles.scss"],
|
"styles": ["src/styles.scss"],
|
||||||
"scripts": ["node_modules/tinymce/tinymce.min.js"]
|
"scripts": ["node_modules/tinymce/tinymce.min.js"],
|
||||||
|
"webWorkerTsConfig": "tsconfig.worker.json"
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"production": {
|
"production": {
|
||||||
|
@ -2,7 +2,7 @@ import { inject, TestBed } from '@angular/core/testing';
|
|||||||
|
|
||||||
import { E2EImportsModule } from 'e2e-imports.module';
|
import { E2EImportsModule } from 'e2e-imports.module';
|
||||||
|
|
||||||
import { PdfDocumentService } from '../ui-services/pdf-document.service';
|
import { PdfDocumentService } from './pdf-document.service';
|
||||||
|
|
||||||
describe('PdfDocumentService', () => {
|
describe('PdfDocumentService', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
@ -1,13 +1,15 @@
|
|||||||
import { HttpHeaders } from '@angular/common/http';
|
import { HttpHeaders } from '@angular/common/http';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
import { MatSnackBar } from '@angular/material';
|
||||||
|
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { saveAs } from 'file-saver';
|
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 { 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 { HttpService } from '../core-services/http.service';
|
||||||
|
import { ProgressService } from '../ui-services/progress.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enumeration to define possible values for the styling.
|
* Enumeration to define possible values for the styling.
|
||||||
@ -51,7 +53,7 @@ export class PdfError extends Error {
|
|||||||
* @example
|
* @example
|
||||||
* ```ts
|
* ```ts
|
||||||
* const motionContent = this.motionPdfService.motionToDocDef(this.motion);
|
* const motionContent = this.motionPdfService.motionToDocDef(this.motion);
|
||||||
* this.this.pdfDocumentService.open(motionContent);
|
* this.pdfDocumentService.download(motionContent, 'test.pdf');
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
@Injectable({
|
@Injectable({
|
||||||
@ -64,25 +66,6 @@ export class PdfDocumentService {
|
|||||||
*/
|
*/
|
||||||
private imageUrls: string[] = [];
|
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
|
* Constructor
|
||||||
*
|
*
|
||||||
@ -93,7 +76,9 @@ export class PdfDocumentService {
|
|||||||
public constructor(
|
public constructor(
|
||||||
private translate: TranslateService,
|
private translate: TranslateService,
|
||||||
private configService: ConfigService,
|
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],
|
customMargins?: [number, number, number, number],
|
||||||
landscape?: boolean
|
landscape?: boolean
|
||||||
): Promise<object> {
|
): Promise<object> {
|
||||||
this.initFonts();
|
|
||||||
this.imageUrls = imageUrls ? imageUrls : [];
|
this.imageUrls = imageUrls ? imageUrls : [];
|
||||||
pdfMake.vfs = await this.initVfs();
|
|
||||||
const pageSize = this.configService.instant('general_export_pdf_pagesize');
|
const pageSize = this.configService.instant('general_export_pdf_pagesize');
|
||||||
const defaultMargins = pageSize === 'A5' ? [45, 30, 45, 45] : [75, 90, 75, 75];
|
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 = {
|
const result = {
|
||||||
pageSize: pageSize || 'A4',
|
pageSize: pageSize || 'A4',
|
||||||
pageOrientation: landscape ? 'landscape' : 'portrait',
|
pageOrientation: landscape ? 'landscape' : 'portrait',
|
||||||
@ -199,21 +180,12 @@ export class PdfDocumentService {
|
|||||||
fontSize: this.configService.instant('general_export_pdf_fontsize')
|
fontSize: this.configService.instant('general_export_pdf_fontsize')
|
||||||
},
|
},
|
||||||
header: this.getHeader(customMargins ? [customMargins[0], customMargins[2]] : null),
|
header: this.getHeader(customMargins ? [customMargins[0], customMargins[2]] : null),
|
||||||
|
// real footer gets created in the worker
|
||||||
// TODO: option for no footer, wherever this can be defined
|
tmpfooter: this.getFooter(customMargins ? [customMargins[0], customMargins[2]] : null, exportInfo),
|
||||||
footer: (currentPage, pageCount) => {
|
|
||||||
return this.getFooter(
|
|
||||||
currentPage,
|
|
||||||
pageCount,
|
|
||||||
customMargins ? [customMargins[0], customMargins[2]] : null,
|
|
||||||
exportInfo
|
|
||||||
);
|
|
||||||
},
|
|
||||||
info: metadata,
|
info: metadata,
|
||||||
content: documentContent,
|
content: documentContent,
|
||||||
styles: this.getStandardPaperStyles()
|
styles: this.getStandardPaperStyles()
|
||||||
};
|
};
|
||||||
await this.loadAllImages();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,9 +198,7 @@ export class PdfDocumentService {
|
|||||||
* @returns the pdf document definition ready to export
|
* @returns the pdf document definition ready to export
|
||||||
*/
|
*/
|
||||||
private async getBallotPaper(documentContent: object, imageUrl?: string): Promise<object> {
|
private async getBallotPaper(documentContent: object, imageUrl?: string): Promise<object> {
|
||||||
this.initFonts();
|
|
||||||
this.imageUrls = imageUrl ? [imageUrl] : [];
|
this.imageUrls = imageUrl ? [imageUrl] : [];
|
||||||
pdfMake.vfs = await this.initVfs();
|
|
||||||
const result = {
|
const result = {
|
||||||
pageSize: 'A4',
|
pageSize: 'A4',
|
||||||
pageMargins: [0, 0, 0, 0],
|
pageMargins: [0, 0, 0, 0],
|
||||||
@ -239,21 +209,18 @@ export class PdfDocumentService {
|
|||||||
content: documentContent,
|
content: documentContent,
|
||||||
styles: this.getBlankPaperStyles()
|
styles: this.getBlankPaperStyles()
|
||||||
};
|
};
|
||||||
await this.loadAllImages();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define the fonts
|
* Get pdfFonts from storage
|
||||||
*/
|
*/
|
||||||
private initFonts(): void {
|
private getPdfFonts(): object {
|
||||||
pdfMake.fonts = {
|
return {
|
||||||
PdfFont: {
|
normal: this.getFontName('font_regular'),
|
||||||
normal: this.getFontName('font_regular'),
|
bold: this.getFontName('font_bold'),
|
||||||
bold: this.getFontName('font_bold'),
|
italics: this.getFontName('font_italic'),
|
||||||
italics: this.getFontName('font_italic'),
|
bolditalics: this.getFontName('font_bold_italic')
|
||||||
bolditalics: this.getFontName('font_bold_italic')
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,14 +308,9 @@ export class PdfDocumentService {
|
|||||||
* @param lrMargin optionally overriding the margins
|
* @param lrMargin optionally overriding the margins
|
||||||
* @returns the footer doc definition
|
* @returns the footer doc definition
|
||||||
*/
|
*/
|
||||||
private getFooter(
|
private getFooter(lrMargin?: [number, number], exportInfo?: ExportFormData): object {
|
||||||
currentPage: number,
|
|
||||||
pageCount: number,
|
|
||||||
lrMargin?: [number, number],
|
|
||||||
exportInfo?: ExportFormData
|
|
||||||
): object {
|
|
||||||
const columns = [];
|
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;
|
const showDate = exportInfo && exportInfo.pdfOptions ? exportInfo.pdfOptions.includes('date') : false;
|
||||||
let logoContainerWidth: string;
|
let logoContainerWidth: string;
|
||||||
let pageNumberPosition: string;
|
let pageNumberPosition: string;
|
||||||
@ -357,11 +319,10 @@ export class PdfDocumentService {
|
|||||||
const logoFooterRightUrl = this.configService.instant<any>('logo_pdf_footer_R').path;
|
const logoFooterRightUrl = this.configService.instant<any>('logo_pdf_footer_R').path;
|
||||||
|
|
||||||
let footerPageNumber = '';
|
let footerPageNumber = '';
|
||||||
if (showPage) {
|
if (showPageNr) {
|
||||||
footerPageNumber += `${currentPage} / ${pageCount}`;
|
// footerPageNumber += `${currentPage} / ${pageCount}`;
|
||||||
if (showDate) {
|
// replace with `${currentPage} / ${pageCount}` in worker
|
||||||
footerPageNumber += '\n';
|
footerPageNumber += `%PAGENR%`;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let footerDate = {};
|
let footerDate = {};
|
||||||
@ -402,11 +363,12 @@ export class PdfDocumentService {
|
|||||||
width: logoContainerWidth,
|
width: logoContainerWidth,
|
||||||
alignment: 'left'
|
alignment: 'left'
|
||||||
});
|
});
|
||||||
|
this.imageUrls.push(logoFooterLeftUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the page number
|
// add the page number
|
||||||
columns.push({
|
columns.push({
|
||||||
text: [footerPageNumber, footerDate],
|
stack: [footerPageNumber, footerDate],
|
||||||
style: 'footerPageNumber',
|
style: 'footerPageNumber',
|
||||||
alignment: pageNumberPosition
|
alignment: pageNumberPosition
|
||||||
});
|
});
|
||||||
@ -419,6 +381,7 @@ export class PdfDocumentService {
|
|||||||
width: logoContainerWidth,
|
width: logoContainerWidth,
|
||||||
alignment: 'right'
|
alignment: 'right'
|
||||||
});
|
});
|
||||||
|
this.imageUrls.push(logoFooterRightUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
const margin = [lrMargin ? lrMargin[0] : 75, 0, lrMargin ? lrMargin[0] : 75, 10];
|
const margin = [lrMargin ? lrMargin[0] : 75, 0, lrMargin ? lrMargin[0] : 75, 10];
|
||||||
@ -454,6 +417,7 @@ export class PdfDocumentService {
|
|||||||
this.createPdf(doc, filename);
|
this.createPdf(doc, filename);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Downloads a pdf with the ballot papet page definitions.
|
* Downloads a pdf with the ballot papet page definitions.
|
||||||
*
|
*
|
||||||
@ -471,12 +435,57 @@ export class PdfDocumentService {
|
|||||||
* Triggers the actual page creation and saving.
|
* Triggers the actual page creation and saving.
|
||||||
*
|
*
|
||||||
* @param doc the finished layout
|
* @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 {
|
private async createPdf(doc: object, filetitle: string): Promise<void> {
|
||||||
pdfMake.createPdf(doc).getBlob(blob => {
|
const filename = `${filetitle}.pdf`;
|
||||||
saveAs(blob, `${filename}.pdf`, { autoBOM: true });
|
|
||||||
|
// 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<any>('logo_pdf_footer_L').path;
|
|
||||||
const logoFooterRightUrl = this.configService.instant<any>('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)
|
* Triggers the addition of all images found during creation(including header and footer)
|
||||||
* to the vfs.
|
* to the vfs.
|
||||||
*/
|
*/
|
||||||
private async loadAllImages(): Promise<void> {
|
private async loadAllImages(vfs: object): Promise<void> {
|
||||||
const promises = this.imageUrls.map(image => {
|
const promises = this.imageUrls.map(image => {
|
||||||
return this.addImageToVfS(image);
|
return this.addImageToVfS(image, vfs);
|
||||||
});
|
});
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
}
|
}
|
||||||
@ -645,14 +637,14 @@ export class PdfDocumentService {
|
|||||||
*
|
*
|
||||||
* @param url
|
* @param url
|
||||||
*/
|
*/
|
||||||
private async addImageToVfS(url: string): Promise<void> {
|
private async addImageToVfS(url: string, vfs: object): Promise<void> {
|
||||||
if (url.indexOf('/') === 0) {
|
if (url.indexOf('/') === 0) {
|
||||||
url = url.substr(1);
|
url = url.substr(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pdfMake.vfs[url]) {
|
if (!vfs[url]) {
|
||||||
const base64 = await this.convertUrlToBase64(url);
|
const base64 = await this.convertUrlToBase64(url);
|
||||||
pdfMake.vfs[url] = base64;
|
vfs[url] = base64;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
114
client/src/app/core/pdf-services/pdf-worker.worker.ts
Normal file
114
client/src/app/core/pdf-services/pdf-worker.worker.ts
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/// <reference lib="webworker" />
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
12
client/src/app/core/ui-services/progress.service.spec.ts
Normal file
12
client/src/app/core/ui-services/progress.service.spec.ts
Normal file
@ -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();
|
||||||
|
});
|
||||||
|
});
|
63
client/src/app/core/ui-services/progress.service.ts
Normal file
63
client/src/app/core/ui-services/progress.service.ts
Normal file
@ -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<ProgressInfo> = new Subject();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subject to get the progress amount
|
||||||
|
*/
|
||||||
|
private _progressAmount: Subject<number> = new Subject();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the progress information as observable
|
||||||
|
*/
|
||||||
|
public get info(): Subject<ProgressInfo> {
|
||||||
|
return this._progressInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the progres amount as observable
|
||||||
|
*/
|
||||||
|
public get amount(): Subject<number> {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
<div>
|
||||||
|
{{ message | translate }}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<mat-progress-bar color="accent" [mode]="mode" [value]="value"></mat-progress-bar>
|
||||||
|
</div>
|
@ -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<ProgressSnackBarComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [E2EImportsModule]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ProgressSnackBarComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -96,6 +96,7 @@ import { AgendaContentObjectFormComponent } from './components/agenda-content-ob
|
|||||||
import { ExtensionFieldComponent } from './components/extension-field/extension-field.component';
|
import { ExtensionFieldComponent } from './components/extension-field/extension-field.component';
|
||||||
import { AttachmentControlComponent } from './components/attachment-control/attachment-control.component';
|
import { AttachmentControlComponent } from './components/attachment-control/attachment-control.component';
|
||||||
import { RoundedInputComponent } from './components/rounded-input/rounded-input.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.
|
* Share Module for all "dumb" components and pipes.
|
||||||
@ -274,7 +275,8 @@ import { RoundedInputComponent } from './components/rounded-input/rounded-input.
|
|||||||
AgendaContentObjectFormComponent,
|
AgendaContentObjectFormComponent,
|
||||||
ExtensionFieldComponent,
|
ExtensionFieldComponent,
|
||||||
AttachmentControlComponent,
|
AttachmentControlComponent,
|
||||||
RoundedInputComponent
|
RoundedInputComponent,
|
||||||
|
ProgressSnackBarComponent
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: DateAdapter, useClass: OpenSlidesDateAdapter },
|
{ provide: DateAdapter, useClass: OpenSlidesDateAdapter },
|
||||||
@ -283,14 +285,16 @@ import { RoundedInputComponent } from './components/rounded-input/rounded-input.
|
|||||||
SortingTreeComponent,
|
SortingTreeComponent,
|
||||||
SortFilterBarComponent,
|
SortFilterBarComponent,
|
||||||
SortBottomSheetComponent,
|
SortBottomSheetComponent,
|
||||||
DecimalPipe
|
DecimalPipe,
|
||||||
|
ProgressSnackBarComponent
|
||||||
],
|
],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
SortBottomSheetComponent,
|
SortBottomSheetComponent,
|
||||||
C4DialogComponent,
|
C4DialogComponent,
|
||||||
PromptDialogComponent,
|
PromptDialogComponent,
|
||||||
ChoiceDialogComponent,
|
ChoiceDialogComponent,
|
||||||
ProjectionDialogComponent
|
ProjectionDialogComponent,
|
||||||
|
ProgressSnackBarComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class SharedModule {}
|
export class SharedModule {}
|
||||||
|
@ -12,13 +12,13 @@ import { AgendaFilterListService } from '../../services/agenda-filter-list.servi
|
|||||||
import { AgendaPdfService } from '../../services/agenda-pdf.service';
|
import { AgendaPdfService } from '../../services/agenda-pdf.service';
|
||||||
import { OperatorService } from 'app/core/core-services/operator.service';
|
import { OperatorService } from 'app/core/core-services/operator.service';
|
||||||
import { StorageService } from 'app/core/core-services/storage.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 { ItemRepositoryService } from 'app/core/repositories/agenda/item-repository.service';
|
||||||
import { ListOfSpeakersRepositoryService } from 'app/core/repositories/agenda/list-of-speakers-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 { TopicRepositoryService } from 'app/core/repositories/topics/topic-repository.service';
|
||||||
import { _ } from 'app/core/translate/translation-marker';
|
import { _ } from 'app/core/translate/translation-marker';
|
||||||
import { ConfigService } from 'app/core/ui-services/config.service';
|
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||||
import { DurationService } from 'app/core/ui-services/duration.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 { PromptService } from 'app/core/ui-services/prompt.service';
|
||||||
import { ViewportService } from 'app/core/ui-services/viewport.service';
|
import { ViewportService } from 'app/core/ui-services/viewport.service';
|
||||||
import { ColumnRestriction } from 'app/shared/components/list-view-table/list-view-table.component';
|
import { ColumnRestriction } from 'app/shared/components/list-view-table/list-view-table.component';
|
||||||
|
@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
|
|||||||
|
|
||||||
import { TranslateService } from '@ngx-translate/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 { AssignmentPdfService } from './assignment-pdf.service';
|
||||||
import { ViewAssignment } from '../models/view-assignment';
|
import { ViewAssignment } from '../models/view-assignment';
|
||||||
|
|
||||||
|
@ -2,8 +2,7 @@ import { Injectable } from '@angular/core';
|
|||||||
|
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
import { HtmlToPdfService } from 'app/core/ui-services/html-to-pdf.service';
|
import { HtmlToPdfService } from 'app/core/pdf-services/html-to-pdf.service';
|
||||||
import { PdfDocumentService } from 'app/core/ui-services/pdf-document.service';
|
|
||||||
import { PollVoteValue } from 'app/core/ui-services/poll.service';
|
import { PollVoteValue } from 'app/core/ui-services/poll.service';
|
||||||
import { AssignmentPollService } from './assignment-poll.service';
|
import { AssignmentPollService } from './assignment-poll.service';
|
||||||
import { ViewAssignment } from '../models/view-assignment';
|
import { ViewAssignment } from '../models/view-assignment';
|
||||||
@ -34,7 +33,6 @@ export class AssignmentPdfService {
|
|||||||
public constructor(
|
public constructor(
|
||||||
private translate: TranslateService,
|
private translate: TranslateService,
|
||||||
private pollService: AssignmentPollService,
|
private pollService: AssignmentPollService,
|
||||||
private pdfDocumentService: PdfDocumentService,
|
|
||||||
private htmlToPdfService: HtmlToPdfService
|
private htmlToPdfService: HtmlToPdfService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@ -265,7 +263,7 @@ export class AssignmentPdfService {
|
|||||||
headerRows: 1,
|
headerRows: 1,
|
||||||
body: pollTableBody
|
body: pollTableBody
|
||||||
},
|
},
|
||||||
layout: this.pdfDocumentService.switchColorTableLayout
|
layout: 'switchColorTableLayout'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,11 @@ import { Injectable } from '@angular/core';
|
|||||||
|
|
||||||
import { TranslateService } from '@ngx-translate/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 { AssignmentRepositoryService } from 'app/core/repositories/assignments/assignment-repository.service';
|
||||||
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';
|
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';
|
||||||
import { ConfigService } from 'app/core/ui-services/config.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 { AssignmentPollMethod } from './assignment-poll.service';
|
||||||
import { ViewAssignmentPoll } from '../models/view-assignment-poll';
|
import { ViewAssignmentPoll } from '../models/view-assignment-poll';
|
||||||
|
|
||||||
|
@ -8,13 +8,13 @@ import { TranslateService } from '@ngx-translate/core';
|
|||||||
import { PblColumnDefinition } from '@pebula/ngrid';
|
import { PblColumnDefinition } from '@pebula/ngrid';
|
||||||
|
|
||||||
import { StorageService } from 'app/core/core-services/storage.service';
|
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 { CategoryRepositoryService } from 'app/core/repositories/motions/category-repository.service';
|
||||||
import { MotionBlockRepositoryService } from 'app/core/repositories/motions/motion-block-repository.service';
|
import { MotionBlockRepositoryService } from 'app/core/repositories/motions/motion-block-repository.service';
|
||||||
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
||||||
import { WorkflowRepositoryService } from 'app/core/repositories/motions/workflow-repository.service';
|
import { WorkflowRepositoryService } from 'app/core/repositories/motions/workflow-repository.service';
|
||||||
import { TagRepositoryService } from 'app/core/repositories/tags/tag-repository.service';
|
import { TagRepositoryService } from 'app/core/repositories/tags/tag-repository.service';
|
||||||
import { ConfigService } from 'app/core/ui-services/config.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 { ColumnRestriction } from 'app/shared/components/list-view-table/list-view-table.component';
|
||||||
import { infoDialogSettings, largeDialogSettings } from 'app/shared/utils/dialog-settings';
|
import { infoDialogSettings, largeDialogSettings } from 'app/shared/utils/dialog-settings';
|
||||||
import { BaseListViewComponent } from 'app/site/base/base-list-view';
|
import { BaseListViewComponent } from 'app/site/base/base-list-view';
|
||||||
|
@ -3,10 +3,10 @@ import { Injectable } from '@angular/core';
|
|||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { BehaviorSubject } from 'rxjs';
|
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 { CategoryRepositoryService } from 'app/core/repositories/motions/category-repository.service';
|
||||||
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
||||||
import { ConfigService } from 'app/core/ui-services/config.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 { ExportFormData } from '../modules/motion-list/components/motion-export-dialog/motion-export-dialog.component';
|
||||||
import { MotionPdfService } from './motion-pdf.service';
|
import { MotionPdfService } from './motion-pdf.service';
|
||||||
import { ViewCategory } from '../models/view-category';
|
import { ViewCategory } from '../models/view-category';
|
||||||
|
@ -2,8 +2,8 @@ import { Injectable } from '@angular/core';
|
|||||||
|
|
||||||
import { TranslateService } from '@ngx-translate/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 { 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 { PersonalNoteContent } from 'app/shared/models/users/personal-note';
|
||||||
import { ExportFormData } from '../modules/motion-list/components/motion-export-dialog/motion-export-dialog.component';
|
import { ExportFormData } from '../modules/motion-list/components/motion-export-dialog/motion-export-dialog.component';
|
||||||
import { MotionPdfCatalogService } from './motion-pdf-catalog.service';
|
import { MotionPdfCatalogService } from './motion-pdf-catalog.service';
|
||||||
|
@ -2,14 +2,14 @@ import { Injectable } from '@angular/core';
|
|||||||
|
|
||||||
import { TranslateService } from '@ngx-translate/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 { ChangeRecommendationRepositoryService } from 'app/core/repositories/motions/change-recommendation-repository.service';
|
||||||
import { MotionCommentSectionRepositoryService } from 'app/core/repositories/motions/motion-comment-section-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 { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
||||||
import { StatuteParagraphRepositoryService } from 'app/core/repositories/motions/statute-paragraph-repository.service';
|
import { StatuteParagraphRepositoryService } from 'app/core/repositories/motions/statute-paragraph-repository.service';
|
||||||
import { ConfigService } from 'app/core/ui-services/config.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 { 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 { CalculablePollKey } from 'app/core/ui-services/poll.service';
|
||||||
import { ViewUnifiedChange, ViewUnifiedChangeType } from 'app/shared/models/motions/view-unified-change';
|
import { ViewUnifiedChange, ViewUnifiedChangeType } from 'app/shared/models/motions/view-unified-change';
|
||||||
import { getRecommendationTypeName } from 'app/shared/utils/recommendation-type-names';
|
import { getRecommendationTypeName } from 'app/shared/utils/recommendation-type-names';
|
||||||
@ -547,21 +547,7 @@ export class MotionPdfService {
|
|||||||
body: metaTableBody
|
body: metaTableBody
|
||||||
},
|
},
|
||||||
margin: [0, 0, 0, 20],
|
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: 'metaboxLayout'
|
||||||
layout: {
|
|
||||||
fillColor: () => {
|
|
||||||
return '#dddddd';
|
|
||||||
},
|
|
||||||
hLineWidth: (i, node) => {
|
|
||||||
return i === 0 || i === node.table.body.length ? 0 : 0.5;
|
|
||||||
},
|
|
||||||
vLineWidth: () => {
|
|
||||||
return 0;
|
|
||||||
},
|
|
||||||
hLineColor: () => {
|
|
||||||
return 'white';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -776,7 +762,7 @@ export class MotionPdfService {
|
|||||||
dontBreakRows: true,
|
dontBreakRows: true,
|
||||||
body: callListTableBody.concat(callListRows)
|
body: callListTableBody.concat(callListRows)
|
||||||
},
|
},
|
||||||
layout: this.pdfDocumentService.switchColorTableLayout
|
layout: 'switchColorTableLayout'
|
||||||
};
|
};
|
||||||
return [title, table];
|
return [title, table];
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,11 @@ import { Injectable } from '@angular/core';
|
|||||||
|
|
||||||
import { TranslateService } from '@ngx-translate/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 { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
||||||
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';
|
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';
|
||||||
import { ConfigService } from 'app/core/ui-services/config.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';
|
import { MotionPoll } from 'app/shared/models/motions/motion-poll';
|
||||||
|
|
||||||
type BallotCountChoices = 'NUMBER_OF_DELEGATES' | 'NUMBER_OF_ALL_PARTICIPANTS' | 'CUSTOM_NUMBER';
|
type BallotCountChoices = 'NUMBER_OF_DELEGATES' | 'NUMBER_OF_ALL_PARTICIPANTS' | 'CUSTOM_NUMBER';
|
||||||
|
@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
|
|||||||
|
|
||||||
import { TranslateService } from '@ngx-translate/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 { UserPdfService } from './user-pdf.service';
|
||||||
import { ViewUser } from '../models/view-user';
|
import { ViewUser } from '../models/view-user';
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ import { Injectable } from '@angular/core';
|
|||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
import { ConfigService } from 'app/core/ui-services/config.service';
|
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';
|
import { ViewUser } from '../models/view-user';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,13 +24,8 @@ export class UserPdfService {
|
|||||||
*
|
*
|
||||||
* @param translate handle translations
|
* @param translate handle translations
|
||||||
* @param configService Read config variables
|
* @param configService Read config variables
|
||||||
* @param pdfDocumentService Global PDF Functions
|
|
||||||
*/
|
*/
|
||||||
public constructor(
|
public constructor(private translate: TranslateService, private configService: ConfigService) {}
|
||||||
private translate: TranslateService,
|
|
||||||
private configService: ConfigService,
|
|
||||||
private pdfDocumentService: PdfDocumentService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a user to PdfMake doc definition, containing access information
|
* Converts a user to PdfMake doc definition, containing access information
|
||||||
@ -254,7 +248,7 @@ export class UserPdfService {
|
|||||||
headerRows: 1,
|
headerRows: 1,
|
||||||
body: userTableBody.concat(this.getListUsers(users))
|
body: userTableBody.concat(this.getListUsers(users))
|
||||||
},
|
},
|
||||||
layout: this.pdfDocumentService.switchColorTableLayout
|
layout: 'switchColorTableLayout'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,5 +8,5 @@
|
|||||||
"enableIvy": false
|
"enableIvy": false
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts"],
|
"include": ["src/**/*.ts"],
|
||||||
"exclude": ["src/test.ts", "**/*.spec.ts"]
|
"exclude": ["src/test.ts", "**/*.spec.ts", "src/**/*.worker.ts"]
|
||||||
}
|
}
|
||||||
|
14
client/tsconfig.worker.json
Normal file
14
client/tsconfig.worker.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./out-tsc/worker",
|
||||||
|
"lib": [
|
||||||
|
"es2018",
|
||||||
|
"webworker"
|
||||||
|
],
|
||||||
|
"types": []
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.worker.ts"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user