8 Commits
1.1.0 ... 1.2.0

Author SHA1 Message Date
Gitlab CI
f9c1045557 chore: Release 1.2.0 2022-04-29 11:47:01 +00:00
Matthieu CAILLEAUX
b759c032a8 chore: docs 2022-04-29 13:44:36 +02:00
Matthieu CAILLEAUX
851bc738e5 fix: regression generate pdf 2022-04-29 13:38:39 +02:00
Matthieu CAILLEAUX
049c77a004 feat: add mobile css 2022-04-27 23:36:15 +02:00
Matthieu CAILLEAUX
b16967c351 feat: base html sheet 2022-04-26 21:11:35 +02:00
Matthieu CAILLEAUX
986d50a5eb feat: init export html button 2022-04-23 21:05:13 +02:00
Matthieu CAILLEAUX
a246f899f4 chore: release node update 2022-01-30 19:55:13 +01:00
Matthieu CAILLEAUX
b5c6b5510e chore: sync package lock 2022-01-30 19:46:32 +01:00
31 changed files with 1279 additions and 364 deletions

View File

@@ -7,7 +7,7 @@ include:
ref: 1.0.0 ref: 1.0.0
file: '/release-common.yml' file: '/release-common.yml'
- project: '$CI_PROJECT_ROOT_NAMESPACE/ci-tools/pipeline/ci-tools-pipeline-release-node' - project: '$CI_PROJECT_ROOT_NAMESPACE/ci-tools/pipeline/ci-tools-pipeline-release-node'
ref: 1.0.1 ref: 1.0.2
file: '/release-node.yml' file: '/release-node.yml'
- project: '$CI_PROJECT_ROOT_NAMESPACE/ci-tools/pipeline/ci-tools-pipeline-project-foundry-module' - project: '$CI_PROJECT_ROOT_NAMESPACE/ci-tools/pipeline/ci-tools-pipeline-project-foundry-module'
ref: 1.0.1 ref: 1.0.1

View File

@@ -1,5 +1,12 @@
## In development ## In development
## 1.2.0
### New features
- HTML Responsive Export Characters sheet
- Add contextual menu to actor to HTML responsive Export Characters sheet
## 1.1.0 ## 1.1.0
- Add contextual menu to actor to PDF Export Characters sheet - Add contextual menu to actor to PDF Export Characters sheet

View File

@@ -1,6 +1,6 @@
# WFRP 4 Actor Sheet Print # WFRP 4 Actor Sheet Print
This module allow to export characters sheet on a friendly print pdf. This module allow to export characters sheet on a friendly print pdf or a responsive html.
# Authors # Authors
@@ -28,7 +28,7 @@ A print buton is added on top of sheet to export as pdf
![Print button](media/actor-sheet-print-button.png) ![Print button](media/actor-sheet-print-button.png)
A Contextual menu is added on Actor menu A Contextual menu is added on Actor menu, one for pdf, an other for html
![Actor button](media/actor-sheet-print-actor-button.png) ![Actor button](media/actor-sheet-print-actor-button.png)

View File

@@ -1,3 +1,4 @@
{ {
"WFRP4SHEETPRINT.export.pdf": "Export to PDF" "WFRP4SHEETPRINT.export.pdf": "Export to PDF",
"WFRP4SHEETPRINT.export.html": "Export to Html"
} }

View File

@@ -1,3 +1,4 @@
{ {
"WFRP4SHEETPRINT.export.pdf": "Exporter en PDF" "WFRP4SHEETPRINT.export.pdf": "Exporter en PDF",
"WFRP4SHEETPRINT.export.html": "Exporter en Html"
} }

View File

