Why removeChild method doesn't remove element? - javascript

I have realized toast notifications by using vanilla javascript. Code works great, but one problem, why this code below doesn't work? What i should replace or add or remove? I don't understand why it doesn't work, could somebody explain me?
const autoRemove = setTimeout(function () {
item.removeChild(toast);
}, duration + 1000);
Here is code snippet of full application:
function toast({title = '', description = '', type = message, duration = 5000}) {
const item = document.querySelector('#toast');
if(item) {
const toast = document.createElement('div');
const autoRemove = setTimeout(function () {
item.removeChild(toast);
}, duration + 1000);
toast.addEventListener('click', function(event) {
if (event.target.closest('.close')) {
item.removeChild(toast);
clearTimeout(autoRemove);
}
});
const delay = (duration / 1000).toFixed(2);
toast.classList.add('toast', `${type}`);
toast.style.animation = `slide ease 1s, out ease 1s ${delay}s forwards`;
toast.innerHTML = `
<div>
<span class="title">${title}</span>
<i class="close fas fa-times"></i>
</div>
<p class="description">${description}</p>`;
item.appendChild(toast);
}
}
const button = document.querySelector('.button');
button.addEventListener('click', function() {
toast ({
title: 'Lorem ipsum',
description: 'Lorem ipsum dolor sit amet',
type: 'message',
duration: '5000'
});
});
body {
font-family: Arial, Helvetica, sans-serif;
min-height: 100vh;
}
.container {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
justify-content: center;
align-items: center;
}
*,
*:before,
*:after
{
box-sizing: border-box;
margin: 0;
padding: 0;
}
.button
{
cursor: pointer;
border: none;
text-transform: uppercase;
white-space: nowrap;
color: #fff;
background-color: #21262b;
border-radius: 5px;
padding: 10px;
font-size: 14px;
font-weight: bold;
}
#media(max-width: 992px) {
.container {
flex-direction: column;
}
}
#toast {
position: fixed;
top: 25px;
right: 25px;
z-index: 100;
}
.toast {
background: #fff;
box-shadow: rgba(100, 100, 110, 0.25) 0px 5px 30px 0px;
padding: 20px;
width: 250px;
border-radius: 7.5px;
border-left: 5px solid;
transition: all ease 0.25s;
}
.toast div {
display: flex;
justify-content: space-between;
}
.toast + .toast {
margin-top: 20px;
}
.toast.message {
border-color: #21262b;
}
.toast.message .title {
color: #21262b;
}
.toast.message .close {
color: #21262b;
}
.toast.success {
border-color: #20bdff;
}
.toast.success .title {
color: #20bdff;
}
.toast.success .close{
color: #20bdff;
}
.toast.error {
border-color: #f85032;
}
.toast.error .title {
color: #f85032;
}
.toast.error .close{
color: #f85032;
}
#keyframes slide {
from {
opacity: 0;
transform: translate(calc(100% + 25px), 0);
}
to {
opacity: 1;
transform: translate(0);
}
}
#keyframes out {
from {
opacity: 1;
transform: translate(0);
}
to {
opacity: 0;
transform: translate(calc(100% + 25px), 0);
}
}
.title {
font-weight: bold;
font-size: 20px;
}
.description {
margin-top: 10px;
font-size: 12px;
}
.close {
font-size: 20px;
cursor: pointer;
}
<div class="container">
<button class="button">Toast Button</button>
</div>
<div id="toast"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/js/all.min.js"></script>

When you create a toast (in the example) you pass duration: '5000'. In toast() you then use a delay of duration + 1000 which results in '50001000', not the intended 6000.
You can either pass the duration as a number or parse the string as a number and only then add 1000.
button.addEventListener('click', function() {
toast ({
title: 'Lorem ipsum',
description: 'Lorem ipsum dolor sit amet',
type: 'message',
duration: 5000
});
});
or
const autoRemove = setTimeout(function () {
item.removeChild(toast);
}, Number(duration) + 1000);

Related

How to update Answer for each click

