tasto back e bugfix editor
This commit is contained in:
@@ -33,6 +33,7 @@ export class ProposeCantoPage implements OnInit {
|
||||
private alertCtrl = inject(AlertController);
|
||||
|
||||
showChordsPreview: boolean = true;
|
||||
activeTab: string = 'editor';
|
||||
|
||||
get parsedSections(): ParsedSection[] {
|
||||
return this.lyricsParser.parseAccordi(this.content);
|
||||
@@ -47,6 +48,15 @@ export class ProposeCantoPage implements OnInit {
|
||||
youtubeLink: string = '';
|
||||
selectedLiturgico: number[] = [];
|
||||
selectedTematico: number[] = [];
|
||||
|
||||
get sortedLiturgico() {
|
||||
return [...this.cantiService.indiceLiturgico()].sort((a, b) => a.tag_name.localeCompare(b.tag_name));
|
||||
}
|
||||
|
||||
get sortedTematico() {
|
||||
return [...this.cantiService.indiceTematico()].sort((a, b) => a.tag_name.localeCompare(b.tag_name));
|
||||
}
|
||||
|
||||
editId: string | null = null;
|
||||
|
||||
private _content: string = '';
|
||||
@@ -195,6 +205,194 @@ export class ProposeCantoPage implements OnInit {
|
||||
this.fileInput.nativeElement.click();
|
||||
}
|
||||
|
||||
async deduceChords() {
|
||||
if (!this.content) return;
|
||||
|
||||
// Salva nello stack degli undo
|
||||
this.saveToUndoStack(this.content);
|
||||
|
||||
const lines = this.content.split('\n');
|
||||
|
||||
interface SectionLine {
|
||||
originalIndex: number;
|
||||
text: string;
|
||||
}
|
||||
|
||||
interface Section {
|
||||
type: 'verse' | 'chorus' | 'other';
|
||||
startTag: string | null;
|
||||
endTag: string | null;
|
||||
lines: SectionLine[];
|
||||
hasChords: boolean;
|
||||
}
|
||||
|
||||
const sections: Section[] = [];
|
||||
let currentSection: Section = { type: 'other', startTag: null, endTag: null, lines: [], hasChords: false };
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i];
|
||||
const trimmed = line.trim();
|
||||
|
||||
const startMatch = trimmed.match(/^\{(start_verse|start_chorus|start_verse_num|sov|soc)\}/);
|
||||
const endMatch = trimmed === '{end_verse}' || trimmed === '{eov}' || trimmed === '{end_chorus}' || trimmed === '{eoc}' || trimmed === '{end_verse_num}';
|
||||
|
||||
if (startMatch) {
|
||||
if (currentSection.lines.length > 0 || currentSection.startTag) {
|
||||
sections.push(currentSection);
|
||||
}
|
||||
let type: 'verse' | 'chorus' | 'other' = 'other';
|
||||
const tag = startMatch[1];
|
||||
if (tag === 'start_verse' || tag === 'start_verse_num' || tag === 'sov') {
|
||||
type = 'verse';
|
||||
} else if (tag === 'start_chorus' || tag === 'soc') {
|
||||
type = 'chorus';
|
||||
}
|
||||
currentSection = { type, startTag: line, endTag: null, lines: [], hasChords: false };
|
||||
} else if (endMatch) {
|
||||
currentSection.endTag = line;
|
||||
sections.push(currentSection);
|
||||
currentSection = { type: 'other', startTag: null, endTag: null, lines: [], hasChords: false };
|
||||
} else {
|
||||
if (trimmed === '' && !currentSection.startTag) {
|
||||
if (currentSection.lines.length > 0) {
|
||||
sections.push(currentSection);
|
||||
}
|
||||
sections.push({ type: 'other', startTag: null, endTag: null, lines: [{ originalIndex: i, text: '' }], hasChords: false });
|
||||
currentSection = { type: 'other', startTag: null, endTag: null, lines: [], hasChords: false };
|
||||
} else {
|
||||
const hasChords = /\[[^\]]+\]/.test(line);
|
||||
if (hasChords) {
|
||||
currentSection.hasChords = true;
|
||||
}
|
||||
if (currentSection.lines.length === 0 && !currentSection.startTag && trimmed !== '') {
|
||||
currentSection.type = 'verse';
|
||||
}
|
||||
const isComment = trimmed.startsWith('{c:') || trimmed.startsWith('{comment:');
|
||||
if (!isComment) {
|
||||
currentSection.lines.push({ originalIndex: i, text: line });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (currentSection.lines.length > 0 || currentSection.startTag) {
|
||||
sections.push(currentSection);
|
||||
}
|
||||
|
||||
const templateVerse = sections.find(s => s.type === 'verse' && s.hasChords);
|
||||
const templateChorus = sections.find(s => s.type === 'chorus' && s.hasChords);
|
||||
|
||||
let deducedCount = 0;
|
||||
|
||||
const getWords = (text: string) => {
|
||||
const words: { text: string; start: number; end: number }[] = [];
|
||||
const regex = /\S+/g;
|
||||
let match;
|
||||
while ((match = regex.exec(text)) !== null) {
|
||||
words.push({
|
||||
text: match[0],
|
||||
start: match.index,
|
||||
end: match.index + match[0].length
|
||||
});
|
||||
}
|
||||
return words;
|
||||
};
|
||||
|
||||
const alignChords = (templateLine: string, targetLine: string): string => {
|
||||
if (/\[[^\]]+\]/.test(targetLine)) {
|
||||
return targetLine;
|
||||
}
|
||||
|
||||
const parsedTemplate = this.lyricsParser.parseChordLine(templateLine);
|
||||
const templateClean = parsedTemplate.text;
|
||||
const targetClean = targetLine.replace(/\[[^\]]*\]/g, '');
|
||||
|
||||
if (!templateClean.trim() || !targetClean.trim()) {
|
||||
return targetLine;
|
||||
}
|
||||
|
||||
const chords: { chord: string; charIndex: number }[] = [];
|
||||
let charAcc = 0;
|
||||
parsedTemplate.segments.forEach(seg => {
|
||||
if (seg.chord) {
|
||||
chords.push({ chord: seg.chord, charIndex: charAcc });
|
||||
}
|
||||
charAcc += seg.text.length;
|
||||
});
|
||||
|
||||
if (chords.length === 0) {
|
||||
return targetLine;
|
||||
}
|
||||
|
||||
const templateWords = getWords(templateClean);
|
||||
const targetWords = getWords(targetClean);
|
||||
|
||||
const insertions: { chord: string; index: number }[] = [];
|
||||
|
||||
chords.forEach(c => {
|
||||
const ratio = c.charIndex / Math.max(1, templateClean.length);
|
||||
const wordIdx = templateWords.findIndex(w => Math.abs(w.start - c.charIndex) <= 1);
|
||||
|
||||
let targetIndex = 0;
|
||||
if (wordIdx !== -1 && templateWords.length > 1 && targetWords.length > 1) {
|
||||
const wRatio = wordIdx / (templateWords.length - 1);
|
||||
const targetWIdx = Math.round(wRatio * (targetWords.length - 1));
|
||||
targetIndex = targetWords[targetWIdx].start;
|
||||
} else {
|
||||
targetIndex = Math.round(ratio * targetClean.length);
|
||||
}
|
||||
|
||||
insertions.push({ chord: c.chord, index: targetIndex });
|
||||
});
|
||||
|
||||
insertions.sort((a, b) => b.index - a.index);
|
||||
|
||||
let result = targetClean;
|
||||
insertions.forEach(ins => {
|
||||
result = result.substring(0, ins.index) + `[${ins.chord}]` + result.substring(ins.index);
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const newLines = [...lines];
|
||||
|
||||
sections.forEach(sec => {
|
||||
if (!sec.hasChords && sec.type !== 'other') {
|
||||
const template = sec.type === 'verse' ? templateVerse : templateChorus;
|
||||
if (template) {
|
||||
for (let j = 0; j < sec.lines.length; j++) {
|
||||
const targetSecLine = sec.lines[j];
|
||||
if (j < template.lines.length) {
|
||||
const templateSecLine = template.lines[j];
|
||||
const aligned = alignChords(templateSecLine.text, targetSecLine.text);
|
||||
if (aligned !== targetSecLine.text) {
|
||||
newLines[targetSecLine.originalIndex] = aligned;
|
||||
deducedCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (deducedCount > 0) {
|
||||
this.content = newLines.join('\n');
|
||||
const toast = await this.toastController.create({
|
||||
message: `Accordi dedotti con successo in ${deducedCount} righe!`,
|
||||
duration: 3000,
|
||||
color: 'success'
|
||||
});
|
||||
toast.present();
|
||||
} else {
|
||||
const toast = await this.toastController.create({
|
||||
message: 'Nessuna strofa compatibile trovata o accordi già presenti.',
|
||||
duration: 3000,
|
||||
color: 'warning'
|
||||
});
|
||||
toast.present();
|
||||
}
|
||||
}
|
||||
|
||||
onDragOver(event: DragEvent) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
@@ -804,11 +1002,11 @@ export class ProposeCantoPage implements OnInit {
|
||||
return italianChordsCount > englishChordsCount;
|
||||
}
|
||||
|
||||
isChordWord(text: string, isItalian: boolean): boolean {
|
||||
isChordWord(text: string, isItalian: boolean, allowLowercase: boolean = false): boolean {
|
||||
if (!text || text.length === 0) return false;
|
||||
const lower = text.toLowerCase();
|
||||
// Skip common valid words written purely in lowercase
|
||||
if (text[0] === lower[0] && ['la', 'mi', 're', 'do', 'si', 'fa', 'e'].includes(lower)) {
|
||||
// Skip common valid words written purely in lowercase unless allowLowercase is true
|
||||
if (!allowLowercase && text[0] === lower[0] && ['la', 'mi', 're', 'do', 'si', 'fa', 'e'].includes(lower)) {
|
||||
return false;
|
||||
}
|
||||
let clean = text.toUpperCase().replace(/\s+/g, '').replace(/\((.*?)\)/g, '/$1').replace(/[\.\,\[\]]/g, '');
|
||||
@@ -943,7 +1141,7 @@ export class ProposeCantoPage implements OnInit {
|
||||
let hasLongNonChord = false;
|
||||
|
||||
line.forEach(w => {
|
||||
if (this.isChordWord(w.text, isItalian)) {
|
||||
if (this.isChordWord(w.text, isItalian, true)) {
|
||||
chordCount++;
|
||||
} else {
|
||||
const clean = w.text.replace(/[.,:;!\?]/g, '').trim();
|
||||
@@ -1047,10 +1245,11 @@ export class ProposeCantoPage implements OnInit {
|
||||
}
|
||||
|
||||
// If we see a large vertical gap, close open blocks
|
||||
const lastProcessedLine = classifiedLines[i];
|
||||
const currentNext = (i + 1 < classifiedLines.length) ? classifiedLines[i + 1] : null;
|
||||
if (currentNext) {
|
||||
const gap = currentNext.yCenter - current.yCenter;
|
||||
if (gap > avgHeight * 2.5) {
|
||||
if (currentNext && lastProcessedLine) {
|
||||
const gap = currentNext.yCenter - lastProcessedLine.yCenter;
|
||||
if (gap > avgHeight * 3.5) {
|
||||
if (inChorus) { processedLines.push('{end_chorus}'); inChorus = false; }
|
||||
if (inVerse) { processedLines.push('{end_verse}'); inVerse = false; }
|
||||
processedLines.push('');
|
||||
@@ -1120,7 +1319,7 @@ export class ProposeCantoPage implements OnInit {
|
||||
if (!part.trim()) return part;
|
||||
let clean = part.toUpperCase().replace(/\s+/g, '').replace(/\((.*?)\)/g, '/$1').replace(/[\.\,\[\]]/g, '');
|
||||
clean = this.sanitizeOcrChord(clean);
|
||||
if (this.isChordWord(part, isItalian)) {
|
||||
if (this.isChordWord(part, isItalian, true)) {
|
||||
return `[${this.convertEnglishChordToItalian(clean, isItalian)}]`;
|
||||
} else {
|
||||
return part;
|
||||
@@ -1234,7 +1433,7 @@ export class ProposeCantoPage implements OnInit {
|
||||
|
||||
let cleanChord = chord.text.replace(/[\(\)\[\]]/g, '').toUpperCase();
|
||||
cleanChord = this.sanitizeOcrChord(cleanChord);
|
||||
if (this.isChordWord(chord.text, isItalian)) {
|
||||
if (this.isChordWord(chord.text, isItalian, true)) {
|
||||
wordResult += wordText.substring(lastCharIndex, charIndex) + `[${this.convertEnglishChordToItalian(cleanChord, isItalian)}]`;
|
||||
} else {
|
||||
wordResult += wordText.substring(lastCharIndex, charIndex);
|
||||
|
||||
Reference in New Issue
Block a user