diff --git a/js/activity.js b/js/activity.js index 3122474ede..52cf1afd31 100644 --- a/js/activity.js +++ b/js/activity.js @@ -48,6 +48,7 @@ Activity, LEADING, _THIS_IS_MUSIC_BLOCKS_, _THIS_IS_TURTLE_BLOCKS_, globalActivity, hideArrows, doAnalyzeProject */ + const LEADING = 0; const BLOCKSCALES = [1, 1.5, 2, 3, 4]; const _THIS_IS_MUSIC_BLOCKS_ = true; @@ -7719,11 +7720,12 @@ class Activity { }; // Music Block Parser from abc to MB - abcReader.onload = event => { + abcReader.onload = async event => { //get the abc data and replace the / so that the block does not break let abcData = event.target.result; abcData = abcData.replace(/\\/g, ""); + await ensureABCJS(); const tunebook = new ABCJS.parseOnly(abcData); // eslint-disable-next-line no-console console.log(tunebook); @@ -8273,3 +8275,8 @@ define(["domReady!"].concat(MYDEFINES), doc => { }; initialize(); }); + +// Export Activity for Node/Jest tests +if (typeof module !== "undefined" && module.exports) { + module.exports = Activity; +} diff --git a/js/utils/abcLoader.js b/js/utils/abcLoader.js new file mode 100644 index 0000000000..2868f8bff0 --- /dev/null +++ b/js/utils/abcLoader.js @@ -0,0 +1,42 @@ +function ensureABCJS() { + if (typeof window !== "undefined" && window.ABCJS) { + return Promise.resolve(); + } + + if (typeof window === "undefined") { + return Promise.resolve(); + } + + return new Promise((resolve, reject) => { + const existing = document.querySelector('script[src="lib/abc.min.js"]'); + + if (existing) { + if (existing.hasAttribute("data-loaded")) { + resolve(); + } else { + existing.addEventListener("load", resolve); + } + return; + } + + const script = document.createElement("script"); + script.src = "lib/abc.min.js"; + + script.onload = () => { + script.setAttribute("data-loaded", "true"); + resolve(); + }; + + script.onerror = reject; + + document.head.appendChild(script); + }); +} + +if (typeof window !== "undefined") { + window.ensureABCJS = ensureABCJS; +} + +if (typeof module !== "undefined" && module.exports) { + module.exports = ensureABCJS; +} diff --git a/js/widgets/aiwidget.js b/js/widgets/aiwidget.js index b5ab354b7c..99e2feb76b 100644 --- a/js/widgets/aiwidget.js +++ b/js/widgets/aiwidget.js @@ -18,6 +18,7 @@ */ /* exported Abhijeet Singh */ + /** * Represents a AI Widget. * @constructor @@ -28,6 +29,7 @@ function AIWidget() { const SAMPLEHEIGHT = 400; // Don't include natural when construcing the note name... const EXPORTACCIDENTALNAMES = [DOUBLEFLAT, FLAT, "", SHARP, DOUBLESHARP]; + // ...but display it in the selector. const ACCIDENTALNAMES = [DOUBLEFLAT, FLAT, NATURAL, SHARP, DOUBLESHARP]; const SOLFEGENAMES = ["do", "re", "mi", "fa", "sol", "la", "ti", "do"]; @@ -720,7 +722,8 @@ function AIWidget() { * @private * @returns {void} */ - this.__save = function () { + this.__save = async function () { + await ensureABCJS(); const tunebook = new ABCJS.parseOnly(abcNotationSong); tunebook.forEach(tune => { @@ -873,7 +876,8 @@ function AIWidget() { * Plays the reference pitch based on the current sample's pitch, accidental, and octave. * @returns {void} */ - this._playABCSong = function () { + this._playABCSong = async function () { + await window.ensureABCJS(); const abc = abcNotationSong; const stopAudioButton = document.querySelector(".stop-audio");