bugfixing

This commit is contained in:
2020-06-14 15:46:24 +02:00
parent 1e1e127f13
commit 19b28453d3
36 changed files with 175 additions and 97 deletions

View File

@@ -10,19 +10,21 @@ import {PerfectScrollbarComponent} from 'ngx-perfect-scrollbar';
animations: [fader] animations: [fader]
}) })
export class AppComponent implements OnInit { export class AppComponent implements OnInit {
public static hideLoader = () => document.querySelector('#load-bg').classList.add('hidden');
@ViewChild('scrollbar', {static: false}) scrollbar: PerfectScrollbarComponent; @ViewChild('scrollbar', {static: false}) scrollbar: PerfectScrollbarComponent;
constructor(private scrollService: ScrollService) { constructor(private scrollService: ScrollService) {
scrollService.restoreScrollPosition$.subscribe(pos => { scrollService.restoreScrollPosition$.subscribe(pos => {
if (this.scrollbar && pos) { if (this.scrollbar && pos) {
//this.scrollbar.scrollTo(pos, 0); // this.scrollbar.scrollTo(pos, 0);
this.scrollbar.directiveRef.scrollTo(0, pos, 300) this.scrollbar.directiveRef.scrollTo(0, pos, 300);
// debugger; // debugger;
} }
}) });
} }
public static hideLoader = () => document.querySelector('#load-bg').classList.add('hidden');
public ngOnInit(): void { public ngOnInit(): void {
setTimeout(() => AppComponent.hideLoader(), 800); setTimeout(() => AppComponent.hideLoader(), 800);

View File

@@ -9,9 +9,9 @@ import {User} from '../../../services/user/user';
styleUrls: ['./new-user.component.less'] styleUrls: ['./new-user.component.less']
}) })
export class NewUserComponent { export class NewUserComponent {
public user$: Observable<User> public user$: Observable<User>;
constructor(private userService: UserService) { constructor(private userService: UserService) {
this.user$ = userService.user$ this.user$ = userService.user$;
} }
} }

View File

@@ -77,7 +77,7 @@ export class RemoteComponent {
id: song.id, id: song.id,
title: song.title, title: song.title,
sections: this.textRenderingService.parse(song.text, null) sections: this.textRenderingService.parse(song.text, null)
})) }));
}); });
await delay(500); await delay(500);
this.progress = false; this.progress = false;
@@ -91,7 +91,7 @@ export class RemoteComponent {
await this.showService.update$(this.currentShowId, { await this.showService.update$(this.currentShowId, {
presentationSongId: id, presentationSongId: id,
presentationSection: index presentationSection: index
}) });
} }
public async onZoom(zoom: number) { public async onZoom(zoom: number) {

View File

@@ -18,11 +18,11 @@ export class ListComponent {
} }
public getPublicShows(songs: Show[]): Show[] { public getPublicShows(songs: Show[]): Show[] {
return songs.filter(_ => _.published) return songs.filter(_ => _.published);
} }
public getPrivateSongs(songs: Show[]): Show[] { public getPrivateSongs(songs: Show[]): Show[] {
return songs.filter(_ => !_.published) return songs.filter(_ => !_.published);
} }
} }

View File

