Compare commits

...

10 Commits

Author SHA1 Message Date
1106b9648d 1.6.11
Some checks failed
Default (tags) / security (push) Failing after 2s
Default (tags) / test (push) Failing after 1s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-01-01 04:57:29 +01:00
1f06a73422 fix(license): Update copyright notice in license to reflect new ownership 2025-01-01 04:57:29 +01:00
7d5508e4d8 1.6.10
Some checks failed
Default (tags) / security (push) Failing after 0s
Default (tags) / test (push) Failing after 0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2024-12-08 22:08:59 +01:00
67ae3ac22b fix(core): Improve stability and performance of document generation 2024-12-08 22:08:59 +01:00
389db4f014 1.6.9
Some checks failed
Default (tags) / security (push) Failing after 0s
Default (tags) / test (push) Failing after 0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2024-12-08 17:37:17 +01:00
60fd21c6d3 fix(contentinvoice.ts): Improve invoice item layout and fix alignment issues. 2024-12-08 17:37:17 +01:00
89cc610aa0 1.6.8
Some checks failed
Default (tags) / security (push) Failing after 1s
Default (tags) / test (push) Failing after 0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2024-12-07 15:38:17 +01:00
db9b53462d fix(rendering and logging): remove extensive console chattiness, remove content memory leak when rerendering 2024-12-07 15:38:17 +01:00
dbca81987c 1.6.7
Some checks failed
Default (tags) / security (push) Failing after 0s
Default (tags) / test (push) Failing after 0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2024-12-07 14:22:42 +01:00
2e3739e765 fix(document rendering): Fixed overflow issues in document and page elements 2024-12-07 14:22:42 +01:00
9 changed files with 167 additions and 42 deletions

View File

@ -1,5 +1,33 @@
# Changelog # Changelog
## 2025-01-01 - 1.6.11 - fix(license)
Update copyright notice in license to reflect new ownership
- Updated copyright from Lossless GmbH to Task Venture Capital GmbH.
## 2024-12-08 - 1.6.10 - fix(core)
Improve stability and performance of document generation
## 2024-12-08 - 1.6.9 - fix(contentinvoice.ts)
Improve invoice item layout and fix alignment issues.
- Fixed missing border on last invoice item.
- Added highlighted style for invoice lines.
- Corrected alignment and display of invoice item details.
- Included VAT percentage display adjustments.
## 2024-12-07 - 1.6.8 - fix(rendering and logging)
Removed debug logging from document rendering process.
- Removed console logs from content invoice, document rendering, page scaling, and overflow checking.
## 2024-12-07 - 1.6.7 - fix(document rendering)
Fixed overflow issues in document and page elements
- Ensured content overflow handling in document.ts
- Adjusted page element overflow settings in page.ts
## 2024-12-07 - 1.6.6 - fix(page-render) ## 2024-12-07 - 1.6.6 - fix(page-render)
Fix layout scaling adjustment for page component Fix layout scaling adjustment for page component

View File

@ -1,4 +1,4 @@
Copyright (c) 2022 Lossless GmbH (hello@lossless.com) Copyright (c) 2022 Task Venture Capital GmbH (hello@task.vc)
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -16,4 +16,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.

View File

@ -1,6 +1,6 @@
{ {
"name": "@design.estate/dees-document", "name": "@design.estate/dees-document",
"version": "1.6.6", "version": "1.6.11",
"private": false, "private": false,
"description": "A sophisticated framework for dynamically generating and rendering business documents like invoices with modern web technologies, featuring PDF creation, templating, and automation.", "description": "A sophisticated framework for dynamically generating and rendering business documents like invoices with modern web technologies, featuring PDF creation, templating, and automation.",
"main": "dist_ts_web/index.js", "main": "dist_ts_web/index.js",

View File

@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@design.estate/dees-document', name: '@design.estate/dees-document',
version: '1.6.6', version: '1.6.11',
description: 'A sophisticated framework for dynamically generating and rendering business documents like invoices with modern web technologies, featuring PDF creation, templating, and automation.' description: 'A sophisticated framework for dynamically generating and rendering business documents like invoices with modern web technologies, featuring PDF creation, templating, and automation.'
} }

