263 lines
9.1 KiB
JavaScript
Executable File
263 lines
9.1 KiB
JavaScript
Executable File
/**
|
|
* Agent Gallery JavaScript
|
|
*
|
|
* Thumbnail slider with lightbox functionality
|
|
*
|
|
* @package HomeProz
|
|
*/
|
|
|
|
(function($) {
|
|
'use strict';
|
|
|
|
// Early return if not on agent page
|
|
if (!$('.Single_Agent').length) {
|
|
return;
|
|
}
|
|
|
|
var AgentGallery = {
|
|
$gallery: null,
|
|
$thumbsSlider: null,
|
|
$thumbs: null,
|
|
$lightbox: null,
|
|
$lightboxImage: null,
|
|
$lightboxCounter: null,
|
|
images: [],
|
|
currentIndex: 0,
|
|
isTransitioning: false,
|
|
slideDuration: 300,
|
|
|
|
init: function() {
|
|
this.$gallery = $('.agent-gallery');
|
|
|
|
if (!this.$gallery.length) {
|
|
return;
|
|
}
|
|
|
|
this.$thumbsSlider = this.$gallery.find('.agent-gallery-thumbs-slider');
|
|
this.$thumbs = this.$gallery.find('.agent-gallery-thumb');
|
|
this.$lightbox = this.$gallery.find('.agent-gallery-lightbox');
|
|
this.$lightboxImage = this.$lightbox.find('.lightbox-image');
|
|
this.$lightboxCounter = this.$lightbox.find('.lightbox-current');
|
|
|
|
// Load images data
|
|
var $dataScript = this.$gallery.find('.agent-gallery-data');
|
|
if ($dataScript.length) {
|
|
try {
|
|
this.images = JSON.parse($dataScript.text());
|
|
} catch (e) {
|
|
console.error('Failed to parse gallery data');
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (this.images.length === 0) {
|
|
return;
|
|
}
|
|
|
|
this.initSlick();
|
|
this.bindEvents();
|
|
},
|
|
|
|
initSlick: function() {
|
|
// Only init slick if more images than can fit
|
|
this.$thumbsSlider.slick({
|
|
slidesToShow: 6,
|
|
slidesToScroll: 3,
|
|
arrows: true,
|
|
dots: false,
|
|
infinite: false,
|
|
speed: 300,
|
|
autoplay: false,
|
|
variableWidth: false,
|
|
prevArrow: '<button type="button" class="slick-prev" aria-label="Previous"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg></button>',
|
|
nextArrow: '<button type="button" class="slick-next" aria-label="Next"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg></button>',
|
|
responsive: [
|
|
{
|
|
breakpoint: 768,
|
|
settings: {
|
|
slidesToShow: 4,
|
|
slidesToScroll: 2
|
|
}
|
|
},
|
|
{
|
|
breakpoint: 480,
|
|
settings: {
|
|
slidesToShow: 3,
|
|
slidesToScroll: 2
|
|
}
|
|
}
|
|
]
|
|
});
|
|
},
|
|
|
|
bindEvents: function() {
|
|
var self = this;
|
|
|
|
// Thumbnail clicks open lightbox
|
|
this.$thumbs.on('click', function() {
|
|
var index = parseInt($(this).data('index'));
|
|
self.openLightbox(index);
|
|
});
|
|
|
|
// Close lightbox - clicking overlay, container, or close button
|
|
this.$lightbox.find('.lightbox-close, .lightbox-overlay, .lightbox-container').on('click', function(e) {
|
|
// Only close if clicking directly on these elements, not their children (except close btn)
|
|
if (e.target === this || $(this).hasClass('lightbox-close')) {
|
|
self.closeLightbox();
|
|
}
|
|
});
|
|
|
|
// Lightbox navigation
|
|
this.$lightbox.find('.lightbox-prev').on('click', function() {
|
|
self.slideLightboxImage('prev');
|
|
});
|
|
|
|
this.$lightbox.find('.lightbox-next').on('click', function() {
|
|
self.slideLightboxImage('next');
|
|
});
|
|
|
|
// Keyboard navigation
|
|
$(document).on('keydown', function(e) {
|
|
if (!self.$lightbox.is('[aria-hidden="false"]')) {
|
|
return;
|
|
}
|
|
|
|
switch (e.key) {
|
|
case 'Escape':
|
|
self.closeLightbox();
|
|
break;
|
|
case 'ArrowLeft':
|
|
self.slideLightboxImage('prev');
|
|
break;
|
|
case 'ArrowRight':
|
|
self.slideLightboxImage('next');
|
|
break;
|
|
}
|
|
});
|
|
|
|
// Swipe support for lightbox
|
|
this.bindSwipeEvents();
|
|
},
|
|
|
|
bindSwipeEvents: function() {
|
|
var self = this;
|
|
var startX = 0;
|
|
var threshold = 50;
|
|
|
|
var $container = this.$lightbox.find('.lightbox-image-container');
|
|
|
|
$container[0].addEventListener('touchstart', function(e) {
|
|
if (e.touches.length === 1) {
|
|
startX = e.touches[0].clientX;
|
|
}
|
|
}, { passive: true });
|
|
|
|
$container[0].addEventListener('touchend', function(e) {
|
|
if (e.changedTouches.length !== 1) return;
|
|
|
|
var deltaX = e.changedTouches[0].clientX - startX;
|
|
|
|
if (Math.abs(deltaX) > threshold) {
|
|
if (deltaX > 0) {
|
|
self.slideLightboxImage('prev');
|
|
} else {
|
|
self.slideLightboxImage('next');
|
|
}
|
|
}
|
|
}, { passive: true });
|
|
},
|
|
|
|
openLightbox: function(index) {
|
|
this.currentIndex = index;
|
|
this.updateLightboxImage();
|
|
this.$lightbox.attr('aria-hidden', 'false');
|
|
$('body').addClass('lightbox-open');
|
|
},
|
|
|
|
closeLightbox: function() {
|
|
this.$lightbox.attr('aria-hidden', 'true');
|
|
$('body').removeClass('lightbox-open');
|
|
},
|
|
|
|
slideLightboxImage: function(direction) {
|
|
var self = this;
|
|
|
|
if (this.isTransitioning || this.images.length <= 1) {
|
|
return;
|
|
}
|
|
|
|
var newIndex;
|
|
if (direction === 'prev') {
|
|
newIndex = this.currentIndex - 1;
|
|
if (newIndex < 0) newIndex = this.images.length - 1;
|
|
} else {
|
|
newIndex = this.currentIndex + 1;
|
|
if (newIndex >= this.images.length) newIndex = 0;
|
|
}
|
|
|
|
this.isTransitioning = true;
|
|
|
|
var image = this.images[newIndex];
|
|
var slideFrom = direction === 'next' ? '100%' : '-100%';
|
|
var slideTo = direction === 'next' ? '-100%' : '100%';
|
|
|
|
var $container = this.$lightbox.find('.lightbox-image-container');
|
|
|
|
// Create new image
|
|
var $newImage = $('<img class="lightbox-slide-image" />');
|
|
$newImage.attr('src', image.url);
|
|
$newImage.attr('alt', image.alt || 'Gallery photo');
|
|
$newImage.css({
|
|
'position': 'absolute',
|
|
'max-width': '100%',
|
|
'max-height': 'calc(100vh - 8rem)',
|
|
'object-fit': 'contain',
|
|
'transform': 'translateX(' + slideFrom + ')',
|
|
'left': '50%',
|
|
'top': '50%',
|
|
'margin-left': '-45vw',
|
|
'margin-top': 'calc(-50vh + 4rem)'
|
|
});
|
|
|
|
$container.css({
|
|
'position': 'relative',
|
|
'overflow': 'hidden'
|
|
});
|
|
|
|
$container.append($newImage);
|
|
|
|
this.$lightboxImage.css('transition', 'transform ' + this.slideDuration + 'ms ease-out');
|
|
$newImage.css('transition', 'transform ' + this.slideDuration + 'ms ease-out');
|
|
|
|
// Trigger reflow
|
|
$newImage[0].offsetHeight;
|
|
|
|
this.$lightboxImage.css('transform', 'translateX(' + slideTo + ')');
|
|
$newImage.css('transform', 'translateX(0)');
|
|
|
|
setTimeout(function() {
|
|
self.$lightboxImage.attr('src', image.url);
|
|
self.$lightboxImage.attr('alt', image.alt || 'Gallery photo');
|
|
self.$lightboxImage.css({ 'transition': '', 'transform': '' });
|
|
$newImage.remove();
|
|
self.isTransitioning = false;
|
|
self.$lightboxCounter.text(newIndex + 1);
|
|
}, this.slideDuration);
|
|
|
|
this.currentIndex = newIndex;
|
|
},
|
|
|
|
updateLightboxImage: function() {
|
|
var image = this.images[this.currentIndex];
|
|
this.$lightboxImage.attr('src', image.url);
|
|
this.$lightboxImage.attr('alt', image.alt || 'Gallery photo');
|
|
this.$lightboxCounter.text(this.currentIndex + 1);
|
|
}
|
|
};
|
|
|
|
$(function() {
|
|
AgentGallery.init();
|
|
});
|
|
|
|
})(jQuery);
|