Template Literal Function not working as expected - javascript

I have a function that turns an array into modal window links as a template literal.
The code that creates the links works fine outside of the function
But once it gets rendered in the function it no longer works. I can't find any errors, but it does NOT work.
However, if I copy the HTML that the function renders and save that as actual HTML, that works fine on its own.
A good chunk of the JavaScript portion of the code is posted below. A full version is on Codepen.
There are two sections in the example on Codepen:
The first section has the code as it's rendered by the function.
The second section is copied from the Elements tab in Developer Tools and saved as actual HTML.
"use strict";
const modalBtns = document.querySelectorAll(".modal-button");
const modalWin = document.querySelector(".modal-window");
const closeBtn = document.querySelector(".close-modal");
const modal_iframe = document.getElementById("modal_iframe");
modalBtns.forEach((item) => {
item.addEventListener("click", function (e) {
let modal = e.currentTarget;
if (modal.dataset.target) {
let modalID = modal.dataset.target;
document.getElementById(modalID).style.display = "block";
}
if (modal.dataset.iframe) {
modal_iframe.src = modal.dataset.iframe;
document
.querySelector(".button-footer")
.addEventListener("click", function () {
window.open(modal.dataset.iframe, "_blank");
});
}
if (modal.dataset.header) {
document.querySelector(
".modal-header"
).innerHTML = `<h1>${modal.dataset.header}</h1>`;
}
if (modal.dataset.dimensions) {
document
.querySelector(".modal-window")
.setAttribute("style", modal.dataset.dimensions);
}
function loadIframe() {
let frame = document.getElementById("modal_window");
frame.style.height =
frame.contentWindow.document.body.scrollHeight + "px";
}
if (document.querySelector("#modal_window")) {
setTimeout(function () {
loadIframe;
}, 2000);
}
if (modal.dataset.reload && modal.dataset.reload === "1") {
document
.querySelector(".close-modal")
.addEventListener("click", function (e) {
console.log("parent.location.reload() pending...");
parent.location.reload();
});
}
/*======= All EventListeners Below Close Modal ================*/
closeBtn.addEventListener("click", function (e) {
document.querySelector(".modal-background").style.display = "none";
});
window.addEventListener("click", function (e) {
if (e.currentTarget === document.querySelector(".modal-background")) {
document.querySelector(".modal-background").style.display = "none";
}
});
document.body.addEventListener("keydown", (e) => {
if (e.key === "Escape") {
document.querySelector(".modal-background").style.display = "none";
}
});
});
});
const main = document.querySelector("main");
const modal_links = [
{
link: "https://notation.netcentrx.net/staff/",
header: "Musical Staff",
thb: "notation",
w_h: "min-width:60vw;max-width:600px;height:650px",
reload: 0
},
{
link: "https://wsl.netcentrx.net/",
header: "WSL Commands",
thb: "wsl",
w_h: "min-width:60vw;max-width:600px;height:650px",
reload: 0
}
];
let modalLink = "";
function createModalLinks(
link,
modalID,
header,
img,
w_h = "width:90vw;height:600px",
reload = "0"
) {
modalLink = `
<a href="javascript:void(0)" class="modal-button" onclick="console.log('onclick handler:${link}');" data-header="${header}" data-target="${modalID}" data-iframe="${link}" data-dimensions="${w_h};margin-top:20px" data-reload="${reload}">
<img src="https://resume.netcentrx.net/examples/${img}.jpg" title="${img}" width="50">
</a>
`;
return modalLink;
}
let theLinks = "";
modal_links.forEach((item) => {
theLinks += createModalLinks(
item.link,
"modal_window",
item.header,
item.thb,
item.w_h,
item.reload
);
});
main.innerHTML = theLinks;
My apologies in advance for it not being stripped down to just the bare minimum. But in order to replicate the problem, it required more code than it probably should have had. I've been reworking this for the better part of a day without any insight as to what the real problem is. I've been creating functions using template literals just like this for years now, usually with a high success rate. Whatever the problem is, I need to know so I can get past it. The only anomaly that I spotted is that–in the version on Codepen–the only thing that doesn't work in that version is once the modal is displayed clicking on the background does not dismiss the modal like it does elsewhere. If that's significant as to what the problem may be, I'm not sure what the connection is.
Usually when I take the time to painstakingly write everything out like this I typically either spot the problem or figure out an alternative solution so there's no need to actually post a question, but this does not appear to be one of those times. As always, your help is very much appreciated!