@@ -1,3 +1,6 @@
#!/bin/bash
set -e
cp -r ./dist/* $LOCAL_FOUNDRY cp -r ./dist/* $LOCAL_FOUNDRY

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 83 KiB

13
package-lock.json generated
View File

@@ -1,5 +1,5 @@
{ {
"version": "1.0.4", "version": "1.2.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@@ -519,6 +519,12 @@
"integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==",
"dev": true "dev": true
}, },
"@types/file-saver": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.5.tgz",
"integrity": "sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ==",
"dev": true
},
"@types/jquery": { "@types/jquery": {
"version": "3.5.11", "version": "3.5.11",
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.11.tgz", "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.11.tgz",
@@ -1224,6 +1230,11 @@
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz",
"integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==" "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA=="
}, },
"file-saver": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
},
"fill-range": { "fill-range": {
"version": "7.0.1", "version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",

View File

@@ -5,7 +5,7 @@
"build": "webpack", "build": "webpack",
"local-deploy": "npm run package && sh ./local-deploy.sh" "local-deploy": "npm run package && sh ./local-deploy.sh"
}, },
"version": "1.1.0", "version": "1.2.0",
"devDependencies": { "devDependencies": {
"@league-of-foundry-developers/foundry-vtt-types": "0.8.9-9", "@league-of-foundry-developers/foundry-vtt-types": "0.8.9-9",
"husky": "4.3.7", "husky": "4.3.7",
@@ -14,7 +14,8 @@
"typescript": "4.5.4", "typescript": "4.5.4",
"ts-loader": "9.2.6", "ts-loader": "9.2.6",
"webpack": "5.65.0", "webpack": "5.65.0",
"webpack-cli": "4.9.1" "webpack-cli": "4.9.1",
"@types/file-saver": "2.0.5"
}, },
"husky": { "husky": {
"hooks": { "hooks": {
@@ -22,6 +23,7 @@
} }
}, },
"dependencies": { "dependencies": {
"jspdf": "2.4.0" "jspdf": "2.4.0",
"file-saver": "2.0.5"
} }
} }

View File

@@ -1,3 +1,6 @@
#!/bin/bash
set -e
rm -fr dist rm -fr dist
npm run build npm run build
cp -r $MODULE_DIRS dist/ cp -r $MODULE_DIRS dist/

14
src/abstract-builder.ts Normal file
View File

@@ -0,0 +1,14 @@
import { AbstractElement } from './elements/abstract-element';
import { GenerateTypeEnum } from './elements/generate-type.enum';
export abstract class AbstractBuilder {
public abstract build(elements: AbstractElement[]);
public abstract getLabelledRowHeight(): number;
public abstract save(name: string);
public abstract getImageScale(): number;
public abstract getGenerateType(): GenerateTypeEnum;
}

View File

@@ -6,4 +6,6 @@ export const isGM = () => user()?.isGM ?? false;
export const TEXT_SIZE = 8; export const TEXT_SIZE = 8;
export const LABEL_SIZE = 6; export const LABEL_SIZE = 6;
export const HTML_TEXT_SIZE = 1;
export const HTML_LABEL_SIZE = 0.75;
export const MARGINS = { top: 10, left: 10, bottom: 10, right: 10 }; export const MARGINS = { top: 10, left: 10, bottom: 10, right: 10 };

View File

@@ -0,0 +1,38 @@
import { AbstractElement } from './abstract-element';
import { IContext } from './context';
import { GenerateTypeEnum } from './generate-type.enum';
export abstract class AbstractContainerElement extends AbstractElement {
public pdfElements: AbstractElement[] = [];
public htmlElements: AbstractElement[] = [];
public contextElements: AbstractElement[] = [];
constructor(
globalType: GenerateTypeEnum,
x: number,
y: number,
maxWidth: number | undefined,
elements: AbstractElement[] = [],
context: Partial<IContext> = AbstractElement.DEFAULT_CONTEXT
) {
super(globalType, x, y, maxWidth, context);
this.htmlElements = this.context.isHtml
? elements.filter((el) => el.context.isHtml)
: [];
this.pdfElements = this.context.isPdf
? elements.filter((el) => el.context.isPdf)
: [];
this.contextElements =
this.globalType === GenerateTypeEnum.HTML
? this.htmlElements
: this.pdfElements;
}
public getElements(): AbstractElement[] {
const elements: AbstractElement[] = [];
for (const element of this.contextElements) {
elements.push(...element.getElements());
}
return elements;
}
}

View File

@@ -1,15 +1,36 @@
import jsPDF from 'jspdf'; import jsPDF from 'jspdf';
import { MARGINS } from '../constants'; import { MARGINS } from '../constants';
import { IContext } from './context';
import { GenerateTypeEnum } from './generate-type.enum';
export abstract class AbstractElement { export abstract class AbstractElement {
public static readonly DEFAULT_CONTEXT: IContext = {
isHtml: true,
isPdf: true,
name: 'element',
};
public globalType: GenerateTypeEnum;
public x: number; public x: number;
public y: number; public y: number;
public maxWidth?: number; public maxWidth?: number;
public context: IContext = AbstractElement.DEFAULT_CONTEXT;
constructor(x: number, y: number, maxWidth?: number | undefined) { constructor(
globalType: GenerateTypeEnum,
x: number,
y: number,
maxWidth?: number | undefined,
context: Partial<IContext> = AbstractElement.DEFAULT_CONTEXT
) {
this.globalType = globalType;
this.x = x >= MARGINS.left ? x : MARGINS.left; this.x = x >= MARGINS.left ? x : MARGINS.left;
this.y = y >= MARGINS.top ? y : MARGINS.top; this.y = y >= MARGINS.top ? y : MARGINS.top;
this.maxWidth = maxWidth; this.maxWidth = maxWidth;
this.context = {
...this.context,
...context,
};
} }
public getHeightFromPx(doc: jsPDF, size: number) { public getHeightFromPx(doc: jsPDF, size: number) {
@@ -28,6 +49,13 @@ export abstract class AbstractElement {
public abstract render(doc: jsPDF, maxWidth?: number): jsPDF; public abstract render(doc: jsPDF, maxWidth?: number): jsPDF;
public abstract renderHtml(
doc: Document,
parent: HTMLElement,
cssRules: string[],
sheet: HTMLStyleElement
): Document;
public abstract getHeight(doc?: jsPDF): number; public abstract getHeight(doc?: jsPDF): number;
public abstract getCheckNewPageHeight(doc?: jsPDF): number; public abstract getCheckNewPageHeight(doc?: jsPDF): number;

View File

@@ -1,14 +1,23 @@
import { AbstractElement } from './abstract-element'; import { AbstractElement } from './abstract-element';
import jsPDF from 'jspdf'; import jsPDF from 'jspdf';
import { Box } from './box'; import { Box } from './box';
import { IContext } from './context';
import { GenerateTypeEnum } from './generate-type.enum';
export class Blank extends Box { export class Blank extends Box {
constructor(x: number, y: number, w: number, h: number) { constructor(
super(x, y, w, h); globalType: GenerateTypeEnum,
x: number,
y: number,
w: number,
h: number,
context: Partial<IContext> = AbstractElement.DEFAULT_CONTEXT
) {
super(globalType, x, y, w, h, context);
} }
public static heightBlank(h: number) { public static heightBlank(globalType: GenerateTypeEnum, h: number) {
return new Blank(0, 0, 0, h); return new Blank(globalType, 0, 0, 0, h);
} }
public getCheckNewPageHeight(doc?: jsPDF): number { public getCheckNewPageHeight(doc?: jsPDF): number {

View File

@@ -1,12 +1,21 @@
import { AbstractElement } from './abstract-element'; import { AbstractElement } from './abstract-element';
import jsPDF from 'jspdf'; import jsPDF from 'jspdf';
import { IContext } from './context';
import { GenerateTypeEnum } from './generate-type.enum';
export class Box extends AbstractElement { export class Box extends AbstractElement {
public w: number; public w: number;
public h: number; public h: number;
constructor(x: number, y: number, w: number, h: number) { constructor(
super(x, y, w); globalType: GenerateTypeEnum,
x: number,
y: number,
w: number,
h: number,
context: Partial<IContext> = AbstractElement.DEFAULT_CONTEXT
) {
super(globalType, x, y, w, context);
this.w = w; this.w = w;
this.h = h; this.h = h;
} }
@@ -20,6 +29,34 @@ export class Box extends AbstractElement {
return doc; return doc;
} }
public renderHtml(
doc: Document,
parent: HTMLElement,
cssRules: string[],
sheet: HTMLStyleElement
): Document {
const div = doc.createElement('div');
const css = `box-${this.w ?? 0}-${this.h ?? 0}`;
div.classList.add(`box`);
div.classList.add(css);
div.classList.add(this.context.name);
if (!cssRules.includes(css)) {
cssRules.push(css);
let rule = 'width: 100%;';
if (this.w > 0) {
rule += `max-width: ${this.w}px;`;
rule += `min-width: ${this.w}px;`;
}
if (this.h > 0) {
rule += `max-height: ${this.h}px;`;
rule += `min-height: ${this.h}px;`;
}
sheet.innerHTML += ` .${css} { ${rule} }`;
}
parent.append(div);
return doc;
}
public getHeight(_doc): number { public getHeight(_doc): number {
return this.h; return this.h;
} }

View File

@@ -1,16 +1,22 @@
import { AbstractElement } from './abstract-element'; import { AbstractElement } from './abstract-element';
import jsPDF from 'jspdf'; import jsPDF from 'jspdf';
import { IContext } from './context';
import { AbstractContainerElement } from './abstract-container-element';
import { GenerateTypeEnum } from './generate-type.enum';
export class Column extends AbstractElement { export class Column extends AbstractContainerElement {
public elements: AbstractElement[] = []; constructor(
globalType: GenerateTypeEnum,
constructor(x: number, y: number, elements: AbstractElement[]) { x: number,
super(x, y); y: number,
this.elements = elements; elements: AbstractElement[],
context: Partial<IContext> = AbstractElement.DEFAULT_CONTEXT
) {
super(globalType, x, y, undefined, elements, context);
} }
public prepareRender(doc: jsPDF, _maxWidth?: number): jsPDF { public prepareRender(doc: jsPDF, _maxWidth?: number): jsPDF {
const elements = this.elements ?? []; const elements = this.pdfElements ?? [];
let currentY = this.y; let currentY = this.y;
for (let i = 0; i < elements.length; i++) { for (let i = 0; i < elements.length; i++) {
@@ -29,9 +35,27 @@ export class Column extends AbstractElement {
return doc; return doc;
} }
public renderHtml(
doc: Document,
parent: HTMLElement,
cssRules: string[],
sheet: HTMLStyleElement
): Document {
const div = doc.createElement('div');
div.classList.add(`column`);
div.classList.add(this.context.name);
const elements = this.htmlElements ?? [];
for (let i = 0; i < elements.length; i++) {
const element = elements[i];
element.renderHtml(doc, div, cssRules, sheet);
}
parent.append(div);
return doc;
}
public getHeight(doc): number { public getHeight(doc): number {
return this.elements.length > 0 return this.pdfElements.length > 0
? this.elements ? this.pdfElements
.map((e) => e.getHeight(doc)) .map((e) => e.getHeight(doc))
.reduce((p, c, i) => { .reduce((p, c, i) => {
if (i === 0) { if (i === 0) {
@@ -43,20 +67,8 @@ export class Column extends AbstractElement {
} }
public getCheckNewPageHeight(doc?: jsPDF): number { public getCheckNewPageHeight(doc?: jsPDF): number {
return this.elements.length > 0 return this.pdfElements.length > 0
? this.elements[0].getCheckNewPageHeight(doc) ? this.pdfElements[0].getCheckNewPageHeight(doc)
: 0; : 0;
} }
public getElements(): AbstractElement[] {
const elements: AbstractElement[] = [];
for (const element of this.elements) {
elements.push(...element.getElements());
}
return elements;
}
public isEmpty(): boolean {
return this.elements.length === 0;
}
} }

5
src/elements/context.ts Normal file
View File

@@ -0,0 +1,5 @@
export interface IContext {
name: string;
isHtml: boolean;
isPdf: boolean;
}

View File

@@ -0,0 +1,4 @@
export enum GenerateTypeEnum {
PDF = 'PDF',
HTML = 'HTML',
}

View File

@@ -1,12 +1,22 @@
import { Box } from './box'; import { Box } from './box';
import jsPDF from 'jspdf'; import jsPDF from 'jspdf';
import { AbstractElement } from './abstract-element'; import { AbstractElement } from './abstract-element';
import { IContext } from './context';
import { GenerateTypeEnum } from './generate-type.enum';
export class Image extends Box { export class Image extends Box {
public imageData: string; public imageData: string;
constructor(x: number, y: number, w: number, h: number, imageData: string) { constructor(
super(x, y, w, h); globalType: GenerateTypeEnum,
x: number,
y: number,
w: number,
h: number,
imageData: string,
context: Partial<IContext> = AbstractElement.DEFAULT_CONTEXT
) {
super(globalType, x, y, w, h, context);
this.imageData = imageData; this.imageData = imageData;
} }
@@ -21,6 +31,32 @@ export class Image extends Box {
return doc; return doc;
} }
public renderHtml(
doc: Document,
parent: HTMLElement,
cssRules: string[],
sheet: HTMLStyleElement
): Document {
const img = doc.createElement('img');
img.src = this.imageData;
const css = `img-${this.w ?? 0}`;
img.classList.add(`img`);
img.classList.add(css);
img.classList.add(this.context.name);
if (!cssRules.includes(css)) {
cssRules.push(css);
let rule = '';
if (this.w > 0) {
rule += `width: ${this.w}px;`;
}
if (rule.length > 0) {
sheet.innerHTML += ` .${css} { ${rule} }`;
}
}
parent.append(img);
return doc;
}
public getElements(): AbstractElement[] { public getElements(): AbstractElement[] {
return [this]; return [this];
} }

View File

@@ -1,21 +1,31 @@
import jsPDF, { TextOptionsLight } from 'jspdf'; import jsPDF, { TextOptionsLight } from 'jspdf';
import { Text } from './text'; import { Text } from './text';
import { i18nLocalize, LABEL_SIZE, TEXT_SIZE } from '../constants'; import {
HTML_LABEL_SIZE,
HTML_TEXT_SIZE,
i18nLocalize,
LABEL_SIZE,
TEXT_SIZE,
} from '../constants';
import { AbstractElement } from './abstract-element'; import { AbstractElement } from './abstract-element';
import { IContext } from './context';
import { GenerateTypeEnum } from './generate-type.enum';
export class LabelledText extends Text { export class LabelledText extends Text {
public label: string; public label: string;
public labelOptions?: TextOptionsLight; public labelOptions?: TextOptionsLight;
constructor( constructor(
globalType: GenerateTypeEnum,
x: number, x: number,
y: number, y: number,
label: string, label: string,
text: string, text: string,
textOptions?: TextOptionsLight, textOptions?: TextOptionsLight,
labelOptions?: TextOptionsLight labelOptions?: TextOptionsLight,
context: Partial<IContext> = AbstractElement.DEFAULT_CONTEXT
) { ) {
super(x, y, text, textOptions); super(globalType, x, y, text, textOptions, context);
this.label = label; this.label = label;
this.labelOptions = labelOptions; this.labelOptions = labelOptions;
const textMaxWidth = this.textOptions?.maxWidth ?? 0; const textMaxWidth = this.textOptions?.maxWidth ?? 0;
@@ -40,6 +50,40 @@ export class LabelledText extends Text {
return doc; return doc;
} }
public renderHtml(
doc: Document,
parent: HTMLElement,
cssRules: string[],
sheet: HTMLStyleElement
): Document {
const div = doc.createElement('div');
div.classList.add(`column`);
div.classList.add(`labelled-text`);
div.classList.add(this.context.name);
const label = doc.createElement('p');
const text = doc.createElement('p');
const labelCss = `label-${LABEL_SIZE}`;
const textCss = `text-${TEXT_SIZE}`;
label.classList.add(labelCss);
text.classList.add(textCss);
if (!cssRules.includes(labelCss)) {
cssRules.push(labelCss);
sheet.innerHTML += ` .${labelCss} { font-size: ${HTML_LABEL_SIZE}rem; margin: 0; }`;
}
if (!cssRules.includes(textCss)) {
cssRules.push(textCss);
sheet.innerHTML += ` .${textCss} { font-size: ${HTML_TEXT_SIZE}rem; margin-top: 0.5rem; margin-bottom: 0.5rem; }`;
sheet.innerHTML += ` .labelled-text { margin-top: 0.5rem; margin-bottom: 0.5rem; }`;
sheet.innerHTML += ` .labelled-text > .${textCss} { font-size: ${HTML_TEXT_SIZE}rem; margin: 0; }`;
}
label.innerHTML = i18nLocalize(this.label);
text.innerHTML = i18nLocalize(this.text);
div.append(label);
div.append(text);
parent.append(div);
return doc;
}
protected updateMaxWidth(maxWidth?: number) { protected updateMaxWidth(maxWidth?: number) {
if (maxWidth != null && maxWidth > 0) { if (maxWidth != null && maxWidth > 0) {
this.maxWidth = maxWidth; this.maxWidth = maxWidth;

View File

@@ -1,32 +1,52 @@
import { Row } from './row'; import { Row } from './row';
import { Text } from './text'; import { Text } from './text';
import { MultilineText } from './multiline-text'; import { MultilineText } from './multiline-text';
import { IContext } from './context';
import { AbstractElement } from './abstract-element';
import { GenerateTypeEnum } from './generate-type.enum';
export class LabelledValue extends Row { export class LabelledValue extends Row {
public label: string; public label: string;
public value: number; public value: number;
constructor( constructor(
globalType: GenerateTypeEnum,
label: string, label: string,
value: number, value: number,
widthPercents?: number[], widthPercents?: number[],
multiline = false, multiline = false,
maxWidth?: number maxWidth?: number,
context: Partial<IContext> = AbstractElement.DEFAULT_CONTEXT
) { ) {
super( super(
globalType,
0, 0,
0, 0,
[ [
multiline ? new MultilineText(0, 0, label) : new Text(0, 0, label), multiline
new Text(0, 0, value.toString(), { ? new MultilineText(globalType, 0, 0, label)
: new Text(globalType, 0, 0, label),
new Text(globalType, 0, 0, value.toString(), {
align: 'right', align: 'right',
}), }),
], ],
maxWidth, maxWidth,
widthPercents, widthPercents,
[] [],
context
); );
this.label = label; this.label = label;
this.value = value; this.value = value;
} }
public renderHtml(
doc: Document,
parent: HTMLElement,
cssRules: string[],
sheet: HTMLStyleElement
): Document {
const resultDoc = super.renderHtml(doc, parent, cssRules, sheet);
parent.lastElementChild?.classList?.add('labelled-value');
return resultDoc;
}
} }

View File

@@ -3,19 +3,24 @@ import { Column } from './column';
import { LabelledValue } from './labelled-value'; import { LabelledValue } from './labelled-value';
import jsPDF from 'jspdf'; import jsPDF from 'jspdf';
import { MARGINS } from '../constants'; import { MARGINS } from '../constants';
import { IContext } from './context';
import { AbstractElement } from './abstract-element';
import { GenerateTypeEnum } from './generate-type.enum';
export class LabelledValues extends Row { export class LabelledValues extends Row {
public labelledValues: { label: string; value: number }[]; public labelledValues: { label: string; value: number }[];
public nbrOfCol: number; public nbrOfCol: number;
constructor( constructor(
globalType: GenerateTypeEnum,
x: number, x: number,
y: number, y: number,
labelledValues: { label: string; value: number }[], labelledValues: { label: string; value: number }[],
nbrOfCol?: number, nbrOfCol?: number,
multiline = false multiline = false,
context: Partial<IContext> = AbstractElement.DEFAULT_CONTEXT
) { ) {
super(x, y, []); super(globalType, x, y, [], undefined, undefined, undefined, context);
this.labelledValues = labelledValues; this.labelledValues = labelledValues;
this.nbrOfCol = nbrOfCol ?? 3; this.nbrOfCol = nbrOfCol ?? 3;
if (this.nbrOfCol > 3) { if (this.nbrOfCol > 3) {
@@ -35,7 +40,9 @@ export class LabelledValues extends Row {
rest > 2 ? nbrPerCol + 1 : nbrPerCol, rest > 2 ? nbrPerCol + 1 : nbrPerCol,
]; ];
for (let i = 0; i < this.nbrOfCol; i++) { for (let i = 0; i < this.nbrOfCol; i++) {
this.elements[i] = new Column(0, 0, []); this.contextElements[i] = new Column(globalType, 0, 0, [], {
name: `${this.context.name}-column`,
});
} }
for (let i = 0; i < labelledValues.length; i++) { for (let i = 0; i < labelledValues.length; i++) {
if (i < nbrPerCols[0]) { if (i < nbrPerCols[0]) {
@@ -45,8 +52,9 @@ export class LabelledValues extends Row {
} else { } else {
currentIndex = 2; currentIndex = 2;
} }
(<Column>this.elements[currentIndex]).elements.push( (<Column>this.contextElements[currentIndex]).contextElements.push(
new LabelledValue( new LabelledValue(
globalType,
labelledValues[i].label, labelledValues[i].label,
labelledValues[i].value, labelledValues[i].value,
widthPercent, widthPercent,
@@ -55,19 +63,24 @@ export class LabelledValues extends Row {
); );
} }
} else { } else {
this.elements.push( this.contextElements.push(
new Column( new Column(
globalType,
0, 0,
0, 0,
labelledValues.map( labelledValues.map(
(libelledValue) => (libelledValue) =>
new LabelledValue( new LabelledValue(
globalType,
libelledValue.label, libelledValue.label,
libelledValue.value, libelledValue.value,
widthPercent, widthPercent,
multiline multiline
) )
) ),
{
name: `${this.context.name}-column`,
}
) )
); );
} }
@@ -77,8 +90,8 @@ export class LabelledValues extends Row {
public prepareRender(doc: jsPDF, maxWidth?: number): jsPDF { public prepareRender(doc: jsPDF, maxWidth?: number): jsPDF {
const pageWidth = doc.internal.pageSize.width; const pageWidth = doc.internal.pageSize.width;
const rowWidth = pageWidth - this.x - MARGINS.right; const rowWidth = pageWidth - this.x - MARGINS.right;
for (const column of this.elements) { for (const column of this.pdfElements) {
for (const labelledValue of (<Column>column).elements) { for (const labelledValue of (<Column>column).pdfElements) {
labelledValue.maxWidth = rowWidth / this.nbrOfCol; labelledValue.maxWidth = rowWidth / this.nbrOfCol;
} }
} }

View File

@@ -1,18 +1,22 @@
import { AbstractElement } from './abstract-element'; import { AbstractElement } from './abstract-element';
import jsPDF, { TextOptionsLight } from 'jspdf'; import jsPDF, { TextOptionsLight } from 'jspdf';
import { i18nLocalize, TEXT_SIZE } from '../constants'; import { HTML_TEXT_SIZE, i18nLocalize, TEXT_SIZE } from '../constants';
import { Text } from './text'; import { Text } from './text';
import { IContext } from './context';
import { GenerateTypeEnum } from './generate-type.enum';
export class MultilineText extends Text { export class MultilineText extends Text {
private nbrLine = 1; private nbrLine = 1;
constructor( constructor(
globalType: GenerateTypeEnum,
x: number, x: number,
y: number, y: number,
text: string, text: string,
textOptions?: TextOptionsLight textOptions?: TextOptionsLight,
context: Partial<IContext> = AbstractElement.DEFAULT_CONTEXT
) { ) {
super(x, y, text, textOptions); super(globalType, x, y, text, textOptions, context);
} }
public prepareRender(doc: jsPDF, maxWidth?: number): jsPDF { public prepareRender(doc: jsPDF, maxWidth?: number): jsPDF {
@@ -32,6 +36,27 @@ export class MultilineText extends Text {
return doc; return doc;
} }
public renderHtml(
doc: Document,
parent: HTMLElement,
cssRules: string[],
sheet: HTMLStyleElement
): Document {
const text = doc.createElement('p');
const css = `text-${TEXT_SIZE}`;
text.classList.add(`multiline-text`);
text.classList.add(css);
text.classList.add(this.context.name);
if (!cssRules.includes(css)) {
cssRules.push(css);
sheet.innerHTML += ` .${css} { font-size: ${HTML_TEXT_SIZE}rem }`;
sheet.innerHTML += ` .labelled-text > .${css} { font-size: ${HTML_TEXT_SIZE}rem; margin: 0; }`;
}
text.innerHTML = i18nLocalize(this.text);
parent.append(text);
return doc;
}
public getHeight(doc): number { public getHeight(doc): number {
return this.getHeightFromPx(doc, TEXT_SIZE) * this.nbrLine; return this.getHeightFromPx(doc, TEXT_SIZE) * this.nbrLine;
} }

View File

@@ -1,28 +1,31 @@
import { AbstractElement } from './abstract-element'; import { AbstractElement } from './abstract-element';
import jsPDF from 'jspdf'; import jsPDF from 'jspdf';
import { MARGINS } from '../constants'; import { MARGINS } from '../constants';
import { IContext } from './context';
import { AbstractContainerElement } from './abstract-container-element';
import { GenerateTypeEnum } from './generate-type.enum';
export class Row extends AbstractElement { export class Row extends AbstractContainerElement {
public elements: AbstractElement[] = [];
public widthPercents?: number[]; public widthPercents?: number[];
public maxWidths?: number[]; public maxWidths?: number[];
constructor( constructor(
globalType: GenerateTypeEnum,
x: number, x: number,
y: number, y: number,
elements: AbstractElement[], elements: AbstractElement[],
maxWidth?: number | undefined, maxWidth?: number | undefined,
widthPercents?: number[], widthPercents?: number[],
maxWidths?: number[] maxWidths?: number[],
context: Partial<IContext> = AbstractElement.DEFAULT_CONTEXT
) { ) {
super(x, y, maxWidth); super(globalType, x, y, maxWidth, elements, context);
this.elements = elements ?? [];
this.widthPercents = widthPercents ?? []; this.widthPercents = widthPercents ?? [];
this.maxWidths = maxWidths ?? []; this.maxWidths = maxWidths ?? [];
} }
public prepareRender(doc: jsPDF, maxWidth?: number): jsPDF { public prepareRender(doc: jsPDF, maxWidth?: number): jsPDF {
const elements = this.elements ?? []; const elements = this.pdfElements ?? [];
let maxWidths = this.maxWidths ?? []; let maxWidths = this.maxWidths ?? [];
let widthPercents = this.widthPercents ?? []; let widthPercents = this.widthPercents ?? [];
@@ -60,9 +63,27 @@ export class Row extends AbstractElement {
return doc; return doc;
} }
public renderHtml(
doc: Document,
parent: HTMLElement,
cssRules: string[],
sheet: HTMLStyleElement
): Document {
const div = doc.createElement('div');
div.classList.add(`row`);
div.classList.add(this.context.name);
const elements = this.htmlElements ?? [];
for (let i = 0; i < elements.length; i++) {
const element = elements[i];
element.renderHtml(doc, div, cssRules, sheet);
}
parent.append(div);
return doc;
}
public getHeight(doc?: jsPDF): number { public getHeight(doc?: jsPDF): number {
let maxHeight = 0; let maxHeight = 0;
for (const element of this.elements) { for (const element of this.pdfElements) {
maxHeight = Math.max(maxHeight, element.getHeight(doc)); maxHeight = Math.max(maxHeight, element.getHeight(doc));
} }
return maxHeight; return maxHeight;
@@ -70,21 +91,9 @@ export class Row extends AbstractElement {
public getCheckNewPageHeight(doc?: jsPDF): number { public getCheckNewPageHeight(doc?: jsPDF): number {
let maxHeight = 0; let maxHeight = 0;
for (const element of this.elements) { for (const element of this.pdfElements) {
maxHeight = Math.max(maxHeight, element.getCheckNewPageHeight(doc)); maxHeight = Math.max(maxHeight, element.getCheckNewPageHeight(doc));
} }
return maxHeight; return maxHeight;
} }
public getElements(): AbstractElement[] {
const elements: AbstractElement[] = [];
for (const element of this.elements) {
elements.push(...element.getElements());
}
return elements;
}
public isEmpty(): boolean {
return this.elements.length === 0;
}
} }

View File

@@ -1,10 +1,18 @@
import { AbstractElement } from './abstract-element'; import { AbstractElement } from './abstract-element';
import jsPDF from 'jspdf'; import jsPDF from 'jspdf';
import { MARGINS } from '../constants'; import { MARGINS } from '../constants';
import { IContext } from './context';
import { GenerateTypeEnum } from './generate-type.enum';
export class Separator extends AbstractElement { export class Separator extends AbstractElement {
constructor(x: number, y: number, maxWidth?: number | undefined) { constructor(
super(x, y, maxWidth); globalType: GenerateTypeEnum,
x: number,
y: number,
maxWidth?: number | undefined,
context: Partial<IContext> = AbstractElement.DEFAULT_CONTEXT
) {
super(globalType, x, y, maxWidth, context);
} }
public getHeight(_doc?: jsPDF): number { public getHeight(_doc?: jsPDF): number {
@@ -33,6 +41,19 @@ export class Separator extends AbstractElement {
return doc; return doc;
} }
public renderHtml(
doc: Document,
parent: HTMLElement,
_cssRules: string[],
_sheet: HTMLStyleElement
): Document {
const div = doc.createElement('div');
div.classList.add(`separator`);
div.classList.add(this.context.name);
parent.append(div);
return doc;
}
public getElements(): AbstractElement[] { public getElements(): AbstractElement[] {
return [this]; return [this];
} }

View File

@@ -1,18 +1,22 @@
import { AbstractElement } from './abstract-element'; import { AbstractElement } from './abstract-element';
import jsPDF, { TextOptionsLight } from 'jspdf'; import jsPDF, { TextOptionsLight } from 'jspdf';
import { i18nLocalize, TEXT_SIZE } from '../constants'; import { HTML_TEXT_SIZE, i18nLocalize, TEXT_SIZE } from '../constants';
import { IContext } from './context';
import { GenerateTypeEnum } from './generate-type.enum';
export class Text extends AbstractElement { export class Text extends AbstractElement {
public text: string; public text: string;
public textOptions?: TextOptionsLight; public textOptions?: TextOptionsLight;
constructor( constructor(
globalType: GenerateTypeEnum,
x: number, x: number,
y: number, y: number,
text: string, text: string,
textOptions?: TextOptionsLight textOptions?: TextOptionsLight,
context: Partial<IContext> = AbstractElement.DEFAULT_CONTEXT
) { ) {
super(x, y, textOptions?.maxWidth); super(globalType, x, y, textOptions?.maxWidth, context);
this.text = text; this.text = text;
this.textOptions = textOptions; this.textOptions = textOptions;
} }
@@ -36,6 +40,27 @@ export class Text extends AbstractElement {
return doc; return doc;
} }
public renderHtml(
doc: Document,
parent: HTMLElement,
cssRules: string[],
sheet: HTMLStyleElement
): Document {
const text = doc.createElement('p');
const css = `text-${TEXT_SIZE}`;
text.classList.add(`ellipsis`);
text.classList.add(css);
text.classList.add(this.context.name);
text.innerHTML = i18nLocalize(i18nLocalize(this.text));
if (!cssRules.includes(css)) {
cssRules.push(css);
sheet.innerHTML += ` .${css} { font-size: ${HTML_TEXT_SIZE}rem }`;
sheet.innerHTML += ` .labelled-text > .${css} { font-size: ${HTML_TEXT_SIZE}rem; margin: 0; }`;
}
parent.append(text);
return doc;
}
protected updateMaxWidth(maxWidth?: number) { protected updateMaxWidth(maxWidth?: number) {
if (maxWidth != null && maxWidth > 0) { if (maxWidth != null && maxWidth > 0) {
this.maxWidth = maxWidth; this.maxWidth = maxWidth;

View File

@@ -4,19 +4,24 @@ import jsPDF from 'jspdf';
import { MARGINS } from '../constants'; import { MARGINS } from '../constants';
import { Text } from './text'; import { Text } from './text';
import { MultilineText } from './multiline-text'; import { MultilineText } from './multiline-text';
import { IContext } from './context';
import { AbstractElement } from './abstract-element';
import { GenerateTypeEnum } from './generate-type.enum';
export class Texts extends Row { export class Texts extends Row {
public texts: string[]; public texts: string[];
public nbrOfCol: number; public nbrOfCol: number;
constructor( constructor(
globalType: GenerateTypeEnum,
x: number, x: number,
y: number, y: number,
texts: string[], texts: string[],
nbrOfCol?: number, nbrOfCol?: number,
multiline = false multiline = false,
context: Partial<IContext> = AbstractElement.DEFAULT_CONTEXT
) { ) {
super(x, y, []); super(globalType, x, y, [], undefined, undefined, undefined, context);
this.texts = texts; this.texts = texts;
this.nbrOfCol = nbrOfCol ?? 4; this.nbrOfCol = nbrOfCol ?? 4;
if (this.nbrOfCol > 4) { if (this.nbrOfCol > 4) {
@@ -34,7 +39,7 @@ export class Texts extends Row {
rest > 3 ? nbrPerCol + 1 : nbrPerCol, rest > 3 ? nbrPerCol + 1 : nbrPerCol,
]; ];
for (let i = 0; i < this.nbrOfCol; i++) { for (let i = 0; i < this.nbrOfCol; i++) {
this.elements[i] = new Column(0, 0, []); this.contextElements[i] = new Column(this.globalType, 0, 0, []);
} }
for (let i = 0; i < texts.length; i++) { for (let i = 0; i < texts.length; i++) {
if (i < nbrPerCols[0]) { if (i < nbrPerCols[0]) {
@@ -46,25 +51,26 @@ export class Texts extends Row {
} else { } else {
currentIndex = 3; currentIndex = 3;
} }
(<Column>this.elements[currentIndex]).elements.push( (<Column>this.contextElements[currentIndex]).contextElements.push(
new Row(0, 0, [ new Row(this.globalType, 0, 0, [
multiline multiline
? new MultilineText(0, 0, texts[i]) ? new MultilineText(this.globalType, 0, 0, texts[i])
: new Text(0, 0, texts[i]), : new Text(this.globalType, 0, 0, texts[i]),
]) ])
); );
} }
} else { } else {
this.elements.push( this.contextElements.push(
new Column( new Column(
this.globalType,
0, 0,
0, 0,
texts.map( texts.map(
(text) => (text) =>
new Row(0, 0, [ new Row(this.globalType, 0, 0, [
multiline multiline
? new MultilineText(0, 0, text) ? new MultilineText(this.globalType, 0, 0, text)
: new Text(0, 0, text), : new Text(this.globalType, 0, 0, text),
]) ])
) )
) )
@@ -76,8 +82,8 @@ export class Texts extends Row {
public prepareRender(doc: jsPDF, maxWidth?: number): jsPDF { public prepareRender(doc: jsPDF, maxWidth?: number): jsPDF {
const pageWidth = doc.internal.pageSize.width; const pageWidth = doc.internal.pageSize.width;
const rowWidth = pageWidth - this.x - MARGINS.right; const rowWidth = pageWidth - this.x - MARGINS.right;
for (const column of this.elements) { for (const column of this.pdfElements) {
for (const labelledValue of (<Column>column).elements) { for (const labelledValue of (<Column>column).pdfElements) {
labelledValue.maxWidth = rowWidth / this.nbrOfCol; labelledValue.maxWidth = rowWidth / this.nbrOfCol;
} }
} }

94
src/html-builder.ts Normal file
View File

@@ -0,0 +1,94 @@
import { AbstractElement } from './elements/abstract-element';
import { AbstractBuilder } from './abstract-builder';
import { saveAs } from 'file-saver';
import {
HTML_LABEL_SIZE,
HTML_TEXT_SIZE,
i18n,
LABEL_SIZE,
TEXT_SIZE,
} from './constants';
import { GenerateTypeEnum } from './elements/generate-type.enum';
export class HtmlBuilder extends AbstractBuilder {
public doc: Document;
public styleSheet: HTMLStyleElement;
constructor() {
super();
this.doc = document.implementation.createHTMLDocument();
const style = document.createElement('style');
style.innerHTML = '.column { display: flex; flex-direction: column; }';
style.innerHTML += ' .main-column { align-items: center; }';
style.innerHTML += ' .row { display: flex; flex-direction: row }';
style.innerHTML += ' .row:not(.labelled-value) { gap: 5em; }';
style.innerHTML +=
' .row.labelled-value { gap: 10px; justify-content: space-between; }';
style.innerHTML +=
' .separator { border: 1px solid; width: 100%; height: 0px }';
style.appendChild(document.createTextNode(''));
this.doc.head.appendChild(style);
this.styleSheet = style;
const meta1 = document.createElement('meta');
meta1.setAttribute('charset', 'UTF-8');
this.doc.head.appendChild(meta1);
const meta2 = document.createElement('meta');
meta2.setAttribute('name', 'viewport');
meta2.setAttribute(
'content',
'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=yes'
);
this.doc.head.appendChild(meta2);
}
public getLabelledRowHeight(): number {
return 0;
}
public save(name: string) {
this.doc.title = name;
const blob = new Blob(
[
`<html lang="${i18n().lang}">
${this.doc.documentElement.innerHTML}
</html>`,
],
{ type: 'text/html;charset=utf-8' }
);
saveAs(blob, `${name}.html`);
}
public build(elements: AbstractElement[]) {
const cssList: string[] = [];
for (const element of elements.filter((el) => el.context.isHtml)) {
element.renderHtml(this.doc, this.doc.body, cssList, this.styleSheet);
}
// Mobile start
this.styleSheet.innerHTML += ' @media screen and (max-width: 959px) {';
this.styleSheet.innerHTML += ` .text-${TEXT_SIZE} { font-size: ${
2 * HTML_TEXT_SIZE
}rem; }`;
this.styleSheet.innerHTML += ` .labelled-text > .text-${TEXT_SIZE} { font-size: ${
2 * HTML_TEXT_SIZE
}rem; margin: 0; }`;
this.styleSheet.innerHTML += ` .label-${LABEL_SIZE} { font-size: ${
2 * HTML_LABEL_SIZE
}rem; }`;
this.styleSheet.innerHTML +=
' .main-column { align-items: stretch; overflow-x: hidden; }';
this.styleSheet.innerHTML +=
' .row:not(.labelled-value) { flex-wrap: wrap; gap: 0 5em; }';
this.styleSheet.innerHTML += ' .skills { width: 100%; }';
this.styleSheet.innerHTML += ' .skills-column { width: 100%; }';
this.styleSheet.innerHTML += ' }';
// Mobile end
}
public getImageScale(): number {
return 4;
}
public getGenerateType(): GenerateTypeEnum {
return GenerateTypeEnum.HTML;
}
}

View File

@@ -4,13 +4,7 @@ import { Row } from './elements/row';
import { Image } from './elements/image'; import { Image } from './elements/image';
import { Box } from './elements/box'; import { Box } from './elements/box';
import { Util } from './util'; import { Util } from './util';
import { import { i18nLocalize, isGM, MARGINS } from './constants';
i18nLocalize,
isGM,
LABEL_SIZE,
MARGINS,
TEXT_SIZE,
} from './constants';
import { ItemData } from '@league-of-foundry-developers/foundry-vtt-types/src/foundry/common/data/data.mjs'; import { ItemData } from '@league-of-foundry-developers/foundry-vtt-types/src/foundry/common/data/data.mjs';
import { LabelledValues } from './elements/labelled-values'; import { LabelledValues } from './elements/labelled-values';
import { Text } from './elements/text'; import { Text } from './elements/text';
@@ -18,9 +12,12 @@ import { Texts } from './elements/texts';
import { Column } from './elements/column'; import { Column } from './elements/column';
import { Separator } from './elements/separator'; import { Separator } from './elements/separator';
import { Blank } from './elements/blank'; import { Blank } from './elements/blank';
import { AbstractBuilder } from './abstract-builder';
import { HtmlBuilder } from './html-builder';
Hooks.on('getActorDirectoryEntryContext', async (_, options) => { Hooks.on('getActorDirectoryEntryContext', async (_, options) => {
options.push({ options.push(
{
name: i18nLocalize('WFRP4SHEETPRINT.export.pdf'), name: i18nLocalize('WFRP4SHEETPRINT.export.pdf'),
condition: isGM(), condition: isGM(),
icon: '<i class="fas fa-file-pdf"></i>', icon: '<i class="fas fa-file-pdf"></i>',
@@ -28,9 +25,26 @@ Hooks.on('getActorDirectoryEntryContext', async (_, options) => {
const actor: Actor & any = (<any>game).actors.get( const actor: Actor & any = (<any>game).actors.get(
target.attr('data-document-id') target.attr('data-document-id')
); );
await generatePdf(actor); const docBuilder = new PdfBuilder({
}, orientation: 'p',
unit: 'mm',
}); });
await generate(actor, docBuilder);
},
},
{
name: i18nLocalize('WFRP4SHEETPRINT.export.html'),
condition: isGM(),
icon: '<i class="fas fa-file-code"></i>',
callback: async (target) => {
const actor: Actor & any = (<any>game).actors.get(
target.attr('data-document-id')
);
const docBuilder = new HtmlBuilder();
await generate(actor, docBuilder);
},
}
);
}); });
Hooks.on( Hooks.on(
@@ -39,7 +53,11 @@ Hooks.on(
const actor: Actor & any = app.actor; const actor: Actor & any = app.actor;
addActorSheetActionButton(html, 'print', async () => { addActorSheetActionButton(html, 'print', async () => {
await generatePdf(actor); const docBuilder = new PdfBuilder({
orientation: 'p',
unit: 'mm',
});
await generate(actor, docBuilder);
}); });
} }
); );
@@ -60,7 +78,7 @@ function addActorSheetActionButton(
title.after(button); title.after(button);
} }
async function generatePdf(actor: Actor & any) { async function generate(actor: Actor & any, docBuilder: AbstractBuilder) {
const actorData = actor.data; const actorData = actor.data;
// @ts-ignore // @ts-ignore
const actorDetails = actorData.data.details; const actorDetails = actorData.data.details;
@@ -76,15 +94,8 @@ async function generatePdf(actor: Actor & any) {
const careerData: ItemData = currentCareer?.data; const careerData: ItemData = currentCareer?.data;
const careerDetail: any = careerData?.data; const careerDetail: any = careerData?.data;
const docBuilder = new PdfBuilder({
orientation: 'p',
unit: 'mm',
});
const labelledRowHeight =
Util.getHeightFromPx(docBuilder.doc, TEXT_SIZE + LABEL_SIZE) + 1;
const skills = new LabelledValues( const skills = new LabelledValues(
docBuilder.getGenerateType(),
0, 0,
0, 0,
actor.itemCategories.skill actor.itemCategories.skill
@@ -94,20 +105,32 @@ async function generatePdf(actor: Actor & any) {
value: item.data.data.total.value, value: item.data.data.total.value,
}; };
}) })
.sort((a, b) => a.label.localeCompare(b.label)) .sort((a, b) => a.label.localeCompare(b.label)),
undefined,
false,
{ name: 'skills' }
); );
const talentsByName: { [name: string]: { count: number; test: string } } = {};
actor.itemCategories.talent.forEach((item) => {
const name = item.name;
if (talentsByName[name] == null) {
talentsByName[name] = { count: 1, test: item.data.data.tests.value };
} else {
talentsByName[name].count++;
}
});
const talents = new LabelledValues( const talents = new LabelledValues(
docBuilder.getGenerateType(),
0, 0,
0, 0,
actor.itemCategories.talent Object.entries(talentsByName)
.map((item) => { .map(([name, value]) => {
return { return {
label: label: value.test.length > 0 ? `${name} : ${value.test}` : name,
item.data.data.tests.value.length > 0 value: value.count,
? `${item.name} : ${item.data.data.tests.value}`
: item.name,
value: item.data.data.advances.value,
}; };
}) })
.sort((a, b) => a.label.localeCompare(b.label)), .sort((a, b) => a.label.localeCompare(b.label)),
@@ -116,6 +139,7 @@ async function generatePdf(actor: Actor & any) {
); );
const traits = new Texts( const traits = new Texts(
docBuilder.getGenerateType(),
0, 0,
0, 0,
actor.itemCategories.trait actor.itemCategories.trait
@@ -127,6 +151,7 @@ async function generatePdf(actor: Actor & any) {
); );
const weaponsMelee = new Texts( const weaponsMelee = new Texts(
docBuilder.getGenerateType(),
0, 0,
0, 0,
Util.getActorItems(actor, 'weapon') Util.getActorItems(actor, 'weapon')
@@ -144,6 +169,7 @@ async function generatePdf(actor: Actor & any) {
); );
const weaponsRanged = new Texts( const weaponsRanged = new Texts(
docBuilder.getGenerateType(),
0, 0,
0, 0,
Util.getActorItems(actor, 'weapon') Util.getActorItems(actor, 'weapon')
@@ -161,6 +187,7 @@ async function generatePdf(actor: Actor & any) {
); );
const ammunitions = new Texts( const ammunitions = new Texts(
docBuilder.getGenerateType(),
0, 0,
0, 0,
Util.getActorItems(actor, 'ammunition') Util.getActorItems(actor, 'ammunition')
@@ -202,6 +229,7 @@ async function generatePdf(actor: Actor & any) {
} }
const armours = new Texts( const armours = new Texts(
docBuilder.getGenerateType(),
0, 0,
0, 0,
armourLocation.map((al) => { armourLocation.map((al) => {
@@ -214,6 +242,7 @@ async function generatePdf(actor: Actor & any) {
); );
const petty = new Texts( const petty = new Texts(
docBuilder.getGenerateType(),
0, 0,
0, 0,
actor.itemCategories.spell actor.itemCategories.spell
@@ -226,6 +255,7 @@ async function generatePdf(actor: Actor & any) {
); );
const spell = new Texts( const spell = new Texts(
docBuilder.getGenerateType(),
0, 0,
0, 0,
actor.itemCategories.spell actor.itemCategories.spell
@@ -238,6 +268,7 @@ async function generatePdf(actor: Actor & any) {
); );
const blessing = new Texts( const blessing = new Texts(
docBuilder.getGenerateType(),
0, 0,
0, 0,
actor.itemCategories.prayer actor.itemCategories.prayer
@@ -250,6 +281,7 @@ async function generatePdf(actor: Actor & any) {
); );
const miracle = new Texts( const miracle = new Texts(
docBuilder.getGenerateType(),
0, 0,
0, 0,
actor.itemCategories.prayer actor.itemCategories.prayer
@@ -275,6 +307,7 @@ async function generatePdf(actor: Actor & any) {
} }
const trappingsHeader = new Texts( const trappingsHeader = new Texts(
docBuilder.getGenerateType(),
0, 0,
0, 0,
[ [
@@ -289,6 +322,7 @@ async function generatePdf(actor: Actor & any) {
); );
const trappings = new Texts( const trappings = new Texts(
docBuilder.getGenerateType(),
0, 0,
0, 0,
Util.getAllActorItems(actor, ['container', 'trapping']) Util.getAllActorItems(actor, ['container', 'trapping'])
@@ -307,6 +341,7 @@ async function generatePdf(actor: Actor & any) {
); );
const critical = new Texts( const critical = new Texts(
docBuilder.getGenerateType(),
0, 0,
0, 0,
actor.itemCategories.critical.map((i) => { actor.itemCategories.critical.map((i) => {
@@ -316,6 +351,7 @@ async function generatePdf(actor: Actor & any) {
); );
const disease = new Texts( const disease = new Texts(
docBuilder.getGenerateType(),
0, 0,
0, 0,
actor.itemCategories.disease.map((i) => { actor.itemCategories.disease.map((i) => {
@@ -325,6 +361,7 @@ async function generatePdf(actor: Actor & any) {
); );
const injury = new Texts( const injury = new Texts(
docBuilder.getGenerateType(),
0, 0,
0, 0,
actor.itemCategories.injury.map((i) => { actor.itemCategories.injury.map((i) => {
@@ -334,6 +371,7 @@ async function generatePdf(actor: Actor & any) {
); );
const mutationP = new Texts( const mutationP = new Texts(
docBuilder.getGenerateType(),
0, 0,
0, 0,
actor.itemCategories.mutation actor.itemCategories.mutation
@@ -345,6 +383,7 @@ async function generatePdf(actor: Actor & any) {
); );
const mutationM = new Texts( const mutationM = new Texts(
docBuilder.getGenerateType(),
0, 0,
0, 0,
actor.itemCategories.mutation actor.itemCategories.mutation
@@ -356,6 +395,7 @@ async function generatePdf(actor: Actor & any) {
); );
const psychology = new Texts( const psychology = new Texts(
docBuilder.getGenerateType(),
0, 0,
0, 0,
actor.itemCategories.psychology.map((i) => { actor.itemCategories.psychology.map((i) => {
@@ -364,107 +404,464 @@ async function generatePdf(actor: Actor & any) {
3 3
); );
const imageWidth = 25; const labelledRowHeight = docBuilder.getLabelledRowHeight();
const imageWidth = 25 * docBuilder.getImageScale();
const imageY = labelledRowHeight + MARGINS.top + 2; const imageY = labelledRowHeight + MARGINS.top + 2;
const actorImageElement = const actorImageElementPdf =
actorImageData != null actorImageData != null
? new Image(0, imageY, imageWidth, imageWidth, actorImageData) ? new Image(
: new Box(0, imageY, imageWidth, imageWidth); docBuilder.getGenerateType(),
0,
imageY,
imageWidth,
imageWidth,
actorImageData,
{
isHtml: false,
}
)
: new Box(
docBuilder.getGenerateType(),
0,
imageY,
imageWidth,
imageWidth,
{
isHtml: false,
}
);
const actorImageElementHtml =
actorImageData != null
? new Image(
docBuilder.getGenerateType(),
0,
imageY,
imageWidth,
imageWidth,
actorImageData,
{
isPdf: false,
}
)
: new Box(
docBuilder.getGenerateType(),
0,
imageY,
imageWidth,
imageWidth,
{
isPdf: false,
}
);
docBuilder.build([ docBuilder.build([
actorImageElement, actorImageElementPdf,
new Column(0, 0, [ new Column(
new Row(0, 0, [ docBuilder.getGenerateType(),
new LabelledText(0, 0, 'Name', `${actor.name}`), 0,
new LabelledText(0, 0, 'Species', `${actorDetails?.species?.value}`), 0,
new LabelledText(0, 0, 'Gender', `${actorDetails?.gender?.value}`), [
]), new Row(docBuilder.getGenerateType(), 0, 0, [
new Row(imageWidth + MARGINS.left + 1, 0, [
new LabelledText(0, 0, 'Class', `${careerDetail?.class?.value}`),
new LabelledText( new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Name',
`${actor.name}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Species',
`${actorDetails?.species?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Gender',
`${actorDetails?.gender?.value}`
),
]),
new Row(
docBuilder.getGenerateType(),
imageWidth + MARGINS.left + 1,
0,
[
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Class',
`${careerDetail?.class?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0, 0,
0, 0,
'Career Group', 'Career Group',
`${careerDetail?.careergroup?.value}` `${careerDetail?.careergroup?.value}`
), ),
new LabelledText(0, 0, 'Career', `${currentCareer?.name}`),
]),
new Row(imageWidth + MARGINS.left + 1, 0, [
new LabelledText(0, 0, 'Status', `${actorDetails?.status?.value}`),
new LabelledText(0, 0, 'Age', `${actorDetails?.age?.value}`),
new LabelledText(0, 0, 'Height', `${actorDetails?.height?.value}`),
new LabelledText(0, 0, 'Weight', `${actorDetails?.weight?.value}`),
new LabelledText( new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Career',
`${currentCareer?.name}`
),
],
undefined,
undefined,
undefined,
{ isHtml: false }
),
new Row(
docBuilder.getGenerateType(),
imageWidth + MARGINS.left + 1,
0,
[
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Status',
`${actorDetails?.status?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Age',
`${actorDetails?.age?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Height',
`${actorDetails?.height?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Weight',
`${actorDetails?.weight?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0, 0,
0, 0,
'Hair Colour', 'Hair Colour',
`${actorDetails?.haircolour?.value}` `${actorDetails?.haircolour?.value}`
), ),
]), ],
new Row(imageWidth + MARGINS.left + 1, 0, [ undefined,
undefined,
undefined,
{ isHtml: false }
),
new Row(
docBuilder.getGenerateType(),
imageWidth + MARGINS.left + 1,
0,
[
new LabelledText( new LabelledText(
docBuilder.getGenerateType(),
0, 0,
0, 0,
'Eye Colour', 'Eye Colour',
`${actorDetails?.eyecolour?.value}` `${actorDetails?.eyecolour?.value}`
), ),
new LabelledText( new LabelledText(
docBuilder.getGenerateType(),
0, 0,
0, 0,
'Distinguishing Mark', 'Distinguishing Mark',
`${actorDetails?.distinguishingmark?.value}` `${actorDetails?.distinguishingmark?.value}`
), ),
new LabelledText(0, 0, 'Star Sign', `${actorDetails?.starsign?.value}`),
]),
Blank.heightBlank(2),
new Row(0, 0, [
new LabelledText(0, 0, 'CHARAbbrev.WS', `${actorCharacs?.ws?.value}`),
new LabelledText(0, 0, 'CHARAbbrev.BS', `${actorCharacs?.bs?.value}`),
new LabelledText(0, 0, 'CHARAbbrev.S', `${actorCharacs?.s?.value}`),
new LabelledText(0, 0, 'CHARAbbrev.T', `${actorCharacs?.t?.value}`),
new LabelledText(0, 0, 'CHARAbbrev.I', `${actorCharacs?.i?.value}`),
new LabelledText(0, 0, 'CHARAbbrev.Ag', `${actorCharacs?.ag?.value}`),
new LabelledText(0, 0, 'CHARAbbrev.Dex', `${actorCharacs?.dex?.value}`),
new LabelledText(0, 0, 'CHARAbbrev.Int', `${actorCharacs?.int?.value}`),
new LabelledText(0, 0, 'CHARAbbrev.WP', `${actorCharacs?.wp?.value}`),
new LabelledText(0, 0, 'CHARAbbrev.Fel', `${actorCharacs?.fel?.value}`),
]),
new Row(0, 0, [
new LabelledText(0, 0, 'Move', `${actorDetails?.move?.value}`),
new LabelledText(0, 0, 'Walk', `${actorDetails?.move?.walk}`),
new LabelledText(0, 0, 'Run', `${actorDetails?.move?.run}`),
new LabelledText(0, 0, 'Fortune', `${actorStatus?.fortune?.value}`),
new LabelledText(0, 0, 'Fate', `${actorStatus?.fate?.value}`),
new LabelledText(0, 0, 'Resolve', `${actorStatus?.resolve?.value}`),
new LabelledText( new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Star Sign',
`${actorDetails?.starsign?.value}`
),
],
undefined,
undefined,
undefined,
{ isHtml: false }
),
new Row(
docBuilder.getGenerateType(),
0,
0,
[
actorImageElementHtml,
new Column(docBuilder.getGenerateType(), 0, 0, [
new Row(
docBuilder.getGenerateType(),
imageWidth + MARGINS.left + 1,
0,
[
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Class',
`${careerDetail?.class?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Career Group',
`${careerDetail?.careergroup?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Career',
`${currentCareer?.name}`
),
]
),
new Row(
docBuilder.getGenerateType(),
imageWidth + MARGINS.left + 1,
0,
[
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Status',
`${actorDetails?.status?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Age',
`${actorDetails?.age?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Height',
`${actorDetails?.height?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Weight',
`${actorDetails?.weight?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Hair Colour',
`${actorDetails?.haircolour?.value}`
),
]
),
new Row(
docBuilder.getGenerateType(),
imageWidth + MARGINS.left + 1,
0,
[
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Eye Colour',
`${actorDetails?.eyecolour?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Distinguishing Mark',
`${actorDetails?.distinguishingmark?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Star Sign',
`${actorDetails?.starsign?.value}`
),
]
),
]),
],
undefined,
undefined,
undefined,
{ isPdf: false }
),
Blank.heightBlank(docBuilder.getGenerateType(), 2),
new Row(docBuilder.getGenerateType(), 0, 0, [
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'CHARAbbrev.WS',
`${actorCharacs?.ws?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'CHARAbbrev.BS',
`${actorCharacs?.bs?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'CHARAbbrev.S',
`${actorCharacs?.s?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'CHARAbbrev.T',
`${actorCharacs?.t?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'CHARAbbrev.I',
`${actorCharacs?.i?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'CHARAbbrev.Ag',
`${actorCharacs?.ag?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'CHARAbbrev.Dex',
`${actorCharacs?.dex?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'CHARAbbrev.Int',
`${actorCharacs?.int?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'CHARAbbrev.WP',
`${actorCharacs?.wp?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'CHARAbbrev.Fel',
`${actorCharacs?.fel?.value}`
),
]),
new Row(docBuilder.getGenerateType(), 0, 0, [
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Move',
`${actorDetails?.move?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Walk',
`${actorDetails?.move?.walk}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Run',
`${actorDetails?.move?.run}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Fortune',
`${actorStatus?.fortune?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Fate',
`${actorStatus?.fate?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0,
0,
'Resolve',
`${actorStatus?.resolve?.value}`
),
new LabelledText(
docBuilder.getGenerateType(),
0, 0,
0, 0,
'Resilience', 'Resilience',
`${actorStatus?.resilience?.value}` `${actorStatus?.resilience?.value}`
), ),
new LabelledText( new LabelledText(
docBuilder.getGenerateType(),
0, 0,
0, 0,
'Wounds', 'Wounds',
`${actorStatus?.wounds?.value}/${actorStatus?.wounds?.max}` `${actorStatus?.wounds?.value}/${actorStatus?.wounds?.max}`
), ),
]), ]),
new Separator(0, 0), new Separator(docBuilder.getGenerateType(), 0, 0),
new Text(0, 0, 'Skills'), new Text(docBuilder.getGenerateType(), 0, 0, 'Skills'),
skills, skills,
new Separator(0, 0), new Separator(docBuilder.getGenerateType(), 0, 0),
new Text(0, 0, `${i18nLocalize('Talents')} : ${i18nLocalize('Tests')}`), new Text(
docBuilder.getGenerateType(),
0,
0,
`${i18nLocalize('Talents')} : ${i18nLocalize('Tests')}`
),
talents, talents,
traits.elements.length > 0 ? new Separator(0, 0) : Blank.heightBlank(0), traits.contextElements.length > 0
traits.elements.length > 0 ? new Separator(docBuilder.getGenerateType(), 0, 0)
? new Text(0, 0, 'Traits') : Blank.heightBlank(docBuilder.getGenerateType(), 0),
: Blank.heightBlank(0), traits.contextElements.length > 0
? new Text(docBuilder.getGenerateType(), 0, 0, 'Traits')
: Blank.heightBlank(docBuilder.getGenerateType(), 0),
traits, traits,
weaponsMelee.elements.length > 0 weaponsMelee.contextElements.length > 0
? new Separator(0, 0) ? new Separator(docBuilder.getGenerateType(), 0, 0)
: Blank.heightBlank(0), : Blank.heightBlank(docBuilder.getGenerateType(), 0),
weaponsMelee.elements.length > 0 weaponsMelee.contextElements.length > 0
? new Text( ? new Text(
docBuilder.getGenerateType(),
0, 0,
0, 0,
`${i18nLocalize('SHEET.MeleeWeaponHeader')} : ${i18nLocalize( `${i18nLocalize('SHEET.MeleeWeaponHeader')} : ${i18nLocalize(
@@ -473,13 +870,14 @@ async function generatePdf(actor: Actor & any) {
'Damage' 'Damage'
)}, ${i18nLocalize('Qualities')}, ${i18nLocalize('Flaws')}` )}, ${i18nLocalize('Qualities')}, ${i18nLocalize('Flaws')}`
) )
: Blank.heightBlank(0), : Blank.heightBlank(docBuilder.getGenerateType(), 0),
weaponsMelee, weaponsMelee,
weaponsRanged.elements.length > 0 weaponsRanged.contextElements.length > 0
? new Separator(0, 0) ? new Separator(docBuilder.getGenerateType(), 0, 0)
: Blank.heightBlank(0), : Blank.heightBlank(docBuilder.getGenerateType(), 0),
weaponsRanged.elements.length > 0 weaponsRanged.contextElements.length > 0
? new Text( ? new Text(
docBuilder.getGenerateType(),
0, 0,
0, 0,
`${i18nLocalize('SHEET.RangedWeaponHeader')} : ${i18nLocalize( `${i18nLocalize('SHEET.RangedWeaponHeader')} : ${i18nLocalize(
@@ -488,13 +886,14 @@ async function generatePdf(actor: Actor & any) {
'Damage' 'Damage'
)}, ${i18nLocalize('Qualities')}, ${i18nLocalize('Flaws')}` )}, ${i18nLocalize('Qualities')}, ${i18nLocalize('Flaws')}`
) )
: Blank.heightBlank(0), : Blank.heightBlank(docBuilder.getGenerateType(), 0),
weaponsRanged, weaponsRanged,
ammunitions.elements.length > 0 ammunitions.contextElements.length > 0
? new Separator(0, 0) ? new Separator(docBuilder.getGenerateType(), 0, 0)
: Blank.heightBlank(0), : Blank.heightBlank(docBuilder.getGenerateType(), 0),
ammunitions.elements.length > 0 ammunitions.contextElements.length > 0
? new Text( ? new Text(
docBuilder.getGenerateType(),
0, 0,
0, 0,
`${i18nLocalize('Ammunition')} : ${i18nLocalize( `${i18nLocalize('Ammunition')} : ${i18nLocalize(
@@ -503,16 +902,21 @@ async function generatePdf(actor: Actor & any) {
'Qualities' 'Qualities'
)}, ${i18nLocalize('Flaws')}` )}, ${i18nLocalize('Flaws')}`
) )
: Blank.heightBlank(0), : Blank.heightBlank(docBuilder.getGenerateType(), 0),
ammunitions, ammunitions,
armours.elements.length > 0 ? new Separator(0, 0) : Blank.heightBlank(0), armours.contextElements.length > 0
armours.elements.length > 0 ? new Separator(docBuilder.getGenerateType(), 0, 0)
? new Text(0, 0, 'Armour') : Blank.heightBlank(docBuilder.getGenerateType(), 0),
: Blank.heightBlank(0), armours.contextElements.length > 0
? new Text(docBuilder.getGenerateType(), 0, 0, 'Armour')
: Blank.heightBlank(docBuilder.getGenerateType(), 0),
armours, armours,
petty.elements.length > 0 ? new Separator(0, 0) : Blank.heightBlank(0), petty.contextElements.length > 0
petty.elements.length > 0 ? new Separator(docBuilder.getGenerateType(), 0, 0)
: Blank.heightBlank(docBuilder.getGenerateType(), 0),
petty.contextElements.length > 0
? new Text( ? new Text(
docBuilder.getGenerateType(),
0, 0,
0, 0,
`${i18nLocalize('SHEET.PettySpell')} : ${i18nLocalize( `${i18nLocalize('SHEET.PettySpell')} : ${i18nLocalize(
@@ -521,11 +925,14 @@ async function generatePdf(actor: Actor & any) {
'Target' 'Target'
)}, ${i18nLocalize('Duration')}` )}, ${i18nLocalize('Duration')}`
) )
: Blank.heightBlank(0), : Blank.heightBlank(docBuilder.getGenerateType(), 0),
petty, petty,
spell.elements.length > 0 ? new Separator(0, 0) : Blank.heightBlank(0), spell.contextElements.length > 0
spell.elements.length > 0 ? new Separator(docBuilder.getGenerateType(), 0, 0)
: Blank.heightBlank(docBuilder.getGenerateType(), 0),
spell.contextElements.length > 0
? new Text( ? new Text(
docBuilder.getGenerateType(),
0, 0,
0, 0,
`${i18nLocalize('SHEET.LoreSpell')} : ${i18nLocalize( `${i18nLocalize('SHEET.LoreSpell')} : ${i18nLocalize(
@@ -536,78 +943,96 @@ async function generatePdf(actor: Actor & any) {
'WFRP4E.TrappingType.Ingredients' 'WFRP4E.TrappingType.Ingredients'
)}` )}`
) )
: Blank.heightBlank(0), : Blank.heightBlank(docBuilder.getGenerateType(), 0),
spell, spell,
blessing.elements.length > 0 ? new Separator(0, 0) : Blank.heightBlank(0), blessing.contextElements.length > 0
blessing.elements.length > 0 ? new Separator(docBuilder.getGenerateType(), 0, 0)
: Blank.heightBlank(docBuilder.getGenerateType(), 0),
blessing.contextElements.length > 0
? new Text( ? new Text(
docBuilder.getGenerateType(),
0, 0,
0, 0,
`${i18nLocalize('Blessing')} : ${i18nLocalize( `${i18nLocalize('Blessing')} : ${i18nLocalize(
'Range' 'Range'
)}, ${i18nLocalize('Target')}, ${i18nLocalize('Duration')}` )}, ${i18nLocalize('Target')}, ${i18nLocalize('Duration')}`
) )
: Blank.heightBlank(0), : Blank.heightBlank(docBuilder.getGenerateType(), 0),
blessing, blessing,
miracle.elements.length > 0 ? new Separator(0, 0) : Blank.heightBlank(0), miracle.contextElements.length > 0
miracle.elements.length > 0 ? new Separator(docBuilder.getGenerateType(), 0, 0)
: Blank.heightBlank(docBuilder.getGenerateType(), 0),
miracle.contextElements.length > 0
? new Text( ? new Text(
docBuilder.getGenerateType(),
0, 0,
0, 0,
`${i18nLocalize('Miracle')} : ${i18nLocalize( `${i18nLocalize('Miracle')} : ${i18nLocalize(
'Range' 'Range'
)}, ${i18nLocalize('Target')}, ${i18nLocalize('Duration')}` )}, ${i18nLocalize('Target')}, ${i18nLocalize('Duration')}`
) )
: Blank.heightBlank(0), : Blank.heightBlank(docBuilder.getGenerateType(), 0),
miracle, miracle,
new Separator(0, 0), new Separator(docBuilder.getGenerateType(), 0, 0),
trappingsHeader, trappingsHeader,
trappings, trappings,
psychology.elements.length > 0 psychology.contextElements.length > 0
? new Separator(0, 0) ? new Separator(docBuilder.getGenerateType(), 0, 0)
: Blank.heightBlank(0), : Blank.heightBlank(docBuilder.getGenerateType(), 0),
psychology.elements.length > 0 psychology.contextElements.length > 0
? new Text(0, 0, 'Psychology') ? new Text(docBuilder.getGenerateType(), 0, 0, 'Psychology')
: Blank.heightBlank(0), : Blank.heightBlank(docBuilder.getGenerateType(), 0),
psychology, psychology,
critical.elements.length > 0 ? new Separator(0, 0) : Blank.heightBlank(0), critical.contextElements.length > 0
critical.elements.length > 0 ? new Separator(docBuilder.getGenerateType(), 0, 0)
? new Text(0, 0, 'Criticals') : Blank.heightBlank(docBuilder.getGenerateType(), 0),
: Blank.heightBlank(0), critical.contextElements.length > 0
? new Text(docBuilder.getGenerateType(), 0, 0, 'Criticals')
: Blank.heightBlank(docBuilder.getGenerateType(), 0),
critical, critical,
disease.elements.length > 0 ? new Separator(0, 0) : Blank.heightBlank(0), disease.contextElements.length > 0
disease.elements.length > 0 ? new Separator(docBuilder.getGenerateType(), 0, 0)
? new Text(0, 0, 'Diseases') : Blank.heightBlank(docBuilder.getGenerateType(), 0),
: Blank.heightBlank(0), disease.contextElements.length > 0
? new Text(docBuilder.getGenerateType(), 0, 0, 'Diseases')
: Blank.heightBlank(docBuilder.getGenerateType(), 0),
disease, disease,
injury.elements.length > 0 ? new Separator(0, 0) : Blank.heightBlank(0), injury.contextElements.length > 0
injury.elements.length > 0 ? new Separator(docBuilder.getGenerateType(), 0, 0)
? new Text(0, 0, 'Injuries') : Blank.heightBlank(docBuilder.getGenerateType(), 0),
: Blank.heightBlank(0), injury.contextElements.length > 0
? new Text(docBuilder.getGenerateType(), 0, 0, 'Injuries')
: Blank.heightBlank(docBuilder.getGenerateType(), 0),
injury, injury,
mutationP.elements.length > 0 mutationP.contextElements.length > 0
? new Separator(0, 0) ? new Separator(docBuilder.getGenerateType(), 0, 0)
: Blank.heightBlank(0), : Blank.heightBlank(docBuilder.getGenerateType(), 0),
mutationP.elements.length > 0 mutationP.contextElements.length > 0
? new Text( ? new Text(
docBuilder.getGenerateType(),
0, 0,
0, 0,
`${i18nLocalize('Mutations')} (${i18nLocalize('Physical')})` `${i18nLocalize('Mutations')} (${i18nLocalize('Physical')})`
) )
: Blank.heightBlank(0), : Blank.heightBlank(docBuilder.getGenerateType(), 0),
mutationP, mutationP,
mutationM.elements.length > 0 mutationM.contextElements.length > 0
? new Separator(0, 0) ? new Separator(docBuilder.getGenerateType(), 0, 0)
: Blank.heightBlank(0), : Blank.heightBlank(docBuilder.getGenerateType(), 0),
mutationM.elements.length > 0 mutationM.contextElements.length > 0
? new Text( ? new Text(
docBuilder.getGenerateType(),
0, 0,
0, 0,
`${i18nLocalize('Mutations')} (${i18nLocalize('Mental')})` `${i18nLocalize('Mutations')} (${i18nLocalize('Mental')})`
) )
: Blank.heightBlank(0), : Blank.heightBlank(docBuilder.getGenerateType(), 0),
mutationM, mutationM,
]), ],
{
name: 'main-column',
}
),
]); ]);
docBuilder.doc.save(`${actor.name}.pdf`); docBuilder.save(`${actor.name}`);
} }

View File

@@ -1,17 +1,29 @@
import jsPDF, { jsPDFOptions } from 'jspdf'; import jsPDF, { jsPDFOptions } from 'jspdf';
import { AbstractElement } from './elements/abstract-element'; import { AbstractElement } from './elements/abstract-element';
import { MARGINS } from './constants'; import { LABEL_SIZE, MARGINS, TEXT_SIZE } from './constants';
import { AbstractBuilder } from './abstract-builder';
import { Util } from './util';
import { GenerateTypeEnum } from './elements/generate-type.enum';
export class PdfBuilder { export class PdfBuilder extends AbstractBuilder {
public doc: jsPDF; public doc: jsPDF;
constructor(options: jsPDFOptions) { constructor(options: jsPDFOptions) {
super();
this.doc = new jsPDF(options); this.doc = new jsPDF(options);
} }
public getLabelledRowHeight(): number {
return Util.getHeightFromPx(this.doc, TEXT_SIZE + LABEL_SIZE) + 1;
}
public save(name: string) {
this.doc.save(`${name}.pdf`);
}
public build(elements: AbstractElement[]) { public build(elements: AbstractElement[]) {
const finalElements: AbstractElement[] = []; const finalElements: AbstractElement[] = [];
for (const element of elements) { for (const element of elements.filter((el) => el.context.isPdf)) {
element.prepareRender(this.doc); element.prepareRender(this.doc);
finalElements.push(...element.getElements()); finalElements.push(...element.getElements());
} }
@@ -58,4 +70,12 @@ export class PdfBuilder {
} }
} }
} }
public getImageScale(): number {
return 1;
}
public getGenerateType(): GenerateTypeEnum {
return GenerateTypeEnum.PDF;
}
} }