Two identical modals, but one does not work. Why? - javascript

EDIT:
The new code:
const modal2 = () => {
'use strict';
class Modal {
constructor() {
this.triggers = document.querySelectorAll('.js-modal2');
this.close = document.querySelectorAll('.js-close-modal');
this.modals = document.querySelectorAll('.modal');
this.modalInners = document.querySelectorAll('.modal-inner');
this.listeners();
}
listeners() {
window.addEventListener('keydown', this.keyDown);
this.triggers.forEach(el => {
el.addEventListener('click', this.openModal, false);
});
this.modals.forEach(el => {
el.addEventListener('transitionend', this.revealModal, false);
el.addEventListener('click', this.backdropClose, false);
});
this.close.forEach(el => {
el.addEventListener('click', Modal.hideModal, false);
});
this.modalInners.forEach(el => {
el.addEventListener('transitionend', this.closeModal, false);
});
}
keyDown(e) {
if (27 === e.keyCode && document.body.classList.contains('modal-body')) {
Modal.hideModal();
}
}
backdropClose(el) {
if (!el.target.classList.contains('modal-visible')) {
return;
}
let backdrop = el.currentTarget.dataset.backdrop !== undefined ? el.currentTarget.dataset.backdrop : true;
if (backdrop === true) {
Modal.hideModal();
}
}
static hideModal() {
let modalOpen = document.querySelector('.modal.modal-visible');
modalOpen.querySelector('.modal-inner').classList.remove('modal-reveal');
document.querySelector('.modal-body').addEventListener('transitionend', Modal.modalBody, false);
document.body.classList.add('modal-fadeOut');
}
closeModal(el) {
if ('opacity' === el.propertyName && !el.target.classList.contains('modal-reveal')) {
document.querySelector('.modal.modal-visible').classList.remove('modal-visible');
}
}
openModal(el) {
if (!el.currentTarget.dataset.modal) {
console.error('No data-modal attribute defined!');
return;
}
let modalID = el.currentTarget.dataset.modal2;
let modal2 = document.getElementById(modalID);
document.body.classList.add('modal-body');
modal.classList.add('modal-visible');
}
revealModal(el) {
if ('opacity' === el.propertyName && el.target.classList.contains('modal-visible')) {
el.target.querySelector('.modal-inner').classList.add('modal-reveal');
}
}
static modalBody(el) {
if ('opacity' === el.propertyName && el.target.classList.contains('modal') && !el.target.classList.contains('modal-visible')) {
document.body.classList.remove('modal-body', 'modal-fadeOut');
}
}}
new Modal();
};
export default modal2;
I am sorry if this is going to be a bit long.
I have two ul elements on my page that contain a list that is made to look like a subway map.
For the first ul, I made a class inside the li elements, which fetch json data that pops up in a modal.
This modal WORKS!
The problem is my SECOND modal.
Here I have a simple button, and when I click that button I want a modal to pop up, containing my second ul element.
The problem is that I can´t get THIS modal to work.
I renamed everything, both in the html, css and script, and I am going crazy because I can´t find the error. I need this project finished tonight, so I am getting more and more frustrated about it
My test page is here: http://handig.dk/EXAM2019/index.html
The second section contains my working modal.
The third contains the non-working modal.
The html
`<div class="map">
<ul>
<li id="getTime" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime2" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime3" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime4" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime5" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime6" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime7" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime8" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime9" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime10" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime11" class="js-modal" data-modal="modal-1">Text</li>
<li id="getTime12" class="js-modal" data-modal="modal-1">Text</li>
</ul>
<h2>Text</h2>
<div id="modal-1" class="modal">
<div class="modal-inner">
<div id="modal-body">
</div>
<a class="js-close-modal">×</a>
<div class="modal-content">
<p class="modal-headline">Text</p>
</div>
</div><!-- .modal-content -->
</div><!-- .modal-inner -->
</div><!-- .modal -->
<!-- SECOND MODAL (NOT WORKING) -->
<div class="trains">
<button class="js-modal2" data-modal="modal-2">Tjek driften</button>
<div id="modal-2" class="modal2">
<div class="modal-inner2">
<div id="modal-body2">
</div>
<a class="js-close-modal2">×</a>
<div class="modal-content2">
<p class="modal-headline">Drift</p>
<ul>
<li>Text</li>
<li>Text</li>
<li>Text</li>
<li>Text</li>
<li>Text</li>
<li>Text</li>
<li>Text</li>
<li>Text</li>
<li>Text</li>
<li>Text</li>
<li>Text</li>
<li>Text</li>
</ul>
</div>
</div><!-- .modal-content2 -->
</div><!-- .modal-inner2 -->`
CSS for the WORKING modal
.modal-body {
overflow: hidden;
position: relative;
}
#modal-body {
background:#900;
}
.modal-body:before {
position: fixed;
display: block;
content: '';
top: 0px;
bottom: 0px;
right: 0px;
left: 0px;
background-color: rgba(0, 0, 0, 0.75);
z-index: 10;
}
.modal-body:before {
-webkit-animation: fadeIn 320ms ease;
animation: fadeIn 320ms ease;
transition: opacity ease 320ms;
}
.modal-body.modal-fadeOut:before {
opacity: 0;
}
.modal {
transition: all ease 0.01s;
display: block;
opacity: 0;
height: 0;
position: fixed;
content: '';
top: 0;
left: 0;
right: 0;
z-index: 2000;
text-align: center;
overflow: hidden;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
.modal.modal-visible {
opacity: 1;
height: auto;
bottom: 0;
}
.modal-inner {
transition: all ease 320ms;
-webkit-transform: translateY(-50px);
transform: translateY(-50px);
position: relative;
display: inline-block;
background-color: #fff;
width: 90%;
max-width: 600px;
background: #fff;
opacity: 0;
margin: 40px 0;
border-radius: 4px;
box-shadow: 0 30px 18px -20px #020202;
}
.modal-inner.modal-reveal {
-webkit-transform: translateY(0);
transform: translateY(0);
opacity: 1;
}
.js-close-modal {
transition: color 320ms ease;
color: #9e9e9e;
opacity: 0.75;
position: absolute;
z-index: 2;
right: 0px;
top: 0px;
width: 30px;
height: 30px;
line-height: 30px;
font-size: 20px;
cursor: pointer;
text-align: center;
}
.js-close-modal:hover {
color: #000;
}
.modal-headline {
font-size: 1.5em;
font-weight: 700;
}
.modal-content {
letter-spacing: 1px;
}
.modal-content2 {
letter-spacing: 1px;
}
CSS for modal that does NOT work
.modal-body2 {
overflow: hidden;
position: relative;
}
#modal-body2 {
background:#900;
}
.modal-body2:before {
position: fixed;
display: block;
content: '';
top: 0px;
bottom: 0px;
right: 0px;
left: 0px;
background-color: rgba(0, 0, 0, 0.75);
z-index: 10;
}
.modal-body2:before {
-webkit-animation: fadeIn 320ms ease;
animation: fadeIn 320ms ease;
transition: opacity ease 320ms;
}
.modal-body2.modal2-fadeOut:before {
opacity: 0;
}
.modal2 {
transition: all ease 0.01s;
display: block;
opacity: 0;
height: 0;
position: fixed;
content: '';
top: 0;
left: 0;
right: 0;
z-index: 2000;
text-align: center;
overflow: hidden;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
.modal2.modal2-visible {
opacity: 1;
height: auto;
bottom: 0;
}
.modal-inner2 {
transition: all ease 320ms;
-webkit-transform: translateY(-50px);
transform: translateY(-50px);
position: relative;
display: inline-block;
background-color: #fff;
width: 90%;
max-width: 600px;
background: #fff;
opacity: 0;
margin: 40px 0;
border-radius: 4px;
box-shadow: 0 30px 18px -20px #020202;
}
.modal-inner2.modal2-reveal {
-webkit-transform: translateY(0);
transform: translateY(0);
opacity: 1;
}
.js-close-modal2 {
transition: color 320ms ease;
color: #9e9e9e;
opacity: 0.75;
position: absolute;
z-index: 2;
right: 0px;
top: 0px;
width: 30px;
height: 30px;
line-height: 30px;
font-size: 20px;
cursor: pointer;
text-align: center;
}
.js-close-modal2:hover {
color: #000;
}
Script for modal that WORKS
const modal = () => {
'use strict';
class Modal {
constructor() {
this.triggers = document.querySelectorAll('.js-modal');
this.close = document.querySelectorAll('.js-close-modal');
this.modals = document.querySelectorAll('.modal');
this.modalInners = document.querySelectorAll('.modal-inner');
this.listeners();
}
listeners() {
window.addEventListener('keydown', this.keyDown);
this.triggers.forEach(el => {
el.addEventListener('click', this.openModal, false);
});
this.modals.forEach(el => {
el.addEventListener('transitionend', this.revealModal, false);
el.addEventListener('click', this.backdropClose, false);
});
this.close.forEach(el => {
el.addEventListener('click', Modal.hideModal, false);
});
this.modalInners.forEach(el => {
el.addEventListener('transitionend', this.closeModal, false);
});
}
keyDown(e) {
if (27 === e.keyCode && document.body.classList.contains('modal-body')) {
Modal.hideModal();
}
}
backdropClose(el) {
if (!el.target.classList.contains('modal-visible')) {
return;
}
let backdrop = el.currentTarget.dataset.backdrop !== undefined ? el.currentTarget.dataset.backdrop : true;
if (backdrop === true) {
Modal.hideModal();
}
}
static hideModal() {
let modalOpen = document.querySelector('.modal.modal-visible');
modalOpen.querySelector('.modal-inner').classList.remove('modal-reveal');
document.querySelector('.modal-body').addEventListener('transitionend', Modal.modalBody, false);
document.body.classList.add('modal-fadeOut');
}
closeModal(el) {
if ('opacity' === el.propertyName && !el.target.classList.contains('modal-reveal')) {
document.querySelector('.modal.modal-visible').classList.remove('modal-visible');
}
}
openModal(el) {
if (!el.currentTarget.dataset.modal) {
console.error('No data-modal attribute defined!');
return;
}
let modalID = el.currentTarget.dataset.modal;
let modal = document.getElementById(modalID);
document.body.classList.add('modal-body');
modal.classList.add('modal-visible');
}
revealModal(el) {
if ('opacity' === el.propertyName && el.target.classList.contains('modal-visible')) {
el.target.querySelector('.modal-inner').classList.add('modal-reveal');
}
}
static modalBody(el) {
if ('opacity' === el.propertyName && el.target.classList.contains('modal') && !el.target.classList.contains('modal-visible')) {
document.body.classList.remove('modal-body', 'modal-fadeOut');
}
}}
new Modal();
};
export default modal;
Script for modal that does NOT WORK
const modal2 = () => {
'use strict';
class Modal2 {
constructor() {
this.triggers = document.querySelectorAll('.js-modal2');
this.close = document.querySelectorAll('.js-close-modal2');
this.modals = document.querySelectorAll('.modal2');
this.modalInners = document.querySelectorAll('.modal-inner2');
this.listeners();
}
listeners() {
window.addEventListener('keydown', this.keyDown);
this.triggers.forEach(el => {
el.addEventListener('click', this.openModal2, false);
});
this.modals.forEach(el => {
el.addEventListener('transitionend', this.revealModal2, false);
el.addEventListener('click', this.backdropClose, false);
});
this.close.forEach(el => {
el.addEventListener('click', Modal2.hideModal2, false);
});
this.modalInners.forEach(el => {
el.addEventListener('transitionend', this.closeModal2, false);
});
}
keyDown(e) {
if (27 === e.keyCode && document.body.classList.contains('modal-body2')) {
Modal2.hideModal2();
}
}
backdropClose(el) {
if (!el.target.classList.contains('modal2-visible')) {
return;
}
let backdrop = el.currentTarget.dataset.backdrop !== undefined ? el.currentTarget.dataset.backdrop : true;
if (backdrop === true) {
Modal2.hideModal2();
}
}
static hideModal2() {
let modalOpen = document.querySelector('.modal2.modal2-visible');
modalOpen.querySelector('.modal-inner2').classList.remove('modal2-reveal');
document.querySelector('.modal-body2').addEventListener('transitionend', Modal2.modalBody2, false);
document.body.classList.add('modal2-fadeOut');
}
closeModal2(el) {
if ('opacity' === el.propertyName && !el.target.classList.contains('modal2-reveal')) {
document.querySelector('.modal2.modal2-visible').classList.remove('modal2-visible');
}
}
openModal(el) {
if (!el.currentTarget.dataset.modal) {
console.error('No data-modal attribute defined!');
return;
}
let modal2ID = el.currentTarget.dataset.modal2;
let modal2 = document.getElementById(modal2ID);
document.body.classList.add('modal-body2');
modal.classList.add('modal2-visible');
}
revealModal2(el) {
if ('opacity' === el.propertyName && el.target.classList.contains('modal2-visible')) {
el.target.querySelector('.modal-inner2').classList.add('modal2-reveal');
}
}
static modalBody2(el) {
if ('opacity' === el.propertyName && el.target.classList.contains('modal2') && !el.target.classList.contains('modal2-visible')) {
document.body.classList.remove('modal-body2', 'modal2-fadeOut');
}
}}
new Modal2();
};
export default modal2;

in your javascript, this.triggers refer to your button but in your function openModal the variable modal2ID is undefined because your button doesn't have dataset.modal2

Related

How to loop slides and autoplay in custom javascript?

I'm a beginner in javascript. I downloaded a custom javacsript slide from this website:
https://www.cssscript.com/swiper-thumbnail-paginator/
Slide demo here: https://www.cssscript.com/demo/swiper-thumbnail-paginator/
I've also created a demo on jsfiddle: https://jsfiddle.net/t4c1nb3g/
The file consists of 5 files, namely: index.html, style.css, debounce.js, script.js, slide.js
And it has 6 images.
Currently, there is no slide loop in the demo, I want the slide to start itself (autoplay) and repeat it again and again (looping).
How can I make it loop for the slide and start itself (autoplay)?
Below is the index.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Slider</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="slide-wrapper">
<ul class="slide">
<li><img src="https://i.stack.imgur.com/2fkLR.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/gN1Ri.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/FgqYP.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/su1na.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/vZYry.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/5dXtQ.jpg" alt=""></li>
</ul>
</div>
<div class="wrap-controls">
<div class="arrow-nav">
<button class="prev"></button>
</div>
<ul class="custom-controls">
<li><img src="https://i.stack.imgur.com/2fkLR.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/gN1Ri.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/FgqYP.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/su1na.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/vZYry.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/5dXtQ.jpg" alt=""></li>
</ul>
<div class="arrow-nav">
<button class="next"></button>
</div>
</div>
<script type="module" src="js/script.js"></script>
</body>
</html>
Below is the style.css file:
body {
margin: 0px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
}
ul {
padding: 0px;
margin: 0px;
list-style: none;
}
img {
display: block;
max-width: 100%;
}
.slide-wrapper {
overflow: hidden;
}
.slide {
display: flex;
}
.slide:hover {
will-change: transform;
}
.slide li {
flex-shrink: 0;
max-width: 600px;
margin: 0 20px;
border-radius: 4px;
overflow: hidden;
box-shadow: 0 2px 4px rgba(0,0,0,.4);
opacity: .8;
transform: scale(.8);
transition: .4s;
}
.slide li.active {
opacity: 1;
transform: scale(1);
}
[data-control="slide"] {
display: flex;
justify-content: center;
margin-top: 20px;
}
[data-control="slide"] li a {
display: block;
width: 12px;
height: 12px;
background: #FB5;
border-radius: 50%;
overflow: hidden;
text-indent: -999px;
margin: 5px;
}
[data-control="slide"] li.active a, [data-control="slide"] li a:hover {
background: #E54;
}
.custom-controls {
display: flex;
justify-content: center;
margin-top: 40px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.custom-controls li {
opacity: .8;
transform: scale(.8);
width: 40px;
height: 40px;
border-radius: 50%;
overflow: hidden;
margin: 2px;
box-shadow: 0 2px 2px rgba(0,0,0,.5);
transition: .3s;
cursor: pointer;
}
.custom-controls li.active {
opacity: 1;
transform: scale(1);
}
.arrow-nav {
display: flex;
justify-content: space-around;
margin: 20px 10px 0 10px;
}
.arrow-nav button {
cursor: pointer;
border: none;
border-radius: 50%;
color: white;
width: 30px;
height: 30px;
background: #999 url('../img/arrow.svg') center center no-repeat;
outline: none;
}
.arrow-nav button:hover {
background: #333 url('../img/arrow.svg') center center no-repeat;
transition: ease-in-out .3s;
}
.arrow-nav button.prev {
transform: rotate(-180deg);
}
.wrap-controls {
display: flex;
justify-content: center;
align-items: center;
}
Below is the debounce.js file:
export default function debounce(callback, delay) {
let timer;
return (...args) => {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
callback(...args);
timer = null;
}, delay);
};
}
Below is the script.js file:
import SlideNav from './slide.js';
const slide = new SlideNav('.slide', '.slide-wrapper');
slide.init();
slide.addArrow('.prev', '.next');
slide.addControl('.custom-controls');
Below is the slide.js file:
import debounce from './debounce.js';
export class Slide {
constructor(slide, wrapper) {
this.slide = document.querySelector(slide)
this.wrapper = document.querySelector(wrapper);
this.dist = { finalPosition: 0, startX: 0, movement: 0 }
this.activeClass = 'active';
this.changeEvent = new Event('changeEvent');
}
transition(active) {
this.slide.style.transition = active ? 'transform .3s' : '';
}
moveSlide(distX) {
this.dist.movePosition = distX;
this.slide.style.transform = `translate3d(${distX}px, 0, 0)`;
}
updatePosition(clientX) {
this.dist.movement = (this.dist.startX - clientX) * 1.6;
return this.dist.finalPosition - this.dist.movement;
}
onStart(event) {
let movetype;
if (event.type === 'mousedown') {
event.preventDefault();
this.dist.startX = event.clientX;
movetype = 'mousemove';
} else {
this.dist.startX = event.changedTouches[0].clientX;
movetype = 'touchmove';
}
this.wrapper.addEventListener(movetype, this.onMove);
this.transition(false);
}
onMove(event) {
const pointerPosition = (event.type === 'mousemove') ? event.clientX : event.changedTouches[0].clientX;
const finalPosition = this.updatePosition(pointerPosition);
this.moveSlide(finalPosition);
}
onEnd(event) {
const movetype = (event.type === 'mouseup') ? 'mousemove' : 'touchmove';
this.wrapper.removeEventListener(movetype, this.onMove);
this.dist.finalPosition = this.dist.movePosition;
this.transition(true);
this.changeSlideOnEnd();
}
changeSlideOnEnd() {
if (this.dist.movement > 120 && this.index.next !== undefined) {
this.activeNextSlide();
} else if (this.dist.movement < -120 && this.index.prev !== undefined) {
this.activePrevSlide();
} else {
this.changeSlide(this.index.active);
}
}
addSlideEvents() {
this.wrapper.addEventListener('mousedown', this.onStart);
this.wrapper.addEventListener('touchstart', this.onStart);
this.wrapper.addEventListener('mouseup', this.onEnd);
this.wrapper.addEventListener('touchend', this.onEnd);
}
// Slides config
slidePosition(slide) {
const margin = (this.wrapper.offsetWidth - slide.offsetWidth) / 2;
return -(slide.offsetLeft - margin);
}
slidesConfig() {
this.slideArray = [...this.slide.children].map((element) => {
const position = this.slidePosition(element);
return { position, element };
});
}
slidesIndexNav(index) {
const last = this.slideArray.length - 1;
this.index = {
prev: index ? index - 1 : undefined,
active: index,
next: index === last ? undefined : index + 1,
}
}
changeSlide(index) {
const activeSlide = this.slideArray[index];
this.moveSlide(activeSlide.position);
this.slidesIndexNav(index);
this.dist.finalPosition = activeSlide.position;
this.changeActiveClass();
this.wrapper.dispatchEvent(this.changeEvent);
}
changeActiveClass() {
this.slideArray.forEach(item => item.element.classList.remove(this.activeClass));
this.slideArray[this.index.active].element.classList.add(this.activeClass);
}
activePrevSlide() {
if (this.index.prev !== undefined) this.changeSlide(this.index.prev);
}
activeNextSlide() {
if (this.index.next !== undefined) this.changeSlide(this.index.next);
}
onResize() {
setTimeout(() => {
this.slidesConfig();
this.changeSlide(this.index.active);
}, 1000);
}
addResizeEvent() {
window.addEventListener('resize', this.onResize);
}
bindEvents() {
this.onStart = this.onStart.bind(this);
this.onMove = this.onMove.bind(this);
this.onEnd = this.onEnd.bind(this);
this.activePrevSlide = this.activePrevSlide.bind(this);
this.activeNextSlide = this.activeNextSlide.bind(this);
this.onResize = debounce(this.onResize.bind(this), 200);
}
init() {
this.bindEvents();
this.transition(true);
this.addSlideEvents();
this.slidesConfig();
this.addResizeEvent();
this.changeSlide(0);
return this;
}
}
export default class SlideNav extends Slide {
constructor(slide, wrapper) {
super(slide, wrapper);
this.bindControlEvents();
}
addArrow(prev, next) {
this.prevElement = document.querySelector(prev);
this.nextElement = document.querySelector(next);
this.addArrowEvent();
}
addArrowEvent() {
this.prevElement.addEventListener('click', this.activePrevSlide);
this.nextElement.addEventListener('click', this.activeNextSlide);
}
createControl() {
const control = document.createElement('ul');
control.dataset.control = 'slide';
this.slideArray.forEach((item, index) => {
control.innerHTML += `<li>${index + 1}</li>`;
});
this.wrapper.appendChild(control);
return control;
}
eventControl(item, index) {
item.addEventListener('click', (event) => {
event.preventDefault();
this.changeSlide(index);
});
this.wrapper.addEventListener('changeEvent', this.activeControlItem);
}
activeControlItem() {
this.controlArray.forEach(item => item.classList.remove(this.activeClass));
this.controlArray[this.index.active].classList.add(this.activeClass);
}
addControl(customControl) {
this.control = document.querySelector(customControl) || this.createControl();
this.controlArray = [...this.control.children];
this.activeControlItem();
this.controlArray.forEach(this.eventControl);
}
bindControlEvents() {
this.eventControl = this.eventControl.bind(this);
this.activeControlItem = this.activeControlItem.bind(this);
}
}
Thank you very much,
best regards.
Franks.
After debugging your case on Codepen, I finally figured it out.
Basically you need to know 2 changes that I made:
The first one is handling the edge cases:
When you're at the end and click Next, you should go to the beginning
When you're at the beginning and click Previous, you should go to the end
The 2nd aspect is making this slider autoplaying or looping.
Now for the code
For the 1st change (the edge cases), modify in your code the methods activePrevSlide and activeNextSlide as the following:
activePrevSlide() {
if (this.index.prev !== undefined)
this.changeSlide(this.index.prev);
else
this.changeSlide(this.slideArray.length - 1);
}
activeNextSlide() {
if (this.index.next !== undefined)
this.changeSlide(this.index.next);
else
this.changeSlide(0);
}
For the 2nd aspect, add at the end of script.js, this statement:
setInterval(slide.activeNextSlide, 3000);
It will autoplay each 3 seconds (you can change it definitely).
Finally, this is the full code, if you want to play here:
function debounce(callback, delay) {
let timer;
return (...args) => {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
callback(...args);
timer = null;
}, delay);
};
}
class Slide {
constructor(slide, wrapper) {
this.slide = document.querySelector(slide)
this.wrapper = document.querySelector(wrapper);
this.dist = { finalPosition: 0, startX: 0, movement: 0 }
this.activeClass = 'active';
this.changeEvent = new Event('changeEvent');
}
transition(active) {
this.slide.style.transition = active ? 'transform .3s' : '';
}
moveSlide(distX) {
this.dist.movePosition = distX;
this.slide.style.transform = `translate3d(${distX}px, 0, 0)`;
}
updatePosition(clientX) {
this.dist.movement = (this.dist.startX - clientX) * 1.6;
return this.dist.finalPosition - this.dist.movement;
}
onStart(event) {
let movetype;
if (event.type === 'mousedown') {
event.preventDefault();
this.dist.startX = event.clientX;
movetype = 'mousemove';
} else {
this.dist.startX = event.changedTouches[0].clientX;
movetype = 'touchmove';
}
this.wrapper.addEventListener(movetype, this.onMove);
this.transition(false);
}
onMove(event) {
const pointerPosition = (event.type === 'mousemove') ? event.clientX : event.changedTouches[0].clientX;
const finalPosition = this.updatePosition(pointerPosition);
this.moveSlide(finalPosition);
}
onEnd(event) {
const movetype = (event.type === 'mouseup') ? 'mousemove' : 'touchmove';
this.wrapper.removeEventListener(movetype, this.onMove);
this.dist.finalPosition = this.dist.movePosition;
this.transition(true);
this.changeSlideOnEnd();
}
changeSlideOnEnd() {
if (this.dist.movement > 120 && this.index.next !== undefined) {
this.activeNextSlide();
} else if (this.dist.movement < -120 && this.index.prev !== undefined) {
this.activePrevSlide();
} else {
this.changeSlide(this.index.active);
}
}
addSlideEvents() {
this.wrapper.addEventListener('mousedown', this.onStart);
this.wrapper.addEventListener('touchstart', this.onStart);
this.wrapper.addEventListener('mouseup', this.onEnd);
this.wrapper.addEventListener('touchend', this.onEnd);
}
// Slides config
slidePosition(slide) {
const margin = (this.wrapper.offsetWidth - slide.offsetWidth) / 2;
return -(slide.offsetLeft - margin);
}
slidesConfig() {
this.slideArray = [...this.slide.children].map((element) => {
const position = this.slidePosition(element);
return { position, element };
});
}
slidesIndexNav(index) {
const last = this.slideArray.length - 1;
this.index = {
prev: index ? index - 1 : undefined,
active: index,
next: index === last ? undefined : index + 1,
}
}
changeSlide(index) {
const activeSlide = this.slideArray[index];
this.moveSlide(activeSlide.position);
this.slidesIndexNav(index);
this.dist.finalPosition = activeSlide.position;
this.changeActiveClass();
this.wrapper.dispatchEvent(this.changeEvent);
}
changeActiveClass() {
this.slideArray.forEach(item => item.element.classList.remove(this.activeClass));
this.slideArray[this.index.active].element.classList.add(this.activeClass);
}
activePrevSlide() {
if (this.index.prev !== undefined)
this.changeSlide(this.index.prev);
else
this.changeSlide(this.slideArray.length - 1);
}
activeNextSlide() {
if (this.index.next !== undefined)
this.changeSlide(this.index.next);
else
this.changeSlide(0);
}
onResize() {
setTimeout(() => {
this.slidesConfig();
this.changeSlide(this.index.active);
}, 1000);
}
addResizeEvent() {
window.addEventListener('resize', this.onResize);
}
bindEvents() {
this.onStart = this.onStart.bind(this);
this.onMove = this.onMove.bind(this);
this.onEnd = this.onEnd.bind(this);
this.activePrevSlide = this.activePrevSlide.bind(this);
this.activeNextSlide = this.activeNextSlide.bind(this);
this.onResize = debounce(this.onResize.bind(this), 200);
}
init() {
this.bindEvents();
this.transition(true);
this.addSlideEvents();
this.slidesConfig();
this.addResizeEvent();
this.changeSlide(0);
return this;
}
}
class SlideNav extends Slide {
constructor(slide, wrapper) {
super(slide, wrapper);
this.bindControlEvents();
}
addArrow(prev, next) {
this.prevElement = document.querySelector(prev);
this.nextElement = document.querySelector(next);
this.addArrowEvent();
}
addArrowEvent() {
this.prevElement.addEventListener('click', this.activePrevSlide);
this.nextElement.addEventListener('click', this.activeNextSlide);
}
createControl() {
const control = document.createElement('ul');
control.dataset.control = 'slide';
this.slideArray.forEach((item, index) => {
control.innerHTML += `<li>${index + 1}</li>`;
});
this.wrapper.appendChild(control);
return control;
}
eventControl(item, index) {
item.addEventListener('click', (event) => {
event.preventDefault();
this.changeSlide(index);
});
this.wrapper.addEventListener('changeEvent', this.activeControlItem);
}
activeControlItem() {
this.controlArray.forEach(item => item.classList.remove(this.activeClass));
this.controlArray[this.index.active].classList.add(this.activeClass);
}
addControl(customControl) {
this.control = document.querySelector(customControl) || this.createControl();
this.controlArray = [...this.control.children];
this.activeControlItem();
this.controlArray.forEach(this.eventControl);
}
bindControlEvents() {
this.eventControl = this.eventControl.bind(this);
this.activeControlItem = this.activeControlItem.bind(this);
}
}
const slide = new SlideNav('.slide', '.slide-wrapper');
slide.init();
slide.addArrow('.prev', '.next');
slide.addControl('.custom-controls');
setInterval(slide.activeNextSlide, 3000);
body {
margin: 0px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
}
ul {
padding: 0px;
margin: 0px;
list-style: none;
}
img {
display: block;
max-width: 100%;
}
.slide-wrapper {
overflow: hidden;
}
.slide {
display: flex;
}
.slide:hover {
will-change: transform;
}
.slide li {
flex-shrink: 0;
max-width: 600px;
margin: 0 20px;
border-radius: 4px;
overflow: hidden;
box-shadow: 0 2px 4px rgba(0,0,0,.4);
opacity: .8;
transform: scale(.8);
transition: .4s;
}
.slide li.active {
opacity: 1;
transform: scale(1);
}
[data-control="slide"] {
display: flex;
justify-content: center;
margin-top: 20px;
}
[data-control="slide"] li a {
display: block;
width: 12px;
height: 12px;
background: #FB5;
border-radius: 50%;
overflow: hidden;
text-indent: -999px;
margin: 5px;
}
[data-control="slide"] li.active a, [data-control="slide"] li a:hover {
background: #E54;
}
.custom-controls {
display: flex;
justify-content: center;
margin-top: 40px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.custom-controls li {
opacity: .8;
transform: scale(.8);
width: 40px;
height: 40px;
border-radius: 50%;
overflow: hidden;
margin: 2px;
box-shadow: 0 2px 2px rgba(0,0,0,.5);
transition: .3s;
cursor: pointer;
}
.custom-controls li.active {
opacity: 1;
transform: scale(1);
}
.arrow-nav {
display: flex;
justify-content: space-around;
margin: 20px 10px 0 10px;
}
.arrow-nav button {
cursor: pointer;
border: none;
border-radius: 50%;
color: white;
width: 30px;
height: 30px;
background: #999 url('../img/arrow.svg') center center no-repeat;
outline: none;
}
.arrow-nav button:hover {
background: #333 url('../img/arrow.svg') center center no-repeat;
transition: ease-in-out .3s;
}
.arrow-nav button.prev {
transform: rotate(-180deg);
}
.wrap-controls {
display: flex;
justify-content: center;
align-items: center;
}
<div class="slide-wrapper">
<ul class="slide">
<li><img src="https://i.stack.imgur.com/2fkLR.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/gN1Ri.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/FgqYP.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/su1na.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/vZYry.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/5dXtQ.jpg" alt=""></li>
</ul>
</div>
<div class="wrap-controls">
<div class="arrow-nav">
<button class="prev"></button>
</div>
<ul class="custom-controls">
<li><img src="https://i.stack.imgur.com/2fkLR.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/gN1Ri.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/FgqYP.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/su1na.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/vZYry.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/5dXtQ.jpg" alt=""></li>
</ul>
<div class="arrow-nav">
<button class="next"></button>
</div>
</div>
Regards

Having a tremendous amount of difficulty getting play buttons to work from inside their own container, separate from the HTML

This code I am trying to get working has the play buttons at the bottom inside their own container.
How the code works is, click on a button, and then a video should appear on the screen.
To test jsitor code, press run, not update.
https://jsitor.com/MIYiywN4HC / https://jsfiddle.net/kxhyLdr8/
<div class="playButtonContainer">
<button class="playa cover" type="button"></button>
<button class="playb cover" type="button"></button>
<button class="playc cover" type="button"></button>
<button class="playd cover" type="button"></button>
<button class="playe cover" type="button"></button>
<button class="playf cover" type="button"></button>
<button class="playg cover" type="button"></button>
<button class="playh cover" type="button"></button>
<button class="playi cover" type="button"></button>
</div>
What is weird about the above code is that after clicking on the buttons, no errors are appearing, when there should be.
By errors I mean, in the console log, I was referring to, usually errors will appear in there if something is broken. I am stuck trying to figure out how to get the broken code working.
For comparison, here is a demo code of it working with the play buttons not inside their own container.
The only difference between the demo code and the code I am working on is that in the code I am working on, the play buttons are inside their own container.
To test jsitor code, press run, not update.
https://jsitor.com/qTWoiuHp7z / https://jsfiddle.net/24xf0avp/
The only difference between the working and non working example is just the extra layer of HTML.
Nothing was touched in any other part of the code.
Would anyone be able to check and see if their able that code to work, the code with the play buttons in their own container?
No one has been able to figure out how that would be done, getting the play buttons to work inside their own container.
I was told by my instructor, the code needs to work with the play buttons inside their own container, separate from the HTML.
I have no idea how that would be done, and because there are no errors appearing in the code, that further confuses me.
I was told this:
The problem here is inside the body of the function showCover, which
adds the class active and calls the function show (which removes the
class hide) to and from the parent of the button , instead of the
.container element where it should be.
Could it be that you just need to extend your JS code so that it
reaches the inner html node?
on the button click event it probably captures the parent element
instead of the target element?
Binding of the click of the play button
So you should either wrap them together, put the play button in the
outer, and then go to the closest('.outer') then
querySelector('.video') or whatever you want to do. Or put an
attribute on the .playa button (eg data-player-id="play1") that you
can use to directly find from the click and then use this to call the
.container.play1 element
Here I created a very simple demo with one button.
<div class="playButtonContainer">
<button class="playa cover" type="button"></button>
</div>
Here is the working demo code with only 1 button.
https://jsitor.com/Qer_1Oi9Jv / https://jsfiddle.net/1bmrwuzn/
Here is the broken code with only 1 button.
https://jsitor.com/D38vgjs3g / https://jsfiddle.net/gt57k29h/
What is meant by broken is, is that it is not working or functioning the same way as the demo code I provided.
Smaller, reproducible example code:
const manageCover = (function makeManageCover() {
const config = {};
const body = document.body;
let currentPlayButton = {};
function show(el) {
el.classList.remove("hide");
}
function hide(el) {
el.classList.add("hide");
}
function hideAll(elements) {
elements.forEach(hide);
}
function resetBackground(backgroundSelector) {
const allBackgrounds = document.querySelectorAll(backgroundSelector);
function hideBackground(background) {
background.classList.add("bg1");
}
allBackgrounds.forEach(hideBackground);
}
function resetButtons(buttonSelector) {
const allButtons = document.querySelectorAll(buttonSelector);
function hideButton(button) {
button.classList.add("isOpen");
}
allButtons.forEach(hideButton);
}
function resetPage() {
resetBackground("body");
resetButtons(".outer");
}
function markAsPlayed(played) {
played.classList.add("played");
}
function showCover(playButton) {
hideAll(config.containers);
resetPage();
markAsPlayed(playButton);
const cover = playButton.parentElement;
cover.classList.add("active");
show(cover);
}
function animationEndHandler(evt) {
const animationName = evt.animationName;
if (animationName === "initial-fade") {
body.classList.remove("initial-fade");
showCover(currentPlayButton);
}
}
function coverClickHandler(evt) {
currentPlayButton = evt.currentTarget;
body.classList.add("initial-fade");
}
function addClickToButtons(playButtons) {
playButtons.forEach(function playButtonHandler(playButton) {
playButton.addEventListener("click", coverClickHandler);
});
}
function addCoverHandler(coverSelector, handler) {
const cover = document.querySelector(coverSelector);
cover.addEventListener("click", handler);
}
function init(selectors) {
config.containers = document.querySelectorAll(selectors.container);
const playButtons = document.querySelectorAll(selectors.playButton);
addClickToButtons(playButtons);
body.addEventListener("animationend", animationEndHandler);
}
return {
addCoverHandler,
init
};
}());
const manageUI = (function makeManageUI() {
const body = document.body;
const players = [];
function findPlayers() {
const allCovers = document.querySelectorAll(".cover");
const allWrappers = document.querySelectorAll(".wrap");
allCovers.forEach(function addToPlayers(cover, index) {
players.push({
"cover": cover,
"wrapper": allWrappers[index]
});
});
}
// inline arrow function, direct return
function getWrapper(cover) {
const index = players.findIndex(
(player) => player.cover === cover
);
return players[index].wrapper;
}
function resetBackground(backgroundSelector) {
const allBackgrounds = document.querySelectorAll(backgroundSelector);
function showBackground(background) {
background.classList.remove("bg1");
}
allBackgrounds.forEach(showBackground);
}
function resetCurtains(curtainSelector) {
const allCurtains = document.querySelectorAll(curtainSelector);
function showCurtain(curtain) {
curtain.classList.remove("active");
}
allCurtains.forEach(showCurtain);
}
function showAllButtons(buttonSelector) {
const allButtons = document.querySelectorAll(buttonSelector);
function showButton(button) {
button.classList.remove("hide");
}
allButtons.forEach(showButton);
}
function resetButtons(buttonSelector) {
const allButtons = document.querySelectorAll(buttonSelector);
function showButton(button) {
button.classList.remove("isOpen");
}
allButtons.forEach(showButton);
}
function animationEndHandler(evt) {
const animationName = evt.animationName;
console.log(animationName);
if (animationName === "fadingOut") {
fadeReset();
}
}
function fadeReset() {
body.classList.remove("fadingOut");
resetBackground("body");
resetCurtains(".with-curtain");
showAllButtons(".hide");
resetButtons(".outer");
}
function resetPage() {
body.classList.add("fadingOut");
}
function exitClickHandler() {
resetPage();
}
function addClickToExit(exitButtons) {
exitButtons.forEach(function addExitButtonHandler(exitButtons) {
exitButtons.addEventListener("click", exitClickHandler);
});
}
function addExitHandlers(callback) {
const resetVideo = document.querySelectorAll(".exit");
resetVideo.forEach(function resetVideoHandler(video) {
video.addEventListener("click", callback);
});
}
function init() {
findPlayers();
const exitButtons = document.querySelectorAll(".exit");
addClickToExit(exitButtons);
body.addEventListener("animationend", animationEndHandler);
}
return {
addExitHandlers,
getWrapper,
init
};
}());
const videoPlayer = (function makeVideoPlayer() {
const tag = document.createElement("script");
tag.src = "https://www.youtube.com/player_api";
const firstScriptTag = document.getElementsByTagName("script")[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
function onPlayerReady(event) {
const player = event.target;
player.setVolume(100);
}
function onPlayerStateChange(event) {
const player = event.target;
return player;
}
function addPlayer(video, playerOptions) {
playerOptions.videoId = playerOptions.videoId || video.dataset.id;
playerOptions.events = playerOptions.events || {};
playerOptions.events.onReady = onPlayerReady;
playerOptions.events.onStateChange = onPlayerStateChange;
const player = new YT.Player(video, playerOptions);
return player;
}
return {
addPlayer
};
}());
const managePlayer = (function makeManagePlayer() {
const playerVars = {
autoplay: 0,
controls: 1,
disablekb: 1,
enablejsapi: 1,
fs: 0,
iv_load_policy: 3
};
const defaults = {
height: 360,
host: "https://www.youtube-nocookie.com",
playerVars,
width: 640
};
function show(el) {
el.classList.remove("hide");
}
function combinePlayerOptions(opts1 = {}, opts2 = {}) {
const combined = Object.assign({}, opts1, opts2);
Object.keys(opts1).forEach(function checkObjects(prop) {
if (typeof opts1[prop] === "object") {
combined[prop] = Object.assign({}, opts1[prop], opts2[prop]);
}
});
return combined;
}
function createPlayer(videoWrapper, playerOptions = {}) {
const video = videoWrapper.querySelector(".video");
const options = combinePlayerOptions(defaults, playerOptions);
return videoPlayer.addPlayer(video, options);
}
function playerAdder(wrapper, playerOptions) {
return function addPlayerCallback() {
initPlayer(wrapper, playerOptions);
};
}
function removePlayer(wrapper) {
wrapper.player.destroy();
delete wrapper.player;
console.log("removePlayer");
}
function removePlayerHandler(evt) {
const el = evt.target;
const container = el.closest(".container");
const wrapper = container.querySelector(".wrap");
if (wrapper.player) {
return removePlayer(wrapper);
}
}
function initPlayer(wrapper, playerOptions) {
show(wrapper);
const player = createPlayer(wrapper, playerOptions);
wrapper.player = player;
}
return {
adder: playerAdder,
removePlayerHandler
};
}());
const players = (function coverUIPlayerFacade() {
function addPlayer(coverSelector, playerOptions) {
const cover = document.querySelector(coverSelector);
const wrapper = manageUI.getWrapper(cover);
const callback = managePlayer.adder(wrapper, playerOptions);
manageCover.addCoverHandler(coverSelector, callback);
}
function init() {
manageCover.init({
container: ".container",
playButton: ".cover"
});
manageUI.init({});
manageUI.addExitHandlers(managePlayer.removePlayerHandler);
}
return {
add: addPlayer,
init
};
}());
players.init();
function onYouTubeIframeAPIReady() {
players.add(".playa", {});
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
body {
background: #353198;
}
.initial-fade {
animation: initial-fade 500ms ease forwards;
}
#keyframes initial-fade {
to {
opacity: 0;
}
}
.initial-fade,
.fadingOut {
cursor: default;
}
.initial-fade .cover,
.initial-fade .cover * {
pointer-events: none !important;
}
.container {
display: flex;
justify-content: center;
position: relative;
/*z-index: 2;*/
}
.container.active {
flex: 1 0 0;
}
/*body.*/
.bg1 {
animation: fadeInBody 5s ease 0s forwards;
animation-delay: 0s;
opacity: 0;
}
#keyframes fadeInBody {
100% {
opacity: 1;
}
}
/*body.*/
.bg1 .with-curtain:before {
content: "";
position: fixed;
/*z-index: 1;*/
top: 0;
left: 0;
right: 0;
bottom: 0;
background-size: 165px 165px;
background-image:
}
.playButtonContainer {
display: flex;
flex-wrap: wrap;
min-height: 100%;
margin: auto;
justify-content: center;
align-content: center;
width: 290px;
gap: 10px;
animation: fadeInButtons 3s ease 0s forwards;
}
#keyframes fadeInButtons {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.outer.isOpen {
width: auto;
}
.fadingOut .isOpen {
animation: fadingOut 1s;
animation-delay: 11.3s;
}
#keyframes fadingOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.inner-container {
display: none;
}
/* when container is active hide the cssPlay and show the inner container*/
.container.active .cover {
display: none;
}
.container.active .inner-container {
display: flex;
}
.container.active .inner-container.curtain {
display: block;
}
.cover {
-webkit-appearance: none;
appearance: none;
display: flex;
justify-content: center;
align-items: center;
position: relative;
width: 90px;
height: 90px;
border-radius: 50%;
cursor: pointer;
border: 9px solid blue;
background: transparent;
filter: drop-shadow(3px 3px 3px rgba(0, 0, 0, 0.7));
}
.cover::before {
content: "";
width: 0;
height: 0;
border-top: 20px solid transparent;
border-bottom: 20px solid transparent;
border-left: 27px solid blue;
transform: translateX(4px);
}
.cover:hover {
box-shadow: 0 0 0 5px rgba(43, 179, 20, 0.5);
}
.cover:focus {
outline: 0;
box-shadow: 0 0 0 5px rgba(0, 255, 255, 0.5);
}
.played {
border-color: green;
}
.played::before {
border-left-color: green;
}
.curtain {
flex: 1 0 0;
margin: auto;
max-width: 642px;
/*box-shadow: inset 0 -2px 0px 0px #0a0a0a;*/
border: 20px solid black;
border-radius: 3.2px;
border-color: #000 #101010 #000 #101010;
position: relative;
}
.curtain::before {
content: '';
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: radial-gradient(circle, transparent 0% 35%, #0a0a0a 35%);
}
.ratio-keeper {
position: relative;
height: 0;
padding-top: 56.25%;
margin: auto;
overflow: hidden;
border: 1px solid #333;
}
.video-frame {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
iframe {
user-select: none;
}
.panel-left,
.panel-right {
position: absolute;
height: 100%;
width: calc(50% + 1px);
/* rounding error fix */
top: 0%;
transition: all ease 10s;
/*background-image: url("https://picsum.photos/600");
background-size: cover;
background-repeat: no-repeat;
background-position: center;*/
overflow: hidden;
}
.panel-left {
left: 0;
/*background-color: rgb(91, 96, 106);*/
}
.panel-right {
right: 0;
/*background-color: rgb(229, 211, 211);*/
}
.panel-left::before,
.panel-right::before {
content: "";
position: absolute;
height: 100%;
width: 200%;
top: 0;
left: 0;
background-size: auto;
background-repeat: no-repeat;
background-position: 0 0;
}
.panel-right::before {
left: -100%;
}
.container.active .curtain .panel-left {
animation: curtain1-open 8s forwards 520ms;
}
#keyframes curtain1-open {
to {
transform: translateX(calc(-100% - 1px));
}
}
.container.active .curtain .panel-right {
animation: curtain2-open 8s forwards 520ms;
}
#keyframes curtain2-open {
to {
transform: translateX(calc(100% + 1px));
}
}
.fadingOut .container.active .curtain .panel-left {
animation: curtain1-close 8s ease forwards;
transform: translateX(calc(-100% - 1px));
animation-delay: 3.3s;
}
#keyframes curtain1-close {
to {
transform: translateX(0);
}
}
.fadingOut .container.active .curtain .panel-right {
animation: curtain2-close 8s ease forwards;
transform: translateX(calc(100% + 1px));
animation-delay: 3.3s;
}
#keyframes curtain2-close {
to {
transform: translateX(0);
}
}
.exit {
position: absolute;
top: auto;
bottom: -47px;
margin: auto;
right: 0;
left: 0;
width: 47px;
height: 47px;
cursor: pointer;
background: black;
border-radius: 50%;
border: 5px solid red;
animation: fadeInExit 1s forwards;
opacity: 0;
pointer-events: none;
}
.exit::before,
.exit::after {
content: "";
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
margin: auto;
width: 100%;
height: 5px;
background: red;
transform: rotate(45deg);
transition: all 1s ease;
}
.exit::after {
transform: rotate(-45deg);
}
#keyframes fadeInExit {
99% {
pointer-events: none;
}
100% {
pointer-events: initial;
opacity: 1;
}
}
.exit:hover::before,
.exit:hover::after,
.fadingOut .exit::before,
.fadingOut .exit::after {
background: green;
}
.fadingOut .exit {
animation: fadeOutExit 8s forwards;
pointer-events: none;
opacity: 1;
}
#keyframes fadeOutExit {
to {
opacity: 0;
}
}
.hide {
display: none;
}
<div class="outer">
<div class="container play1 with-curtain">
<div class="inner-container curtain curtain1">
<div class="ratio-keeper">
<div class="wrap">
<div class="video video-frame" data-id="CHahce95B1g"></div>
</div>
<div class="sliding-panels">
<div class="panel-left"></div>
<div class="panel-right"></div>
</div>
</div>
<button class="exit" type="button" title="Exit" aria-label="Close"></button>
</div>
</div>
</div>
<div class="playButtonContainer">
<button class="playa cover" type="button" aria-label="Open"></button>
</div>

