Search code examples
javascripthtmlcsshtml5-audio

Can't get audio player button to turn off


I have a toggle player here that works without an issue.

https://jsfiddle.net/h4q86s25/

I can't get this one to work using the same code.

In the snippet, when you click on it, the audio plays, the button changes, but only once and doesn't flip back.

How do I get the button to flip back and for the audio to go off?

https://jsfiddle.net/md4a0xyv/

enter image description here

(function iife() {
   "use strict";

   
     function show(el) {
       el.classList.remove("hide");
     }

     function hide(el) {
       el.classList.add("hide");
     }

   function getButtonContainer(el) {
      while (el.classList.contains("playButton") === false) {
         el = el.parentNode;
      }
      return el;
   }

   function hideAllButtons(button) {
     const buttons = button.querySelectorAll(".play, .pause");
     for (let i = 0; i < buttons.length; i++) {
       hide(buttons[i]);
     }
   }

   function getPlay(button) {
      return button.querySelector(".play");
   }

   function getPause(button) {
      return button.querySelector(".pause");
   }

   function showPlayButton(button) {
       const play = getPlay(button);
       hideAllButtons(button);
       show(play);
       button.classList.remove("active");
    }
   function isPlaying(button) {
      const play = getPlay(button);
      return play.classList.contains("active");

   }

   function pauseAllButtons() {
     let buttons = document.querySelectorAll(".playButton");
     for (let i = 0; i < buttons.length; i++) {
       if (isPlaying(buttons[i])) {
             showPlayButton(buttons[i]);
       }
     }
   }

   function showPauseButton(button) {
     const pause = getPause(button);
      pauseAllButtons();
      hideAllButtons(button);
      show(pause);
      button.classList.add("active");
   }

   function getAudio() {
      return document.querySelector("audio");
   }

   function playAudio(player, src) {
      player.volume = 1.0;
      if (player.getAttribute("src") !== src) {
         player.setAttribute("src", src);
      }
      player.play();
   }

   function showButton(button, opts) {
     if (opts.playing) {
         showPlayButton(button);
     } else {
       showPauseButton(button);
     }
   }

   function pauseAudio(player) {
      player.pause();
   }

   function manageAudio(player, opts) {
      if (opts.playing) {
         pauseAudio(player);
      } else {
         playAudio(player, opts.src);
      }
   }

   function togglePlayButton(button) {
      const player = getAudio();
      const playing = isPlaying(button);
      showButton(button, {
        playing
      });
      manageAudio(player, {
         src: button.getAttribute("data-audio"),
         playing
      });
   }

   function playButtonClickHandler(evt) {
      const button = getButtonContainer(evt.target);
      togglePlayButton(button);
   }

   const playButton = document.querySelector(".wrapa");
   playButton.addEventListener("click", playButtonClickHandler);
}());
.wrapa {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  margin: auto;
  background-color: black;
  width: 150px;
  height: 195px;
  box-shadow: 0 0 10px 2px rgba(0, 0, 0, 0.2), 0 0 1px 2px black, inset 0 2px 2px -2px white, inset 0 0 2px 15px #47434c, inset 0 0 2px 22px black;
  border-radius: 5px;
  padding: 20px;
  perspective: 700px;
}

.wrapa.active .play.pause.button {
  transform: translateZ(20px) rotateX(25deg);
  box-shadow: 0 -10px 20px #ff1818;
}

.wrapa.active .play.pause.button .light {
  animation: flicker 0.2s infinite 0.3s;
}

.wrapa.active .play.pause.button .shine {
  opacity: 1;
}

.wrapa.active .play.pause.button .shadow {
  opacity: 0;
}