The issue appears to just be timing. Your code is executed in order, and the first part gets all of the modal buttons on the page and sets the appropriate event listeners. Then the second part of your code adds 2 modal buttons, which were not present earlier.
By simply wrapping the first part of your code in a function and calling it later (or swapping the order of those two parts of code), everything works as expected.
"use strict";
const _InitModal = () => {
const modalBtns = document.querySelectorAll(".modal-button");
const modalWin = document.querySelector(".modal-window");
const closeBtn = document.querySelector(".close-modal");
const modal_iframe = document.getElementById("modal_iframe");
modalBtns.forEach((item) => {
item.addEventListener("click", function (e) {
console.log("e.currentTarget = " + e.currentTarget);
let modal = e.currentTarget;
console.log("modal = " + modal);
if (modal.dataset.target) {
let modalID = modal.dataset.target;
console.log("modal.dataset.target = " + modal.dataset.target);
document.getElementById(modalID).style.display = "block";
}
if (modal.dataset.iframe) {
modal_iframe.src = modal.dataset.iframe;
document
.querySelector(".button-footer")
.addEventListener("click", function () {
window.open(modal.dataset.iframe, "_blank");
});
}
if (modal.dataset.header) {
document.querySelector(
".modal-header"
).innerHTML = `<h1>${modal.dataset.header}</h1>`;
console.log(`modal.dataset.header = ${modal.dataset.header}`);
}
if (modal.dataset.dimensions) {
document
.querySelector(".modal-window")
.setAttribute("style", modal.dataset.dimensions);
}
function loadIframe() {
let frame = document.getElementById("modal_window");
frame.style.height =
frame.contentWindow.document.body.scrollHeight + "px";
}
if (document.querySelector("#modal_window")) {
setTimeout(function () {
loadIframe;
}, 2000);
}
// e.preventDefault();
if (modal.dataset.reload && modal.dataset.reload === "1") {
document
.querySelector(".close-modal")
.addEventListener("click", function (e) {
console.log("parent.location.reload() pending...");
parent.location.reload();
});
}
/*======= All EventListeners Below Close Modal ================*/
closeBtn.addEventListener("click", function (e) {
document.querySelector(".modal-background").style.display = "none";
});
window.addEventListener("click", function (e) {
console.log("e.currentTarget = " + e.currentTarget);
if (e.currentTarget === document.querySelector(".modal-background")) {
document.querySelector(".modal-background").style.display = "none";
}
});
document.body.addEventListener("keydown", (e) => {
if (e.key === "Escape") {
console.log("e=" + e);
document.querySelector(".modal-background").style.display = "none";
}
});
});
});
}
const main = document.querySelector("main");
const modal_links = [
{
link: "https://notation.netcentrx.net/staff/",
header: "Musical Staff",
thb: "notation",
w_h: "min-width:60vw;max-width:600px;height:650px",
reload: 0
},
{
link: "https://wsl.netcentrx.net/",
header: "WSL Commands",
thb: "wsl",
w_h: "min-width:60vw;max-width:600px;height:650px",
reload: 0
}
];
function createModalLinks(
link,
modalID,
header,
img,
w_h = "width:90vw;height:600px",
reload = "0"
) {
let modalLink = "";
modalLink = `
<a href="javascript:void(0)" class="modal-button" onclick="console.log('onclick handler:${link}');" data-header="${header}" data-target="${modalID}" data-iframe="${link}" data-dimensions="${w_h};margin-top:20px" data-reload="${reload}">
<img src="https://resume.netcentrx.net/examples/${img}.jpg" title="${img}" width="50">
</a>`;
return modalLink;
}
let theLinks = "";
modal_links.forEach((item) => {
theLinks += createModalLinks(
item.link,
"modal_window",
item.header,
item.thb,
item.w_h,
item.reload
);
});
main.innerHTML = theLinks;
_InitModal();
.modal-background {
font-family: sans-serif;
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
display: none;
overflow: auto;
background-color: rgba(0, 0, 0, 0.9);
z-index: 9999;
background: rgba(55, 55, 55, 0.6);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
.modal-window {
position: relative;
background-color: #ffffff;
width: 50%;
margin: 10% auto;
border-radius: 0.5rem;
padding: 0.75rem;
border: 1px groove #ccc;
/* box-shadow: 1px 1px 1px #999, 2px 2px 2px #000; */
}
.close-modal:hover,
.close-modal:focus {
color: rgba(255, 255, 255, 1);
cursor: pointer;
background: red;
transition: 1s;
text-shadow: 1px 1px 1px #999, 2px 2px 2px #000;
}
button.close-modal {
position: absolute;
top: -0.75rem;
right: -0.75rem;
padding: 0.05rem 0.75rem;
background: #999;
color: #ccc;
border-radius: 50%;
border: none;
outline: none;
-webkit-transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1);
transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1);
-webkit-animation-name: animatebottom;
-webkit-animation-duration: 1.5s;
animation-name: animatebottom;
animation-duration: 1.5s;
}
button.close-modal::before {
content: "\D7";
font-size: 2rem;
}
.modal-window {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
-webkit-animation-name: animatetop;
-webkit-animation-duration: 0.5s;
animation-name: animatetop;
animation-duration: 0.5s;
}
.modal-header {
height: 30px;
text-align: center;
width: 100%;
background: #fff;
padding: 0.2rem;
}
.modal-header h1 {
font-size: 1.1rem;
}
.modal-footer {
height: 20px;
text-align: center;
width: 100%;
background: #fff;
padding: 0.2rem;
}
.modal-content {
background-color: #fff;
height: calc(100% - 70px);
border-radius: 0.5rem;
border: 0.1rem groove #ddd;
overflow: hidden;
}
.button-footer {
background: #fff;
border-radius: 0.5rem;
border: 1px outset #aaa;
padding: 0.2rem;
color: #999;
transition: 1s;
cursor: pointer;
}
.button-footer:hover {
background: #fdfdfd;
color: #555;
border: 1px inset #ddd;
text-shadow: 0.05rem 0.05rem 0.05rem #ccc, 0.055rem 0.055rem 0.055rem #999,
0.06rem 0.06rem 0.06rem #333;
transition: 1s;
}
.close-btn:hover {
color: white;
background: #f00;
cursor: pointer;
}
#modal_iframe {
width: 100%;
height: 100%;
}
button.modal-button {
border-radius: 0.5rem;
border: 0px solid #aaa;
padding: 0;
cursor: pointer;
}
.modal-button-img {
border-radius: 0.5rem;
border: 0.1rem groove #444;
cursor: pointer;
}
.sepia:hover {
filter: sepia(150%);
}
/*
.none {
display: none;
}
*/
#-webkit-keyframes animatetop {
from {
top: -300px;
opacity: 0;
}
to {
top: 0;
opacity: 1;
}
}
#keyframes animatetop {
from {
top: -300px;
opacity: 0;
}
to {
top: 0;
opacity: 1;
}
}
#-webkit-keyframes animatebottom {
from {
top: 0;
opacity: 1;
}
to {
bottom: -300px;
opacity: 0;
}
}
#keyframes animatebottom {
from {
top: 0;
opacity: 1;
}
to {
bottom: -300px;
opacity: 0;
}
}
.container {
border-radius: 0.5rem;
border: 1px solid #aaa;
max-width: 800px;
width: 500px;
margin: 0 auto;
text-align: center;
font-family: sans-serif;
}
main,
aside {
font-family: sans-serif;
max-width: 800px;
width: 500px;
margin: 0 auto;
text-align: center;
}
h2 {
text-align: center;
font-family: sans-serif;
font-weight: normal;
font-size: 1.2rem;
}
span {
font-size: 75%;
background: #ffff0055;
}
<div id="modal_window" class="modal-background">
<div class="modal-window">
<button class="close-modal" data-dismiss="modal"></button>
<div class="modal-header"></div>
<div class="modal-content">
<iframe src="#" id="modal_iframe" frameborder="0">If you'd have had a real browser, I wouldn't be boring you with this now...</iframe>
</div>
<div class="modal-footer"><button class="button-footer">Open In New Tab</button></div>
</div>
</div>
<div class="container">
<h2><code>main</code> Content Rendered By JavaScript</h2>
<main>
Main
</main>
<span>working now</span>
</div>

Related

How to reload all kinds of functions and all HTML code in JavaScript to restart a game?

