Swiper JS destroy() not firing - javascript

I'm trying to disable Swiper JS (https://github.com/nolimits4web/swiper) on anything other than mobile using the destroy() function, but I get the error Uncaught TypeError: swiper.destroy is not a function.
I've tried various different things, but I can't get it to work.
import Swiper from 'swiper';
const ImageCarousel = $el => {
let swiper = Swiper;
let init = false;
function swiperMode() {
let mobile = window.matchMedia('(min-width: 0px) and (max-width: 768px)');
let tablet = window.matchMedia('(min-width: 769px) and (max-width: 1024px)');
let desktop = window.matchMedia('(min-width: 1025px)');
// Enable (for mobile)
if (mobile.matches) {
if (!init) {
init = true;
const MySwiper = new Swiper('.swiper-container-cta', {
direction: 'horizontal',
loop: false,
speed: 1000,
grabCursor: true,
watchSlidesProgress: false,
mousewheelControl: true,
keyboardControl: true,
width: 280,
spaceBetween: 16,
});
}
}
// Disable (for tablet)
else if (tablet.matches) {
swiper.destroy();
init = false;
}
// Disable (for desktop)
else if (desktop.matches) {
swiper.destroy();
init = false;
}
}
// console.log(swiper);
window.addEventListener('load', () => {
swiperMode();
});
window.addEventListener('resize', () => {
swiperMode();
});
};
export default ImageCarousel;

Did you try MySwiper.destroy(); instead of swiper.destroy();

Related

Unable to deactivate Controls

In my Carousel, there is an option to show more than 1 item at a time. It is activated by selecting the number of items you wish to show (max 4). The code refers to this as perView.
Items to display example
This carousel is glide.js, so everything is modular. I have 2 things of note getting activated, the Controls (next/prev button) and Breakpoints (think media queries).
The goal is to turn off the controls in mobile only if perView equals anything other than NaN (not a number)... When it is inactive, it returns NaN... so I guess the comment would be:
if perView does not equal NaN, then controls = false
and because i need this in a mobile breakpoint, I would put the code in the breakpoint bracket.
import AEM from 'base/js/aem';
import Glide, { Controls, Breakpoints, Autoplay, Keyboard, Swipe } from '#glidejs/glide/dist/glide.modular.esm';
class Carousel extends AEM.Component {
init() {
this.initCarousel();
}
initCarousel() {
const el = this.element;
const props = this.props;
const pauseButton = this.element.querySelector('.pause-button');
let perView = parseInt(props.cmpPerView, 10);
let cmpDelay = parseInt(props.cmpDelay, 10);
let autoPlay = true;
if (this.props.cmpAutoplay === 'false' ||
this.props.carouselAutoplay === 'false' ||
!Number.isNaN(perView) && perView < 1 ||
window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
autoPlay = false;
}
this.modules = {
Controls: Controls,
Breakpoints: Breakpoints,
Autoplay: Autoplay,
Keyboard: Keyboard,
Swipe: Swipe
};
this.options = {
type: props.cmpType,
perView: Number.isNaN(perView) ? 1 : perView,
autoplay: autoPlay ? cmpDelay : false,
peek: 0,
keyboard: true,
animationDuration: 400,
rewind: true,
breakpoints: {
768: {
perView: Number.isNaN(perView) || perView === 1 ? 1 : 3,
},
578: {
peek: perView > 1 ? 125 : 0,
perView: 1,
controls: perView > 1,
},
375: {
peek: perView > 1 ? 85 : 0,
perView: 1,
}
}
};
const glide = new Glide(el, this.options);
if (pauseButton && autoPlay) {
const pauseClasses = pauseButton.classList;
glide.on('play', () => {
pauseClasses.add('fa-pause');
pauseClasses.remove('fa-play');
});
glide.on('pause', () => {
pauseClasses.add('fa-play');
pauseClasses.remove('fa-pause');
});
pauseButton.addEventListener('click', () => {
if (pauseClasses.contains('fa-play')) {
glide.play();
} else {
glide.pause();
}
});
} else if (pauseButton) {
pauseButton.remove();
}
if (window.Granite && window.Granite.author && window.Granite.author.MessageChannel) {
/*
* Editor message handling:
* - subscribe to "cmp.panelcontainer" message requests sent by the editor frame
* - check that the message data panel container type is correct and that the id (path) matches this specific
* - Carousel component. If so, route the "navigate" operation to enact a navigation of the Carousel based
* - on index data
*/
this.element.querySelectorAll('.glide__slide').forEach(e => {
if (!e.classList.contains('glide__slide--active')) {
e.classList.add('visually-hidden');
}
});
window.CQ = window.CQ || {};
window.CQ.CoreComponents = window.CQ.CoreComponents || {};
window.CQ.CoreComponents.MESSAGE_CHANNEL = window.CQ.CoreComponents.MESSAGE_CHANNEL ||
new window.Granite.author.MessageChannel('cqauthor', window);
window.CQ.CoreComponents.MESSAGE_CHANNEL.subscribeRequestMessage('cmp.panelcontainer', message => {
if (message.data && message.data.type === 'cmp-carousel' &&
message.data.id === el.dataset.cmpPanelcontainerId) {
if (message.data.operation === 'navigate') {
let index = message.data.index;
if (index < 0) {
return;
}
this.element.querySelectorAll('.glide__slide').forEach((slide, i) => {
if (i === index) {
slide.classList.add('glide__slide--active');
slide.classList.remove('visually-hidden');
} else {
slide.classList.remove('glide__slide--active');
slide.classList.add('visually-hidden');
}
});
}
}
});
} else {
glide.mount(this.modules);
}
}
}
export { Carousel };
So I have
controls: perView > 1
in the 578 breakpoint... but it doesn't work.