.wrapa .button {
  transition: all 0.3s cubic-bezier(1, 0, 1, 1);
  transform-origin: center center -20px;
  transform: translateZ(20px) rotateX(-25deg);
  transform-style: preserve-3d;
  background-color: #9b0621;
  width: 100%;
  height: 100%;
  position: relative;
  cursor: pointer;
  background: linear-gradient( #980000 0%, #6f0000 30%, #6f0000 70%, #980000 100%);
  background-repeat: no-repeat;
}

.wrapa .button::before {
  content: "";
  background: linear-gradient( rgba(255, 255, 255, 0.8) 10%, rgba(255, 255, 255, 0.3) 30%, #650000 75%, #320000) 50% 50%/97% 97%, #b10000;
  background-repeat: no-repeat;
  width: 100%;
  height: 50px;
  transform-origin: top;
  transform: rotateX(-90deg);
  position: absolute;
  top: 0;
}

.wrapa .button::after {
  content: "";
  background-image: linear-gradient(#650000, #320000);
  width: 100%;
  height: 50px;
  transform-origin: top;
  transform: translateY(50px) rotateX(-90deg);
  position: absolute;
  bottom: 0;
  box-shadow: 0 50px 8px 0px black, 0 80px 20px 0px rgba(0, 0, 0, 0.5);
}

.wrapa .light {
  opacity: 0;
  animation: light-off 1s;
  position: absolute;
  width: 100%;
  height: 100%;
  background-image: radial-gradient(#ffc97e, #ff1818 40%, transparent 70%);
}

.wrapa .dots {
  position: absolute;
  width: 100%;
  height: 100%;
  background-image: radial-gradient(transparent 30%, rgba(101, 0, 0, 0.7) 70%);
  background-size: 10px 10px;
}

.wrapa .characters {
  position: absolute;
  width: 100%;
  height: 100%;
  background: linear-gradient(white, white) 50% 20%/5% 20%, radial-gradient( circle, transparent 50%, white 52%, white 70%, transparent 72%) 50% 80%/33% 25%;
  background-repeat: no-repeat;
}

.wrapa .shine {
  transition: all 0.3s cubic-bezier(1, 0, 1, 1);
  opacity: 0.3;
  position: absolute;
  width: 100%;
  height: 100%;
  background: linear-gradient(white, transparent 3%) 50% 50%/97% 97%, linear-gradient( rgba(255, 255, 255, 0.5), transparent 50%, transparent 80%, rgba(255, 255, 255, 0.5)) 50% 50%/97% 97%;
  background-repeat: no-repeat;
}

.wrapa .shadow {
  transition: all 0.3s cubic-bezier(1, 0, 1, 1);
  opacity: 1;
  position: absolute;
  width: 100%;
  height: 100%;
  background: linear-gradient(transparent 70%, rgba(0, 0, 0, 0.8));
  background-repeat: no-repeat;
}

@keyframes flicker {
  0% {
    opacity: 1;
  }
  80% {
    opacity: 0.8;
  }
  100% {
    opacity: 1;
  }
}

@keyframes light-off {
  0% {
    opacity: 1;
  }
  80% {
    opacity: 0;
  }
}
<audio></audio>
<div class="playButton wrapa" data-audio="https://getradio.me/svoefm">
   <div class="button play pause">
      <div class="light"></div>
      <div class="dots"></div>
      <div class="characters"></div>
      <div class="shine"></div>
      <div class="shadow"></div>
   </div>
</div>


Solution

  • The error is in your getPause and getPlay functions. You try to find the button with the .play class, but your container contains the active state, not the .play button. If you edit these two functions:

       function getPlay(button) {
          return button;
       }
    
       function getPause(button) {
          return button;
       }
    

    I think it should work as expected.

    EDIT: Second solution (exercise). You could also try to add the active state to the .play button instead of the container. Then you have to modify showPauseButton and showPlayButton.

    Example:

       function showPauseButton(button) {
         const pause = getPause(button);
          pauseAllButtons();
          hideAllButtons(button);
          show(pause);
          // button.classList.add("active");
          pause.classList.add("active");
       }
    

    (function iife() {
       "use strict";
    
       
         function show(el) {
           el.classList.remove("hide");
         }
    
         function hide(el) {
           el.classList.add("hide");
         }
    
       function getButtonContainer(el) {
          while (el.classList.contains("playButton") === false) {
             el = el.parentNode;
          }
          return el;
       }
    
       function hideAllButtons(button) {
         const buttons = button.querySelectorAll(".play, .pause");
         for (let i = 0; i < buttons.length; i++) {
           hide(buttons[i]);
         }
       }
    
       function getPlay(button) {
          return button;
       }
    
       function getPause(button) {
          return button;
       }
    
       function showPlayButton(button) {
           const play = getPlay(button);
           hideAllButtons(button);
           show(play);
           button.classList.remove("active");
        }
       function isPlaying(button) {
          const play = getPlay(button);
          return play.classList.contains("active");
    
       }
    
       function pauseAllButtons() {
         let buttons = document.querySelectorAll(".playButton");
         for (let i = 0; i < buttons.length; i++) {
           if (isPlaying(buttons[i])) {
                 showPlayButton(buttons[i]);
           }
         }
       }
    
       function showPauseButton(button) {
         const pause = getPause(button);
          pauseAllButtons();
          hideAllButtons(button);
          show(pause);
          button.classList.add("active");
       }
    
       function getAudio() {
          return document.querySelector("audio");
       }
    
       function playAudio(player, src) {
          player.volume = 1.0;
          if (player.getAttribute("src") !== src) {
             player.setAttribute("src", src);
          }
          player.play();
       }
    
       function showButton(button, opts) {
         if (opts.playing) {
             showPlayButton(button);
         } else {
           showPauseButton(button);
         }
       }
    
       function pauseAudio(player) {
          player.pause();
       }
    
       function manageAudio(player, opts) {
          if (opts.playing) {
             pauseAudio(player);
          } else {
             playAudio(player, opts.src);
          }
       }
    
       function togglePlayButton(button) {
          const player = getAudio();
          const playing = isPlaying(button);
          showButton(button, {
            playing
          });
          manageAudio(player, {
             src: button.getAttribute("data-audio"),
             playing
          });
       }
    
       function playButtonClickHandler(evt) {
          const button = getButtonContainer(evt.target);
          togglePlayButton(button);
       }
    
       const playButton = document.querySelector(".wrapa");
       playButton.addEventListener("click", playButtonClickHandler);
    }());
    .wrapa {
      position: absolute;
      top: 0;
      left: 0;
      bottom: 0;
      right: 0;
      margin: auto;
      background-color: black;
      width: 150px;
      height: 195px;
      box-shadow: 0 0 10px 2px rgba(0, 0, 0, 0.2), 0 0 1px 2px black, inset 0 2px 2px -2px white, inset 0 0 2px 15px #47434c, inset 0 0 2px 22px black;
      border-radius: 5px;
      padding: 20px;
      perspective: 700px;
    }
    
    .wrapa.active .play.pause.button {
      transform: translateZ(20px) rotateX(25deg);
      box-shadow: 0 -10px 20px #ff1818;
    }
    
    .wrapa.active .play.pause.button .light {
      animation: flicker 0.2s infinite 0.3s;
    }
    
    .wrapa.active .play.pause.button .shine {
      opacity: 1;
    }
    
    .wrapa.active .play.pause.button .shadow {
      opacity: 0;
    }
    
    .wrapa .button {
      transition: all 0.3s cubic-bezier(1, 0, 1, 1);
      transform-origin: center center -20px;
      transform: translateZ(20px) rotateX(-25deg);
      transform-style: preserve-3d;
      background-color: #9b0621;
      width: 100%;
      height: 100%;
      position: relative;
      cursor: pointer;
      background: linear-gradient( #980000 0%, #6f0000 30%, #6f0000 70%, #980000 100%);
      background-repeat: no-repeat;
    }
    
    .wrapa .button::before {
      content: "";
      background: linear-gradient( rgba(255, 255, 255, 0.8) 10%, rgba(255, 255, 255, 0.3) 30%, #650000 75%, #320000) 50% 50%/97% 97%, #b10000;
      background-repeat: no-repeat;
      width: 100%;
      height: 50px;
      transform-origin: top;
      transform: rotateX(-90deg);
      position: absolute;
      top: 0;
    }
    
    .wrapa .button::after {
      content: "";
      background-image: linear-gradient(#650000, #320000);
      width: 100%;
      height: 50px;
      transform-origin: top;
      transform: translateY(50px) rotateX(-90deg);
      position: absolute;
      bottom: 0;
      box-shadow: 0 50px 8px 0px black, 0 80px 20px 0px rgba(0, 0, 0, 0.5);
    }
    
    .wrapa .light {
      opacity: 0;
      animation: light-off 1s;
      position: absolute;
      width: 100%;
      height: 100%;
      background-image: radial-gradient(#ffc97e, #ff1818 40%, transparent 70%);
    }
    
    .wrapa .dots {
      position: absolute;
      width: 100%;
      height: 100%;
      background-image: radial-gradient(transparent 30%, rgba(101, 0, 0, 0.7) 70%);
      background-size: 10px 10px;
    }
    
    .wrapa .characters {
      position: absolute;
      width: 100%;
      height: 100%;
      background: linear-gradient(white, white) 50% 20%/5% 20%, radial-gradient( circle, transparent 50%, white 52%, white 70%, transparent 72%) 50% 80%/33% 25%;
      background-repeat: no-repeat;
    }
    
    .wrapa .shine {
      transition: all 0.3s cubic-bezier(1, 0, 1, 1);
      opacity: 0.3;
      position: absolute;
      width: 100%;
      height: 100%;
      background: linear-gradient(white, transparent 3%) 50% 50%/97% 97%, linear-gradient( rgba(255, 255, 255, 0.5), transparent 50%, transparent 80%, rgba(255, 255, 255, 0.5)) 50% 50%/97% 97%;
      background-repeat: no-repeat;
    }
    
    .wrapa .shadow {
      transition: all 0.3s cubic-bezier(1, 0, 1, 1);
      opacity: 1;
      position: absolute;
      width: 100%;
      height: 100%;
      background: linear-gradient(transparent 70%, rgba(0, 0, 0, 0.8));
      background-repeat: no-repeat;
    }
    
    @keyframes flicker {
      0% {
        opacity: 1;
      }
      80% {
        opacity: 0.8;
      }
      100% {
        opacity: 1;
      }
    }
    
    @keyframes light-off {
      0% {
        opacity: 1;
      }
      80% {
        opacity: 0;
      }
    }
    <audio></audio>
    <div class="playButton wrapa" data-audio="https://getradio.me/svoefm">
       <div class="button play pause">
          <div class="light"></div>
          <div class="dots"></div>
          <div class="characters"></div>
          <div class="shine"></div>
          <div class="shadow"></div>
       </div>
    </div>