Clicking on the Home button at the end of this project brings it to the beginning, but no function is reset. Level buttons are not also being enabled anew. If I enable those level buttons by writing some extra code for enabling, then the number of buttons given for each level will be doubled after selecting the level. In other words, for the first time due to selecting the basic level, there were 4 options, But when I click on the last home button and then select the medium level to play the game from the beginning, it becomes 16 options instead of 8.
//VARIABLE DECLARATION PART
let frontpage = document.querySelector(".front-page");
let playbutton = document.querySelector(".play");
let levelpage = document.querySelector(".levelpg");
let startbtn = document.querySelector(".startbtn");
let maingame = document.querySelector(".maingame");
let easybtn = document.querySelector(".easy");
let mediumbtn = document.querySelector(".medium");
let hardbtn = document.querySelector(".hard");
let nextbtn = document.querySelector(".nextbtn");
let pagecount = document.querySelector('.gamepagecount');
let getnumberdiv = document.querySelector('.numberbtn').children;
let resultpg = document.querySelector('.resultpage');
let backhome = document.querySelector('.backhome');
let finalscore = document.querySelector('.score');
let resulttext = resultpg.children[1];
let changeimg = document.querySelector('.resultpage img');
// PLAYBUTTON CLICK
playbutton.addEventListener("click", () => {
frontpage.classList.add("hidden");
levelpage.classList.remove("hidden");
levelpage.classList.add("visibility");
});
//GAME START FUNCTION
function startGame(level) {
if (level == "easy") {
mediumbtn.disabled = true;
hardbtn.disabled = true;
easybtn.disabled = true;
easybtn.classList.add('levelcolor');
startbtn.addEventListener("click", () => {
pagecount.innerHTML = `1 of 10`;
nextbtn.disabled = true
levelChange(4);
gameInterfaceChange()
mainGame(10);
//NEXTBUTTON FUNCTION
nextbtn.addEventListener('click', () => {
enableBtn(4)
pageCount(10);
mainGame(10);
})
});
}
else if (level == "medium") {
mediumbtn.disabled = true;
hardbtn.disabled = true;
easybtn.disabled = true;
mediumbtn.classList.add('levelcolor');
startbtn.addEventListener("click", () => {
pagecount.innerHTML = `1 of 15`;
nextbtn.disabled = true
levelChange(8);
gameInterfaceChange();
maingame.style.top = "20%";
mainGame(20);
//NEXTBUTTON FUNCTION
nextbtn.addEventListener('click', () => {
enableBtn(8)
pageCount(15)
mainGame(20);
})
});
}
else if (level == "hard") {
mediumbtn.disabled = true;
hardbtn.disabled = true;
easybtn.disabled = true;
hardbtn.classList.add('levelcolor');
startbtn.addEventListener("click", () => {
pagecount.innerHTML = `1 of 20`;
nextbtn.disabled = true
levelChange(12);
gameInterfaceChange();
maingame.style.top = "12%";
mainGame(30);
//NEXTBUTTON FUNCTION
nextbtn.addEventListener('click', () => {
enableBtn(12)
pageCount(20)
mainGame(30);
})
});
}
}
//PAGE SLIDING FUNCTION
function gameInterfaceChange() {
levelpage.classList.remove("hidden");
levelpage.classList.add("hidden");
maingame.classList.remove("hidden");
maingame.style.top = "25%";
maingame.classList.add("visibility");
}
// FUNCTION OF RANDOM INPUTING NUMBER IN DIV
function mainGame(maxnum) {
let numboxlen = getnumberdiv.length;
let wrongnum = Math.floor(Math.random() * maxnum) + 1;
let getnumber = [];
//DUPLICATE RANDOM NUMBER CHECKING
for (let i = 0; i < numboxlen; i++) {
let check = getnumber.includes(wrongnum);
if (check === false) {
getnumber.push(wrongnum);
}
else {
while (check === true) {
wrongnum = Math.floor(Math.random() * maxnum) + 1;
check = getnumber.includes(wrongnum);
if (check === false) {
getnumber.push(wrongnum);
}
}
}
}
// NUMBER PUTTING IN InnerHtml
for (var j = 0; j < numboxlen; j++) {
if (getnumber[j] < 10) {
getnumberdiv[j].innerHTML = '0' + getnumber[j];
}
else {
getnumberdiv[j].innerHTML = getnumber[j];
}
}
}
// BUTTON ADDING ACCORDING TO THE LEVEL
function levelChange(divnum) {
for (let index = 0; index < divnum; index++) {
let newBtn = document.createElement('button');
let newbtnNode = document.createTextNode('');
newBtn.appendChild(newbtnNode);
let gamebtn = document.getElementById('numbrbtn');
gamebtn.appendChild(newBtn);
newBtn.setAttribute("onclick", `numberClick(${index},${divnum})`);
}
}
//RIGHT - WRONG CHECKING FUNTION
var right = 0;
var wrong = 0;
function numberClick(index, divnum) {
let rightnumberindex = Math.floor(Math.random() * divnum);
if (index == rightnumberindex) {
nextbtn.disabled = false
right++;
//RIGHT AND WRONG BACKGROUND ADDING AND BUTTON DISABLE
getnumberdiv[index].classList.add("rightans");
for (let i = 0; i < divnum; i++) {
getnumberdiv[i].disabled = true;
}
}
else {
nextbtn.disabled = false
wrong++;
//RIGHT AND WRONG BACKGROUND ADDING AND BUTTON DISABLE
getnumberdiv[rightnumberindex].classList.add("rightans");
getnumberdiv[index].classList.add("wrongans");
for (let i = 0; i < divnum; i++) {
getnumberdiv[i].disabled = true;
}
}
}
// BUTTON ENABLE ON NEXT BUTTION CLICK
function enableBtn(divnum) {
for (let i = 0; i < divnum; i++) {
nextbtn.disabled = true
getnumberdiv[i].disabled = false;
getnumberdiv[i].classList.remove("wrongans");
getnumberdiv[i].classList.remove("rightans");
}
}
//PAGE COUNTING ACCORDING TO THE LEVEL
let currentpg = 1;
function pageCount(levelPg) {
currentpg++;
if (currentpg <= levelPg) {
if (currentpg == levelPg) {
nextbtn.innerHTML = 'Result'
pagecount.innerHTML = `${currentpg} of ${levelPg}`;
}
else {
pagecount.innerHTML = `${currentpg} of ${levelPg}`;
}
}
else {
result();
}
}
//FINAL RESULT FUNTION
function result() {
maingame.classList.remove("visibility");
maingame.classList.add("hidden");
resultpg.classList.remove('hidden')
resultpg.classList.add('visibility')
if (right > wrong) {
changeimg.setAttribute('src', 'trophy.png')
resulttext.innerHTML = `You Win`;
finalscore.innerHTML = `Your Right Score is : ${right} out of ${right + wrong}`;
}
else if (right == wrong) {
changeimg.setAttribute('src', 'draw.png')
resulttext.innerHTML = `It's Draw`;
finalscore.innerHTML = `Your Right Score is : ${right} out of ${right + wrong}`;
}
else if (right < wrong) {
changeimg.setAttribute('src', 'lose.png')
resulttext.innerHTML = `You Lose`;
finalscore.innerHTML = `Your Right Score is : ${right} out of ${right + wrong}`;
}
}
//BACK TO THE HOME FUNCTION
backhome.addEventListener('click', () => {
frontpage.classList.add("visibility");
frontpage.classList.remove("hidden");
resultpg.classList.add('hidden')
resultpg.classList.remove('visibility')
// enable level button
mediumbtn.disabled = false;
hardbtn.disabled = false;
easybtn.disabled = false;
})
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Poppins", sans-serif;
}
body {
margin-top: 50px;
}
.guessing-game {
position: relative;
color: white;
text-align: center;
margin: auto;
width: 350px;
height: 600px;
border-radius: 25px;
padding: 50px 30px;
background: linear-gradient(to right, #bd3f32, #cb356b);
}
.guessing-game .front-page .front-img {
height: 160px;
text-align: center;
}
.guessing-game .front-page img {
max-height: 100%;
}
.guessing-game .front-page .front-text h1 {
margin-top: 50px;
font-size: 1.8em;
}
.guessing-game .front-page .front-text p {
margin-top: 10px;
font-size: 1em;
}
.guessing-game .front-page .front-text button,
.resultpage button ,
.levelpg .easy,
.levelpg .medium,
.levelpg .hard,
.maingame .nextbtn {
margin-top: 30px;
width: 100%;
color: white;
padding: 15px;
outline: 0;
border: 0;
border-radius: 50px;
font-size: 0.9em;
background-color: #d64d5d;
box-shadow: rgba(17, 17, 26, 0.1) 0px 1px 0px,
rgba(17, 17, 26, 0.144) 0px 8px 24px, rgba(17, 17, 26, 0.1) 0px 16px 48px;
}
.guessing-game .front-page .front-text button:hover,
.maingame .nextbtn:hover,
.resultpage button:hover {
transition: 0.5s;
background-color: #c22f40;
}
/* Level page */
.visiblepg {
position: absolute;
top: 12%;
width: 290px;
}
.levelpg h1 {
margin: 45px 0 40px 0;
font-weight: 600;
font-size: 2.4em;
border: 1px solid white;
}
.levelpg .easy,
.levelpg .medium,
.levelpg .hard {
display: block;
margin-top: 15px;
padding: 12px;
background: white;
font-size: 1em;
border-radius: 10px;
font-weight: 400;
color: #c22f40;
}
.startbtn {
background: transparent;
border: 0;
outline: 0;
}
.levelpg i {
color: white;
margin-top: 50px;
font-size: 70px;
border-radius: 50%;
border: 2px solid transparent;
}
.levelpg i:hover {
background-color: white;
border: 2px solid white;
color: #c22f40;
transition: 0.5s;
}
/* GAME PART */
.maingame .gamepagecount {
background-color: #d64d5d;
color: white;
padding: 4px;
border-radius: 6px;
font-size: 0.8em;
font-weight: 600;
}
.maingame .gametext {
margin-top: 15px;
font-size: 1.2em;
}
.maingame .numberbtn {
display: flex;
justify-content: space-around;
flex-wrap: wrap;
}
.maingame .numberbtn button {
margin-top: 40px;
width: 50px;
height: 50px;
background-color: white;
display: flex;
align-content: space-around;
justify-content: center;
align-items: center;
flex-wrap: wrap;
flex: 1 0 21%;
margin-left: 10px;
border: 0;
outline: 0;
border-radius: 10px;
font-size: 1em;
color: #c22f40;
font-weight: 600;
}
.maingame .numberbtn button:nth-child(1),
.maingame .numberbtn button:nth-child(5),
.maingame .numberbtn button:nth-child(9) {
margin-left: 0;
}
.resultpage h1 {
margin: 0px 0 40px 0;
}
.resultpage img {
margin-top: 45px;
width: 50%;
}
/* PRE DEFINE CSS */
.visibility {
visibility: visiible;
opacity: 2s;
transition: 0.5s;
transform: translateX(0px);
}
.hidden {
visibility: hidden;
opacity: 0;
transition: 0.5s;
transform: translateX(-30px);
}
.levelcolor {
transition: 0.5s;
color: white !important;
background-color: #c22f40 !important;
}
.rightans {
background-color: #27ae60 !important;
color: white !important;
transition: 0.5s;
}
.wrongans {
background-color: #fd4631 !important;
color: white !important;
transition: 0.5s;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Poppins:ital,wght#0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"
rel="stylesheet" />
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css"
integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p" crossorigin="anonymous" />
<title>Guessing Game</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="guessing-game">
<div class="front-page">
<div class="front-img">
<img src="./question.png" alt="" />
</div>
<div class="front-text">
<h1>Guessing Game</h1>
<p>
You just need to chose the right number from the option. If your
guess is right more than wrong , you will win otherwise you will
fail! Let's see how good your sixth sense is!!!
</p>
<button class="play">Let's play</button>
</div>
</div>
<div class="levelpg hidden visiblepg">
<h1>Game level</h1>
<button class="easy" onclick="startGame('easy')">Easy</button>
<button class="medium" onclick="startGame('medium')">Medium</button>
<button class="hard" onclick="startGame('hard')">Hard</button>
<button class="startbtn"><i class="fas fa-play-circle"></i></button>
</div>
<div class="maingame visiblepg hidden">
<p class="gamepagecount">1</p>
<p class="gametext">Guess the number you think is right</p>
<div class="numberbtn" id="numbrbtn"></div>
<button class="nextbtn">Next</button>
</div>
<div class="resultpage levelpg hidden visiblepg">
<img src="" alt="" />
<h1></h1>
<div class="score"></div>
<button class="backhome">Home</button>
</div>
</div>
<script src="./main.js"></script>
</body>
</html>
In short, as soon as I click on the home button, I want the game to start anew, all the functions will be reset anew, and the HTML will be reset anew also. I hope my problem is enough clear to understand.
I have solved the problem.
I just add a reload function to solve this problem.
backhome.addEventListener('click', () => {
frontpage.classList.add("visibility");
frontpage.classList.remove("hidden");
resultpg.classList.add('hidden')
resultpg.classList.remove('visibility')
//reload function
window.location.reload();
})

Function removes items from localStorage only if run manually

I'm looking for advice/tips on how to fix a function that is supposed to remove items from localStorage. I'm following a tutorial by John Smilga that I found on Youtube. Although I've modeled my code on his, apparently, I have missed something.
This function works perfectly well if I run it manually from the console and pass in the id of the item that I want to remove from localStorage.
function removeFromLocalStorage(id) {
console.log(id);
let storageItems = getLocalStorage();
console.log(storageItems);
storageItems = storageItems.filter(function(singleItem) {
if (singleItem.id !== id) {
return singleItem;
}
})
console.log(storageItems);
localStorage.setItem("list", JSON.stringify(storageItems));
}
However, when this function is triggered by the deleteItem() function, it refuses to remove the item from localStorage. It still works, there are a bunch of console.logs in it that track its execution, and I can check that it receives the correct item id as the argument, but for some reason it doesn't filter out the item that needs to be removed. I am completely lost and have no idea how to identify the problem. I can't debug it with console.logs as I usually do. I will be very grateful if you help me find the problem. Any advice will be appreciated.
In case the entire code is needed, please find it below.
const form = document.querySelector(".app__form");
const alert = document.querySelector(".app__alert");
const input = document.querySelector(".app__input");
const submitBtn = document.querySelector(".app__submit-btn");
const itemsContainer = document.querySelector(".app__items-container");
const itemsList = document.querySelector(".app__items-list");
const clearBtn = document.querySelector(".app__clear-btn");
let editElement;
let editFlag = false;
let editId = "";
form.addEventListener("submit", addItem);
clearBtn.addEventListener("click", clearItems);
function addItem(e) {
e.preventDefault();
const id = Math.floor(Math.random() * 9999999999);
if (input.value && !editFlag) {
const item = document.createElement("div");
item.classList.add("app__item");
const attr = document.createAttribute("data-id");
attr.value = id;
item.setAttributeNode(attr);
item.innerHTML = `<p class='app__item-text'>${input.value}</p>
<div class='app__item-btn-cont'>
<button class='app__item-btn app__item-btn--edit'>edit</button>
<button class='app__item-btn app__item-btn--delete'>delete</button>
</div>`
const editBtn = item.querySelector(".app__item-btn--edit");
const deleteBtn = item.querySelector(".app__item-btn--delete");
editBtn.addEventListener("click", editItem);
deleteBtn.addEventListener("click", deleteItem);
itemsList.appendChild(item);
displayAlert("item added", "success");
addToLocalStorage(id, input.value);
setBackToDefault();
itemsContainer.classList.add("app__items-container--visible");
} else if (input.value && editFlag) {
editElement.textContent = input.value;
// edit local storage
editLocalStorage(editId, input.value);
setBackToDefault();
displayAlert("item edited", "success");
} else {
displayAlert("empty field", "warning");
}
}
function setBackToDefault() {
input.value = "";
editFlag = false;
editId = "";
submitBtn.textContent = "Submit";
submitBtn.className = "app__submit-btn";
}
function displayAlert(text, action) {
alert.textContent = text;
alert.classList.add(`app__alert--${action}`);
setTimeout(function() {
alert.textContent = "";
alert.classList.remove(`app__alert--${action}`);
}, 700)
}
function clearItems() {
const items = document.querySelectorAll(".app__item");
if (items.length > 0) {
items.forEach(function(singleItem) {
itemsList.removeChild(singleItem);
})
itemsContainer.classList.remove("app__items-container--visible");
displayAlert("items cleared", "cleared");
setBackToDefault();
}
}
function editItem(e) {
const item = e.currentTarget.parentElement.parentElement;
editElement = e.currentTarget.parentElement.previousElementSibling;
editId = item.dataset.id;
editFlag = true;
input.value = editElement.textContent;
submitBtn.textContent = "Edit";
submitBtn.classList.add("app__submit-btn--edit");
input.focus();
}
function deleteItem(e) {
const item = e.currentTarget.parentElement.parentElement;
const itemId = item.dataset.id;
removeFromLocalStorage(itemId);
displayAlert("item removed", "cleared");
setBackToDefault();
itemsList.removeChild(item);
if (itemsList.children.length === 0) {
itemsContainer.classList.remove("app__items-container--visible");
}
}
function addToLocalStorage(id, value) {
const itemsObj = {id: id, value: input.value};
let storageItems = getLocalStorage();
storageItems.push(itemsObj);
localStorage.setItem("list", JSON.stringify(storageItems));
}
function removeFromLocalStorage(id) {
console.log(id);
let storageItems = getLocalStorage();
console.log(storageItems);
storageItems = storageItems.filter(function(singleItem) {
if (singleItem.id !== id) {
return singleItem;
}
})
console.log(storageItems);
localStorage.setItem("list", JSON.stringify(storageItems));
}
function editLocalStorage(id, value) {
}
function getLocalStorage() {
return localStorage.getItem("list") ? JSON.parse(localStorage.getItem("list")) : [];
}
* {
margin: 0;
padding: 0;
}
.app {
width: 70%;
max-width: 600px;
margin: 75px auto 0;
}
.app__title {
text-align: center;
/* color: #1B5D81; */
margin-top: 20px;
color: #377FB4;
}
.app__alert {
width: 60%;
margin: 0 auto;
text-align: center;
font-size: 20px;
color: #215884;
border-radius: 7px;
height: 23px;
transition: 0.4s;
text-transform: capitalize;
}
.app__alert--warning {
background-color: rgba(243, 117, 66, 0.2);
color: #006699;
}
.app__alert--success {
background-color: rgba(165, 237, 92, 0.4);
color: #3333ff;
}
.app__alert--cleared {
background-color: #a978da;
color: white;
}
.app__input-btn-cont {
display: flex;
margin-top: 30px;
}
.app__input {
width: 80%;
box-sizing: border-box;
font-size: 20px;
padding: 3px 0 3px 10px;
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
border-right: none;
border: 1px solid #67B5E2;
background-color: #EDF9FF;
}
.app__input:focus {
outline: transparent;
}
.app__submit-btn {
display: block;
width: 20%;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
border-left: none;
background-color: #67B5E2;
border: 1px solid #67B5E2;
cursor: pointer;
font-size: 20px;
color: white;
transition: background-color 0.7s;
padding: 3px 0;
}
.app__submit-btn--edit {
background-color: #95CB5D;
}
.app__submit-btn:active {
width: 19.9%;
padding: 0 0;
}
.app__submit-btn:hover {
background-color: #377FB4;
}
.app__submit-btn--edit:hover {
background-color: #81AF51;
}
.app__items-container {
visibility: hidden;
/* transition: 0.7s; */
}
.app__items-container--visible {
visibility: visible;
}
.app__item {
display: flex;
justify-content: space-between;
margin: 20px 0;
}
.app__item:hover {
background-color: #b9e2fa;
border-radius: 10px;
}
.app__item-text {
padding-left: 10px;
font-size: 20px;
color: #1B5D81;
}
.app__item-btn-cont {
display: flex;
}
.app__item-btn-img {
width: 20px;
height: 20px;
}
.app__item-btn {
border: none;
background-color: transparent;
cursor: pointer;
display: block;
font-size: 18px;
}
.app__item-btn--edit {
margin-right: 45px;
color: #2c800f;
}
.app__item-btn--delete {
margin-right: 15px;
color: rgb(243, 117, 66);
}
.app__clear-btn {
display: block;
width: 150px;
margin: 20px auto;
border: none;
background-color: transparent;
font-size: 20px;
color: rgb(243, 117, 66);
letter-spacing: 2px;
cursor: pointer;
transition: border 0.3s;
border: 1px solid transparent;
}
.app__clear-btn:hover {
border: 1px solid rgb(243, 117, 66);
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8" name="viewport" content="width=device-width,
initial-scale=1">
<link rel="stylesheet" href="list.css">
<title>To Do List App</title>
</head>
<body>
<section class="app">
<form class="app__form">
<p class="app__alert"></p>
<h2 class="app__title">To Do List</h2>
<div class="app__input-btn-cont">
<input class="app__input" type="text" id="todo" placeholder="do stuff">
<button class="app__submit-btn">Submit</button>
</div>
</form>
<div class="app__items-container">
<div class="app__items-list">
</div>
<button class="app__clear-btn">Clear Items</button>
</div>
</section>
<script src="list.js"></script>
</body>
</html>
Your code is fine you just used the wrong comparison operator.
In your case you are comparing 2 IDs (operands) to see if they match up, so you should use normal operators such as (==, !=), but instead in your case, you have used strict operators which are used to compare the operand type and the operand itself.
You can learn more about Comparison Operators here.
Ultimatly,
In your function removeFromLocalStorage(id), you have an extra equal sign in your if function.
Instead of:
if (singleItem.id !== id) {
return singleItem;}
It should be:
if (singleItem.id != id) {
return singleItem;}
Hope this helps.

Transition event listener doesn't execute

I'm working on transitions by using javascript. But i want to display element to none when the transition is end. I'm using addEventListener on element but function doesn't execute.
var fun;
var transitions = {
'transition':'transitionend',
'OTransition':'oTransitionEnd',
'MozTransition':'transitionend',
'WebkitTransition':'webkitTransitionEnd'
};
(function(){
var i=0,
containterget = document.querySelector('.container');
elementGet = document.querySelector('.Number');
fun = function(){
i++;
elementGet.innerHTML = i;
elementGet.style.transform = 'translateX('+(containterget.offsetWidth - 40 -35)+'px)';
elementGet.addEventListener(transitions,function(event){
console.log("Transition End Execute");
elementGet.style.display='none';
} );
};
})();
*{
margin:0;
padding:0;
box-sizing: border-box;
}
.container{
border:1px solid green;
max-width:85%;
margin: 2em auto 0;
}
button{
background-color:transparent;
padding: 15px;
margin:0;
color:#000;
border:2px solid #F44336;
text-align: center;
outline: 0;
transition: opacity 0.3s;
}
button:hover{
background-color:#F44336;
color: white;
opacity :.75;
}
button:hover{
cursor: pointer;
transition: opacity .4s;
}
span{
display: inline-block;
transition: transform 1.5s ease;
}
.Number{
font-size: 4em;
border:1px solid black;
/*transform: translateX(0);*/
}
.EndBoundry{
float: right;
font-size: 4em;
border:1px solid black;
}
.contain:after{
content: "";
display: table;
clear: both;
}
.btn{
text-align: center;
margin: 2em 0;
}
<div class="container contain">
<span class="Number">1</span>
<span class="EndBoundry">E</span>
</div>
<div class="btn">
<button onclick="fun()">Number Transition Click</button>
</div>
The following Snippet demonstrates the transitionend event. All details are commented in Snippet.
SNIPPET
// Reference the section#area and input#gone
var area = document.getElementById('area');
var chx = document.getElementById('gone');
// Register click event on #area call offON()
area.addEventListener('click', offON, false);
function offON(e) {
// Determine the clicked button
if (e.target !== e.currentTarget) {
var tgt = e.target;
// Switch clicked button classes .on and .off
tgt.classList.toggle('on');
tgt.classList.toggle('off');
}
// If the checkbox is checked call transEND()
if (chx.checked) {
transEND()
}
}
function transEND() {
// Register the transitionend event on #area
area.addEventListener("transitionend", function(e) {
// Determine which button was clicked
if (e.target !== e.currentTarget) {
var tgt = e.target;
// Clicked button will disappear after transition
tgt.style.display = 'none';
}
}, false);
}
/* All buttons will have the same
|| transition. This transition is
|| dependent upon another animatable
|| style to exist.
*/
/* This particular transition says:
|| ALL animatable styles have a
|| duration of 3 seconds,
|| with a timing function: ease,
|| and a delay of 300msec
*/
button {
width: 120px;
height: 40px;
transition: all 3s ease .3s
}
/* Classes .on and .off are "states"
|| to each #id the "states" have a
|| different meaning
*/
#fade.off {
opacity: 1;
}
#fade.on {
opacity: 0;
}
#move.off {
transform: translateY(0);
}
#move.on {
transform: translateY(200px);
}
#shrink.off {
transform: scale(1);
}
#shrink.on {
transform: scale(.3);
}
#gone {
width: 18px;
height: 18px;
}
p {
font-size: 12px;
}
<p>Click each button. Then click them again (the "FADER" is still there and clickable)</p>
<p>Now click the checkbox and push the buttons again. If you can't click the buttons back to original "state", then the event handler on transitionend was successful.</p>
<label for='gone'>Enable "transitionEND" </label>
<input id='gone' type='checkbox'>
<section id='area'>
<button id='fade' class='off'>FADER</button>
<button id='move' class='off'>MOVER</button>
<button id='shrink' class='off'>SHRINKER</button>
</section>
Use "transitionend" without prefixes
elementGet.addEventListener("transitionend", function(){});
You can listen to transitionend event on supported browsers.
I did some reshuffling of your codes and add an id tag to your button.
See snippet below
var fun;
var i = 0,
containterget = document.querySelector('.container');
elementGet = document.querySelector('.Number');
console.log(elementGet)
function execute(event) {
console.log("Transition End Execute");
alert("Transition End Execute");
elementGet.style.display = 'none';
}
fun = function() {
i++;
elementGet.innerHTML = i;
elementGet.style.transform = 'translateX(' + (containterget.offsetWidth - 40 - 35) + 'px)';
elementGet.addEventListener('transitionend', execute);
elementGet.addEventListener('webkitTransitionEnd', execute);
elementGet.addEventListener('mozTransitionEnd', execute);
elementGet.addEventListener('oTransitionEnd', execute);
};
document.getElementById("target").addEventListener("click", fun)
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
border: 1px solid green;
max-width: 85%;
margin: 2em auto 0;
}
button {
background-color: transparent;
padding: 15px;
margin: 0;
color: #000;
border: 2px solid #F44336;
text-align: center;
outline: 0;
transition: opacity 0.3s;
}
button:hover {
background-color: #F44336;
color: white;
opacity: .75;
}
button:hover {
cursor: pointer;
transition: opacity .4s;
}
span {
display: inline-block;
transition: transform 1.5s ease;
}
.Number {
font-size: 4em;
border: 1px solid black;
/*transform: translateX(0);*/
}
.EndBoundry {
float: right;
font-size: 4em;
border: 1px solid black;
}
.contain:after {
content: "";
display: table;
clear: both;
}
.btn {
text-align: center;
margin: 2em 0;
}
<div class="container contain">
<span class="Number">1</span>
<span class="EndBoundry">E</span>
</div>
<div class="btn">
<script></script>
<button id="target">Number Transition Click</button>
</div>

