diff --git a/src/app/modules/songs/services/text-rendering.service.spec.ts b/src/app/modules/songs/services/text-rendering.service.spec.ts
index de4216a..338f326 100644
--- a/src/app/modules/songs/services/text-rendering.service.spec.ts
+++ b/src/app/modules/songs/services/text-rendering.service.spec.ts
@@ -35,9 +35,13 @@ Cool bridge without any chords
const service: TextRenderingService = TestBed.get(TextRenderingService);
const sections = service.parse(testText);
expect(sections[0].type).toBe(SectionType.Verse);
+ expect(sections[0].number).toBe(0);
expect(sections[1].type).toBe(SectionType.Verse);
+ expect(sections[1].number).toBe(1);
expect(sections[2].type).toBe(SectionType.Chorus);
+ expect(sections[2].number).toBe(0);
expect(sections[3].type).toBe(SectionType.Bridge);
+ expect(sections[3].number).toBe(0);
});
it('should parse text lines', () => {
@@ -60,6 +64,7 @@ Cool bridge without any chords
it('should parse chord lines', () => {
const service: TextRenderingService = TestBed.get(TextRenderingService);
const sections = service.parse(testText);
+ console.log(sections);
expect(sections[0].lines[0].type).toBe(LineType.chord);
expect(sections[0].lines[0].text).toBe('C D E F G A H');
expect(sections[0].lines[2].type).toBe(LineType.chord);
@@ -72,7 +77,6 @@ Cool bridge without any chords
expect(sections[2].lines[0].text).toBe('c c# db c7 cmaj7 c/e');
// c c# db c7 cmaj7 c/e
- console.log(sections[2].lines[0].chords);
expect(sections[2].lines[0].chords).toEqual([
{chord: 'c', length: 2, position: 0},
{chord: 'c#', length: 3, position: 2},
diff --git a/src/app/modules/songs/services/text-rendering.service.ts b/src/app/modules/songs/services/text-rendering.service.ts
index 18e170e..b356a75 100644
--- a/src/app/modules/songs/services/text-rendering.service.ts
+++ b/src/app/modules/songs/services/text-rendering.service.ts
@@ -35,8 +35,6 @@ export interface Section {
providedIn: 'root'
})
export class TextRenderingService {
-
-
private regexSection = /(Strophe|Refrain|Bridge)/;
constructor() {
@@ -44,29 +42,40 @@ export class TextRenderingService {
public parse(text: string): Section[] {
const arrayOfLines = text.split(/\r?\n/).filter(_ => _);
- return arrayOfLines.reduce((array, line) => {
+ const indices = {
+ [SectionType.Bridge]: 0,
+ [SectionType.Chorus]: 0,
+ [SectionType.Verse]: 0,
+ };
+ const sections = arrayOfLines.reduce((array, line) => {
+ const type = this.getSectionTypeOfLine(line);
if (line.match(this.regexSection)) return [...array, {
- type: this.getSectionTypeOfLine(line),
- number: -1,
+ type: type,
+ number: indices[type]++,
lines: []
}];
array[array.length - 1].lines.push(this.getLineOfLineText(line));
return array;
}, [] as Section[]);
+ console.log(indices);
+
+ return sections;
}
private getLineOfLineText(text: string): Line {
- const regex = /\b(C#|C|Db|D#|D|Eb|E|F#|F|Gb|G#|G|Ab|A#|A|B|H|c#|c|db|d#|d|eb|e|f#|f|gb|g#|g|ab|a#|a|b|h)(\/(C#|C|Db|D#|D|Eb|E|F#|F|Gb|G#|G|Ab|A#|A|B|H|c#|c|db|d#|d|eb|e|f#|f|gb|g#|g|ab|a#|a|b|h))?(\d+|maj7)?.?\b/mg;
-
- const match = text.match(regex);
- const hasMatches = !!match;
+ if (!text) return null;
+ const cords = this.readChords(text);
+ const hasMatches = cords.length > 0;
const type = hasMatches ? LineType.chord : LineType.text;
- return {type, text, chords: hasMatches ? this.readChords(text) : undefined}
+ return {type, text, chords: hasMatches ? cords : undefined}
}
private getSectionTypeOfLine(line: string): SectionType {
- const typeString = line.match(this.regexSection)[1];
+ if (!line) return null;
+ const match = line.match(this.regexSection);
+ if (!match || match.length < 2) return null;
+ const typeString = match[1];
switch (typeString) {
case "Strophe":
return SectionType.Verse;
@@ -81,7 +90,8 @@ export class TextRenderingService {
let match;
const chords: Chord[] = [];
- const regex = /\b(C#|C|Db|D#|D|Eb|E|F#|F|Gb|G#|G|Ab|A#|A|B|H|c#|c|db|d#|d|eb|e|f#|f|gb|g#|g|ab|a#|a|b|h)(\/(C#|C|Db|D#|D|Eb|E|F#|F|Gb|G#|G|Ab|A#|A|B|H|c#|c|db|d#|d|eb|e|f#|f|gb|g#|g|ab|a#|a|b|h))?(\d+|maj7)?.?\b/mg;
+ // https://regex101.com/r/68jMB8/3
+ const regex = /\b(C#|C|Db|D#|D|Eb|E|F#|F|Gb|G#|G|Ab|A#|A|B|H|c#|c|db|d#|d|eb|e|f#|f|gb|g#|g|ab|a#|a|b|h)(\/(C#|C|Db|D#|D|Eb|E|F#|F|Gb|G#|G|Ab|A#|A|B|H|c#|c|db|d#|d|eb|e|f#|f|gb|g#|g|ab|a#|a|b|h))?(\d+|maj7)?\s?\b/mg;
while ((match = regex.exec(chordLine)) !== null) {
const chord: Chord = {
diff --git a/src/app/modules/songs/song/song.component.html b/src/app/modules/songs/song/song.component.html
index 0299272..8a29577 100644
--- a/src/app/modules/songs/song/song.component.html
+++ b/src/app/modules/songs/song/song.component.html
@@ -15,7 +15,10 @@
-
{{song.text}}
+
+
+
+
{{song.comment}}
Anhänge
diff --git a/src/app/modules/songs/song/song.module.ts b/src/app/modules/songs/song/song.module.ts
index f5b880f..918484c 100644
--- a/src/app/modules/songs/song/song.module.ts
+++ b/src/app/modules/songs/song/song.module.ts
@@ -7,6 +7,7 @@ import {MatButtonModule} from '@angular/material/button';
import {ButtonRowModule} from '../../../widget-modules/components/button-row/button-row.module';
import {RouterModule} from '@angular/router';
import {LegalOwnerTranslatorModule} from '../../../widget-modules/pipes/legal-owner-translator/legal-owner-translator.module';
+import {SongTextModule} from '../../../widget-modules/components/song-text/song-text.module';
@NgModule({
@@ -21,6 +22,7 @@ import {LegalOwnerTranslatorModule} from '../../../widget-modules/pipes/legal-ow
MatButtonModule,
ButtonRowModule,
LegalOwnerTranslatorModule,
+ SongTextModule,
]
})
export class SongModule {
diff --git a/src/app/widget-modules/components/song-text/song-text.component.html b/src/app/widget-modules/components/song-text/song-text.component.html
new file mode 100644
index 0000000..7616c68
--- /dev/null
+++ b/src/app/widget-modules/components/song-text/song-text.component.html
@@ -0,0 +1,12 @@
+
diff --git a/src/app/widget-modules/components/song-text/song-text.component.less b/src/app/widget-modules/components/song-text/song-text.component.less
new file mode 100644
index 0000000..dcd970e
--- /dev/null
+++ b/src/app/widget-modules/components/song-text/song-text.component.less
@@ -0,0 +1,48 @@
+.song-text {
+ white-space: pre-wrap;
+ position: relative;
+
+ &.chords {
+ font-family: 'Ubuntu Mono', monospace;
+ }
+
+ &:hover .menu {
+ opacity: 1;
+ }
+}
+
+.menu {
+ position: absolute;
+ right: 0;
+ background: #eee;
+ border-radius: 8px;
+ padding: 5px;
+ width: 20px;
+ height: 20px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ transition: 300ms all ease-in-out;
+ cursor: pointer;
+ opacity: 0;
+
+ &:hover {
+ background: #ddd;
+ }
+
+
+}
+
+.section {
+ margin-bottom: 20px;
+ border-left: 3px solid #ddd;
+}
+
+.chorus {
+ margin-left: 20px;
+ border-left: none;
+}
+
+.chord {
+ font-weight: bold;
+}
diff --git a/src/app/widget-modules/components/song-text/song-text.component.spec.ts b/src/app/widget-modules/components/song-text/song-text.component.spec.ts
new file mode 100644
index 0000000..37f30e6
--- /dev/null
+++ b/src/app/widget-modules/components/song-text/song-text.component.spec.ts
@@ -0,0 +1,25 @@
+import {async, ComponentFixture, TestBed} from '@angular/core/testing';
+
+import {SongTextComponent} from './song-text.component';
+
+describe('SongTextComponent', () => {
+ let component: SongTextComponent;
+ let fixture: ComponentFixture
;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [SongTextComponent]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SongTextComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/widget-modules/components/song-text/song-text.component.ts b/src/app/widget-modules/components/song-text/song-text.component.ts
new file mode 100644
index 0000000..bfbd85e
--- /dev/null
+++ b/src/app/widget-modules/components/song-text/song-text.component.ts
@@ -0,0 +1,67 @@
+import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
+import {
+ Line,
+ LineType,
+ Section,
+ SectionType,
+ TextRenderingService
+} from '../../../modules/songs/services/text-rendering.service';
+import {faGripLines} from '@fortawesome/free-solid-svg-icons/faGripLines';
+
+export type ChordMode = 'show' | 'hide' | 'onlyFirst'
+
+@Component({
+ selector: 'app-song-text',
+ templateUrl: './song-text.component.html',
+ styleUrls: ['./song-text.component.less']
+})
+export class SongTextComponent implements OnInit {
+ public sections: Section[];
+ public chordMode: ChordMode = 'hide';
+ @Output() public chordModeChanged = new EventEmitter();
+ public faLines = faGripLines;
+
+ constructor(private textRenderingService: TextRenderingService) {
+ }
+
+ @Input()
+ public set text(value: string) {
+ this.sections = this.textRenderingService.parse(value).sort((a, b) => a.type - b.type);
+ console.log(this.sections)
+ }
+
+ ngOnInit(): void {
+ }
+
+ public getLines(section: Section): Line[] {
+ return section.lines.filter(_ => {
+ if (_.type !== LineType.chord) return true;
+
+ switch (this.chordMode) {
+ case 'show':
+ return true;
+ case 'hide':
+ return false;
+ case 'onlyFirst':
+ return section.number === 0 || section.type !== SectionType.Verse;
+ }
+ });
+ }
+
+ public onChordClick(): void {
+ const next = this.getNextChordMode();
+ this.chordMode = next;
+ this.chordModeChanged.next(next);
+ }
+
+ private getNextChordMode(): ChordMode {
+ switch (this.chordMode) {
+ case 'show':
+ return 'hide';
+ case 'hide':
+ return 'onlyFirst';
+ case 'onlyFirst':
+ return 'show';
+ }
+ }
+}
diff --git a/src/app/widget-modules/components/song-text/song-text.module.ts b/src/app/widget-modules/components/song-text/song-text.module.ts
new file mode 100644
index 0000000..f57ba16
--- /dev/null
+++ b/src/app/widget-modules/components/song-text/song-text.module.ts
@@ -0,0 +1,16 @@
+import {NgModule} from '@angular/core';
+import {CommonModule} from '@angular/common';
+import {SongTextComponent} from './song-text.component';
+import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
+
+
+@NgModule({
+ declarations: [SongTextComponent],
+ exports: [SongTextComponent],
+ imports: [
+ CommonModule,
+ FontAwesomeModule
+ ]
+})
+export class SongTextModule {
+}