View File

@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@design.estate/dees-document', name: '@design.estate/dees-document',
version: '1.6.6', version: '1.6.11',
description: 'A sophisticated framework for dynamically generating and rendering business documents like invoices with modern web technologies, featuring PDF creation, templating, and automation.' description: 'A sophisticated framework for dynamically generating and rendering business documents like invoices with modern web technologies, featuring PDF creation, templating, and automation.'
} }

View File

@ -18,7 +18,6 @@ import * as plugins from '../plugins.js';
import { dedocumentSharedStyle } from '../style.js'; import { dedocumentSharedStyle } from '../style.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
'dedocument-contentinvoice': DeContentInvoice; 'dedocument-contentinvoice': DeContentInvoice;
@ -175,7 +174,6 @@ export class DeContentInvoice extends DeesElement {
(await this.getContentNodes()).trimmedContent.append( (await this.getContentNodes()).trimmedContent.append(
(await this.getContentNodes()).currentContent.children.item(0) (await this.getContentNodes()).currentContent.children.item(0)
); );
console.log('hey' + this.shadowRoot.children.length);
} }
if ( if (
(await this.getContentNodes()).currentContent.children (await this.getContentNodes()).currentContent.children
@ -220,14 +218,26 @@ export class DeContentInvoice extends DeesElement {
border-right: 1px dashed #ccc; border-right: 1px dashed #ccc;
} }
.lineItem:last-child {
border-right: none;
}
.lineItem.rightAlign { .lineItem.rightAlign {
text-align: right; text-align: right;
} }
.invoiceLine { .invoiceLine {
background: #ffffff00;
border-bottom: 1px dotted #ccc; border-bottom: 1px dotted #ccc;
} }
.invoiceLine.highlighted {
transition: background 0.2s;
background: #ffc18f;
border: 1px solid #ff9d4d;
box-sizing: content-box;
}
.sums { .sums {
margin-top: 5px; margin-top: 5px;
font-size: 12px; font-size: 12px;
@ -287,33 +297,77 @@ export class DeContentInvoice extends DeesElement {
</style> </style>
<div>We hereby invoice products and services provided to you by Lossless GmbH:</div> <div>We hereby invoice products and services provided to you by Lossless GmbH:</div>
<div class="grid topLine dataHeader"> <div class="grid topLine dataHeader">
<div class="lineItem rightAlign">${plugins.shared.translation.translate(this.documentSettings.languageCode, 'itemPos', 'Item Pos.')}</div> <div class="lineItem rightAlign">
<div class="lineItem">${plugins.shared.translation.translate(this.documentSettings.languageCode, 'description', 'Description')}</div> ${plugins.shared.translation.translate(
<div class="lineItem rightAlign">${plugins.shared.translation.translate(this.documentSettings.languageCode, 'quantity', 'Quantity')}</div> this.documentSettings.languageCode,
<div class="lineItem">${plugins.shared.translation.translate(this.documentSettings.languageCode, 'unitType', 'Unit Type')}</div> 'itemPos',
<div class="lineItem rightAlign">${plugins.shared.translation.translate(this.documentSettings.languageCode, 'unitNetPrice', 'Unit Net Price')}</div> 'Item Pos.'
<div class="lineItem rightAlign">${plugins.shared.translation.translate(this.documentSettings.languageCode, 'totalNetPrice', 'Total Net Price')}</div> )}
<div class="lineItem rightAlign">${plugins.shared.translation.translate(this.documentSettings.languageCode, 'vatShort', 'VAT')}</div> </div>
<div class="lineItem">
${plugins.shared.translation.translate(
this.documentSettings.languageCode,
'description',
'Description'
)}
</div>
<div class="lineItem rightAlign">
${plugins.shared.translation.translate(
this.documentSettings.languageCode,
'quantity',
'Quantity'
)}
</div>
<div class="lineItem">
${plugins.shared.translation.translate(
this.documentSettings.languageCode,
'unitType',
'Unit Type'
)}
</div>
<div class="lineItem rightAlign">
${plugins.shared.translation.translate(
this.documentSettings.languageCode,
'unitNetPrice',
'Unit Net Price'
)}
</div>
<div class="lineItem rightAlign">
${plugins.shared.translation.translate(
this.documentSettings.languageCode,
'totalNetPrice',
'Total Net Price'
)}
</div>
<div class="lineItem rightAlign">
${plugins.shared.translation.translate(
this.documentSettings.languageCode,
'vatShort',
'VAT'
)}
</div>
</div> </div>
${(() => { ${(() => {
let counter = 1; let counter = 1;
return this.letterData?.content.invoiceData?.items?.map( return this.letterData?.content.invoiceData?.items?.map((invoiceItem) => {
(invoiceItem) => html` const isHighlighted = false; // TODO: implement rest of highlight logic
<div class="grid invoiceLine needsDataHeader"> return html`
<div class="grid invoiceLine needsDataHeader ${isHighlighted ? 'highlighted' : ''}">
<div class="lineItem rightAlign">${counter++}</div> <div class="lineItem rightAlign">${counter++}</div>
<div class="lineItem">${invoiceItem.name}</div> <div class="lineItem">${invoiceItem.name}</div>
<div class="lineItem rightAlign">${invoiceItem.unitQuantity}</div> <div class="lineItem rightAlign">${invoiceItem.unitQuantity}</div>
<div class="lineItem">${invoiceItem.unitType}</div> <div class="lineItem">${invoiceItem.unitType}</div>
<div class="lineItem rightAlign">${invoiceItem.unitNetPrice} ${this.letterData?.content.invoiceData.currency}</div>
<div class="lineItem rightAlign"> <div class="lineItem rightAlign">
${invoiceItem.unitQuantity * invoiceItem.unitNetPrice} ${this.letterData?.content.invoiceData.currency} ${invoiceItem.unitNetPrice} ${this.letterData?.content.invoiceData.currency}
</div> </div>
<div class="lineItem rightAlign"> <div class="lineItem rightAlign">
${invoiceItem.vatPercentage}% ${invoiceItem.unitQuantity * invoiceItem.unitNetPrice}
${this.letterData?.content.invoiceData.currency}
</div> </div>
<div class="lineItem rightAlign">${invoiceItem.vatPercentage}%</div>
</div> </div>
` `;
); });
})()} })()}
<div class="sums"> <div class="sums">
<div class="sumline"> <div class="sumline">
@ -332,9 +386,13 @@ export class DeContentInvoice extends DeesElement {
<div class="sumline"> <div class="sumline">
<div class="label"> <div class="label">
Vat ${vatGroupArg.vatPercentage}% Vat ${vatGroupArg.vatPercentage}%
${this.documentSettings.vatGroupPositions ? html` ${this.documentSettings.vatGroupPositions
<br /><span style="font-weight: normal">(on item positions: ${itemNumbers})</span> ? html`
` : html``} <br /><span style="font-weight: normal"
>(on item positions: ${itemNumbers})</span
>
`
: html``}
</div> </div>
<div class="value">${vatGroupArg.vatAmountSum} EUR</div> <div class="value">${vatGroupArg.vatAmountSum} EUR</div>
</div> </div>
@ -349,7 +407,11 @@ export class DeContentInvoice extends DeesElement {
${this.letterData?.content.invoiceData.reverseCharge ${this.letterData?.content.invoiceData.reverseCharge
? html` ? html`
<div class="taxNote"> <div class="taxNote">
${plugins.shared.translation.translate(this.documentSettings.languageCode, 'reverseVatNote', 'VAT arises on a reverse charge basis and is payable by the customer.')} ${plugins.shared.translation.translate(
this.documentSettings.languageCode,
'reverseVatNote',
'VAT arises on a reverse charge basis and is payable by the customer.'
)}
</div> </div>
` `
: ``} : ``}
@ -369,7 +431,9 @@ export class DeContentInvoice extends DeesElement {
<div class="infoBox"> <div class="infoBox">
<div class="label">Referenced contract:</div> <div class="label">Referenced contract:</div>
This invoice is adhering to agreements made by contract between the parties on This invoice is adhering to agreements made by contract between the parties on
${plugins.smarttime.ExtendedDate.fromMillis(this.letterData?.content.contractData.contractDate).format('MMMM D, YYYY')}. ${plugins.smarttime.ExtendedDate.fromMillis(
this.letterData?.content.contractData.contractDate
).format('MMMM D, YYYY')}.
</div> </div>
` `
: html``} : html``}
@ -396,7 +460,6 @@ ${this.letterData.content.invoiceData.id}
EPC QR Code`, EPC QR Code`,
(error) => { (error) => {
if (error) console.error(error); if (error) console.error(error);
console.log('success!');
} }
); );
contentNodes.currentContent.querySelector('.paymentCode').append(canvas); contentNodes.currentContent.querySelector('.paymentCode').append(canvas);

View File

@ -115,11 +115,35 @@ export class DeDocument extends DeesElement {
} }
public async firstUpdated(_changedProperties: Map<string | number | symbol, unknown>) { public async firstUpdated(_changedProperties: Map<string | number | symbol, unknown>) {
domtools.plugins.smartdelay.delayFor(0).then(() => { domtools.plugins.smartdelay.delayFor(0).then(async () => {
this.documentSettings = { this.documentSettings = {
...defaultDocumentSettings, ...defaultDocumentSettings,
...this.documentSettings, ...this.documentSettings,
} }
while (false) {
await domtools.plugins.smartdelay.delayFor(1000);
this.letterData = {
...this.letterData,
content: {
...this.letterData.content,
invoiceData: {
...this.letterData.content.invoiceData,
items: [
...this.letterData.content.invoiceData.items,
{
name: 'Test Item',
unitQuantity: 1,
unitNetPrice: 100,
unitType: 'hours',
vatPercentage: 19,
position: 1,
},
],
},
}
}
}
}); });
const resizeObserver = new ResizeObserver((entries) => { const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) { for (const entry of entries) {
@ -137,6 +161,7 @@ export class DeDocument extends DeesElement {
public latestDocumentSettings: plugins.shared.interfaces.IDocumentSettings = null; public latestDocumentSettings: plugins.shared.interfaces.IDocumentSettings = null;
public latestRenderedLetterData: plugins.tsclass.business.ILetter = null; public latestRenderedLetterData: plugins.tsclass.business.ILetter = null;
public cleanupStore: any[] = [];
public async renderDocument() { public async renderDocument() {
@ -144,11 +169,12 @@ export class DeDocument extends DeesElement {
this.latestDocumentSettings = this.documentSettings; this.latestDocumentSettings = this.documentSettings;
this.latestRenderedLetterData = this.letterData; this.latestRenderedLetterData = this.letterData;
console.log(`rendering with settings:`); const cleanUpStoreCurrentRender = [];
console.log(this.latestDocumentSettings); const cleanUpStoreNextRender = [];
const domtools = await this.domtoolsPromise; const domtools = await this.domtoolsPromise;
const documentBuildContainer = document.createElement('div'); const documentBuildContainer = document.createElement('div');
cleanUpStoreCurrentRender.push(documentBuildContainer);
document.body.appendChild(documentBuildContainer); document.body.appendChild(documentBuildContainer);
let pages: DePage[] = []; let pages: DePage[] = [];
@ -157,6 +183,7 @@ export class DeDocument extends DeesElement {
// lets append the content // lets append the content
const content: DeContentInvoice = new DeContentInvoice(); const content: DeContentInvoice = new DeContentInvoice();
cleanUpStoreCurrentRender.push(content);
content.letterData = this.letterData; content.letterData = this.letterData;
content.documentSettings = this.documentSettings; content.documentSettings = this.documentSettings;
document.body.appendChild(content); document.body.appendChild(content);
@ -168,6 +195,7 @@ export class DeDocument extends DeesElement {
while (!complete) { while (!complete) {
pageCounter++; pageCounter++;
const currentContent = content.cloneNode(true) as DeContentInvoice; const currentContent = content.cloneNode(true) as DeContentInvoice;
cleanUpStoreNextRender.push(currentContent);
const newPage = new DePage(); const newPage = new DePage();
newPage.printMode = this.printMode; newPage.printMode = this.printMode;
newPage.letterData = this.letterData; newPage.letterData = this.letterData;
@ -176,6 +204,9 @@ export class DeDocument extends DeesElement {
newPage.pageNumber = pageCounter; newPage.pageNumber = pageCounter;
newPage.append(currentContent); newPage.append(currentContent);
newPage.pageTotalNumber = pageCounter; newPage.pageTotalNumber = pageCounter;
// store current page
cleanUpStoreNextRender.push(newPage);
documentBuildContainer.append(newPage); documentBuildContainer.append(newPage);
await currentContent.elementDomReady; await currentContent.elementDomReady;
@ -192,16 +223,24 @@ export class DeDocument extends DeesElement {
if (trimmed === 0) { if (trimmed === 0) {
complete = true; complete = true;
} }
// complete = true;
console.log(currentContentOffset);
} }
document.body.removeChild(content);
document.body.removeChild(documentBuildContainer); for (const cleanUp of this.cleanupStore) {
cleanUp.remove();
}
this.cleanupStore = cleanUpStoreNextRender
cleanUpStoreCurrentRender.forEach((cleanUp) => {
cleanUp.remove();
});
const documentContainer = this.shadowRoot.querySelector('.documentContainer'); const documentContainer = this.shadowRoot.querySelector('.documentContainer');
if (documentContainer) { if (documentContainer) {
const children = Array.from(documentContainer.children); const children = Array.from(documentContainer.children);
children.forEach((child) => documentContainer.removeChild(child)); children.forEach((child) => {
documentContainer.removeChild(child);
child.remove();
});
} }
for (const page of pages) { for (const page of pages) {
page.pageTotalNumber = pageCounter; page.pageTotalNumber = pageCounter;
@ -245,7 +284,6 @@ export class DeDocument extends DeesElement {
} }
if (this.viewWidth) { if (this.viewWidth) {
page.viewWidth = this.viewWidth; page.viewWidth = this.viewWidth;
console.log('setting viewWidth: ', this.viewWidth);
} }
}); });
} }

View File

@ -77,6 +77,7 @@ export class DePage extends DeesElement {
css` css`
:host { :host {
display: block; display: block;
overflow: hidden;
} }
#scaleWrapper { #scaleWrapper {
@ -195,7 +196,6 @@ export class DePage extends DeesElement {
} }
private adjustScaling() { private adjustScaling() {
console.log('page scale adjustment triggered.');
const scaleWrapper: HTMLDivElement = this.shadowRoot.querySelector('#scaleWrapper'); const scaleWrapper: HTMLDivElement = this.shadowRoot.querySelector('#scaleWrapper');
if (!scaleWrapper) return; if (!scaleWrapper) return;
@ -206,12 +206,10 @@ export class DePage extends DeesElement {
} else if (this.viewWidth) { } else if (this.viewWidth) {
scale = this.viewWidth / plugins.shared.a4Width; scale = this.viewWidth / plugins.shared.a4Width;
} }
console.log(`new scale is ${scale}`);
scaleWrapper.style.transform = `scale(${scale})`; scaleWrapper.style.transform = `scale(${scale})`;
// Adjust the outer dimensions so they match the scaled content // Adjust the outer dimensions so they match the scaled content
this.style.overflow = 'hidden';
this.style.width = `${plugins.shared.a4Width * scale}px`; this.style.width = `${plugins.shared.a4Width * scale}px`;
this.style.height = `${plugins.shared.a4Height * scale}px`; this.style.height = `${plugins.shared.a4Height * scale}px`;
} }

View File

@ -138,10 +138,8 @@ export class DePageContent extends DeesElement {
await this.elementDomReady; await this.elementDomReady;
const contentContainer = this.shadowRoot.querySelector('.content'); const contentContainer = this.shadowRoot.querySelector('.content');
if (contentContainer.scrollHeight > contentContainer.clientHeight) { if (contentContainer.scrollHeight > contentContainer.clientHeight) {
console.log('overflows');
return true; return true;
} else { } else {
console.log('does not overflow!');
return false; return false;
} }
} }