Cannot read properties of null (reading 'classList') at window. Onload. Element not in the DOM when the script ran

I converted a page that contains HTML, CSS and JavaScript to a React app. The original website is working fine. But, when I load the React app, I get this error:
Uncaught TypeError: Cannot read properties of null (reading 'classList') at window. Onload
It seems like the element I'm trying to get is not in the DOM when the script runs.
So, I tried 5 following solutions without any positive result:
Putting the defer attribute on the external scripts.
I was thinking of moving the script in script.js, but I can't because I'm using an external script.
Using the type attribute with the module value, but I can't because I'm using an external script.
Deferring with event handling, but it's not working.
Tried the Event delegation, but is not working neither.
Here is my code:
App.js with some changes to adapt the HTML to JSX:
/* eslint-disable no-unused-vars */
/* eslint-disable no-script-url */
/* eslint-disable jsx-a11y/anchor-is-valid */
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div>
{/* <!-- Start preloader --> */}
<div id="preloader">
<div id="ctn-preloader" className="ctn-preloader">
<div className="animation-preloader">
<div className="spinner"></div>
<div className="txt-loading">
<span data-text-preloader="C" className="letters-loading">
{' '}
C{' '}
</span>
<span data-text-preloader="H" className="letters-loading">
{' '}
H{' '}
</span>
<span data-text-preloader="A" className="letters-loading">
{' '}
A{' '}
</span>
<span data-text-preloader="R" className="letters-loading">
{' '}
R{' '}
</span>
<span data-text-preloader="G" className="letters-loading">
{' '}
G{' '}
</span>
<span data-text-preloader="E" className="letters-loading">
{' '}
E{' '}
</span>
<span data-text-preloader="M" className="letters-loading">
{' '}
M{' '}
</span>
<span data-text-preloader="E" className="letters-loading">
{' '}
E{' '}
</span>
<span data-text-preloader="N" className="letters-loading">
{' '}
N{' '}
</span>
<span data-text-preloader="T" className="letters-loading">
{' '}
T{' '}
</span>
</div>
</div>
<div className="loader-section section-left"></div>
<div className="loader-section section-right"></div>
</div>
</div>
{/* <!-- End preloader --> */}
</div>
);
}
export default App;
script.js without any change:
'use strict';
// Preloader
const preLoader = function () {
let preloaderWrapper = document.getElementById('preloader');
window.onload = () => {
preloaderWrapper.classList.add('loaded');
};
};
preLoader();
// getSiblings
var getSiblings = function (elem) {
const siblings = [];
let sibling = elem.parentNode.firstChild;
while (sibling) {
if (sibling.nodeType === 1 && sibling !== elem) {
siblings.push(sibling);
}
sibling = sibling.nextSibling;
}
return siblings;
};
/* Slide Up */
var slideUp = (target, time) => {
const duration = time ? time : 500;
target.style.transitionProperty = 'height, margin, padding';
target.style.transitionDuration = duration + 'ms';
target.style.boxSizing = 'border-box';
target.style.height = target.offsetHeight + 'px';
target.offsetHeight;
target.style.overflow = 'hidden';
target.style.height = 0;
window.setTimeout(() => {
target.style.display = 'none';
target.style.removeProperty('height');
target.style.removeProperty('overflow');
target.style.removeProperty('transition-duration');
target.style.removeProperty('transition-property');
}, duration);
};
/* Slide Down */
var slideDown = (target, time) => {
const duration = time ? time : 500;
target.style.removeProperty('display');
let display = window.getComputedStyle(target).display;
if (display === 'none') display = 'block';
target.style.display = display;
const height = target.offsetHeight;
target.style.overflow = 'hidden';
target.style.height = 0;
target.offsetHeight;
target.style.boxSizing = 'border-box';
target.style.transitionProperty = 'height, margin, padding';
target.style.transitionDuration = duration + 'ms';
target.style.height = height + 'px';
window.setTimeout(() => {
target.style.removeProperty('height');
target.style.removeProperty('overflow');
target.style.removeProperty('transition-duration');
target.style.removeProperty('transition-property');
}, duration);
};
// Get window top offset
function TopOffset(el) {
let rect = el.getBoundingClientRect(),
scrollTop = window.pageYOffset || document.documentElement.scrollTop;
return { top: rect.top + scrollTop };
}
// Header sticky activation
const headerStickyWrapper = document.querySelector('header');
const headerStickyTarget = document.querySelector('.header__sticky');
if (headerStickyTarget) {
let headerHeight = headerStickyWrapper.clientHeight;
window.addEventListener('scroll', function () {
let StickyTargetElement = TopOffset(headerStickyWrapper);
let TargetElementTopOffset = StickyTargetElement.top;
if (window.scrollY > TargetElementTopOffset) {
headerStickyTarget.classList.add('sticky');
} else {
headerStickyTarget.classList.remove('sticky');
}
});
}
// Back to top
const scrollTop = document.getElementById('scroll__top');
if (scrollTop) {
scrollTop.addEventListener('click', function () {
window.scroll({ top: 0, left: 0, behavior: 'smooth' });
});
window.addEventListener('scroll', function () {
if (window.scrollY > 300) {
scrollTop.classList.add('active');
} else {
scrollTop.classList.remove('active');
}
});
}
// blog swiper column3 activation
var swiper = new Swiper('.blog__swiper--activation', {
slidesPerView: 3,
loop: true,
clickable: true,
spaceBetween: 30,
breakpoints: {
1200: {
slidesPerView: 3
},
992: {
slidesPerView: 3
},
768: {
slidesPerView: 2,
spaceBetween: 30
},
480: {
slidesPerView: 2,
spaceBetween: 20
},
0: {
slidesPerView: 1
}
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev'
}
});
// testimonial swiper activation
var swiper = new Swiper('.testimonial__swiper--activation', {
slidesPerView: 2,
loop: true,
clickable: true,
spaceBetween: 30,
breakpoints: {
768: {
slidesPerView: 2,
spaceBetween: 30
},
576: {
slidesPerView: 2,
spaceBetween: 20
},
0: {
slidesPerView: 1
}
},
pagination: {
clickable: true,
el: '.swiper-pagination'
}
});
// testimonial swiper column1 activation
var swiper = new Swiper('.testimonial__swiper--column1', {
slidesPerView: 1,
loop: true,
clickable: true,
spaceBetween: 30,
pagination: {
clickable: true,
el: '.swiper-pagination'
}
});
// project swiper activation
var swiper = new Swiper('.project__swiper--activation', {
slidesPerView: 4,
loop: true,
spaceBetween: 30,
clickable: true,
roundLengths: true,
centeredSlides: true,
breakpoints: {
1200: {
slidesPerView: 4,
spaceBetween: 30
},
992: {
slidesPerView: 3,
spaceBetween: 25
},
768: {
slidesPerView: 3,
spaceBetween: 25
},
400: {
slidesPerView: 2,
spaceBetween: 15
},
300: {
slidesPerView: 1,
spaceBetween: 15
},
0: {
slidesPerView: 1
}
},
pagination: {
clickable: true,
el: '.swiper-pagination'
}
});
// brand swiper activation
var swiper = new Swiper('.brand__swiper--activation', {
slidesPerView: 5,
loop: true,
spaceBetween: 50,
clickable: true,
breakpoints: {
1366: {
slidesPerView: 5,
spaceBetween: 50
},
1200: {
slidesPerView: 5,
spaceBetween: 40
},
992: {
slidesPerView: 5,
spaceBetween: 30
},
768: {
slidesPerView: 4,
spaceBetween: 30
},
400: {
slidesPerView: 3,
spaceBetween: 20
},
200: {
slidesPerView: 2,
spaceBetween: 20
},
0: {
slidesPerView: 1
}
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev'
}
});
// related project swiper activation
var swiper = new Swiper('.related__project--swiper', {
slidesPerView: 4,
loop: true,
clickable: true,
spaceBetween: 30,
breakpoints: {
992: {
slidesPerView: 4
},
768: {
slidesPerView: 3,
spaceBetween: 30
},
576: {
slidesPerView: 3,
spaceBetween: 20
},
480: {
slidesPerView: 2,
spaceBetween: 20
},
300: {
slidesPerView: 2,
spaceBetween: 15
},
0: {
slidesPerView: 1
}
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev'
}
});
// tab activation
const tab = function (wrapper) {
let tabContainer = document.querySelector(wrapper);
if (tabContainer) {
tabContainer.addEventListener('click', function (evt) {
let listItem = evt.target;
if (listItem.hasAttribute('data-toggle')) {
let targetId = listItem.dataset.target,
targetItem = document.querySelector(targetId);
listItem.parentElement
.querySelectorAll('[data-toggle="tab"]')
.forEach(function (list) {
list.classList.remove('active');
});
listItem.classList.add('active');
targetItem.classList.add('active');
setTimeout(function () {
targetItem.classList.add('show');
}, 150);
getSiblings(targetItem).forEach(function (pane) {
pane.classList.remove('show');
setTimeout(function () {
pane.classList.remove('active');
}, 150);
});
}
});
}
};
// Homepage 1 product tab
tab('.project__tab--one');
tab('.product__tab--one');
// countdown activation
document.querySelectorAll('[data-countdown]').forEach(function (elem) {
const countDownItem = function (value, label) {
return `<div class="countdown__item" ${label}"><span class="countdown__number">${value}</span><p class="countdown__text">${label}</p></div>`;
};
const date = new Date(elem.getAttribute('data-countdown')).getTime(),
second = 1000,
minute = second * 60,
hour = minute * 60,
day = hour * 24;
const countDownInterval = setInterval(function () {
let currentTime = new Date().getTime(),
timeDistance = date - currentTime,
daysValue = Math.floor(timeDistance / day),
hoursValue = Math.floor((timeDistance % day) / hour),
minutesValue = Math.floor((timeDistance % hour) / minute),
secondsValue = Math.floor((timeDistance % minute) / second);
elem.innerHTML =
countDownItem(daysValue, 'days') +
countDownItem(hoursValue, 'hrs') +
countDownItem(minutesValue, 'mins') +
countDownItem(secondsValue, 'secs');
if (timeDistance < 0) clearInterval(countDownInterval);
}, 1000);
});
// adding & removing class function
const activeClassAction = function (toggle, target) {
const to = document.querySelector(toggle),
ta = document.querySelector(target);
if (to && ta) {
to.addEventListener('click', function (e) {
e.preventDefault();
let triggerItem = e.target;
if (triggerItem.classList.contains('active')) {
triggerItem.classList.remove('active');
ta.classList.remove('active');
} else {
triggerItem.classList.add('active');
ta.classList.add('active');
}
});
document.addEventListener('click', function (event) {
if (
!event.target.closest(toggle) &&
!event.target.classList.contains(toggle.replace(/\./, ''))
) {
if (
!event.target.closest(target) &&
!event.target.classList.contains(target.replace(/\./, ''))
) {
to.classList.remove('active');
ta.classList.remove('active');
}
}
});
}
};
activeClassAction('.account__currency--link', '.dropdown__currency');
activeClassAction('.language__switcher', '.dropdown__language');
activeClassAction(
'.offcanvas__language--switcher',
'.offcanvas__dropdown--language'
);
activeClassAction(
'.offcanvas__account--currency__menu',
'.offcanvas__account--currency__submenu'
);
activeClassAction('.footer__language--link', '.footer__dropdown--language');
activeClassAction('.footer__currency--link', '.footer__dropdown--currency');
// OffCanvas Sidebar Activation
function offcanvsSidebar(openTrigger, closeTrigger, wrapper) {
let OpenTriggerprimary__btn = document.querySelectorAll(openTrigger);
let closeTriggerprimary__btn = document.querySelector(closeTrigger);
let WrapperSidebar = document.querySelector(wrapper);
let wrapperOverlay = wrapper.replace('.', '');
function handleBodyClass(evt) {
let eventTarget = evt.target;
if (!eventTarget.closest(wrapper) && !eventTarget.closest(openTrigger)) {
WrapperSidebar.classList.remove('active');
document
.querySelector('body')
.classList.remove(`${wrapperOverlay}_active`);
}
}
if (OpenTriggerprimary__btn && WrapperSidebar) {
OpenTriggerprimary__btn.forEach(function (singleItem) {
singleItem.addEventListener('click', function (e) {
if (e.target.dataset.offcanvas != undefined) {
WrapperSidebar.classList.add('active');
document
.querySelector('body')
.classList.add(`${wrapperOverlay}_active`);
document.body.addEventListener('click', handleBodyClass.bind(this));
}
});
});
}
if (closeTriggerprimary__btn && WrapperSidebar) {
closeTriggerprimary__btn.addEventListener('click', function (e) {
if (e.target.dataset.offcanvas != undefined) {
WrapperSidebar.classList.remove('active');
document
.querySelector('body')
.classList.remove(`${wrapperOverlay}_active`);
document.body.removeEventListener('click', handleBodyClass.bind(this));
}
});
}
}
// Mini Cart
offcanvsSidebar(
'.minicart__open--btn',
'.minicart__close--btn',
'.offCanvas__minicart'
);
// Search Bar
offcanvsSidebar(
'.search__open--btn',
'.predictive__search--close__btn',
'.predictive__search--box'
);
// Offcanvas filter sidebar
offcanvsSidebar(
'.widget__filter--btn',
'.offcanvas__filter--close',
'.offcanvas__filter--sidebar'
);
/* Offcanvas Mobile Menu Function */
const offcanvasHeader = function () {
const offcanvasOpen = document.querySelector(
'.offcanvas__header--menu__open--btn'
),
offcanvasClose = document.querySelector('.offcanvas__close--btn'),
offcanvasHeader = document.querySelector('.offcanvas-header'),
offcanvasMenu = document.querySelector('.offcanvas__menu'),
body = document.querySelector('body');
/* Offcanvas SubMenu Toggle */
if (offcanvasMenu) {
offcanvasMenu
.querySelectorAll('.offcanvas__sub_menu')
.forEach(function (ul) {
const subMenuToggle = document.createElement('button');
subMenuToggle.classList.add('offcanvas__sub_menu_toggle');
ul.parentNode.appendChild(subMenuToggle);
});
}
/* Open/Close Menu On Click Toggle Button */
if (offcanvasOpen) {
offcanvasOpen.addEventListener('click', function (e) {
e.preventDefault();
if (e.target.dataset.offcanvas != undefined) {
offcanvasHeader.classList.add('open');
body.classList.add('mobile_menu_open');
}
});
}
if (offcanvasClose) {
offcanvasClose.addEventListener('click', function (e) {
e.preventDefault();
if (e.target.dataset.offcanvas != undefined) {
offcanvasHeader.classList.remove('open');
body.classList.remove('mobile_menu_open');
}
});
}
/* Mobile submenu slideToggle Activation */
let mobileMenuWrapper = document.querySelector('.offcanvas__menu_ul');
if (mobileMenuWrapper) {
mobileMenuWrapper.addEventListener('click', function (e) {
let targetElement = e.target;
if (targetElement.classList.contains('offcanvas__sub_menu_toggle')) {
const parent = targetElement.parentElement;
if (parent.classList.contains('active')) {
targetElement.classList.remove('active');
parent.classList.remove('active');
parent
.querySelectorAll('.offcanvas__sub_menu')
.forEach(function (subMenu) {
subMenu.parentElement.classList.remove('active');
subMenu.nextElementSibling.classList.remove('active');
slideUp(subMenu);
});
} else {
targetElement.classList.add('active');
parent.classList.add('active');
slideDown(targetElement.previousElementSibling);
getSiblings(parent).forEach(function (item) {
item.classList.remove('active');
item
.querySelectorAll('.offcanvas__sub_menu')
.forEach(function (subMenu) {
subMenu.parentElement.classList.remove('active');
subMenu.nextElementSibling.classList.remove('active');
slideUp(subMenu);
});
});
}
}
});
}
if (offcanvasHeader) {
document.addEventListener('click', function (event) {
if (
!event.target.closest('.offcanvas__header--menu__open--btn') &&
!event.target.classList.contains(
'.offcanvas__header--menu__open--btn'.replace(/\./, '')
)
) {
if (
!event.target.closest('.offcanvas-header') &&
!event.target.classList.contains(
'.offcanvas-header'.replace(/\./, '')
)
) {
offcanvasHeader.classList.remove('open');
body.classList.remove('mobile_menu_open');
}
}
});
}
/* Remove Mobile Menu Open Class & Hide Mobile Menu When Window Width in More Than 991 */
if (offcanvasHeader) {
window.addEventListener('resize', function () {
if (window.outerWidth >= 992) {
offcanvasHeader.classList.remove('open');
body.classList.remove('mobile_menu_open');
}
});
}
};
/* Mobile Menu Active */
offcanvasHeader();
// Increment & Decrement Qunatity Button
const quantityWrapper = document.querySelectorAll('.quantity__box');
if (quantityWrapper) {
quantityWrapper.forEach(function (singleItem) {
let increaseButton = singleItem.querySelector('.increase');
let decreaseButton = singleItem.querySelector('.decrease');
increaseButton.addEventListener('click', function (e) {
let input = e.target.previousElementSibling.children[0];
if (input.dataset.counter != undefined) {
let value = parseInt(input.value, 10);
value = isNaN(value) ? 0 : value;
value++;
input.value = value;
}
});
decreaseButton.addEventListener('click', function (e) {
let input = e.target.nextElementSibling.children[0];
if (input.dataset.counter != undefined) {
let value = parseInt(input.value, 10);
value = isNaN(value) ? 0 : value;
value < 1 ? (value = 1) : '';
value--;
input.value = value;
}
});
});
}
// Modal JS
const openEls = document.querySelectorAll('[data-open]');
const closeEls = document.querySelectorAll('[data-close]');
const isVisible = 'is-visible';
for (const el of openEls) {
el.addEventListener('click', function () {
const modalId = this.dataset.open;
document.getElementById(modalId).classList.add(isVisible);
});
}
for (const el of closeEls) {
el.addEventListener('click', function () {
this.parentElement.parentElement.parentElement.classList.remove(isVisible);
});
}
document.addEventListener('click', e => {
if (e.target == document.querySelector('.modal.is-visible')) {
document.querySelector('.modal.is-visible').classList.remove(isVisible);
}
});
document.addEventListener('keyup', e => {
if (e.key == 'Escape' && document.querySelector('.modal.is-visible')) {
document.querySelector('.modal.is-visible').classList.remove(isVisible);
}
});
// Accordion
function customAccordion(accordionWrapper, singleItem, accordionBody) {
let accoridonButtons = document.querySelectorAll(accordionWrapper);
accoridonButtons.forEach(function (item) {
item.addEventListener('click', function (evt) {
let itemTarget = evt.target;
if (
itemTarget.classList.contains('accordion__items--button') ||
itemTarget.classList.contains('widget__categories--menu__label')
) {
let singleAccordionWrapper = itemTarget.closest(singleItem),
singleAccordionBody =
singleAccordionWrapper.querySelector(accordionBody);
if (singleAccordionWrapper.classList.contains('active')) {
singleAccordionWrapper.classList.remove('active');
slideUp(singleAccordionBody);
} else {
singleAccordionWrapper.classList.add('active');
slideDown(singleAccordionBody);
getSiblings(singleAccordionWrapper).forEach(function (item) {
let sibllingSingleAccordionBody = item.querySelector(accordionBody);
item.classList.remove('active');
slideUp(sibllingSingleAccordionBody);
});
}
}
});
});
}
customAccordion(
'.accordion__container',
'.accordion__items',
'.accordion__items--body'
);
customAccordion(
'.widget__categories--menu',
'.widget__categories--menu__list',
'.widget__categories--sub__menu'
);
// footer widget js
let accordion = true;
const footerWidgetAccordion = function () {
accordion = false;
let footerWidgetContainer = document.querySelector('.main__footer');
footerWidgetContainer.addEventListener('click', function (evt) {
let singleItemTarget = evt.target;
if (singleItemTarget.classList.contains('footer__widget--button')) {
const footerWidget = singleItemTarget.closest('.footer__widget'),
footerWidgetInner = footerWidget.querySelector(
'.footer__widget--inner'
);
if (footerWidget.classList.contains('active')) {
footerWidget.classList.remove('active');
slideUp(footerWidgetInner);
} else {
footerWidget.classList.add('active');
slideDown(footerWidgetInner);
getSiblings(footerWidget).forEach(function (item) {
const footerWidgetInner = item.querySelector(
'.footer__widget--inner'
);
item.classList.remove('active');
slideUp(footerWidgetInner);
});
}
}
});
};
window.addEventListener('load', function () {
if (accordion) {
footerWidgetAccordion();
}
});
window.addEventListener('resize', function () {
document.querySelectorAll('.footer__widget').forEach(function (item) {
if (window.outerWidth >= 768) {
item.classList.remove('active');
item.querySelector('.footer__widget--inner').style.display = '';
}
});
if (accordion) {
footerWidgetAccordion();
}
});
// lightbox Activation
const customLightboxHTML = `<div id="glightbox-body" class="glightbox-container">
<div class="gloader visible"></div>
<div class="goverlay"></div>
<div class="gcontainer">
<div id="glightbox-slider" class="gslider"></div>
<button class="gnext gbtn" tabindex="0" aria-label="Next" data-customattribute="example">{nextSVG}</button>
<button class="gprev gbtn" tabindex="1" aria-label="Previous">{prevSVG}</button>
<button class="gclose gbtn" tabindex="2" aria-label="Close">{closeSVG}</button>
</div>
</div>`;
const lightbox = GLightbox({
touchNavigation: true,
lightboxHTML: customLightboxHTML,
loop: true
});
// CounterUp Activation
const wrapper = document.getElementById('funfactId');
if (wrapper) {
const counters = wrapper.querySelectorAll('.js-counter');
const duration = 400;
let isCounted = false;
document.addEventListener('scroll', function () {
const wrapperPos = wrapper.offsetTop - window.innerHeight;
if (!isCounted && window.scrollY > wrapperPos) {
counters.forEach(counter => {
const countTo = counter.dataset.count;
const countPerMs = countTo / duration;
let currentCount = 0;
const countInterval = setInterval(function () {
if (currentCount >= countTo) {
clearInterval(countInterval);
}
counter.textContent = Math.round(currentCount);
currentCount = currentCount + countPerMs;
}, 1);
});
isCounted = true;
}
});
}
Anyone has the correct solution?

