5 changed files with 239 additions and 0 deletions
@ -0,0 +1,221 @@ |
|||
{% extends "/Bases/StandardWebPage.html.twig" %} |
|||
|
|||
{% block content %} |
|||
<script src="/Static/JS/ThirdParty/abcjs-basic.js"></script> |
|||
<script> |
|||
|
|||
let partCounter = 0; // Keeps track of the number of parts |
|||
let barCounters = {}; // Keeps track of the number of bars in each part |
|||
|
|||
|
|||
|
|||
function generateABC() { |
|||
let builder = ""; |
|||
|
|||
// Add the tune metadata |
|||
builder += "X: 1\n"; // Default index |
|||
builder += "T: " + document.getElementById("TuneTitle").value + "\n"; // Title |
|||
builder += "S: " + document.getElementById("TuneCopyright").value + "\n"; // Copyright |
|||
builder += "M: 4/4\n"; // Default meter |
|||
builder += "K: C\n"; // Default key |
|||
|
|||
// Iterate through all parts |
|||
for (let partId = 1; partId <= partCounter; partId++) { |
|||
if (document.getElementById(`Part_${partId}`)) { |
|||
builder += `P: Part ${partId}\n`; // Part header |
|||
|
|||
// Iterate through bars in the part |
|||
for (let barId = 1; barId <= barCounters[partId]; barId++) { |
|||
const barInput = document.querySelector(`#Part_${partId}_Bar_${barId} .bar-input`); |
|||
if (barInput && barInput.value.trim() !== "") { |
|||
builder += barInput.value.trim() + " | "; // Append bar content |
|||
} |
|||
} |
|||
|
|||
// Add a line break after each part |
|||
builder += "\n"; |
|||
} |
|||
} |
|||
|
|||
renderABC(builder); // Render the ABC notation |
|||
} |
|||
|
|||
function renderABC(payload) |
|||
{ |
|||
document.getElementById('ABCReadout').innerHTML = payload; |
|||
const tunes = window.ABCJS.renderAbc( |
|||
'NotationContainer', |
|||
payload, |
|||
{ |
|||
add_classes: true, |
|||
format: { |
|||
gchordfont: "Atkinson Hyperlegible", |
|||
annotationfont: "Atkinson Hyperlegible", |
|||
headerfont: "Atkinson Hyperlegible", |
|||
infofont: "Atkinson Hyperlegible", |
|||
repeatfont: "Atkinson Hyperlegible", |
|||
tempofont: "Atkinson Hyperlegible", |
|||
titlefont: "Atkinson Hyperlegible", |
|||
voicefont: "Atkinson Hyperlegible", |
|||
wordsfont: "Atkinson Hyperlegible", |
|||
}, |
|||
} |
|||
); |
|||
} |
|||
|
|||
|
|||
function createNewPart() { |
|||
const container = document.getElementById('PartsWrapper'); |
|||
|
|||
// Increment the part counter |
|||
partCounter++; |
|||
barCounters[partCounter] = 8; // Start with 4 bars |
|||
|
|||
// Create a new part container |
|||
const newPartDiv = document.createElement('div'); |
|||
newPartDiv.id = `Part_${partCounter}`; |
|||
newPartDiv.classList.add('part'); |
|||
|
|||
// Add the title and initial bars to the part |
|||
newPartDiv.innerHTML = ` |
|||
<h3>Part ${partCounter}</h3> |
|||
<button class="delete-part-btn" onclick="deletePart(${partCounter})">{{ "Delete Part"|translate }}</button> |
|||
<button class="add-bar-btn" onclick="addBar(${partCounter})">{{ "Add Bar"|translate }}</button> |
|||
<div class="bars-wrapper" id="BarsWrapper_${partCounter}"> |
|||
${generateBarsHTML(partCounter, 8)} |
|||
</div> |
|||
`; |
|||
|
|||
container.appendChild(newPartDiv); |
|||
} |
|||
|
|||
function addBar(partId) { |
|||
const barsWrapper = document.getElementById(`BarsWrapper_${partId}`); |
|||
barCounters[partId]++; |
|||
|
|||
const barDiv = document.createElement('div'); |
|||
barDiv.classList.add('bar'); |
|||
barDiv.id = `Part_${partId}_Bar_${barCounters[partId]}`; |
|||
barDiv.innerHTML = ` |
|||
<textarea class="bar-input" placeholder="{{ "Bar"|translate }} ${barCounters[partId]}"></textarea> |
|||
<button class="bar-btn remove-bar" onclick="removeBar(${partId}, ${barCounters[partId]})">-</button> |
|||
`; |
|||
barsWrapper.appendChild(barDiv); |
|||
} |
|||
|
|||
function removeBar(partId, barId) { |
|||
const barDiv = document.getElementById(`Part_${partId}_Bar_${barId}`); |
|||
if (barDiv) { |
|||
barDiv.remove(); |
|||
} |
|||
} |
|||
|
|||
function deletePart(partId) { |
|||
const partDiv = document.getElementById(`Part_${partId}`); |
|||
if (partDiv) { |
|||
delete barCounters[partId]; // Clean up the bar counters |
|||
partDiv.remove(); |
|||
} |
|||
} |
|||
|
|||
function generateBarsHTML(partId, numBars) { |
|||
let barsHTML = ''; |
|||
for (let i = 1; i <= numBars; i++) { |
|||
barsHTML += ` |
|||
<div class="bar" id="Part_${partId}_Bar_${i}"> |
|||
<input type="text" class="bar-input" placeholder="{{ "Bar"|translate }} ${i}" onchange=generateABC()></textarea> |
|||
<button class="bar-btn remove-bar" onclick="removeBar(${partId}, ${i})">-</button> |
|||
</div> |
|||
`; |
|||
} |
|||
return barsHTML; |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
.part { |
|||
border: 1px solid #ddd; |
|||
margin: 1rem 0; |
|||
padding: 1rem; |
|||
border-radius: 5px; |
|||
background: #f9f9f9; |
|||
} |
|||
|
|||
.bars-wrapper { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
gap: 1rem; |
|||
margin-top: 1rem; |
|||
} |
|||
|
|||
.bar { |
|||
position: relative; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: flex-start; |
|||
gap: 0.5rem; |
|||
} |
|||
|
|||
.bar textarea { |
|||
width: 8rem; |
|||
height: 3rem; |
|||
resize: none; |
|||
} |
|||
|
|||
.bar-btn { |
|||
padding: 0.25rem 0.5rem; |
|||
font-size: 0.9rem; |
|||
border: none; |
|||
border-radius: 3px; |
|||
cursor: pointer; |
|||
background-color: #ff4d4d; |
|||
color: white; |
|||
} |
|||
|
|||
.bar-btn:hover { |
|||
background-color: #d93636; |
|||
} |
|||
|
|||
.delete-part-btn, |
|||
.add-bar-btn { |
|||
background-color: #007bff; |
|||
color: white; |
|||
border: none; |
|||
border-radius: 3px; |
|||
padding: 0.5rem 1rem; |
|||
cursor: pointer; |
|||
margin: 0.5rem 0; |
|||
} |
|||
|
|||
.delete-part-btn:hover, |
|||
.add-bar-btn:hover { |
|||
background-color: #0056b3; |
|||
} |
|||
</style> |
|||
|
|||
<div class="InnerContent"> |
|||
<h1>{{ "Tune Creator"|translate }}</h1> |
|||
|
|||
<div class="container"> |
|||
<div class="left-main"> |
|||
<div> |
|||
<label for="TuneTitle">{{ "Tune Title"|translate }}</label><br> |
|||
<input id="TuneTitle" name="TuneTitle" type="text" onchange="generateABC()"> |
|||
<br><br> |
|||
<label for="TuneCopyright">{{ "Copyright"|translate }}</label><br> |
|||
<input id="TuneCopyright" name="TuneCopyright" type="text" onchange="generateABC()"> |
|||
|
|||
<div> |
|||
<button onclick="createNewPart()">{{ "Create New Part"|translate }}</button> |
|||
<div id="PartsWrapper"></div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="right"> |
|||
<textarea id="ABCReadout" style="width: 100%; height: 25rem;" readonly></textarea> |
|||
</div> |
|||
</div> |
|||
|
|||
<div id="NotationContainer"></div> |
|||
</div> |
|||
{% endblock %} |
Loading…
Reference in new issue