UNPKG

1gallery

Version:

a modern SEO friendly ejs web banner gallery for any kind of slides (photos, html...)

402 lines (363 loc) 18 kB
var _1gallery = (function () { 'use strict'; async function sleep$1(ms){ return new Promise((resolve,reject)=>setTimeout(resolve,ms)); } function docReady$1(fn) { // see if DOM is already available if (document.readyState === "complete" || document.readyState === "interactive") { // call on next available tick setTimeout(fn, 1); } else { document.addEventListener("DOMContentLoaded", fn); } } function tryPreventingDefault$1(e){ if(typeof e !== "undefined" && typeof e.preventDefault !== "undefined")e.preventDefault(); } function init(){ if(typeof window !== "undefined"){ window.sleep = sleep$1; window.docReady = docReady$1; window.tryPreventingDefault = tryPreventingDefault$1; } } init(); var init1GalleryCore = (galleryNode)=> { const self = galleryNode; self.updateCardsCount = () => self.cardsCount = self.querySelectorAll('.card').length; self.rearrangeCardsAroundActiveCard = () => { self.classList.remove('smooth'); const afterActive = self.querySelectorAll('.card.active ~ .card').length; let toPush = Math.floor(self.cardsCount / 2) - afterActive; if (toPush > 0) { for (; toPush > 0; toPush--) self.push(self.shiftInPlace()); } if (toPush < 0) { for (; toPush < 0; toPush++) self.unshiftInPlace(self.pop()); } self.classList.add('smooth'); }; self.activeCard = () => self.querySelector('.card.active'); self.firstCard = () => self.querySelectorAll('.card')[0]; self.lastCard = () => self.querySelectorAll('.card')[self.cardsCount - 1]; self.pop = function pop() { const lastCard = self.lastCard(); self.slider.removeChild(lastCard); self.cardsCount--; return lastCard; }; self.push = function push(card) { self.slider.appendChild(card); self.cardsCount++; }; self.shift = function shift() { const firstCard = self.firstCard(); self.slider.removeChild(firstCard); self.cardsCount--; return firstCard; }; self.shiftInPlace = function shiftInPlace() { const refCard = self.firstCard(); const cardFullWidth = refCard.nextElementSibling.offsetLeft - refCard.offsetLeft; self.slider.style.left = `${self.slider.offsetLeft + cardFullWidth}px`; const res = self.shift(); self.slider.offsetLeft; // to fix a update issue making transition to jump. return res; }; self.unshift = function unshift(card) { self.slider.insertBefore(card, self.firstCard()); self.cardsCount++; }; self.unshiftInPlace = function unshiftInPlace(card) { self.unshift(card); const refCard = self.firstCard(); const cardFullWidth = refCard.nextElementSibling.offsetLeft - refCard.offsetLeft; self.slider.style.left = `${self.slider.offsetLeft - cardFullWidth}px`; self.slider.offsetLeft; // to fix a update issue making transition to jump. }; self.first = (e) => self.changeActiveCard(self.cardsOrdered[0]) && tryPreventingDefault(e); self.prev = (e) => self.changeActiveCard(self.activeCard().previousElementSibling) && tryPreventingDefault(e); self.next = (e) => self.changeActiveCard(self.activeCard().nextElementSibling) && tryPreventingDefault(e); self.last = (e) => self.changeActiveCard(self.cardsOrdered[self.cardsCount - 1]) && tryPreventingDefault(e); self.changeActiveCard = (newActiveCard) => { const oldActiveCard = self.activeCard(); oldActiveCard.classList.remove('active'); newActiveCard.classList.add('active'); self.rearrangeCardsAroundActiveCard(); self.updateCardsCounter(); self.centerActiveCard(); return true; }; self.initSlider = () => self.slider = self.querySelector('.slideArea'); self.initCardOrder = () => self.cardsOrdered = Array.from(self.querySelectorAll('.card')); if (!self.activeCard()) self.firstCard().classList.add('active'); self.updateCardsCount(); self.initCardOrder(); self.initSlider(); self.rearrangeCardsAroundActiveCard(); }; function initSizer(galleryNode) { const self = galleryNode; self.updateSize = ()=> self.cardsOrdered.forEach(card=>card.updateSize()); self.cardsOrdered.forEach((card)=>initCard(card,self)); self.updateSize(); window.addEventListener('resize',()=>{ self.centerActiveCardInstantly(); // include updateSize }); } function initCard(card, galleryNode){ const self = card; self.gallery = galleryNode; self.updateSize = ()=>{ const cardContentNode = self.querySelector(".cardContent"); const galleryRatio = self.gallery.offsetWidth / self.gallery.offsetHeight; const screenRatio = window.innerWidth / window.innerHeight; if(self.classList.contains('cover')){ cardContentNode.style.width = `${self.gallery.offsetWidth}px`; cardContentNode.style.height = `${self.gallery.offsetHeight}px`; } else if(self.classList.contains('ratio')){ const ratioWH = cardContentNode.className.match(/ratio-([0-9]+)-([0-9]+)/); const cardRatio = ratioWH[1]/ratioWH[2]; if(cardRatio>galleryRatio) { cardContentNode.style.width = `${self.gallery.offsetWidth}px`; cardContentNode.style.height = `${self.gallery.offsetWidth/cardRatio}px`; } else { cardContentNode.style.width = `${self.gallery.offsetHeight*cardRatio}px`; cardContentNode.style.height = `${self.gallery.offsetHeight}px`; } } else { // auto if(screenRatio>galleryRatio) { cardContentNode.style.width = `${self.gallery.offsetWidth}px`; cardContentNode.style.height = `${self.gallery.offsetWidth/screenRatio}px`; } else { cardContentNode.style.width = `${self.gallery.offsetHeight*screenRatio}px`; cardContentNode.style.height = `${self.gallery.offsetHeight}px`; } } }; } function initScroll(galleryNode) { const self = galleryNode; self.initPrevNext = () => { self.resizePrevNext(); self.querySelector('.prev').addEventListener('click', self.prev); self.querySelector('.next').addEventListener('click', self.next); window.addEventListener('resize',self.resizePrevNext); // mobile swipe https://css-tricks.com/simple-swipe-with-vanilla-javascript/ function unify(e) { return e.changedTouches ? e.changedTouches[0] : e } let initialX = "not dragging"; let initialSliderX; async function press(e){ tryPreventingDefault(e); self.classList.remove('smooth'); await sleep(0); initialX = unify(e).clientX; initialSliderX = self.slider.offsetLeft; } function drag(e){ if("not dragging" === initialX) return; tryPreventingDefault(e); self.slider.style.left = `${Math.round(initialSliderX + unify(e).clientX - initialX)}px`; } async function release(e){ const actualX = unify(e).clientX; self.classList.add('smooth'); if (actualX-initialX > window.innerWidth/20){ self.prev(unify(e)); } else if (initialX-actualX > window.innerWidth/20){ self.next(unify(e)); } else { self.centerActiveCard(); } initialX = "not dragging"; } self.slider.addEventListener('mousedown', press); self.slider.addEventListener('touchstart', press); self.slider.addEventListener('mousemove', drag); self.slider.addEventListener('touchmove', drag); self.slider.addEventListener('mouseup', release); self.slider.addEventListener('touchend', release); self.slider.addEventListener('touchcancel',release); self.uglySwipZoomFirefoxFix = release; //self.slider.addEventListener('mouseleave',release); // déplacé dans zoom.mjs en conditionnel pour éviter les conflit au dézoom via esc dans firefox. (gère le glissé hors zone de galerie). //self.slider.addEventListener('touchleave',release); }; self.resizePrevNext = ()=>{ const resizeButton = btn=>{ btn.style.height = `${btn.offsetWidth}px`; btn.style.marginTop = `-${btn.offsetWidth/2}px`; }; resizeButton(self.querySelector('.prev')); resizeButton(self.querySelector('.next')); }; self.initCardCounter = () => { self.cardCounter = self.querySelector('.cardCounter'); if (self.cardsCount < 10) { self.cardCounter.classList.add('dots'); const dots = []; for (let i = 0; i < self.cardsCount; i++) dots.push(`<a class="dot" href="#card-${i + 1}"></a>`); // ⬤ self.cardCounter.innerHTML = dots.join(''); Array.from(self.cardCounter.children).forEach((n, i) => { n.addEventListener('click', (e) => self.changeActiveCard(self.cardsOrdered[i]) && tryPreventingDefault(e)); }); } else { self.cardCounter.classList.add('arrowNav'); self.cardCounter.innerHTML = ` <a class="first" href="#firstCard">«</a> <a class="prev" href="#previousCard">‹</a> <span class="currentCard"></span> / <span class="totalCards">${self.cardsCount}</span> <a class="next" href="#nextCard">›</a> <a class="last" href="#lastCard">»</a> `; const onDo = (selector, action) => self.cardCounter.querySelector(selector).addEventListener('click', action); onDo('.first', self.first); onDo('.prev', self.prev); onDo('.next', self.next); onDo('.last', self.last); } self.updateCardsCounter(); }; self.updateCardsCounter = () => { const activeNumber = self.cardsOrdered.indexOf(self.activeCard()); if (self.cardsCount < 10) { const oldActive = self.cardCounter.querySelector('.active'); if (oldActive) oldActive.classList.remove('active'); self.cardCounter.children[activeNumber].classList.add('active'); } else self.cardCounter.querySelector('.currentCard').innerHTML = `${activeNumber + 1}`; }; self.initPrevNext(); self.initCardCounter(); } var initScroll$1 = async (galleryNode) => { const self = galleryNode; self.centerActiveCard = () => { if(typeof self.updateSize !== "undefined") self.updateSize(); const galleryWidth = self.offsetWidth; const activeCardWidth = self.activeCard().offsetWidth; const activeCardLeft = self.activeCard().offsetLeft; self.slider.style.left = `${galleryWidth / 2 - activeCardLeft - activeCardWidth / 2}px`; }; self.centerActiveCardInstantly = async () => { self.classList.remove('smooth'); await sleep(0); self.classList.remove('smooth'); self.centerActiveCard(); await sleep(0); self.classList.add('smooth'); }; await self.centerActiveCardInstantly(); }; var initAutoPlay = (galleryNode) => { const self = galleryNode; self.initAutoPlay = ()=>{ const isAutoPlay = self.className.match(/autoplay-([0-9]+)s/); if(!isAutoPlay) return; const playSpeed = parseInt(isAutoPlay[1]); setInterval(self.autoNext,playSpeed*1000); const setPauseArea = (pauseArea)=>{ pauseArea.addEventListener('mouseenter', ()=>self.pause=true); pauseArea.addEventListener('mouseleave', ()=>self.pause=false); }; setPauseArea(self.cardCounter); setPauseArea(self.querySelector('.prev')); setPauseArea(self.querySelector('.next')); // Don't auto-play when dragging / swapping self.slider.addEventListener('mousedown', ()=>self.pause=true); self.slider.addEventListener('touchstart', ()=>self.pause=true); self.slider.addEventListener('mouseup', ()=>self.pause=false); self.slider.addEventListener('touchend', ()=>self.pause=false); self.slider.addEventListener('touchcancel',()=>self.pause=false); }; self.autoNext = ()=>{ if(self.pause) return; self.next(); }; self.initAutoPlay(); }; function init$1(galleryNode){ const self = galleryNode; self.zoomToggle = async (e)=>{ tryPreventingDefault(e); if(self.classList.contains('fullScreen')) await self.zoomOut(); else await self.zoomFullScreen(); return false; }; self.zoomFullScreen = async ()=>{ self.slider.removeEventListener('mouseleave',self.uglySwipZoomFirefoxFix); self.classList.add('fullScreen'); try{await self.requestFullscreen();}catch (e){console.error(e);} self.activateKeyboardNav(); self.resizePrevNext(); await self.centerActiveCardInstantly(); // to try to mitigate firefox resize/fullscreen random behavior and false size delay await sleep(100); await self.centerActiveCardInstantly(); }; self.zoomOut = async ()=>{ self.classList.remove('fullScreen'); try{await document.exitFullscreen();}catch (e){} self.disableKeyboardNav(); await sleep(0); self.resizePrevNext(); await self.centerActiveCardInstantly(); // to try to mitigate firefox resize/fullscreen random behavior and false size delay await sleep(100); await self.centerActiveCardInstantly(); self.slider.addEventListener('mouseleave',self.uglySwipZoomFirefoxFix); }; self.keyUpFunc = (event)=>{ switch (event.code){ case "ArrowLeft" : self.prev(); break; case "Space" : case "ArrowRight" : self.next(); break; case "PageUp" : case "Home" : self.first(); break; case "PageDown" : case "End" : self.last(); break; case "Digit1" : if(self.cardsOrdered[0]) self.changeActiveCard(self.cardsOrdered[0]); else return; break; case "Digit2" : if(self.cardsOrdered[1]) self.changeActiveCard(self.cardsOrdered[1]); else return; break; case "Digit3" : if(self.cardsOrdered[2]) self.changeActiveCard(self.cardsOrdered[2]); else return; break; case "Digit4" : if(self.cardsOrdered[3]) self.changeActiveCard(self.cardsOrdered[3]); else return; break; case "Digit5" : if(self.cardsOrdered[4]) self.changeActiveCard(self.cardsOrdered[4]); else return; break; case "Digit6" : if(self.cardsOrdered[5]) self.changeActiveCard(self.cardsOrdered[5]); else return; break; case "Digit7" : if(self.cardsOrdered[6]) self.changeActiveCard(self.cardsOrdered[6]); else return; break; case "Digit8" : if(self.cardsOrdered[7]) self.changeActiveCard(self.cardsOrdered[7]); else return; break; case "Digit9" : if(self.cardsOrdered[8]) self.changeActiveCard(self.cardsOrdered[8]); else return; break; case "Digit0" : if(self.cardsOrdered[9]) self.changeActiveCard(self.cardsOrdered[9]); else return; break; default: return; } tryPreventingDefault(event); }; self.activateKeyboardNav = ()=>{ document.addEventListener('keyup', self.keyUpFunc); }; self.disableKeyboardNav = ()=>{ document.removeEventListener('keyup',self.keyUpFunc); }; if(!self.classList.contains('zoomable')) return; const zoomButton = document.createElement('a'); zoomButton.classList.add('zoom'); zoomButton.setAttribute('href','#fullScreen'); zoomButton.innerHTML = `<span>🔍</span>`; zoomButton.addEventListener('click', self.zoomToggle); self.appendChild(zoomButton); document.addEventListener('fullscreenchange', async ()=> { if (!document.fullscreenElement && self.classList.contains('fullScreen')) await self.zoomOut(); }); } function init$2(){ init(); document.querySelectorAll('._1gallery').forEach(g=>{ if(g.classList.contains('js')) return; g.classList.add('js'); init1GalleryCore(g); initScroll(g); initSizer(g); initScroll$1(g); initAutoPlay(g); init$1(g); }); } docReady(init$2); return init$2; }());