Forum Discussion

jliu's avatar
jliu
Community Member
3 months ago

Javascript not working in full screen

Hi all!

I have two Javascript codes that execute when selected: one to copy a claim key, and another to add confetti.

Both seem to work when completed normally, but once I'm in full screen, neither work! Is it because of the Javascript itself?

To recreate the issue:
1. Claim key: if you have something copied, open the Storyline file in full screen, select the "Copy Claim Key" button, and paste in the text field below. If in full screen, it will paste your previous selection instead of the key (which is "S8AM83B2QDBBKKF89K3K")!

The code used for this is below, using a "ClaimKey" variable already set in the Storyline file: 

var player = GetPlayer();
var text = player.GetVar("ClaimKey");
copyFunction (text);

function copyFunction(tt) {
  
  const copyText = tt;
  const textArea = document.createElement('textarea');
  textArea.textContent = copyText;
  document.body.append(textArea);
  textArea.select();
  document.execCommand("copy");
  textArea.style.display = "none";
}



2. Confetti: if you select the "Add Confetti" button, the confetti will appear on the page normally. If you select full screen and the "Add Confetti" button again, exit full screen early to see the last instances of confetti that don't show up in full screen.

Two Javascript codes were used for confetti:

var duration = 5 * 1000;
var animationEnd = Date.now() + duration;
var defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: 0 };
function randomInRange(min, max) {
  return Math.random() * (max - min) + min;
}
var interval = setInterval(function() {
  var timeLeft = animationEnd - Date.now();
  if (timeLeft <= 0) {
    return clearInterval(interval);
  }
  var particleCount = 50 * (timeLeft / duration);
  // since particles fall down, start a bit higher than random
  confetti(Object.assign({}, defaults, { particleCount, origin: { x: randomInRange(0.1, 0.3), y: Math.random() - 0.2 } }));
  confetti(Object.assign({}, defaults, { particleCount, origin: { x: randomInRange(0.7, 0.9), y: Math.random() - 0.2 } }));
}, 250);
var confettiScript = document.createElement('script');
confettiScript.setAttribute('src','https://cdn.jsdelivr.net/npm/canvas-confetti@1.5.1/dist/confetti.browser.min.js');
document.head.appendChild(confettiScript);

*The second code is a workaround I used from this Little Man Project post to avoid updating the HTML file each time I publish :) 

 

