/*
SITE GALLERY MANAGER
Handles two main functions:
1. Responsive Images
- Automatically loads appropriate image sizes based on screen width
- Listens for resize events and updates images accordingly
- Uses data-small, data-medium, and data-full attributes on images
2. Gallery Management
- HTML Structure:
Key Features:
- Opens in modal dialog with keyboard navigation
- Manages thumbnail navigation state
- Handles responsive image loading
- Uses class-based state management (open, expanded, hide-info)
- All event handling through delegation
- Built on UIHandler base class for state management
State Management:
- Dialog: open/closed
- Thumbnails: collapsed/open/expanded
- Info panel: visible/hidden
- Active image: tracked with .focused class
*/
class Media {
constructor() {
this.currentWidth = window.innerWidth;
this.initElements();
if (this.images.length === 0) {
return;
}
this.store = new window.jvbStore({
name: 'images',
TTL: 604800
});
this.touch = {
x: null,
y: null
}
this.a11y = window.jvbA11y;
this.debouncer = window.debouncer;
this.isTouching = false;
this.initListeners();
document.addEventListener('beforeunload', this.cleanup);
}
initElements(){
this.images = document.querySelectorAll('.wp-site-blocks img');
this.gallery = document.querySelector('dialog.gallery');
this.modal = new window.jvbModal(this.gallery, {
openMessage: 'Opened Gallery',
closeMessage: 'Closed Gallery',
open: '.open-gallery',
close: '.close'
});
this.modal.subscribe((event, data) => {
if (event === 'modal-open') {
this.openGallery();
} else if (event === 'modal-close') {
this.closeGallery();
}
});
}
initListeners() {
this.resizeHandler = this.handleResize.bind(this);
this.clickHandler = this.handleClick.bind(this);
this.keysHandler = this.handleKeys.bind(this);
this.touchStartHandler = this.handleTouchStart.bind(this);
this.touchEndHandler = this.handleTouchEnd.bind(this);
document.addEventListener('click', this.clickHandler);
window.addEventListener('resize', this.resizeHandler);
console.log('window hash: ',window.location.hash);
let target = document.querySelector(window.location.hash);
if (target && target.tagName === 'LI') {
let trigger = target.querySelector('.open-gallery');
if (trigger) {
this.openGallery(trigger);
}
}
this.observer = new IntersectionObserver((entries) =>{
entries.forEach(entry => {
if (entry.isIntersecting) {
let img = entry.target;
if (!img.closest('dialog')) {
this.loadAppropriateImage(img);
this.observer.unobserve(img);
}
}
})
}, {
root: null,
rootMargin: '50px',
threshold: .1
});
this.images.forEach(img => {
if (!img.closest('dialog')) {
this.observer.observe(img);
}
})
}
initTouchHandling() {
this.isTouching = true;
this.touch.x = 0;
this.touch.y = 0;
this.gallery.addEventListener('touchstart', this.touchStartHandler);
this.gallery.addEventListener('touchend', this.touchEndHandler);
}
cancelTouchHandling() {
this.isTouching = false;
this.gallery.removeEventListener('touchstart', this.touchStartHandler);
this.gallery.removeEventListener('touchend', this.touchEndHandler);
}
handleTouchStart(e) {
this.touch.x = e.touches[0].clientX;
this.touch.y = e.touches[0].clientY;
}
handleTouchEnd(e) {
const diffX = e.changedTouches[0].clientX - this.touch.x;
const diffY = e.changedTouches[0].clientY - this.touch.y;
if (Math.abs(diffX) > Math.abs(diffY) && Math.abs(diffX) > 50) {
this.navigateImages({target: this.gallery}, diffX < 0 ? 'next' : 'previous');
}
}
handleResize(e) {
window.debouncer.schedule(
'resize',
()=> {
const currentWidth = window.innerWidth;
if (Math.abs(currentWidth - this.currentWidth) > 100) {
this.currentWidth = currentWidth;
this.handleImageResize();
}
},
150
);
}
handleClick(e) {
}
handleKeys(e) {
//Escape handled by Modal.js
if (e.key === 'Tab') {
if (e.shiftKey) {
} else {
}
}
}
openGallery(target = null) {
document.addEventListener('keydown', this.clickHandler);
const id = target.dataset.opens;
this.initTouchHandling();
let focus;
if (!target) {
focus = this.images[0];
} else {
focus = target.dataset.focus;
}
if (focus) {
this.updateImage(this.gallery.querySelector(`#${focus}`));
}
}
closeGallery() {
this.cancelTouchHandling();
document.removeEventListener('keydown', this.keysHandler);
//Restore focus
if (this.lastFocusedElement) {
this.lastFocusedElement.focus();
}
}
cleanup() {
this.observer.disconnect();
window.removeEventListener('resize', this.resizeHandler)
if (this.isTouching) {
this.cancelTouchHandling();
document.removeEventListener('keydown', this.keysHandler);
}
document.removeEventListener('click', this.clickHandler);
}
}