Javascript Slideshow Functions Not Working

I would please like an explanation to why the slideshow is not working. Below I have used an interval to perpetually change the slideshow, if userClick is false. The white and squared buttons (made of divs) are set to call upon two functions; slideRight() or slideLeft() and clicked(). When the buttons are clicked however, the clicked() function does not seem to change the variable, based on the data on top of the page.
<body>
<div class="page-wrapper">
<header>
<div class="headContent">
<h1 class="titleText">Slideshow</h1>
<h2 class="subTitleText">A slideshow made with JavaScript.</h2>
<p>userClick <span id="uc"></span></p>
</div>
<nav>
<ul>
<li>Home</li>
<li>About</li>
<li>Gallery</li>
</ul>
</nav>
</header>
<div class="body-wrapper">
<h1 class="titleText">Slideshow</h1>
<div id="slideshow">
<div id="leftSlide" onclick="leftSlide(); clicked()"></div>
<div id="rightSlide" onclick="rightSlide(); clicked()"></div>
</div>
<p>The image is not invoked by a tag, but invoked by the background property using Javascript.</p>
</div>
<footer>
<p id="footerText">© 2017 <br>Designed by JastineRay</p>
</footer>
</div>
<script language="javascript">
// Slide function
var slide = ["minivan", "lifeinthecity", "sunsetbodyoflove"];
var slideTo = 1;
window.onload = getSlide();
// Previous Image
function leftSlide() {
if (slideTo != 0) {
slideTo = slideTo - 1;
} else if (slideTo == 0) {
slideTo = slide.length - 1;
} else {
alert('SLIDE ERROR');
}
getSlide();
}
// Next Image
function rightSlide() {
if (slideTo != (slide.length - 1)) {
slideTo = slideTo + 1;
} else if (slideTo == (slide.length - 1)) {
slideTo = 0;
} else {
alert('SLIDE ERROR');
}
getSlide();
}
function getSlide() {
imageURL = 'url(images/' + slide[slideTo] + '.jpg)';
document.getElementById("slideshow").style.backgroundImage = imageURL;
}
// Interval Slideshow & Check if user clicked (timeout)
var userClick = false;
window.onload = slideInterval(5000);
// Start Slideshow
function slideInterval(interval) {
while (userClick = false) {
setInterval(function() {
rightSlide();
}, interval)
}
}
// Stop Slideshow and start timeout
function clicked() {
userClick = true;
setTimeout(function() {
userClick = false;
slideInterval();
}, 2000)
}
window.onload = function() {
setInterval(document.getElementById("uc").innerHTML = userClick), 100
}
</script>
</body>
CSS coding below.
* {
margin: 0;
padding: 0;
}
.page-wrapper {
width: 100%;
}
// Class Styling
.titleText {
font-family: monospace;
font-size: 40px;
}
.subTitleText {
font-family: monospace;
font-size: 20px;
font-weight: normal;
}
// Header Styling
header {
height: 500px;
}
.headContent {
margin: 30px 7%;
}
// Navigation Styling
nav {
overflow: hidden;
}
nav ul {
background: black;
background: linear-gradient(#595959, black);
list-style-type: none;
font-size: 0;
padding-left: 13.33%;
margin: 40px 0;
}
nav ul li {
padding: 15px 20px;
border-right: 1px solid #595959;
border-left: 1px solid #595959;
color: white;
display: inline-block;
font-size: 20px;
font-family: sans-serif;
}
// Body Styling
.body-wrapper {
}
.body-wrapper > .titleText {
text-align: center;
font-size: 50px;
}
#slideshow {
overflow: hidden;
margin: 20px auto;
border: 2px solid blue;
height: 350px;
max-width: 800px;
background-size: cover;
background-position: center;
position: relative;
}
#leftSlide {
position: absolute;
left: 40px;
top: 175px;
background-color: white;
height: 40px;
width: 40px;
}
#rightSlide {
position: absolute;
left: 100px;
top: 175px;
background-color: white;
height: 40px;
width: 40px;
}
// Footer Styling
Try changing the checking part to:
window.onload = function() {
setInterval(function () {
document.getElementById("uc").innerHTML = userClick;
}, 100);
}
The first argument of setInterval has to be a function (something that can be called), not a generic piece of code.

