From cd0e679f9a31317c6c6e938b845b4a315a5bc99a Mon Sep 17 00:00:00 2001 From: Javier Borrego Date: Mon, 23 Feb 2026 11:50:01 +0100 Subject: [PATCH 1/5] Agenda to PDF export style changed --- .../pdf-document.service.ts | 2 +- .../pages/agenda/agenda.subscription.ts | 15 +- .../agenda-pdf-catalog-export.service.ts | 130 ++++++++++++++---- 3 files changed, 121 insertions(+), 26 deletions(-) diff --git a/client/src/app/gateways/export/pdf-document.service/pdf-document.service.ts b/client/src/app/gateways/export/pdf-document.service/pdf-document.service.ts index f993498607..c773735d3b 100644 --- a/client/src/app/gateways/export/pdf-document.service/pdf-document.service.ts +++ b/client/src/app/gateways/export/pdf-document.service/pdf-document.service.ts @@ -768,7 +768,7 @@ export class PdfDocumentService { ); } } - const margin: Margins = [lrMargin ? lrMargin[0] : 75, 30, lrMargin ? lrMargin[0] : 75, 10]; + const margin: Margins = [lrMargin ? lrMargin[0] : 75, 18, lrMargin ? lrMargin[0] : 0, 35]; // pdfmake order: [left, top, right, bottom] return { diff --git a/client/src/app/site/pages/meetings/pages/agenda/agenda.subscription.ts b/client/src/app/site/pages/meetings/pages/agenda/agenda.subscription.ts index c0063e5a1b..cf39cc2b0a 100644 --- a/client/src/app/site/pages/meetings/pages/agenda/agenda.subscription.ts +++ b/client/src/app/site/pages/meetings/pages/agenda/agenda.subscription.ts @@ -218,7 +218,16 @@ export const getAgendaExportSubscriptionConfig: SubscriptionConfigGenerator = (. follow: [ { idField: `content_object_id`, - fieldset: [`number`, `title`, `agenda_item_id`, `text`, `poll_ids`, ...MEETING_ROUTING_FIELDS], + fieldset: [ + `number`, + `title`, + `agenda_item_id`, + `text`, + `description`, + `poll_ids`, + `assignment`, + ...MEETING_ROUTING_FIELDS + ], follow: [ { idField: `list_of_speakers_id`, @@ -271,6 +280,10 @@ export const getAgendaExportSubscriptionConfig: SubscriptionConfigGenerator = (. { idField: `poll_ids`, ...pollModelRequest + }, + { + idField: `motion_ids`, + fieldset: [`title`, `meeting_id`, `sequential_number`, `number`, `block_id`] } ] } diff --git a/client/src/app/site/pages/meetings/pages/agenda/services/agenda-pdf-catalog-export.service/agenda-pdf-catalog-export.service.ts b/client/src/app/site/pages/meetings/pages/agenda/services/agenda-pdf-catalog-export.service/agenda-pdf-catalog-export.service.ts index 4f689c973a..357de4e412 100644 --- a/client/src/app/site/pages/meetings/pages/agenda/services/agenda-pdf-catalog-export.service/agenda-pdf-catalog-export.service.ts +++ b/client/src/app/site/pages/meetings/pages/agenda/services/agenda-pdf-catalog-export.service/agenda-pdf-catalog-export.service.ts @@ -11,6 +11,7 @@ import { TreeService } from 'src/app/ui/modules/sorting/modules/sorting-tree/ser import { MeetingPdfExportService } from '../../../../services/export'; import { MeetingSettingsService } from '../../../../services/meeting-settings.service'; +import { ViewMotion } from '../../../motions'; import { ViewPoll } from '../../../polls'; import { ViewSpeaker } from '../../modules/list-of-speakers/view-models/view-speaker'; import { ViewTopic } from '../../modules/topics/view-models'; @@ -231,7 +232,12 @@ export class AgendaPdfCatalogExportService { const useTitle: boolean = info.includes(`title`); const itemNumber: string = agendaItem.item_number ?? ``; const title: string = agendaItem.content_object!.getTitle(); - const styleName = agendaItem.level ? `header-child` : `header2`; + let styleName = `header2`; + let margin = ``; + if (agendaItem.level > 0) { + styleName = `header-child`; + margin = `margin-header-child`; + } let numberOrTitle = ``; if (agendaItem.content_object?.collection === `motion`) { const motion = agendaItem.content_object; @@ -252,6 +258,16 @@ export class AgendaPdfCatalogExportService { numberOrTitle = `${itemNumber} `; } numberOrTitle = numberOrTitle.concat(`${this.translate.instant('Motion block')}: ${motionBlock.title}`); + } else if (agendaItem.content_object?.collection === `assignment`) { + const election = agendaItem.content_object; + if (useItemNumber && itemNumber) { + numberOrTitle = `${itemNumber} `; + } + numberOrTitle = numberOrTitle.concat( + election.number + ? `${(this.translate.instant('Wahl'), election.number)}: ${election.title}` + : `${this.translate.instant('Wahl')}: ${election.title}` + ); } else { if (useItemNumber && itemNumber && useTitle) { numberOrTitle = `${itemNumber}: ${title}`; @@ -263,17 +279,45 @@ export class AgendaPdfCatalogExportService { } return { style: this.getStyle(styleName), - text: numberOrTitle + text: numberOrTitle, + margin: this.getStyle(margin) }; } private createTextDoc(agendaItem: ViewAgendaItem): Content { + const style = this.getStyle(`body-text`); + const margin = this.getStyle(`margin-body-text`); if (!this.isTopic(agendaItem.content_object)) { - return []; - } - if (agendaItem.content_object?.getCSVExportText) { - const entry = this.htmlToPdfService.convertHtml({ htmlText: agendaItem.content_object?.text ?? `` }); - return entry; + // MOTION + if (agendaItem.content_object?.collection === 'motion') { + const entry = this.htmlToPdfService.convertHtml({ + htmlText: agendaItem.content_object?.text ?? `EMPTY ${agendaItem.content_object?.collection}` + }); + return { text: [...entry], style: style, margin: margin }; + // ASSIGNMENT / ELECTION + } else if (agendaItem.content_object?.collection === `assignment`) { + const entry = this.htmlToPdfService.convertHtml({ + htmlText: agendaItem.content_object.description ?? `EMPTY ${agendaItem.content_object?.collection}` + }); + return { text: [...entry], style: style, margin: margin }; + // MOTION BLOCK + } else if (agendaItem.content_object?.collection === 'motion_block') { + const motions: ViewMotion[] = agendaItem.content_object?.motions || []; + const entry = this.htmlToPdfService.convertHtml({ + htmlText: + motions.map(m => `Motion ${m.number}: ${m.title}`).join('

