1/* DOKUWIKI:include_once js/raphael.js */
2/* DOKUWIKI:include_once js/jtab.min.js */
3
4function ready() {
5    "use strict";
6    runSongHighlighter();
7    jtab.renderimplicit(null);
8}
9
10var songBlockSelector = "song-with-chords";
11var songChordSelector = "song-chord";
12var songSectionSelector = "song-section";
13var songSectionHeadingSelector = "song-section-heading";
14var chordLineSelector = "song-chordLine";
15var songTextLineSelector = "song-textLine";
16
17function parseSong(songText, transpose, showToolTips) {
18    "use strict";
19    transpose = transpose || 0;
20
21    var currentSection = "";
22
23    function parseText(text, transpose, showToolTips) {
24        var lines = text.split(/\n/g);
25
26        try {
27            transpose = Number(transpose);
28        } catch (error) {
29            transpose = 0;
30        }
31        findChords(lines, transpose, showToolTips);
32        return lines.join("\n");
33    }
34
35    function findChords(lines, transpose, showToolTips) {
36        for (var i = 0; i < lines.length; i++) {
37            var ln = parseLine(lines[i], transpose, showToolTips);
38            lines[i] = ln.text;
39        }
40        if (currentSection != "") {
41            lines.push("</div>");
42        }
43    };
44
45    function parseLine(lineText, transpose, addTooltip) {
46        addTooltip = addTooltip || true;
47        /* ignore empty lines, will be controlled by paragraphs */
48        if (isNullOrWhiteSpace(lineText)) {
49            return {
50                'isChord': false,
51                'isSection': false,
52                'text': ""
53            };
54        }
55
56        var isChord = false;
57        var isSection = false;
58
59        var chordRegEx = /(?:(\s*)([a-g]{1}[b#]?(?:no|add|sus|dim|maj|min|m|13|11|9|7|6|5|4|3|2)*(?:\s*\/\s*[a-g]{1}[b#]?)?)|\s*(\().*\))/iy;
60
61        var sectionRegex = new RegExp("^\\s*(\\[(.+)\\])", "i");
62
63        var chordRep = lineText.replace(new RegExp("[a-g]{1}[b#]?(no|add|sus|dim|maj|min|m|13|11|9|7|6|5|4|3|2)*", "gi"), "");
64        var hasTextRegExp = new RegExp("[a-z](?![^\\(]*\\))", "i");
65        var isChord = hasTextRegExp.test(chordRep) == false;
66
67        if (isChord) {
68            var newLine = "";
69            var chordMatch;
70
71            while ((chordMatch = chordRegEx.exec(lineText)) != null) {
72                if (chordMatch[3] === "(") {
73                    newLine += '<span style="color:black;">' + chordMatch[0] + '</span>';
74                    continue;
75                }
76                try {
77                    var subchords = chordMatch[2].split("/");
78                } catch (error) {
79                    var i = 0;
80                }
81
82                for (var i2 = 0; i2 < subchords.length; i2++) {
83                    var chordRootRegEx = new RegExp("([a-g]{1}[b#]?)(.*)", "i");
84                    var chordRootMatch = chordRootRegEx.exec(subchords[i2]);
85                    var transposed = substChord(chordRootMatch[1], transpose);
86                    subchords[i2] = transposed + chordRootMatch[2] || "";
87                }
88                var newChord = subchords.join("/");
89                if (addTooltip)
90                    newLine += chordMatch[0].replace(chordMatch[2], '<span class="' + songChordSelector + ' tooltip">' + newChord + '<span class="tooltiptext jtab">' + subchords[0] + '</span></span>');
91                else
92                    newLine += chordMatch[0].replace(chordMatch[2], '<span class="' + songChordSelector + '">' + newChord + '</span>');
93            }
94            lineText = '<p style="white-space: pre;color: #d73a49;font-family: \'Courier New\', Courier, monospace;margin:0;" class="' + chordLineSelector + '">' + newLine + '</p>';
95        }
96        else if (sectionRegex.test(lineText)) {
97            var match = sectionRegex.exec(lineText);
98            var sectionText = "";
99            if (currentSection != "") {
100                sectionText += "</div>\n"
101            }
102            currentSection = match[2].toLowerCase();
103            sectionText += '<div class="' + songSectionSelector + ' ' + currentSection + '">\n';
104            sectionText += '<h3 class="' + songSectionHeadingSelector + ' ' + currentSection + '">' + match[1] + '</h3>';
105            lineText = sectionText;
106            isSection = true;
107        } else {
108            lineText = '<p style="white-space: pre;font-family: \'Courier New\', Courier, monospace;margin:0;" class="' + songTextLineSelector + '">' + lineText + '</p>';
109        }
110
111        return {
112            'isChord': isChord,
113            'isSection': isSection,
114            'text': lineText
115        };
116    };
117
118    function substChord(chord, transp) {
119        chord = normalizeChord(chord);
120        var notes = ["A", "Bb", "B", "C", "C#", "D", "Eb", "E", "F", "F#", "G", "G#"];
121
122        var x = notes.indexOf(chord);
123        x = (x + transp) % 12;
124        if (x < 0) x += 12;
125        return notes[x];
126    };
127
128    function normalizeChord(chord) {
129
130        chord = chord.charAt(0).toUpperCase() + chord.slice(1);
131
132        if (chord == "A#") chord = "Bb";
133        else if (chord == "Db") chord = "C#";
134        else if (chord == "Cb") chord = "B";
135        else if (chord == "D#") chord = "Eb";
136        else if (chord == "E#") chord = "F";
137        else if (chord == "Gb") chord = "F#";
138        else if (chord == "Ab") chord = "G#";
139        return chord;
140    }
141
142    function isNullOrWhiteSpace(str) {
143        return str == null || str.replace(/\s/g, '').length < 1;
144    }
145
146    return parseText(songText, transpose, showToolTips);
147}
148
149function runSongHighlighter() {
150    var songs = document.querySelectorAll('.' + songBlockSelector);
151    for (var i = 0; i < songs.length; i++) {
152        var transpose = songs[i].dataset.transpose;
153        songs[i].rawText = songs[i].innerHTML;
154        songs[i].innerHTML = parseSong(songs[i].rawText, transpose);
155    }
156};
157
158function cSheetExportToWord(id) {
159    var song = document.getElementById(id);
160
161    function copy() {
162        try {
163            // Now that we've selected the anchor text, execute the copy command
164            var successful = document.execCommand('copy');
165            var msg = successful ? 'successfully' : 'unsuccessfully';
166            alert(msg + " copied song to clipboard. Use CTRL + V to paste it in your word document.");
167        } catch (err) {
168            alert('Oops, unable to copy');
169        }
170    }
171
172    if (song.rawText) {
173        var node = document.createElement("div");
174        node.innerHTML = parseSong(song.rawText, song.dataset.transpose, false);
175        song.appendChild(node);
176        var range = document.createRange();
177        range.selectNode(node);
178        window.getSelection().addRange(range);
179        copy();
180        song.removeChild(node);
181    } else {
182        var range = document.createRange();
183        range.selectNode(song);
184        window.getSelection().addRange(range);
185        copy();
186    }
187
188    // Remove the selections - NOTE: Should use
189    // removeRange(range) when it is supported
190    window.getSelection().removeAllRanges();
191}
192
193document.addEventListener("DOMContentLoaded", ready);