<!DOCTYPE html>
<html>
<body onload="document.getElementById ('textareaCode').focus ();">
<script type="text/javascript">
// Edit the following two lines, e.g. use "div" instead of "blockquote".
// § will be replaced by the value in the entry field at transform time
var gBeginWith = "<blockquote style=\"font-family: Arial Unicode MS; font-size:§%;\">";
var gEndWith = "\n</blockquote>";
var mBeginOfChord;
var mEndOfChord;
var mPretty;
function IdentifyChordSeparators (aEntered)
{
var lChordsInParentheses = true;
var lBracketIdx = aEntered.indexOf ('[');
if (lBracketIdx >= 0) {
var lParenIdx = aEntered.indexOf ('(');
if (lParenIdx < 0 || lParenIdx > lBracketIdx)
lChordsInParentheses = false;
}
if (lChordsInParentheses) {
mBeginOfChord = '(';
mEndOfChord = ')';
}
else {
mBeginOfChord = '[';
mEndOfChord = ']';
}
}
function Add (aWhat)
{
mPretty = mPretty + aWhat;
}
function AddEscaped (aWhat)
{
for (var i = 0; i < aWhat.length; i++) {
var lChar = aWhat.charCodeAt (i);
if (lChar >= 127)
Add ("&#" + lChar + ";");
else
Add (String.fromCharCode (lChar));
}
}
function ProcessNoteName (aChordPart)
{
if (aChordPart.charAt (0) == '\\') { // formatting done by the user!
Add (aChordPart.substring (1));
return "";
}
AddEscaped (aChordPart.charAt (0));
switch (aChordPart.charAt (1)) {
case 'b':
Add ("♭"); // a prettier flat sign
return aChordPart.substring (2);
case '#':
Add ("♯"); // a prettier sharp sign
return aChordPart.substring (2);
}
return aChordPart.substring (1);
}
function AddChord (aChord)
{
var lStillTodo = ProcessNoteName (aChord);
if (lStillTodo.charAt (0) == 'm' && lStillTodo.charAt (1) != 'a') {
Add ("m");
lStillTodo = lStillTodo.substring (1);
}
if (lStillTodo.charAt (0) == '/') { // the bass note must follow immediately
Add ("/");
AddEscaped (ProcessNoteName (lStillTodo.substring (1)));
Add ("<sup> </sup>");
}
else {
Add ("<sup>");
var aSlash = lStillTodo.indexOf ('/');
if (aSlash >= 0) { // the bass note must appear in normal size
AddEscaped (lStillTodo.substring (0, aSlash));
Add ("</sup>/");
AddEscaped (ProcessNoteName (lStillTodo.substring (aSlash + 1)));
Add (" "); // ensure distance to the next chord
}
else {
AddEscaped (lStillTodo);
Add (" </sup>");
}
}
}
function AddChordDiv (aChordDiv, aIsFirst)
{
// a section of one chord and its lyrics
if (aIsFirst)
Add ("<div style=\"clear:left;float:left;\">");
else
Add ("<div style=\"float:left;\">");
var lEnd = aChordDiv.indexOf (mEndOfChord); // if < 0, syntax error
var lChord = aChordDiv.substring (0, lEnd).trim ();
if (lChord.length == 0)
Add (" <sup> </sup>");
else
AddChord (lChord);
Add ("<br />");
var lLyrics = aChordDiv.substring (lEnd + 1);
if (lLyrics.length == 0)
Add (" ");
else {
AddEscaped (lLyrics.trim ());
if (lLyrics.charAt (lLyrics.length - 1) == ' ')
Add (" ");
}
Add ("</div>");
}
function AddLine (aLine)
{
Add ("\n"); // used as a token only!
if (aLine.length == 0) {
Add ("<div style=\"clear:left;\"> </div>");
return;
}
var lChords = aLine.split (mBeginOfChord);
if (lChords.length == 1) { // no chord found
// line without chords, e.g. title does not need superscript space
Add ("<div style=\"clear:left;\">");
AddEscaped (aLine);
Add ("</div>");
return;
}
if (lChords [0].length == 0) // the line starts with a chord
AddChordDiv (lChords [1], true);
else {
AddChordDiv (mEndOfChord + lChords [0], true); // fake an empty chord
AddChordDiv (lChords [1], false);
}
for (var i = 2; i < lChords.length; i++)
AddChordDiv (lChords [i], false);
}
function TransformIt (aPurpose)
{
document.getElementById ("transformed").innerHTML = "Error!"; // in case of a crash
var lEntered = document.getElementById ("textareaCode").value;
IdentifyChordSeparators (lEntered);
var lLineSep = "\n"; // determine the line separator, to be on the safe side
var lIdxA = lEntered.indexOf ('\n');
if (lIdxA < 0)
lLineSep = "\r";
else if (lEntered.charAt (lIdxA - 1) == '\r')
lLineSep = "\r\n";
var lLines = lEntered.split (lLineSep);
mPretty = gBeginWith.replace ("§", document.getElementById ("fontsize").value);
for (var i = 0; i < lLines.length; i++)
AddLine (lLines [i].trim ());
Add (gEndWith);
document.getElementById ("transformed").innerHTML = mPretty;
var lWindow;
switch (aPurpose) {
case "As HTML":
lWindow = open ("", "SourceWindow", "height=500, width=1000");
lWindow.document.write ("<code>" + mPretty.replace (/&/g, "&").replace (/</g, "<")
.replace (/>/g, ">").replace (/\n/g, "<br />") + "</code>");
lWindow.document.close ();
lWindow.focus ();
break;
case "Print":
lWindow = open ("", "PrintWindow", "height=500, width=700");
lWindow.document.write (mPretty);
lWindow.document.close ();
lWindow.focus ();
lWindow.print ();
break;
}
}
</script>
<div style="top:0;height:40%;width:98%;position:absolute;">
<textarea id="textareaCode" wrap="logical" style="height:85%;width:100%;"></textarea>
<button type="button" onclick="TransformIt ('')">Transform</button>
<button type="button" onclick="TransformIt ('As HTML')">As HTML</button>
<button type="button" onclick="TransformIt ('Print')" style="margin-right:30px;">Print</button>
<label for="fontsize">Font size in %:</label>
<input id="fontsize" type="number" min="20" max="2000" value="100">
</div>
<div id="transformed" style="bottom:0;height:60%;width:98%;overflow-y:scroll;position:absolute;"><h2>Chordalign</h2>
<noscript><p style="color:red;">To use this tool, you must <b>activate JavaScript</b>
and reload the file.</p></noscript>
<p>Enter or “paste” your song lyrics above, with chord symbols either all in parentheses or
all in brackets, each directly preceding its syllable (if any). You can enter characters of any language, which will
be processed for codepage independence. Use HTML items at your own risk. To exempt a “chord”
from the automatized recognition of superscripts and accidentals, prefix it with \.</p>
<p>Example:<br />
<code>(C)We shall (F7)over(G/B)come, (Am7)(Ab7/Gb)<br />
&#40;Tá mé (Baug)cinnte,&mdash;&#41; (Cmaj7)We (Abmaj7)shall (F#dim7)ov-(G9/F)er-(Em7)come!(\C°)<br />
(\<i>Interlude:</i>)(Ammaj7)(C7 &#40;-11&#41;)</code></p>
<p>When you click either of the buttons, the transformed text will appear here. It is meant for testing only
(—errors, such as unmatched parentheses, result in incomplete or wrong display—), <b>not
suitable for clipboard copying</b>. To use the result elsewhere, click “As HTML”,
select the whole content of the new window (Ctrl-A), and copy&paste it to the desired destination.</p>
<p><i>Donated to the public domain by “Grishka and Friends”. Have fun!</i></p></div>
</body>
</html>gt;/");
AddEscaped (ProcessNoteName (lStillTodo.substring (aSlash + 1)));
Add ("