How to turn on/off the embla carousel by breakpoint in React?

Using the Embla Carousel, React version, I'm trying to turn/on off the carousel based on breakpoint. So for mobile, it's on and for tablet up it's off. Here's what I tried that seems to work initially, but won't reinitialize. I'm guessing it's because destory was called so it can reInit and tried init, but no luck there either.
const emblaOptions = {};
const [viewportRef, emblaApi] = useEmblaCarousel(emblaOptions);
const handleEmblaInit = () => {
if (window.innerWidth > 768) {
emblaApi.destroy();
} else {
emblaApi.reInit(emblaOptions);
}
};
useEffect(() => {
if (emblaApi) {
handleEmblaInit();
window.addEventListener("resize", handleEmblaInit);
}
}, [emblaApi]);
Pass null instead of the emblaRef when you want it to be inactive, like demonstrated here:
https://github.com/davidcetinkaya/embla-carousel/issues/99#issuecomment-688730519
From version 7 and up you can use the active option together with the breakpoints option to achieve this. Example from the Embla Carousel docs:
const options = {
active: true,
breakpoints: {
'(min-width: 768px)': { active: false },
},
}
Usage with React:
const [emblaRef, emblaApi] = useEmblaCarousel({
active: true,
breakpoints: {
'(min-width: 768px)': { active: false },
},
});