Fullscreen API; browser thinks I don't start with a user gesture

I'm working on a custom video player using the HTML5 video element and I'm having trouble getting the full screen button to work with the Fullscreen API.
When I click it, I get the error message:
Failed to execute 'requestFullscreen' on 'Element': API can only be initiated by a user gesture.
However, I am initiating the call to requestFullscreen with a user gesture... Unless I'm misunderstanding what constitutes a user gesture. A click on an element is a user gesture, isn't it?
I realize that there are a lot of questions about the Fullscreen API on SO, but it looks like many people want to initiate full screen mode without user interaction.
What am I doing wrong?
There is a pen with this code, but I'm likely to change that when I find a solution. I won't change the code here.
Here's the code:
/* Get our elements. */
const player = document.querySelector('.player');
const video = player.querySelector('.viewer');
const progress = player.querySelector('.progress');
const progressBar = player.querySelector('.progress__filled');
const toggle = player.querySelector('.toggle');
const skipButtons = player.querySelectorAll('[data-skip]');
const ranges = player.querySelectorAll('.player__slider');
const fullscreen = player.querySelector('.fullscreen');
let isFullScreen = false;
/* Build our functions */
function togglePlay() {
const action = video.paused ? 'play' : 'pause';
video[action]();
}
function updatePlayIcon() {
toggle.classList.toggle('playing');
}
function skip() {
video.currentTime += parseFloat(this.dataset.skip);
}
function handleRangeUpdate() {
video[this.name] = this.value;
}
function handleProgress() {
const percent = (video.currentTime / video.duration) * 100;
progressBar.style.flexBasis = percent + '%';
}
function scrub(e) {
const seconds = (e.offsetX / progress.offsetWidth) * video.duration;
video.currentTime = seconds;
}
function toggleFullScreen() {
if (isFullScreen) {
console.log("exiting fullscreen");
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
console.log('removing fullscreen class');
player.classList.remove('fullscreen');
} else {
console.log("entering fullscreen");
if (player.requestFullscreen) {
console.log('requestFullScreen');
player.requestFullscreen(); // standard
} else if (player.webkitRequestFullscreen) {
console.log('webkitRequestFullscreen');
player.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
} else if (player.mozRequestFullScreen) {
console.log('mozRequestFullScreen');
player.mozRequestFullScreen();
} else if (player.msRequestFullscreen) {
console.log('msRequestFullscreen');
player.msRequestFullscreen();
} else {
console.error('Unable to find a fullscreen request method');
}
console.log('adding fullscreen class');
player.classList.add('fullscreen');
}
isFullScreen = !isFullScreen;
}
/* Hook up the event listeners */
video.addEventListener('click', togglePlay);
toggle.addEventListener('click', togglePlay);
video.addEventListener('play', updatePlayIcon);
video.addEventListener('pause', updatePlayIcon);
video.addEventListener('timeupdate', handleProgress);
skipButtons.forEach(button => button.addEventListener('click', skip));
ranges.forEach(range => range.addEventListener('change', handleRangeUpdate));
ranges.forEach(range => range.addEventListener('mousemove', handleRangeUpdate));
let mousedown = false;
progress.addEventListener('click', scrub);
progress.addEventListener('mousemove', (e) => mousedown && scrub(e));
progress.addEventListener('mousedown', () => mousedown = true);
progress.addEventListener('mouseup', () => mousedown = false);
fullscreen.addEventListener('click', toggleFullScreen);
document.addEventListener('fullscreenchange', toggleFullScreen);
document.addEventListener('mozfullscreenchange', toggleFullScreen);
document.addEventListener('webkitfullscreenchange', toggleFullScreen);
document.addEventListener('msfullscreenchange', toggleFullScreen);
html {
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
html, body {
height: 100%;
}
body {
margin: 0;
display: flex;
background: #7A419B;
background: linear-gradient(135deg, #7c1599 0%, #921099 48%, #7e4ae8 100%);
background-size: cover;
align-items: center;
justify-content: center;
}
.player {
max-width: 750px;
max-height: 100%;
border: 5px solid rgba(0, 0, 0, 0.2);
box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
position: relative;
font-size: 0;
overflow: hidden;
}
button.toggle.fullscreen::before {
font-family: "FontAwesome";
content: "\f065";
}
.player.fullscreen .player__controls .toggle.fullscreen::before {
content: "\f066";
}
/* This css is only applied when fullscreen is active. */
.player.fullscreen {
max-width: none;
max-height: none;
width: 100%;
height: 100%;
background-color: black;
}
.player.fullscreen video {
width: 100%;
}
.player__video {
max-width: 100%;
max-height: 100%;
}
.player__button {
background: none;
border: 0;
line-height: 1;
color: white;
text-align: center;
outline: 0;
padding: 0;
cursor: pointer;
max-width: 50px;
}
.player__button:focus {
border-color: #ffc600;
}
.toggle::before {
font-family: "FontAwesome";
content: "\f04b";
}
.toggle.playing::before {
font-family: "FontAwesome";
content: "\f04c";
}
.player__slider {
width: 10px;
height: 30px;
}
.player__controls {
display: flex;
position: absolute;
bottom: 0;
width: 100%;
transform: translateY(100%) translateY(-5px);
transition: all .3s;
flex-wrap: wrap;
background: rgba(0, 0, 0, 0.1);
}
.player:hover .player__controls {
transform: translateY(0);
}
.player:hover .progress {
height: 15px;
}
.player__controls > * {
flex: 1;
}
.progress {
flex: 10;
position: relative;
display: flex;
flex-basis: 100%;
height: 5px;
transition: height 0.3s;
background: rgba(0, 0, 0, 0.5);
cursor: ew-resize;
}
.progress__filled {
width: 50%;
background: #ffc600;
flex: 0;
flex-basis: 0%;
}
.player__slider {
position: relative;
}
.player__slider::after {
content: attr(name);
position: absolute;
top: -2px;
text-shadow: 1px 1px 1px 0 rgba(0,0,0,0.5);
font-size: 0.8em;
}
/* unholy css to style input type="range" */
input[type=range] {
-webkit-appearance: none;
background: transparent;
width: 100%;
margin: 0 5px;
}
input[type=range]:focus {
outline: none;
}
input[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 8.4px;
cursor: pointer;
box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0 0 1px rgba(13, 13, 13, 0);
background: rgba(255, 255, 255, 0.8);
border-radius: 1.3px;
border: 0.2px solid rgba(1, 1, 1, 0);
}
input[type=range]::-webkit-slider-thumb {
box-shadow: 0 0 0 rgba(0, 0, 0, 0), 0 0 0 rgba(13, 13, 13, 0);
height: 15px;
width: 15px;
border-radius: 50px;
background: #ffc600;
cursor: pointer;
-webkit-appearance: none;
margin-top: -3.5px;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
}
input[type=range]:focus::-wefbkit-slider-runnable-track {
background: #bada55;
}
input[type=range]::-moz-range-track {
width: 100%;
height: 8.4px;
cursor: pointer;
box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0 0 1px rgba(13, 13, 13, 0);
background: #ffffff;
border-radius: 1.3px;
border: 0.2px solid rgba(1, 1, 1, 0);
}
input[type=range]::-moz-range-thumb {
box-shadow: 0 0 0 rgba(0, 0, 0, 0), 0 0 0 rgba(13, 13, 13, 0);
height: 15px;
width: 15px;
border-radius: 50px;
background: #ffc600;
cursor: pointer;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<div class="player">
<video class="player__video viewer" src="https://player.vimeo.com/external/194837908.sd.mp4?s=c350076905b78c67f74d7ee39fdb4fef01d12420&profile_id=164"></video>
<div class="player__controls">
<div class="progress">
<div class="progress__filled"></div>
</div>
<button class="player__button toggle" title="Toggle Play"></button>
<input type="range" name="volume" class="player__slider" min="0" max="1" step="0.05" value="1">
<input type="range" name="playbackRate" class="player__slider" min="0.5" max="2" step="0.1" value="1">
<button data-skip="-10" class="player__button"><i class="fa fa-step-backward"></i> 10s</button>
<button data-skip="25" class="player__button">25s <i class="fa fa-step-forward"></i></button>
<button class="player__button toggle fullscreen"></button>
</div>
</div>
The problem was that my toggleFullScreen function was being called twice when I clicked on the full screen button. I saw it while I was replying to Bibek Khadka's answer. The first time was when I clicked the button and the second time was when the full-screen mode actually changed because of these event listeners...
document.addEventListener('fullscreenchange', toggleFullScreen);
document.addEventListener('mozfullscreenchange', toggleFullScreen);
document.addEventListener('webkitfullscreenchange', toggleFullScreen);
document.addEventListener('msfullscreenchange', toggleFullScreen);
It would go to fullscreen mode, then back so quick that I didn't see the change. I believe the second time called the Fullscreen API method (technically) without a user gesture and that's why I got the error message.
The solution (for now at least) is to create a separate function for changing classes and the variable I'm using to track whether or not I'm in full screen mode ...
function toggleFullScreenClasses() {
player.classList.toggle('fullscreen');
isFullScreen = !isFullScreen;
}
... then I don't use that to handle the click on the button. I only use it to handle the actual fullscreenchange event...
document.addEventListener('fullscreenchange', toggleFullScreenClasses);
document.addEventListener('mozfullscreenchange', toggleFullScreenClasses);
document.addEventListener('webkitfullscreenchange', toggleFullScreenClasses);
document.addEventListener('msfullscreenchange', toggleFullScreenClasses);
I know this is sloppy, but it solves the problem for now. I previously tried using the :fullscreen pseudo-class, but I had some difficulty and I switched to the more familiar method of toggling classes and variables. I need to take another look at that.
I am no expert...just someone with free time :)
your const player = document.querySelector('.player'); is an element and trying to player.requestFullscreen(); gives you the errror. Modify your code so that the api call is made from something like player.onclick().requestFullscreen(); maybe. Sorry if I wasn't that helpful.

Categories

Resources