I'm making a quiz front-end with "Back" and "Next" buttons. I want to update my answer if I change my answer when I go back. Idk how to update a new answer if I press "Back" and change the answer to a different one.
Secondly, how to fix my result table into bigger one because it looks small eventhough i try to change the width.
HTML
<div>
<div class="user-role">
<div class="question current">
<transition name="slide-fade" mode="out-in">
<div :key="questions[currentQuestion].question" :class="{deactivate: answered == questions.length}">
<h2>{{questions[currentQuestion].question }}</h2>
<div class="answers">
<span v-for="(answer, index) in questions[currentQuestion].answer" :key="index" v-bind:data-index="index" #click="selectAnswer">{{ answer }}</span>
</div>
<button class="back-btn" v-on:click="backBtn">Back</button>
<button class="next-btn" disabled v-on:click="nextBtn">{{ currentQuestion < (questions.length -1) ? "Next" : "Result!" }}</button>
</div>
</transition>
</div>
<div class="result">
<div class="success"></div>
<h2>Your score is:</h2>
<h1 :class="[(Number(((correctAnswers / questions.length) *100)).toFixed(2) >= 50)]">{{ Number(((correctAnswers / questions.length) *100)).toFixed(2) }}%</h1>
<small><b>{{ correctAnswers }}</b>Correct, <b>{{ wrongAnswers }}</b>Wrong</small>
<button v-on:click="Closeresult">CLOSE</button>
<button class="show-wrong-ones"
v-show= "wrongAnswers > 0"
#click="showWrongQuestion = true">Wrong answers
</button>
</div>
</div>
<div class="wrong-questions">
<h2 v-if="wrongQuestions.length > 1">Your wrong Questions</h2>
<h2 v-else-if="wrongQuestions.length == 1">Your wrong Question</h2>
<div class="wrong-one" v-for="question in wrongQuestions">
<h3>{{ question.question }}</h3>
<div class="answers-container">
<span class="selected">{{ question.answers[question.selected] }}</span>
<span class="correct">{{ question.answers[question.correct_answer] }}</span>
</div>
</div>
<button id="return-to-result">Show my result</button>
</div>
</div>
CSS
body {
font: Arial , sans-serif;
background: linear-gradient(#2d8dcb, #F0FFFF);
height: 100vh;
max-height: 100vh;
overflow: hidden;
}
h1.main{
font-weight: 100;
color: #FFFFFF;
text-align: center;
margin: 0;
}
.user-role {
transition: opacity .2s ease;
}
.user-role.mute {
opacity: .5;
}
.question{
max-width: 650px;
position: absolute;
top: 50%;
left: 50%;
transform: translateY(-50%) translateX(-250%);
background-color: rgba(255, 255, 255, .25);
color: #FFFFFF;
padding: 10px;
border-radius: 4px;
overflow: hidden;
transition: transform .4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
font-size: 30px;
}
.question.current {
transform: translateY(-50%) translateX(-50%);
}
.wrong.current {
transform: translateY(-50%) translateX(-50%);
}
.question.blur {
filter: blur(2px);
pointer-events: none;
}
.deactivate {
pointer-events: none;
}
.question h2{
min-width: calc(100% - 20px);
max-width: calc(100% - 20px);
background-color: transparent;
font-weight: 100;
padding: 0;
border-radius: 3px;
}
.question .answers {
display: flex;
flex-wrap: wrap;
color: #FFFFFF;
}
.question .answers span{
display: inline-block;
width: calc(50% - 5px);
max-width: calc(50% - 5px);
background-color: rgba(255, 255, 255, .5);
color: #FFFFFF;
font-size: 30px;
margin: 5px 5px 0 0;
padding: 5px;
border-radius: 3px;
cursor: pointer;
}
.question .answers span.selected {
animation: select-answer .5s ease;
background-color: #A52A2A;
}
#keyframes select-answer {
0% {
transform: scale(0.95);
}
100% {
transform: scale(1);
}
}
.question .next-question {
margin-top: 15px;
padding-right: 5px;
text-align: right;
}
.question .next-btn {
background-color: #F0F8FF;
border: none;
padding: 3px 20px;
border-radius: 3px;
font-size: 1.5em;
color: #FFFFFF;
cursor: pointer;
transition: all .5s ease;
}
.question .next-btn:hover {
outline: none;
background-color: #A52A2A;
}
.question .next-btn[disabled] {
opacity: .6;
cursor: no-drop;
}
.question .back-btn {
background-color: #F0F8FF;
border: none;
padding: 3px 20px;
border-radius: 3px;
font-size: 1.5em;
color: #FFFFFF;
cursor: pointer;
transition: all .5s ease;
}
.question .back-btn:hover {
outline: none;
background-color: #A52A2A;
}
.question .back-btn[disabled] {
opacity: .6;
cursor: no-drop;
}
.slide-fade-enter-active {
transition: all .3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
.slide-fade-leave-active {
transition: all .3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
.slide-fade-enter {
transform: translateY(-40%);
opacity: 0;
}
.slide-fade-leave-to {
transform: translateY(40%);
opacity: 0;
}
.status {
font-size: 0.8em;
margin: 3px auto 0;
text-align: center;
padding: 5px;
border-radius: 2px;
color: rgba(255, 255, 255, .5);
transition: color .3s ease;
}
.result{
max-width: 560px;
overflow: hidden;
text-align: center;
position: absolute;
top: -50%;
left: 50%;
transform: translateY(-50%) translateX(-50%);
padding: 15px;
border-radius: 5px;
background-color: #fff;
transition: all .3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
.result.active {
top: 50%;
left: 50%;
transform: translateY(-50%) translateX(-50%);
}
.result svg {
position: absolute;
opacity: 0.15
}
.result .success {
position: absolute;
top: -10px;
left: 10px;
width: calc(100% - 20px);
height: 100%;
opacity: 0.1;
}
.result h2 {
font-family: 'Bad Script', cursive;
font-weight: 400;
text-align: center;
}
.result h1 {
font-size: 2.3em;
font-weight: 400;
margin-bottom: -10px;
}
.result button {
position: absolute;
bottom: 5px;
background-color: transparent;
border-radius: 5px;
color: #FFFFFF;
cursor: pointer;
font-size: 10px;
transition: box-shadow .2s ease;
}
.result button.close {
right: 10px;
padding: 0 15px;
color: #A52A2A;
font-size: 25px;
}
.result button.show-wrong-ones {
left: 10px;
padding: 5px;
color: #A52A2A;
font-size: 20px;
}
.result button:hover {
box-shadow: 4px 6px 15px 1px #ddd;
}
.green {
color: #0dcc0d;
}
.red {
color: #d21d0f;
}
.wrong-questions {
width: 80vw;
max-height: 100vh;
text-align: center;
overflow-y: scroll;
padding: 5px;
position: absolute;
top: 150%;
left: 50%;
transform: translateY(-50%) translateX(-50%);
border-radius: 5px;
background-color:#000000;
color:#FFFFFF;
transition: all .4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
.wrong-questions.active {
top: 50%;
left: 50%;
transform: translateY(-50%) translateX(-50%);
}
.wrong-questions::-webkit-scrollbar-track {
border-radius: 10px;
}
.wrong-questions::-webkit-scrollbar {
width: 4px;
}
.wrong-questions::-webkit-scrollbar-thumb {
border-radius: 10px;
background-color: #e6e6e6;
}
.wrong-questions h2 {
font-weight: 100;
margin: 10px 0;
text-align: center;
color: #d21d0f;
}
.wrong-questions .wrong-one {
width: 90%;
text-align: left;
margin: 0 auto;
padding: 3px 7px;
border-bottom: 1px solid #eee;
}
.wrong-questions .wrong-one h3 {
font-weight: 100;
}
.wrong-questions .answers-container {
padding-right: 40px;
}
.wrong-questions .answers-container span {
display: block;
padding: 0 7px;
position: relative;
}
.wrong-questions .answers-container span:after {
position: absolute;
top: 0px;
right: -40px;
font-weight: 100;
font-size: .9em;
}
.wrong-questions .answers-container span.selected {
color: #d21d0f;
}
.wrong-questions .answers-container span.selected:after {
content: "Yours";
}
.wrong-questions .answers-container span.correct {
color: #0dcc0d;
}
.wrong-questions .answers-container span.correct:after {
content: "Correct";
right: -52px;
}
.wrong-questions button {
display: inline-block;
margin-top: 10px;
padding: 3px 10px;
background-color: transparent;
border: none;
outline: none;
border-radius: 5px;
color: #d21d0f;
cursor: pointer;
font-size: 1.05em;
font-family: 'Bad Script', cursive;
transition: box-shadow .2s ease;
}
.wrong-questions button:hover {
box-shadow: 4px 6px 15px 1px #ddd;
}
JsVue2
Vue.component('display-question',{
data: function(){
return{
showWrongQuestion: false,
wrongQuestions: [],
temp: [],
currentQuestion: 0,
answered: 0,
wrongAnswers: 0,
correctAnswers: 0,
questions: [
{
question: 'What is the capital of Ukrain ?',
answer: [
'Kyiv',
' Kabul',
' Buenos Aires',
' Praia'
],
correct_answer: 0,
selected: null,
sense: 0
},
{
question: 'When was Queen Elizabeth II death ?',
answer: [
'11/09/2022',
'08/09/2022',
'12/08/2022',
'07/09/2022'
],
correct_answer: 1,
selected: null,
sense: 0
},
{
question: 'How many bones are there in human body?',
answer: [
'206',
'186',
'209',
'190'
],
correct_answer: 0,
selected: null,
sense: 0
},
{
question: 'Who were the 30th president of ?',
answer: [
'Julia Eileen Gillard',
'John Winston Howard ',
' Scott John Morrison ',
'Anthony Albanese,'
],
correct_answer: 2,
selected: null,
sense: 0
},
{
question: 'What is the biggest continent?',
answer: [
'Oceania',
'Europe',
'Asia',
'Africa'
],
correct_answer: 2,
selected: null,
sense: 0
}
],
}},
methods: {
//select answer function
selectAnswer: function(a) {
var choice = a.currentTarget,
backBtn = document.querySelector('.back-btn'),
answers = document.querySelectorAll('.answers span'),
nextBtn = document.querySelector('.next-btn');
answers.forEach(answer => {
answer.classList.contains('selected') ? answer.classList.remove('selected') : '';
});
choice.classList.add('selected');
this.questions[this.currentQuestion].selected = choice.dataset.index;
nextBtn.removeAttribute('disabled');
backBtn.removeAttribute('disabled');
//Back button function
},
backBtn:function () {
var backbutton = this.$el.querySelector('.back-btn'),
answers = this.$el.querySelectorAll('.answers span'),
questionsLength = this.questions.length,
result = this.$el.querySelector('.result'),
question = this.$el.querySelector('.question');
if(!backbutton.hasAttribute('disabled') && this.currentQuestion >= (this.currentQuestion -1)) {
this.currentQuestion--;
answers.forEach(answer => {
answer.classList.contains('selected') ? answer.classList.remove('selected') : '';
})
}
else if(this.currentQuestion >= (questionsLength -1)) {
this.questions.forEach( (question) => {
if(question.selected == question.correct_answer && question.sense ==0) {
this.correctAnswers++;
question.sense = 1;
} else if(question.selected != question.correct_answer && question.sense ==0) {
this.wrongAnswers++;
question.sense = 1;
let temp = {};
temp.answers = question.answers;
temp.question = question.question;
temp.correct_answer = question.correct_answer;
temp.selected = question.selected;
this.wrongQuestions.push(temp);
}
});
result.classList.add('active');
question.classList.add('blur');
}
},
//Next button Function
nextBtn: function() {
var nextbutton = this.$el.querySelector('.next-btn'),
answers = this.$el.querySelectorAll('.answers span'),
questionsLength = this.questions.length,
result = this.$el.querySelector('.result'),
question = this.$el.querySelector('.question');
if(!nextbutton.hasAttribute('disabled') && this.currentQuestion < (questionsLength -1)) {
this.currentQuestion++;
answers.forEach(answer => {
answer.classList.contains('selected') ? answer.classList.remove('selected') : '';
}),
nextbutton.setAttribute('disabled', '');
}
else if(this.currentQuestion >= (questionsLength -1)) {
this.questions.forEach( (question) => {
if(question.selected == question.correct_answer && question.sense ==0) {
this.correctAnswers++;
question.sense = 1;
} else if(question.selected != question.correct_answer && question.sense ==0) {
this.wrongAnswers++;
question.sense = 1;
let temp = {};
temp.answers = question.answers;
temp.question = question.question;
temp.correct_answer = question.correct_answer;
temp.selected = question.selected;
this.wrongQuestions.push(temp);
}
});
result.classList.add('active');
question.classList.add('blur');
}
},
//calculate result
calculateResult: (questions) => {
var correct;
for(var i=0; i< questions.length; i++) {
this.questions[i].selected == questions[i].correct ? correct++ : '';
}
return (correct / questions.length) * 100;
},
//wrong answer button
wrongAnswersBtn: function() {
result.classList.remove('active');
wrongQuestions.classList.add('active');
},
//close result
Closeresult:function(){
var question = this.$el.querySelector('.question'),
result = this.$el.querySelector('.result');
result.classList.remove('active');
question.classList.remove('blur');
},
showMyResults: function(){
result.classList.add('active');
wrongQuestions.classList.remove('active');
},
},
template: '<div><div class="user-role"><div class="question current"><transition name="slide-fade" mode="out-in"><div :key="questions[currentQuestion].question" :class="{deactivate: answered == questions.length}"><h2>{{questions[currentQuestion].question }}</h2><div class="answers"><span v-for="(answer, index) in questions[currentQuestion].answer" :key="index" v-bind:data-index="index" #click="selectAnswer">{{ answer }}</span></div> <button class="back-btn" v-on:click="backBtn">Back</button> <button class="next-btn" disabled v-on:click="nextBtn">{{ currentQuestion < (questions.length -1) ? "Next" : "Result!" }}</button></div></transition></div><div class="result"><div class="success"></div><h2>Your score is:</h2><h1 :class="[(Number(((correctAnswers / questions.length) *100)).toFixed(2) >= 50)]">{{ Number(((correctAnswers / questions.length) *100)).toFixed(2) }}%</h1><small><b>{{ correctAnswers }}</b>Correct, <b>{{ wrongAnswers }}</b>Wrong</small> <button class=closeresult v-on:click="Closeresult">Close</button> <button class="show-wrong-ones"v-show= "wrongAnswers > 0"#click="showWrongQuestion = true">Wrong answers</button></div></div><div class="wrong-questions"><h2 v-if="wrongQuestions.length > 1">Your wrong Questions</h2> <div class="wrong-one" v-for="question in wrongQuestions"> <h3>{{ question.question }}</h3><div class="answers-container"></div></div> </div> </div>',
})
var test1 = new Vue({
el: "#app1",
data: {
},
});
if I understood correctly -
you need to move your question to a computed propery.
in the data section -
data(){
return{
currentQuestionIndex:0
}
}
in the computed section -
computed:{
currentQuestion(){
return this.questions[this.currentQuestionIndex];
}
}
now, every time the data property currentQuestionIndex will be changed, the computed property currentQuestion will be changed.
Hope its hopeful.

How to integrate AWS IVS with JW Player?

I'm trying to follow this IVS sample, the only difference is using the JW player, I following this documentation
The problem is that this snippet
jwplayer(videoPlayer).addEventListener(
PlayerEventType.TEXT_METADATA_CUE,
function (cue) {
const metadataText = cue.text;
const position = player.getPosition().toFixed(2);
console.log(
`Player Event - TEXT_METADATA_CUE: "${metadataText}". Observed ${position}s after playback started.`
);
triggerQuiz(metadataText);
}
);
is giving this error
script.js:60 Uncaught TypeError: Cannot read properties of undefined (reading 'TEXT_METADATA_CUE')
I'm either not adding an event listener to the jw player correctly or I'm doing something wrong while working with IVS.
My full code is below
const playbackUrl =
"https://fcc3ddae59ed.us-west-2.playback.live-video.net/api/video/v1/us-west-2.893648527354.channel.xhP3ExfcX8ON.m3u8";
const videoPlayer = document.getElementById("video-player");
const quizEl = document.getElementById("quiz");
const waitMessage = document.getElementById("waiting");
const questionEl = document.getElementById("question");
const answersEl = document.getElementById("answers");
const cardInnerEl = document.getElementById("card-inner");
var ivsPlayer = {};
var ivsEvents = {};
const ivsConfig = {
playlist: [
{
file: playbackUrl,
type: "ivs",
},
],
};
(function (ivsPlayer) {
jwplayer(videoPlayer)
.setup(ivsConfig)
.on("providerPlayer", function (player) {
console.log("Amazon IVS Player: ", player.ivsPlayer);
console.log("Amazon IVS Player Events: ", player.ivsEvents);
// store the reference to the Amazon IVS Player
ivsPlayer = player.ivsPlayer;
// store the reference to the Amazon IVS Player Events
ivsEvents = player.ivsEvents;
});
const PlayerState = ivsPlayer.PlayerState;
const PlayerEventType = ivsPlayer.PlayerEventType;
jwplayer(videoPlayer).addEventListener(
PlayerEventType.TEXT_METADATA_CUE,
function (cue) {
const metadataText = cue.text;
const position = player.getPosition().toFixed(2);
console.log(
`Player Event - TEXT_METADATA_CUE: "${metadataText}". Observed ${position}s after playback started.`
);
triggerQuiz(metadataText);
}
);
// Setup stream and play
// Remove card
function removeCard() {
quizEl.classList.toggle("drop");
}
// Trigger quiz
function triggerQuiz(metadataText) {
let obj = JSON.parse(metadataText);
quizEl.style.display = "";
quizEl.classList.remove("drop");
waitMessage.style.display = "none";
cardInnerEl.style.display = "none";
cardInnerEl.style.pointerEvents = "auto";
while (answersEl.firstChild) answersEl.removeChild(answersEl.firstChild);
questionEl.textContent = obj.question;
let createAnswers = function (obj, i) {
let q = document.createElement("a");
let qText = document.createTextNode(obj.answers[i]);
answersEl.appendChild(q);
q.classList.add("answer");
q.appendChild(qText);
q.addEventListener("click", (event) => {
cardInnerEl.style.pointerEvents = "none";
if (q.textContent === obj.answers[obj.correctIndex]) {
q.classList.toggle("correct");
} else {
q.classList.toggle("wrong");
}
setTimeout(function () {
removeCard();
waitMessage.style.display = "";
}, 1050);
return false;
});
};
for (var i = 0; i < obj.answers.length; i++) {
createAnswers(obj, i);
}
cardInnerEl.style.display = "";
}
waitMessage.style.display = "";
})(window.ivsPlayer);
Edit see the snippet
const playbackUrl =
"https://fcc3ddae59ed.us-west-2.playback.live-video.net/api/video/v1/us-west-2.893648527354.channel.xhP3ExfcX8ON.m3u8";
const ivsConfig = {
playlist: [
{
file: playbackUrl,
type: "ivs",
},
],
};
const videoPlayer = document.getElementById("video-player");
const quizEl = document.getElementById("quiz");
const waitMessage = document.getElementById("waiting");
const questionEl = document.getElementById("question");
const answersEl = document.getElementById("answers");
const cardInnerEl = document.getElementById("card-inner");
(async (IVSPlayer) => {
try {
const playerInstance = jwplayer(videoPlayer).setup(ivsConfig);
playerInstance.on("providerPlayer", function (player) {
console.log("Amazon IVS Player: ", player.ivsPlayer);
console.log("Amazon IVS Player Events: ", player.ivsEvents);
const PlayerEventType = player.ivsEvents;
playerInstance.addEventListener(
PlayerEventType.TEXT_METADATA_CUE,
function (cue) {
const metadataText = cue.text;
const position = player.getPosition().toFixed(2);
console.log(metadataText);
//console.log(
// `Player Event - TEXT_METADATA_CUE: "${metadataText}". Observed ${position}s after playback started.`
//);
//onsole.log(cue);
//triggerQuiz(metadataText);
}
);
});
} catch (e) {
console.error(e);
}
function triggerQuiz(metadataText) {
let obj = JSON.parse(metadataText);
quizEl.style.display = "";
quizEl.classList.remove("drop");
waitMessage.style.display = "none";
cardInnerEl.style.display = "none";
cardInnerEl.style.pointerEvents = "auto";
while (answersEl.firstChild) answersEl.removeChild(answersEl.firstChild);
questionEl.textContent = obj.question;
let createAnswers = function (obj, i) {
let q = document.createElement("a");
let qText = document.createTextNode(obj.answers[i]);
answersEl.appendChild(q);
q.classList.add("answer");
q.appendChild(qText);
q.addEventListener("click", (event) => {
cardInnerEl.style.pointerEvents = "none";
if (q.textContent === obj.answers[obj.correctIndex]) {
q.classList.toggle("correct");
} else {
q.classList.toggle("wrong");
}
setTimeout(function () {
removeCard();
waitMessage.style.display = "";
}, 1050);
return false;
});
};
for (var i = 0; i < obj.answers.length; i++) {
createAnswers(obj, i);
}
cardInnerEl.style.display = "";
}
waitMessage.style.display = "";
})(window.IVSPlayer);
/* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. */
/* SPDX-License-Identifier: MIT-0 */
/* Reset */
*,*::before,*::after{box-sizing:border-box}ul[class],ol[class]{padding:0}body,h1,h2,h3,h4,p,ul[class],ol[class],figure,blockquote,dl,dd{margin:0}html{scroll-behavior:smooth}body{min-height:100vh;text-rendering:optimizeSpeed;line-height:1.5}ul[class],ol[class]{list-style:none}a:not([class]){text-decoration-skip-ink:auto}img{max-width:100%;display:block}article>*+*{margin-top:1em}input,button,textarea,select{font:inherit}#media (prefers-reduced-motion:reduce){*{animation-duration:0.01ms!important;animation-iteration-count:1!important;transition-duration:0.01ms!important;scroll-behavior:auto!important}}
/* Variables */
:root {
--radius: 12px;
}
/* Style */
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
body {
overflow: hidden;
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", sans-serif;
user-select: none;
}
#app {
background: #334273;
height: 100%;
}
.inner {
max-width: 1080px;
display: flex;
flex-direction: column;
position: relative;
align-items: stretch;
margin: 0 auto;
padding: 40px;
}
.player-wrapper {
width: 100%;
position: relative;
overflow: hidden;
transform: translate3d(0, 0, 0);
backface-visibility: hidden;
border-radius: var(--radius);
box-shadow: 0 6px 30px rgba(0, 0, 0, 0.3);
z-index: 1;
}
.aspect-spacer {
padding-bottom: 56.25%;
}
.el-player {
width: 100%;
height: 100%;
position: absolute;
top: 0;
background: #000;
border-radius: var(--radius);
}
video {
width: 100%;
border-radius: var(--radius);
background: #000;
}
.quiz-wrap {
min-height: 460px;
position: relative;
transition: all 0.25s ease-in;
}
.card {
margin: 0 20px;
padding: 20px;
position: absolute;
left: 0;
right: 0;
background: #fff;
border-radius: 20px;
box-shadow: 0px 10px 20px rgba(0, 0, 0, 0.1);
transition: all 1s cubic-bezier(1, -0.56, 0, 1);
transform: translate3d(0, 0, 0) scale(1);
backface-visibility: hidden;
z-index: 1;
}
.card.drop {
opacity: 0;
transform: translate3d(0, 200px, -20px) scale(0.92);
}
h2 {
font-size: 25px;
text-align: center;
padding-bottom: 20px;
}
.answer {
height: 50px;
line-height: 50px;
font-size: 20px;
display: flex;
text-decoration: none;
border: 1px solid #d5dbdb;
border-radius: 50px;
padding: 0 24px;
margin: 10px 0;
background: #fafafa;
color: #545b64;
transition: all 0.05s ease-in-out;
}
.answer:hover {
background: #ebebebe0;
}
.answer:active {
background: #ff9900;
border: 1px solid #eb5f07;
color: #fff;
}
.answer.correct {
background: #25a702;
border: 1px solid #1d8102;
color: #fff;
animation: blink 0.45s infinite;
}
.answer.wrong {
background: #d13212;
border: 1px solid #b7290d;
color: #fff;
animation: blink 0.45s infinite;
}
#waiting {
top: 100px;
left: 0;
right: 0;
position: absolute;
display: flex;
align-items: center;
}
.waiting-text {
width: 100%;
display: block;
text-align: center;
font-size: 18px;
color: #d5dbdb;
}
.float {
transform: translateY(0px);
animation: float 6s ease-in-out infinite;
}
/* Utility - Position */
.pos-absolute {
position: absolute !important;
}
.pos-fixed {
position: fixed !important;
}
.pos-relative {
position: relative !important;
}
.top-0 {
top: 0 !important;
}
.bottom-0 {
bottom: 0 !important;
}
/* Utility - Width/Height */
.full-width {
width: 100%;
}
.full-height {
height: 100%;
}
/* Animations */
#keyframes blink {
50% {
opacity: 0.8;
}
}
#keyframes float {
0% {
transform: translateY(0px);
}
50% {
transform: translateY(-20px);
}
100% {
transform: translateY(0px);
}
}
/* Mediaqueries */
#media (max-width: 767px) {
h2 {
font-size: 20px;
}
.card {
top: -20px;
}
}
#media (min-width: 767px) {
.card {
top: -25%;
}
}
<head>
<script src="https://content.jwplatform.com/libraries/oH2wJDod.js"></script>
<script src="https://player.live-video.net/1.11.0/amazon-ivs-jw-provider.min.js"></script>
</head>
<body>
<div id="app">
<div class="inner">
<!-- Player wrapper, forcing 16:9 aspect ratio -->
<div class="player-wrapper">
<div class="aspect-spacer"></div>
<div class="pos-absolute full-width full-height top-0">
<div id="video-player"></div>
</div>
</div>
<!-- Quiz UI -->
<div class="quiz-wrap">
<div id="waiting">
<span class="waiting-text float"
>Waiting for the next question</span
>
</div>
<div id="quiz" class="card drop">
<div id="card-inner">
<h2 id="question"></h2>
<div id="answers"></div>
</div>
</div>
</div>
</div>
</div>
<script src="script.js"></script>
</body>
You are inside IIFE you can't declare outside of scope IIFE's are anonymous
Please read docume
const playbackUrl =
"https://fcc3ddae59ed.us-west-2.playback.live-video.net/api/video/v1/us-west-2.893648527354.channel.xhP3ExfcX8ON.m3u8";
const ivsConfig = {
playlist: [
{
file: playbackUrl,
type: "ivs"
}
]
};
const videoPlayer = document.getElementById("video-player");
const quizEl = document.getElementById("quiz");
const waitMessage = document.getElementById("waiting");
const questionEl = document.getElementById("question");
const answersEl = document.getElementById("answers");
const cardInnerEl = document.getElementById("card-inner");
(async (IVSPlayer) => {
try {
const playerInstance = jwplayer(videoPlayer).setup(ivsConfig);
playerInstance.on("providerPlayer", function (player) {
if (player) {
const { ivsEvents, ivsPlayer } = player;
ivsPlayer.addEventListener(
ivsEvents.PlayerEventType.TEXT_METADATA_CUE,
function (cue) {
const metadataText = cue.text;
// const position = player.getPosition().toFixed(2);
// position is under state.
const position = ivsPlayer.core.state.position.toFixed(2);
console.log(
`Player Event - TEXT_METADATA_CUE: "${metadataText}". Observed ${position}s after playback started.`
);
triggerQuiz(metadataText);
}
);
}
});
} catch (e) {
console.error(e);
}
function triggerQuiz(metadataText) {
let obj = JSON.parse(metadataText);
quizEl.style.display = "";
quizEl.classList.remove("drop");
waitMessage.style.display = "none";
cardInnerEl.style.display = "none";
cardInnerEl.style.pointerEvents = "auto";
while (answersEl.firstChild) answersEl.removeChild(answersEl.firstChild);
questionEl.textContent = obj.question;
let createAnswers = function (obj, i) {
let q = document.createElement("a");
let qText = document.createTextNode(obj.answers[i]);
answersEl.appendChild(q);
q.classList.add("answer");
q.appendChild(qText);
q.addEventListener("click", (event) => {
cardInnerEl.style.pointerEvents = "none";
if (q.textContent === obj.answers[obj.correctIndex]) {
q.classList.toggle("correct");
} else {
q.classList.toggle("wrong");
}
setTimeout(function () {
// removeCard(); is not defined. you must
// create it first
waitMessage.style.display = "";
}, 1050);
return false;
});
};
for (var i = 0; i < obj.answers.length; i++) {
createAnswers(obj, i);
}
cardInnerEl.style.display = "";
}
waitMessage.style.display = "";
})(window.IVSPlayer);
/* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. */
/* SPDX-License-Identifier: MIT-0 */
/* Reset */
*,
*::before,
*::after {
box-sizing: border-box;
}
ul[class],
ol[class] {
padding: 0;
}
body,
h1,
h2,
h3,
h4,
p,
ul[class],
ol[class],
figure,
blockquote,
dl,
dd {
margin: 0;
}
html {
scroll-behavior: smooth;
}
body {
min-height: 100vh;
text-rendering: optimizeSpeed;
line-height: 1.5;
}
ul[class],
ol[class] {
list-style: none;
}
a:not([class]) {
text-decoration-skip-ink: auto;
}
img {
max-width: 100%;
display: block;
}
article > * + * {
margin-top: 1em;
}
input,
button,
textarea,
select {
font: inherit;
}
#media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
/* Variables */
:root {
--radius: 12px;
}
/* Style */
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
body {
overflow: hidden;
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Ubuntu, "Helvetica Neue", sans-serif;
user-select: none;
}
#app {
background: #334273;
height: 100%;
}
.inner {
max-width: 1080px;
display: flex;
flex-direction: column;
position: relative;
align-items: stretch;
margin: 0 auto;
padding: 40px;
}
.player-wrapper {
width: 100%;
position: relative;
overflow: hidden;
transform: translate3d(0, 0, 0);
backface-visibility: hidden;
border-radius: var(--radius);
box-shadow: 0 6px 30px rgba(0, 0, 0, 0.3);
z-index: 1;
}
.aspect-spacer {
padding-bottom: 56.25%;
}
.el-player {
width: 100%;
height: 100%;
position: absolute;
top: 0;
background: #000;
border-radius: var(--radius);
}
video {
width: 100%;
border-radius: var(--radius);
background: #000;
}
.quiz-wrap {
min-height: 460px;
position: relative;
transition: all 0.25s ease-in;
}
.card {
margin: 0 20px;
padding: 20px;
position: absolute;
left: 0;
right: 0;
background: #fff;
border-radius: 20px;
box-shadow: 0px 10px 20px rgba(0, 0, 0, 0.1);
transition: all 1s cubic-bezier(1, -0.56, 0, 1);
transform: translate3d(0, 0, 0) scale(1);
backface-visibility: hidden;
z-index: 1;
}
.card.drop {
opacity: 0;
transform: translate3d(0, 200px, -20px) scale(0.92);
}
h2 {
font-size: 25px;
text-align: center;
padding-bottom: 20px;
}
.answer {
height: 50px;
line-height: 50px;
font-size: 20px;
display: flex;
text-decoration: none;
border: 1px solid #d5dbdb;
border-radius: 50px;
padding: 0 24px;
margin: 10px 0;
background: #fafafa;
color: #545b64;
transition: all 0.05s ease-in-out;
}
.answer:hover {
background: #ebebebe0;
}
.answer:active {
background: #ff9900;
border: 1px solid #eb5f07;
color: #fff;
}
.answer.correct {
background: #25a702;
border: 1px solid #1d8102;
color: #fff;
animation: blink 0.45s infinite;
}
.answer.wrong {
background: #d13212;
border: 1px solid #b7290d;
color: #fff;
animation: blink 0.45s infinite;
}
#waiting {
top: 100px;
left: 0;
right: 0;
position: absolute;
display: flex;
align-items: center;
}
.waiting-text {
width: 100%;
display: block;
text-align: center;
font-size: 18px;
color: #d5dbdb;
}
.float {
transform: translateY(0px);
animation: float 6s ease-in-out infinite;
}
/* Utility - Position */
.pos-absolute {
position: absolute !important;
}
.pos-fixed {
position: fixed !important;
}
.pos-relative {
position: relative !important;
}
.top-0 {
top: 0 !important;
}
.bottom-0 {
bottom: 0 !important;
}
/* Utility - Width/Height */
.full-width {
width: 100%;
}
.full-height {
height: 100%;
}
/* Animations */
#keyframes blink {
50% {
opacity: 0.8;
}
}
#keyframes float {
0% {
transform: translateY(0px);
}
50% {
transform: translateY(-20px);
}
100% {
transform: translateY(0px);
}
}
/* Mediaqueries */
#media (max-width: 767px) {
h2 {
font-size: 20px;
}
.card {
top: -20px;
}
}
#media (min-width: 767px) {
.card {
top: -25%;
}
}
<head>
<script src="https://content.jwplatform.com/libraries/oH2wJDod.js"></script>
<script src="https://player.live-video.net/1.11.0/amazon-ivs-jw-provider.min.js"></script>
</head>
<body>
<div id="app">
<div class="inner">
<!-- Player wrapper, forcing 16:9 aspect ratio -->
<div class="player-wrapper">
<div class="aspect-spacer"></div>
<div class="pos-absolute full-width full-height top-0">
<div id="video-player"></div>
</div>
</div>
<!-- Quiz UI -->
<div class="quiz-wrap">
<div id="waiting">
<span class="waiting-text float">Waiting for the next question</span>
</div>
<div id="quiz" class="card drop">
<div id="card-inner">
<h2 id="question"></h2>
<div id="answers"></div>
</div>
</div>
</div>
</div>
</div>
</body>

