validate chords
This commit is contained in:
@@ -54,10 +54,26 @@
|
||||
matInput
|
||||
></textarea>
|
||||
</mat-form-field>
|
||||
@if (chordValidationIssues.length > 0) {
|
||||
<div class="song-text-validation">
|
||||
<h3>Akkordschreibweise korrigieren</h3>
|
||||
@for (issue of chordValidationIssues; track issue.lineNumber + '-' + issue.token) {
|
||||
<div class="issue">
|
||||
<strong>Zeile {{ issue.lineNumber }}:</strong>
|
||||
<span>{{ issue.message }}</span>
|
||||
<code>{{ issue.token }}</code>
|
||||
@if (issue.suggestion) {
|
||||
<span>-></span>
|
||||
<code>{{ issue.suggestion }}</code>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@if (songtextFocus) {
|
||||
<div class="song-text-help">
|
||||
<h3>Vorschau</h3>
|
||||
<app-song-text [text]="form.value.text" chordMode="show"></app-song-text>
|
||||
<app-song-text [invalidChordIssues]="chordValidationIssues" [text]="form.value.text" chordMode="show"></app-song-text>
|
||||
<h3>Hinweise zur Bearbeitung</h3>
|
||||
<h4>Aufbau</h4>
|
||||
Der Liedtext wird hintereinander weg geschrieben. Dabei werden Strophen,
|
||||
@@ -180,7 +196,7 @@
|
||||
</div>
|
||||
</form>
|
||||
<app-button-row>
|
||||
<app-button (click)="onSave()" [icon]="faSave">Speichern</app-button>
|
||||
<app-button (click)="onSave()" [disabled]="form.invalid" [icon]="faSave">Speichern</app-button>
|
||||
</app-button-row>
|
||||
</app-card>
|
||||
}
|
||||
|
||||
@@ -43,3 +43,26 @@ h4 {
|
||||
.song-text-help {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.song-text-validation {
|
||||
margin: -8px 0 12px;
|
||||
padding: 12px 14px;
|
||||
border-radius: 6px;
|
||||
background: rgba(166, 32, 32, 0.08);
|
||||
border: 1px solid rgba(166, 32, 32, 0.22);
|
||||
color: #7d1919;
|
||||
|
||||
.issue {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: baseline;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
code {
|
||||
padding: 1px 4px;
|
||||
border-radius: 4px;
|
||||
background: rgba(125, 25, 25, 0.08);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,15 @@ import {ActivatedRoute, Router, RouterStateSnapshot} from '@angular/router';
|
||||
import {SongService} from '../../../services/song.service';
|
||||
import {EditService} from '../edit.service';
|
||||
import {first, map, switchMap} from 'rxjs/operators';
|
||||
import {startWith} from 'rxjs';
|
||||
import {KEYS} from '../../../services/key.helper';
|
||||
import {COMMA, ENTER} from '@angular/cdk/keycodes';
|
||||
import {MatChipGrid, MatChipInput, MatChipInputEvent, MatChipRow} from '@angular/material/chips';
|
||||
import {faExternalLinkAlt, faSave, faTimesCircle} from '@fortawesome/free-solid-svg-icons';
|
||||
import {MatDialog} from '@angular/material/dialog';
|
||||
import {SaveDialogComponent} from './save-dialog/save-dialog.component';
|
||||
import {TextRenderingService} from '../../../services/text-rendering.service';
|
||||
import {ChordValidationIssue} from '../../../services/chord';
|
||||
|
||||
import {CardComponent} from '../../../../../widget-modules/components/card/card.component';
|
||||
import {MatFormField, MatLabel, MatSuffix} from '@angular/material/form-field';
|
||||
@@ -63,6 +66,7 @@ export class EditSongComponent implements OnInit {
|
||||
private songService = inject(SongService);
|
||||
private editService = inject(EditService);
|
||||
private router = inject(Router);
|
||||
private textRenderingService = inject(TextRenderingService);
|
||||
public dialog = inject(MatDialog);
|
||||
|
||||
public song: Song | null = null;
|
||||
@@ -78,6 +82,7 @@ export class EditSongComponent implements OnInit {
|
||||
public faSave = faSave;
|
||||
public faLink = faExternalLinkAlt;
|
||||
public songtextFocus = false;
|
||||
public chordValidationIssues: ChordValidationIssue[] = [];
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.activatedRoute.params
|
||||
@@ -92,12 +97,15 @@ export class EditSongComponent implements OnInit {
|
||||
if (!song) return;
|
||||
this.form = this.editService.createSongForm(song);
|
||||
this.form.controls.flags.valueChanges.subscribe(_ => this.onFlagsChanged(_ as string));
|
||||
this.form.controls.text.valueChanges.pipe(startWith(this.form.controls.text.value)).subscribe(text => {
|
||||
this.updateChordValidation(text as string);
|
||||
});
|
||||
this.onFlagsChanged(this.form.controls.flags.value as string);
|
||||
});
|
||||
}
|
||||
|
||||
public async onSave(): Promise<void> {
|
||||
if (!this.song) return;
|
||||
if (!this.song || this.form.invalid) return;
|
||||
const data = this.form.value as Partial<Song>;
|
||||
await this.songService.update$(this.song.id, data);
|
||||
this.form.markAsPristine();
|
||||
@@ -149,8 +157,23 @@ export class EditSongComponent implements OnInit {
|
||||
this.flags = flagArray.split(';').filter(_ => !!_);
|
||||
}
|
||||
|
||||
private updateChordValidation(text: string): void {
|
||||
const control = this.form.controls.text;
|
||||
this.chordValidationIssues = this.textRenderingService.validateChordNotation(text ?? '');
|
||||
|
||||
const errors = {...(control.errors ?? {})};
|
||||
if (this.chordValidationIssues.length > 0) {
|
||||
errors.chordNotation = this.chordValidationIssues;
|
||||
control.setErrors(errors);
|
||||
return;
|
||||
}
|
||||
|
||||
delete errors.chordNotation;
|
||||
control.setErrors(Object.keys(errors).length > 0 ? errors : null);
|
||||
}
|
||||
|
||||
private async onSaveDialogAfterClosed(save: boolean, url: string) {
|
||||
if (save && this.song) {
|
||||
if (save && this.song && !this.form.invalid) {
|
||||
const data = this.form.value as Partial<Song>;
|
||||
await this.songService.update$(this.song.id, data);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user