Skip to content
Draft
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,94 @@ <h1 mat-dialog-title translate>Insert/edit link</h1>
<div>
<mat-form-field>
<mat-label translate>URL</mat-label>
<input matInput [(ngModel)]="link.href" />
<input matInput [disabled]="referenceText !== ``" [(ngModel)]="link.href" />
</mat-form-field>
</div>

<div>
@if (data.needsText) {
<mat-form-field>
<mat-label translate>Text to display</mat-label>
<input matInput [(ngModel)]="text" />
<input matInput [disabled]="referenceText !== ``" [(ngModel)]="text" />
</mat-form-field>
}
</div>

<div>
<mat-form-field>
<mat-label translate>Open link in ...</mat-label>
<select matNativeControl [(ngModel)]="link.target">
<select matNativeControl [disabled]="referenceText !== ``" [(ngModel)]="link.target">
<option translate value="_self">Current window</option>
<option translate value="_blank">New window</option>
</select>
</mat-form-field>
</div>
<div class="internalReferences">
<h2 class="internalReferencesTitle">Link topic/motion/assignment</h2>
<button class="internalReferencesArrows" matIconButton (click)="toggle()">
@if (toggleInsert) {
<mat-icon>keyboard_arrow_up</mat-icon>
} @else {
<mat-icon>keyboard_arrow_down</mat-icon>
}
</button>
</div>
@if (toggleInsert) {
<div class="card-grid">
<mat-form-field class="mat-form-margin-top">
<mat-label translate>Selected item</mat-label>
<input
autocomplete="off"
matInput
osAutofocus
[(ngModel)]="inputControl"
(keydown)="keyDownFunction($event)"
/>
</mat-form-field>
<div>
<mat-radio-group aria-label="Select an option" class="radio-group" [(ngModel)]="selectedRepoValue">
<mat-radio-button aria-label="Topics" translate [value]="0" (click)="initForm()">
Topics
</mat-radio-button>
<mat-radio-button aria-label="Motions" translate [value]="1" (click)="initForm()">
Motions
</mat-radio-button>
<mat-radio-button aria-label="Assignments" translate [value]="2" (click)="initForm()">
Assignments
</mat-radio-button>
</mat-radio-group>
</div>

<mat-form-field [formGroup]="extensionFieldForm">
<mat-label translate>
{{ searchLists[selectedRepoValue].label }}
</mat-label>
@for (searchRepo of searchRepos; track $index) {
@if (selectedRepoValue === $index) {
<os-repo-search-selector
formControlName="{{ searchLists[$index].label }}FormControl"
[disabled]="!!link.href"
[keepOpen]="searchRepo.keepOpen"
[repo]="searchRepo"
[subscriptionConfig]="subscriptionConfig"
[wider]="searchRepo.wider"
></os-repo-search-selector>
}
}
</mat-form-field>
</div>
<div class="matDialogLinkActions">
<button color="warn" mat-icon-button [disabled]="!!link.href" (click)="changeEditMode(true)">
<mat-icon>done</mat-icon>
</button>
<button mat-icon-button [disabled]="!!link.href" (click)="changeEditMode()">
<mat-icon>close</mat-icon>
</button>
</div>
}
</div>
<div mat-dialog-actions>
<button color="accent" mat-button translate [disabled]="!link.href" (click)="save()">Ok</button>
<div class="matDialogActions" mat-dialog-actions>
<button color="accent" mat-button translate [disabled]="!link.href && !referenceText" (click)="save()">Ok</button>
@if (isUpdate) {
<button color="warn" mat-button translate (click)="removeLink()">Remove link</button>
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,39 @@
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;
}

.radio-group {
display: flex;
gap: 15px;
margin-bottom: 5px;
}

.internalReferences {
display: flex;

.internalReferencesTitle {
margin-bottom: 7px;
padding-right: 29px;
}

.internalReferencesArrows {
display: flex;
margin-top: 7px;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
import { Component, Inject } 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 } 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';

interface EditorLinkDialogInput {
link?: { href: string; target?: string };
Expand All @@ -18,22 +30,103 @@ 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;

/**
* 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;

/**
* Boolean to decide, whether to open the extension-input and search-list.
*/
public editMode = false;

/**
* Model for the input-field.
*/
public inputControl;

/**
* Prevent selecting the same value twice.
*/
private searchListDisabledItems = [];

/**
* 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<ViewAgendaItem<any>[]>;
protected motionItemList: Observable<ViewMotion[]>;
protected assignmentItemList: Observable<ViewAssignment[]>;

public searchLists;
public searchRepos;
/**
* FormGroup for the search-list.
*/
public extensionFieldForm: UntypedFormGroup;

public constructor(
@Inject(MAT_DIALOG_DATA) public data: EditorLinkDialogInput,
private dialogRef: MatDialogRef<EditorLinkDialogComponent>
private dialogRef: MatDialogRef<EditorLinkDialogComponent>,
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 };
if (!this.referenceLink.target) {
this.referenceLink.target = `_blank`;
}
}

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 {
Expand All @@ -45,14 +138,109 @@ export class EditorLinkDialogComponent {
}

public save(): void {
if (this.link.href && !/^[a-zA-Z]+:\/\//.test(this.link.href)) {
this.link.href = `http://` + this.link.href;
if (this.link.href) {
if (!/^[a-zA-Z]+:\/\//.test(this.link.href)) {
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 {
if (!/^[a-zA-Z]+:\/\//.test(this.referenceLink.href)) {
this.dialogRef.close({
action: `set-link`,
text: this.referenceText,
link: this.referenceLink
});
}
}
}

if (this.data.needsText) {
this.dialogRef.close({ action: `set-link`, link: this.link, text: this.text || this.link });
public toggle(): void {
this.toggleInsert = !this.toggleInsert;
}

/**
* 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.referenceText = ``;
}
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 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 urlBuilder(item): string {
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;
}
}
Loading
Loading