Why is my text going vertical at a certain width?

So I have an issue with my code where when my JavaScript types of a word (eg. Gamer) it limits to a certain width and ends up going vertical instead of horizontal.
Here are all the classes and code for the text:
// TYPEWRITER //
const typedTextSpan = document.querySelector(".typed-text");
const cursorSpan = document.querySelector(".cursor");
const textArray = ["YouTuber", "Writer", "Designer", "Creator", "Programmer", "Gamer"]
const typingDelay = 200;
const erasingDelay = 100;
const newTextDelay = 2000;
let textArrayIndex = 0;
let charIndex = 0;
function type() {
if(charIndex < textArray[textArrayIndex].length) {
if(!cursorSpan.classList.contains("typing")) cursorSpan.classList.add("typing");
typedTextSpan.textContent += textArray[textArrayIndex].charAt(charIndex);
charIndex++;
setTimeout(type, typingDelay);
}
else {
cursorSpan.classList.remove("typing");
setTimeout(erase, newTextDelay);
}
}
function erase() {
if(charIndex > 0) {
if(!cursorSpan.classList.contains("typing")) cursorSpan.classList.add("typing");
typedTextSpan.textContent = textArray[textArrayIndex].substring(0,charIndex-1);
charIndex--;
setTimeout(erase, erasingDelay)
}
else {
cursorSpan.classList.remove("typing");
textArrayIndex++;
if(textArrayIndex>=textArray.length) textArrayIndex=0;
setTimeout(type, typingDelay + 800);
}
}
document.addEventListener("DOMContentLoaded", function() {
if(textArray.length) setTimeout(type, newTextDelay + 250);
});
/* CUSTOMIZATION */
body {
margin: 0;
padding: 0;
background-color: #494949;
}
h1 {
position: relative;
font-size: 10vw;
}
/* TYPEWRITER */
.textbody {
margin-top: 10vh;
font-family: "Source Sans Pro", sans-serif;
font-weight: bold;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
max-width: 100%;
color: white;
}
.typed-text {
font-weight: normal;
color: #dd7732;
}
.cursor {
display: inline-block;
width: 3px;
background-color: #ccc;
margin-left: 0.1rem;
animation: blink 1s infinite;
}
.cursor.typing {
animation: none;
}
<body>
<div class="textbody">
<h1>
I am a <span class="typed-text"></span><span class="cursor typing"> </span>
</h1>
</div>
</body>
I had a flexbox in it and it fixed it adding 3 lines and making it look very weird, so that's a start.
I noticed none of the classes under the TYPEWRITER comment in CSS do anything to the problem. I believe it has to do something with the other two or the JavaScript.
Change max-width to width : 100%; into the .textbody and to put it in center add display: flex;
.textbody {
margin-top: 10vh;
font-family: "Source Sans Pro", sans-serif;
font-weight: bold;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100%;
display: flex;
justify-content: center;
color: white;
}

