I am trying to create a notification system that gives custom notifications. Here is my function:
var notificationCount = 0;
document.querySelector("body").innerHTML += '<div class="notification-holder"></div>';
function notification(content){
notificationCount+=1;
document.querySelector(".notification-holder").innerHTML += `
<div class="notification" id="notification-${notificationCount}">
<p>${content}</p>
</div>
`;
var msg = document.querySelector(`#notification-${notificationCount}`);
msg.style.animation = "notificationAnimate 0.2s forwards"
msg.addEventListener("animationend", () => {
msg.style.visibility = "visible";
msg.style.animation = "";
setTimeout(() => {
msg.style.animation="notificationAnimate 0.2s reverse"
msg.addEventListener("animationend", () => {
msg.remove()
})
}, 1000)
})
};
:root{
--black: #151515;
--white: #EDEDEE;
}
.notification-holder{
position: absolute;
bottom: 0px;
right: 10px;
padding-bottom: 10px;
overflow: hidden;
}
.notification{
width: 250px;
padding: 10px;
text-align: center;
background-color: var(--black);
color: var(--white);
font-size: 14px;
font-family: "Poppins", sans-serif;
border-radius: 10px;
}
.notification:not(:first-of-type){
margin-top: 10px;
}
#keyframes notificationAnimate{
0%{
opacity: 0;
max-height: 1px;
transform: translateY(100px);
scale: 0;
}
100%{
opacity: 1;
max-height: fit-content;
transform: translateY(0px);
/* visibility: visible; */
scale: 1;
}
}
<html>
<head>
</head>
<body>
<button onclick="notification('Dark theme has been enabled!')">Dark theme </button>
</body>
</html>
The code works perfectly fine for 1 notification at a time. However, when there are multiple notifications at a time, only the latest one goes through the reverse animation.
Regenerate Problem:
Click on the button twice
You will see only the latest notification goes back down. Earlier ones just stick there.
Expectation: I want all of them to go back down after 1s of when they were shown.
As noted in my earlier comment, I think the problem comes with you using notificationCount in the ID/selector. That changes over time.
My solution removes the need for that, as well as all the document re-querying you were doing over time. Instead of tracking IDs and querying the DOM repeatedly, I create elements and store references to them, which I later act upon as needed.
My changes are in the JS, the rest of this snippet is from your post:
var notificationContainer,
notification;
notificationContainer = document.createElement('div');
notificationContainer.className = 'notification-holder';
document.body.appendChild(notificationContainer);
notification = function (content) {
var msg = document.createElement('div');
msg.className = 'notification';
msg.innerHTML = `<p>${content}</p>`;
msg.style.animation = 'notificationAnimate 0.2s forwards';
msg.addEventListener('animationend', function () {
msg.style.visibility = 'visible';
msg.style.animation = '';
setTimeout(function () {
msg.style.animation='notificationAnimate 0.2s reverse';
msg.addEventListener('animationend', function () {
msg.remove();
});
}, 1000);
});
notificationContainer.appendChild(msg);
};
:root{
--black: #151515;
--white: #EDEDEE;
}
.notification-holder{
position: absolute;
bottom: 0px;
right: 10px;
padding-bottom: 10px;
overflow: hidden;
}
.notification{
width: 250px;
padding: 10px;
text-align: center;
background-color: var(--black);
color: var(--white);
font-size: 14px;
font-family: "Poppins", sans-serif;
border-radius: 10px;
}
.notification:not(:first-of-type){
margin-top: 10px;
}
#keyframes notificationAnimate{
0%{
opacity: 0;
max-height: 1px;
transform: translateY(100px);
scale: 0;
}
100%{
opacity: 1;
max-height: fit-content;
transform: translateY(0px);
/* visibility: visible; */
scale: 1;
}
}
<html>
<head>
</head>
<body>
<button onclick="notification('Dark theme has been enabled!')">Dark theme </button>
</body>
</html>
Here you go, may require some fine tuning, but works as expected:
document.querySelector("body").innerHTML += '<div class="notification-holder"></div>';
function notification(content){
var msg = document.createElement('div');
msg.innerHTML += `
<div class="notification">
<p>${content}</p>
</div>
`
document.querySelector(".notification-holder").appendChild(msg);
msg.style.animation = "notificationAnimate 0.2s forwards"
msg.addEventListener("animationend", () => {
msg.style.visibility = "visible";
msg.style.animation = "";
setTimeout(() => {
msg.style.animation="notificationAnimate 0.2s reverse"
msg.addEventListener("animationend", () => {
msg.remove()
})
}, 1000)
})
};
:root{
--black: #151515;
--white: #EDEDEE;
}
.notification-holder{
position: absolute;
bottom: 0px;
right: 10px;
padding-bottom: 10px;
overflow: hidden;
}
.notification{
width: 250px;
padding: 10px;
text-align: center;
background-color: var(--black);
color: var(--white);
font-size: 14px;
font-family: "Poppins", sans-serif;
border-radius: 10px;
}
.notification:not(:first-of-type){
margin-top: 10px;
}
#keyframes notificationAnimate{
0%{
opacity: 0;
max-height: 1px;
transform: translateY(100px);
scale: 0;
}
100%{
opacity: 1;
max-height: fit-content;
transform: translateY(0px);
/* visibility: visible; */
scale: 1;
}
}
<html>
<head>
</head>
<body>
<button onclick="notification('Dark theme has been enabled!')">Dark theme </button>
</body>
</html>
BTW, nice script :-)
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>
It's another question on animation in JS / CSS.
I'd like to ask how should I correct the code in JavaScript, in order to achieve the visual effect that, after a screen full of random characters, all the lines of random characters will disappear, with only the black background, while a new line of random characters starts generating at the top of the screen? I thought it would be a solution that, after the characters in the div element fill up the whole screen, the height can be a reference to trigger the function of .removeChild(), in order to remove the appended p elements. After that, by .appendChild() it will start the generation process again at the top of the screen. If not so, Is there any other ways to do it?
Thank you very much!
Code:
function create_random_string(string_length) {
var random_string = '';
var characters = 'ABCDEFGabcdefg';
for (var i, i = 0; i < string_length; i++) {
random_string += characters.charAt(Math.floor(Math.random() * characters.length));
}
return random_string;
}
let divElem = document.getElementById('container');
NewLine();
var MyInterval = setInterval(NewLine, 11000);
function NewLine() {
let text = document.createElement("p");
text.setAttribute("id", "text");
text.innerHTML = create_random_string(15);
divElem.appendChild(text);
}
function RemoveChild() {
if (divElem.clientHeight > window.innerHeight) {
while (divElem.firstChild) {
divElem.removeChild(divElem.firstChild)
};
}
}
body {
background-color: #000000;
margin: 0;
padding: 0;
overflow: hidden;
display: grid;
height: 100vh;
width: 100vw;
}
#container {
place-content: center;
text-align: center;
line-height: 7.5vh;
}
#text {
font-family: 'Courier New', Courier, monospace;
font-size: 4vw;
letter-spacing: 3vw;
font-weight: bold;
color: #ffffff;
position: relative;
}
#text::before,
#text::after {
content: "";
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
#text::before {
background: #000000;
animation: typewriter 10s steps(15) forwards;
}
#text::after {
width: 0.125em;
bottom: 0vh;
Top: 0vh;
background: #ffffff;
animation: TypingBar 10s steps(15) forwards, blink 750ms steps(15) infinite;
}
#keyframes typewriter {
0% {
left: 0;
}
6.7% {
left: 7vw;
}
100% {
left: 90vw;
}
}
#keyframes TypingBar {
0%,
6.7% {
left: 8vw;
}
99.99% {
left: 89.5vw;
opacity: 1;
}
/* escape fade-in effect */
100% {
opacity: 0;
}
/* hide trailing cursor */
}
#keyframes blink {
to {
background: transparent;
}
}
<body>
<div id="container">
<p id="text"></p>
</div>
</body>
function create_random_string(string_length) {
var random_string = '';
var characters = 'ABCDEFGabcdefg';
for (var i, i = 0; i < string_length; i++) {
random_string += characters.charAt(Math.floor(Math.random() * characters.length));
}
return random_string;
}
let divElem = document.getElementById('container');
NewLine();
var MyInterval = setInterval(NewLine, 11000);
function NewLine() {
RemoveChild();
let text = document.createElement("p");
text.setAttribute("id", "text");
text.innerHTML = create_random_string(15);
divElem.appendChild(text);
}
function RemoveChild() {
if (divElem.clientHeight > window.innerHeight) {
divElem.innerHTML ="";
}
}
body {
background-color: #000000;
margin: 0;
padding: 0;
overflow: hidden;
display: grid;
height: 100vh;
width: 100vw;
}
#container {
place-content: center;
text-align: center;
line-height: 7.5vh;
}
#text {
font-family: 'Courier New', Courier, monospace;
font-size: 4vw;
letter-spacing: 3vw;
font-weight: bold;
color: #ffffff;
position: relative;
}
#text::before,
#text::after {
content: "";
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
#text::before {
background: #000000;
animation: typewriter 10s steps(15) forwards;
}
#text::after {
width: 0.125em;
bottom: 0vh;
Top: 0vh;
background: #ffffff;
animation: TypingBar 10s steps(15) forwards, blink 750ms steps(15) infinite;
}
#keyframes typewriter {
0% {
left: 0;
}
6.7% {
left: 7vw;
}
100% {
left: 90vw;
}
}
#keyframes TypingBar {
0%,
6.7% {
left: 8vw;
}
99.99% {
left: 89.5vw;
opacity: 1;
}
/* escape fade-in effect */
100% {
opacity: 0;
}
/* hide trailing cursor */
}
#keyframes blink {
to {
background: transparent;
}
}
<body>
<div id="container">
<p id="text"></p>
</div>
</body>
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);
I am trying to put this typewriting effect on my website. I use Brackets as code editor and in its live preview the code simply isn't running. Tested a few other ways to do this effect but nothing seems to work on my live preview, only on codepen. Can someone help?
const typedTextSpan = document.querySelector(".typed-text");
const cursorSpan = document.querySelector(".cursor");
const textArray = ["hard.", "fun.", "a journey.", "LIFE!"];
const typingDelay = 200;
const erasingDelay = 100;
const newTextDelay = 2000; // Delay between current and next text
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 + 1100);
}
}
document.addEventListener("DOMContentLoaded", function() { // On DOM Load initiate the effect
if (textArray.length) setTimeout(type, newTextDelay + 250);
});
#import url('https://fonts.googleapis.com/css?family=Montserrat');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Montserrat', sans-serif;
background-color: #000;
color: #eee;
}
.container {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.container p {
font-size: 3rem;
padding: 0.5rem;
font-weight: bold;
letter-spacing: 0.1rem;
text-align: center;
overflow: hidden;
}
.container p span.typed-text {
font-weight: normal;
color: #dd7732;
}
.container p span.cursor {
display: inline-block;
background-color: #ccc;
margin-left: 0.1rem;
width: 3px;
animation: blink 1s infinite;
}
.container p span.cursor.typing {
animation: none;
}
#keyframes blink {
0% {
background-color: #ccc;
}
49% {
background-color: #ccc;
}
50% {
background-color: transparent;
}
99% {
background-color: transparent;
}
100% {
background-color: #ccc;
}
}
<div class="container">
<h1>
<p>Coding is <span class="typed-text"></span><span class="cursor"> </span></p>
</h1>
</div>