Forum Discussion

JOJO1's avatar
JOJO1
Community Member
1 month ago

JAVAscript does not work in LMS Moodle

This silde has a Javascript which works in storyline and review360 but doesn't working on the LMS platform Moodle. 
What can i do? 

2 Replies

  • What’s happening probably isn’t GSAP — it’s more likely the SCORM runtime environment.

    When you publish to Moodle, your Storyline content runs inside a SCORM iframe. Storyline dynamically injects the slide DOM at runtime, so code like:

    document.querySelectorAll("[data-acc-text='target']");

    may execute:

    • before the slide objects exist
    • or against the wrong DOM scope
    • or before layers have finished rendering

    In Preview and Review 360 everything loads faster and flatter, so you don’t see the issue.

    In Moodle, the slide content is injected into the #slide-window container inside the SCORM frame — so querying document immediately on timeline start can return an empty NodeList.

    What to Try

    Delay execution slightly:

         setTimeout(function() { // your code here }, 500);

    Scope your selector to the slide window instead of the whole document:

         var slideWindow = document.querySelector("#slide-window"); var targets = slideWindow ?     slideWindow.querySelectorAll("[data-acc-text='target']") : [];

    Open Moodle → F12 → Console
    Add:

    console.log(targets.length);

    If it logs 0, your selector is running before the objects exist.

    Even Better

    Accessibility attributes (data-acc-text) can be fragile across LMS publishing.

    If possible, give the objects unique names and select by ID or custom class instead — that’s more reliable in SCORM environments.

  • Nedim's avatar
    Nedim
    Community Member

    I tested your file on MoodleCloud and the JavaScript works just fine there.

    I don’t have much experience with Moodle LMS, so this is only a guess, but it’s possible that the LMS environment loads or renders SCORM content differently than MoodleCloud, which can impact JavaScript timing.

    Because of this, the behavior may be related to the LMS setup rather than the code itself. To me, it appears to be a timing issue where the Storyline slide content may be loaded or rendered slightly later, causing the JavaScript to run before the elements it depends on are available.

    One possible workaround would be to run the JavaScript after a small delay (for example, when the Storyline timeline reaches around 0.25 seconds), or to use a version of the code that waits until the required elements are present before initializing.

    IMO:

    1. The SCORM player loads
    2. Your JS runs
    3. Storyline has not rendered the slide yet
    4. querySelectorAll(...) returns an empty NodeList
    5. targets.forEach(...) runs on nothing
    6. No listeners → no interaction → code doesn’t work
    7. No error is thrown (an empty NodeList is still a valid object, so calling .forEach on it is completely legal, it just silently does nothing

    Try:

    (function initWhenReady() {
        var targets = document.querySelectorAll("[data-acc-text='target']");
    
        if (!targets.length) {
            setTimeout(initWhenReady, 100);
            return;
        }
    
        let activeTarget = null;
        let inTakeover = false;
    
        function takeover(target) {
            gsap.killTweensOf(targets);
            gsap.set(targets, { opacity: 0 });
            gsap.set(target, { opacity: 1 });
    
            targets.forEach(t => {
                t.style.pointerEvents = (t === target) ? "auto" : "none";
            });
    
            activeTarget = target;
            inTakeover = true;
            GetPlayer().SetVar("isBlinking", false);
        }
    
        function startBlink(target) {
            gsap.killTweensOf(targets);
            gsap.set(targets, { opacity: 1 });
    
            gsap.to(targets, {
                opacity: 0,
                duration: 0.5,
                repeat: -1,
                yoyo: true,
                ease: "power1.inOut"
            });
    
            targets.forEach(t => t.style.pointerEvents = "auto");
    
            activeTarget = target;
            inTakeover = false;
            GetPlayer().SetVar("isBlinking", true);
        }
    
        targets.forEach(target => {
            target.addEventListener('click', () => {
                if (inTakeover && activeTarget === target) {
                    startBlink(target);
                } else if (inTakeover && activeTarget !== target) {
                    return;
                } else {
                    takeover(target);
                }
            });
        });
    })();