Template Literal Function not working as expected

I have a function that turns an array into modal window links as a template literal.
The code that creates the links works fine outside of the function
But once it gets rendered in the function it no longer works. I can't find any errors, but it does NOT work.
However, if I copy the HTML that the function renders and save that as actual HTML, that works fine on its own.
A good chunk of the JavaScript portion of the code is posted below. A full version is on Codepen.
There are two sections in the example on Codepen:
The first section has the code as it's rendered by the function.
The second section is copied from the Elements tab in Developer Tools and saved as actual HTML.
"use strict";
const modalBtns = document.querySelectorAll(".modal-button");
const modalWin = document.querySelector(".modal-window");
const closeBtn = document.querySelector(".close-modal");
const modal_iframe = document.getElementById("modal_iframe");
modalBtns.forEach((item) => {
item.addEventListener("click", function (e) {
let modal = e.currentTarget;
if (modal.dataset.target) {
let modalID = modal.dataset.target;
document.getElementById(modalID).style.display = "block";
}
if (modal.dataset.iframe) {
modal_iframe.src = modal.dataset.iframe;
document
.querySelector(".button-footer")
.addEventListener("click", function () {
window.open(modal.dataset.iframe, "_blank");
});
}
if (modal.dataset.header) {
document.querySelector(
".modal-header"
).innerHTML = `<h1>${modal.dataset.header}</h1>`;
}
if (modal.dataset.dimensions) {
document
.querySelector(".modal-window")
.setAttribute("style", modal.dataset.dimensions);
}
function loadIframe() {
let frame = document.getElementById("modal_window");
frame.style.height =
frame.contentWindow.document.body.scrollHeight + "px";
}
if (document.querySelector("#modal_window")) {
setTimeout(function () {
loadIframe;
}, 2000);
}
if (modal.dataset.reload && modal.dataset.reload === "1") {
document
.querySelector(".close-modal")
.addEventListener("click", function (e) {
console.log("parent.location.reload() pending...");
parent.location.reload();
});
}
/*======= All EventListeners Below Close Modal ================*/
closeBtn.addEventListener("click", function (e) {
document.querySelector(".modal-background").style.display = "none";
});
window.addEventListener("click", function (e) {
if (e.currentTarget === document.querySelector(".modal-background")) {
document.querySelector(".modal-background").style.display = "none";
}
});
document.body.addEventListener("keydown", (e) => {
if (e.key === "Escape") {
document.querySelector(".modal-background").style.display = "none";
}
});
});
});
const main = document.querySelector("main");
const modal_links = [
{
link: "https://notation.netcentrx.net/staff/",
header: "Musical Staff",
thb: "notation",
w_h: "min-width:60vw;max-width:600px;height:650px",
reload: 0
},
{
link: "https://wsl.netcentrx.net/",
header: "WSL Commands",
thb: "wsl",
w_h: "min-width:60vw;max-width:600px;height:650px",
reload: 0
}
];
let modalLink = "";
function createModalLinks(
link,
modalID,
header,
img,
w_h = "width:90vw;height:600px",
reload = "0"
) {
modalLink = `
<a href="javascript:void(0)" class="modal-button" onclick="console.log('onclick handler:${link}');" data-header="${header}" data-target="${modalID}" data-iframe="${link}" data-dimensions="${w_h};margin-top:20px" data-reload="${reload}">
<img src="https://resume.netcentrx.net/examples/${img}.jpg" title="${img}" width="50">
</a>
`;
return modalLink;
}
let theLinks = "";
modal_links.forEach((item) => {
theLinks += createModalLinks(
item.link,
"modal_window",
item.header,
item.thb,
item.w_h,
item.reload
);
});
main.innerHTML = theLinks;
My apologies in advance for it not being stripped down to just the bare minimum. But in order to replicate the problem, it required more code than it probably should have had. I've been reworking this for the better part of a day without any insight as to what the real problem is. I've been creating functions using template literals just like this for years now, usually with a high success rate. Whatever the problem is, I need to know so I can get past it. The only anomaly that I spotted is that–in the version on Codepen–the only thing that doesn't work in that version is once the modal is displayed clicking on the background does not dismiss the modal like it does elsewhere. If that's significant as to what the problem may be, I'm not sure what the connection is.
Usually when I take the time to painstakingly write everything out like this I typically either spot the problem or figure out an alternative solution so there's no need to actually post a question, but this does not appear to be one of those times. As always, your help is very much appreciated!
The issue appears to just be timing. Your code is executed in order, and the first part gets all of the modal buttons on the page and sets the appropriate event listeners. Then the second part of your code adds 2 modal buttons, which were not present earlier.
By simply wrapping the first part of your code in a function and calling it later (or swapping the order of those two parts of code), everything works as expected.
"use strict";
const _InitModal = () => {
const modalBtns = document.querySelectorAll(".modal-button");
const modalWin = document.querySelector(".modal-window");
const closeBtn = document.querySelector(".close-modal");
const modal_iframe = document.getElementById("modal_iframe");
modalBtns.forEach((item) => {
item.addEventListener("click", function (e) {
console.log("e.currentTarget = " + e.currentTarget);
let modal = e.currentTarget;
console.log("modal = " + modal);
if (modal.dataset.target) {
let modalID = modal.dataset.target;
console.log("modal.dataset.target = " + modal.dataset.target);
document.getElementById(modalID).style.display = "block";
}
if (modal.dataset.iframe) {
modal_iframe.src = modal.dataset.iframe;
document
.querySelector(".button-footer")
.addEventListener("click", function () {
window.open(modal.dataset.iframe, "_blank");
});
}
if (modal.dataset.header) {
document.querySelector(
".modal-header"
).innerHTML = `<h1>${modal.dataset.header}</h1>`;
console.log(`modal.dataset.header = ${modal.dataset.header}`);
}
if (modal.dataset.dimensions) {
document
.querySelector(".modal-window")
.setAttribute("style", modal.dataset.dimensions);
}
function loadIframe() {
let frame = document.getElementById("modal_window");
frame.style.height =
frame.contentWindow.document.body.scrollHeight + "px";
}
if (document.querySelector("#modal_window")) {
setTimeout(function () {
loadIframe;
}, 2000);
}
// e.preventDefault();
if (modal.dataset.reload && modal.dataset.reload === "1") {
document
.querySelector(".close-modal")
.addEventListener("click", function (e) {
console.log("parent.location.reload() pending...");
parent.location.reload();
});
}
/*======= All EventListeners Below Close Modal ================*/
closeBtn.addEventListener("click", function (e) {
document.querySelector(".modal-background").style.display = "none";
});
window.addEventListener("click", function (e) {
console.log("e.currentTarget = " + e.currentTarget);
if (e.currentTarget === document.querySelector(".modal-background")) {
document.querySelector(".modal-background").style.display = "none";
}
});
document.body.addEventListener("keydown", (e) => {
if (e.key === "Escape") {
console.log("e=" + e);
document.querySelector(".modal-background").style.display = "none";
}
});
});
});
}
const main = document.querySelector("main");
const modal_links = [
{
link: "https://notation.netcentrx.net/staff/",
header: "Musical Staff",
thb: "notation",
w_h: "min-width:60vw;max-width:600px;height:650px",
reload: 0
},
{
link: "https://wsl.netcentrx.net/",
header: "WSL Commands",
thb: "wsl",
w_h: "min-width:60vw;max-width:600px;height:650px",
reload: 0
}
];
function createModalLinks(
link,
modalID,
header,
img,
w_h = "width:90vw;height:600px",
reload = "0"
) {
let modalLink = "";
modalLink = `
<a href="javascript:void(0)" class="modal-button" onclick="console.log('onclick handler:${link}');" data-header="${header}" data-target="${modalID}" data-iframe="${link}" data-dimensions="${w_h};margin-top:20px" data-reload="${reload}">
<img src="https://resume.netcentrx.net/examples/${img}.jpg" title="${img}" width="50">
</a>`;
return modalLink;
}
let theLinks = "";
modal_links.forEach((item) => {
theLinks += createModalLinks(
item.link,
"modal_window",
item.header,
item.thb,
item.w_h,
item.reload
);
});
main.innerHTML = theLinks;
_InitModal();
.modal-background {
font-family: sans-serif;
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
display: none;
overflow: auto;
background-color: rgba(0, 0, 0, 0.9);
z-index: 9999;
background: rgba(55, 55, 55, 0.6);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
.modal-window {
position: relative;
background-color: #ffffff;
width: 50%;
margin: 10% auto;
border-radius: 0.5rem;
padding: 0.75rem;
border: 1px groove #ccc;
/* box-shadow: 1px 1px 1px #999, 2px 2px 2px #000; */
}
.close-modal:hover,
.close-modal:focus {
color: rgba(255, 255, 255, 1);
cursor: pointer;
background: red;
transition: 1s;
text-shadow: 1px 1px 1px #999, 2px 2px 2px #000;
}
button.close-modal {
position: absolute;
top: -0.75rem;
right: -0.75rem;
padding: 0.05rem 0.75rem;
background: #999;
color: #ccc;
border-radius: 50%;
border: none;
outline: none;
-webkit-transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1);
transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1);
-webkit-animation-name: animatebottom;
-webkit-animation-duration: 1.5s;
animation-name: animatebottom;
animation-duration: 1.5s;
}
button.close-modal::before {
content: "\D7";
font-size: 2rem;
}
.modal-window {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
-webkit-animation-name: animatetop;
-webkit-animation-duration: 0.5s;
animation-name: animatetop;
animation-duration: 0.5s;
}
.modal-header {
height: 30px;
text-align: center;
width: 100%;
background: #fff;
padding: 0.2rem;
}
.modal-header h1 {
font-size: 1.1rem;
}
.modal-footer {
height: 20px;
text-align: center;
width: 100%;
background: #fff;
padding: 0.2rem;
}
.modal-content {
background-color: #fff;
height: calc(100% - 70px);
border-radius: 0.5rem;
border: 0.1rem groove #ddd;
overflow: hidden;
}
.button-footer {
background: #fff;
border-radius: 0.5rem;
border: 1px outset #aaa;
padding: 0.2rem;
color: #999;
transition: 1s;
cursor: pointer;
}
.button-footer:hover {
background: #fdfdfd;
color: #555;
border: 1px inset #ddd;
text-shadow: 0.05rem 0.05rem 0.05rem #ccc, 0.055rem 0.055rem 0.055rem #999,
0.06rem 0.06rem 0.06rem #333;
transition: 1s;
}
.close-btn:hover {
color: white;
background: #f00;
cursor: pointer;
}
#modal_iframe {
width: 100%;
height: 100%;
}
button.modal-button {
border-radius: 0.5rem;
border: 0px solid #aaa;
padding: 0;
cursor: pointer;
}
.modal-button-img {
border-radius: 0.5rem;
border: 0.1rem groove #444;
cursor: pointer;
}
.sepia:hover {
filter: sepia(150%);
}
/*
.none {
display: none;
}
*/
#-webkit-keyframes animatetop {
from {
top: -300px;
opacity: 0;
}
to {
top: 0;
opacity: 1;
}
}
#keyframes animatetop {
from {
top: -300px;
opacity: 0;
}
to {
top: 0;
opacity: 1;
}
}
#-webkit-keyframes animatebottom {
from {
top: 0;
opacity: 1;
}
to {
bottom: -300px;
opacity: 0;
}
}
#keyframes animatebottom {
from {
top: 0;
opacity: 1;
}
to {
bottom: -300px;
opacity: 0;
}
}
.container {
border-radius: 0.5rem;
border: 1px solid #aaa;
max-width: 800px;
width: 500px;
margin: 0 auto;
text-align: center;
font-family: sans-serif;
}
main,
aside {
font-family: sans-serif;
max-width: 800px;
width: 500px;
margin: 0 auto;
text-align: center;
}
h2 {
text-align: center;
font-family: sans-serif;
font-weight: normal;
font-size: 1.2rem;
}
span {
font-size: 75%;
background: #ffff0055;
}
<div id="modal_window" class="modal-background">
<div class="modal-window">
<button class="close-modal" data-dismiss="modal"></button>
<div class="modal-header"></div>
<div class="modal-content">
<iframe src="#" id="modal_iframe" frameborder="0">If you'd have had a real browser, I wouldn't be boring you with this now...</iframe>
</div>
<div class="modal-footer"><button class="button-footer">Open In New Tab</button></div>
</div>
</div>
<div class="container">
<h2><code>main</code> Content Rendered By JavaScript</h2>
<main>
Main
</main>
<span>working now</span>
</div>

