abcweb-1.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. // abc2svg - ABC to SVG translator
  2. // @source: https://chiselapp.com/user/moinejf/repository/abc2svg
  3. // Copyright (C) 2014-2023 Jean-Francois Moine - LGPL3+
  4. //abcweb-1.js file to include in html pages
  5. window.onerror = function (msg, url, line) {
  6. if (typeof msg == 'string')
  7. alert("window error: " + msg + "\nURL: " + url + "\nLine: " + line)
  8. else if (typeof msg == 'object')
  9. alert("window error: " + msg.type + ' ' + msg.target.src)
  10. else
  11. alert("window error: " + msg)
  12. return false
  13. }
  14. var user, abcplay
  15. if (typeof abc2svg == "undefined")
  16. var abc2svg = {}
  17. abc2svg.mu = ""
  18. abc2svg.abc_end = function () { }
  19. abc2svg.jsdir = document.currentScript ? document.currentScript.src.match(/.*\//) : (function () {
  20. var s_a = document.getElementsByTagName('script')
  21. for (var k = 0; k < s_a.length; k++) {
  22. if (s_a[k].src.indexOf("abcweb") >= 0)
  23. return s_a[k].src.match(/.*\//) || ''
  24. }
  25. return ""
  26. })()
  27. abc2svg.loadjs = function (fn, relay, onerror) {
  28. var s = document.createElement('script')
  29. if (/:\/\//.test(fn))
  30. s.src = fn
  31. else
  32. s.src = abc2svg.jsdir + fn
  33. s.onload = relay
  34. s.onerror = function () {
  35. if (onerror)
  36. onerror(fn)
  37. else
  38. alert('error loading ' + fn)
  39. }
  40. document.head.appendChild(s)
  41. }
  42. function dom_loaded() {
  43. var abc, src, outb, err, a_inc = {}, tune_lst = [], html, busy, playing, playconf = { onend: function () { playing = 0 } }
  44. function visible() {
  45. var mu, r, wh = window.innerHeight || document.documentElement.clientHeight
  46. while (1) {
  47. mu = abc2svg.alldiv[0]
  48. if (!mu)
  49. break
  50. r = mu.d.getBoundingClientRect()
  51. if (r.top > wh)
  52. break
  53. musgen(mu)
  54. abc2svg.alldiv.shift()
  55. }
  56. if (abc2svg.alldiv.length) {
  57. if (!abc2svg.onscroll) {
  58. abc2svg.onscroll = visible
  59. window.addEventListener("scroll", visible)
  60. }
  61. } else { window.removeEventListener("scroll", visible) }
  62. }
  63. function get_p(e) {
  64. var i, j, k, r, o = '', sh = document.styleSheets, s = e.style
  65. c = e.getAttribute("class")
  66. if (c) {
  67. c = '.' + c
  68. for (i = 0; i < sh.length; i++) {
  69. r = sh[i].rules
  70. for (j = 0; j < r.length; j++) {
  71. if (r[j].selectorText == c)
  72. break
  73. }
  74. if (j < r.length)
  75. break
  76. }
  77. if (i < sh.length) {
  78. r = r[j]
  79. for (i = 0; i < r.style.length; i++) {
  80. k = r.style[i]
  81. if (k[0] == '-' && k[1] == '-')
  82. o += '%%' + k.slice(2) + ' '
  83. + r.style.getPropertyValue(k)
  84. + '\n'
  85. }
  86. }
  87. }
  88. for (i = 0; i < s.length; i++) {
  89. k = s[i]
  90. if (k[0] == '-' && k[1] == '-')
  91. o += '%%' + k.slice(2) + ' '
  92. + s.getPropertyValue(k)
  93. + '\n'
  94. }
  95. return o
  96. }
  97. function move_music(src) {
  98. var re, res, i, j, k, t, re_stop = /\n<|\n%.begin[^\s]+/g, ss = 0, out = ""
  99. if (/<[^>]* class="[^"]*abc[^"]*/.test(src))
  100. re = '<[^>]* class="[^"]*abc[^"]*'
  101. else
  102. re = '%abc-\\d|X:\\s*\\d'
  103. re = new RegExp('(^|\n)(' + re + ')', 'g')
  104. while (1) {
  105. res = re.exec(src)
  106. if (!res)
  107. break
  108. i = re.lastIndex - res[0].length
  109. if (i > ss) {
  110. out += src.slice(ss, i)
  111. html = 1
  112. }
  113. t = res[2]
  114. if (t[0] == '<') {
  115. i = src.indexOf('>', i) + 1
  116. j = res[2].indexOf(' ')
  117. t = res[2].slice(1, j)
  118. j = src.indexOf('</' + t + '>', i)
  119. ss = j + t.length + 4
  120. } else {
  121. re_stop.lastIndex = i
  122. while (1) {
  123. res = re_stop.exec(src)
  124. if (!res || res[0] == "\n<")
  125. break
  126. k = src.indexOf(res[0].replace("begin", "end"), re_stop.lastIndex)
  127. if (k < 0)
  128. break
  129. re_stop.lastIndex = k
  130. }
  131. if (!res || k < 0)
  132. j = src.length
  133. else
  134. j = re_stop.lastIndex - 1
  135. ss = j
  136. }
  137. out += '<script type="text/vnd.abc">\n'
  138. + src.slice(i, j)
  139. + '</script>\n'
  140. re.lastIndex = ss
  141. }
  142. out += src.slice(ss)
  143. if (abc2svg.page && html)
  144. out += '\
  145. <pre class="nop" style="background:#ff8080">\
  146. Printing may be bad because the file contains pure HTML and %%pageheight\
  147. </pre>\n'
  148. document.body.innerHTML = out
  149. }
  150. function save_music() {
  151. var i, k, div, c, s, sa
  152. abc2svg.music = [{ t: "", n: "mus0" }]
  153. k = location.search
  154. if (k) {
  155. k = k.substr(1).split("&")
  156. for (i = 0; i < k.length; i++)
  157. abc2svg.music[0].t += "%%"
  158. + decodeURIComponent(k[i].replace('=', ' '))
  159. + '\n'
  160. }
  161. while (1) {
  162. sa = document.getElementsByTagName('script')
  163. for (i = 0; i < sa.length; i++) {
  164. s = sa[i]
  165. if (s.type == 'text/vnd.abc')
  166. break
  167. }
  168. if (i >= sa.length)
  169. break
  170. c = get_p(s)
  171. div = document.createElement('div')
  172. if (s.text.indexOf('\nX:') < 0) {
  173. abc2svg.music[0].t += c + s.innerHTML
  174. if (!abc2svg.music[0].d)
  175. abc2svg.music[0].d = div
  176. } else { abc2svg.music.push({ n: "mus" + abc2svg.music.length, t: c + s.innerHTML, d: div }) }
  177. s.parentNode.replaceChild(div, s)
  178. }
  179. }
  180. function musgen(mu) {
  181. var t = mu.t
  182. if (busy) {
  183. mu.w = 1
  184. return
  185. }
  186. busy = 1
  187. function render() {
  188. var i, j, e
  189. outb = err = ""
  190. abc.tosvg(mu.n, t)
  191. abc2svg.abc_end()
  192. if (mu.d) {
  193. if (err)
  194. outb += '<pre class="nop" style="background:#ff8080">'
  195. + err + "</pre>\n"
  196. if (abc.cfmt().with_source && outb)
  197. outb = '<pre class="source">'
  198. + clean_txt(t)
  199. + '</pre>\n\
  200. <div class="source">\n'
  201. + outb
  202. + '</div>\n'
  203. mu.d.innerHTML = outb
  204. mu.d.addEventListener('click', abc2svg.playseq)
  205. e = mu.d.getElementsByTagName('svg')
  206. for (i = 0; i < e.length; i++) {
  207. j = e[i].getAttribute('class')
  208. if (!j)
  209. continue
  210. j = j.match(/tune(\d+)/)
  211. if (!j)
  212. continue
  213. j = j[1]
  214. tune_lst[j] = null
  215. }
  216. }
  217. mu.w = busy = 0
  218. for (i = 1; i < abc2svg.music.length; i++) {
  219. if (abc2svg.music[i].w) {
  220. musgen(abc2svg.music[i])
  221. break
  222. }
  223. }
  224. }
  225. function include() {
  226. var i, j, fn, r, k = 0
  227. while (1) {
  228. i = t.indexOf('%%abc-include ', k)
  229. if (i < 0) {
  230. render()
  231. return
  232. }
  233. i += 14
  234. j = t.indexOf('\n', i)
  235. fn = t.slice(i, j).trim()
  236. if (!a_inc[fn])
  237. break
  238. k = j
  239. }
  240. r = new XMLHttpRequest()
  241. r.open('GET', fn, true)
  242. r.onload = function () {
  243. if (r.status === 200) {
  244. a_inc[fn] = r.responseText
  245. if (abc2svg.modules.load(a_inc[fn], include))
  246. include()
  247. } else {
  248. a_inc[fn] = '%\n'
  249. alert('Error getting ' + fn + '\n' + r.statusText)
  250. include()
  251. }
  252. }
  253. r.onerror = function () {
  254. a_inc[fn] = '%\n'
  255. alert('Error getting ' + fn + '\n' + r.statusText)
  256. include()
  257. }
  258. r.send()
  259. }
  260. if (abc2svg.modules.load(t, include))
  261. include()
  262. }
  263. abc2svg.musgen = musgen
  264. user = { read_file: function (fn) { return a_inc[fn] }, errmsg: function (msg, l, c) { err += clean_txt(msg) + '\n' }, img_out: function (p) { outb += p } }
  265. function clean_txt(txt) {
  266. return txt.replace(/<|>|&.*?;|&/g, function (c) {
  267. switch (c) {
  268. case '<': return "&lt;"
  269. case '>': return "&gt;"
  270. case '&': return "&amp;"
  271. }
  272. return c
  273. })
  274. }
  275. abc2svg.playseq = function (evt) {
  276. if (playing) {
  277. abcplay.stop()
  278. return
  279. }
  280. var i, j, svg = evt.target, e = svg
  281. while (svg.tagName != 'svg') {
  282. svg = svg.parentNode
  283. if (!svg)
  284. return
  285. }
  286. i = svg.getAttribute('class')
  287. if (!i)
  288. return
  289. i = i.match(/tune(\d+)/)
  290. if (!i)
  291. return
  292. i = i[1]
  293. if (!abcplay) {
  294. if (typeof AbcPlay == "undefined") {
  295. abc2svg.playseq = function () { }
  296. return
  297. }
  298. if (abc.cfmt().soundfont)
  299. playconf.sfu = abc.cfmt().soundfont
  300. abcplay = AbcPlay(playconf)
  301. }
  302. if (!tune_lst[i]) {
  303. tune_lst[i] = abc.tunes[i]
  304. abcplay.add(tune_lst[i][0], tune_lst[i][1], tune_lst[i][3])
  305. }
  306. s = tune_lst[i][0]
  307. i = e.getAttribute('class')
  308. if (i)
  309. i = i.match(/abcr _(\d+)_/)
  310. if (i) {
  311. i = i[1]
  312. while (s && s.istart != i)
  313. s = s.ts_next
  314. if (!s) {
  315. alert("play bug: no such symbol in the tune")
  316. return
  317. }
  318. }
  319. while (s && !s.fname)
  320. s = s.ts_next
  321. for (i = 1; i < abc2svg.music.length; i++) {
  322. if (abc2svg.music[i].n == s.fname)
  323. break
  324. }
  325. abc2svg.mu = abc2svg.music[i]
  326. playing = 1
  327. abcplay.play(s, null)
  328. }
  329. src = document.body.innerHTML
  330. if (!abc2svg.Abc) {
  331. abc2svg.loadjs("abc2svg-1.js", dom_loaded)
  332. return
  333. }
  334. if (src.indexOf('type="text/vnd.abc"') < 0)
  335. move_music(src)
  336. save_music()
  337. abc = new abc2svg.Abc(user)
  338. if (typeof follow == "function")
  339. follow(abc, user, playconf)
  340. if (abc2svg.music[0].t)
  341. musgen(abc2svg.music[0])
  342. abc2svg.alldiv = []
  343. for (var i = 1; i < abc2svg.music.length; i++)
  344. abc2svg.alldiv.push(abc2svg.music[i])
  345. visible()
  346. }
  347. abc2svg.get_music = function (d) {
  348. var i, mu
  349. for (var i = 1; i < abc2svg.music.length; i++) {
  350. mu = abc2svg.music[i]
  351. if (mu.d == d)
  352. return mu.t
  353. }
  354. }
  355. abc2svg.set_music = function (d, t) {
  356. var i, mu
  357. for (var i = 1; i < abc2svg.music.length; i++) {
  358. mu = abc2svg.music[i]
  359. if (mu.d == d) {
  360. mu.t = t
  361. abc2svg.musgen(mu)
  362. break
  363. }
  364. }
  365. }
  366. window.addEventListener("load", dom_loaded, { once: true })