Phaser pointer events not working in WebView (Xamarin Forms) C#

I have create a simple animation screen using phaser and its rendering perfect and invoking all pointer events like pointerover, pointerout, pointerup and pointerdown on button btn as expected for browser. But when I render same game using WebView its rendering screen but its not invoking any pointer events. To confirm JavaScript is working I have tested by adding eventlistner on window and it was working.
var config = {
type: Phaser.CANVAS,
width: 650,
height: 900,
canvas: document.getElementById('myCustomCanvas'),
scale: {
mode: Phaser.Scale.FIT,
width: 750,
height: 1334,
parent: 'game'
},
physics: {
default: 'arcade',
arcade: {
gravity: { y: 0 }
}
},
scene : {
preload: function(){game.preload(this, 'asset_url');},
create: function(){game.create(this);},
update: function(){game.update(this);},
}
};
function game(config) {
this.start = function(config)
{
this.phaserGame = new Phaser.Game(config);
};
this.create = function()
{
var btn = this.scene.add.sprite(375, 665, 'btn');
btn.setInteractive()
.on('pointerover', () => {
console.log('pointerover');
})
.on('pointerout', () => {
console.log('pointerout');
})
.on('pointerdown', () => {
console.log('pointerdown');
})
.on('pointerup', () => {
console.log('pointerup');
});
};
}
I am using Xamarin Forms WebView to render game in mobile. My setting for WebView is as follow.
var webView = CreateNativeControl();
webView.SetWebViewClient(new HTMLGameWebClient(this));
webView.Settings.LightTouchEnabled = true;
webView.Settings.JavaScriptEnabled = true;
webView.Settings.DomStorageEnabled = true;
webView.Settings.MediaPlaybackRequiresUserGesture = false;
SetNativeControl(webView);
I also have conditional CSS which is used only if canvas is rendering in mobile.
canvas {
width: 100vw !important;
height: unset;
}
Thanks in advance for any helps or suggestions.

