Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle invalid obliques #1193

Merged
merged 2 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions assets/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
<div id="remove-empty-syls" class="navbar-dropdown-item">Remove Empty Syllables</div>
<div id="remove-empty-neumes" class="navbar-dropdown-item">Remove Empty Neumes</div>
<div id="remove-out-of-bounds-glyphs" class="navbar-dropdown-item">Remove Out-of-bounds Glyphs</div>
<div id="untoggle-invalid-oblique" class="navbar-dropdown-item">Untoggle Invalid Obliques</div>
<div id="untoggle-invalid-syls" class="navbar-dropdown-item">Untoggle Invalid Toggled Syllables</div>
<div id="revert" class="navbar-dropdown-item">Revert</div>
</div>
Expand Down
20 changes: 15 additions & 5 deletions src/utils/ConvertMei.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,8 @@ export function convertToVerovio(sbBasedMei: string): string {
const newSyllables = Array.from(mei.getElementsByTagName('syllable'));
let invalidLinked = false;
let invalidLinkedInfo = 'The following linked syllables are not encoded correctly: \n\n';
let invalidOblique = false;
let invalidObliqueInfo = 'The following obliques are incomplete: \n\n';
for (const syllable of mei.querySelectorAll('syllable')) {
for (const clef of syllable.querySelectorAll('clef')) {
syllable.insertAdjacentElement('beforebegin', clef);
Expand All @@ -409,7 +411,11 @@ export function convertToVerovio(sbBasedMei: string): string {

// Check incomplete obliques
// Obliques always come as a pair
checkOblique(syllable);
const obliqueInfo = checkOblique(syllable);
if (obliqueInfo) {
invalidOblique = true;
invalidObliqueInfo += obliqueInfo;
}

// Check syllables that contains @precedes or @follows
// Update syllable arrays for each syllable
Expand Down Expand Up @@ -438,6 +444,9 @@ export function convertToVerovio(sbBasedMei: string): string {
}
}
}
if (invalidOblique) {
Notification.queueNotification('This file contains incomplete oblique(s)', 'error', invalidObliqueInfo);
}
if (invalidLinked) {
Notification.queueNotification('This file contains invalid linked syllable(s)', 'error', invalidLinkedInfo);
}
Expand Down Expand Up @@ -542,22 +551,23 @@ function checkFollowsSyllable (syllable: Element, syllables: Element[]): string
}
}

function checkOblique (syllable: Element): void {
function checkOblique (syllable: Element): string {
const ncs = syllable.querySelectorAll('nc');
let ncIdx = 0;
let info = '';
while (ncIdx < ncs.length) {
if (ncs[ncIdx].getAttribute('ligated')) {
if ((ncIdx < ncs.length-1 && !ncs[ncIdx+1].getAttribute('ligated')) || (ncIdx == ncs.length-1)) {
// If nc is ligated, and the next nc is not
// Or, nc is ligated, but already at the end (there is no next)
const sylText = getSyllableText(syllable);
const sylId = syllable.getAttribute('xml:id');
Notification.queueNotification(`The oblique in syllable (${sylText}) is incomplete!<br/>ID: ${sylId}`, 'error');
info += `- The oblique in syllable (${getSyllableText(syllable)}) with xml:id: ${syllable.getAttribute('xml:id')}\n`;
}
ncIdx += 2;
}
ncIdx += 1;
}

return info;
}

export function removeColumnLabel(mei: string): string {
Expand Down
53 changes: 53 additions & 0 deletions src/utils/EditControls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,59 @@ export function initNavbar (neonView: NeonView): void {
});
});

document.getElementById('untoggle-invalid-oblique').addEventListener('click', function () {
const uri = neonView.view.getCurrentPageURI();
neonView.getPageMEI(uri).then(meiString => {
// Load MEI document into parser
const parser = new DOMParser();
const meiDoc = parser.parseFromString(meiString, 'text/xml');
const mei = meiDoc.documentElement;
const ncs = Array.from(mei.getElementsByTagName('nc'));

let hasInvalidOblique = false;
const chainAction: EditorAction = {
action: 'chain',
param: []
};
const param = new Array<EditorAction>();
let ncIdx = 0;
while (ncIdx < ncs.length) {
if (ncs[ncIdx].getAttribute('ligated')) {
if ((ncIdx < ncs.length-1 && !ncs[ncIdx+1].getAttribute('ligated')) || (ncIdx == ncs.length-1)) {
// If nc is ligated, and the next nc is not
// Or, nc is ligated, but already at the end (there is no next)\
hasInvalidOblique = true;
param.push({
action: 'set',
param: {
elementId: ncs[ncIdx].getAttribute('xml:id'),
attrType: 'ligated',
attrValue: ''
}
});
}
ncIdx += 2;
}
ncIdx += 1;
}

if (!hasInvalidOblique) {
Notification.queueNotification('No invalid obliques found', 'warning');
}
else {
chainAction.param = param;
neonView.edit(chainAction, neonView.view.getCurrentPageURI()).then((result) => {
if (result) {
Notification.queueNotification('Untoggled invalid obliques', 'success');
} else {
Notification.queueNotification('Failed to untoggle invalid obliques', 'error');
}
neonView.updateForCurrentPage();
});
}
});
});

document.getElementById('untoggle-invalid-syls').addEventListener('click', function () {
const uri = neonView.view.getCurrentPageURI();
neonView.getPageMEI(uri).then(meiString => {
Expand Down
Loading