') ?? + `EMPTY ${agendaItem.content_object.collection}` + }); + return { text: entry, style: this.getStyle(`header3`), margin: margin }; + } else { + return { text: agendaItem.content_object?.collection, style: style, margin: margin }; + } + // AGENDA TOPIC + } else if (agendaItem.content_object?.getCSVExportText) { + const entry = this.htmlToPdfService.convertHtml({ + htmlText: agendaItem.content_object?.text ?? `EMPTY ${agendaItem.content_object?.collection}` + }); + return { text: [...entry], style: style, margin: margin }; } return []; } @@ -286,14 +330,45 @@ export class AgendaPdfCatalogExportService { const entry = this.htmlToPdfService.convertHtml({ htmlText: moderationNotes }); if (moderationNotes) { this._addExtraSpace = true; - return [ - { - text: this.translate.instant(`Moderation note`), - style: this.getStyle(`header3`), - margin: this.getStyle(`margin-header3`) - }, - entry - ]; + const moderationText = { + text: entry + }; + const text = this.translate.instant(`Moderation note`); + const style = [this.getStyle(`header3`), this.getStyle(`body-text`)]; + const margin: [ + [number, number, number, number], + [number, number, number, number], + [number, number, number, number], + [number, number, number, number] + ] = [[20, 10, 0, 0], [25, 10, 0, 0], this.getStyle(`margin-header3`), this.getStyle(`margin-body-text`)]; + // Indents the moderation note inside a subitem + if (agendaItem.level > 0) { + return [ + { + text: text, + style: style[0], + margin: margin[0] + }, + { + text: moderationText, + style: style[1], + margin: margin[1] + } + ]; + } else { + return [ + { + text: text, + style: style[0], + margin: margin[2] + }, + { + text: moderationText, + style: style[1], + margin: margin[3] + } + ]; + } } else { return []; } @@ -517,27 +592,34 @@ export class AgendaPdfCatalogExportService { private getStyle(name: string): any { switch (name) { case `header1`: - return { bold: true, fontSize: 24 }; - case `header2`: return { bold: true, fontSize: 20 }; + case `header2`: + return { bold: true, fontSize: 16 }; case `header3`: - return { bold: true, fontSize: 14 }; + return { bold: true, fontSize: 12 }; case `header-child`: - return { bold: true, fontSize: 16 }; + return { bold: true, fontSize: 14 }; case `table-header`: - return { bold: true, fontSize: 12 }; + return { bold: true, fontSize: 10 }; + case `body-text`: + return { fontSize: 10 }; case `grey`: return { layout: TABLEROW_GREY }; case `italics`: return { italics: true }; case `margin-header1`: - return [0, 0, 0, 20]; + // [L,U,R,D] + return [0, 10, 0, 0]; case `margin-header3`: - return [0, 15, 0, 10]; + return [15, 10, 0, 0]; + case `margin-header-child`: + return [15, 10, 0, 0]; case `margin-type-text`: - return [0, 0, 0, 10]; + return [12, 10, 0, 0]; + case `margin-body-text`: + return [20, 10, 0, 5]; case `margin-item`: - return [0, 0, 0, 5]; + return [0, 0, 0, 0]; case `margin-item-2`: return [0, 10, 0, 5]; default: From 64a75a3ab61cc6af45bc3559f04eefe721b233c2 Mon Sep 17 00:00:00 2001 From: Javier Borrego Date: Wed, 25 Mar 2026 11:36:48 +0100 Subject: [PATCH 2/5] fixed indentation levels and aligned texts --- .../pdf-document.service.ts | 2 +- .../agenda-pdf-catalog-export.service.ts | 40 +++++++++++++------ 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/client/src/app/gateways/export/pdf-document.service/pdf-document.service.ts b/client/src/app/gateways/export/pdf-document.service/pdf-document.service.ts index c773735d3b..f993498607 100644 --- a/client/src/app/gateways/export/pdf-document.service/pdf-document.service.ts +++ b/client/src/app/gateways/export/pdf-document.service/pdf-document.service.ts @@ -768,7 +768,7 @@ export class PdfDocumentService { ); } } - const margin: Margins = [lrMargin ? lrMargin[0] : 75, 18, lrMargin ? lrMargin[0] : 0, 35]; + const margin: Margins = [lrMargin ? lrMargin[0] : 75, 30, lrMargin ? lrMargin[0] : 75, 10]; // pdfmake order: [left, top, right, bottom] return { diff --git a/client/src/app/site/pages/meetings/pages/agenda/services/agenda-pdf-catalog-export.service/agenda-pdf-catalog-export.service.ts b/client/src/app/site/pages/meetings/pages/agenda/services/agenda-pdf-catalog-export.service/agenda-pdf-catalog-export.service.ts index 357de4e412..cd22d5fe88 100644 --- a/client/src/app/site/pages/meetings/pages/agenda/services/agenda-pdf-catalog-export.service/agenda-pdf-catalog-export.service.ts +++ b/client/src/app/site/pages/meetings/pages/agenda/services/agenda-pdf-catalog-export.service/agenda-pdf-catalog-export.service.ts @@ -106,7 +106,7 @@ export class AgendaPdfCatalogExportService { { text: this.translate.instant(`Agenda`), style: this.getStyle(`header1`), - margin: this.getStyle(`margin-header1`) + margin: this.getStyle(`agenda-title`) } ]); @@ -233,10 +233,11 @@ export class AgendaPdfCatalogExportService { const itemNumber: string = agendaItem.item_number ?? ``; const title: string = agendaItem.content_object!.getTitle(); let styleName = `header2`; - let margin = ``; + let margin: string | number[] = `margin-header1`; if (agendaItem.level > 0) { styleName = `header-child`; - margin = `margin-header-child`; + const indentationLevel = agendaItem.level * 10 + 10; + margin = [indentationLevel, 10, 0, 0]; } let numberOrTitle = ``; if (agendaItem.content_object?.collection === `motion`) { @@ -280,13 +281,15 @@ export class AgendaPdfCatalogExportService { return { style: this.getStyle(styleName), text: numberOrTitle, - margin: this.getStyle(margin) + margin: margin === 'margin-header1' ? this.getStyle(margin) : margin }; } private createTextDoc(agendaItem: ViewAgendaItem): Content { const style = this.getStyle(`body-text`); - const margin = this.getStyle(`margin-body-text`); + // The operation calculates the correct intentation level + const indentationLevel = agendaItem.level * 10 + 10; + const margin = agendaItem.level > 0 ? [indentationLevel, 10, 0, 0] : this.getStyle(`margin-body-text`); if (!this.isTopic(agendaItem.content_object)) { // MOTION if (agendaItem.content_object?.collection === 'motion') { @@ -328,21 +331,28 @@ export class AgendaPdfCatalogExportService { } const moderationNotes = agendaItem.content_object?.list_of_speakers?.moderator_notes ?? ``; const entry = this.htmlToPdfService.convertHtml({ htmlText: moderationNotes }); + console.log(moderationNotes, entry, agendaItem.getTitle()); if (moderationNotes) { this._addExtraSpace = true; const moderationText = { text: entry }; const text = this.translate.instant(`Moderation note`); - const style = [this.getStyle(`header3`), this.getStyle(`body-text`)]; + const style = [this.getStyle(`header3`), this.getStyle(`margin-body-text`)]; const margin: [ [number, number, number, number], [number, number, number, number], [number, number, number, number], [number, number, number, number] - ] = [[20, 10, 0, 0], [25, 10, 0, 0], this.getStyle(`margin-header3`), this.getStyle(`margin-body-text`)]; + ] = [ + [20, 10, 0, 0], + [20, 10, 0, 0], + this.getStyle(`margin-header3`), + this.getStyle(`margin-moderation-note`) + ]; // Indents the moderation note inside a subitem if (agendaItem.level > 0) { + margin[0][0] = margin[0][0] + agendaItem.level * 10; return [ { text: text, @@ -352,7 +362,7 @@ export class AgendaPdfCatalogExportService { { text: moderationText, style: style[1], - margin: margin[1] + margin: margin[0] } ]; } else { @@ -607,17 +617,21 @@ export class AgendaPdfCatalogExportService { return { layout: TABLEROW_GREY }; case `italics`: return { italics: true }; + // [L,U,R,D] + case `agenda-title`: + return [0, 15, 0, 20]; case `margin-header1`: - // [L,U,R,D] - return [0, 10, 0, 0]; + return [0, 0, 0, 0]; case `margin-header3`: return [15, 10, 0, 0]; case `margin-header-child`: - return [15, 10, 0, 0]; + return [15, 0, 0, 0]; case `margin-type-text`: - return [12, 10, 0, 0]; + return [12, 0, 0, 0]; case `margin-body-text`: - return [20, 10, 0, 5]; + return [0, 10, 0, 5]; + case `margin-moderation-note`: + return [15, 10, 0, 5]; case `margin-item`: return [0, 0, 0, 0]; case `margin-item-2`: From 0615dc4c1ac7b550e0d4c0cdecf71f1afc5bea7c Mon Sep 17 00:00:00 2001 From: Javier Borrego Date: Thu, 26 Mar 2026 15:48:07 +0100 Subject: [PATCH 3/5] Increased distance between headings --- .../agenda-pdf-catalog-export.service.ts | 57 ++++++++++++------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/client/src/app/site/pages/meetings/pages/agenda/services/agenda-pdf-catalog-export.service/agenda-pdf-catalog-export.service.ts b/client/src/app/site/pages/meetings/pages/agenda/services/agenda-pdf-catalog-export.service/agenda-pdf-catalog-export.service.ts index cd22d5fe88..35f30d4fb6 100644 --- a/client/src/app/site/pages/meetings/pages/agenda/services/agenda-pdf-catalog-export.service/agenda-pdf-catalog-export.service.ts +++ b/client/src/app/site/pages/meetings/pages/agenda/services/agenda-pdf-catalog-export.service/agenda-pdf-catalog-export.service.ts @@ -15,6 +15,7 @@ import { ViewMotion } from '../../../motions'; import { ViewPoll } from '../../../polls'; import { ViewSpeaker } from '../../modules/list-of-speakers/view-models/view-speaker'; import { ViewTopic } from '../../modules/topics/view-models'; +import { InfoToExport } from '../../pages/agenda-item-list/services/agenda-item-export.service/agenda-item-export.service'; import { ViewAgendaItem } from '../../view-models'; import { AgendaItemCommonServiceModule } from '../agenda-item-common-service.module'; @@ -58,7 +59,7 @@ export class AgendaPdfCatalogExportService { * @param pdfMeta * @returns pdfmake doc definition as object */ - public agendaListToDocDef(agendaItems: ViewAgendaItem[], exportInfo: any, pdfMeta: string[]): Content { + public agendaListToDocDef(agendaItems: ViewAgendaItem[], exportInfo: InfoToExport[], pdfMeta: string[]): Content { const addedAgendaItems = this.getMissingAgendaItems(agendaItems); this.addedAgendaItemIds = addedAgendaItems.map(item => item.id); const tree = this.treeService.makeSortedTree(agendaItems.concat(addedAgendaItems), `weight`, `parent_id`); @@ -70,22 +71,29 @@ export class AgendaPdfCatalogExportService { for (let agendaItemIndex = 0; agendaItemIndex < sortedAgendaItems.length; ++agendaItemIndex) { try { + const agendaItem: string | null = + agendaItems[agendaItemIndex].content_object.description === undefined + ? agendaItems[agendaItemIndex].content_object.text + : agendaItems[agendaItemIndex].content_object.description; const agendaDocDef: any = this.agendaItemToDoc(sortedAgendaItems[agendaItemIndex], exportInfo); // add id field to the first page of a agenda item to make it findable over TOC + agendaDocDef[0].id = `${sortedAgendaItems[agendaItemIndex].id}`; if (!enforcePageBreaks && agendaItemIndex + 1 < sortedAgendaItems.length) { - if (!sortedAgendaItems[agendaItemIndex + 1].parent) { - agendaDocDef.push({ - text: ``, - marginBottom: this._addExtraSpace ? 25 : 20 - }); - } else { - agendaDocDef.push({ - text: ``, - marginBottom: this._addExtraSpace ? 15 : 10 - }); + if (agendaItem != '') { + if (!sortedAgendaItems[agendaItemIndex + 1].parent) { + agendaDocDef.push({ + text: ``, + marginBottom: this._addExtraSpace ? 25 : 20 + }); + } else { + agendaDocDef.push({ + text: ``, + marginBottom: this._addExtraSpace ? 15 : 10 + }); + } + this._addExtraSpace = false; } - this._addExtraSpace = false; } agendaDocList.push(agendaDocDef); @@ -306,12 +314,22 @@ export class AgendaPdfCatalogExportService { // MOTION BLOCK } else if (agendaItem.content_object?.collection === 'motion_block') { const motions: ViewMotion[] = agendaItem.content_object?.motions || []; - const entry = this.htmlToPdfService.convertHtml({ - htmlText: - motions.map(m => `Motion ${m.number}: ${m.title}`).join('

