Unable to deactivate Controls - javascript

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.

Related

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?

Asprise / scannerjs.javascript-scanner-web-twain-wia-browsers-scanner.js connection problem reactjs

i try to use scanner.js but the same error keeps on showing
i have a problem with websocket connection when i try using scanner.js from Asprise.
i installed scanner.js using npm i scanner.js and imported it in my react code. i even added the following script script in my html page and it does notwork.
import React from "react";
import scanner from 'scanner-js';
let scanRequest = {
"use_asprise_dialog": true, // Whether to use Asprise Scanning Dialog
"show_scanner_ui": true, // Whether scanner UI should be shown
"twain_cap_setting" : {
"ICAP_PIXELTYPE" : "TWPT_RGB", // Color
"ICAP_XRESOLUTION" : "100", // DPI: 100
"ICAP_YRESOLUTION" : "100",
"ICAP_SUPPORTEDSIZES" : "TWSS_USLETTER" // Paper size: TWSS_USLETTER, TWSS_A4, ...
},
"output_settings": [{
"type": "return-base64",
"format": "pdf",
"thumbnail_height": 200,
}]
};
/** Triggers the scan */
const scan = () => {
scanner.scan(displayImagesOnPage, scanRequest);
}
/** Processes the scan result */
const displayImagesOnPage = (successful, mesg, response) => {
if (!successful) { // On error
console.error('Failed: ' + mesg);
return;
}
if (successful && mesg != null && mesg.toLowerCase().indexOf('user cancel') >= 0) { // User cancelled.
console.info('User cancelled');
return;
}
let scannedImages = scanner.getScannedImages(response, true, false); // returns an array of ScannedImage
for (let i = 0;
(scannedImages instanceof Array) && i < scannedImages.length; i++) {
let scannedImage = scannedImages[i];
let elementImg = scanner.createDomElementFromModel({
'name': 'img',
'attributes': {
'class': 'scanned',
'src': scannedImage.src
}
});
(document.getElementById('images') ? document.getElementById('images') : document.body).appendChild(elementImg);
}
}
export const Scanner = () => {
return (
<div>
<h2>Scanner.js TEST</h2>
<button type="button" onClick={()=>scan()}>
Scan
</button>
<div id="images"></div>
</div>
);
};
export default Scanner;

How to use a camera stream multiple times