How do I change grid for a memory game using dropdown list, I've manage to make it work but the cards stops flipping when I change the grid?

When I first load page the game works but when I change grid the game cards don't flip. I'm not sure if it the use of onchange inside the select tag or it something else. If I change the value of a variable named value inside displayCardsDiv manual it also works fine maybe if I could find a way to update it by dropddown list or button click it will work.
Html
<div class="game-container" >
<script>displayCardsDiv();</script>
<div ></div>
</div>
</div>
<div class="game-title">
<label class="changeGrid">change Grid</label>
<select id="grid" name="grid" onchange="displayCardsDiv()">
<option value="first" id="first">2x2</option>
<option value="second" id="second">3x2</option>
<option value="third" id="third">4x3</option>
</select>
<button class="reset-btn" onclick="resetGame()">Reset</button>
</div>
<script src="./src/script.js"></script>
</body>
Javascript
"src/img/apple-eye.png",
"src/img/apple-eye.png",
"src/img/blue-nife.png",
"src/img/blue-nife.png",
"src/img/devil.png",
"src/img/devil.png",
"src/img/headless.png",
"src/img/headless.png",
"src/img/heart.png",
"src/img/heart.png",
"src/img/mommy.png",
"src/img/mommy.png",
];
class MemoryGame {
constructor() {
this.cardsArray = playCard;
}
beforeGameStart() {
this.cardChecker = null;
this.matchingCardsArray = [];
this.isLocked = true;
setTimeout(() => {
this.shuffleCards(this.cardsArray);
this.isLocked = false;
}, 500);
}
handleCardFlip(card) {
if (this.flipCard(card)) {
card.classList.add("showingCard");
if (this.cardChecker) {
this.checkForMatch(card);
} else {
this.cardChecker = card;
}
}
}
checkForMatch(card) {
if (this.findTypeOfCard(card) === this.findTypeOfCard(this.cardChecker))
this.matchCards(card, this.cardChecker);
else this.misMatchCards(card, this.cardChecker);
this.cardChecker = null;
}
matchCards(firstCard, secondCard) {
this.matchingCardsArray.push(firstCard);
this.matchingCardsArray.push(secondCard);
firstCard.classList.add("matched");
secondCard.classList.add("matched");
setTimeout(() => {
if (this.matchingCardsArray.length === this.cardsArray.length) {
alert("All cards matched");
resetGame();
}
}, 1000);
}
misMatchCards(firstCard, secondCard) {
this.isLocked = true;
setTimeout(() => {
firstCard.classList.remove("showingCard");
secondCard.classList.remove("showingCard");
this.isLocked = false;
}, 1000);
}
shuffleCards(cardsArray) {
cardsArray.forEach((card) => {
let randomPos = Math.floor(Math.random() * cardsArray.length);
card.style.order = randomPos;
});
}
findTypeOfCard(card) {
return card.getElementsByClassName("value")[0].src;
}
flipCard(card) {
return (
!this.isLocked &&
!this.matchingCardsArray.includes(card) &&
card !== this.cardChecker
);
}
}
function resetGame() {
location.reload();
}
let gameContainer = document.querySelector(".game-container");
function twoByTwoGrid() {
gameContainer.style.gridTemplateColumns = "repeat(2, auto)";
return imagesArray.slice(0, 4);
}
function threeByTwoGrid() {
gameContainer.style.gridTemplateColumns = "repeat(3, auto)";
return imagesArray.slice(0, 6);
}
function displayCardsDiv() {
let deckOfCards = [];
let displayGameCards = "";
let value = document.querySelector("#grid").value;
if (value == "first") {
deckOfCards = twoByTwoGrid();
}
if (value === "second") {
deckOfCards = threeByTwoGrid();
}
if (value !== "first" && value !== "second") {
gameContainer.style.gridTemplateColumns = "repeat(4, auto)";
deckOfCards = [...imagesArray];
}
for (let i in deckOfCards) {
displayGameCards += `<div class="card">
<div class="card-back card-face"><img class="demonsCards" src="src/img/demons.png"></div>
<div class="card-front card-face"><img class="value" src="${deckOfCards[i]}"></div>
</div>`;
}
document.getElementsByClassName("game-container")[0].innerHTML =
displayGameCards;
}
displayCardsDiv();
const playCard = document.querySelectorAll(".card");
const game = new MemoryGame(playCard);
game.beforeGameStart();
for (let i = 0; i < imagesArray.length; i++) {
playCard[i].addEventListener("click", () => game.handleCardFlip(playCard[i]));
}
module.exports = { game };
CSS
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
min-height: 100vh;
}
body {
margin: 0;
background: radial-gradient(#46bddb, #4672db);
}
h1{
background: -webkit-repeating-linear-gradient(#eee, #333);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
img {
height: 175px;
width: 125px;
}
.game-title {
color: aliceblue;
font-family: 'Noto Sans Mono', monospace;
font-weight: normal;
text-align: center;
font-size: 4em;
margin-top: 0px;
}
.game-info-container {
grid-column: 1 / -1;
display: flex;
justify-content: space-between;
}
.game-info {
font-family: 'Pacifico', cursive;
color: aliceblue;
font-size: 4em;
}
.changeGrid{
font-size: large;
}
.game-container {
margin: 50px auto;
display: grid;
grid-template-columns:repeat(4, auto);
grid-gap: 10px;
justify-content: center;
perspective: 500px;
}
.card {
position: relative;
height: 175px;
width: 125px;
cursor: pointer;
}
.card-face {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
border-radius: 12px;
border-width: 1px;
border-style: solid;
overflow: hidden;
transition: transform 500ms ease-in-out;
backface-visibility: hidden;
}
.card.showingCard .card-back {
transform: rotateY(180deg);
}
.card.showingCard .card-front {
transform: rotateY(0);
}
.card-back {
background-color:aliceblue;
border-color: aliceblue;
transform: rotateY(0);
}
.demonsCards {
align-self: flex-start;
transition: transform 100ms ease-in-out;
transform: translateY(-10px);
}
.card:active {
transform: scale(0.79);
transition: transform .1s;
}
.card-front:hover .card-value {
transform: scale(1);
}
.card-front {
background-color: #FFBB89;
border-color: #333;
transform: rotateY(-180deg);
}
#media (max-width: 600px) {
.game-container {
grid-template-columns: repeat(2, auto)
}
.game-info-container {
flex-direction: column;
align-items: center;
}
}

I get a gap while transition in between sliders? [Design Like Carousel Bootstrap]

Recently I am trying to design like bootstrap carousel for Angular developing purpose.
The problem that I head it was the transition itself
as we know left arrow will keep sliding (from right to left) even if we return back to the first item. So I was wondering about how they did it with a perfect transition!
Note that they use display block for the other slides so I did a simple trick with javascript to escape display none render problem.
Finaly I do not know if it is caused the problem or some thing else because I did it as they do but I have a problem that my carousel is making a gap while transiting.
Any ideas about how to fix this?
Here is the code
Run the code and try to press next picture and see the gap between the slides.
"use strict";
(function (window) {
function carousel(selector) {
if (!(this instanceof carousel)) return new carousel(selector);
if (selector.nodeType == 1 || selector == window.document || selector == window) {
this.push(selector);
return;
}
var arr = document.querySelectorAll(selector);
arr.forEach(function (ele) {
this.push(ele);
}.bind(this))
return;
}
window.carousel = carousel;
return;
})(window);
var fn = carousel.prototype = [];
fn.default = {
"delay": 6000,
"transition": 'slide',
"startCycle": true,
"showArrows": true
};
fn.extend = function (prop) {
if (prop && typeof prop == "object") {
for (var value in prop) {
if (prop.hasOwnProperty(value)) {
this.default[value] = prop[value];
}
}
}
return;
};
fn.currPos = 0;
fn.oldPos = 0;
fn.render = function () {
// this.carouselInner.style.left = -1*this.currPos*this.carouselWidth+'px';
this.indicators[this.oldPos].classList.remove('active');
this.indicators[this.currPos].classList.add('active');
['prev', 'active'].forEach(function (e, i) {
(i == 0) ? this.items[this.oldPos].classList.add(e) : this.items[this.oldPos].classList.remove(e);
}.bind(this));
// this.items[this.oldPos].classList.add('prev')
// this.items[this.oldPos].classList.remove('active')
this.items[this.currPos].classList.add('next')
window.setTimeout(function () {
this.items[this.currPos].classList.add('active')
}.bind(this), 0.001);
window.setTimeout(function () {
this.items[this.oldPos].classList.remove('active')
this.items[this.oldPos].classList.remove('prev')
this.items[this.currPos].classList.remove('next')
}.bind(this), 600)
return;
}
fn.cycle = false;
fn.loop = null;
fn.iteration = window.setInterval.bind(window);
fn.clearIteration = window.clearInterval.bind(window);
fn.stopIteration = function () {
if (this.cycle && this.loop != null) {
this.clearIteration(this.loop);
this.cycle = false;
this.loop = null;
this.timeLine.classList.remove('animate');
}
return;
}
fn.startIteration = function () {
if (!this.cycle && this.loop == null) {
this.timeLine.classList.add('animate');
this.cycle = true;
this.loop = this.iteration(function () {
this.to();
}.bind(this), this.default.delay);
}
return;
}
fn.to = function () {
this.nextSlide();
this.timeLine.classList.remove('animate');
this.timeLine.classList.add('animate');
return;
};
fn.calculatePosition = function (number) {
this.oldPos = this.currPos;
this.currPos = number;
if (this.currPos != this.oldPos) {
if (this.currPos > this.itemsLength - 1) {
this.currPos = 0;
} else if (this.currPos < 0) {
this.currPos = this.itemsLength - 1;
}
this.render();
};
return;
}
fn.events = function () {
this.next.onclick = function () {
this.calculatePosition(this.currPos + 1);
}.bind(this);
this.prev.onclick = function () {
this.calculatePosition(this.currPos - 1);
}.bind(this);
this.indicators.forEach(function (ele, i) {
ele.onclick = function () {
this.calculatePosition(i);
}.bind(this);
}.bind(this));
// window.onresize = function(){
// this.arrangeSlides();
// this.render();
// }.bind(this);
if (this.default.startCycle == true) {
this[0].addEventListener('mouseenter', function (e) {
e.stopPropagation();
this.stopIteration();
}.bind(this), false);
this[0].addEventListener('mouseleave', function (e) {
e.stopPropagation();
this.startIteration();
}.bind(this), false);
};
return;
}
fn.arrangeSlides = function () {
this.carouselWidth = this[0].offsetWidth;
this.items.forEach(function (ele, i) {
ele.style.left = i * this.carouselWidth + 'px';
}.bind(this));
return;
}
fn.cashing = function () {
this.itemsLength = this[0].querySelectorAll('.carousel-inner .item').length;
this.next = this[0].querySelectorAll('.carousel-control.right')[0];
this.prev = this[0].querySelectorAll('.carousel-control.left')[0];
this.indicators = this[0].querySelectorAll('.carousel-indicators > li');
this.carouselWidth = this[0].offsetWidth;
this.carouselInner = this[0].querySelector('.carousel-inner');
this.items = this[0].querySelectorAll('.carousel-inner .item');
this.nextSlide = this.next.click.bind(this.next);
this.prevSlide = this.prev.click.bind(this.prev);
return;
}
fn.addTimeLine = function () {
var div = document.createElement('div');
div.className = 'timeLine animate';
this[0].appendChild(div);
this.timeLine = div;
this.timeLine.style.animationDuration = (this.default.delay / 1000) + 's';
return;
};
fn.init = function (prop) {
this.cashing();
this.extend(prop);
// this.arrangeSlides();
this.events();
if (this.default.startCycle == true) {
this.addTimeLine();
this.startIteration();
}
if (this.default.showArrows == false) {
this.next.style.display = 'none';
this.prev.style.display = 'none';
}
return this;
}
fn.apply = function (prop) {
var self = [];
this.forEach(function (ele) {
self.push(new carousel(ele).init(prop));
}.bind(this))
return {
"carouselElement": self[0][0],
"next": self[0].nextSlide,
"prev": self[0].prevSlide,
"Indicators": self[0].indicators,
"Settings": self[0].default
};
};
document.addEventListener('DOMContentLoaded', function () {
document.removeEventListener('DOMContentLoaded', arguments.calee);
carousel('.carousel').apply({
"delay": '1000',
"startCycle": false,
"showArrows": true
});
});
* {
border-size: border-box;
}
body {
background: #999;
}
.container {
margin: 0 auto;
width: 90%;
height: 400px;
background: #aaa;
}
.carousel {
position: relative;
width: 100%;
height: 100%;
border: 1px solid rgba(255, 255, 255, 0.7);
overflow: hidden;
}
.carousel ol {
list-style: none;
position: absolute;
bottom: 5px;
width: 50%;
padding: 0px;
margin: 0 25%;
text-align: center;
}
.carousel ol li {
width: 14px;
height: 14px;
display: inline-block;
border: 1px solid black;
border-radius: 50%;
position: relative;
z-index: 999;
cursor: pointer;
}
.carousel ol li:after {
transition: all .4s ease-in-out;
position: absolute;
top: 2px;
left: 2px;
content: '';
width: 10px;
height: 10px;
transform: scale(0);
display: inline-block;
border-radius: 50%;
background: rgba(0, 0, 0, 0.7);
}
.carousel ol li.active:after {
transform: scale(1);
}
.carousel .carousel-inner {
position: relative;
width: 100%;
height: 100%;
}
.carousel .carousel-inner .item {
position: absolute;
width: 100%;
height: 100%;
transition: left .6s ease-in-out;
transform: translate3d(0%, 0, 0);
float: left;
opacity: 1;
perspective: 1000px;
display: none;
}
.carousel .carousel-inner .item img {
width: 100%;
height: 100%;
}
.carousel .carousel-inner .item .carousel-caption {
position: absolute;
top: 0;
}
.carousel .carousel-inner .prev {
left: -100%;
display: block;
}
.carousel .carousel-inner .next {
left: 100%;
display: block;
}
.carousel .carousel-inner .active {
display: block;
left: 0;
opacity: 1;
}
.carousel a.carousel-control {
position: absolute;
top: 0;
right: 85%;
bottom: 0;
left: 0;
display: block;
text-decoration: none;
cursor: pointer;
}
.carousel a.carousel-control span {
pointer-events: none;
width: 100%;
text-align: center;
margin-top: 180px;
display: inline-block;
}
.carousel a.carousel-control span i {
font-size: 40px;
color: rgba(255, 255, 255, 0.5);
}
.carousel a.carousel-control:hover {
background: linear-gradient(90deg, rgba(0, 0, 0, 0.35), transparent);
}
.carousel a.carousel-control:hover i {
color: white;
}
.carousel a.carousel-control.right {
right: 0%;
left: 85%;
}
.carousel a.carousel-control.right:hover {
background: linear-gradient(-90deg, rgba(0, 0, 0, 0.35), transparent);
}
.carousel a.carousel-control.right:hover i {
color: white;
}
.carousel .timeLine {
position: absolute;
height: 3px;
background: red;
top: 0px;
left: 0px;
right: 100%;
}
.carousel .animate {
animation-name: timeLine;
animation-iteration-count: infinite;
animation-timing-function: cubic-bezier(0, 0, 0.05, 0.85);
}
#keyframes timeLine {
0% {
background: white;
right: 100%;
}
100% {
background: red;
right: 0%;
}
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<div class="container">
<div id="carousel-example-generic" class="carousel slide" data-ride="carousel">
<!-- Indicators -->
<ol class="carousel-indicators">
<li data-target="#carousel-example-generic" data-slide-to="0"></li>
<li data-target="#carousel-example-generic" data-slide-to="1"></li>
<li data-target="#carousel-example-generic" data-slide-to="2"></li>
<li data-target="#carousel-example-generic" data-slide-to="3"></li>
<li data-target="#carousel-example-generic" data-slide-to="4"></li>
<li data-target="#carousel-example-generic" data-slide-to="5"></li>
<li data-target="#carousel-example-generic" data-slide-to="6"></li>
<li data-target="#carousel-example-generic" data-slide-to="7"></li>
</ol>
<!-- Wrapper for slides -->
<div class="carousel-inner" role="listbox">
<div class="item active">
<img src="http://placehold.it/800/321" alt="...">
<div class="carousel-caption">
Hi my name is Ahmed
</div>
</div>
<div class="item">
<img src="http://placehold.it/800/421" alt="...">
<div class="carousel-caption">
...
</div>
</div>
<div class="item">
<img src="http://placehold.it/800/5b1" alt="...">
<div class="carousel-caption">
...
</div>
</div>
<div class="item">
<img src="http://placehold.it/800/051" alt="...">
<div class="carousel-caption">
...
</div>
</div>
<div class="item">
<img src="http://placehold.it/800/321" alt="...">
<div class="carousel-caption">
...
</div>
</div>
<div class="item">
<img src="http://placehold.it/800/c31" alt="...">
<div class="carousel-caption">
...
</div>
</div>
<div class="item">
<img src="http://placehold.it/800/9b1" alt="...">
<div class="carousel-caption">
...
</div>
</div>
<div class="item">
<img src="http://placehold.it/800/abc" alt="...">
<div class="carousel-caption">
...
</div>
</div>
</div>
<!-- Controls -->
<a class="left carousel-control" role="button" data-slide="prev">
<span><i class="fa fa-chevron-left" aria-hidden="true"></i></span>
</a>
<a class="right carousel-control" role="button" data-slide="next">
<span><i class="fa fa-chevron-right" aria-hidden="true"></i></span>
</a>
</div>
</div>
I have solved my issue successfully. The problem were in my render function which i modified it like this
Javascript
fn.render = function(){
this.indicators[this.oldPos].classList.remove('active');
this.indicators[this.currPos].classList.add('active'); // dont play with this
this.items[this.oldPos].classList.add('prev');
this.items[this.currPos].classList.add('next')
window.setTimeout(function(){
this.items[this.oldPos].classList.remove('active');
this.items[this.currPos].classList.add('active');
}.bind(this), 0.1);
window.setTimeout(function(){
this.items[this.oldPos].classList.remove('prev')
this.items[this.currPos].classList.remove('next')
this.underAnimate = true;
}.bind(this), 600)
return;
}

Categories

Resources