Hello I'm trying to use translate Y (100%) in a child element
so that it is exactly below the total height of the parent element
but this is not happening:
I need my options box to be exactly below the total height of the parent element
something like that:
In this photo above the box is exactly below the box that shows the option currently active and in my example for some reason I can't do that.
const data = [
{
id: 1,
name: "SIMPLES NACIONAL – MEI",
funcionarioIncrease: 49.99,
maxFuncionario: 1,
socioIncrease: 0,
maxSocio: 5,
FATURAMENTO: [
{
name: "ATÉ 30.000,00",
value: 49.99,
},
{
name: "De 30.001,00 a 50.000,00 ",
value: 99.99,
},
],
},
{
id: 2,
name: "SIMPLES NACIONAL – SERVIÇOS",
funcionarioIncrease: 25,
maxFuncionario: 3,
socioIncrease: 25,
maxSocio: 5,
FATURAMENTO: [
{
name: "ATÉ 30.000,00",
value: 149.99,
},
{
name: "De 30.001,00 a 50.000,00 ",
value: 199.99,
},
],
},
];
function createInput(id, value) {
var inputRadio = document.createElement("input");
if (id && value) {
inputRadio.id = value;
inputRadio.name = "category";
inputRadio.type = "radio";
inputRadio.value = value;
inputRadio.classList.add("radio");
return inputRadio;
}
return null;
}
function createOptions() {
const container = document.querySelector(".options-container");
data.forEach((value) => {
const optionDiv = document.createElement("div");
optionDiv.classList.add("option");
container.append(optionDiv);
const input = createInput(value.name, value.id);
if (!input) {
return null;
}
optionDiv.append(input);
var label = document.createElement("label");
label.htmlFor = value.id;
label.innerHTML = value.name;
optionDiv.append(label);
});
}
function initalize() {
createOptions();
const selected = document.querySelector(".selected");
const optionsContainer = document.querySelector(".options-container");
const optionsList = document.querySelectorAll(".option");
selected.addEventListener("click", () => {
optionsContainer.classList.toggle("active");
});
optionsList.forEach((o) => {
o.addEventListener("click", () => {
let input = o.querySelector("input").id;
selected.innerHTML = o.querySelector("label").innerHTML;
selected.setAttribute("data-value", input);
optionsContainer.classList.remove("active");
});
});
}
initalize();
.select-box {
display: flex;
width: 100%;
max-height: 50px;
flex-direction: column;
position: relative;
z-index: 2;
}
.select-box .options-container {
background: #2f3640;
color: #f5f6fa;
max-height: 0;
width: 100%;
opacity: 0;
transition: all 0.4s;
border-radius: 8px;
overflow: hidden;
position: absolute;
order: 1;
transform: translateY(100%);
z-index: 2;
}
.selected {
background: #2f3640;
border-radius: 8px;
margin-bottom: 8px;
color: #f5f6fa;
position: relative;
order: 0;
}
.selected::after {
content: "";
background: url("img/arrow-down.svg");
background-size: contain;
background-repeat: no-repeat;
position: absolute;
height: 100%;
width: 32px;
right: 10px;
top: 5px;
transition: all 0.4s;
}
.select-box .options-container.active {
max-height: 240px;
opacity: 1;
overflow-y: scroll;
}
.select-box .options-container.active + .selected::after {
transform: rotateX(180deg);
top: -6px;
}
.select-box .options-container::-webkit-scrollbar {
width: 8px;
background: #0d141f;
border-radius: 0 8px 8px 0;
}
.select-box .options-container::-webkit-scrollbar-thumb {
background: #525861;
border-radius: 0 8px 8px 0;
}
.select-box .option,
.selected {
padding: 12px 24px;
cursor: pointer;
}
.select-box .option:hover {
background: #414b57;
}
.select-box label {
cursor: pointer;
color: white;
}
.select-box .option .radio {
display: none;
}
<div class="inputs_container">
<div class="service_mode flex">
<div class="select-box">
<div class="options-container"></div>
<div class="selected">
Select Video Category
</div>
</div>
</div>
</div>
Just add top position as 100% and remove translate.
const data = [
{
id: 1,
name: "SIMPLES NACIONAL – MEI",
funcionarioIncrease: 49.99,
maxFuncionario: 1,
socioIncrease: 0,
maxSocio: 5,
FATURAMENTO: [
{
name: "ATÉ 30.000,00",
value: 49.99,
},
{
name: "De 30.001,00 a 50.000,00 ",
value: 99.99,
},
],
},
{
id: 2,
name: "SIMPLES NACIONAL – SERVIÇOS",
funcionarioIncrease: 25,
maxFuncionario: 3,
socioIncrease: 25,
maxSocio: 5,
FATURAMENTO: [
{
name: "ATÉ 30.000,00",
value: 149.99,
},
{
name: "De 30.001,00 a 50.000,00 ",
value: 199.99,
},
],
},
];
function createInput(id, value) {
var inputRadio = document.createElement("input");
if (id && value) {
inputRadio.id = value;
inputRadio.name = "category";
inputRadio.type = "radio";
inputRadio.value = value;
inputRadio.classList.add("radio");
return inputRadio;
}
return null;
}
function createOptions() {
const container = document.querySelector(".options-container");
data.forEach((value) => {
const optionDiv = document.createElement("div");
optionDiv.classList.add("option");
container.append(optionDiv);
const input = createInput(value.name, value.id);
if (!input) {
return null;
}
optionDiv.append(input);
var label = document.createElement("label");
label.htmlFor = value.id;
label.innerHTML = value.name;
optionDiv.append(label);
});
}
function initalize() {
createOptions();
const selected = document.querySelector(".selected");
const optionsContainer = document.querySelector(".options-container");
const optionsList = document.querySelectorAll(".option");
selected.addEventListener("click", () => {
optionsContainer.classList.toggle("active");
});
optionsList.forEach((o) => {
o.addEventListener("click", () => {
let input = o.querySelector("input").id;
selected.innerHTML = o.querySelector("label").innerHTML;
selected.setAttribute("data-value", input);
optionsContainer.classList.remove("active");
});
});
}
initalize();
.select-box {
display: flex;
width: 100%;
max-height: 50px;
flex-direction: column;
position: relative;
z-index: 2;
}
.select-box .options-container {
background: #2f3640;
color: #f5f6fa;
max-height: 0;
width: 100%;
opacity: 0;
transition: all 0.4s;
border-radius: 8px;
overflow: hidden;
position: absolute;
top:100%;
order: 1;
z-index: 2;
}
.selected {
background: #2f3640;
border-radius: 8px;
margin-bottom: 8px;
color: #f5f6fa;
position: relative;
order: 0;
}
.selected::after {
content: "";
background: url("img/arrow-down.svg");
background-size: contain;
background-repeat: no-repeat;
position: absolute;
height: 100%;
width: 32px;
right: 10px;
top: 5px;
transition: all 0.4s;
}
.select-box .options-container.active {
max-height: 240px;
opacity: 1;
overflow-y: scroll;
}
.select-box .options-container.active + .selected::after {
transform: rotateX(180deg);
top: -6px;
}
.select-box .options-container::-webkit-scrollbar {
width: 8px;
background: #0d141f;
border-radius: 0 8px 8px 0;
}
.select-box .options-container::-webkit-scrollbar-thumb {
background: #525861;
border-radius: 0 8px 8px 0;
}
.select-box .option,
.selected {
padding: 12px 24px;
cursor: pointer;
}
.select-box .option:hover {
background: #414b57;
}
.select-box label {
cursor: pointer;
color: white;
}
.select-box .option .radio {
display: none;
}
<div class="inputs_container">
<div class="service_mode flex">
<div class="select-box">
<div class="options-container"></div>
<div class="selected">
Select Video Category
</div>
</div>
</div>
</div>
Related
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>
Hello i'm trying to make an up arrow like this:
but i got this :
I am not able to rotate the direction of the arrow
I already tried to change the rotate to 360, 90
and it doesn't work I'm not able to do something like the image I posted
const data = [
{
id: 1,
name: "SIMPLES NACIONAL – MEI",
funcionarioIncrease: 49.99,
maxFuncionario: 1,
socioIncrease: 0,
maxSocio: 5,
FATURAMENTO: [
{
name: "ATÉ 30.000,00",
value: 49.99,
},
{
name: "De 30.001,00 a 50.000,00 ",
value: 99.99,
},
],
},
{
id: 2,
name: "SIMPLES NACIONAL – SERVIÇOS",
funcionarioIncrease: 25,
maxFuncionario: 3,
socioIncrease: 25,
maxSocio: 5,
FATURAMENTO: [
{
name: "ATÉ 30.000,00",
value: 149.99,
},
{
name: "De 30.001,00 a 50.000,00 ",
value: 199.99,
},
],
},
];
function createInput(id, value) {
var inputRadio = document.createElement("input");
if (id && value) {
inputRadio.id = value;
inputRadio.name = "category";
inputRadio.type = "radio";
inputRadio.value = value;
inputRadio.classList.add("radio");
return inputRadio;
}
return null;
}
function createOptions() {
const container = document.querySelector(".options-container");
data.forEach((value) => {
const optionDiv = document.createElement("div");
optionDiv.classList.add("option");
container.append(optionDiv);
const input = createInput(value.name, value.id);
if (!input) {
return null;
}
optionDiv.append(input);
var label = document.createElement("label");
label.htmlFor = value.id;
label.innerHTML = value.name;
optionDiv.append(label);
});
}
function initalize() {
createOptions();
const selected = document.querySelector(".selected");
const optionsContainer = document.querySelector(".options-container");
const optionsList = document.querySelectorAll(".option");
selected.addEventListener("click", () => {
optionsContainer.classList.toggle("active");
});
optionsList.forEach((o) => {
o.addEventListener("click", () => {
let input = o.querySelector("input").id;
selected.innerHTML = o.querySelector("label").innerHTML;
selected.setAttribute("data-value", input);
optionsContainer.classList.remove("active");
});
});
}
initalize();
.select-box {
display: flex;
width: 100%;
max-height: 50px;
flex-direction: column;
position: relative;
z-index: 2;
}
.select-box .options-container {
background: #2f3640;
color: #f5f6fa;
max-height: 0;
width: 100%;
opacity: 0;
transition: all 0.4s;
border-radius: 8px;
overflow: hidden;
position: absolute;
order: 1;
top: 100%;
z-index: 2;
}
.select-box .options-container::before {
position: absolute;
display: block;
content: "";
bottom: 100%;
right: 25px;
width: 7px;
height: 7px;
margin-bottom: -4px;
border-top: 1px solid #b5b5b5;
border-left: 1px solid #b5b5b5;
background: blue;
transform: rotate(45deg);
transition: all 0.4s ease-in-out;
}
.selected {
background: #2f3640;
border-radius: 8px;
margin-bottom: 8px;
color: #f5f6fa;
position: relative;
order: 0;
}
.selected::after {
position: absolute;
display: block;
content: "";
width: 10px;
height: 10px;
top: 50%;
right: 25px;
margin-top: -3px;
border-bottom: 1px solid #fff;
border-right: 1px solid #fff;
transform: rotate(45deg) translateY(-50%);
transition: all 0.4s ease-in-out;
transform-origin: 50% 0;
transition: all 0.4s;
}
.select-box .options-container.active {
max-height: 240px;
opacity: 1;
}
.select-box .options-container.active + .selected::after {
margin-top: 3px;
transform: rotate(-135deg) translateY(-50%);
}
.select-box .options-container::-webkit-scrollbar {
width: 8px;
background: #0d141f;
border-radius: 0 8px 8px 0;
}
.select-box .options-container::-webkit-scrollbar-thumb {
background: #525861;
border-radius: 0 8px 8px 0;
}
.select-box .option,
.selected {
padding: 12px 24px;
cursor: pointer;
}
.select-box .option:hover {
background: #414b57;
}
.select-box label {
cursor: pointer;
color: white;
}
.select-box .option .radio {
display: none;
}
<div class="inputs_container">
<div class="service_mode flex">
<div class="select-box">
<div class="options-container"></div>
<div class="selected">
Select Video Category
</div>
</div>
</div>
if anyone can help me i would be grateful
the css class I'm trying to add to the arrow is this:
.select-box .options-container::before
Here is one I think I made it clear the change is not hard to see mean that you will see where I made it but let me make something clear I removed width and height and alter the border-top to 10px solid transparent and border-right from 10px solid green to 10px solid #2f3640 to make its appearance so good
const data = [{
id: 1,
name: "SIMPLES NACIONAL – MEI",
funcionarioIncrease: 49.99,
maxFuncionario: 1,
socioIncrease: 0,
maxSocio: 5,
FATURAMENTO: [{
name: "ATÉ 30.000,00",
value: 49.99,
},
{
name: "De 30.001,00 a 50.000,00 ",
value: 99.99,
},
],
},
{
id: 2,
name: "SIMPLES NACIONAL – SERVIÇOS",
funcionarioIncrease: 25,
maxFuncionario: 3,
socioIncrease: 25,
maxSocio: 5,
FATURAMENTO: [{
name: "ATÉ 30.000,00",
value: 149.99,
},
{
name: "De 30.001,00 a 50.000,00 ",
value: 199.99,
},
],
},
];
function createInput(id, value) {
var inputRadio = document.createElement("input");
if (id && value) {
inputRadio.id = value;
inputRadio.name = "category";
inputRadio.type = "radio";
inputRadio.value = value;
inputRadio.classList.add("radio");
return inputRadio;
}
return null;
}
function createOptions() {
const container = document.querySelector(".options-container");
data.forEach((value) => {
const optionDiv = document.createElement("div");
optionDiv.classList.add("option");
container.append(optionDiv);
const input = createInput(value.name, value.id);
if (!input) {
return null;
}
optionDiv.append(input);
var label = document.createElement("label");
label.htmlFor = value.id;
label.innerHTML = value.name;
optionDiv.append(label);
});
}
function initalize() {
createOptions();
const selected = document.querySelector(".selected");
const optionsContainer = document.querySelector(".options-container");
const optionsList = document.querySelectorAll(".option");
selected.addEventListener("click", () => {
optionsContainer.classList.toggle("active");
});
optionsList.forEach((o) => {
o.addEventListener("click", () => {
let input = o.querySelector("input").id;
selected.innerHTML = o.querySelector("label").innerHTML;
selected.setAttribute("data-value", input);
optionsContainer.classList.remove("active");
});
});
}
initalize();
.select-box {
display: flex;
width: 100%;
max-height: 50px;
flex-direction: column;
position: relative;
z-index: 2;
}
.select-box .options-container {
background: #2f3640;
color: #f5f6fa;
max-height: 0;
width: 100%;
opacity: 0;
transition: all 0.4s;
border-radius: 8px;
/*overflow: hidden;*/
position: absolute;
order: 1;
top: 100%;
z-index: 2;
}
.select-box .options-container::before {
position: absolute;
display: block;
content: "";
bottom: 100%;
right: 25px;
/*width: 7px;
height: 7px;*/
margin-bottom: -6px;
border-top: 10px solid transparent;
border-right: 10px solid #2f3640/*green*/
;
/*background: blue;*/
transform: rotate(225deg);
transition: all 0.4s ease-in-out;
}
.selected {
background: #2f3640;
border-radius: 8px;
margin-bottom: 8px;
color: #f5f6fa;
position: relative;
order: 0;
}
.selected::after {
position: absolute;
display: block;
content: "";
width: 10px;
height: 10px;
top: 50%;
right: 25px;
margin-top: -3px;
border-bottom: 1px solid #fff;
border-right: 1px solid #fff;
transform: rotate(45deg) translateY(-50%);
transition: all 0.4s ease-in-out;
transform-origin: 50% 0;
transition: all 0.4s;
}
.select-box .options-container.active {
max-height: 240px;
opacity: 1;
}
.select-box .options-container.active+.selected::after {
margin-top: 3px;
transform: rotate(-135deg) translateY(-50%);
}
.select-box .options-container::-webkit-scrollbar {
width: 8px;
background: #0d141f;
border-radius: 0 8px 8px 0;
}
.select-box .options-container::-webkit-scrollbar-thumb {
background: #525861;
border-radius: 0 8px 8px 0;
}
.select-box .option,
.selected {
padding: 12px 24px;
cursor: pointer;
}
.select-box .option:hover {
background: #414b57;
}
.select-box label {
cursor: pointer;
color: white;
}
.select-box .option .radio {
display: none;
}
<div class="inputs_container">
<div class="service_mode flex">
<div class="select-box">
<div class="options-container"></div>
<div class="selected">
Select Video Category
</div>
</div>
</div>
and if you find any bug in the code please let me know if there could be any further help
I have a code that gets characters names and gender after clicking on film name. This information appears in modal window and my goal is to delete HTML element with characters every time I close modal, so if I select another film the new set of characters will appear, and the old one is already deleted.
The problem is that removeChild method doesn't work as expected. I've tried different variations including parentNode but nothing helped.
Here is the code:
window.addEventListener('DOMContentLoaded', function() {
let btn = document.querySelector('.sw-btn');
let content = document.querySelector('.content');
let modal = document.querySelector('.modal');
let modalBody = document.querySelector('.modal-body');
let closeBtn = document.querySelector('.close-btn');
let filmsList = document.createElement('ul');
let charsList = document.createElement('ol');
function getFilms() {
axios.get('https://swapi.co/api/films/').then(res => {
content.appendChild(filmsList);
for (var i = 0; i < res.data.results.length; i++) {
res.data.results.sort(function(a, b) {
let dateA = new Date(a.release_date),
dateB = new Date(b.release_date);
return dateA - dateB;
});
(function updateFilms() {
let addFilm = document.createElement('li');
filmsList.appendChild(addFilm);
let addFilmAnchor = document.createElement('a');
let addFilmId = document.createElement('p');
let addFilmCrawl = document.createElement('p');
let addFilmDirector = document.createElement('p');
let addFilmDate = document.createElement('p');
addFilmAnchor.textContent = res.data.results[i].title;
addFilmId.textContent = `Episode ID: ${res.data.results[i].episode_id}`;
addFilmCrawl.textContent = `Episode description: ${res.data.results[i].opening_crawl}`;
addFilmDirector.textContent = `Episode director: ${res.data.results[i].director}`;
addFilmDate.textContent = `Episode release date: ${res.data.results[i].release_date}`;
addFilm.append(addFilmAnchor, addFilmId, addFilmCrawl, addFilmDirector, addFilmDate);
})();
}
let links = document.getElementsByTagName('a');
for (let j = 0; j < links.length; j++) {
links[j].onclick = function() {
modal.style.display = 'block';
modalBody.appendChild(charsList);
let chars = res.data.results[j].characters;
for (let k = 0; k < chars.length; k++) {
const element = chars[k];
axios.get(element).then(res => {
let addChar = document.createElement('li');
charsList.appendChild(addChar);
let addCharName = document.createElement('p');
let addCharGender = document.createElement('p');
addCharName.textContent = `Character name: ${res.data.name}`;
addCharGender.textContent = `Character gender: ${res.data.gender}`;
addChar.append(addCharName, addCharGender);
})
}
closeBtn.addEventListener('click', () => {
modal.style.display = 'none';
console.log(modalBody.childNodes[0]);
// Problem is here
modalBody.removeChild(modalBody.childNodes[0]);
});
window.addEventListener('click', (e) => {
if (e.target == modal) {
modal.style.display = 'none';
console.log(modalBody.childNodes[0]);
modalBody.removeChild(modalBody.childNodes[0]);
}
})
}
}
}).catch(err => {
console.log("An error occured");
})
};
btn.addEventListener('click', getFilms);
closeBtn.addEventListener('click', () => {
modal.style.display = 'none';
});
window.addEventListener('click', (e) => {
if (e.target == modal) {
modal.style.display = 'none';
}
})
});
body {
max-height: 100vh;
padding: 0;
margin: 0;
font-family: Muli;
}
body::before {
background: url('https://upload.wikimedia.org/wikipedia/commons/thumb/6/6c/Star_Wars_Logo.svg/1200px-Star_Wars_Logo.svg.png') no-repeat center / cover;
background-size: cover;
content: "";
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -2;
opacity: 0.1;
}
h1 {
text-align: center;
color: #660d41;
font-size: 3em;
margin-top: 10px;
letter-spacing: 1px;
}
main {
display: flex;
align-items: center;
flex-direction: column;
}
.content {
max-width: 55%;
overflow-y: scroll;
max-height: 75vh;
}
.modal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.5);
}
.modal-content {
background-color: #f4f4f4;
margin: 20% auto;
width: 40%;
box-shadow: 0 5px 8px 0 rgba(0, 0, 0, 0.2), 0 7px 20px 0 rgba(0, 0, 0, 0.2);
animation: modalOpen 1s;
}
.modal-header {
background: coral;
padding: 15px;
color: white;
letter-spacing: 1px;
position: relative;
}
.modal-header h2 {
margin: 0;
}
.modal-body {
padding: 10px 20px;
}
.close-btn {
color: white;
float: right;
font-size: 30px;
position: absolute;
top: 0px;
right: 10px;
}
.close-btn:hover,
.close-btn:focus {
color: black;
text-decoration: none;
cursor: pointer;
transition: all 0.4s ease-in;
}
ul {
list-style-type: none;
padding: 10px 20px;
}
li {
border-bottom: 1px solid orangered;
margin-bottom: 30px;
}
li:last-child {
border-bottom: none;
margin-bottom: 0;
}
a {
font-size: 1.7em;
color: #b907d9;
cursor: pointer;
margin-bottom: 10px;
}
p {
font-size: 1.2rem;
color: #0f063f;
margin: 10px 0;
}
button {
padding: .5em 1.5em;
border: none;
color: white;
transition: all 0.2s ease-in;
background: #da2417;
border-radius: 20px;
font-size: 1em;
cursor: pointer;
margin-top: 15px;
}
button:focus {
outline: none;
}
button:hover {
background: #e7736b;
}
button:active {
box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.7) inset;
}
#keyframes modalOpen {
from {
opacity: 0
}
to {
opacity: 1
}
}
<link href="https://fonts.googleapis.com/css?family=Muli&display=swap" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.min.js"></script>
<h1>Star wars films</h1>
<main>
<div class="content"></div>
<div class="modal">
<div class="modal-content">
<div class="modal-header">
<span class="close-btn">×</span>
<h2>Episode Characters</h2>
</div>
<div class="modal-body"></div>
</div>
</div>
<button class="sw-btn">Find Films</button>
</main>
Any help would be appreciated.
The problem is that you are using the same ol element when appending the characters to the list, since you instantiate it at the beginning and re-use it later: let charsList = document.createElement('ol');
When you close the modal, you will remove that ol element from the modal, but you will not remove its content. When opening the modal again, the ol will be added again - with your old content.
If you move the declaration of charsList inside your onclick handler, it will work.
Also, you should register the close handlers of your modal only once. Otherwise, it will be called as often as you open your modal.
Demo:
window.addEventListener('DOMContentLoaded', function () {
let btn = document.querySelector('.sw-btn');
let content = document.querySelector('.content');
let modal = document.querySelector('.modal');
let modalBody = document.querySelector('.modal-body');
let closeBtn = document.querySelector('.close-btn');
let filmsList = document.createElement('ul');
closeBtn.addEventListener('click', () => {
modal.style.display = 'none';
console.log(modalBody.childNodes[0]);
modalBody.removeChild(modalBody.childNodes[0]);
});
window.addEventListener('click', (e) => {
if (e.target == modal) {
modal.style.display = 'none';
console.log(modalBody.childNodes[0]);
modalBody.removeChild(modalBody.childNodes[0]);
}
})
function getFilms() {
axios.get('https://swapi.co/api/films/').then(res => {
content.appendChild(filmsList);
for (var i = 0; i < res.data.results.length; i++) {
res.data.results.sort(function (a, b) {
let dateA = new Date(a.release_date),
dateB = new Date(b.release_date);
return dateA - dateB;
});
(function updateFilms() {
let addFilm = document.createElement('li');
filmsList.appendChild(addFilm);
let addFilmAnchor = document.createElement('a');
let addFilmId = document.createElement('p');
let addFilmCrawl = document.createElement('p');
let addFilmDirector = document.createElement('p');
let addFilmDate = document.createElement('p');
addFilmAnchor.textContent = res.data.results[i].title;
addFilmId.textContent = `Episode ID: ${res.data.results[i].episode_id}`;
addFilmCrawl.textContent = `Episode description: ${res.data.results[i].opening_crawl}`;
addFilmDirector.textContent = `Episode director: ${res.data.results[i].director}`;
addFilmDate.textContent = `Episode release date: ${res.data.results[i].release_date}`;
addFilm.append(addFilmAnchor, addFilmId, addFilmCrawl, addFilmDirector, addFilmDate);
})();
}
let links = document.getElementsByTagName('a');
for (let j = 0; j < links.length; j++) {
links[j].onclick = function () {
modal.style.display = 'block';
let charsList = document.createElement('ol');
modalBody.appendChild(charsList);
let chars = res.data.results[j].characters;
for (let k = 0; k < chars.length; k++) {
const element = chars[k];
axios.get(element).then(res => {
let addChar = document.createElement('li');
charsList.appendChild(addChar);
let addCharName = document.createElement('p');
let addCharGender = document.createElement('p');
addCharName.textContent = `Character name: ${res.data.name}`;
addCharGender.textContent = `Character gender: ${res.data.gender}`;
addChar.append(addCharName, addCharGender);
})
}
}
}
}).catch(err => {
console.log("An error occured");
})
};
btn.addEventListener('click', getFilms);
closeBtn.addEventListener('click', () => {
modal.style.display = 'none';
});
window.addEventListener('click', (e) => {
if (e.target == modal) {
modal.style.display = 'none';
}
})
});
body {
max-height: 100vh;
padding: 0;
margin: 0;
font-family: Muli;
}
body::before {
background: url('https://upload.wikimedia.org/wikipedia/commons/thumb/6/6c/Star_Wars_Logo.svg/1200px-Star_Wars_Logo.svg.png') no-repeat center / cover;
background-size: cover;
content: "";
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -2;
opacity: 0.1;
}
h1 {
text-align: center;
color: #660d41;
font-size: 3em;
margin-top: 10px;
letter-spacing: 1px;
}
main {
display: flex;
align-items: center;
flex-direction: column;
}
.content {
max-width: 55%;
overflow-y: scroll;
max-height: 75vh;
}
.modal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.5);
}
.modal-content {
background-color: #f4f4f4;
margin: 20% auto;
width: 40%;
box-shadow: 0 5px 8px 0 rgba(0, 0, 0, 0.2), 0 7px 20px 0 rgba(0, 0, 0, 0.2);
animation: modalOpen 1s;
}
.modal-header {
background: coral;
padding: 15px;
color: white;
letter-spacing: 1px;
position: relative;
}
.modal-header h2 {
margin: 0;
}
.modal-body {
padding: 10px 20px;
}
.close-btn {
color: white;
float: right;
font-size: 30px;
position: absolute;
top: 0px;
right: 10px;
}
.close-btn:hover,
.close-btn:focus {
color: black;
text-decoration: none;
cursor: pointer;
transition: all 0.4s ease-in;
}
ul {
list-style-type: none;
padding: 10px 20px;
}
li {
border-bottom: 1px solid orangered;
margin-bottom: 30px;
}
li:last-child {
border-bottom: none;
margin-bottom: 0;
}
a {
font-size: 1.7em;
color: #b907d9;
cursor: pointer;
margin-bottom: 10px;
}
p {
font-size: 1.2rem;
color: #0f063f;
margin: 10px 0;
}
button {
padding: .5em 1.5em;
border: none;
color: white;
transition: all 0.2s ease-in;
background: #da2417;
border-radius: 20px;
font-size: 1em;
cursor: pointer;
margin-top: 15px;
}
button:focus {
outline: none;
}
button:hover {
background: #e7736b;
}
button:active {
box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.7) inset;
}
#keyframes modalOpen {
from {
opacity: 0
}
to {
opacity: 1
}
}
<link href="https://fonts.googleapis.com/css?family=Muli&display=swap" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.min.js"></script>
<h1>Star wars films</h1>
<main>
<div class="content"></div>
<div class="modal">
<div class="modal-content">
<div class="modal-header">
<span class="close-btn">×</span>
<h2>Episode Characters</h2>
</div>
<div class="modal-body"></div>
</div>
</div>
<button class="sw-btn">Find Films</button>
</main>
Do this charsList.innerText = ''; when click close button.
When you call removeChild you take off the <ol> from modalbody in UI. You can see the modalBody is empty after clicking close button.
But you already store the <ol> element in js variable by let charsList = document.createElement('ol'); so the ol element itself doesn't change actually.
The <li> element still inside the <ol>. Then you add more new <li> and put it back to modalBody.
My solution is remove all element in <ol> when clicking close button.
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>
I'm working on the "Simon Game" project.
I want it to lighten buttons in the proper sequence. But now by far the code works properly until the 2-nd level.
If I am right the checkButton(randIndexArr, counter) should be included to the promise, so that if counter === index then it should call checkButton and maybe there are some more errors that I missed.
Here's a link with the video: How the code should work to be more clear Zipline: Build a Simon Game
and here is my code:
document.addEventListener("DOMContentLoaded", function () {
'use strict';
var checkOn = document.querySelector("input[type=checkbox]");
var gameCount = document.getElementsByClassName("innerCount")[0];
var startButton = document.getElementById("innerStart");
var strictButton = document.getElementById("strictButton");
var strictInd = document.getElementById("strictIndicator");
var strictMode = false;
var soundArray = document.getElementsByTagName("audio");
var buttons = document.querySelectorAll(".bigButton");
var buttonArray = [].slice.call(buttons, 0);
checkOn.addEventListener("change", function () {
if (checkOn.checked) {
gameCount.innerHTML = "--";
} else {
gameCount.innerHTML = "";
}
});
strictButton.addEventListener("click", function () {
strictMode = !strictMode;
strictMode ? strictInd.style.backgroundColor = "#FF0000" :
strictInd.style.backgroundColor = "#850000";
});
function getRandArray() {
var array = [];
for (var i = 0; i < 22; i++) {
array[i] = Math.floor(Math.random() * 4);
}
document.getElementsByClassName("randArray")[0].innerHTML = array;
return array;
}
startButton.addEventListener("click", function () {
var level = 0;
var randIndexArr = getRandArray();
playGame(randIndexArr, level);
});
function sleep(time) {
return new Promise(resolve => {
setTimeout(resolve, time)
})
}
function checkButton(randIndexArr, counter) {
console.log('checkButton');
var checker = function checker(e) {
var clickedButtonId = e.target.dataset.sound;
lightenButton(clickedButtonId);
sleep(1000);
for (let index = 0; index <= counter; index++) {
if (+(clickedButtonId) === randIndexArr[index]) {
if (index === counter) {
console.log('checking passed - next level :', (counter + 1));
counter++;
for (var i = 0; i < 4; i++) {
buttonArray[i].removeEventListener("click", checker, false)
}
playGame(randIndexArr, counter);
}
}
}
}
;
for (var i = 0; i < 4; i++) {
buttonArray[i].addEventListener("click", checker, false)
}
}
function playGame(randIndexArr, counter) {
if (counter === 22) {
return;
}
//Show the level of the Game
gameCount.innerHTML = counter + 1;
//Light and play random buttons according to the level
//Light and play user's input then check if input is correct
randIndexArr.slice(0, counter + 1).reduce(function (promise, div, index) {
return promise.then(function () {
console.log("slice reduce");
lightenButton(div);
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("reduce Resolve");
}, 1000);
})
})
}, Promise.resolve()).then(function (value) {
console.log(value);
checkButton(randIndexArr, counter);
});
}
function lightenButton(id) {
var lightColorsArr = ["liteGreen", "liteRed", "liteYell", "liteBlue"];
var promise = new Promise((resolve, reject) => {
soundArray[id].play();
buttonArray[id].classList.add(lightColorsArr[id]);
setTimeout(function () {
resolve("lighten");
}, 500);
});
promise.then(function (value) {
console.log(value);
buttonArray[id].classList.remove(lightColorsArr[id]);
});
}
});
#font-face {
font-family: myDirector;
src: url('https://raw.githubusercontent.com/Y-Taras/FreeCodeCamp/master/Simon/fonts/myDirector-Bold.otf');
}
#outerCircle {
display: flex;
flex-wrap: wrap;
margin: 0 auto;
width: 560px;
border: 2px dotted grey;
position: relative;
}
.bigButton {
height: 250px;
width: 250px;
border: solid #464646;
transition: all 1s;
-webkit-transition: all 1s;
-moz-transition: all 1s;
-o-transition: background-color 0.5s ease;
}
#greenButton {
background-color: rgb(9, 174, 37);
border-radius: 100% 0 0 0;
border-width: 20px 10px 10px 20px;
}
.liteGreen#greenButton {
background-color: #86f999;
}
#redButton {
background-color: rgb(174, 9, 15);
border-radius: 0 100% 0 0;
border-width: 20px 20px 10px 10px;
}
.liteRed#redButton {
background-color: #f9868a;
}
#yellowButton {
background-color: rgb(174, 174, 9);
border-radius: 0 0 0 100%;
border-width: 10px 10px 20px 20px;
}
.liteYell#yellowButton {
background-color: #f9f986;
}
#blueButton {
background-color: rgb(9, 37, 174);
border-radius: 0 0 100% 0;
border-width: 10px 20px 20px 10px;
}
.liteBlue#blueButton {
background-color: #8699f9;
}
div#innerCircle {
border: 15px solid #464646;
border-radius: 50%;
position: absolute;
top: 25%;
right: 25%;
background-color: #c4c7ce;
}
div.additionalBorder {
margin: 4px;
border-radius: 50%;
height: 242px;
width: 242px;
overflow: hidden;
}
p#tradeMark {
margin: auto;
height: 104px;
text-align: center;
font-size: 68px;
font-family: myDirector;
color: #c4c7ce;
background-color: black;
border-color: antiquewhite;
line-height: 162px;
}
span#reg {
font-size: 12px;
}
.partition {
height: 6px;
}
.buttons {
height: 128px;
border-radius: 0 0 128px 128px;
border: 2px solid black;
}
/* Start and Strict buttons*/
table {
margin-left: 5px;
}
td {
text-align: center;
width: auto;
padding: 2px 10px;
vertical-align: bottom;
}
div.innerCount {
width: 54px;
height: 40px;
background-color: #34000e;
color: crimson;
border-radius: 11px;
font-size: 28px;
line-height: 42px;
text-align: center;
font-family: 'Segment7Standard', italic;
}
button#innerStart {
width: 27px;
height: 27px;
border: 4px solid #404241;
border-radius: 50%;
background: #a50005;
box-shadow: 0 0 3px gray;
cursor: pointer;
}
div.strict {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
button#strictButton {
width: 27px;
height: 27px;
border: 4px solid #404241;
border-radius: 50%;
background: yellow;
box-shadow: 0 0 3px gray;
cursor: pointer;
}
div#strictIndicator {
width: 6px;
height: 6px;
margin-bottom: 2px;
background-color: #850000;
border-radius: 50%;
border: 1px solid #5f5f5f;
}
#switcher {
display: flex;
justify-content: center;
align-items: center;
}
.labels {
font-family: 'Roboto', sans-serif;
margin: 4px;
}
/* toggle switch */
.checkbox > input[type=checkbox] {
visibility: hidden;
}
.checkbox {
display: inline-block;
position: relative;
width: 60px;
height: 30px;
border: 2px solid #424242;
}
.checkbox > label {
position: absolute;
width: 30px;
height: 26px;
top: 2px;
right: 2px;
background-color: #a50005;
cursor: pointer;
}
.checkbox > input[type=checkbox]:checked + label {
right: 28px;
}
<div id="outerCircle">
<div class="bigButton" id="greenButton" data-sound = "0" >0
<audio src="https://s3.amazonaws.com/freecodecamp/simonSound1.mp3"></audio>
</div>
<div class="bigButton" id="redButton" data-sound = "1">1
<audio src="https://s3.amazonaws.com/freecodecamp/simonSound2.mp3" ></audio>
</div>
<div class="bigButton" id="yellowButton" data-sound = "2">2
<audio src="https://s3.amazonaws.com/freecodecamp/simonSound3.mp3"></audio>
</div>
<div class="bigButton" id="blueButton" data-sound = "3">3
<audio src="https://s3.amazonaws.com/freecodecamp/simonSound4.mp3"></audio>
</div>
<div id="innerCircle">
<div class="additionalBorder">
<p id="tradeMark">simon<span id="reg">®</span></p>
<div class="partition"></div>
<div class="buttons">
<table>
<tr class="firstRow">
<td>
<div class="innerCount"></div>
</td>
<td>
<button type="button" id="innerStart"></button>
</td>
<td>
<div class="strict">
<div id="strictIndicator"></div>
<button type="button" id="strictButton"></button>
</div>
</td>
</tr>
<tr class="labels">
<td>
<div id="countLabel">COUNT</div>
</td>
<td>
<div id="startLabel">START</div>
</td>
<td>
<div id="strictLabel">STRICT</div>
</td>
</tr>
</table>
<div id="switcher">
<span class="labels">ON</span>
<div class="checkbox">
<input id="checkMe" type="checkbox">
<label for="checkMe"></label>
</div>
<span class="labels">OFF</span>
</div>
</div>
</div>
</div>
</div>
<div class="randArray"></div>
One of the problem (along many others) is in checkButton function itself, where you checking buttons against array, but doesn't check the series of button presses, or "attempts".
For example, if randIndexArr contains values [2,2,1,1...], your code is okay with checking clickeBbuttonId with value 2 against both array's first two values, and so on.
I did rewrote only one function checkButton just to show you one of possible approaches:
var currentAttempt = 1
function checkButton(randIndexArr, counter) {
var checker = function checker(e) {
var clickedButtonId = e.target.dataset.sound;
lightenButton(clickedButtonId);
if (randIndexArr[currentAttempt -1] === +(clickedButtonId)){
if (currentAttempt - 1 === counter) {
counter++
currentAttempt = 1
for (var i = 0; i < 4; i++) {
buttonArray[i].removeEventListener("click", checker, false)
}
playGame(randIndexArr, counter);
}
currentAttempt++
} else {
currentAttempt = 1
}
};
for (var i = 0; i < 4; i++) {
buttonArray[i].addEventListener("click", checker, false)
}
}
But to be honest, whole code should be redesigned.