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