From c64a1c51ccc404430c4e632b1797aa4b9e1d55cb Mon Sep 17 00:00:00 2001 From: Javier Borrego Date: Mon, 23 Feb 2026 11:50:01 +0100 Subject: [PATCH 01/14] 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 688388f154..ac9d4536fe 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 86e6a8cb55bd3ade3f2390977941aa2d75452c18 Mon Sep 17 00:00:00 2001 From: Javier Borrego Date: Thu, 5 Mar 2026 10:55:07 +0100 Subject: [PATCH 02/14] Added field to reference motions, topics, or assignments --- .../editor-link-dialog.component.html | 65 ++++- .../editor-link-dialog.component.scss | 30 +++ .../editor-link-dialog.component.ts | 227 +++++++++++++++++- .../app/ui/modules/editor/editor.module.ts | 7 +- 4 files changed, 322 insertions(+), 7 deletions(-) diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html index 1845e51093..8a455f1976 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html @@ -25,8 +25,71 @@

Insert/edit link

+
+

Link topic/motion/assignment

+ +
+ @if (toggleInsert) { +
+ + Selected item + + +
+ + + Topics + + + Motions + + + Assignments + + +
+ + + + {{ searchLists[selectedRepoValue].label }} + + @for (searchRepo of searchRepos; track $index) { + @if (selectedRepoValue === $index) { + + } + } + +
+
+ + +
+ } -
+
@if (isUpdate) { diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss index bc76a27e25..35fc17d328 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss @@ -1,3 +1,33 @@ mat-form-field { width: 100%; } + +.matDialogLinkActions { + display: flex; + flex-direction: row; + justify-content: flex-end; + margin-bottom: -20px; + margin-top: -15px; +} + +.matDialogActions { + margin-top: -15px; +} + +.mat-form-margin-top { + margin-top: 10px; +} + +.internalReferences { + display: flex; + + .internalReferencesTitle { + margin-bottom: 7px; + padding-right: 29px; + } + + .internalReferencesArrows { + display: flex; + margin-top: 7px; + } +} diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts index dd1dcde6f6..5913e1c38f 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts @@ -1,5 +1,17 @@ -import { Component, Inject } from '@angular/core'; +import { ChangeDetectorRef, Component, EventEmitter, Inject, inject, Input, OnInit, Output } from '@angular/core'; +import { FormControl, FormGroup, UntypedFormGroup } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { Observable, Subscription } from 'rxjs'; +import { AgendaItemRepositoryService } from 'src/app/gateways/repositories/agenda'; +import { AssignmentRepositoryService } from 'src/app/gateways/repositories/assignments/assignment-repository.service'; +import { MotionRepositoryService } from 'src/app/gateways/repositories/motions'; +import { getAgendaListMinimalSubscriptionConfig } from 'src/app/site/pages/meetings/pages/agenda/agenda.subscription'; +import { ViewAgendaItem } from 'src/app/site/pages/meetings/pages/agenda/view-models'; +import { ViewAssignment } from 'src/app/site/pages/meetings/pages/assignments/view-models/view-assignment'; +import { ViewMotion } from 'src/app/site/pages/meetings/pages/motions/view-models/view-motion'; +import { ActiveMeetingIdService } from 'src/app/site/pages/meetings/services/active-meeting-id.service'; +import { SubscribeToConfig } from 'src/app/site/services/model-request.service'; +import { ViewModelListProvider } from 'src/app/ui/base/view-model-list-provider'; interface EditorLinkDialogInput { link?: { href: string; target?: string }; @@ -18,13 +30,114 @@ export interface EditorLinkDialogOutput { styleUrls: [`editor-link-dialog.component.scss`], standalone: false }) -export class EditorLinkDialogComponent { +export class EditorLinkDialogComponent implements OnInit { public isUpdate: boolean; public link: { href: string; target?: string }; public text = ``; + public referenceLink: { href: string; target?: string }; + + public referenceText = ``; + + public toggleInsert: boolean; + + private _repo!: ViewModelListProvider; + + protected subscriptions: Subscription[] = []; + @Input() + public set repo(repo: ViewModelListProvider) { + this._repo = repo; + } + + /** + * Values selected by radio buttons + */ + public selectedRepoValue = 0; + + private activeMeetingIdService = inject(ActiveMeetingIdService); + public subscriptionConfig: SubscribeToConfig = getAgendaListMinimalSubscriptionConfig( + this.activeMeetingIdService.meetingId + ); + + /** + * Initial value of the input-field. + */ + @Input() + public searchFieldInput!: string; + + /** + * Optional label for the input. + */ + @Input() + public extensionLabel!: string; + + /** + * Title for this component. + */ + @Input() + public title!: string; + + /** + * Boolean, whether the input and the search-list can be changed. + */ + @Input() + public canBeEdited = true; + + /** + * EventEmitter, when clicking on the 'save'-button. + */ + @Output() + public succeeded = new EventEmitter(); + + /** + * Boolean to decide, whether to open the extension-input and search-list. + */ + public editMode = false; + + /** + * The index of the search list that was last selected from, or -1 if something was written in + * the input field afterwards. + */ + private searchListLastSelected = -1; + + /** + * Model for the input-field. + */ + public inputControl; + + /** + * Prevent selecting the same value twice. + */ + private searchListDisabledItems = []; + + private cd: ChangeDetectorRef; + + /** + * The item from the list that will be added to the editor. + */ + public itemToReference; + /** + * Init Repos + */ + public agendaItemRepo = inject(AgendaItemRepositoryService); + public motionItemRepo = inject(MotionRepositoryService); + public assignmentItemRepo = inject(AssignmentRepositoryService); + /** + * Define lists + */ + protected agendaItemList: Observable[]>; + protected motionItemList: Observable; + protected assignmentItemList: Observable; + + public searchLists; + public searchRepos; + /** + * FormGroup for the search-list. + */ + public extensionFieldForm: UntypedFormGroup; + public constructor( @Inject(MAT_DIALOG_DATA) public data: EditorLinkDialogInput, private dialogRef: MatDialogRef @@ -34,6 +147,23 @@ export class EditorLinkDialogComponent { if (!this.link.target) { this.link.target = `_self`; } + this.referenceLink = data.link; + this.referenceLink.target = `_self`; + } + + public ngOnInit(): void { + this.agendaItemList = this.agendaItemRepo.getSortedViewModelListObservable(); + this.motionItemList = this.motionItemRepo.getSortedViewModelListObservable(); + this.assignmentItemList = this.assignmentItemRepo.getSortedViewModelListObservable(); + + this.searchLists = [ + { observable: this.agendaItemList, label: 'Topic' }, + { observable: this.motionItemList, label: 'Motion' }, + { observable: this.assignmentItemList, label: 'Assignment' } + ]; + this.searchRepos = [this.agendaItemRepo, this.motionItemRepo, this.assignmentItemRepo]; + this.initInput(); + this.initForm(); } public removeLink(): void { @@ -48,11 +178,98 @@ export class EditorLinkDialogComponent { if (this.link.href && !/^[a-zA-Z]+:\/\//.test(this.link.href)) { this.link.href = `http://` + this.link.href; } - + console.log(this.link.href); if (this.data.needsText) { - this.dialogRef.close({ action: `set-link`, link: this.link, text: this.text || this.link }); + // this.dialogRef.close({ action: `set-link`, link: this.link, text: this.text || this.link }); + } else { + // this.dialogRef.close({ action: `set-link`, link: this.link }); + } + } + + public toggle(): void { + this.toggleInsert = !this.toggleInsert; + } + + public inputChanged(): void { + this.searchListLastSelected = -1; + } + + /** + * Hitting enter on the input field should save the content + */ + public keyDownFunction(event: any): void { + if (event.key === `Enter`) { + this.changeEditMode(true); + } + } + + /** + * Function to switch to or from editing-mode. + * + * @param save Boolean, whether the changes should be saved or resetted. + */ + public changeEditMode(save = false): void { + if (save) { + this.addToExtensionField(); } else { - this.dialogRef.close({ action: `set-link`, link: this.link }); + this.initForm(); + this.initInput(); } + this.editMode = !this.editMode; + } + + /** + * Initialize the value of the input. + */ + public initInput(): void { + this.inputControl = this.searchFieldInput; + this.searchListDisabledItems = []; + } + + /** + * Initializes the form. + */ + public initForm(): void { + this.extensionFieldForm = new FormGroup({ + TopicFormControl: new FormControl(this.agendaItemRepo), + MotionFormControl: new FormControl(this.motionItemRepo), + AssignmentFormControl: new FormControl(this.assignmentItemRepo) + }); + } + + /** + * Function to execute, to add the values. + */ + public addToExtensionField(): void { + const controlName = `${this.searchLists[this.selectedRepoValue].label}FormControl`; + const selectedId: number = this.extensionFieldForm.get(controlName)?.value; + const repo = this.searchRepos[this.selectedRepoValue]; + const item = repo.getViewModel(selectedId); + console.log(item); + // this.referenceText = + this.getTitle(item); + if (!this.getIsDisabled(item)) { + this.inputControl = `[${item.fqid}]`; + this.disableItem(item); + this.getIsDisabled(item); + } + } + + public getIsDisabled(item): boolean { + console.log('IS DISABLED?', this.searchListDisabledItems?.includes(item.fqid)); + return this.searchListDisabledItems?.includes(item.fqid); + } + + public disableItem(item): void { + if (!this.getIsDisabled(item.fqid)) this.searchListDisabledItems = [item.fqid]; + console.log(this.searchListDisabledItems); + } + + public getTitle(item): void { + console.log(item.content_object_id, item.collection, item.id); + } + + public sendSuccess(): void { + this.succeeded.emit(this.inputControl); } } diff --git a/client/src/app/ui/modules/editor/editor.module.ts b/client/src/app/ui/modules/editor/editor.module.ts index ee73d107ca..5dafd45ab8 100644 --- a/client/src/app/ui/modules/editor/editor.module.ts +++ b/client/src/app/ui/modules/editor/editor.module.ts @@ -8,10 +8,12 @@ import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; import { MatMenuModule } from '@angular/material/menu'; +import { MatRadioButton, MatRadioGroup } from '@angular/material/radio'; import { MatTooltipModule } from '@angular/material/tooltip'; import { OpenSlidesTranslationModule } from 'src/app/site/modules/translations'; import { MotionEditorComponent } from 'src/app/site/pages/meetings/pages/motions/components/motion-editor/motion-editor.component'; +import { SearchSelectorModule } from '../search-selector'; import { EditorComponent } from './components/editor/editor.component'; import { EditorEmbedDialogComponent } from './components/editor-embed-dialog/editor-embed-dialog.component'; import { EditorHtmlDialogComponent } from './components/editor-html-dialog/editor-html-dialog.component'; @@ -43,7 +45,10 @@ const DECLARATIONS = [ MatTooltipModule, FormsModule, ArrowNavigationDirective, - OpenSlidesTranslationModule.forChild() + OpenSlidesTranslationModule.forChild(), + SearchSelectorModule, + MatRadioButton, + MatRadioGroup ], exports: DECLARATIONS }) From de3ca5b7c865bf80a23039d9e9f6349220f3e2c9 Mon Sep 17 00:00:00 2001 From: Javier Borrego Date: Thu, 5 Mar 2026 17:54:09 +0100 Subject: [PATCH 03/14] Added title and link to the editor --- .../editor-link-dialog.component.html | 32 +++---- .../editor-link-dialog.component.ts | 91 ++++++++++++++----- 2 files changed, 84 insertions(+), 39 deletions(-) diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html index 8a455f1976..6ffffa8b8a 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html @@ -3,7 +3,7 @@

Insert/edit link

URL - +
@@ -11,7 +11,7 @@

Insert/edit link

@if (data.needsText) { Text to display - + }
@@ -19,7 +19,7 @@

Insert/edit link

Open link in ... - @@ -70,27 +70,27 @@

Link topic/motion/assignment

{{ searchLists[selectedRepoValue].label }} - @for (searchRepo of searchRepos; track $index) { - @if (selectedRepoValue === $index) { - + @for (searchRepo of searchRepos; track $index) { + @if (selectedRepoValue === $index) { + + } } - }
- - + +
}
- + @if (isUpdate) { } diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts index 5913e1c38f..a3f284803f 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts @@ -1,6 +1,7 @@ import { ChangeDetectorRef, Component, EventEmitter, Inject, inject, Input, OnInit, Output } from '@angular/core'; import { FormControl, FormGroup, UntypedFormGroup } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { Router } from '@angular/router'; import { Observable, Subscription } from 'rxjs'; import { AgendaItemRepositoryService } from 'src/app/gateways/repositories/agenda'; import { AssignmentRepositoryService } from 'src/app/gateways/repositories/assignments/assignment-repository.service'; @@ -46,6 +47,7 @@ export class EditorLinkDialogComponent implements OnInit { private _repo!: ViewModelListProvider; protected subscriptions: Subscription[] = []; + @Input() public set repo(repo: ViewModelListProvider) { this._repo = repo; @@ -56,6 +58,11 @@ export class EditorLinkDialogComponent implements OnInit { */ public selectedRepoValue = 0; + /** + * Selected id in repo-search-selector (used as flag to disable buttons) + */ + public selectedId; + private activeMeetingIdService = inject(ActiveMeetingIdService); public subscriptionConfig: SubscribeToConfig = getAgendaListMinimalSubscriptionConfig( this.activeMeetingIdService.meetingId @@ -138,17 +145,25 @@ export class EditorLinkDialogComponent implements OnInit { */ public extensionFieldForm: UntypedFormGroup; + /** + * Holds the nav suscription + */ + private navigationSubscription!: Subscription; + public constructor( @Inject(MAT_DIALOG_DATA) public data: EditorLinkDialogInput, - private dialogRef: MatDialogRef + private dialogRef: MatDialogRef, + private router: Router ) { - this.link = data.link; + this.link = { ...data.link }; this.isUpdate = !!data.link && !!data.link.href; if (!this.link.target) { this.link.target = `_self`; } - this.referenceLink = data.link; - this.referenceLink.target = `_self`; + this.referenceLink = { ...data.link }; + if (!this.referenceLink.target) { + this.referenceLink.target = `_blank`; + } } public ngOnInit(): void { @@ -162,6 +177,7 @@ export class EditorLinkDialogComponent implements OnInit { { observable: this.assignmentItemList, label: 'Assignment' } ]; this.searchRepos = [this.agendaItemRepo, this.motionItemRepo, this.assignmentItemRepo]; + console.log(this.inputControl, this.referenceText); this.initInput(); this.initForm(); } @@ -175,14 +191,25 @@ export class EditorLinkDialogComponent implements OnInit { } public save(): void { - if (this.link.href && !/^[a-zA-Z]+:\/\//.test(this.link.href)) { - this.link.href = `http://` + this.link.href; - } - console.log(this.link.href); - if (this.data.needsText) { - // this.dialogRef.close({ action: `set-link`, link: this.link, text: this.text || this.link }); + if (this.link.href) { + console.log('link esiten', this.link.href); + console.trace(); + if (!/^[a-zA-Z]+:\/\//.test(this.link.href)) { + console.log('link esiten 2'); + this.link.href = `http://` + this.link.href; + } + if (this.data.needsText) { + this.dialogRef.close({ action: `set-link`, link: this.link, text: this.text || this.link }); + } else { + this.dialogRef.close({ action: `set-link`, link: this.link }); + } } else { - // this.dialogRef.close({ action: `set-link`, link: this.link }); + console.log('referencelink esiten'); + if (!/^[a-zA-Z]+:\/\//.test(this.referenceLink.href)) { + console.log('referencelink esiten 2'); + this.sendSuccess(); + this.dialogRef.close({ action: `set-link`, text: this.referenceText, link: this.referenceLink }); + } } } @@ -214,6 +241,7 @@ export class EditorLinkDialogComponent implements OnInit { } else { this.initForm(); this.initInput(); + this.referenceText = ``; } this.editMode = !this.editMode; } @@ -238,38 +266,55 @@ export class EditorLinkDialogComponent implements OnInit { } /** - * Function to execute, to add the values. + * Function to add the values. */ public addToExtensionField(): void { const controlName = `${this.searchLists[this.selectedRepoValue].label}FormControl`; - const selectedId: number = this.extensionFieldForm.get(controlName)?.value; + this.selectedId = this.extensionFieldForm.get(controlName)?.value; const repo = this.searchRepos[this.selectedRepoValue]; - const item = repo.getViewModel(selectedId); - console.log(item); - // this.referenceText = - this.getTitle(item); + const item = repo.getViewModel(this.selectedId); + this.referenceText = item.getTitle(); if (!this.getIsDisabled(item)) { this.inputControl = `[${item.fqid}]`; + this.referenceLink.href = this.urlBuilder(item); this.disableItem(item); - this.getIsDisabled(item); } } public getIsDisabled(item): boolean { - console.log('IS DISABLED?', this.searchListDisabledItems?.includes(item.fqid)); return this.searchListDisabledItems?.includes(item.fqid); } public disableItem(item): void { if (!this.getIsDisabled(item.fqid)) this.searchListDisabledItems = [item.fqid]; - console.log(this.searchListDisabledItems); } - public getTitle(item): void { - console.log(item.content_object_id, item.collection, item.id); + public urlBuilder(item): string { + const setCollection = item.collection === 'agenda_item' ? 'agenda/topic' : item.collection; + const setId = item.collection === 'agenda_item' ? item.id : item.content_object_id.split('/')[1]; + const builtUrl = `${this.activeMeetingIdService.meetingId}/${setCollection}s/${setId}`; + const url = this.router.url.replace(/^\/.*$/, `/${builtUrl}`); + console.log( + 'THISURL:', + this.router.url, + 'URL:', + url, + 'SETCOLLECTION:', + setCollection, + 'REFERENCELINK:', + this.referenceLink, + 'RLINK HREF:', + item.fqid, + this.referenceLink.target, + 'ITEM COID: ', + item.content_object_id.split(`/`)[1], + 'ITEM: ', + item + ); + return url; } public sendSuccess(): void { - this.succeeded.emit(this.inputControl); + this.succeeded.emit(this.referenceLink.href); } } From e479b39be85cf40df5aaa99cde37076016806482 Mon Sep 17 00:00:00 2001 From: Javier Borrego Date: Fri, 6 Mar 2026 11:50:46 +0100 Subject: [PATCH 04/14] Built routes --- .../editor-link-dialog.component.html | 5 +- .../editor-link-dialog.component.scss | 6 ++ .../editor-link-dialog.component.ts | 66 +++---------------- 3 files changed, 18 insertions(+), 59 deletions(-) diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html index 6ffffa8b8a..5c3d256b8f 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html @@ -3,7 +3,7 @@

Insert/edit link

URL - +
@@ -44,14 +44,13 @@

Link topic/motion/assignment

matInput osAutofocus [(ngModel)]="inputControl" - (change)="inputChanged()" (keydown)="keyDownFunction($event)" />
diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss index 35fc17d328..c74c08d6bc 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss @@ -18,6 +18,12 @@ mat-form-field { margin-top: 10px; } +.radio-group { + display: flex; + gap: 15px; + margin-bottom: 5px +} + .internalReferences { display: flex; diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts index a3f284803f..0eb6433854 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectorRef, Component, EventEmitter, Inject, inject, Input, OnInit, Output } from '@angular/core'; +import { Component, EventEmitter, Inject, inject, Input, OnInit, Output } from '@angular/core'; import { FormControl, FormGroup, UntypedFormGroup } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Router } from '@angular/router'; @@ -58,11 +58,6 @@ export class EditorLinkDialogComponent implements OnInit { */ public selectedRepoValue = 0; - /** - * Selected id in repo-search-selector (used as flag to disable buttons) - */ - public selectedId; - private activeMeetingIdService = inject(ActiveMeetingIdService); public subscriptionConfig: SubscribeToConfig = getAgendaListMinimalSubscriptionConfig( this.activeMeetingIdService.meetingId @@ -103,12 +98,6 @@ export class EditorLinkDialogComponent implements OnInit { */ public editMode = false; - /** - * The index of the search list that was last selected from, or -1 if something was written in - * the input field afterwards. - */ - private searchListLastSelected = -1; - /** * Model for the input-field. */ @@ -119,8 +108,6 @@ export class EditorLinkDialogComponent implements OnInit { */ private searchListDisabledItems = []; - private cd: ChangeDetectorRef; - /** * The item from the list that will be added to the editor. */ @@ -145,11 +132,6 @@ export class EditorLinkDialogComponent implements OnInit { */ public extensionFieldForm: UntypedFormGroup; - /** - * Holds the nav suscription - */ - private navigationSubscription!: Subscription; - public constructor( @Inject(MAT_DIALOG_DATA) public data: EditorLinkDialogInput, private dialogRef: MatDialogRef, @@ -177,7 +159,6 @@ export class EditorLinkDialogComponent implements OnInit { { observable: this.assignmentItemList, label: 'Assignment' } ]; this.searchRepos = [this.agendaItemRepo, this.motionItemRepo, this.assignmentItemRepo]; - console.log(this.inputControl, this.referenceText); this.initInput(); this.initForm(); } @@ -192,10 +173,7 @@ export class EditorLinkDialogComponent implements OnInit { public save(): void { if (this.link.href) { - console.log('link esiten', this.link.href); - console.trace(); if (!/^[a-zA-Z]+:\/\//.test(this.link.href)) { - console.log('link esiten 2'); this.link.href = `http://` + this.link.href; } if (this.data.needsText) { @@ -204,11 +182,12 @@ export class EditorLinkDialogComponent implements OnInit { this.dialogRef.close({ action: `set-link`, link: this.link }); } } else { - console.log('referencelink esiten'); if (!/^[a-zA-Z]+:\/\//.test(this.referenceLink.href)) { - console.log('referencelink esiten 2'); - this.sendSuccess(); - this.dialogRef.close({ action: `set-link`, text: this.referenceText, link: this.referenceLink }); + this.dialogRef.close({ + action: `set-link`, + text: this.referenceText, + link: this.referenceLink + }); } } } @@ -217,10 +196,6 @@ export class EditorLinkDialogComponent implements OnInit { this.toggleInsert = !this.toggleInsert; } - public inputChanged(): void { - this.searchListLastSelected = -1; - } - /** * Hitting enter on the input field should save the content */ @@ -270,10 +245,10 @@ export class EditorLinkDialogComponent implements OnInit { */ public addToExtensionField(): void { const controlName = `${this.searchLists[this.selectedRepoValue].label}FormControl`; - this.selectedId = this.extensionFieldForm.get(controlName)?.value; + const selectedId = this.extensionFieldForm.get(controlName)?.value; const repo = this.searchRepos[this.selectedRepoValue]; - const item = repo.getViewModel(this.selectedId); - this.referenceText = item.getTitle(); + const item = repo.getViewModel(selectedId); + this.referenceText = ' ' + item.getTitle() + ' '; if (!this.getIsDisabled(item)) { this.inputControl = `[${item.fqid}]`; this.referenceLink.href = this.urlBuilder(item); @@ -291,30 +266,9 @@ export class EditorLinkDialogComponent implements OnInit { public urlBuilder(item): string { const setCollection = item.collection === 'agenda_item' ? 'agenda/topic' : item.collection; - const setId = item.collection === 'agenda_item' ? item.id : item.content_object_id.split('/')[1]; + const setId = item.collection === 'agenda_item' ? item.content_object_id?.split('/')[1] : item.id; const builtUrl = `${this.activeMeetingIdService.meetingId}/${setCollection}s/${setId}`; const url = this.router.url.replace(/^\/.*$/, `/${builtUrl}`); - console.log( - 'THISURL:', - this.router.url, - 'URL:', - url, - 'SETCOLLECTION:', - setCollection, - 'REFERENCELINK:', - this.referenceLink, - 'RLINK HREF:', - item.fqid, - this.referenceLink.target, - 'ITEM COID: ', - item.content_object_id.split(`/`)[1], - 'ITEM: ', - item - ); return url; } - - public sendSuccess(): void { - this.succeeded.emit(this.referenceLink.href); - } } From 772fbbb9ef6144ff08ce4bd0e4d904ad29c28f76 Mon Sep 17 00:00:00 2001 From: Javier Borrego Date: Fri, 6 Mar 2026 12:03:08 +0100 Subject: [PATCH 05/14] Cleanup run --- .../editor-link-dialog.component.html | 41 ++++++++++--------- .../editor-link-dialog.component.scss | 2 +- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html index 5c3d256b8f..746e23b6ea 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html @@ -3,7 +3,7 @@

Insert/edit link

URL - +
@@ -11,7 +11,7 @@

Insert/edit link

@if (data.needsText) { Text to display - + }
@@ -19,7 +19,7 @@

Insert/edit link

Open link in ... - @@ -48,11 +48,7 @@

Link topic/motion/assignment

/>
- + Topics @@ -69,22 +65,27 @@

Link topic/motion/assignment

{{ searchLists[selectedRepoValue].label }} - @for (searchRepo of searchRepos; track $index) { - @if (selectedRepoValue === $index) { - - } + @for (searchRepo of searchRepos; track $index) { + @if (selectedRepoValue === $index) { + } + }
- - + +
}
diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss index c74c08d6bc..5d585b8aa9 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss @@ -21,7 +21,7 @@ mat-form-field { .radio-group { display: flex; gap: 15px; - margin-bottom: 5px + margin-bottom: 5px; } .internalReferences { From b7f131584a627e2c07d3b5b083e6aab7b631ab2d Mon Sep 17 00:00:00 2001 From: Javier Borrego Date: Fri, 6 Mar 2026 13:34:46 +0100 Subject: [PATCH 06/14] Revert "Agenda to PDF export style changed" This reverts commit c64a1c51ccc404430c4e632b1797aa4b9e1d55cb. --- .../pdf-document.service.ts | 2 +- .../pages/agenda/agenda.subscription.ts | 15 +- .../agenda-pdf-catalog-export.service.ts | 130 ++++-------------- 3 files changed, 26 insertions(+), 121 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 ac9d4536fe..688388f154 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/agenda.subscription.ts b/client/src/app/site/pages/meetings/pages/agenda/agenda.subscription.ts index cf39cc2b0a..c0063e5a1b 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,16 +218,7 @@ export const getAgendaExportSubscriptionConfig: SubscriptionConfigGenerator = (. follow: [ { idField: `content_object_id`, - fieldset: [ - `number`, - `title`, - `agenda_item_id`, - `text`, - `description`, - `poll_ids`, - `assignment`, - ...MEETING_ROUTING_FIELDS - ], + fieldset: [`number`, `title`, `agenda_item_id`, `text`, `poll_ids`, ...MEETING_ROUTING_FIELDS], follow: [ { idField: `list_of_speakers_id`, @@ -280,10 +271,6 @@ 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 357de4e412..4f689c973a 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,7 +11,6 @@ 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'; @@ -232,12 +231,7 @@ export class AgendaPdfCatalogExportService { const useTitle: boolean = info.includes(`title`); const itemNumber: string = agendaItem.item_number ?? ``; const title: string = agendaItem.content_object!.getTitle(); - let styleName = `header2`; - let margin = ``; - if (agendaItem.level > 0) { - styleName = `header-child`; - margin = `margin-header-child`; - } + const styleName = agendaItem.level ? `header-child` : `header2`; let numberOrTitle = ``; if (agendaItem.content_object?.collection === `motion`) { const motion = agendaItem.content_object; @@ -258,16 +252,6 @@ 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}`; @@ -279,45 +263,17 @@ export class AgendaPdfCatalogExportService { } return { style: this.getStyle(styleName), - text: numberOrTitle, - margin: this.getStyle(margin) + text: numberOrTitle }; } private createTextDoc(agendaItem: ViewAgendaItem): Content { - const style = this.getStyle(`body-text`); - const margin = this.getStyle(`margin-body-text`); if (!this.isTopic(agendaItem.content_object)) { - // 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 []; + } + if (agendaItem.content_object?.getCSVExportText) { + const entry = this.htmlToPdfService.convertHtml({ htmlText: agendaItem.content_object?.text ?? `` }); + return entry; } return []; } @@ -330,45 +286,14 @@ export class AgendaPdfCatalogExportService { const entry = this.htmlToPdfService.convertHtml({ htmlText: moderationNotes }); 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 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] - } - ]; - } + return [ + { + text: this.translate.instant(`Moderation note`), + style: this.getStyle(`header3`), + margin: this.getStyle(`margin-header3`) + }, + entry + ]; } else { return []; } @@ -592,34 +517,27 @@ export class AgendaPdfCatalogExportService { private getStyle(name: string): any { switch (name) { case `header1`: - return { bold: true, fontSize: 20 }; + return { bold: true, fontSize: 24 }; case `header2`: - return { bold: true, fontSize: 16 }; + return { bold: true, fontSize: 20 }; case `header3`: - return { bold: true, fontSize: 12 }; - case `header-child`: return { bold: true, fontSize: 14 }; + case `header-child`: + return { bold: true, fontSize: 16 }; case `table-header`: - return { bold: true, fontSize: 10 }; - case `body-text`: - return { fontSize: 10 }; + return { bold: true, fontSize: 12 }; case `grey`: return { layout: TABLEROW_GREY }; case `italics`: return { italics: true }; case `margin-header1`: - // [L,U,R,D] - return [0, 10, 0, 0]; + return [0, 0, 0, 20]; case `margin-header3`: - return [15, 10, 0, 0]; - case `margin-header-child`: - return [15, 10, 0, 0]; + return [0, 15, 0, 10]; case `margin-type-text`: - return [12, 10, 0, 0]; - case `margin-body-text`: - return [20, 10, 0, 5]; + return [0, 0, 0, 10]; case `margin-item`: - return [0, 0, 0, 0]; + return [0, 0, 0, 5]; case `margin-item-2`: return [0, 10, 0, 5]; default: From 8183481ab502bb48951efe6fa17b442f2a56b3e3 Mon Sep 17 00:00:00 2001 From: Javier Borrego Date: Mon, 9 Mar 2026 11:13:12 +0100 Subject: [PATCH 07/14] Cleanup and routing fix --- .../editor-link-dialog.component.ts | 48 ++++--------------- 1 file changed, 10 insertions(+), 38 deletions(-) diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts index 0eb6433854..320ff2919d 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts @@ -1,8 +1,8 @@ -import { Component, EventEmitter, Inject, inject, Input, OnInit, Output } from '@angular/core'; +import { Component, Inject, inject, Input, OnInit } from '@angular/core'; import { FormControl, FormGroup, UntypedFormGroup } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Router } from '@angular/router'; -import { Observable, Subscription } from 'rxjs'; +import { Observable } from 'rxjs'; import { AgendaItemRepositoryService } from 'src/app/gateways/repositories/agenda'; import { AssignmentRepositoryService } from 'src/app/gateways/repositories/assignments/assignment-repository.service'; import { MotionRepositoryService } from 'src/app/gateways/repositories/motions'; @@ -12,7 +12,6 @@ import { ViewAssignment } from 'src/app/site/pages/meetings/pages/assignments/vi import { ViewMotion } from 'src/app/site/pages/meetings/pages/motions/view-models/view-motion'; import { ActiveMeetingIdService } from 'src/app/site/pages/meetings/services/active-meeting-id.service'; import { SubscribeToConfig } from 'src/app/site/services/model-request.service'; -import { ViewModelListProvider } from 'src/app/ui/base/view-model-list-provider'; interface EditorLinkDialogInput { link?: { href: string; target?: string }; @@ -44,15 +43,6 @@ export class EditorLinkDialogComponent implements OnInit { public toggleInsert: boolean; - private _repo!: ViewModelListProvider; - - protected subscriptions: Subscription[] = []; - - @Input() - public set repo(repo: ViewModelListProvider) { - this._repo = repo; - } - /** * Values selected by radio buttons */ @@ -69,30 +59,6 @@ export class EditorLinkDialogComponent implements OnInit { @Input() public searchFieldInput!: string; - /** - * Optional label for the input. - */ - @Input() - public extensionLabel!: string; - - /** - * Title for this component. - */ - @Input() - public title!: string; - - /** - * Boolean, whether the input and the search-list can be changed. - */ - @Input() - public canBeEdited = true; - - /** - * EventEmitter, when clicking on the 'save'-button. - */ - @Output() - public succeeded = new EventEmitter(); - /** * Boolean to decide, whether to open the extension-input and search-list. */ @@ -265,8 +231,14 @@ export class EditorLinkDialogComponent implements OnInit { } public urlBuilder(item): string { - const setCollection = item.collection === 'agenda_item' ? 'agenda/topic' : item.collection; - const setId = item.collection === 'agenda_item' ? item.content_object_id?.split('/')[1] : item.id; + const parts = item.content_object_id?.split('/'); + const isAgendaItem = item.collection === 'agenda_item' && item.content_object_id?.split('/')[0] === 'topic'; + const setCollection: string = isAgendaItem + ? 'agenda/topic' + : item.collection === 'agenda_item' + ? parts?.[0] + : item.collection; + const setId: number = isAgendaItem ? parts?.[1] : item.content_object_id ? parts?.[1] : item.id; const builtUrl = `${this.activeMeetingIdService.meetingId}/${setCollection}s/${setId}`; const url = this.router.url.replace(/^\/.*$/, `/${builtUrl}`); return url; From a064b2e3b0d0ec164e317b02472c256f8436392c Mon Sep 17 00:00:00 2001 From: Javier Borrego Date: Thu, 12 Mar 2026 17:12:20 +0100 Subject: [PATCH 08/14] Done requested changes --- .../editor-link-dialog.component.html | 145 ++++++++++-------- .../editor-link-dialog.component.scss | 20 +-- .../editor-link-dialog.component.ts | 56 ++++--- 3 files changed, 108 insertions(+), 113 deletions(-) diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html index 746e23b6ea..99fd1ba047 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html @@ -1,66 +1,82 @@ -

Insert/edit link

-
-
- - URL - - -
- -
- @if (data.needsText) { +
+

Insert/edit external link

+ +
+@if (toggleExternalReference) { +
+
- Text to display - + URL + - } -
- -
- - Open link in ... - - -
-
-

Link topic/motion/assignment

-
+
+ @if (data.needsText) { + + Text to display + + } - +
+
+ + Open link in ... + + +
- @if (toggleInsert) { +} +
+

Link a topic/motion/assignment

+ +
+@if (toggleInternalReference) { +
- - Selected item - - -
- - - Topics - - - Motions - - - Assignments - - -
- + + + Topics + + + Motions + + + Assignments + + {{ searchLists[selectedRepoValue].label }} @@ -79,16 +95,9 @@

Link topic/motion/assignment

}
-
- - -
- } -
+
+} +
@if (isUpdate) { diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss index 5d585b8aa9..ce964b14ed 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss @@ -2,18 +2,6 @@ mat-form-field { width: 100%; } -.matDialogLinkActions { - display: flex; - flex-direction: row; - justify-content: flex-end; - margin-bottom: -20px; - margin-top: -15px; -} - -.matDialogActions { - margin-top: -15px; -} - .mat-form-margin-top { margin-top: 10px; } @@ -24,16 +12,18 @@ mat-form-field { margin-bottom: 5px; } -.internalReferences { +.references { display: flex; .internalReferencesTitle { margin-bottom: 7px; - padding-right: 29px; + justify-self: start; } - .internalReferencesArrows { + .arrows { display: flex; margin-top: 7px; + margin-left: auto; + transform: translateX(-20px); } } diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts index 320ff2919d..6102f826d5 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts @@ -41,7 +41,8 @@ export class EditorLinkDialogComponent implements OnInit { public referenceText = ``; - public toggleInsert: boolean; + public toggleInternalReference: boolean; + public toggleExternalReference: boolean; /** * Values selected by radio buttons @@ -69,11 +70,6 @@ export class EditorLinkDialogComponent implements OnInit { */ public inputControl; - /** - * Prevent selecting the same value twice. - */ - private searchListDisabledItems = []; - /** * The item from the list that will be added to the editor. */ @@ -98,6 +94,11 @@ export class EditorLinkDialogComponent implements OnInit { */ public extensionFieldForm: UntypedFormGroup; + /** + * The selected internal item + */ + public item; + public constructor( @Inject(MAT_DIALOG_DATA) public data: EditorLinkDialogInput, private dialogRef: MatDialogRef, @@ -148,6 +149,7 @@ export class EditorLinkDialogComponent implements OnInit { this.dialogRef.close({ action: `set-link`, link: this.link }); } } else { + this.changeEditMode(true); if (!/^[a-zA-Z]+:\/\//.test(this.referenceLink.href)) { this.dialogRef.close({ action: `set-link`, @@ -158,8 +160,8 @@ export class EditorLinkDialogComponent implements OnInit { } } - public toggle(): void { - this.toggleInsert = !this.toggleInsert; + public toggleArrow(prop: 'toggleInternalReference' | 'toggleExternalReference'): void { + this[prop] = !this[prop]; } /** @@ -178,7 +180,7 @@ export class EditorLinkDialogComponent implements OnInit { */ public changeEditMode(save = false): void { if (save) { - this.addToExtensionField(); + this.addReference(); } else { this.initForm(); this.initInput(); @@ -192,7 +194,6 @@ export class EditorLinkDialogComponent implements OnInit { */ public initInput(): void { this.inputControl = this.searchFieldInput; - this.searchListDisabledItems = []; } /** @@ -204,30 +205,21 @@ export class EditorLinkDialogComponent implements OnInit { MotionFormControl: new FormControl(this.motionItemRepo), AssignmentFormControl: new FormControl(this.assignmentItemRepo) }); + this.extensionFieldForm.valueChanges.subscribe(() => { + const controlName = `${this.searchLists[this.selectedRepoValue].label}FormControl`; + const selectedId = this.extensionFieldForm.get(controlName)?.value; + const repo = this.searchRepos[this.selectedRepoValue]; + this.item = repo.getViewModel(selectedId); + this.addReference(); + }); } /** * Function to add the values. */ - public addToExtensionField(): void { - const controlName = `${this.searchLists[this.selectedRepoValue].label}FormControl`; - const selectedId = this.extensionFieldForm.get(controlName)?.value; - const repo = this.searchRepos[this.selectedRepoValue]; - const item = repo.getViewModel(selectedId); - this.referenceText = ' ' + item.getTitle() + ' '; - if (!this.getIsDisabled(item)) { - this.inputControl = `[${item.fqid}]`; - this.referenceLink.href = this.urlBuilder(item); - this.disableItem(item); - } - } - - public getIsDisabled(item): boolean { - return this.searchListDisabledItems?.includes(item.fqid); - } - - public disableItem(item): void { - if (!this.getIsDisabled(item.fqid)) this.searchListDisabledItems = [item.fqid]; + public addReference(): void { + this.referenceText = this.item ? `${this.item.getTitle()}` : ''; + this.referenceLink.href = this.item ? this.urlBuilder(this.item) : ''; } public urlBuilder(item): string { @@ -238,7 +230,11 @@ export class EditorLinkDialogComponent implements OnInit { : item.collection === 'agenda_item' ? parts?.[0] : item.collection; - const setId: number = isAgendaItem ? parts?.[1] : item.content_object_id ? parts?.[1] : item.id; + const setId: number = isAgendaItem + ? item.content_object.sequential_number + : item.content_object_id + ? parts?.[1] + : item.sequential_number; const builtUrl = `${this.activeMeetingIdService.meetingId}/${setCollection}s/${setId}`; const url = this.router.url.replace(/^\/.*$/, `/${builtUrl}`); return url; From e85474844280b4772b10172df418eecd50f3839b Mon Sep 17 00:00:00 2001 From: Javier Borrego Date: Fri, 13 Mar 2026 17:13:57 +0100 Subject: [PATCH 09/14] Fix overwriting previous embedded items --- .../editor-link-dialog.component.html | 14 +++--- .../editor-link-dialog.component.scss | 9 ---- .../editor-link-dialog.component.ts | 43 ++++++++----------- .../components/editor/editor.component.ts | 1 + 4 files changed, 28 insertions(+), 39 deletions(-) diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html index 99fd1ba047..e5d4a472fe 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html @@ -47,8 +47,8 @@

Link

@if (toggleInternalReference) {
-
- +
+ Link Assignments - + {{ searchLists[selectedRepoValue].label }} @@ -99,9 +99,11 @@

Link }
- + @if (isUpdate) { - + } - +
diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss index ce964b14ed..792b403134 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss @@ -2,10 +2,6 @@ mat-form-field { width: 100%; } -.mat-form-margin-top { - margin-top: 10px; -} - .radio-group { display: flex; gap: 15px; @@ -15,11 +11,6 @@ mat-form-field { .references { display: flex; - .internalReferencesTitle { - margin-bottom: 7px; - justify-self: start; - } - .arrows { display: flex; margin-top: 7px; diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts index 6102f826d5..f4e7999500 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts @@ -1,5 +1,5 @@ import { Component, Inject, inject, Input, OnInit } from '@angular/core'; -import { FormControl, FormGroup, UntypedFormGroup } from '@angular/forms'; +import { FormBuilder, FormControl, FormGroup, UntypedFormGroup } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Router } from '@angular/router'; import { Observable } from 'rxjs'; @@ -44,11 +44,6 @@ export class EditorLinkDialogComponent implements OnInit { public toggleInternalReference: boolean; public toggleExternalReference: boolean; - /** - * Values selected by radio buttons - */ - public selectedRepoValue = 0; - private activeMeetingIdService = inject(ActiveMeetingIdService); public subscriptionConfig: SubscribeToConfig = getAgendaListMinimalSubscriptionConfig( this.activeMeetingIdService.meetingId @@ -70,10 +65,6 @@ export class EditorLinkDialogComponent implements OnInit { */ public inputControl; - /** - * The item from the list that will be added to the editor. - */ - public itemToReference; /** * Init Repos */ @@ -92,17 +83,24 @@ export class EditorLinkDialogComponent implements OnInit { /** * FormGroup for the search-list. */ - public extensionFieldForm: UntypedFormGroup; + public internalReferenceForm: UntypedFormGroup; /** * The selected internal item */ public item; + /** + * Values selected by radio buttons + */ + public internalRadioOptions: FormGroup; + public selectedRepoValue = 0; + public constructor( @Inject(MAT_DIALOG_DATA) public data: EditorLinkDialogInput, private dialogRef: MatDialogRef, - private router: Router + private router: Router, + private fb: FormBuilder ) { this.link = { ...data.link }; this.isUpdate = !!data.link && !!data.link.href; @@ -113,6 +111,12 @@ export class EditorLinkDialogComponent implements OnInit { if (!this.referenceLink.target) { this.referenceLink.target = `_blank`; } + this.internalRadioOptions = this.fb.group({ + options: [0] + }); + this.internalRadioOptions.valueChanges.subscribe(() => { + this.selectedRepoValue = this.internalRadioOptions.get('options').value; + }); } public ngOnInit(): void { @@ -164,15 +168,6 @@ export class EditorLinkDialogComponent implements OnInit { this[prop] = !this[prop]; } - /** - * Hitting enter on the input field should save the content - */ - public keyDownFunction(event: any): void { - if (event.key === `Enter`) { - this.changeEditMode(true); - } - } - /** * Function to switch to or from editing-mode. * @@ -200,14 +195,14 @@ export class EditorLinkDialogComponent implements OnInit { * Initializes the form. */ public initForm(): void { - this.extensionFieldForm = new FormGroup({ + this.internalReferenceForm = new FormGroup({ TopicFormControl: new FormControl(this.agendaItemRepo), MotionFormControl: new FormControl(this.motionItemRepo), AssignmentFormControl: new FormControl(this.assignmentItemRepo) }); - this.extensionFieldForm.valueChanges.subscribe(() => { + this.internalReferenceForm.valueChanges.subscribe(() => { const controlName = `${this.searchLists[this.selectedRepoValue].label}FormControl`; - const selectedId = this.extensionFieldForm.get(controlName)?.value; + const selectedId = this.internalReferenceForm.get(controlName)?.value; const repo = this.searchRepos[this.selectedRepoValue]; this.item = repo.getViewModel(selectedId); this.addReference(); diff --git a/client/src/app/ui/modules/editor/components/editor/editor.component.ts b/client/src/app/ui/modules/editor/components/editor/editor.component.ts index c7a24320ec..f98058285b 100644 --- a/client/src/app/ui/modules/editor/components/editor/editor.component.ts +++ b/client/src/app/ui/modules/editor/components/editor/editor.component.ts @@ -379,6 +379,7 @@ export class EditorComponent extends BaseFormControlComponent implements } ] }) + .insertContent({ type: `text`, text: ` ` }) .run(); } else { chain.setLink(result.link).run(); From 6607771bc9e5f7c0bd1e7c211d62f0084461c28f Mon Sep 17 00:00:00 2001 From: Javier Borrego Date: Mon, 16 Mar 2026 11:47:14 +0100 Subject: [PATCH 10/14] Changed FormsModule to ReactiveFormsModule and improved logic --- .../editor-link-dialog.component.html | 25 +++++---- .../editor-link-dialog.component.ts | 52 ++++++++++++++----- 2 files changed, 54 insertions(+), 23 deletions(-) diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html index e5d4a472fe..8230c8b541 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html @@ -9,25 +9,25 @@

Insert/edi

@if (toggleExternalReference) { -
+
URL - +
@if (data.needsText) { Text to display - + }
Open link in ... - @@ -52,7 +52,7 @@

Link @@ -61,7 +61,7 @@

Link @@ -70,7 +70,7 @@

Link @@ -85,7 +85,7 @@

Link @if (selectedRepoValue === $index) { Link }
- @if (isUpdate) { diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts index f4e7999500..0d2987e580 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts @@ -37,9 +37,9 @@ export class EditorLinkDialogComponent implements OnInit { public text = ``; - public referenceLink: { href: string; target?: string }; + public internalLink: { href: string; target?: string }; - public referenceText = ``; + public internalText = ``; public toggleInternalReference: boolean; public toggleExternalReference: boolean; @@ -96,20 +96,41 @@ export class EditorLinkDialogComponent implements OnInit { public internalRadioOptions: FormGroup; public selectedRepoValue = 0; + /** + * Values for external link + */ + public externalLink: FormGroup; + public externalUrl: string; + public externalText: string; + public externalDisplayMode: string; + public constructor( @Inject(MAT_DIALOG_DATA) public data: EditorLinkDialogInput, private dialogRef: MatDialogRef, private router: Router, private fb: FormBuilder ) { + // External reference this.link = { ...data.link }; this.isUpdate = !!data.link && !!data.link.href; if (!this.link.target) { this.link.target = `_self`; } - this.referenceLink = { ...data.link }; - if (!this.referenceLink.target) { - this.referenceLink.target = `_blank`; + this.externalLink = this.fb.group({ + extUrl: new FormControl(), + extText: new FormControl(), + extDisplayMode: new FormControl() + }); + this.externalLink.valueChanges.subscribe(() => { + this.externalUrl = this.externalLink.get('extUrl').value; + this.externalText = this.externalLink.get('extText').value; + this.externalDisplayMode = this.externalLink.get('extDisplayMode').value; + }); + + // Internal reference + this.internalLink = { ...data.link }; + if (!this.internalLink.target) { + this.internalLink.target = `_blank`; } this.internalRadioOptions = this.fb.group({ options: [0] @@ -143,22 +164,22 @@ export class EditorLinkDialogComponent implements OnInit { } public save(): void { - if (this.link.href) { + if (this.externalUrl) { if (!/^[a-zA-Z]+:\/\//.test(this.link.href)) { - this.link.href = `http://` + this.link.href; + this.link.href = this.externalUrl.includes(`http`) ? this.externalUrl : `http://` + this.externalUrl; } if (this.data.needsText) { - this.dialogRef.close({ action: `set-link`, link: this.link, text: this.text || this.link }); + this.dialogRef.close({ action: `set-link`, link: this.link, text: this.externalText || this.link }); } else { this.dialogRef.close({ action: `set-link`, link: this.link }); } } else { this.changeEditMode(true); - if (!/^[a-zA-Z]+:\/\//.test(this.referenceLink.href)) { + if (!/^[a-zA-Z]+:\/\//.test(this.internalLink.href)) { this.dialogRef.close({ action: `set-link`, - text: this.referenceText, - link: this.referenceLink + text: this.internalText, + link: this.internalLink }); } } @@ -179,7 +200,7 @@ export class EditorLinkDialogComponent implements OnInit { } else { this.initForm(); this.initInput(); - this.referenceText = ``; + this.internalText = ``; } this.editMode = !this.editMode; } @@ -205,6 +226,9 @@ export class EditorLinkDialogComponent implements OnInit { const selectedId = this.internalReferenceForm.get(controlName)?.value; const repo = this.searchRepos[this.selectedRepoValue]; this.item = repo.getViewModel(selectedId); + const action = this.item ? 'disable' : 'enable'; + ['extUrl', 'extText', 'extDisplayMode'].forEach(name => this.externalLink.get(name)?.[action]()); + this.addReference(); }); } @@ -213,8 +237,8 @@ export class EditorLinkDialogComponent implements OnInit { * Function to add the values. */ public addReference(): void { - this.referenceText = this.item ? `${this.item.getTitle()}` : ''; - this.referenceLink.href = this.item ? this.urlBuilder(this.item) : ''; + this.internalText = this.item ? `${this.item.getTitle()}` : ''; + this.internalLink.href = this.item ? this.urlBuilder(this.item) : ''; } public urlBuilder(item): string { From 67f752edf3f4150e1f62e553e4ee552d0194fd79 Mon Sep 17 00:00:00 2001 From: Javier Borrego Date: Wed, 18 Mar 2026 12:28:47 +0100 Subject: [PATCH 11/14] added reset button and improved keywords navigation --- .../editor-link-dialog.component.html | 29 ++++++++++++++++--- .../editor-link-dialog.component.scss | 7 +++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html index 8230c8b541..2c34fc570d 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html @@ -1,6 +1,14 @@ -
+

Insert/edit external link

-
} -
+

Link a topic/motion/assignment

-
+
+ +
} diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss index 792b403134..a316e7dcaa 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss @@ -18,3 +18,10 @@ mat-form-field { transform: translateX(-20px); } } + +.clear-button { + display: flex; + justify-content: flex-end; + margin-top: -15px; + margin-bottom: -20px; +} From e2fd46a4f26bb6f950a3eb9404ac93f74ce48cba Mon Sep 17 00:00:00 2001 From: Javier Borrego Date: Wed, 18 Mar 2026 12:32:57 +0100 Subject: [PATCH 12/14] Revert "added reset button and improved keywords navigation" This reverts commit 67f752edf3f4150e1f62e553e4ee552d0194fd79. --- .../editor-link-dialog.component.html | 29 +++---------------- .../editor-link-dialog.component.scss | 7 ----- 2 files changed, 4 insertions(+), 32 deletions(-) diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html index 2c34fc570d..8230c8b541 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html @@ -1,14 +1,6 @@ -
+

Insert/edit external link

-
} -
+

Link a topic/motion/assignment

-
-
- -
} diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss index a316e7dcaa..792b403134 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss @@ -18,10 +18,3 @@ mat-form-field { transform: translateX(-20px); } } - -.clear-button { - display: flex; - justify-content: flex-end; - margin-top: -15px; - margin-bottom: -20px; -} From 33905a2749f5adba94eb38b4f4e5a9b46e75b1ed Mon Sep 17 00:00:00 2001 From: Javier Borrego Date: Wed, 18 Mar 2026 12:43:44 +0100 Subject: [PATCH 13/14] added reset button and improved keywords navigation --- .../editor-link-dialog.component.html | 29 ++++++++++++++++--- .../editor-link-dialog.component.scss | 7 +++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html index 8230c8b541..2c34fc570d 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html @@ -1,6 +1,14 @@ -
+

Insert/edit external link

-
} -
+

Link a topic/motion/assignment

-
+
+ +
} diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss index 792b403134..a316e7dcaa 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss @@ -18,3 +18,10 @@ mat-form-field { transform: translateX(-20px); } } + +.clear-button { + display: flex; + justify-content: flex-end; + margin-top: -15px; + margin-bottom: -20px; +} From 909723132ed1598dec8bb99605f9fd85459a6c4a Mon Sep 17 00:00:00 2001 From: Javier Borrego Date: Fri, 27 Mar 2026 14:04:43 +0100 Subject: [PATCH 14/14] Keyword navigation done --- .../editor-link-dialog.component.html | 41 +++++++++++-------- .../editor-link-dialog.component.scss | 16 ++++++++ .../editor-link-dialog.component.ts | 10 +++-- 3 files changed, 45 insertions(+), 22 deletions(-) diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html index 2c34fc570d..5e6d907fb7 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html @@ -1,20 +1,23 @@
-

Insert/edit external link

- +
+

Insert/edit external link

+ +
@if (toggleExternalReference) {
@@ -45,21 +48,23 @@

Insert/edi }
-

Link a topic/motion/assignment

- +
+

Link a topic/motion/assignment

+ +
@if (toggleInternalReference) {
diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss index a316e7dcaa..45cb5bd063 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss @@ -19,6 +19,22 @@ mat-form-field { } } +// How the focus is highlighted must be discussed further. Actual style is provisional. + +.title { + padding: 0; +} + +.title:focus { + padding: 0; + outline: none; + box-shadow: none; + & h1 { + background-color: #eee; + border-radius: 25px; + } +} + .clear-button { display: flex; justify-content: flex-end; diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts index 0d2987e580..47371b273d 100644 --- a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts @@ -2,6 +2,7 @@ import { Component, Inject, inject, Input, OnInit } from '@angular/core'; import { FormBuilder, FormControl, FormGroup, UntypedFormGroup } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Router } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; import { Observable } from 'rxjs'; import { AgendaItemRepositoryService } from 'src/app/gateways/repositories/agenda'; import { AssignmentRepositoryService } from 'src/app/gateways/repositories/assignments/assignment-repository.service'; @@ -108,7 +109,8 @@ export class EditorLinkDialogComponent implements OnInit { @Inject(MAT_DIALOG_DATA) public data: EditorLinkDialogInput, private dialogRef: MatDialogRef, private router: Router, - private fb: FormBuilder + private fb: FormBuilder, + private translate: TranslateService ) { // External reference this.link = { ...data.link }; @@ -146,9 +148,9 @@ export class EditorLinkDialogComponent implements OnInit { this.assignmentItemList = this.assignmentItemRepo.getSortedViewModelListObservable(); this.searchLists = [ - { observable: this.agendaItemList, label: 'Topic' }, - { observable: this.motionItemList, label: 'Motion' }, - { observable: this.assignmentItemList, label: 'Assignment' } + { observable: this.agendaItemList, label: this.translate.instant('Topic') }, + { observable: this.motionItemList, label: this.translate.instant('Motion') }, + { observable: this.assignmentItemList, label: this.translate.instant('Assignment') } ]; this.searchRepos = [this.agendaItemRepo, this.motionItemRepo, this.assignmentItemRepo]; this.initInput();