Toggle between 2 divs - visibility and css animation

In my site, I have two divs within a container. One div has text in English and the other has text in mandarin I have a button on the side that I want the user to toggle and control the visibility of each div/language they are comfortable with. I'm using JS to add/remove class visibility (opacity and display). By default, I have the English one in view. My sketch works halfway, when a user clicks the button, the English div fades but the mandarin one doesn't appear. Code below-
HTML -
<div class="textSection">
<div class="eng about" id="eng">
<p>SHEK LEUNG
</p>
</div>
<div class="mandarin about" id="man">
<p>
「為Samson畢業後在倫敦創立的品牌
</p>
</div>
</div>
<button class="langChange">⥃</button>
css -
.textSection {
width: 50vw;
height: 80vh;
position: relative;
top: 10vh;
left: 30vw;
display: flex;
justify-content: center;
align-items: center;
}
.about {
position: absolute;
width: 100%;
height: 100%;
opacity: 1;
box-sizing: border-box;
transition: all 1s;
}
.eng {
border-radius: 10px;
background: url("72ppi/Asset\ 3.png");
background-size: 100% 100%;
font-family: Helvetica, sans-serif;
font-weight: bold;
font-size: 1.2rem;
line-height: 1.7;
text-align: justify;
text-transform: uppercase;
color: white;
padding: 3rem;
opacity: 1;
display: block;
}
.mandarin {
font-family: Hiragino Sans GB;
font-size: 1.3rem;
line-height: 2;
text-align: justify;
text-transform: uppercase;
font-weight: bold;
color: black;
padding: 3rem;
opacity: 1;
border-radius: 10px;
border: solid 2px black;
opacity: 0;
display: none;
}
.hidden {
display: none;
}
.visuallyhidden {
opacity: 0;
}
.seen {
display: block;
}
.visual {
opacity: 1;
}
.langChange {
position: absolute;
border: none;
padding: 1rem 2rem;
border-radius: 10px;
margin: 0;
text-decoration: none;
font-size: 2rem;
left: 20vw;
cursor: pointer;
background-color: transparent;
color: black;
}
JS -
let engBox = document.getElementById('eng'),
manBox = document.getElementById('man')
langbtn = document.querySelector('.langChange');
langbtn.addEventListener('click', function () {
console.log(engBox.classList);
if (engBox.classList.contains('hidden')) {
engBox.classList.remove('hidden');
setTimeout(function () {
engBox.classList.remove('visuallyhidden');
}, 20);
} else {
engBox.classList.add('visuallyhidden');
engBox.addEventListener('transitionend', function (e) {
engBox.classList.add('hidden');
}, {
capture: false,
once: true,
passive: false
});
}
}, false);
langbtn.addEventListener('click', function () {
console.log(manBox.classList);
if (manBox.classList.contains('seen')) {
manBox.classList.remove('seen');
setTimeout(function () {
manBox.classList.remove('visual');
}, 20);
} else {
manBox.classList.add('seen');
manBox.addEventListener('transitionend', function (e) {
manBox.classList.add('seen');
}, {
capture: false,
once: true,
passive: false
});
}
}, false);
Start simple and build up. Here is a minimal working visibility toggle. Position changes, layout, and most timing can be added to the CSS piece by piece until you have what you want.
const engBox = document.getElementById('eng');
const manBox = document.getElementById('man');
const langbtn = document.querySelector('.langChange');
langbtn.addEventListener('click', function () {
engBox.classList.toggle('transparent');
manBox.classList.toggle('transparent');
});
.about {
overflow: hidden;
transition: all 2s;
}
.transparent {
opacity: 0;
}
<div class="textSection">
<div class="eng about" id="eng">
<p>SHEK LEUNG
</p>
</div>
<div class="mandarin about transparent" id="man">
<p>
「為Samson畢業後在倫敦創立的品牌
</p>
</div>
</div>
<button class="langChange">⥃</button>
</div>