@@ -27,12 +27,14 @@ export class NewComponent implements OnInit {
this.form = new FormGroup({ this.form = new FormGroup({
date: new FormControl(null, Validators.required), date: new FormControl(null, Validators.required),
showType: new FormControl(null, Validators.required), showType: new FormControl(null, Validators.required),
}) });
} }
public async onSave() { public async onSave() {
this.form.markAllAsTouched(); this.form.markAllAsTouched();
if (!this.form.valid) return; if (!this.form.valid) {
return;
}
const id = await this.showService.new$(this.form.value); const id = await this.showService.new$(this.form.value);
await this.router.navigateByUrl('/shows/' + id); await this.router.navigateByUrl('/shows/' + id);

View File

@@ -86,11 +86,11 @@ export class DocxService {
}, },
] ]
} }
}) });
} }
private renderSongs(songs: { showSong: ShowSong; song: Song; sections: Section[] }[], options: DownloadOptions, config: Config): Paragraph[] { private renderSongs(songs: { showSong: ShowSong; song: Song; sections: Section[] }[], options: DownloadOptions, config: Config): Paragraph[] {
return songs.reduce((p, song) => [...p, ...this.renderSong(song.showSong, song.song, song.sections, options, config)], []) return songs.reduce((p, song) => [...p, ...this.renderSong(song.showSong, song.song, song.sections, options, config)], []);
} }
private renderSong(showSong: ShowSong, song: Song, sections: Section[], options: DownloadOptions, config: Config): Paragraph[] { private renderSong(showSong: ShowSong, song: Song, sections: Section[], options: DownloadOptions, config: Config): Paragraph[] {
@@ -121,7 +121,9 @@ export class DocxService {
} }
private renderCopyright(song: Song, options: DownloadOptions, config: Config): Paragraph { private renderCopyright(song: Song, options: DownloadOptions, config: Config): Paragraph {
if (!options?.copyright) return null; if (!options?.copyright) {
return null;
}
const label = song.label ? song.label + ', ' : ''; const label = song.label ? song.label + ', ' : '';
const artist = song.artist ? song.artist + ', ' : ''; const artist = song.artist ? song.artist + ', ' : '';
@@ -141,7 +143,9 @@ export class DocxService {
private renderSection(section: Section, chordMode: ChordMode): Paragraph[] { private renderSection(section: Section, chordMode: ChordMode): Paragraph[] {
return section.lines return section.lines
.filter(line => { .filter(line => {
if (line.type === LineType.text) return true; if (line.type === LineType.text) {
return true;
}
switch (chordMode) { switch (chordMode) {
case 'show': case 'show':
return true; return true;
@@ -172,7 +176,7 @@ export class DocxService {
thematicBreak: true, thematicBreak: true,
}); });
return [songTitle] return [songTitle];
} }
private async prepareData(showId: string): Promise<{ songs: ({ showSong: ShowSong, song: Song, sections: Section[] })[]; show: Show, user: User, config: Config }> { private async prepareData(showId: string): Promise<{ songs: ({ showSong: ShowSong, song: Song, sections: Section[] })[]; show: Show, user: User, config: Config }> {
@@ -191,8 +195,8 @@ export class DocxService {
showSong, showSong,
song, song,
sections sections
} };
}) });
const songs = await Promise.all(songsAsync); const songs = await Promise.all(songsAsync);
return {songs, show, user, config}; return {songs, show, user, config};
} }
@@ -213,5 +217,5 @@ export class DocxService {
window.URL.revokeObjectURL(url); window.URL.revokeObjectURL(url);
document.body.removeChild(a); document.body.removeChild(a);
}, 1000); }, 1000);
}; }
} }

View File

@@ -15,5 +15,5 @@ export class ShowDataService {
public list$ = (queryFn?): Observable<Show[]> => this.dbService.col$(this.collection, queryFn); public list$ = (queryFn?): Observable<Show[]> => this.dbService.col$(this.collection, queryFn);
public read$ = (showId: string): Observable<Show | undefined> => this.dbService.doc$(`${this.collection}/${showId}`); public read$ = (showId: string): Observable<Show | undefined> => this.dbService.doc$(`${this.collection}/${showId}`);
public update = async (showId: string, data: Partial<Show>): Promise<void> => await this.dbService.doc(`${this.collection}/${showId}`).update(data); public update = async (showId: string, data: Partial<Show>): Promise<void> => await this.dbService.doc(`${this.collection}/${showId}`).update(data);
public add = async (data: Partial<Show>): Promise<string> => (await this.dbService.col(this.collection).add(data)).id public add = async (data: Partial<Show>): Promise<string> => (await this.dbService.col(this.collection).add(data)).id;
} }

View File

