7 changed files with 246 additions and 3 deletions
@ -0,0 +1,17 @@ |
|||||
|
<?php |
||||
|
|
||||
|
use App\Enumerators\SessionElement; |
||||
|
use App\Wrappers\DatabaseInteractions; |
||||
|
use App\Wrappers\SessionWrapper; |
||||
|
use App\Wrappers\SQLQueryBuilderWrapper; |
||||
|
use App\Wrappers\TwigWrapper; |
||||
|
|
||||
|
require_once __DIR__ . "/../../vendor/autoload.php"; |
||||
|
|
||||
|
|
||||
|
TwigWrapper::RenderTwig( |
||||
|
target: "Pages/create/tune.html.twig", |
||||
|
arguments: [ |
||||
|
] |
||||
|
); |
||||
|
|
@ -0,0 +1,63 @@ |
|||||
|
<?php |
||||
|
|
||||
|
use App\Enumerators\SessionElement; |
||||
|
use App\Wrappers\DatabaseInteractions; |
||||
|
use App\Wrappers\SessionWrapper; |
||||
|
use App\Wrappers\SQLQueryBuilderWrapper; |
||||
|
use Ramsey\Uuid\Uuid; |
||||
|
|
||||
|
$tuneTitle = $_POST['TuneTitle']; |
||||
|
$tuneCopyright = $_POST['TuneCopyright']; |
||||
|
|
||||
|
$parts = []; |
||||
|
|
||||
|
foreach ($_POST as $key => $value) { |
||||
|
if (preg_match('/^PartTimeSignature-Part([A-Z])$/', $key, $matches)) { |
||||
|
$partLetter = $matches[1]; |
||||
|
$parts[$partLetter]['TimeSignature'] = $value; |
||||
|
} elseif (preg_match('/^PartKeySignature-Part([A-Z])$/', $key, $matches)) { |
||||
|
$partLetter = $matches[1]; |
||||
|
$parts[$partLetter]['KeySignature'] = $value; |
||||
|
} elseif (preg_match('/^TextArea-Part([A-Z])$/', $key, $matches)) { |
||||
|
$partLetter = $matches[1]; |
||||
|
$parts[$partLetter]['ABCNotation'] = $value; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
ksort($parts); |
||||
|
|
||||
|
$db = new DatabaseInteractions(); |
||||
|
$id = Uuid::uuid4()->toString(); |
||||
|
|
||||
|
$db->RunInsert( |
||||
|
queryBuilder: SQLQueryBuilderWrapper::INSERT('Tunes') |
||||
|
->set(col: 'ID', value: ':__id__') |
||||
|
->set(col: 'CreatedBy', value: ':__created_by__') |
||||
|
->set(col: 'Title', value: ':__tune_title__') |
||||
|
->set(col: 'Copyright', value: ':__copyright__') |
||||
|
->bindValue(name: '__id__', value: $id) |
||||
|
->bindValue(name: '__created_by__', value: SessionWrapper::Get(SessionElement::USER_ID)) |
||||
|
->bindValue(name: '__tune_title__', value: $tuneTitle) |
||||
|
->bindValue(name: '__copyright__', value: $tuneCopyright) |
||||
|
); |
||||
|
|
||||
|
foreach ($parts as $partLetter => $part) { |
||||
|
$db->RunInsert( |
||||
|
queryBuilder: SQLQueryBuilderWrapper::INSERT('TuneParts') |
||||
|
->set(col: 'CreatedBy', value: ':__created_by__') |
||||
|
->set(col: 'TuneID', value: ':__tune_id__') |
||||
|
->set(col: 'TimeSignature', value: ':__time_signature__') |
||||
|
->set(col: 'KeySignature', value: ':__key_signature__') |
||||
|
->set(col: 'PartLetter', value: ':__part_letter__') |
||||
|
->set(col: 'ABCNotation', value: ':__abc_notation__') |
||||
|
->bindValue(name: '__created_by__', value: SessionWrapper::Get(SessionElement::USER_ID)) |
||||
|
->bindValue(name: '__tune_id__', value: $id) |
||||
|
->bindValue(name: '__time_signature__', value: $part['TimeSignature']) |
||||
|
->bindValue(name: '__key_signature__', value: $part['KeySignature']) |
||||
|
->bindValue(name: '__part_letter__', value: $partLetter) |
||||
|
->bindValue(name: '__abc_notation__', value: $part['ABCNotation']) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
header("Location: /tune/{$id}"); |
||||
|
die(); |
@ -0,0 +1,146 @@ |
|||||
|
{% extends "/Bases/StandardWebPage.html.twig" %} |
||||
|
|
||||
|
{% block content %} |
||||
|
<script src="/Static/JS/ThirdParty/abcjs-basic.js"></script> |
||||
|
<script> |
||||
|
|
||||
|
let partCounter = 0; // Track part count |
||||
|
let partLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // Allowed letters for parts |
||||
|
let barCounters = {}; // Bar counters per part |
||||
|
|
||||
|
function getPartLetter(index) { |
||||
|
return partLetters[index] || `X${index}`; // Prevent overflow |
||||
|
} |
||||
|
|
||||
|
function generateABC() { |
||||
|
let builder = ""; |
||||
|
|
||||
|
builder += "T: " + document.getElementById("TuneTitle").value + "\n"; |
||||
|
builder += "S: " + document.getElementById("TuneCopyright").value + "\n"; |
||||
|
|
||||
|
for (let i = 0; i < partCounter; i++) { |
||||
|
let partLetter = getPartLetter(i); |
||||
|
let partTextarea = document.getElementById(`TextArea-Part${partLetter}`); |
||||
|
let timeSigInput = document.getElementById(`PartTimeSignature-Part${partLetter}`); |
||||
|
let keySigInput = document.getElementById(`PartKeySignature-Part${partLetter}`); |
||||
|
|
||||
|
if (partTextarea) { |
||||
|
builder += `P: Part ${partLetter}\n`; |
||||
|
|
||||
|
if (timeSigInput && timeSigInput.value.trim() !== "") { |
||||
|
builder += `M: ${timeSigInput.value}\n`; |
||||
|
} |
||||
|
|
||||
|
if (keySigInput && keySigInput.value.trim() !== "") { |
||||
|
builder += `K: ${keySigInput.value}\n`; |
||||
|
} |
||||
|
|
||||
|
builder += partTextarea.value + "\n"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
renderABC(builder); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
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() { |
||||
|
if (partCounter >= partLetters.length) { |
||||
|
alert("Maximum parts reached"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
let partLetter = getPartLetter(partCounter); |
||||
|
partCounter++; |
||||
|
|
||||
|
const container = document.getElementById('PartsWrapper'); |
||||
|
const newPartDiv = document.createElement('div'); |
||||
|
newPartDiv.id = `Part_${partLetter}`; |
||||
|
newPartDiv.classList.add('part'); |
||||
|
|
||||
|
newPartDiv.innerHTML = ` |
||||
|
<h3>Part ${partLetter}</h3> |
||||
|
<a class="delete-part-btn" href="javascript:deletePart('${partLetter}')">{{ "Delete Part"|translate }}</a> |
||||
|
<br> |
||||
|
<label for="PartTimeSignature-Part${partLetter}">{{ "Time Signature"|translate }}</label><br> |
||||
|
<input id="PartTimeSignature-Part${partLetter}" name="PartTimeSignature-Part${partLetter}" type="text" onchange="generateABC()"> |
||||
|
<br> |
||||
|
<label for="PartKeySignature-Part${partLetter}">{{ "Key Signature"|translate }}</label><br> |
||||
|
<input id="PartKeySignature-Part${partLetter}" name="PartKeySignature-Part${partLetter}" type="text" onchange="generateABC()"> |
||||
|
<br> |
||||
|
<textarea id="TextArea-Part${partLetter}" name="TextArea-Part${partLetter}" style="width: 100%; height: 5rem;" onchange="generateABC()"></textarea> |
||||
|
`; |
||||
|
|
||||
|
container.appendChild(newPartDiv); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
function deletePart(partLetter) { |
||||
|
const partDiv = document.getElementById(`Part_${partLetter}`); |
||||
|
if (partDiv) { |
||||
|
partDiv.remove(); |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style> |
||||
|
.part { |
||||
|
border: 1px solid #ddd; |
||||
|
margin: 1rem 0; |
||||
|
padding: 1rem; |
||||
|
border-radius: 5px; |
||||
|
background: #f9f9f9; |
||||
|
} |
||||
|
</style> |
||||
|
|
||||
|
<div class="InnerContent"> |
||||
|
<h1>{{ "Tune Creator"|translate }}</h1> |
||||
|
|
||||
|
<div class="container"> |
||||
|
<div class="left-main"> |
||||
|
<form action="/FormHandling/NewTune.php" method="POST"> |
||||
|
<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> |
||||
|
<a href="javascript:createNewPart()">{{ "Create New Part"|translate }}</a> |
||||
|
<div id="PartsWrapper"></div> |
||||
|
</div> |
||||
|
|
||||
|
<input type="submit"> |
||||
|
</form> |
||||
|
</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