Adding time counter to my memory game script

I'm trying to figure out the best way of adding a time counter to my memory game. The game consists of a lot of squares and if the user has figured out and won the game, a modal pops up and tells the user that they have won and offers to reset the game to start over.
I want to add the time the user spent playing the game. Since they have opened the page it should count the time from 0 to x seconds, and later when the user finishes the game, it echo's the score on the modal, so the user can see their score. But if someone did not complete the quiz in x seconds, a function runs that opens modal, but this time echo's that person has run out of time and offers to start over.
I'm using a small remake of this game on codepen
HTML:
<div class="modal-overlay">
<div class="modal">
<h2 class="winner">You Rock!</h2>
<button class="restart">Play Again?</button>
<p class="message">Developed on CodePen by Nate Wiley</p>
<p class="share-text">Share it?</p>
<ul class="social">
<li><a target="_blank" class="twitter" href="http://twitter.com/share?url=http://codepen.io/natewiley/pen/HBrbL"><span class="brandico-twitter-bird"></span></a></li>
<li><a target="_blank" class="facebook" href="http://www.facebook.com/sharer.php?u=http://codepen.io/natewiley/pen/HBrbL"><span class="brandico-facebook"></span></a></li>
<li><a target="_blank" class="google" href="https://plus.google.com/share?url=http://codepen.io/natewiley/pen/HBrbL"><span class="brandico-googleplus-rect"></span></a></li>
</ul>
</div>
</div>
All logos are property of their respective owners, No Copyright infringement intended.
The CSS part:
#import url(http://weloveiconfonts.com/api/?family=brandico);
/* brandico */
[class*="brandico-"]:before {
font-family: 'brandico', sans-serif;
}
* {
box-sizing: border-box;
}
html, body {
height: 100%;
}
body {
background: black;
min-height: 100%;
font-family: "Arial", sans-serif;
}
.wrap {
position: relative;
height: 100%;
min-height: 500px;
padding-bottom: 20px;
}
.game {
transform-style: preserve-3d;
perspective: 500px;
min-height: 100%;
height: 100%;
}
#mixin width($max){
#media (max-width: $max){
#content;
}
}
#keyframes matchAnim {
0% {
background: #bcffcc;
}
100% {
background: white;
}
}
.card {
float: left;
width: 16.66666%;
height: 25%;
padding: 5px;
text-align: center;
display: block;
perspective: 500px;
position: relative;
cursor: pointer;
z-index: 50;
-webkit-tap-highlight-color: rgba(0,0,0,0);
#include width(800px){
width: 25%;
height: 16.666%;
}
.inside {
width: 100%;
height: 100%;
display: block;
transform-style: preserve-3d;
transition: .4s ease-in-out;
background: white;
&.picked, &.matched {
transform: rotateY(180deg);
}
&.matched {
animation: 1s matchAnim ease-in-out;
animation-delay: .4s;
}
}
.front, .back {
border: 1px solid black;
backface-visibility: hidden;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
padding: 20px;
img {
max-width: 100%;
display: block;
margin: 0 auto;
max-height: 100%;
}
}
.front {
transform: rotateY(-180deg);
#include width(800px){
padding: 5px;
}
}
.back{
#include width(800px){
padding: 10px;
}
}
}
.modal-overlay {
display: none;
background: rgba(0,0,0,.8);
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.modal {
display: none;
position: relative;
width: 500px;
height: 400px;
max-height: 90%;
max-width: 90%;
min-height: 380px;
margin: 0 auto;
background: white;
top: 50%;
transform: translateY(-50%);
padding: 30px 10px;
.winner {
font-size: 80px;
text-align: center;
font-family: "Anton", sans-serif;
color: #4d4d4d;
text-shadow: 0px 3px 0 black;
#include width(480px){
font-size: 60px;
}
}
.restart {
font-family: "Anton", sans-serif;
margin: 30px auto;
padding: 20px 30px;
display: block;
font-size: 30px;
border: none;
background: #4d4d4d;
background: linear-gradient(#4d4d4d, #222);
border: 1px solid #222;
border-radius: 5px;
color: white;
text-shadow: 0px 1px 0 black;
cursor: pointer;
&:hover {
background: linear-gradient(#222, black);
}
}
.message {
text-align: center;
a {
text-decoration: none;
color: #28afe6;
font-weight: bold;
&:hover {
$c: lighten(#28afe6, 10%);
color: $c;
border-bottom: 1px dotted $c;
}
}
}
.share-text {
text-align: center;
margin: 10px auto;
}
.social {
margin: 20px auto;
text-align: center;
li {
display: inline-block;
height: 50px;
width: 50px;
margin-right: 10px;
&:last-child {
margin-right: 0;
}
a {
display: block;
line-height: 50px;
font-size: 20px;
color: white;
text-decoration: none;
border-radius: 5px;
&.facebook {
background: #3b5998;
&:hover {
background: lighten(#3b5998, 10%);
}
}
&.google {
background: #D34836;
&:hover {
background: lighten(#D34836, 10%);
}
}
&.twitter {
background: #4099FF;
&:hover {
background: lighten(#4099FF, 10%);
}
}
}
}
}
}
footer {
height: 20px;
position: absolute;
bottom: 0;
width: 100%;
z-index: 0;
.disclaimer {
line-height: 20px;
font-size: 12px;
color: #727272;
text-align: center;
#include width(767px){
font-size: 8px;
}
}
}
And js:
(function(){
var Memory = {
init: function(cards){
this.$game = $(".game");
this.$modal = $(".modal");
this.$overlay = $(".modal-overlay");
this.$restartButton = $("button.restart");
this.cardsArray = $.merge(cards, cards);
this.shuffleCards(this.cardsArray);
this.setup();
},
shuffleCards: function(cardsArray){
this.$cards = $(this.shuffle(this.cardsArray));
},
setup: function(){
this.html = this.buildHTML();
this.$game.html(this.html);
this.$memoryCards = $(".card");
this.binding();
this.paused = false;
this.guess = null;
},
binding: function(){
this.$memoryCards.on("click", this.cardClicked);
this.$restartButton.on("click", $.proxy(this.reset, this));
},
// kinda messy but hey
cardClicked: function(){
var _ = Memory;
var $card = $(this);
if(!_.paused && !$card.find(".inside").hasClass("matched") && !$card.find(".inside").hasClass("picked")){
$card.find(".inside").addClass("picked");
if(!_.guess){
_.guess = $(this).attr("data-id");
} else if(_.guess == $(this).attr("data-id") && !$(this).hasClass("picked")){
$(".picked").addClass("matched");
_.guess = null;
} else {
_.guess = null;
_.paused = true;
setTimeout(function(){
$(".picked").removeClass("picked");
Memory.paused = false;
}, 600);
}
if($(".matched").length == $(".card").length){
_.win();
}
}
},
win: function(){
this.paused = true;
setTimeout(function(){
Memory.showModal();
Memory.$game.fadeOut();
}, 1000);
},
showModal: function(){
this.$overlay.show();
this.$modal.fadeIn("slow");
},
hideModal: function(){
this.$overlay.hide();
this.$modal.hide();
},
reset: function(){
this.hideModal();
this.shuffleCards(this.cardsArray);
this.setup();
this.$game.show("slow");
},
// Fisher--Yates Algorithm -- http://bost.ocks.org/mike/shuffle/
shuffle: function(array){
var counter = array.length, temp, index;
// While there are elements in the array
while (counter > 0) {
// Pick a random index
index = Math.floor(Math.random() * counter);
// Decrease counter by 1
counter--;
// And swap the last element with it
temp = array[counter];
array[counter] = array[index];
array[index] = temp;
}
return array;
},
buildHTML: function(){
var frag = '';
this.$cards.each(function(k, v){
frag += '<div class="card" data-id="'+ v.id +'"><div class="inside">\
<div class="front"><img src="'+ v.img +'"\
alt="'+ v.name +'" /></div>\
<div class="back"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/74196/codepen-logo.png"\
alt="Codepen" /></div></div>\
</div>';
});
return frag;
}
};
var cards = [
{
name: "php",
img: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/74196/php-logo_1.png",
id: 1,
},
{
name: "css3",
img: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/74196/css3-logo.png",
id: 2
},
{
name: "html5",
img: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/74196/html5-logo.png",
id: 3
},
{
name: "jquery",
img: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/74196/jquery-logo.png",
id: 4
},
{
name: "javascript",
img: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/74196/js-logo.png",
id: 5
},
{
name: "node",
img: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/74196/nodejs-logo.png",
id: 6
},
{
name: "photoshop",
img: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/74196/photoshop-logo.png",
id: 7
},
{
name: "python",
img: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/74196/python-logo.png",
id: 8
},
{
name: "rails",
img: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/74196/rails-logo.png",
id: 9
},
{
name: "sass",
img: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/74196/sass-logo.png",
id: 10
},
{
name: "sublime",
img: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/74196/sublime-logo.png",
id: 11
},
{
name: "wordpress",
img: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/74196/wordpress-logo.png",
id: 12
},
];
Memory.init(cards);
})();
You can accomplish a timer functionality with using setTimeout recursively or setInterval like so:
(function () {
var timeContainer = document.getElementById("timer-value");
var startButton = document.getElementById("start-game");
var timer = 0;
var maxTime = 30;
var timeout = null;
function count () {
timeout = setTimeout(function () {
if (timer < maxTime) {
timer++;
timeContainer.innerText = timer;
count();
}
else {
alert("Time's up!");
startButton.style.display = "inline-block";
}
}, 1000);
}
function endGame () {
clearTimeout(timeout);
startButton.style.display = "inline-block";
alert("You completed the game in time!");
}
function startGame () {
if (timeout) { clearTimeout(timeout); }
timer = 0;
timeContainer.innerText = timer;
this.style.display = "none";
count();
}
document.getElementById("start-game").addEventListener("click", startGame);
document.getElementById("end-game").addEventListener("click", endGame);
})();
<h3>Timer: <span id="timer-value">0</span></h3>
<button id="start-game">Start Game</button> <button id="end-game">End Game</button>

Categories