I'm a JavaScript beginner, so any help is appreciated! You can preview the issue here in Review, and I've attached the file for reference. Thanks!

  • Hi jliu

    1. Claim Key

    The issue here is displayed in the browser console when going full screen- Blocked aria-hidden on a <div> element because the element that just received focus must not be hidden from assistive technology users.

    Therefore I think you would achieve the result you need far simpler using the Clipboard API, which is actually built directly into vanilla JS! Try this:

    var text = getVar("ClaimKey");
    copyFunction(text);
    
    function copyFunction(tt) {
      navigator.clipboard.writeText(tt)
        .then(() => {
          console.log('Text copied to clipboard');
        })
        .catch(err => {
          console.error('Failed to copy text: ', err);
        });
    }

    (The GetPlayer method isn't actually needed anymore as long as you are working with the latest SL360 version.)

    2. Confetti

    Unfortunately I don't think the original post implemented this script particularly well, as in their version they don't seem to have created the canvas element that the confetti object would need to display on top of. (I guess it's trying to draw the object in another part of the HTML document which when you switch to full screen is getting it confused.)

    The way I would approach this would be to draw a background rectangle shape onto your slide, give it an Alt Text value in the Accessibility options, and target the shape that way in your JS. Something like this:

    (async () => {
      var slidearea = document.querySelector('[data-acc-text*="background"]');
    
      // We'll attempt to retrieve the existing canvas first if it exists
      var canvas = document.getElementById('confetti-canvas');
    
      if (!canvas) {
        // If not, let's create it...
        canvas = document.createElement('canvas');
        canvas.id = 'confetti-canvas';
        canvas.style.width = '100%';
        canvas.style.height = '100%';
        canvas.style.position = 'absolute';
        canvas.style.top = '0';
        canvas.style.left = '0';
    
        slidearea.appendChild(canvas);
    
        function resizeCanvas() {
          canvas.width = canvas.offsetWidth;
          canvas.height = canvas.offsetHeight;
        }
    
        // We should also listen for browser resize events to adjust the canvas size...
        window.addEventListener('resize', resizeCanvas);
        resizeCanvas(); // Set initial size
      }
    
      canvas.confetti = canvas.confetti || (await confetti.create(canvas, { resize: true }));
    
      // Your existing particle effect settings...
      var duration = 5 * 1000;
      var animationEnd = Date.now() + duration;
      var defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: 0 };
    
      function randomInRange(min, max) {
        return Math.random() * (max - min) + min;
      }
    
      var interval = setInterval(function() {
        var timeLeft = animationEnd - Date.now();
        if (timeLeft <= 0) {
          return clearInterval(interval);
        }
        var particleCount = 50 * (timeLeft / duration);
        // since particles fall down, start a bit higher than random
        canvas.confetti(Object.assign({}, defaults, { particleCount, origin: { x: randomInRange(0.1, 0.3), y: Math.random() - 0.2 } }));
        canvas.confetti(Object.assign({}, defaults, { particleCount, origin: { x: randomInRange(0.7, 0.9), y: Math.random() - 0.2 } }));
      }, 250);
    })();

    (In Storyline you're also running the script to attach the JS library to the document every time the user clicks the button. This should only be ran once, so I recommend changing the Execute JS trigger for this to activate when the Timeline Starts rather than when the button is clicked.)

    Hope that helps, good luck with your project! Chris

  • ChrisHodgson's avatar
    ChrisHodgson
    Community Member

    Hi jliu

    1. Claim Key

    The issue here is displayed in the browser console when going full screen- Blocked aria-hidden on a <div> element because the element that just received focus must not be hidden from assistive technology users.

    Therefore I think you would achieve the result you need far simpler using the Clipboard API, which is actually built directly into vanilla JS! Try this:

    var text = getVar("ClaimKey");
    copyFunction(text);
    
    function copyFunction(tt) {
      navigator.clipboard.writeText(tt)
        .then(() => {
          console.log('Text copied to clipboard');
        })
        .catch(err => {
          console.error('Failed to copy text: ', err);
        });
    }

    (The GetPlayer method isn't actually needed anymore as long as you are working with the latest SL360 version.)

    2. Confetti

    Unfortunately I don't think the original post implemented this script particularly well, as in their version they don't seem to have created the canvas element that the confetti object would need to display on top of. (I guess it's trying to draw the object in another part of the HTML document which when you switch to full screen is getting it confused.)

    The way I would approach this would be to draw a background rectangle shape onto your slide, give it an Alt Text value in the Accessibility options, and target the shape that way in your JS. Something like this:

    (async () => {
      var slidearea = document.querySelector('[data-acc-text*="background"]');
    
      // We'll attempt to retrieve the existing canvas first if it exists
      var canvas = document.getElementById('confetti-canvas');
    
      if (!canvas) {
        // If not, let's create it...
        canvas = document.createElement('canvas');
        canvas.id = 'confetti-canvas';
        canvas.style.width = '100%';
        canvas.style.height = '100%';
        canvas.style.position = 'absolute';
        canvas.style.top = '0';
        canvas.style.left = '0';
    
        slidearea.appendChild(canvas);
    
        function resizeCanvas() {
          canvas.width = canvas.offsetWidth;
          canvas.height = canvas.offsetHeight;
        }
    
        // We should also listen for browser resize events to adjust the canvas size...
        window.addEventListener('resize', resizeCanvas);
        resizeCanvas(); // Set initial size
      }
    
      canvas.confetti = canvas.confetti || (await confetti.create(canvas, { resize: true }));
    
      // Your existing particle effect settings...
      var duration = 5 * 1000;
      var animationEnd = Date.now() + duration;
      var defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: 0 };
    
      function randomInRange(min, max) {
        return Math.random() * (max - min) + min;
      }
    
      var interval = setInterval(function() {
        var timeLeft = animationEnd - Date.now();
        if (timeLeft <= 0) {
          return clearInterval(interval);
        }
        var particleCount = 50 * (timeLeft / duration);
        // since particles fall down, start a bit higher than random
        canvas.confetti(Object.assign({}, defaults, { particleCount, origin: { x: randomInRange(0.1, 0.3), y: Math.random() - 0.2 } }));
        canvas.confetti(Object.assign({}, defaults, { particleCount, origin: { x: randomInRange(0.7, 0.9), y: Math.random() - 0.2 } }));
      }, 250);
    })();

    (In Storyline you're also running the script to attach the JS library to the document every time the user clicks the button. This should only be ran once, so I recommend changing the Execute JS trigger for this to activate when the Timeline Starts rather than when the button is clicked.)

    Hope that helps, good luck with your project! Chris

    • jliu's avatar
      jliu
      Community Member

      Thanks ChrisHodgson ! I published your edited file to preview changes; the confetti seems to work in your project file, which is great 🎉

      One remaining question is that the claim key now doesn't seem to work at all? I've checked the variable to confirm that it's the same name in the file, but would there be any other reason why I can't copy the key using this code for Execute JavaScript?

      • ChrisHodgson's avatar
        ChrisHodgson
        Community Member

        That appears to be an issue with Review360 blocking the Clipboard API function for whatever reason, not with the actual script itself.

        Try previewing the project in Storyline, or publish elsewhere e.g. onto your own LMS.