') ?? - `EMPTY ${agendaItem.content_object.collection}` - }); - return { text: entry, style: this.getStyle(`header3`), margin: margin }; + margin[3] -= 5; + return motions.length + ? motions.map(m => ({ + text: this.htmlToPdfService.convertHtml({ + htmlText: `Motion ${m.number}: ${m.title}` + }), + style: this.getStyle('header3'), + margin: margin + })) + : [ + { + text: `EMPTY ${agendaItem.content_object.collection}`, + style: this.getStyle('header3'), + margin: margin + } + ]; } else { return { text: agendaItem.content_object?.collection, style: style, margin: margin }; } @@ -331,7 +349,6 @@ export class AgendaPdfCatalogExportService { } const moderationNotes = agendaItem.content_object?.list_of_speakers?.moderator_notes ?? ``; const entry = this.htmlToPdfService.convertHtml({ htmlText: moderationNotes }); - console.log(moderationNotes, entry, agendaItem.getTitle()); if (moderationNotes) { this._addExtraSpace = true; const moderationText = { @@ -619,7 +636,7 @@ export class AgendaPdfCatalogExportService { return { italics: true }; // [L,U,R,D] case `agenda-title`: - return [0, 15, 0, 20]; + return [0, 0, 0, 20]; case `margin-header1`: return [0, 0, 0, 0]; case `margin-header3`: From 5b5edd6f9084c7a133429c2e78954836ba3c0ef0 Mon Sep 17 00:00:00 2001 From: Javier Borrego Date: Fri, 27 Mar 2026 12:37:26 +0100 Subject: [PATCH 4/5] Requested changes done --- .../agenda-pdf-catalog-export.service.ts | 57 ++++++++++--------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/client/src/app/site/pages/meetings/pages/agenda/services/agenda-pdf-catalog-export.service/agenda-pdf-catalog-export.service.ts b/client/src/app/site/pages/meetings/pages/agenda/services/agenda-pdf-catalog-export.service/agenda-pdf-catalog-export.service.ts index 35f30d4fb6..1515e2d8bc 100644 --- a/client/src/app/site/pages/meetings/pages/agenda/services/agenda-pdf-catalog-export.service/agenda-pdf-catalog-export.service.ts +++ b/client/src/app/site/pages/meetings/pages/agenda/services/agenda-pdf-catalog-export.service/agenda-pdf-catalog-export.service.ts @@ -72,28 +72,25 @@ export class AgendaPdfCatalogExportService { for (let agendaItemIndex = 0; agendaItemIndex < sortedAgendaItems.length; ++agendaItemIndex) { try { const agendaItem: string | null = - agendaItems[agendaItemIndex].content_object.description === undefined - ? agendaItems[agendaItemIndex].content_object.text - : agendaItems[agendaItemIndex].content_object.description; + agendaItems[agendaItemIndex].content_object?.description ?? + agendaItems[agendaItemIndex].content_object?.text ?? + null; const agendaDocDef: any = this.agendaItemToDoc(sortedAgendaItems[agendaItemIndex], exportInfo); // add id field to the first page of a agenda item to make it findable over TOC - agendaDocDef[0].id = `${sortedAgendaItems[agendaItemIndex].id}`; - if (!enforcePageBreaks && agendaItemIndex + 1 < sortedAgendaItems.length) { - if (agendaItem != '') { - if (!sortedAgendaItems[agendaItemIndex + 1].parent) { - agendaDocDef.push({ - text: ``, - marginBottom: this._addExtraSpace ? 25 : 20 - }); - } else { - agendaDocDef.push({ - text: ``, - marginBottom: this._addExtraSpace ? 15 : 10 - }); - } - this._addExtraSpace = false; + if (!enforcePageBreaks && agendaItemIndex + 1 < sortedAgendaItems.length && agendaItem !== '') { + if (!sortedAgendaItems[agendaItemIndex + 1].parent) { + agendaDocDef.push({ + text: ``, + marginBottom: this._addExtraSpace ? 25 : 20 + }); + } else { + agendaDocDef.push({ + text: ``, + marginBottom: this._addExtraSpace ? 15 : 10 + }); } + this._addExtraSpace = false; } agendaDocList.push(agendaDocDef); @@ -302,13 +299,17 @@ export class AgendaPdfCatalogExportService { // MOTION if (agendaItem.content_object?.collection === 'motion') { const entry = this.htmlToPdfService.convertHtml({ - htmlText: agendaItem.content_object?.text ?? `EMPTY ${agendaItem.content_object?.collection}` + htmlText: + agendaItem.content_object?.text ?? + this.translate.instant(`EMPTY ${agendaItem.content_object?.collection}`) }); return { text: [...entry], style: style, margin: margin }; // ASSIGNMENT / ELECTION } else if (agendaItem.content_object?.collection === `assignment`) { const entry = this.htmlToPdfService.convertHtml({ - htmlText: agendaItem.content_object.description ?? `EMPTY ${agendaItem.content_object?.collection}` + htmlText: + agendaItem.content_object.description ?? + this.translate.instant(`EMPTY`) + `${agendaItem.content_object?.collection}` }); return { text: [...entry], style: style, margin: margin }; // MOTION BLOCK @@ -318,27 +319,29 @@ export class AgendaPdfCatalogExportService { return motions.length ? motions.map(m => ({ text: this.htmlToPdfService.convertHtml({ - htmlText: `Motion ${m.number}: ${m.title}` + htmlText: this.translate.instant(`Motion`) + ` ${m.number}: ${m.title}` }), style: this.getStyle('header3'), - margin: margin + margin })) : [ { - text: `EMPTY ${agendaItem.content_object.collection}`, + text: this.translate.instant(`EMPTY`) + `${agendaItem.content_object.collection}`, style: this.getStyle('header3'), - margin: margin + margin } ]; } else { - return { text: agendaItem.content_object?.collection, style: style, margin: margin }; + return { text: agendaItem.content_object?.collection, style: style, margin }; } // AGENDA TOPIC } else if (agendaItem.content_object?.getCSVExportText) { const entry = this.htmlToPdfService.convertHtml({ - htmlText: agendaItem.content_object?.text ?? `EMPTY ${agendaItem.content_object?.collection}` + htmlText: + agendaItem.content_object?.text ?? + this.translate.instant(`EMPTY ${agendaItem.content_object?.collection}`) }); - return { text: [...entry], style: style, margin: margin }; + return { text: [...entry], style: style, margin }; } return []; } From b69545a4be953b993ff15e6748da9e9f5bce605e Mon Sep 17 00:00:00 2001 From: Javier Borrego Date: Fri, 27 Mar 2026 16:28:17 +0100 Subject: [PATCH 5/5] Cleanup --- .../pages/agenda/agenda.subscription.ts | 1 - .../agenda-pdf-catalog-export.service.ts | 96 ++++++++++--------- 2 files changed, 51 insertions(+), 46 deletions(-) diff --git a/client/src/app/site/pages/meetings/pages/agenda/agenda.subscription.ts b/client/src/app/site/pages/meetings/pages/agenda/agenda.subscription.ts index cf39cc2b0a..5657d5dae8 100644 --- a/client/src/app/site/pages/meetings/pages/agenda/agenda.subscription.ts +++ b/client/src/app/site/pages/meetings/pages/agenda/agenda.subscription.ts @@ -225,7 +225,6 @@ export const getAgendaExportSubscriptionConfig: SubscriptionConfigGenerator = (. `text`, `description`, `poll_ids`, - `assignment`, ...MEETING_ROUTING_FIELDS ], follow: [ diff --git a/client/src/app/site/pages/meetings/pages/agenda/services/agenda-pdf-catalog-export.service/agenda-pdf-catalog-export.service.ts b/client/src/app/site/pages/meetings/pages/agenda/services/agenda-pdf-catalog-export.service/agenda-pdf-catalog-export.service.ts index 1515e2d8bc..ffb0a815a5 100644 --- a/client/src/app/site/pages/meetings/pages/agenda/services/agenda-pdf-catalog-export.service/agenda-pdf-catalog-export.service.ts +++ b/client/src/app/site/pages/meetings/pages/agenda/services/agenda-pdf-catalog-export.service/agenda-pdf-catalog-export.service.ts @@ -78,7 +78,11 @@ export class AgendaPdfCatalogExportService { const agendaDocDef: any = this.agendaItemToDoc(sortedAgendaItems[agendaItemIndex], exportInfo); // add id field to the first page of a agenda item to make it findable over TOC agendaDocDef[0].id = `${sortedAgendaItems[agendaItemIndex].id}`; - if (!enforcePageBreaks && agendaItemIndex + 1 < sortedAgendaItems.length && agendaItem !== '') { + if ( + !enforcePageBreaks && + agendaItemIndex + 1 < sortedAgendaItems.length && + (agendaItem !== '' || agendaItem === null) + ) { if (!sortedAgendaItems[agendaItemIndex + 1].parent) { agendaDocDef.push({ text: ``, @@ -271,8 +275,8 @@ export class AgendaPdfCatalogExportService { } numberOrTitle = numberOrTitle.concat( election.number - ? `${(this.translate.instant('Wahl'), election.number)}: ${election.title}` - : `${this.translate.instant('Wahl')}: ${election.title}` + ? `${(this.translate.instant('Election'), election.number)}: ${election.title}` + : `${this.translate.instant('Election')}: ${election.title}` ); } else { if (useItemNumber && itemNumber && useTitle) { @@ -292,50 +296,17 @@ export class AgendaPdfCatalogExportService { private createTextDoc(agendaItem: ViewAgendaItem): Content { const style = this.getStyle(`body-text`); - // The operation calculates the correct intentation level - const indentationLevel = agendaItem.level * 10 + 10; - const margin = agendaItem.level > 0 ? [indentationLevel, 10, 0, 0] : this.getStyle(`margin-body-text`); + const margin = this.getMargin(agendaItem); + const contentObject = agendaItem.content_object; + const text = contentObject.text ?? contentObject.description; + if (!this.isTopic(agendaItem.content_object)) { - // MOTION - if (agendaItem.content_object?.collection === 'motion') { - const entry = this.htmlToPdfService.convertHtml({ - htmlText: - agendaItem.content_object?.text ?? - this.translate.instant(`EMPTY ${agendaItem.content_object?.collection}`) - }); - return { text: [...entry], style: style, margin: margin }; - // ASSIGNMENT / ELECTION - } else if (agendaItem.content_object?.collection === `assignment`) { - const entry = this.htmlToPdfService.convertHtml({ - htmlText: - agendaItem.content_object.description ?? - this.translate.instant(`EMPTY`) + `${agendaItem.content_object?.collection}` - }); - return { text: [...entry], style: style, margin: margin }; - // MOTION BLOCK - } else if (agendaItem.content_object?.collection === 'motion_block') { - const motions: ViewMotion[] = agendaItem.content_object?.motions || []; - margin[3] -= 5; - return motions.length - ? motions.map(m => ({ - text: this.htmlToPdfService.convertHtml({ - htmlText: this.translate.instant(`Motion`) + ` ${m.number}: ${m.title}` - }), - style: this.getStyle('header3'), - margin - })) - : [ - { - text: this.translate.instant(`EMPTY`) + `${agendaItem.content_object.collection}`, - style: this.getStyle('header3'), - margin - } - ]; - } else { - return { text: agendaItem.content_object?.collection, style: style, margin }; - } - // AGENDA TOPIC + // If not agenda topic and no motion block, it's motion or assignment + if (contentObject.collection === 'motion_block') { + return this.motionBlockEntry(contentObject, margin); + } else return this.createHtmlEntry(text, contentObject.collection, style, margin); } else if (agendaItem.content_object?.getCSVExportText) { + // AGENDA TOPIC const entry = this.htmlToPdfService.convertHtml({ htmlText: agendaItem.content_object?.text ?? @@ -709,4 +680,39 @@ export class AgendaPdfCatalogExportService { const topic = obj as ViewTopic; return !!topic && topic.collection !== undefined && topic.collection === ViewTopic.COLLECTION && !!topic.topic; } + + public getMargin(agendaItem: ViewAgendaItem): any { + const indentationLevel = agendaItem.level * 10 + 10; + return agendaItem.level > 0 ? [indentationLevel, 10, 0, 0] : this.getStyle(`margin-body-text`); + } + + public createHtmlEntry(text: string | undefined, collection: string, style: any, margin: number[]): any { + const htmlText = text ?? this.translate.instant('EMPTY') + collection; + const entry = this.htmlToPdfService.convertHtml({ htmlText }); + return { text: [...entry], style, margin }; + } + + public motionBlockEntry(contentObject: any, margin: number[]): any { + const motions: ViewMotion[] = contentObject?.motions || []; + const adjustedMargin = [...margin]; + adjustedMargin[3] -= 5; + + if (!motions.length) { + return [ + { + text: this.translate.instant('EMPTY') + contentObject.collection, + style: this.getStyle('header3'), + margin: adjustedMargin + } + ]; + } + + return motions.map(m => ({ + text: this.htmlToPdfService.convertHtml({ + htmlText: `${this.translate.instant('Motion')} ${m.number}: ${m.title}` + }), + style: this.getStyle('header3'), + margin: adjustedMargin + })); + } }