PageSourceSearch

https://goldenoakranch.com/app/themes/velocity-golden-oak-v2/assets/js/location-gallery.js?ver=2.0.0

js goldenoakranch.com collected 2026-10-02 12:58:20 UTC 17,360 bytes, 488 lines download raw bytes

1/**
2 * Location Gallery - Swiper Implementation
3 * 
4 * Replaces legacy mediaGallery.js (CodeCanyon) with modern Swiper 11.
5 * Features: Main gallery, thumbnails, video support, info panel, controls.
6 * 
7 * @package Velocity_Golden_Oak_V2
8 * @since 2.0.0
9 */
10
11(function($) {
12    'use strict';
13
14    // Store Swiper instances
15    var galleryInstances = {};
16
17    /**
18     * Initialize all location galleries on the page
19     */
20    function initLocationGalleries() {
21        // Check if Swiper is loaded
22        if (typeof Swiper === 'undefined') {
23            console.error('Swiper.js is not loaded');
24            return;
25        }
26
27        // Check if we have gallery data
28        if (typeof velocityLocationGalleryData === 'undefined') {
29            return;
30        }
31
32        // Initialize each gallery
33        Object.keys(velocityLocationGalleryData).forEach(function(key) {
34            var data = velocityLocationGalleryData[key];
35            initGallery(data);
36        });
37    }
38
39    /**
40     * Initialize a single gallery
41     * 
42     * @param {Object} data Gallery configuration data
43     */
44    function initGallery(data) {
45        var mainContainer = document.getElementById(data.mainId);
46        var thumbsContainer = document.getElementById(data.thumbsId);
47        
48        if (!mainContainer) {
49            console.error('Gallery container not found:', data.mainId);
50            return;
51        }
52
53        // Initialize thumbnails Swiper first (if exists)
54        // Vertical layout on right side (custom_right style from legacy mediaGallery)
55        var thumbsSwiper = null;
56        if (thumbsContainer) {
57            thumbsSwiper = new Swiper('#' + data.thumbsId, {
58                direction: 'vertical',
59                spaceBetween: 10,
60                slidesPerView: 'auto',
61                freeMode: true,
62                watchSlidesProgress: true,
63                initialSlide: data.startIndex,
64                mousewheel: true,
65            });
66        }
67
68        // Initialize main Swiper
69        var mainSwiper = new Swiper('#' + data.mainId, {
70            spaceBetween: 0,
71            slidesPerView: 1,
72            initialSlide: data.startIndex,
73            loop: true, // Circular navigation
74            keyboard: {
75                enabled: true,
76            },
77            // Navigation arrows
78            navigation: {
79                nextEl: '#' + data.mainId + ' .location-nav-next',
80                prevEl: '#' + data.mainId + ' .location-nav-prev',
81            },
82            // Autoplay (disabled by default, controlled via play button)
83            autoplay: data.autoplay ? {
84                delay: data.autoplayDelay,
85                disableOnInteraction: false,
86                pauseOnMouseEnter: true,
87            } : false,
88            // Thumbs
89            thumbs: thumbsSwiper ? {
90                swiper: thumbsSwiper,
91            } : undefined,
92            // Events
93            on: {
94                slideChange: function() {
95                    onSlideChange(this, data);
96                },
97                init: function() {
98                    onSlideChange(this, data);
99                }
100            }
101        });
102
103        // Store instances
104        galleryInstances[data.mainId] = {
105            main: mainSwiper,
106            thumbs: thumbsSwiper,
107            data: data,
108            isPlaying: data.autoplay
109        };
110
111        // Set up controls
112        setupControls(data.mainId);
113        
114        // Set up info panel
115        setupInfoPanel(data.mainId);
116        
117        // Set up video handling
118        setupVideoHandling(data.mainId);
119        
120        // Set up thumbnail toggle
121        setupThumbnailToggle(data.mainId);
122
123        console.log('Location gallery initialized:', data.mainId);
124    }
125
126    /**
127     * Handle slide change event
128     * 
129     * @param {Swiper} swiper Swiper instance
130     * @param {Object} data Gallery data
131     */
132    function onSlideChange(swiper, data) {
133        var currentIndex = swiper.realIndex; // Use realIndex for loop mode
134        var $gallery = $(swiper.el).closest('.velocity-location-gallery');
135        
136        // Update counter in gallery
137        $gallery.find('.counter-current').text(currentIndex + 1);
138        
139        // Update counter in header (.location-image-counter)
140        $('.location-image-counter .counter-current').text(currentIndex + 1);
141        $('.location-image-counter .counter-total').text(data.imageCount);
142        
143        // Update info panel content
144        if (data.images && data.images[currentIndex]) {
145            var image = data.images[currentIndex];
146            $gallery.find('.info-title').text(image.altText || '');
147            $gallery.find('.info-description').text(image.description || '');
148            
149            // Update download link
150            if (image.type === 'image' && image.imageUrl) {
151                $gallery.find('.location-gallery-download')
152                    .attr('href', image.imageUrl)
153                    .show();
154            } else {
155                $gallery.find('.location-gallery-download').hide();
156            }
157        }
158        
159        // Close info_holder when slide changes (navigation button pressed)
160        var $infoHolder = $('.info_holder');
161        if ($infoHolder.is(':visible')) {
162            $infoHolder.fadeOut(200);
163        }
164        
165        // Pause all videos when changing slides
166        pauseAllVideos($gallery);
167        
168        // Auto-play video if current slide is video
169        var $currentSlide = $(swiper.slides[currentIndex]);
170        if ($currentSlide.data('type') === 'video') {
171            var $video = $currentSlide.find('video');
172            if ($video.length) {
173                $video[0].play().catch(function() {
174                    // Auto-play failed, show play button
175                    $currentSlide.find('.video-play-overlay').show();
176                });
177            }
178        }
179    }
180
181    /**
182     * Set up gallery controls (prev, next, play/pause)
183     * 
184     * @param {string} galleryId Main gallery ID
185     */
186    function setupControls(galleryId) {
187        var instance = galleryInstances[galleryId];
188        if (!instance) return;
189        
190        var $gallery = $('#' + galleryId).closest('.velocity-location-gallery');
191        
192        // Previous button
193        $gallery.find('.control-prev').on('click', function() {
194            instance.main.slidePrev();
195        });
196        
197        // Next button
198        $gallery.find('.control-next').on('click', function() {
199            instance.main.slideNext();
200        });
201        
202        // Play/Pause button
203        $gallery.find('.control-play-pause').on('click', function() {
204            var $btn = $(this);
205            
206            if (instance.isPlaying) {
207                // Stop autoplay
208                instance.main.autoplay.stop();
209                instance.isPlaying = false;
210                $btn.find('.play-icon').show();
211                $btn.find('.pause-icon').hide();
212            } else {
213                // Start autoplay
214                if (!instance.main.autoplay.running) {
215                    instance.main.params.autoplay = {
216                        delay: instance.data.autoplayDelay || 3000,
217                        disableOnInteraction: false,
218                    };
219                }
220                instance.main.autoplay.start();
221                instance.isPlaying = true;
222                $btn.find('.play-icon').hide();
223                $btn.find('.pause-icon').show();
224            }
225        });
226    }
227
228    /**
229     * Set up info panel toggle (info_holder)
230     * 
231     * @param {string} galleryId Main gallery ID
232     */
233    function setupInfoPanel(galleryId) {
234        var $infoHolder = $('.info_holder');
235        var $infoToggleBtn = $('.info-toggle-btn');
236        
237        // Toggle info panel on "i" button click
238        $infoToggleBtn.on('click', function() {
239            if ($infoHolder.is(':visible')) {
240                $infoHolder.fadeOut(200);
241            } else {
242                // Update info content with current slide data
243                updateInfoHolder(galleryId);
244                $infoHolder.fadeIn(200);
245            }
246        });
247        
248        // Close info panel on "x" click
249        $infoHolder.find('.info-holder-close').on('click', function(e) {
250            e.preventDefault();
251            $infoHolder.fadeOut(200);
252        });
253    }
254    
255    /**
256     * Update info holder with current slide data
257     * 
258     * @param {string} galleryId Main gallery ID
259     */
260    function updateInfoHolder(galleryId) {
261        var instance = galleryInstances[galleryId];
262        if (!instance) return;
263        
264        var $infoHolder = $('.info_holder');
265        var currentIndex = instance.main.realIndex;
266        var $currentSlide = $(instance.main.slides[instance.main.activeIndex]);
267        
268        // Get data from slide attributes
269        var title = $currentSlide.attr('data-title') || '';
270        var description = $currentSlide.attr('data-description') || '';
271        
272        // Update info holder content
273        $infoHolder.find('.location_img_name').text(title);
274        $infoHolder.find('.location_img_description').html(description);
275        
276        // Hide if no description
277        if (!description && !title) {
278            $infoHolder.hide();
279        }
280    }
281
282    /**
283     * Set up video handling
284     * 
285     * @param {string} galleryId Main gallery ID
286     */
287    function setupVideoHandling(galleryId) {
288        var $gallery = $('#' + galleryId).closest('.velocity-location-gallery');
289        
290        // Video play button click
291        $gallery.find('.video-play-btn').on('click', function() {
292            var $wrapper = $(this).closest('.slide-video-wrapper');
293            var $video = $wrapper.find('video');
294            var $overlay = $wrapper.find('.video-play-overlay');
295            
296            if ($video.length) {
297                $video[0].play();
298                $overlay.fadeOut(200);
299            }
300        });
301        
302        // Video ended - show play button again
303        $gallery.find('video').on('ended', function() {
304            $(this).closest('.slide-video-wrapper').find('.video-play-overlay').fadeIn(200);
305        });
306        
307        // Video click to pause/play
308        $gallery.find('video').on('click', function() {
309            if (this.paused) {
310                this.play();
311                $(this).closest('.slide-video-wrapper').find('.video-play-overlay').fadeOut(200);
312            } else {
313                this.pause();
314                $(this).closest('.slide-video-wrapper').find('.video-play-overlay').fadeIn(200);
315            }
316        });
317    }
318
319    /**
320     * Set up thumbnail panel toggle (collapse/expand)
321     * 
322     * @param {string} galleryId Main gallery ID
323     */
324    function setupThumbnailToggle(galleryId) {
325        var $gallery = $('#' + galleryId).closest('.velocity-location-gallery');
326        var $thumbsWrapper = $gallery.find('.location-gallery-thumbs-wrapper');
327        var $toggleBtn = $gallery.find('.thumbs-toggle-btn');
328        var isOpen = true;
329        var originalTop = parseInt($thumbsWrapper.css('top'), 10) || 130;
330        var footerHeight = 60;
331        
332        // Main slideshow next arrow position when collapsed must be driven by CSS class:
333        // .location-nav-next uses right: … !important, so jQuery .animate() cannot override it.
334        
335        // Minus/plus visibility when collapsed is handled in location-gallery.css (.collapsed).
336        $toggleBtn.on('click', function() {
337            if (isOpen) {
338                // Collapse - slide down above footer
339                $thumbsWrapper.addClass('collapsed');
340                $thumbsWrapper.css('top', 'auto');
341                $thumbsWrapper.css('bottom', (footerHeight + 15) + 'px');
342                $thumbsWrapper.css('height', '48px');
343                $thumbsWrapper.css('padding', '5px');
344                
345                $gallery.addClass('thumbs-panel-collapsed');
346                
347                isOpen = false;
348            } else {
349                // Expand - slide back up
350                $thumbsWrapper.removeClass('collapsed');
351                $thumbsWrapper.css('top', originalTop + 'px');
352                $thumbsWrapper.css('bottom', footerHeight + 'px');
353                $thumbsWrapper.css('height', 'auto');
354                $thumbsWrapper.css('padding', '15px');
355                
356                $gallery.removeClass('thumbs-panel-collapsed');
357                
358                isOpen = true;
359            }
360        });
361        
362        // Thumbnail navigation buttons (vertical prev/next for scrolling thumbs)
363        var $prevThumbBtn = $gallery.find('.thumb-nav-prev');
364        var $nextThumbBtn = $gallery.find('.thumb-nav-next');
365        // Each thumbnail: 100px height + 8px border (4px*2) + 10px margin = 118px
366        var thumbHeight = 118;
367        var thumbScrollAmount = thumbHeight; // Scroll 1 thumbnail at a time
368        
369        // Check if we need navigation buttons (content taller than container)
370        function checkThumbNavigation() {
371            var instance = galleryInstances[galleryId];
372            if (!instance || !instance.thumbs) return;
373            
374            var thumbsSwiper = instance.thumbs;
375            var wrapperEl = thumbsSwiper.wrapperEl;
376            var containerEl = thumbsSwiper.el;
377            
378            // Calculate if content overflows
379            var wrapperHeight = wrapperEl.scrollHeight;
380            var containerHeight = containerEl.clientHeight;
381            
382            if (wrapperHeight > containerHeight) {
383                // Show navigation buttons
384                $prevThumbBtn.show();
385                $nextThumbBtn.show();
386                
387                // Update button states
388                updateThumbNavState(thumbsSwiper);
389            } else {
390                // Hide navigation buttons - not needed
391                $prevThumbBtn.hide();
392                $nextThumbBtn.hide();
393            }
394        }
395        
396        // Update button enabled/disabled state based on scroll position
397        function updateThumbNavState(thumbsSwiper) {
398            var translate = thumbsSwiper.translate;
399            var maxTranslate = thumbsSwiper.maxTranslate();
400            var minTranslate = thumbsSwiper.minTranslate();
401            
402            // At the top (translate = 0 or close to it)
403            if (translate >= minTranslate - 5) {
404                $prevThumbBtn.addClass('disabled');
405            } else {
406                $prevThumbBtn.removeClass('disabled');
407            }
408            
409            // At the bottom
410            if (translate <= maxTranslate + 5) {
411                $nextThumbBtn.addClass('disabled');
412            } else {
413                $nextThumbBtn.removeClass('disabled');
414            }
415        }
416        
417        // Initialize after a short delay to ensure Swiper is ready
418        setTimeout(function() {
419            checkThumbNavigation();
420            
421            var instance = galleryInstances[galleryId];
422            if (instance && instance.thumbs) {
423                // Listen for scroll/translate changes
424                instance.thumbs.on('setTranslate', function() {
425                    updateThumbNavState(this);
426                });
427                instance.thumbs.on('touchEnd', function() {
428                    updateThumbNavState(this);
429                });
430            }
431        }, 500);
432        
433        // Click handlers
434        $prevThumbBtn.on('click', function() {
435            if ($(this).hasClass('disabled')) return;
436            var instance = galleryInstances[galleryId];
437            if (instance && instance.thumbs) {
438                // Scroll up by ~3 thumbnails
439                var currentTranslate = instance.thumbs.translate;
440                var minTranslate = instance.thumbs.minTranslate();
441                var newTranslate = Math.min(currentTranslate + thumbScrollAmount, minTranslate);
442                instance.thumbs.translateTo(newTranslate, 300);
443                setTimeout(function() {
444                    updateThumbNavState(instance.thumbs);
445                }, 350);
446            }
447        });
448        
449        $nextThumbBtn.on('click', function() {
450            if ($(this).hasClass('disabled')) return;
451            var instance = galleryInstances[galleryId];
452            if (instance && instance.thumbs) {
453                // Scroll down by ~3 thumbnails
454                var currentTranslate = instance.thumbs.translate;
455                var maxTranslate = instance.thumbs.maxTranslate();
456                var newTranslate = Math.max(currentTranslate - thumbScrollAmount, maxTranslate);
457                instance.thumbs.translateTo(newTranslate, 300);
458                setTimeout(function() {
459                    updateThumbNavState(instance.thumbs);
460                }, 350);
461            }
462        });
463    }
464
465    /**
466     * Pause all videos in gallery
467     * 
468     * @param {jQuery} $gallery Gallery container
469     */
470    function pauseAllVideos($gallery) {
471        $gallery.find('video').each(function() {
472            this.pause();
473        });
474        $gallery.find('.video-play-overlay').show();
475    }
476
477    // Initialize on DOM ready
478    $(document).ready(function() {
479        initLocationGalleries();
480    });
481
482    // Expose for external access
483    window.velocityLocationGallery = {
484        instances: galleryInstances,
485        init: initLocationGalleries
486    };
487
488})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.