I want to create a PWA which acts as a bar- and QR-code scanner. For detecting QR-codes I use jsQR (see: https://github.com/cozmo/jsQR), for barcodes, I want to use QuaggaJS (see: https://serratus.github.io/quaggaJS/). To select the type of code that should be detected, I have some radio buttons on my site, which call the function "triggerScannerInitialisation()" (see below). Scanning QR-codes is working already, but scanning barcodes causes some problems. The camera image is not loaded properly. If I run the same code on testing site that only uses QuaggaJS, scanning barcodes works as it should do. I assume that opening two camera streams from the same camera may cause a problem. Can anyone give me a hint on how to use both with the same camera stream?
// variables for stopping scanner types on next run
let stopJsQrOnNextRun = true;
function triggerScannerInitialisation() {
// get the selected code type
let codeTypeSelector = document.querySelector('input[name="code_type_selector"]:checked').value;
switch (codeTypeSelector) {
case 'barcode':
stopJsQrOnNextRun = true;
startQuaggaJs();
break;
case 'qr':
stopQuaggaJs();
stopJsQrOnNextRun = false;
startJsQr();
break;
default:
return false;
}
}
function startQuaggaJs() {
document.getElementById("barcode_camera_div").hidden = false;
Quagga.init({
inputStream: {
name: "Live",
type: "LiveStream",
target: document.querySelector('#barcode_camera_div'),
constraints: {
width: 480,
height: 320,
facingMode: "environment"
},
},
decoder: {
readers: [
"code_128_reader",
"ean_reader",
"ean_8_reader",
"code_39_reader",
"code_39_vin_reader",
"codabar_reader",
"upc_reader",
"upc_e_reader",
"i2of5_reader"
],
debug: {
showCanvas: true,
showPatches: true,
showFoundPatches: true,
showSkeleton: true,
showLabels: true,
showPatchLabels: true,
showRemainingPatchLabels: true,
boxFromPatches: {
showTransformed: true,
showTransformedBox: true,
showBB: true
}
}
},
}, function (err) {
if (err) {
console.log(err);
return
}
console.log("Initialization finished. Ready to start");
Quagga.start();
});
Quagga.onProcessed(function (result) {
var drawingCtx = Quagga.canvas.ctx.overlay,
drawingCanvas = Quagga.canvas.dom.overlay;
if (result) {
if (result.boxes) {
drawingCtx.clearRect(0, 0, parseInt(drawingCanvas.getAttribute("width")), parseInt(drawingCanvas.getAttribute("height")));
result.boxes.filter(function (box) {
return box !== result.box;
}).forEach(function (box) {
Quagga.ImageDebug.drawPath(box, { x: 0, y: 1 }, drawingCtx, { color: "green", lineWidth: 2 });
});
}
if (result.box) {
Quagga.ImageDebug.drawPath(result.box, { x: 0, y: 1 }, drawingCtx, { color: "#00F", lineWidth: 2 });
}
if (result.codeResult && result.codeResult.code) {
Quagga.ImageDebug.drawPath(result.line, { x: 'x', y: 'y' }, drawingCtx, { color: 'red', lineWidth: 3 });
}
}
});
Quagga.onDetected(function (result) {
console.log("Barcode detected and processed : [" + result.codeResult.code + "]", result);
});
}
function stopQuaggaJs() {
// stop quagga JS
Quagga.stop();
document.getElementById("barcode_camera_div").hidden = true;
}
function startJsQr() {
let video = document.createElement("video");
let canvasElement = document.getElementById("canvas");
let canvas = canvasElement.getContext("2d");
let loadingMessage = document.getElementById("loadingMessage");
function drawLine(begin, end, color) {
canvas.beginPath();
canvas.moveTo(begin.x, begin.y);
canvas.lineTo(end.x, end.y);
canvas.lineWidth = 4;
canvas.strokeStyle = color;
canvas.stroke();
}
// Use facingMode: environment to attemt to get the front camera on phones
navigator.mediaDevices.getUserMedia({video: {facingMode: "environment"}}).then(function (stream) {
video.srcObject = stream;
video.setAttribute("playsinline", true); // required to tell iOS safari we don't want fullscreen
video.play();
console.log("JSQR triggered");
requestAnimationFrame(tickQRcode);
});
function tickQRcode() {
loadingMessage.innerText = "⌛ Video laden...";
if (video.readyState === video.HAVE_ENOUGH_DATA) {
loadingMessage.hidden = true;
canvasElement.hidden = false;
canvasElement.height = video.videoHeight;
canvasElement.width = video.videoWidth;
canvas.drawImage(video, 0, 0, canvasElement.width, canvasElement.height);
let imageData = canvas.getImageData(0, 0, canvasElement.width, canvasElement.height);
let code = jsQR(imageData.data, imageData.width, imageData.height, {
inversionAttempts: "dontInvert",
});
if (code) {
drawLine(code.location.topLeftCorner, code.location.topRightCorner, "#FF3B58");
drawLine(code.location.topRightCorner, code.location.bottomRightCorner, "#FF3B58");
drawLine(code.location.bottomRightCorner, code.location.bottomLeftCorner, "#FF3B58");
drawLine(code.location.bottomLeftCorner, code.location.topLeftCorner, "#FF3B58");
codeFound(code.data, 'qr');
}
}
if (!stopJsQrOnNextRun) {
requestAnimationFrame(tickQRcode);
} else {
stopJsQr();
}
}
function stopJsQr() {
// stop the stream
video.srcObject.getTracks().forEach(function (track) {
if (track.readyState === 'live') {
track.stop();
}
});
// remove HTML element properties
let canvasElement = document.getElementById('canvas');
canvasElement.setAttribute('hidden', 1);
canvasElement.removeAttribute('height');
canvasElement.removeAttribute('width');
}
}
Thank you for your help!

YouTube IFrame player API onStateChange

On iPhone Safari version 9.3.2 or on chrome, when I inspect it to mobile the iframe flashes visible for a moment when I scroll the slider or even when I navigate between different browser tabs, despite the cover image being "on top".
It seems that the problem is coming from Buffering state, because when I switch tabs and comeback to page it update the value to 3 (buffering) showing the video for a millisecond and then showing back image cover.
Is there a way to avoid it?
React code:
const VideoState = {
UNSTARTED: -1,
ENDED: 0,
PLAYING: 1,
PAUSED: 2,
BUFFERING: 3,
CUED: 5
};
this.state = {
player: null,
showCover: true,
videoInitialised: false
};
onStateChange(event) {
const { showCover } = this.state;
if (this.coverTimeout && event.data === VideoState.BUFFERING) {
window.clearTimeout(this.coverTimeout);
}
if ((event.data === VideoState.PLAYING || event.data === VideoState.BUFFERING) && showCover) {
this.setState({
showCover: false
});
} else if ((event.data === VideoState.PAUSED || event.data === VideoState.ENDED || event.data === VideoState.UNSTARTED) && !showCover) {
this.coverTimeout = window.setTimeout(() => {
this.setState({
showCover: true
});
}, 250);
}
}

Building custom Quill Editor theme

I am trying to put together a custom Quill theme for my application that's based on the default Snow theme.
My project is built in ES6, and so I have had to adapt the Snow theme accordingly (mostly replacing instances of this with a variable name (let tooltip = this).
The area I'm having trouble in is displaying the link tooltip. I am super close in getting it to work (I can add links) but I am now stuck in displaying the preview for a link when the user puts the cursor on a hyperlink.
I have managed to narrow it down to the following line:
let [link, offset] = tooltip.quill.scroll.descendant(LinkBlot, range.index);
Range.index is the correct index of the user's cursor. But link is always null and offset is always -1, no matter if the user's cursor position is on or off a hyperlink.
Why won't the scroll.descendant function correctly retrieve the link that the user is on?
Complete theme code:
import extend from 'extend';
import Emitter from 'quill/core/emitter';
import BaseTheme, { BaseTooltip } from 'quill/themes/base';
import LinkBlot from 'quill/formats/link';
import { Range } from 'quill/core/selection';
const TOOLBAR_CONFIG = [
[{ header: ['1', '2', '3', false] }],
['bold', 'italic', 'underline', 'link'],
[{ list: 'ordered' }, { list: 'bullet' }],
['clean']
];
class ZSSnowTooltip extends BaseTooltip {
constructor(quill, bounds) {
super(quill, bounds);
this.preview = this.root.querySelector('a.ql-preview');
}
listen() {
super.listen();
let tooltip = this;
// on action add
tooltip.root.querySelector('a.ql-action').addEventListener('click', function(event) {
if (tooltip.root.classList.contains('ql-editing')) {
tooltip.save();
} else {
tooltip.edit('link', tooltip.preview.textContent);
}
event.preventDefault();
});
// on action remove
tooltip.root.querySelector('a.ql-remove').addEventListener('click', function(event) {
if (tooltip.linkRange !== null) {
tooltip.restoreFocus();
tooltip.quill.formatText(tooltip.linkRange, 'link', false, Emitter.sources.USER);
delete tooltip.linkRange;
}
event.preventDefault();
tooltip.hide();
});
// on selection change
tooltip.quill.on(Emitter.events.SELECTION_CHANGE, function(range) {
// if no range is selected
if (range === null) {
return;
}
// if range length is 0, try to get a link, if there is a link, show preview box
if (range.length === 0) {
let [link, offset] = tooltip.quill.scroll.descendant(LinkBlot, range.index); // link IS ALWAYS NULL
if (link !== null) {
tooltip.linkRange = new Range(range.index - offset, link.length());
let preview = LinkBlot.formats(link.domNode);
tooltip.preview.textContent = preview;
tooltip.preview.setAttribute('href', preview);
tooltip.show();
tooltip.position(tooltip.quill.getBounds(tooltip.linkRange));
return;
}
} else {
delete tooltip.linkRange;
}
tooltip.hide();
});
}
show() {
super.show();
this.root.removeAttribute('data-mode');
}
}
class ZSSnowTheme extends BaseTheme {
constructor(quill, options) {
if (options.modules.toolbar !== null && options.modules.toolbar.container === null) {
options.modules.toolbar.container = TOOLBAR_CONFIG;
}
super(quill, options);
}
extendToolbar(toolbar) {
this.tooltip = new ZSSnowTooltip(this.quill, this.options.bounds); //eslint-disable-line
if (toolbar.container.querySelector('.ql-link')) {
this.quill.keyboard.addBinding({ key: 'K', shortKey: true }, function(range, context) { //eslint-disable-line
toolbar.handlers['link'].call(toolbar, !context.format.link); //eslint-disable-line
});
}
}
}
ZSSnowTheme.DEFAULTS = extend(true, {}, BaseTheme.DEFAULTS, {
modules: {
toolbar: {
handlers: {
link: function(value) { // eslint-disable-line
if (value) {
let range = this.quill.getSelection(),
tooltip,
preview;
if (range === null || range.length === 0) {
return;
}
preview = this.quill.getText(range);
if (/^\S+#\S+\.\S+$/.test(preview) && preview.indexOf('mailto:') !== 0) {
preview = `mailto:${preview}`;
}
tooltip = this.quill.theme.tooltip;
tooltip.edit('link', preview);
} else {
this.quill.format('link', false);
}
}
}
}
}
});
ZSSnowTooltip.TEMPLATE =
`<span class="title">
Bezoek link
</span>
<a class="ql-preview" target="_blank" href="about:blank"></a>
<input type="text" />
<span> - </span>
<a class="ql-action">
<i class="mdi"></i>
<span class="ql-action-label"></span>
</a>
<a class="ql-remove">
<i class="mdi mdi-delete"></i>
Verwijder
</a>`;
export default ZSSnowTheme;

Categories

Resources