PDA

View Full Version : icon loses class attribute when swapped



tonybabb
07-08-2015, 11:58 AM
Beverly very kindly helped me create a js script that played a sound file from a list and changed the play/pause icon. This works perfectly and the thread can be seen here http://www.dynamicdrive.com/forums/showthread.php?77798-Customizing-controls-for-the-lt-audio-gt-tag&p=310353&highlight=#post310353 .

I have a small problem that I’ve been unable to fix. Some of the song titles are long and extend over two lines, when I click the play/pause icon the 2nd line of the title appears below the icon and not to the right of the icon. The effect can be seen here www.innocente.us/discography.php (http://www.innocente.us/discography.php)when you click on the play icon beside the song titles that extends over two lines the second line shows below the pause icon.

I think the problem is that when the play icon is clicked it is replaced by the pause icon but the attribute class=”fltlft” is removed and I can’t figure out how to retain it – I tried adding it to the variables playicon and pauseicon and it didn’t work - it fixed the alignment problem but when I clicked the pause icon the sound did not pause. Here's what I tried:


var playIcon = '<img class=”fltlft” src="images/play.png">';
var pauseIcon = '<img class=”fltlft” src="images/pause.png">';

Here’s a sample html (using debugger) showing the play icon before being clicked:

<a href="#">
<img class="fltlft" src="images/play.png"/>


And here’s the html (using debugger)after the play icon is clicked

<a href="#">
<img src="images/pause.png"/>

Notice that the class=”fltlft” is missing.

Here’s the script that swaps the play/ pause icon - without my changes above.

<script>
var ctrl = document.getElementById('audio').getElementsByTagName('a');
for(var i = 0; i < ctrl.length; i++){
ctrl[i].onclick = function(){
var audio = this.nextSibling;
while (audio.nodeType != 1){ audio = audio.nextSibling; }
var playIcon = '<img src="images/play.png">';
var pauseIcon = '<img src="images/pause.png">';
var pause = this.innerHTML === pauseIcon;
this.innerHTML = pause ? playIcon : pauseIcon;
var method = pause ? 'pause' : 'play';
audio[method]();
return false;
}
}
</script>

Thanks for any assistance you can provide.
Tony

Beverleyh
07-08-2015, 01:02 PM
I revised the code in my demo a while back after I noticed that the play/pause toggle lost functionality with img tags. This version uses a <button> element with the image set as a background-image instead. The addition of the "pause" class changes the background-image.

CSS;

#audio button { height:64px; width:64px; margin:0.5em; vertical-align:middle; background:url(play.png) 50% no-repeat; border:0; cursor:pointer }
#audio button.pause { background-image:url(pause.png) }

HTML / JS;

<div id="audio">

<button class="fltlft" title="Play / Pause"></button> Song 1 - Takin' It All
<audio preload="none">
<source src="takin_it_all.mp3" type="audio/mpeg" />
</audio><br/>

<button class="fltlft" title="Play / Pause"></button> Song 2 - Too Close
<audio preload="none">
<source src="too_close.mp3" type="audio/mpeg" />
</audio><br/>

<button class="fltlft" title="Play / Pause"></button> Song 3 - Gettin' Down To Business
<audio preload="none">
<source src="gettin_down_to_business.mp3" type="audio/mpeg" />
</audio><br/>

</div>


<script>
var ctrl = document.getElementById('audio').getElementsByTagName('button');
for(var i = 0; i < ctrl.length; i++){
ctrl[i].addEventListener('click', function(){
var audio = this.nextSibling;
while (audio.nodeType != 1){ audio = audio.nextSibling; }
var pause = this.className === 'pause fltlft';
this.className = pause ? 'fltlft' : 'pause fltlft';
var method = pause ? 'pause' : 'play';
audio[method]();
audio.addEventListener('ended', function(){
this.previousElementSibling.className = 'fltlft';
}, false);
}, false);
}
</script>

tonybabb
07-21-2015, 09:43 AM
Hi Beverley,
Thank you for the reply replacing the img with a button. I tried the code you provided and it worked fine. When I added some of the additional formatting I'm using it stopped working - no sound was played. The first thing I added was just a <br /> in the song title and it failed. The original problem I was trying to solve was when a song with a long title played one line displayed alongside and the other below the play icon. You can see this original behaviour here www.innocente.us/discography.php (http://www.innocente.us/discography.php) when you click Play beside a long title.

So, I set up a test page using the buttons and with fewer songs than the original page and included all the various formatting I'm using. The test page can be seen here www.innocente.us/beverley.php (http://www.innocente.us/beverley.php) . I'm afraid my js skills just aren't up to figuring out what the problem is....sigh.

Here is a sample of a song with a long title - i.e. it extends over two lines.

<button class="fltlft" title="Play / Pause"></button> <span class="songTitle" title="">When The Stone<br />Was Rolled Away</span>
<audio preload="none">
<source src="music/Stone.mp3" type="audio/mpeg" />
</audio>
<div class="clearfloat"></div>
When I tried debugger it said it couldn't apply a method "Play" to an <Audio> object.

If you could point me in the right direction I'd really appreciate it.

Thanks,

Tony

Beverleyh
07-21-2015, 03:23 PM
It comes down to these lines in the script - specifically the part in red;

var audio = this.nextSibling;
while (audio.nodeType != 1){ audio = audio.nextSibling; }"this" is the button element, and "nextSibling" is the audio element - matching the original markup structure where <audio> is the next element after <button>.

Now, with you adding another element between <button> and <audio>, the audio element is no longer nextSibling of the button element, so the original script breaks. But you can adapt it to account for the extra nextSibling (the <span>) - replace the two lines above with these;
var span = this.nextSibling;
while (span.nodeType != 1){ span = span.nextSibling; }
var audio = span.nextSibling;
while (audio.nodeType != 1){ audio = audio.nextSibling; }
It also means that this line won't work either;
this.previousElementSibling.className = 'fltlft';There's another previousElementSibling to account for, so change the line to this;
this.previousElementSibling.previousElementSibling.className = 'fltlft';

This makes the script work with your markup, providing that all your musical notes and song titles maintain this format;
<button class="fltlft" title="Play / Pause"></button> <span class="songTitle" title="">When The Stone<br />Was Rolled Away</span>
<audio preload="none">
<source src="music/Stone.mp3" type="audio/mpeg" />
</audio>The <br/> won't affect the script as its contained within the span.

Beverleyh
07-21-2015, 03:37 PM
Scratch
var audio = this.nextSibling;
while (audio.nodeType != 1){ audio = audio.nextSibling; }
and

var span = this.nextSibling;
while (span.nodeType != 1){ span = span.nextSibling; }
var audio = span.nextSibling;
while (audio.nodeType != 1){ audio = audio.nextSibling; }
nextSibling is to account for older browsers - taken from a script that supports IE7/8 - but since this is an audio script that only needs to support modern browsers and IE9 and above due to native compatibility with the <audio> element, we can use nextElementSibling instead;
var audio = this.nextElementSibling.nextElementSibling;