@@ -17,5 +17,5 @@ export class ShowSongDataService {
public read$ = (showId: string, songId: string): Observable<ShowSong | undefined> => this.dbService.doc$(`${this.collection}/${showId}/${this.subCollection}/${songId}`); public read$ = (showId: string, songId: string): Observable<ShowSong | undefined> => this.dbService.doc$(`${this.collection}/${showId}/${this.subCollection}/${songId}`);
public update$ = async (showId: string, songId: string, data: Partial<ShowSong>): Promise<void> => await this.dbService.doc(`${this.collection}/${showId}/${this.subCollection}/${songId}`).update(data); public update$ = async (showId: string, songId: string, data: Partial<ShowSong>): Promise<void> => await this.dbService.doc(`${this.collection}/${showId}/${this.subCollection}/${songId}`).update(data);
public delete = async (showId: string, songId: string): Promise<void> => await this.dbService.doc(`${this.collection}/${showId}/${this.subCollection}/${songId}`).delete(); public delete = async (showId: string, songId: string): Promise<void> => await this.dbService.doc(`${this.collection}/${showId}/${this.subCollection}/${songId}`).delete();
public add = async (showId: string, data: Partial<ShowSong>): Promise<string> => (await this.dbService.col(`${this.collection}/${showId}/${this.subCollection}`).add(data)).id public add = async (showId: string, data: Partial<ShowSong>): Promise<string> => (await this.dbService.col(`${this.collection}/${showId}/${this.subCollection}`).add(data)).id;
} }

View File

@@ -30,7 +30,7 @@ export class ShowService {
.filter(_ => !_.archived) .filter(_ => !_.archived)
.filter(show => show.published || (show.owner === _.user.id && !publishedOnly)) .filter(show => show.published || (show.owner === _.user.id && !publishedOnly))
) )
) );
} }

View File

@@ -76,8 +76,12 @@ export class ShowComponent implements OnInit {
} }
public getStatus(show: Show): string { public getStatus(show: Show): string {
if (show.published) return 'veröffentlicht'; if (show.published) {
if (show.reported) return 'gemeldet'; return 'veröffentlicht';
}
if (show.reported) {
return 'gemeldet';
}
return 'entwurf'; return 'entwurf';
} }

View File

