258 lines
7.9 KiB
JavaScript
258 lines
7.9 KiB
JavaScript
/**
|
|
* Instagram Gallery Sync Pro - Frontend Script
|
|
*
|
|
* Handles gallery initialization, masonry, lightbox, and lazy loading
|
|
*
|
|
* @package Instagram_Gallery_Sync_Pro
|
|
*/
|
|
|
|
(function ($) {
|
|
'use strict';
|
|
|
|
/**
|
|
* Gallery Controller
|
|
*/
|
|
const IGSPGallery = {
|
|
|
|
/**
|
|
* Initialize all galleries on page
|
|
*/
|
|
init: function () {
|
|
const self = this;
|
|
|
|
// Wait for DOM ready
|
|
$(document).ready(function () {
|
|
self.initGalleries();
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Initialize individual galleries
|
|
*/
|
|
initGalleries: function () {
|
|
const self = this;
|
|
|
|
$('.igsp-gallery').each(function () {
|
|
const $gallery = $(this);
|
|
const layout = $gallery.data('layout');
|
|
|
|
// Set responsive CSS variables
|
|
self.setResponsiveVariables($gallery);
|
|
|
|
// Initialize based on layout
|
|
switch (layout) {
|
|
case 'masonry':
|
|
self.initMasonry($gallery);
|
|
break;
|
|
case 'slider':
|
|
self.initSlider($gallery);
|
|
break;
|
|
default:
|
|
self.initGrid($gallery);
|
|
}
|
|
|
|
// Initialize lightbox if enabled
|
|
if (typeof igspFrontend !== 'undefined' && igspFrontend.lightbox) {
|
|
self.initLightbox($gallery);
|
|
}
|
|
|
|
// Initialize lazy loading
|
|
self.initLazyLoad($gallery);
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Set responsive CSS variables
|
|
*/
|
|
setResponsiveVariables: function ($gallery) {
|
|
const columnsTablet = $gallery.data('columns-tablet') || 2;
|
|
const columnsMobile = $gallery.data('columns-mobile') || 1;
|
|
|
|
$gallery.css({
|
|
'--columns-tablet': columnsTablet,
|
|
'--columns-mobile': columnsMobile
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Initialize grid layout
|
|
*/
|
|
initGrid: function ($gallery) {
|
|
$gallery.addClass('loaded');
|
|
},
|
|
|
|
/**
|
|
* Initialize masonry layout
|
|
*/
|
|
initMasonry: function ($gallery) {
|
|
if (typeof Masonry === 'undefined' || typeof imagesLoaded === 'undefined') {
|
|
// Fallback to CSS-only masonry
|
|
$gallery.addClass('no-js loaded');
|
|
return;
|
|
}
|
|
|
|
$gallery.addClass('loading');
|
|
|
|
// Wait for images to load
|
|
imagesLoaded($gallery[0], function () {
|
|
const columns = parseInt($gallery.data('columns')) || 3;
|
|
const spacing = parseInt($gallery.data('spacing')) || 10;
|
|
|
|
// Calculate item width
|
|
const columnWidth = Math.floor(($gallery.width() - (spacing * (columns - 1))) / columns);
|
|
|
|
const msnry = new Masonry($gallery[0], {
|
|
itemSelector: '.igsp-item',
|
|
columnWidth: columnWidth,
|
|
gutter: spacing,
|
|
percentPosition: false,
|
|
transitionDuration: '0.3s'
|
|
});
|
|
|
|
$gallery.removeClass('loading').addClass('masonry-initialized loaded');
|
|
|
|
// Handle responsive
|
|
let resizeTimeout;
|
|
$(window).on('resize', function () {
|
|
clearTimeout(resizeTimeout);
|
|
resizeTimeout = setTimeout(function () {
|
|
msnry.layout();
|
|
}, 250);
|
|
});
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Initialize slider layout
|
|
*/
|
|
initSlider: function ($gallery) {
|
|
if (typeof Swiper === 'undefined') {
|
|
console.warn('IGSP: Swiper library not loaded');
|
|
return;
|
|
}
|
|
|
|
const $swiperContainer = $gallery.find('.swiper');
|
|
|
|
if (!$swiperContainer.length) {
|
|
return;
|
|
}
|
|
|
|
const autoplay = typeof igspFrontend !== 'undefined' && igspFrontend.autoplay;
|
|
|
|
new Swiper($swiperContainer[0], {
|
|
slidesPerView: 'auto',
|
|
spaceBetween: parseInt($gallery.data('spacing')) || 10,
|
|
loop: true,
|
|
centeredSlides: false,
|
|
autoplay: autoplay ? {
|
|
delay: 4000,
|
|
disableOnInteraction: false
|
|
} : false,
|
|
pagination: {
|
|
el: '.swiper-pagination',
|
|
clickable: true
|
|
},
|
|
navigation: {
|
|
nextEl: '.swiper-button-next',
|
|
prevEl: '.swiper-button-prev'
|
|
},
|
|
breakpoints: {
|
|
320: {
|
|
slidesPerView: 1,
|
|
centeredSlides: true
|
|
},
|
|
640: {
|
|
slidesPerView: 2,
|
|
centeredSlides: false
|
|
},
|
|
1024: {
|
|
slidesPerView: 3,
|
|
centeredSlides: false
|
|
}
|
|
}
|
|
});
|
|
|
|
$gallery.addClass('loaded');
|
|
},
|
|
|
|
/**
|
|
* Initialize lightbox
|
|
*/
|
|
initLightbox: function ($gallery) {
|
|
if (typeof GLightbox === 'undefined') {
|
|
console.warn('IGSP: GLightbox library not loaded');
|
|
return;
|
|
}
|
|
|
|
const lightbox = GLightbox({
|
|
selector: '.igsp-gallery [data-gallery="igsp-lightbox"]',
|
|
touchNavigation: true,
|
|
loop: true,
|
|
autoplayVideos: false,
|
|
openEffect: 'zoom',
|
|
closeEffect: 'zoom',
|
|
cssEfects: {
|
|
fade: { in: 'fadeIn', out: 'fadeOut' },
|
|
zoom: { in: 'zoomIn', out: 'zoomOut' }
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Initialize lazy loading
|
|
*/
|
|
initLazyLoad: function ($gallery) {
|
|
const $lazyImages = $gallery.find('.igsp-image.lazyload');
|
|
|
|
if (!$lazyImages.length) {
|
|
return;
|
|
}
|
|
|
|
// Use native lazy loading if supported
|
|
if ('loading' in HTMLImageElement.prototype) {
|
|
$lazyImages.each(function () {
|
|
const $img = $(this);
|
|
$img.attr('src', $img.data('src'));
|
|
$img.removeClass('lazyload').addClass('loaded');
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Fallback: Intersection Observer
|
|
if ('IntersectionObserver' in window) {
|
|
const observer = new IntersectionObserver(function (entries) {
|
|
entries.forEach(function (entry) {
|
|
if (entry.isIntersecting) {
|
|
const img = entry.target;
|
|
img.src = img.dataset.src;
|
|
img.classList.remove('lazyload');
|
|
img.classList.add('loaded');
|
|
observer.unobserve(img);
|
|
}
|
|
});
|
|
}, {
|
|
rootMargin: '100px'
|
|
});
|
|
|
|
$lazyImages.each(function () {
|
|
observer.observe(this);
|
|
});
|
|
} else {
|
|
// Fallback: Load all images immediately
|
|
$lazyImages.each(function () {
|
|
const $img = $(this);
|
|
$img.attr('src', $img.data('src'));
|
|
$img.removeClass('lazyload').addClass('loaded');
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
// Initialize
|
|
IGSPGallery.init();
|
|
|
|
// Make available globally
|
|
window.IGSPGallery = IGSPGallery;
|
|
|
|
})(jQuery);
|