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