@@ -40,13 +40,13 @@ export class SongComponent implements OnInit {
public set song(song: Song) { public set song(song: Song) {
this._song = song; this._song = song;
this.keys = !!song ? getScale(song.key) : []; this.keys = !!song ? getScale(song.key) : [];
}; }
public ngOnInit(): void { public ngOnInit(): void {
this.keyFormControl = new FormControl(this.showSong.key); this.keyFormControl = new FormControl(this.showSong.key);
this.keyFormControl.valueChanges.subscribe(async value => { this.keyFormControl.valueChanges.subscribe(async value => {
await this.showSongService.update$(this.showId, this.showSong.id, {key: value}); await this.showSongService.update$(this.showId, this.showSong.id, {key: value});
}) });
} }
public async onDelete(): Promise<void> { public async onDelete(): Promise<void> {
@@ -55,12 +55,18 @@ export class SongComponent implements OnInit {
public async reorder(up: boolean): Promise<void> { public async reorder(up: boolean): Promise<void> {
if (up) await this.reorderUp(); else await this.reorderDown(); if (up) {
await this.reorderUp();
} else {
await this.reorderDown();
}
} }
public async reorderUp(): Promise<void> { public async reorderUp(): Promise<void> {
const index = this.showSongs.findIndex(_ => _.songId === this._song.id); const index = this.showSongs.findIndex(_ => _.songId === this._song.id);
if (index === 0) return; if (index === 0) {
return;
}
const song = this.showSongs[index]; const song = this.showSongs[index];
const toggleSong = this.showSongs[index - 1]; const toggleSong = this.showSongs[index - 1];
@@ -71,7 +77,9 @@ export class SongComponent implements OnInit {
public async reorderDown(): Promise<void> { public async reorderDown(): Promise<void> {
const index = this.showSongs.findIndex(_ => _.songId === this._song.id); const index = this.showSongs.findIndex(_ => _.songId === this._song.id);
if (index === this.showSongs.length - 1) return; if (index === this.showSongs.length - 1) {
return;
}
const song = this.showSongs[index]; const song = this.showSongs[index];
const toggleSong = this.showSongs[index + 1]; const toggleSong = this.showSongs[index + 1];

View File

@@ -21,7 +21,7 @@ export class FileService {
public async delete(path: string, songId: string, fileId: string) { public async delete(path: string, songId: string, fileId: string) {
const ref = this.storage.ref(path); const ref = this.storage.ref(path);
await ref.delete().toPromise() await ref.delete().toPromise();
await this.fileDataService.delete(songId, fileId); await this.fileDataService.delete(songId, fileId);
} }
} }

View File

@@ -34,12 +34,12 @@ export class SongService {
const song = await this.read(songId); const song = await this.read(songId);
const edits = song.edits ?? []; const edits = song.edits ?? [];
const user = await this.userService.currentUser(); const user = await this.userService.currentUser();
edits.push({username: user.name, timestamp: Timestamp.now()}) edits.push({username: user.name, timestamp: Timestamp.now()});
await this.songDataService.update$(songId, {...data, edits}); await this.songDataService.update$(songId, {...data, edits});
} }
public async new(number: number, title: string): Promise<string> { public async new(number: number, title: string): Promise<string> {
return await this.songDataService.add({number, title, status: 'draft', legalType: 'open'}) return await this.songDataService.add({number, title, status: 'draft', legalType: 'open'});
} }
public async delete(songId: string): Promise<void> { public async delete(songId: string): Promise<void> {

View File

@@ -90,7 +90,7 @@ Cool bridge without any chords
const service: TextRenderingService = TestBed.inject(TextRenderingService); const service: TextRenderingService = TestBed.inject(TextRenderingService);
const text = `Strophe const text = `Strophe
g# F# E g# F# E g# F# E g# F# E
text` text`;
const sections = service.parse(text, null); const sections = service.parse(text, null);
expect(sections[0].lines[0].type).toBe(LineType.chord); expect(sections[0].lines[0].type).toBe(LineType.chord);
expect(sections[0].lines[0].text).toBe('g# F# E g# F# E'); expect(sections[0].lines[0].text).toBe('g# F# E g# F# E');

View File

@@ -17,7 +17,9 @@ export class TextRenderingService {
} }
public parse(text: string, transpose: TransposeMode): Section[] { public parse(text: string, transpose: TransposeMode): Section[] {
if (!text) return []; if (!text) {
return [];
}
const arrayOfLines = text.split(/\r?\n/).filter(_ => _); const arrayOfLines = text.split(/\r?\n/).filter(_ => _);
const indices = { const indices = {
[SectionType.Bridge]: 0, [SectionType.Bridge]: 0,
@@ -26,18 +28,22 @@ export class TextRenderingService {
}; };
return arrayOfLines.reduce((array, line) => { return arrayOfLines.reduce((array, line) => {
const type = this.getSectionTypeOfLine(line); const type = this.getSectionTypeOfLine(line);
if (line.match(this.regexSection)) return [...array, { if (line.match(this.regexSection)) {
type: type, return [...array, {
type,
number: indices[type]++, number: indices[type]++,
lines: [] lines: []
}]; }];
}
array[array.length - 1].lines.push(this.getLineOfLineText(line, transpose)); array[array.length - 1].lines.push(this.getLineOfLineText(line, transpose));
return array; return array;
}, [] as Section[]); }, [] as Section[]);
} }
private getLineOfLineText(text: string, transpose: TransposeMode): Line { private getLineOfLineText(text: string, transpose: TransposeMode): Line {
if (!text) return null; if (!text) {
return null;
}
const cords = this.readChords(text); const cords = this.readChords(text);
const hasMatches = cords.length > 0; const hasMatches = cords.length > 0;
const type = hasMatches ? LineType.chord : LineType.text; const type = hasMatches ? LineType.chord : LineType.text;
@@ -49,16 +55,20 @@ export class TextRenderingService {
} }
private getSectionTypeOfLine(line: string): SectionType { private getSectionTypeOfLine(line: string): SectionType {
if (!line) return null; if (!line) {
return null;
}
const match = line.match(this.regexSection); const match = line.match(this.regexSection);
if (!match || match.length < 2) return null; if (!match || match.length < 2) {
return null;
}
const typeString = match[1]; const typeString = match[1];
switch (typeString) { switch (typeString) {
case "Strophe": case 'Strophe':
return SectionType.Verse; return SectionType.Verse;
case "Refrain": case 'Refrain':
return SectionType.Chorus; return SectionType.Chorus;
case "Bridge": case 'Bridge':
return SectionType.Bridge; return SectionType.Bridge;
} }
} }
@@ -76,14 +86,18 @@ export class TextRenderingService {
length: match[0].length, length: match[0].length,
position: regex.lastIndex - match[0].length, position: regex.lastIndex - match[0].length,
}; };
if (match[3]) chord.slashChord = match[3]; if (match[3]) {
if (match[4]) chord.add = match[4]; chord.slashChord = match[3];
}
if (match[4]) {
chord.add = match[4];
}
chords.push(chord); chords.push(chord);
} }
const chordCount = chords.reduce((acc: number, cur: Chord) => acc + cur.length, 0); const chordCount = chords.reduce((acc: number, cur: Chord) => acc + cur.length, 0);
const lineCount = chordLine.replace(/\s/g, "").length; const lineCount = chordLine.replace(/\s/g, '').length;
const isChrod = chordCount * 1.2 > lineCount; const isChrod = chordCount * 1.2 > lineCount;
return isChrod ? chords : []; return isChrod ? chords : [];
} }

View File

@@ -1,4 +1,4 @@
export interface TransposeMode { export interface TransposeMode {
baseKey: string; baseKey: string;
targetKey: string targetKey: string;
} }

View File

@@ -10,7 +10,9 @@ import {Line} from './line';
export class TransposeService { export class TransposeService {
public transpose(line: Line, baseKey: string, targetKey: string): Line { public transpose(line: Line, baseKey: string, targetKey: string): Line {
if (line.type !== LineType.chord) return line; if (line.type !== LineType.chord) {
return line;
}
const difference = this.getDistance(baseKey, targetKey); const difference = this.getDistance(baseKey, targetKey);
const map = this.getMap(baseKey, difference); const map = this.getMap(baseKey, difference);
@@ -21,7 +23,9 @@ export class TransposeService {
} }
public renderChords(line: Line): Line { public renderChords(line: Line): Line {
if (line.type !== LineType.chord) return line; if (line.type !== LineType.chord) {
return line;
}
const renderedLine = this.renderLine(line.chords); const renderedLine = this.renderLine(line.chords);
return {...line, text: renderedLine}; return {...line, text: renderedLine};
@@ -37,7 +41,9 @@ export class TransposeService {
public getMap(baseKey: string, difference: number) { public getMap(baseKey: string, difference: number) {
const scale = getScaleType(baseKey); const scale = getScaleType(baseKey);
if (!scale) return null; if (!scale) {
return null;
}
const map = {}; const map = {};
for (let i = 0; i < 12; i++) { for (let i = 0; i < 12; i++) {
const source = scale[0][i]; const source = scale[0][i];
@@ -71,7 +77,7 @@ export class TransposeService {
const post = template.substr(pos + newLength); const post = template.substr(pos + newLength);
template = pre + renderedChord + post; template = pre + renderedChord + post;
}) });
return template.trimRight(); return template.trimRight();
} }

View File

@@ -30,12 +30,22 @@ export class FilterComponent implements OnInit {
}); });
activatedRoute.queryParams.subscribe((filterValues: FilterValues) => { activatedRoute.queryParams.subscribe((filterValues: FilterValues) => {
if (filterValues.q) this.filterFormGroup.controls.q.setValue(filterValues.q); if (filterValues.q) {
if (filterValues.type) this.filterFormGroup.controls.type.setValue(filterValues.type); this.filterFormGroup.controls.q.setValue(filterValues.q);
if (filterValues.key) this.filterFormGroup.controls.key.setValue(filterValues.key); }
if (filterValues.legalType) this.filterFormGroup.controls.legalType.setValue(filterValues.legalType); if (filterValues.type) {
if (filterValues.flag) this.filterFormGroup.controls.flag.setValue(filterValues.flag); this.filterFormGroup.controls.type.setValue(filterValues.type);
}) }
if (filterValues.key) {
this.filterFormGroup.controls.key.setValue(filterValues.key);
}
if (filterValues.legalType) {
this.filterFormGroup.controls.legalType.setValue(filterValues.legalType);
}
if (filterValues.flag) {
this.filterFormGroup.controls.flag.setValue(filterValues.flag);
}
});
this.filterFormGroup.controls.q.valueChanges.subscribe(_ => this.filerValueChanged('q', _)); this.filterFormGroup.controls.q.valueChanges.subscribe(_ => this.filerValueChanged('q', _));
this.filterFormGroup.controls.key.valueChanges.subscribe(_ => this.filerValueChanged('key', _)); this.filterFormGroup.controls.key.valueChanges.subscribe(_ => this.filerValueChanged('key', _));

View File

@@ -38,8 +38,8 @@ export class SongListComponent implements OnInit, OnDestroy {
this.songs$ = combineLatest([filter$, songs$]).pipe( this.songs$ = combineLatest([filter$, songs$]).pipe(
map(_ => { map(_ => {
let songs = _[1]; const songs = _[1];
let filter = _[0]; const filter = _[0];
this.anyFilterActive = this.checkIfFilterActive(filter); this.anyFilterActive = this.checkIfFilterActive(filter);
return songs.filter(song => this.filter(song, filter)); return songs.filter(song => this.filter(song, filter));
}) })
@@ -68,10 +68,14 @@ export class SongListComponent implements OnInit, OnDestroy {
} }
private checkFlag(flag: string, flags: string) { private checkFlag(flag: string, flags: string) {
if (!flags) return false; if (!flags) {
return false;
}
const flagStrings = flags.split(';'); const flagStrings = flags.split(';');
if (flagStrings.length === 0) return false; if (flagStrings.length === 0) {
return false;
}
return flagStrings.indexOf(flag) !== -1; return flagStrings.indexOf(flag) !== -1;
} }

View File

@@ -25,7 +25,7 @@ export class FileComponent {
this.name = file.name; this.name = file.name;
this.fileId = file.id; this.fileId = file.id;
this.path = file.path + '/' + file.name; this.path = file.path + '/' + file.name;
}; }
public async onDelete(): Promise<void> { public async onDelete(): Promise<void> {
await this.fileService.delete(this.path, this.songId, this.fileId); await this.fileService.delete(this.path, this.songId, this.fileId);

View File

@@ -51,7 +51,7 @@ export class EditSongComponent implements OnInit {
).subscribe(song => { ).subscribe(song => {
this.song = song; this.song = song;
this.form = this.editService.createSongForm(song); this.form = this.editService.createSongForm(song);
this.form.controls.flags.valueChanges.subscribe(_ => this.onFlagsChanged(_)) this.form.controls.flags.valueChanges.subscribe(_ => this.onFlagsChanged(_));
this.onFlagsChanged(this.form.controls.flags.value); this.onFlagsChanged(this.form.controls.flags.value);
}); });
} }
@@ -78,7 +78,9 @@ export class EditSongComponent implements OnInit {
this.form.controls.flags.setValue(flags.join(';')); this.form.controls.flags.setValue(flags.join(';'));
} }
if (input) input.value = ''; if (input) {
input.value = '';
}
} }
private onFlagsChanged(flagArray: string): void { private onFlagsChanged(flagArray: string): void {
@@ -91,7 +93,9 @@ export class EditSongComponent implements OnInit {
} }
public askForSave(nextState?: RouterStateSnapshot): boolean { public askForSave(nextState?: RouterStateSnapshot): boolean {
if (!this.form.dirty) return true; if (!this.form.dirty) {
return true;
}
const dialogRef = this.dialog.open(SaveDialogComponent, { const dialogRef = this.dialog.open(SaveDialogComponent, {
width: '350px' width: '350px'

View File

@@ -21,7 +21,7 @@ export class FileComponent implements OnInit {
this.url$ = ref.getDownloadURL(); this.url$ = ref.getDownloadURL();
this.name = file.name; this.name = file.name;
}; }
ngOnInit(): void { ngOnInit(): void {
} }

View File

@@ -23,12 +23,12 @@ export class NewComponent implements OnInit {
this.form = new FormGroup({ this.form = new FormGroup({
number: new FormControl(null, Validators.required), number: new FormControl(null, Validators.required),
title: new FormControl(null, Validators.required), title: new FormControl(null, Validators.required),
}) });
this.songService.list$().pipe(autoComplete(this)).subscribe(songs => { this.songService.list$().pipe(autoComplete(this)).subscribe(songs => {
const freeSongnumber = this.getFreeSongNumber(songs); const freeSongnumber = this.getFreeSongNumber(songs);
this.form.controls.number.setValue(freeSongnumber); this.form.controls.number.setValue(freeSongnumber);
}) });
} }
public async onSave(): Promise<void> { public async onSave(): Promise<void> {
@@ -41,7 +41,9 @@ export class NewComponent implements OnInit {
private getFreeSongNumber(songs: Song[]): Number { private getFreeSongNumber(songs: Song[]): Number {
const numbers = songs.map(_ => _.number); const numbers = songs.map(_ => _.number);
for (let i = 1; i < Number.MAX_SAFE_INTEGER; i++) { for (let i = 1; i < Number.MAX_SAFE_INTEGER; i++) {
if (!numbers.some(_ => _ === i)) return i; if (!numbers.some(_ => _ === i)) {
return i;
}
} }
} }
} }

View File

@@ -46,9 +46,11 @@ export class SongComponent implements OnInit {
} }
public getFlags = (flags: string): string[] => { public getFlags = (flags: string): string[] => {
if (!flags) return []; if (!flags) {
return [];
}
return flags.split(';').filter(_ => !!_); return flags.split(';').filter(_ => !!_);
}; }
public async onDelete(songId: string): Promise<void> { public async onDelete(songId: string): Promise<void> {
await this.songService.delete(songId); await this.songService.delete(songId);

View File

@@ -11,7 +11,7 @@ import {faTimes} from '@fortawesome/free-solid-svg-icons/faTimes';
}) })
export class UserComponent { export class UserComponent {
public id: string; public id: string;
public name: string public name: string;
public roles: string[]; public roles: string[];
public ROLE_TYPES = ROLE_TYPES; public ROLE_TYPES = ROLE_TYPES;
public edit = false; public edit = false;
@@ -24,7 +24,7 @@ export class UserComponent {
this.id = value.id; this.id = value.id;
this.name = value.name; this.name = value.name;
this.roles = this.getRoleArray(value.role); this.roles = this.getRoleArray(value.role);
}; }
public async onRoleChanged(id: string, roles: string[]): Promise<void> { public async onRoleChanged(id: string, roles: string[]): Promise<void> {
const role = roles.join(';'); const role = roles.join(';');

View File

@@ -20,7 +20,7 @@ export class NewComponent implements OnInit {
email: new FormControl(null, [Validators.required, Validators.email]), email: new FormControl(null, [Validators.required, Validators.email]),
name: new FormControl(null, [Validators.required]), name: new FormControl(null, [Validators.required]),
password: new FormControl(null, [Validators.required, Validators.minLength(6)]), password: new FormControl(null, [Validators.required, Validators.minLength(6)]),
}) });
} }
public async onCreate(): Promise<void> { public async onCreate(): Promise<void> {

View File

@@ -1,3 +1,3 @@
export interface Config { export interface Config {
ccliLicenseId: string ccliLicenseId: string;
} }

View File

@@ -1,3 +1,3 @@
export interface GlobalSettings { export interface GlobalSettings {
currentShow: string currentShow: string;
} }

View File

@@ -41,9 +41,13 @@ export class RoleDirective implements OnInit {
private checkPermission() { private checkPermission() {
if (this.currentUser && this.currentUser.role) { if (this.currentUser && this.currentUser.role) {
if (this.currentUser.role === 'admin') return true; if (this.currentUser.role === 'admin') {
return true;
}
for (const role of this.appRole) { for (const role of this.appRole) {
if (this.currentUser.role.indexOf(role) !== -1) return true; if (this.currentUser.role.indexOf(role) !== -1) {
return true;
}
} }
} }

View File

@@ -4,5 +4,5 @@ export interface User {
id: string; id: string;
name: string; name: string;
role: string; role: string;
chordMode: ChordMode chordMode: ChordMode;
} }

View File

@@ -35,14 +35,14 @@ export class AddSongComponent {
return 1; return 1;
} }
return 0; return 0;
}) });
const filterValue = this.filteredSongsControl.value; const filterValue = this.filteredSongsControl.value;
return filterValue ? songs.filter(_ => filterSong(_, filterValue)) : songs; return filterValue ? songs.filter(_ => filterSong(_, filterValue)) : songs;
} }
public async onAddSongSelectionChanged(event: MatSelectChange) { public async onAddSongSelectionChanged(event: MatSelectChange) {
let order = this.showSongs.reduce((oa, u) => Math.max(oa, u.order), 0) + 1; const order = this.showSongs.reduce((oa, u) => Math.max(oa, u.order), 0) + 1;
await this.showSongService.new$(this.showId, event.value, order, this.addedLive); await this.showSongService.new$(this.showId, event.value, order, this.addedLive);
event.source.value = null; event.source.value = null;
} }

View File

@@ -11,8 +11,10 @@ export class FilterComponent {
constructor(private router: Router, activatedRoute: ActivatedRoute) { constructor(private router: Router, activatedRoute: ActivatedRoute) {
activatedRoute.queryParams.subscribe(_ => { activatedRoute.queryParams.subscribe(_ => {
if (_.q) this.value = _.q; if (_.q) {
}) this.value = _.q;
}
});
} }
public async valueChange(text: string): Promise<void> { public async valueChange(text: string): Promise<void> {

View File

@@ -17,4 +17,4 @@ export const songSwitch = // the fade-in/fade-out animation.
transition(':leave', transition(':leave',
animate(1200, style({opacity: 0})) animate(1200, style({opacity: 0}))
) )
]) ]);

View File

@@ -8,7 +8,7 @@ import {LineType} from '../../../modules/songs/services/line-type';
import {Section} from '../../../modules/songs/services/section'; import {Section} from '../../../modules/songs/services/section';
import {Line} from '../../../modules/songs/services/line'; import {Line} from '../../../modules/songs/services/line';
export type ChordMode = 'show' | 'hide' | 'onlyFirst' export type ChordMode = 'show' | 'hide' | 'onlyFirst';
@Component({ @Component({
selector: 'app-song-text', selector: 'app-song-text',
@@ -41,10 +41,12 @@ export class SongTextComponent implements OnInit {
public set text(value: string) { public set text(value: string) {
this.sections = null; this.sections = null;
this.offset = 0; this.offset = 0;
if (this.fullscreen) if (this.fullscreen) {
setTimeout(() => setTimeout(() =>
this.sections = this.textRenderingService.parse(value, this.transpose).sort((a, b) => a.type - b.type), 100); this.sections = this.textRenderingService.parse(value, this.transpose).sort((a, b) => a.type - b.type), 100);
else this.sections = this.textRenderingService.parse(value, this.transpose).sort((a, b) => a.type - b.type) } else {
this.sections = this.textRenderingService.parse(value, this.transpose).sort((a, b) => a.type - b.type);
}
} }
@@ -61,7 +63,9 @@ export class SongTextComponent implements OnInit {
public getLines(section: Section): Line[] { public getLines(section: Section): Line[] {
return section.lines.filter(_ => { return section.lines.filter(_ => {
if (_.type !== LineType.chord) return true; if (_.type !== LineType.chord) {
return true;
}
switch (this._chordMode) { switch (this._chordMode) {
case 'show': case 'show':

View File

@@ -1,7 +1,7 @@
import {Directive, ElementRef, Input} from "@angular/core"; import {Directive, ElementRef, Input} from '@angular/core';
@Directive({ @Directive({
selector: "[autofocus]" selector: '[autofocus]'
}) })
export class AutofocusDirective { export class AutofocusDirective {
private focus = true; private focus = true;

View File

@@ -15,21 +15,27 @@ export class RoleGuard implements CanActivate {
next: ActivatedRouteSnapshot, next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> { state: RouterStateSnapshot): Observable<boolean | UrlTree> {
const requiredRoles = next.data.requiredRoles; const requiredRoles = next.data.requiredRoles;
if (!requiredRoles) throw new Error('requiredRoles is not defined!'); if (!requiredRoles) {
throw new Error('requiredRoles is not defined!');
}
return this.userService.user$.pipe( return this.userService.user$.pipe(
map(user => { map(user => {
const roles = user.role?.split(';') ?? []; const roles = user.role?.split(';') ?? [];
if (roles.indexOf('admin') !== -1) return true; if (roles.indexOf('admin') !== -1) {
return true;
}
const allowed = roles.some(s => requiredRoles.indexOf(s) !== -1); const allowed = roles.some(s => requiredRoles.indexOf(s) !== -1);
return allowed || this.router.createUrlTree(this.defaultRoute(roles)); return allowed || this.router.createUrlTree(this.defaultRoute(roles));
}) })
) );
} }
private defaultRoute(roles: string[]): string[] { private defaultRoute(roles: string[]): string[] {
if (!roles || roles.length === 0) return ['brand', 'new-user']; if (!roles || roles.length === 0) {
return ['brand', 'new-user'];
}
switch (roles[0]) { switch (roles[0]) {
case 'user': case 'user':
return ['songs']; return ['songs'];