The Mudcat Café TM
Thread #154141   Message #3613914
Posted By: GUEST,Grishka
31-Mar-14 - 07:02 AM
Thread Name: Tech: Grishka's tool aligning chord symbols
Subject: RE: Tech: Grishka's tool aligning chord symbols
<!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 ("&#x266d;"); // a prettier flat sign
                        return aChordPart.substring (2);
                case '#':
                        Add ("&#x266f;"); // 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>&nbsp;&nbsp;</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 ("&nbsp;"); // ensure distance to the next chord
                        }
                        else {
                                AddEscaped (lStillTodo);
                                Add ("&nbsp;&nbsp;</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 ("&nbsp;<sup>&nbsp;</sup>");
                else
                        AddChord (lChord);
                Add ("<br />");
                var lLyrics = aChordDiv.substring (lEnd + 1);
                if (lLyrics.length == 0)
                        Add ("&nbsp;");
                else {
                        AddEscaped (lLyrics.trim ());
                        if (lLyrics.charAt (lLyrics.length - 1) == ' ')
                                Add ("&nbsp;");
                }
                Add ("</div>");
        }
        function AddLine (aLine)
        {
                Add ("\n"); // used as a token only!
                if (aLine.length == 0) {
                        Add ("<div style=\"clear:left;\">&nbsp;</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, "&amp;").replace (/</g, "&lt;")
                                .replace (/>/g, "&gt;").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 &ldquo;paste&rdquo; 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 &ldquo;chord&rdquo;
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 />
&amp;#40;T&aacute; m&eacute; (Baug)cinnte,&amp;mdash;&amp;#41; (Cmaj7)We (Abmaj7)shall (F#dim7)ov-(G9/F)er-(Em7)come!(\C°)<br />
(\&lt;i&gt;Interlude:&lt;/i&gt;)(Ammaj7)(C7 &amp;#40;-11&amp;#41;)</code></p>

<p>When you click either of the buttons, the transformed text will appear here. It is meant for testing only
(&mdash;errors, such as unmatched parentheses, result in incomplete or wrong display&mdash;), <b>not
suitable for clipboard copying</b>. To use the result elsewhere, click &ldquo;As HTML&rdquo;,
select the whole content of the new window (Ctrl-A), and copy&amp;paste it to the desired destination.</p>

<p><i>Donated to the public domain by &ldquo;Grishka and Friends&rdquo;. Have fun!</i></p></div>
</body>
</html>gt;/");
                                AddEscaped (ProcessNoteName (lStillTodo.substring (aSlash + 1)));
                                Add ("