Media play/pause toggling without using too many if statements? - javascript

I am creating a playlist of songs for a website that looks like this:
However, I am struggling to figure out the proper way to implement all of the possible case statements that a user may go through while toggling the buttons such as:
toggling one play button on and off
toggling one play button on, and then clicking another play button so that the previous has to toggle off
and so on.
Right now my code (below) works for every case EXCEPT for when a user toggles a play button on and off, and then clicks a different play button. This specific case causes both of the icons to toggle to the pause button instead of just the most recently clicked. I know why this happens, it is because an ID of lastPlayed is left on the old play button, thus triggering the toggle if statment.
My question is, is there an easier way to set up play button toggling that covers all of these cases without having to make a specific if statement for every possible outcome?
Either finding a better solution or fixing my one bug works, but cleaner code is always preferred, thanks for any help!
var playCounter = 0;
function clickSongPlay(artist, title, url, imageURL, element) {
//debugger;
player.playlist.push(
{
title: title,
artist: artist,
file: url,
imageURL: imageURL,
howl: null
}
);
//check to see if we need to resume the song
if ($(element).hasClass("resumeSong") && $(".music-control").hasClass("ion-ios-play")) {
console.log("resuming");
/////////LINE BELOW RESUMES THE TRACK FROM CURRENT POSITION////////
player.play();
$(element).toggleClass("ion-ios-play ion-ios-pause");
$(".resumeSong").removeClass("resumeSong");
return;
}
//if a song is playing and the pause button is clicked, pause the track
if ($(element).hasClass("ion-ios-pause")) {
console.log("pausing");
player.pause();
$(element).toggleClass("ion-ios-pause ion-ios-play");
$(element).addClass("resumeSong");
return;
}
//start playing a new song
if ($(element).hasClass("ion-ios-play") && !$(element).hasClass("resumeSong")) {
if ($("#lastPlayed") && !playCounter == 0) {
console.log("here is a new song");
$("#lastPlayed").toggleClass("ion-ios-pause ion-ios-play")
$(".music-control").removeAttr("id", "lastPlayed");
}
console.log("new song");
///////LINE BELOW LOADS THE NEW SONG//////////////
player.skipTo(player.playlist.length - 1);
$(element).toggleClass("ion-ios-play ion-ios-pause");
$(element).attr("id", "lastPlayed");
playCounter += 1;
return;
}
}
Here is the HTML for a specific song div:
<div><i class="icon ion-ios-play music-control" onclick="clickSongPlay('#song.Artist','#song.Title','#song.URL','#song.Album.ImageURL', this);"></i></div>

Well, as I can see it, there are two problems here.
One, you need to pause any song that is currently playing, whenever an element is clicked. The step that is missing from your code is the position at which we the playing song is advanced so far. I'd record this into a data-offset property of the element itself. So later, we can continue playback from where it left...
Two, find out if the clicked element is on pause or not. If it is - resume, else play from the beginning.
So here is UNTESTED code sample, which might set you on the right track:
function clickSongPlay(artist, title, url, imageURL, element) {
var nowPlaying = $(element).siblings(".ion-ios-pause")
if (nowPlaying) {
player.pause();
nowPlaying.data("offset") = player.seek();
nowPlaying.toggleClass("ion-ios-pause ion-ios-play");
nowPlaying.addClass("resumeSong");
}
player.src(url);
player.seek($(element).data("offset"));
if ($(element).hasClass("resumeSong")) {
console.log("resuming");
$(element).removeData("offset");
$(element).toggleClass("ion-ios-play ion-ios-pause");
$(element).removeClass("resumeSong");
}
player.play();
}

Related

JS Button to toggle youtube embedded video

So I made a toggle button with JS functionality inside elementor plugin. When button clicked for the first time, the embedded video will play. When clicked after that, it'll pause. And when clicked again, it'll play again. And so on. Here's the code I've written:
const vid1 = document.getElementsByClassName("eicon-play")[0];
let santanVid = 'pausing';
document.getElementById("santan-thumb").onclick = () => {
if (santanVid = 'pausing') {
santanVid = 'playing'
} else if (santanVid = 'playing') {
santanVid = 'pausing'
}
if (santanVid = 'pausing') {
vid1.click();
$('.elementor-video')[0].contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}', '*')
} else if (santanVid = 'playing') {
vid1.click()
$('.elementor-video')[0].contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*')
}
};
The problem is, it only worked once. The first time I load the page, click the button and the video will play. Click the button the second time, and the video stop. But if I clicked again, the video won't play
I've tried using 2 button and the code is working, the problem occurs when I'm using 1 button as a toggle, and I'm curious how to make it possible that way.
Thank you before!
In your if statements you are assigning values, not checking. To check use double or triple equal signs (==) or (===)
Example: if(santanVid === 'pausing')

Stop any embeded YouTube iframe when another is played