How can I use javascript to make it so the user can only trigger the hover event once the Lottie animation has played in full?

How can I make it so the user is only able to trigger the mouse hover & mouse left events, once the Lottie animation has initially played in full.
Currently the user is able to cause the hover event when the animation is mid-playing, something I don't want to be able to happen.
Thanks
var anim4;
var anim5 = document.getElementById('lottie5')
var animation5 = {
container: anim5,
renderer: 'svg',
loop: true,
autoplay: false, /*MAKE SURE THIS IS FALSE*/
rendererSettings: {
progressiveLoad: false},
path: 'https://assets1.lottiefiles.com/packages/lf20_H2PpYV.json',
name: 'myAnimation',
};
anim4 = lottie.loadAnimation(animation5);
// SCROLLING DOWN
var waypoint5 = new Waypoint({
element: document.getElementById('lottie5'),
handler: function(direction) {
if (direction === 'down') {
anim4.playSegments([[130,447],[358,447]], true);
this.destroy()
}
},
offset: '50%'
})
anim5.addEventListener("mouseenter", myScript1);
anim5.addEventListener("mouseleave", myScript2);
function myScript1(){
anim4.goToAndStop(500, true);
}
function myScript2(){
anim4.playSegments([358,447],true);
};
var anim4;
var anim5 = document.getElementById('lottie5')
var animation5 = {
container: anim5,
renderer: 'svg',
loop: false,
autoplay: true, /*MAKE SURE THIS IS FALSE*/
rendererSettings: {
progressiveLoad: false},
path: 'https://assets1.lottiefiles.com/packages/lf20_H2PpYV.json',
name: 'myAnimation',
};
anim4 = lottie.loadAnimation(animation5);
// SCROLLING DOWN
var waypoint5 = new Waypoint({
element: document.getElementById('lottie5'),
handler: function(direction) {
if (direction === 'down') {
anim4.playSegments([[130,447],[358,447]], true);
this.destroy()
}
},
offset: '50%'
})
anim4.addEventListener("complete", function(){
console.log('Animation completed!!');
anim5.addEventListener("mouseenter", myScript1);
anim5.addEventListener("mouseleave", myScript2);
});
function myScript1(){
anim4.goToAndStop(500, true);
}
function myScript2(){
anim4.playSegments([358,447],true);
};
Figure it out in case anyone is interested.
This might not be the most efficient way, but worked for me!
anim4.addEventListener('complete', function(e) {
console.log('Animation completed');
});
anim4.addEventListener('complete', function(e) {
var elem = document.getElementById('lottie5');
elem.addEventListener('mouseover', mouseElem)
elem.addEventListener('mouseleave', mouseElem2)
function mouseElem() {
anim4.goToAndStop(150, true);
}
function mouseElem2() {
anim4.goToAndStop(30, true);
}

Categories

Resources