curriculum/challenges/english/blocks/workshop-music-player/67516e888477083c31614dc7.md
If you check closely, you'd see the currently playing song is not highlighted in the playlist, so you don't really know which song is playing. You can fix this by creating a function to highlight any song that is being played.
Create a function named highlightCurrentSong. Inside the function, check that a .playlist-song element with aria-current="true" exists. If so, use the removeAttribute method to remove the aria-current attribute from it.
You should have a function named highlightCurrentSong.
assert.isFunction(highlightCurrentSong)
Your highlightCurrentSong function should use the removeAttribute method to remove the aria-current attribute from the .playlist-song element with aria-current="true" if that element exists.
const songs = document.querySelectorAll(".playlist-song");
songs.forEach(song => {song.removeAttribute("aria-current")});
assert.doesNotThrow(highlightCurrentSong);
songs[3].setAttribute("aria-current", "true");
highlightCurrentSong();
songs.forEach(song => {assert.isNull(song.getAttribute("aria-current"))});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css2?family=Lato&family=Roboto+Mono&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="styles.css" />
<title>
Build a Music Player App
</title>
</head>
<body>
<div class="container">
<div class="player">
<div class="player-bar">
<div class="parallel-lines">
<div></div>
<div></div>
</div>
<h1 class="fcc-title">freeCodeCamp</h1>
<div class="parallel-lines">
<div></div>
<div></div>
</div>
</div>
<div class="player-content">
<div id="player-album-art">
</div>
<div class="player-display">
<div class="player-display-song-artist">
<p id="player-song-title"></p>
<p id="player-song-artist"></p>
</div>
<div class="player-buttons">
<button id="previous" class="previous" aria-label="Previous">
<svg width="24" height="19" viewBox="0 0 24 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M23.2248 0L7.03964 9.5L23.2248 19L23.2248 0Z" />
<rect width="4.63633" height="18.5453" transform="matrix(-1 0 0 1 4.63633 0)" />
</svg>
</button>
<button id="play" class="play" aria-label="Play">
<svg width="17" height="19" viewBox="0 0 17 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0L16.1852 9.5L1.88952e-07 19L0 0Z" />
</svg>
</button>
<button id="pause" class="pause" aria-label="Pause">
<svg width="17" height="19" viewBox="0 0 17 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 6.54013e-07H4.75V19H0V6.54013e-07Z" />
<path d="M11.4 0H16.15V19H11.4V0Z" />
</svg>
</button>
<button id="next" class="next" aria-label="Next">
<svg width="24" height="19" viewBox="0 0 24 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0L16.1852 9.5L1.88952e-07 19L0 0Z" />
<rect x="18.5885" width="4.63633" height="18.5453" />
</svg>
</button>
</div>
</div>
</div>
</div>
<div class="playlist">
<div class="playlist-bar">
<div class="parallel-lines">
<div></div>
<div></div>
</div>
<h2 class="playlist-title" id="playlist">Playlist</h2>
<div class="parallel-lines">
<div></div>
<div></div>
</div>
</div>
<ul id="playlist-songs">
<li id="song-0" class="playlist-song">
<button class="playlist-song-info" >
<span class="playlist-song-title">Scratching The Surface</span>
<span class="playlist-song-artist">Quincy Larson</span>
<span class="playlist-song-duration">4:25</span>
</button>
</li>
<li id="song-1" class="playlist-song">
<button class="playlist-song-info" >
<span class="playlist-song-title">Can't Stay Down</span>
<span class="playlist-song-artist">Quincy Larson</span>
<span class="playlist-song-duration">4:15</span>
</button>
</li>
<li id="song-2" class="playlist-song">
<button class="playlist-song-info" >
<span class="playlist-song-title">Still Learning</span>
<span class="playlist-song-artist">Quincy Larson</span>
<span class="playlist-song-duration">3:51</span>
</button>
</li>
<li id="song-3" class="playlist-song">
<button class="playlist-song-info" >
<span class="playlist-song-title">Cruising for a Musing</span>
<span class="playlist-song-artist">Quincy Larson</span>
<span class="playlist-song-duration">3:34</span>
</button>
</li>
<li id="song-4" class="playlist-song">
<button class="playlist-song-info" >
<span class="playlist-song-title">Never Not Favored</span>
<span class="playlist-song-artist">Quincy Larson</span>
<span class="playlist-song-duration">3:35</span>
</button>
</li>
<li id="song-5" class="playlist-song">
<button class="playlist-song-info" >
<span class="playlist-song-title">From the Ground Up</span>
<span class="playlist-song-artist">Quincy Larson</span>
<span class="playlist-song-duration">3:12</span>
</button>
</li>
<li id="song-6" class="playlist-song">
<button class="playlist-song-info" >
<span class="playlist-song-title">Walking on Air</span>
<span class="playlist-song-artist">Quincy Larson</span>
<span class="playlist-song-duration">3:25</span>
</button>
</li>
<li id="song-7" class="playlist-song">
<button class="playlist-song-info" >
<span class="playlist-song-title">Can't Stop Me. Can't Even Slow Me Down.</span>
<span class="playlist-song-artist">Quincy Larson</span>
<span class="playlist-song-duration">3:52</span>
</button>
</li>
<li id="song-8" class="playlist-song">
<button class="playlist-song-info" >
<span class="playlist-song-title">The Surest Way Out is Through</span>
<span class="playlist-song-artist">Quincy Larson</span>
<span class="playlist-song-duration">3:10</span>
</button>
</li>
<li id="song-9" class="playlist-song">
<button class="playlist-song-info" >
<span class="playlist-song-title">Chasing That Feeling</span>
<span class="playlist-song-artist">Quincy Larson</span>
<span class="playlist-song-duration">2:43</span>
</button>
</li>
</ul>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
:root {
/* colors */
--primary-color: #dfdfe2;
--secondary-color: #ffffff;
--app-background-color: #4d4d62;
--background-color: #1b1b32;
--foreground-color: #3b3b4f;
--highlight-color: #f1be32;
/* font sizes */
--root-font-size: 16px;
font-size: var(--root-font-size);
/* font-families */
--font-headline: "Roboto Mono", monospace;
--font-family: "Lato", sans-serif;
}
*,
*::after,
*::before {
box-sizing: border-box;
}
body {
background-color: var(--app-background-color);
color: var(--primary-color);
font-family: var(--font-family);
}
h1 {
font-size: 1.125rem;
line-height: 1.6;
}
h2 {
font-size: var(--root-font-size);
}
ul {
margin: 0;
}
.container {
margin-top: 10px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
row-gap: 5px;
}
.player,
.playlist {
width: 450px;
background-color: var(--background-color);
border: 3px solid var(--foreground-color);
}
.player {
height: 260px;
padding: 10px;
display: flex;
flex-direction: column;
align-items: center;
row-gap: 10px;
}
.player-bar,
.playlist-bar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 5px;
width: 100%;
height: 30px;
background-color: var(--foreground-color);
}
.parallel-lines {
display: flex;
flex-wrap: wrap;
row-gap: 6px;
padding: 0 5px;
}
.parallel-lines > div {
height: 2px;
width: 100%;
min-width: 75px;
background-color: var(--highlight-color);
}
.fcc-title,
.playlist-title {
color: var(--secondary-color);
margin: 0 10px;
font-family: var(--font-headline);
}
.player-content {
display: flex;
background-color: var(--foreground-color);
width: 430px;
height: 200px;
column-gap: 13px;
align-items: center;
justify-content: center;
}
#player-album-art {
background-color: var(--secondary-color);
border: 6px solid var(--background-color);
}
#player-album-art img {
width: 150px;
display: block;
}
.player-display {
display: flex;
flex-direction: column;
row-gap: 20px;
padding: 14px;
background-color: var(--background-color);
height: 153px;
width: 226px;
}
.player-display-song-artist {
height: 80px;
}
.player-buttons svg {
fill: var(--primary-color);
}
.playing > svg {
fill: var(--highlight-color);
}
.player-buttons {
display: flex;
justify-content: space-around;
}
button {
background: transparent;
border: none;
color: var(--primary-color);
cursor: pointer;
font-size: var(--root-font-size);
outline-color: var(--highlight-color);
text-align: center;
}
.playlist-song {
outline-color: var(--highlight-color);
}
.playlist li:not(:last-child) {
border-bottom: 1px solid var(--background-color);
}
button:focus,
.playlist-song:focus {
outline-style: dashed;
outline-width: 2px;
}
/* Playlist */
.playlist {
height: auto;
padding: 10px;
display: flex;
flex-direction: column;
align-items: center;
row-gap: 10px;
}
#playlist-songs {
width: 430px;
height: 100%;
background-color: var(--foreground-color);
display: flex;
flex-direction: column;
row-gap: 8px;
padding: 8px 9px;
visibility: visible;
justify-content: start;
list-style: none;
}
.playlist-song {
display: flex;
height: 55px;
justify-content: space-between;
align-items: center;
padding: 5px;
}
[aria-current="true"] {
background-color: var(--background-color);
}
[aria-current="true"] p {
color: var(--highlight-color);
}
.playlist-song-info {
height: 100%;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-around;
column-gap: 7px;
padding: 5px 0;
font-family: var(--font-family);
}
#player-song-title,
#player-song-artist {
margin: 0;
}
#player-song-artist {
color: var(--highlight-color);
font-size: 0.75rem;
}
#player-song-title {
font-size: 1.125rem;
}
.playlist-song-title {
font-size: 0.85rem;
width: 241px;
text-align: left;
}
.playlist-song-artist {
font-size: 0.725rem;
width: 80px;
}
.playlist-song-duration {
font-size: 0.725rem;
margin: auto;
font-family: var(--font-headline);
width: 30px;
}
.playlist-song-delete {
padding: 0;
width: 20px;
height: 20px;
}
.playlist-song-delete,
.playlist-song-delete {
fill: var(--foreground-color);
}
.playlist-song-delete:hover circle,
.playlist-song-delete:focus circle {
fill: #ff0000;
}
@media (max-width: 700px) {
.player,
.playlist {
width: 300px;
}
.player {
height: 340px;
}
#playlist-songs {
height: 280px;
padding: 5px 6px;
overflow-y: scroll;
overflow-x: hidden;
scrollbar-color: var(--background-color) var(--secondary-color);
scrollbar-width: thin;
}
#playlist-songs::-webkit-scrollbar {
width: 5px;
}
#playlist-songs::-webkit-scrollbar-track {
background: var(--background-color);
}
#playlist-songs::-webkit-scrollbar-thumb {
background: var(--secondary-color);
}
h1 {
font-size: 0.813rem;
}
h2 {
font-size: 0.75rem;
}
.player-bar,
.playlist-bar,
.player-content,
#playlist-songs {
width: 280px;
}
.playlist-song {
justify-content: space-between;
}
.playlist-song-title {
width: 140px;
}
.playlist-song-artist {
width: 40px;
}
.playlist-song-duration > button {
padding: 0;
}
.player-content {
display: inline;
position: relative;
justify-items: center;
height: 100%;
}
#player-album-art {
z-index: -100;
height: 280px;
box-shadow: none;
background: #000;
}
#player-album-art img {
width: 100%;
opacity: 0.6;
}
.player-display-song-artist {
padding: 0 10px;
}
.player-display-song-artist > p {
white-space: pre-wrap;
}
.player-display {
position: absolute;
width: 100%;
z-index: 1000;
background-color: transparent;
top: 0;
height: 280px;
justify-content: space-between;
text-align: center;
}
}
const playlistSongs = document.getElementById("playlist-songs");
const playButton = document.getElementById("play");
const pauseButton = document.getElementById("pause");
const nextButton = document.getElementById("next");
const previousButton = document.getElementById("previous");
const allSongs = [
{
id: 0,
title: "Scratching The Surface",
artist: "Quincy Larson",
duration: "4:25",
src: "https://cdn.freecodecamp.org/curriculum/js-music-player/scratching-the-surface.mp3",
},
{
id: 1,
title: "Can't Stay Down",
artist: "Quincy Larson",
duration: "4:15",
src: "https://cdn.freecodecamp.org/curriculum/js-music-player/can't-stay-down.mp3",
},
{
id: 2,
title: "Still Learning",
artist: "Quincy Larson",
duration: "3:51",
src: "https://cdn.freecodecamp.org/curriculum/js-music-player/still-learning.mp3",
},
{
id: 3,
title: "Cruising for a Musing",
artist: "Quincy Larson",
duration: "3:34",
src: "https://cdn.freecodecamp.org/curriculum/js-music-player/cruising-for-a-musing.mp3",
},
{
id: 4,
title: "Never Not Favored",
artist: "Quincy Larson",
duration: "3:35",
src: "https://cdn.freecodecamp.org/curriculum/js-music-player/never-not-favored.mp3",
},
{
id: 5,
title: "From the Ground Up",
artist: "Quincy Larson",
duration: "3:12",
src: "https://cdn.freecodecamp.org/curriculum/js-music-player/from-the-ground-up.mp3",
},
{
id: 6,
title: "Walking on Air",
artist: "Quincy Larson",
duration: "3:25",
src: "https://cdn.freecodecamp.org/curriculum/js-music-player/walking-on-air.mp3",
},
{
id: 7,
title: "Can't Stop Me. Can't Even Slow Me Down.",
artist: "Quincy Larson",
duration: "3:52",
src: "https://cdn.freecodecamp.org/curriculum/js-music-player/cant-stop-me-cant-even-slow-me-down.mp3",
},
{
id: 8,
title: "The Surest Way Out is Through",
artist: "Quincy Larson",
duration: "3:10",
src: "https://cdn.freecodecamp.org/curriculum/js-music-player/the-surest-way-out-is-through.mp3",
},
{
id: 9,
title: "Chasing That Feeling",
artist: "Quincy Larson",
duration: "2:43",
src: "https://cdn.freecodecamp.org/curriculum/js-music-player/chasing-that-feeling.mp3",
},
];
const audio = new Audio();
const userData = {
songs: allSongs,
currentSong: null,
songCurrentTime: 0,
}
const playSong = (id, start=true) => {
const song = userData.songs.find((song) => song.id === id);
audio.src = song.src;
audio.title = song.title;
if (userData.currentSong === null || start) {
audio.currentTime = 0
} else {
audio.currentTime = userData.songCurrentTime;
}
userData.currentSong = song;
playButton.classList.add("playing");
audio.play()
}
const pauseSong = () => {
userData.songCurrentTime = audio.currentTime;
playButton.classList.remove("playing");
audio.pause();
}
const getCurrentSongIndex = () => userData.songs.indexOf(userData.currentSong);
const getNextSong = () => userData.songs[getCurrentSongIndex() + 1];
const getPreviousSong = () => userData.songs[getCurrentSongIndex() - 1];
const playPreviousSong = () => {
if (userData.currentSong === null) return;
const previousSong = getPreviousSong();
if (previousSong) {
playSong(previousSong.id);
} else {
playSong(userData.songs[0].id);
}
};
const playNextSong = () => {
if (userData.currentSong === null) {
playSong(userData.songs[0].id);
return
}
const nextSong = getNextSong();
if (nextSong) {
playSong(nextSong.id);
} else {
userData.currentSong = null;
userData.songCurrentTime = 0;
pauseSong();
}
}
--fcc-editable-region--
--fcc-editable-region--
playButton.addEventListener("click", () => {
if (userData.currentSong === null) {
playSong(userData.songs[0].id);
} else {
playSong(userData.currentSong.id, false);
}
});
const songs = document.querySelectorAll(".playlist-song");
songs.forEach((song) => {
const id = song.getAttribute("id").slice(5);
const songBtn = song.querySelector("button");
songBtn.addEventListener("click", () => {
playSong(Number(id));
})
})
pauseButton.addEventListener("click", pauseSong);
nextButton.addEventListener("click", playNextSong);
previousButton.addEventListener("click", playPreviousSong);