I am embedding about 10 YouTube iframes in my page, all with their own custom play/pause buttons. I have used this solution to begin http://jsfiddle.net/buuuue/dzroqgj0/ but I'm not sure how to tweak this piece of the code to stop ANY other video that is playing if another one begins...
function stopVideo(player_id) {
if (player_id == "player1") {
player2.stopVideo();
} else if (player_id == "player2") {
player1.stopVideo();
}
}
For example, if player 1 is currently playing, and player 3 is played, I'd want player 1 to stop playing. I've also looked into this solution https://stackoverflow.com/a/38405859/1798756, but I think I need to create the players via JS so that I can also create the custom play/pause buttons.
Thanks in advance for any help!
After creating players push them onto an array.
var vids =[];
player1 = new YT.Player('player1', {
//stuff
});
vids.push(player1);
player2 = new YT.Player('player2', {
// stuff
});
vids.push(player2);
....
..
playerN = new YT.Player('playerN', {
// stuff
});
vids.push(playerN);
Every player object's id can be accessed by its a.id property(a is itself an object , id is a property(string) )
Now when user plays a given player you have to just pause all other except the one being played(id of which you get in stopVideo).Since you have id it's easy
function stopVideo(player_id) {
for(var i=0;i<vids.length;i++){
if (player_id !=vids[i].a.id)
vids[i].stopVideo();
}
}
Example : - http://jsfiddle.net/4t9ah1La/
If you are not creating player through scripts but rather just embedding iframes then this answer mentioned by vbence is enough , below is a demo of that with improvements suggested by Jennie
Example : - http://jsfiddle.net/fyb7fyw1/
All credits to respective original authors

Javascript Sound Start/Stop and Image Change Part2

I want to have a small image that when clicked plays a sound and changes to a different image. When the button is then clicked again it changes back to previous image ans stops the sound.
You can think of it as a button that says "start". when "start" is clicked it loops the sound and changes to "stop" and when "stop" is clicked it goes back to start and the sound ceases playing.
I tried using this code and it works perfectly for the images, but i can not seem to get the different sounds to play for the 2 images.
Javascript Sound Start/Stop and Image Change
I also found seperate code to play and stop sound with this script:
<script>
$(document).ready(function() {
var playing = false;
$('a#button').click(function() {
$(this).toggleClass("down");
if (playing == false) {
document.getElementById('player').play();
playing = true;
$(this).text("stop sound");
} else {
document.getElementById('player').pause();
playing = false;
$(this).text("restart sound");
}
});
});
</script>
<div>
<a id="button">play sound</a>
<audio id="player" src="mysound.mp3" preload="auto"></audio>
Which also works...
Can I combine the 2 together? Or am I not using the first javascript code correctly?
Any help would be much appreciated.
If you want to play a sound and change the image and vice versa, the following would work just fine:
HTML
<p>
<i class="fa fa-play fa-lg" aria-hidden="true"></i>
</p>
<audio id="player" src="http://soundbible.com/mp3/kids-record-player-daniel_simon.mp3" preload="auto"></audio>
JS
var playing = false;
$('#button').click(function() {
if (playing == false) {
document.getElementById('player').play();
playing = true;
$(this).find('i').removeClass('fa-play');
$(this).find('i').addClass('fa-pause');
} else {
document.getElementById('player').pause();
playing = false;
$(this).find('i').removeClass('fa-pause');
$(this).find('i').addClass('fa-play');
}
});
The idea is basically this: If the sound is playing, then swap classes. This example could be expanded to toggling the hide and show of images.
Refer to this working example.
Hope it helps.
EDIT
f I would want to use this for more than one image on the same webpage. Do I just add more add & remove classes? Or do I make a new function for every image?
Actually you can use that function for any number of images. We just need to generalize a few things and we are good to go.
The first thing I did was to change the jQuery selector for the click event. Previously we searched specifically for the element with the unique id #button. In order to bind to multiple buttons, I gave them the same name: $('[name=button]').
The variable playing helped us keep track whether or not the user played the button. In order to control whether or not the button was clicked, I had to move the variable playing to the audio element as an attribute. This way every audio element "knows" its current state (playing or paused);
HTML
<audio name="player" src="http://soundbible.com/mp3/kids-record-player-daniel_simon.mp3" preload="auto" data-playing="false"></audio>
Notice the data-playing="false" attribute
JS
var $button = $(this), // get the button
$player = $button.next('[name=player]'); // button and player are siblings
if ($player.data('playing') == false) {
$player[0].play();
$player.data('playing', true);
...
} else {
$player[0].pause();
$player.data('playing', false);
...
}
The trick here is to update the playing attribute to ensure we know the user clicked play or pause
Please refer to this updated version of the previous example.

changing audio track when a certain dom element enters viewport

