import { CommonModule, Location } from "@angular/common"; import { Component, EventEmitter, inject, Input, OnChanges, OnDestroy, Output } from "@angular/core"; import { FormBuilder, FormControl, FormGroup, ReactiveFormsModule, Validators } from "@angular/forms"; import { MatDialogModule } from "@angular/material/dialog"; import { MatIconModule } from "@angular/material/icon"; import { MatInputModule } from "@angular/material/input"; import { MatProgressSpinnerModule } from "@angular/material/progress-spinner"; import { MatSelectModule } from "@angular/material/select"; import { MatTabsModule } from "@angular/material/tabs"; import { MatTooltipModule } from "@angular/material/tooltip"; import { map, Observable, of, Subscription } from "rxjs"; import { Category } from "../../core/rest-services/category/model/category"; import { Publication } from "../../core/rest-services/publications/model/publication"; import { CategoryService } from "../../core/service/category.service"; import { SubmitButtonComponent } from "../submit-button/submit-button.component"; import { PictureSelectionDialog } from "./picture-selection-dialog/picture-selection-dialog.component"; import { PublicationEditionService } from "./publication-edition.service"; @Component({ selector: 'app-publication-edition', standalone: true, templateUrl: './publication-edition.component.html', styleUrl: './publication-edition.component.scss', imports: [ CommonModule, MatDialogModule, MatIconModule, MatInputModule, MatProgressSpinnerModule, MatSelectModule, MatTabsModule, MatTooltipModule, PictureSelectionDialog, ReactiveFormsModule, SubmitButtonComponent ], providers: [PublicationEditionService] }) export class PublicationEditionComponent implements OnChanges, OnDestroy { @Input() publication!: Publication; @Input() title!: string; @Input() isSaving$: Observable = of(false); @Output() publicationSave = new EventEmitter(); publicationInEdition!: Publication; private readonly categoryService = inject(CategoryService); private readonly formBuilder = inject(FormBuilder); private readonly location = inject(Location); private readonly publicationEditionService = inject(PublicationEditionService); private subscriptions: Subscription[] = []; publicationEditionForm: FormGroup = this.formBuilder.group({ title: new FormControl('', [Validators.required]), description: new FormControl('', [Validators.required]), text: new FormControl('', [Validators.required]), illustrationId: new FormControl('', [Validators.required]), categoryId: new FormControl('', [Validators.required]) }); get isLoading$(): Observable { return this.publicationEditionService.isLoading$; } get isPreviewing$(): Observable { return this.publicationEditionService.isPreviewing$; } get categories$(): Observable { return this.categoryService.categories$ .pipe( map(categories => categories.filter(category => category.subCategories.length == 0) .sort(this.byNameAscComparator()) ) ); } private byNameAscComparator(): (categoryA: Category, categoryB: Category) => number { return (categoryA, categoryB) => this.compareStrings(categoryA.name, categoryB.name); } private compareStrings(stringA: string, stringB: string): number { if (stringA < stringB) { return -1; } if (stringA > stringB) { return 1; } return 0; } ngOnChanges(): void { this.ngOnDestroy(); this.publicationInEdition = this.publication; this.publicationEditionService.init(this.publicationInEdition); ['title', 'description', 'text'].forEach(fieldName => { const fieldSubscription = this.publicationEditionForm.controls[fieldName].valueChanges .pipe( map(value => value?.length ? value as string : '') ) .subscribe(fieldValue => { switch (fieldName) { case 'title': this.publicationEditionService.editTitle(fieldValue); break; case 'description': this.publicationEditionService.editDescription(fieldValue); break; case 'text': this.publicationEditionService.editText(fieldValue); break; default: break; } }); this.subscriptions.push(fieldSubscription); }); const categoryIdChangeSubscription = this.publicationEditionForm.controls['categoryId'].valueChanges .subscribe(newCategoryId => { this.publicationEditionService.editCategoryId(newCategoryId); }); this.subscriptions.push(categoryIdChangeSubscription); const publicationSubscription = this.publicationEditionService.state$.subscribe(state => { console.log(state.publication.parsedText.substring(0, 15)); this.publicationInEdition = state.publication; this.publicationEditionForm.controls['title'].setValue(this.publicationInEdition.title, { emitEvent: false }); this.publicationEditionForm.controls['description'].setValue(this.publicationInEdition.description, { emitEvent: false }); this.publicationEditionForm.controls['text'].setValue(this.publicationInEdition.text, { emitEvent: false }); this.publicationEditionForm.controls['illustrationId'].setValue(this.publicationInEdition.illustrationId, { emitEvent: false }); this.publicationEditionForm.controls['categoryId'].setValue(this.publicationInEdition.categoryId, { emitEvent: false }); }); this.subscriptions.push(publicationSubscription); } ngOnDestroy(): void { this.subscriptions.forEach(subscription => subscription?.unsubscribe()); } goPreviousLocation(): void { this.location.back(); } insertTitle(titleNumber: number): void { this.publicationEditionService.insertTitle(titleNumber); } selectAPicture(): void { this.publicationEditionService.selectAPicture(); } insertLink(): void { this.publicationEditionService.insertLink(); } displayCodeBlockDialog(): void { this.publicationEditionService.displayCodeBlockDialog(); } save(): void { this.publicationSave.emit(this.publicationInEdition); } displayPictureSectionDialog(): void { this.publicationEditionService.displayPictureSectionDialog(); } updateCursorPosition(event: KeyboardEvent | MouseEvent): void { if (event.target) { const textarea = event.target as HTMLTextAreaElement; const positionStart = textarea.selectionStart; const positionEnd = textarea.selectionEnd; this.publicationEditionService.editCursorPosition(positionStart, positionEnd); } } onTabChange(tabSelectedIndex: number): void { if (tabSelectedIndex === 1) { this.publicationEditionService.loadPreview(); } } }