Here is a codepen that illustrates changing music depending on what is showing in the viewport:
http://codepen.io/littleredbowtie/pen/epONpM
One song is triggered by an element at the top and a different song is triggered when you scroll to the bottom. However, If you scroll from top to the middle and then back up to the top, the first song starts over. Since it is the SAME DOM element coming into the viewport, I do not want to reset the music. I have tried using a variable to track the most recently viewed trigger , for example:
var oldInview = "";
and only to change the music if it's different. But as you can see from the codepen, it doesn't work. What is a recommended solution?
Rather than wrap your $('p.inview1').bind(...) in an if, add && oldInview !== 'view1' to your if (visible). This makes sure nothing is called again if oldInvew === 'view1' despite the event being fired and detected.
$('p.inview1').on('inview', function (event, visible) {
if (visible && oldInview !== "view1"){
$(this).text('Yay! You can see me1!');
myFunctionT1();
oldInview = "view1";
} else {
$(this).text('Hidden again. Muhahah!');
myFunctionP1();
}
});

SoundJS music clips should toggle each other on/off

I have a bunch of sounds on a page, similar to the sound grid example. Some of these tracks are music tracks and I'd like to treat them differently. Most of the sounds can play over each other and that is the intent, however, no music track should be able to play over another music track. Think radio buttons.
I've got some very woolly code that detects if the other track is playing when clicked and stops the track, and switches that track's css (play icons and such). But now, adding a 3rd or 4th track to the mix becomes unruly.
sounds are loaded and stored in a hash of reusable sound instances that look like:
mySounds["sound1"]= createjs.Sound.createInstance("sound1");
...
when the button in the html is clicked on (I'm not currently using the data-type attribute, that was from an earlier attempt but I thought it might be useful):
<button type="button" class="btn btn-vol btn-sm" data-type="music" data-track="music1" onclick="play(this)">
<span class="glyphicon glyphicon-play bplay"></span></button>
I currently do:
function play(target) {
//define some stuff from html
musicTrack = $(target).attr('data-track');
music1 = $('button[data-track="music1"]');
music2 = $('button[data-track="music2"]');
myInstance = mySounds[id] //id is defined elsewhere
toggle = $(target).find('span.bplay'); //this is where I have the play/pause icons
//For all cases, not just music I find the play icon and swap it.
if(toggle.hasClass('glyphicon-play')){ //the sound is ready to play. if it had a stop icon it would mean it was already playing
toggle.removeClass('glyphicon-play');
toggle.addClass('glyphicon-stop')
//special case for music Tracks
if(musicTrack == "music1") { //If I clicked on music track 1
if(mySounds[musicTrack2].position !=0){ //if it isn't 0, it's playing!
music2.find('span.bplay).removeClass('glyphicon-stop');
music2.find('span.bplay').addClass('glyphicon-play');
mySounds[musicTrack2].stop();
}
else {
//do nothing because track 2 isn't playing
}
} else if (musicTrack=="music2"){ //If I clicked on music track 2
if(mySounds[musicTrack2].position !=0){
music1.find('span.bplay').removeClass('glyphicon-stop');
music1.find('span.bplay').addClass('glyphicon-play');
mySounds[musicTrack1].stop();
}
else {
//do nothing because track 1 isn't playing
}
myInstance.play(); // play the clicked on instance
}
else {
//if the glyphicon does not say play (says stop) then we stop the sound etc..
toggle.removeClass('glyphicon-stop');
toggle.addClass('glyphicon-play');
myInstance.stop();
}
}
I haven't checked the above for syntax as I copied it by hand from my code, keeping only the relevant bits, but all this works. I click on music1, if music 2 isn't playing - it plays. If music 2 is playing, it stops music 2, switches it's stop icon to play and plays music 1. My actual code does some tweening of the sounds before it stops so they crossfade nicely.
I'm not a programmer but I'd love to be able to do this in a more efficient/elegant manner. Surely there is a way!
A better way to do this would be give the music buttons a different click handling function, and using a app / global variable to track the currently playing music. Then use the icon to determine behavior. You'd need to add a way to get the currently playing music, possible another variable. Something like this:
var currentMusic;
function playMusic(target) {
//define some stuff from html
musicTrack = $(target).attr('data-track');
myInstance = mySounds[id]; //id is defined elsewhere
toggle = $(target).find('span.bplay'); //this is where I have the play/pause icons
//For all cases, not just music I find the play icon and swap it.
if(toggle.hasClass('glyphicon-stop')){
toggle.removeClass('glyphicon-stop');
toggle.addClass('glyphicon-play');
currentMusic = null;
myInstance.stop();
}
else {
if(currentMusic) {
// get current instance and call stop
currentMusic.addClass('glyphicon-play');
currentMusic.removeClass('glyphicon-stop');
}
toggle.removeClass('glyphicon-play');
toggle.addClass('glyphicon-stop');
currentMusic = toggle;
myInstance.play();
}
}

Categories

Resources