PageSourceSearch

https://myquantum.in/wp-content/plugins/ml-slider-lightbox/assets/js/ml-lightgallery-init.js?ver=2.0.0

js myquantum.in collected 2026-09-24 15:03:02 UTC 62,834 bytes, 1,409 lines download raw bytes

1/**
2 * MetaSlider Lightbox - LightGallery.js Integration
3 *
4 * Initializes LightGallery.js for MetaSlider when built-in lightbox is enabled
5 * Optimized for smooth fade transitions with consistent settings
6 */
7(function ($) {
8    'use strict';
9
10    var isInitializing = false;
11
12    // Initialize when document is ready
13    $(document).ready(function () {
14        // Clean up duplicate auto-lightbox links in MetaSlider slides
15        cleanupDuplicateLightboxLinks();
16        initLightbox();
17    });
18
19    // Also initialize on AJAX complete for dynamic content
20    $(document).ajaxComplete(function () {
21        // Add a small delay to prevent multiple rapid calls
22        setTimeout(function () {
23            cleanupDuplicateLightboxLinks();
24            initLightbox();
25        }, 50);
26    });
27
28    /**
29     * Clean up duplicate auto-lightbox links in MetaSlider slides
30     * This removes ml-auto-lightbox links that are inside MetaSlider slides
31     * since MetaSlider provides its own lightbox buttons
32     */
33    function cleanupDuplicateLightboxLinks() {
34        // Find all MetaSlider slides that contain auto-lightbox links
35        $('.ms-custom-html, .ms-external, .ms-folder, .ms-vimeo, .ms-youtube, .ms-local-video, .ms-external-video, .ms-postfeed, .ms-layer').each(function() {
36            var $slide = $(this);
37            
38            // Remove any ml-auto-lightbox links inside this slide
39            $slide.find('a.ml-auto-lightbox').each(function() {
40                var $autoLink = $(this);
41                var $img = $autoLink.find('img');
42                
43                // If there's an image inside the auto-lightbox link, unwrap it
44                if ($img.length > 0) {
45                    $autoLink.replaceWith($img);
46                } else {
47                    // If no image, just remove the link wrapper
48                    $autoLink.replaceWith($autoLink.contents());
49                }
50            });
51        });
52        
53        // Also check for any slides with both ml-auto-lightbox and ml-lightbox-button
54        $('.ml-lightbox-slide').each(function() {
55            var $slide = $(this);
56            
57            // If this slide has a lightbox button, remove any auto-lightbox links
58            if ($slide.find('.ml-lightbox-button').length > 0) {
59                $slide.find('a.ml-auto-lightbox').each(function() {
60                    var $autoLink = $(this);
61                    var $img = $autoLink.find('img');
62                    
63                    if ($img.length > 0) {
64                        $autoLink.replaceWith($img);
65                    } else {
66                        $autoLink.replaceWith($autoLink.contents());
67                    }
68                });
69            }
70        });
71    }
72
73    /**
74     * Get placeholder thumbnail image (SVG data URL)
75     */
76    function getPlaceholderThumb()
77    {
78        // Create a simple SVG placeholder with a camera icon
79        var svgContent = '<svg xmlns="http://www.w3.org/2000/svg" width="100" height="80" viewBox="0 0 100 80" fill="none">' +
80            '<rect width="100" height="80" fill="#f0f0f0" stroke="#ddd" stroke-width="1"/>' +
81            '<path d="M30 25h40c2 0 4 2 4 4v22c0 2-2 4-4 4H30c-2 0-4-2-4-4V29c0-2 2-4 4-4z" fill="#ccc"/>' +
82            '<circle cx="50" cy="40" r="8" fill="#999"/>' +
83            '<circle cx="50" cy="40" r="5" fill="#666"/>' +
84            '<rect x="65" y="30" width="4" height="3" rx="1" fill="#999"/>' +
85            '<text x="50" y="65" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#999">No Image</text>' +
86            '</svg>';
87
88        return 'data:image/svg+xml;base64,' + btoa(svgContent);
89    }
90
91    /**
92     * Get common LightGallery 2.x settings
93     */
94    function getCommonLightboxSettings()
95    {
96        return {
97            speed: 350,
98            mode: 'lg-fade',
99            easing: 'ease-in-out',
100            hideBarsDelay: 2000,
101            showBarsAfter: 100,
102            backdropDuration: 300,
103            loadYouTubeThumbnail: true,
104            loadVimeoThumbnail: true,
105            zoom: false,
106            scale: 1,
107            zoomFromOrigin: false,
108            dynamic: false,
109            swipeThreshold: 50,
110            enableSwipe: true,
111            enableDrag: true,
112            preload: 2,
113            allowMediaOverlap: true,
114            animateThumb: true,
115            toggleThumb: true,
116            hideScrollbar: true,
117            loop: true,
118            escKey: true,
119            controls: true,
120            download: false,
121            counter: true,
122            mobileSettings: {
123                controls: true,
124                showCloseIcon: true,
125                download: false
126            }
127        };
128    }
129
130    /**
131     * Initialize lightbox functionality
132     */
133    function initLightbox()
134    {
135        // Prevent multiple simultaneous initializations
136        if (isInitializing) {
137            return;
138        }
139        isInitializing = true;
140
141        // Check settings
142        var detectGalleries = false;
143        var detectStandaloneImages = false;
144        var detectVideos = false;
145
146        if (typeof mlLightboxSettings !== 'undefined') {
147            detectGalleries = mlLightboxSettings.detect_all_galleries === true || mlLightboxSettings.detect_all_galleries === '1';
148            detectStandaloneImages = mlLightboxSettings.detect_all_images === true || mlLightboxSettings.detect_all_images === '1';
149            detectVideos = mlLightboxSettings.detect_all_videos === true || mlLightboxSettings.detect_all_videos === '1';
150        }
151
152        // Initialize MetaSlider lightbox
153        initMetaSliderLightbox();
154
155        // Initialize galleries
156        if (detectGalleries) {
157            initWordPressGalleries();
158        }
159
160        // Initialize standalone images
161        if (detectStandaloneImages) {
162            initStandaloneImageLightbox();
163        }
164
165        // Initialize videos
166        if (detectVideos) {
167            initAllVideos();
168        }
169
170        // Reset initialization flag
171        isInitializing = false;
172    }
173
174    /**
175     * Initialize WordPress galleries
176     */
177    function initWordPressGalleries()
178    {
179        $('.gallery, .wp-block-gallery, .tiled-gallery').each(function () {
180            var $gallery = $(this);
181
182            // Skip if already initialized
183            if ($gallery.hasClass('lg-initialized')) {
184                return;
185            }
186
187            // Check if this gallery is inside a MetaSlider container
188            var $metaSliderContainer = $gallery.closest('.metaslider, [class*="ml-slider-lightbox-"]');
189            if ($metaSliderContainer.length > 0) {
190                // Get MetaSlider ID and check if lightbox is disabled
191                var sliderId = $metaSliderContainer.attr('id');
192                if (sliderId) {
193                    var matches = sliderId.match(/(\d+)/);
194                    if (matches) {
195                        sliderId = matches[1];
196                        if (typeof mlLightboxSettings !== 'undefined' && mlLightboxSettings.slider_settings && sliderId) {
197                            var sliderSettings = mlLightboxSettings.slider_settings[sliderId];
198                            if (!sliderSettings || !sliderSettings.lightbox_enabled) {
199                                return; // Skip if MetaSlider lightbox is disabled
200                            }
201                        }
202                    }
203                }
204            }
205
206            // Only initialize galleries that have been processed by PHP (have lightbox attributes)
207            var $lightboxLinks = $gallery.find('a.ml-auto-lightbox, a[data-src]');
208
209            if ($lightboxLinks.length > 0 && typeof lightGallery !== 'undefined') {
210                try {
211                    // Initialize LightGallery on the gallery container
212                    var gallerySettings = getCommonLightboxSettings();
213                    gallerySettings.selector = 'a.ml-auto-lightbox, a[data-src]';
214                    gallerySettings.controls = true;
215                    gallerySettings.counter = true;
216                    gallerySettings.closable = true;
217                    gallerySettings.closeOnTap = true;
218                    gallerySettings.hideBarsDelay = 2000;
219
220                    lightGallery($gallery[0], gallerySettings);
221
222
223                    $gallery.addClass('lg-initialized');
224                    $lightboxLinks.addClass('lg-initialized');
225                } catch (error) {
226                    console.error('MetaSlider Lightbox: Error initializing gallery', error);
227                }
228            }
229        });
230    }
231
232    /**
233     * Initialize standalone images (not in galleries or sliders)
234     */
235    function initStandaloneImageLightbox()
236    {
237        // Find standalone images that aren't inside galleries or sliders and have been processed by PHP
238        var $standaloneLinks = $('a.ml-auto-lightbox, a[data-src]').filter(function () {
239            var $link = $(this);
240            var href = $link.attr('href');
241
242            // Must be an image
243            if (!href || !isImageUrl(href)) {
244                return false;
245            }
246
247            // Check if inside a MetaSlider container (exclude ALL MetaSlider content)
248            var $metaSliderContainer = $link.closest('.metaslider, [class*="ml-slider-lightbox-"], [id*="metaslider_"], .ms-external, .ms-folder, .ms-vimeo, .ms-youtube, .ms-local-video, .ms-external-video, .ms-custom-html, .ms-postfeed, .ms-layer, .youtube, .vimeo, .local-video, .external-video');
249            if ($metaSliderContainer.length > 0) {
250                return false; // Always skip MetaSlider content - it has its own button handling
251            }
252
253            // Must not be inside a gallery/slider (excluding MetaSlider which we handled above)
254            return $link.closest('.gallery, .wp-block-gallery, .tiled-gallery').length === 0;
255        });
256
257        if ($standaloneLinks.length > 0 && typeof lightGallery !== 'undefined') {
258            $standaloneLinks.each(function () {
259                var $link = $(this);
260
261                // Skip if already initialized
262                if ($link.hasClass('lg-initialized')) {
263                    return;
264                }
265
266                try {
267                    // Wrap in container and initialize
268                    var $wrapper = $('<div class="ml-standalone-wrapper"></div>');
269                    $link.wrap($wrapper);
270
271                    var standaloneSettings = getCommonLightboxSettings();
272                    standaloneSettings.selector = 'a';
273                    standaloneSettings.loop = false;
274                    standaloneSettings.controls = false;
275                    standaloneSettings.counter = false;
276
277                    lightGallery($link.parent()[0], standaloneSettings);
278
279                    // Apply theme class if settings are available
280                    if (typeof mlLightboxSettings !== 'undefined' && mlLightboxSettings.theme) {
281                        $link.parent().on('lgAfterOpen', function () {
282                            var $lgOuter = $('.lg-outer');
283                            if ($lgOuter.length && mlLightboxSettings.theme !== 'default') {
284                                $lgOuter.addClass('lg-' + mlLightboxSettings.theme + '-theme');
285                            }
286                        });
287                    }
288
289                    $link.addClass('lg-initialized');
290                } catch (error) {
291                    console.error('MetaSlider Lightbox: Error initializing standalone image', error);
292                }
293            });
294        }
295    }
296
297    /**
298     * Detect Radix theme flex-pauseplay content type and add CSS class
299     */
300    function detectRadixPausePlayContent() {
301        $('.metaslider.ms-theme-radix').each(function() {
302            var $slider = $(this);
303            var $flexPausePlay = $slider.find('.flex-pauseplay');
304            
305            if ($flexPausePlay.length > 0) {
306                // Check the width of the flex-pauseplay a elements
307                var $pausePlayLinks = $flexPausePlay.find('a');
308                var isIconOnly = false;
309                
310                if ($pausePlayLinks.length > 0) {
311                    // Check if any of the links has a width of 30px (icon-only mode)
312                    $pausePlayLinks.each(function() {
313                        var width = $(this).outerWidth();
314                        if (width === 30) {
315                            isIconOnly = true;
316                            return false; // break out of each loop
317                        }
318                    });
319                }
320                
321                if (isIconOnly) {
322                    $slider.addClass('ml-radix-icon-only');
323                } else {
324                    $slider.addClass('ml-radix-with-text');
325                }
326            }
327        });
328    }
329
330    /**
331     * Initialize LightGallery for MetaSlider instances
332     */
333    function initMetaSliderLightbox()
334    {
335        // Detect Radix theme content type first
336        detectRadixPausePlayContent();
337
338        // Find all MetaSlider containers
339        $('.metaslider, [class*="ml-slider-lightbox-"]').each(function () {
340            var $slider = $(this);
341
342            // Skip if already initialized
343            if ($slider.hasClass('lg-initialized')) {
344                return;
345            }
346
347            // Get slider ID from various possible attributes
348            var sliderId = $slider.attr('id');
349            if (sliderId) {
350                // Extract numeric ID from string like "metaslider_123"
351                var matches = sliderId.match(/(\d+)/);
352                if (matches) {
353                    sliderId = matches[1];
354                }
355            }
356
357            // Check if lightbox is enabled for this specific slider
358            if (typeof mlLightboxSettings !== 'undefined' && mlLightboxSettings.slider_settings && sliderId) {
359                var sliderSettings = mlLightboxSettings.slider_settings[sliderId];
360                if (!sliderSettings || !sliderSettings.lightbox_enabled) {
361                    return; // Skip if lightbox is disabled for this slider
362                }
363            }
364
365            // Initialize empty collection - we'll only use our button approach
366            var $lightboxLinks = $();
367
368            // Handle external images using ms-external class (exclude clones)
369            var $externalImageSlides = $slider.find('.ms-external').not('.clone');
370            if ($externalImageSlides.length > 0) {
371                $externalImageSlides.each(function () {
372                    var $slide = $(this);
373                    var $img = $slide.find('img').first();
374
375                    if ($img.length > 0) {
376                        var imgSrc = $img.attr('src');
377
378                        // Get MetaSlider lightbox settings
379                        var showArrows = true;
380                        var showThumbnails = false;
381
382                        if (typeof mlLightboxSettings !== 'undefined' && mlLightboxSettings.metaslider_options) {
383                            showArrows = mlLightboxSettings.metaslider_options.show_arrows !== false;
384                            showThumbnails = mlLightboxSettings.metaslider_options.show_thumbnails === true;
385                        }
386
387                        // Get actual image dimensions for smooth loading
388                        var actualWidth = $img.get(0).naturalWidth || $img.width() || $img.attr('width') || $img.data('width') || 1280;
389                        var actualHeight = $img.get(0).naturalHeight || $img.height() || $img.attr('height') || $img.data('height') || 720;
390
391                        // Add caption from img alt or title
392                        var caption = $img.attr('alt') || $img.attr('title') || '';
393
394                        // Create lightbox button using helper function
395                        var $lightboxBtn = createLightboxButton(imgSrc, imgSrc, 'Open in Lightbox', {
396                            showArrows: showArrows,
397                            showThumbnails: showThumbnails,
398                            slideType: 'external',
399                            caption: caption ? '<p>' + escapeHtml(caption) + '</p>' : null,
400                            lgSize: actualWidth + '-' + actualHeight,
401                            dataThumb: imgSrc  // Add data-thumb for LightGallery 2.x
402                        });
403
404                        // Insert button into slide
405                        $slide.addClass('ml-lightbox-slide').append($lightboxBtn);
406
407                        // Add to lightbox links
408                        $lightboxLinks = $lightboxLinks.add($lightboxBtn);
409                    }
410                });
411            }
412
413            // Handle Vimeo video slides using ms-vimeo class (exclude clones)
414            var $vimeoSlides = $slider.find('.ms-vimeo').not('.clone');
415
416            if ($vimeoSlides.length > 0) {
417                $vimeoSlides.each(function () {
418                    var $slide = $(this);
419                    var $vimeoDiv = $slide.find('div.vimeo[data-url*="vimeo.com"]');
420
421                    if ($vimeoDiv.length > 0) {
422                        var dataUrl = $vimeoDiv.attr('data-url');
423                        var vimeoId = $vimeoDiv.attr('data-id');
424
425                        if (!vimeoId) {
426                            return;
427                        }
428
429                        // Get MetaSlider lightbox settings
430                        var showArrows = true;
431                        var showThumbnails = false;
432
433                        if (typeof mlLightboxSettings !== 'undefined' && mlLightboxSettings.metaslider_options) {
434                            showArrows = mlLightboxSettings.metaslider_options.show_arrows !== false;
435                            showThumbnails = mlLightboxSettings.metaslider_options.show_thumbnails === true;
436                        }
437
438                        // For Vimeo, use the slide's existing image as fallback poster
439                        var $slideImg = $slide.find('img').first();
440                        var vimeoPoster = null;
441                        if ($slideImg.length > 0) {
442                            vimeoPoster = $slideImg.attr('src');
443                        }
444
445                        // Create lightbox button using helper function
446                        // Note: Vimeo thumbnails plugin will automatically load thumbnails for Vimeo URLs
447                        var $lightboxBtn = createLightboxButton('//vimeo.com/' + vimeoId, '//vimeo.com/' + vimeoId, 'Open in Lightbox', {
448                            showArrows: showArrows,
449                            showThumbnails: showThumbnails,
450                            slideType: 'vimeo',
451                            lgSize: '1280-720',
452                            dataVideo: 'true',
453                            poster: vimeoPoster,
454                            // Don't set dataThumb - let Vimeo thumbnails plugin handle it automatically
455                        });
456
457                        // Insert button into slide
458                        $slide.addClass('ml-lightbox-slide').append($lightboxBtn);
459
460                        // Add to lightbox links
461                        $lightboxLinks = $lightboxLinks.add($lightboxBtn);
462                    }
463                });
464            }
465
466            // Handle YouTube video slides using ms-youtube class (exclude clones)
467            var $youtubeSlides = $slider.find('.ms-youtube').not('.clone');
468
469            if ($youtubeSlides.length > 0) {
470                $youtubeSlides.each(function () {
471                    var $slide = $(this);
472                    var $youtubeDiv = $slide.find('div.youtube');
473
474                    if ($youtubeDiv.length > 0) {
475                        // Try to get video ID from data-id attribute first
476                        var youtubeId = $youtubeDiv.attr('data-id');
477
478                        // If no data-id, try to extract from data-url
479                        if (!youtubeId) {
480                            var dataUrl = $youtubeDiv.attr('data-url');
481                            if (dataUrl) {
482                                youtubeId = extractYouTubeId(dataUrl);
483                            }
484                        }
485
486                        if (!youtubeId) {
487                            return;
488                        }
489
490                        // Get MetaSlider lightbox settings
491                        var showArrows = true;
492                        var showThumbnails = false;
493
494                        if (typeof mlLightboxSettings !== 'undefined' && mlLightboxSettings.metaslider_options) {
495                            showArrows = mlLightboxSettings.metaslider_options.show_arrows !== false;
496                            showThumbnails = mlLightboxSettings.metaslider_options.show_thumbnails === true;
497                        }
498
499                        // Add YouTube thumbnail poster image
500                        var youtubePoster = 'https://img.youtube.com/vi/' + youtubeId + '/maxresdefault.jpg';
501
502                        // Create lightbox button using helper function
503                        var $lightboxBtn = createLightboxButton('//www.youtube.com/watch?v=' + youtubeId, '//www.youtube.com/watch?v=' + youtubeId, 'Open in Lightbox', {
504                            showArrows: showArrows,
505                            showThumbnails: showThumbnails,
506                            slideType: 'youtube',
507                            lgSize: '1280-720',
508                            dataVideo: 'true',
509                            poster: youtubePoster,
510                            dataThumb: youtubePoster  // Add data-thumb for LightGallery 2.x
511                        });
512
513                        // Insert button into slide
514                        $slide.addClass('ml-lightbox-slide').append($lightboxBtn);
515
516                        // Add to lightbox links
517                        $lightboxLinks = $lightboxLinks.add($lightboxBtn);
518                    }
519                });
520            }
521
522            // Handle Local Video slides using ms-local-video class (exclude clones)
523            var $localVideoSlides = $slider.find('.ms-local-video').not('.clone');
524
525            if ($localVideoSlides.length > 0) {
526                $localVideoSlides.each(function () {
527                    var $slide = $(this);
528                    var $videoDiv = $slide.find('div.local-video');
529
530                    if ($videoDiv.length > 0) {
531                        // Get video sources from data-sources attribute
532                        var dataSources = $videoDiv.attr('data-sources');
533                        var videoSources = [];
534                        var videoUrl = null;
535
536                        if (dataSources) {
537                            try {
538                                var sources = JSON.parse(dataSources);
539                                if (sources && sources.length > 0) {
540                                    // Use the first source as the primary video URL
541                                    videoUrl = sources[0].src;
542
543                                    // Prepare all sources for LightGallery
544                                    videoSources = sources.map(function (source) {
545                                        return {
546                                            'src': source.src,
547                                            'type': source.type || getVideoType(source.src)
548                                        };
549                                    });
550                                }
551                            } catch (e) {
552                                console.error('MetaSlider Lightbox: Error parsing local video sources', e);
553                            }
554                        }
555
556                        if (!videoUrl || videoSources.length === 0) {
557                            return;
558                        }
559
560                        // Get MetaSlider lightbox settings
561                        var showArrows = true;
562                        var showThumbnails = false;
563
564                        if (typeof mlLightboxSettings !== 'undefined' && mlLightboxSettings.metaslider_options) {
565                            showArrows = mlLightboxSettings.metaslider_options.show_arrows !== false;
566                            showThumbnails = mlLightboxSettings.metaslider_options.show_thumbnails === true;
567                        }
568
569                        // Get poster image if available
570                        var posterUrl = $videoDiv.attr('data-poster');
571
572                        // Create data-video JSON attribute with Video.js configuration
573                        var videoData = {
574                            'source': videoSources,
575                            'attributes': {
576                                'preload': false,
577                                'controls': true
578                            },
579                            'videojs': true,
580                            'videojsOptions': {
581                                'fluid': true,
582                                'responsive': true,
583                                'playsinline': true,
584                                'preload': 'none'
585                            }
586                        };
587
588                        // Don't add poster to Video.js to avoid overlay issues
589
590                        // Create lightbox button (special handling for local video)
591                        var $lightboxBtn = $('<a class="ml-lightbox-button" data-lg-size="1280-720">Open in Lightbox</a>');
592                        $lightboxBtn.attr('data-lightbox-arrows', showArrows ? 'true' : 'false');
593                        $lightboxBtn.attr('data-lightbox-thumbnails', showThumbnails ? 'true' : 'false');
594                        $lightboxBtn.attr('data-slide-type', 'local-video');
595                        $lightboxBtn.attr('data-video', JSON.stringify(videoData));
596                        if (posterUrl) {
597                            $lightboxBtn.attr('data-poster', posterUrl);
598                            $lightboxBtn.attr('data-thumb', posterUrl);  // Add data-thumb for thumbnails
599                        } else {
600                            $lightboxBtn.attr('data-thumb', getPlaceholderThumb());  // Use placeholder if no poster
601                        }
602
603                        // Insert button into slide
604                        $slide.addClass('ml-lightbox-slide').append($lightboxBtn);
605
606                        // Add to lightbox links
607                        $lightboxLinks = $lightboxLinks.add($lightboxBtn);
608                    }
609                });
610            }
611
612            // Handle External Video slides using ms-external-video class (exclude clones)
613            var $externalVideoSlides = $slider.find('.ms-external-video').not('.clone');
614
615            if ($externalVideoSlides.length > 0) {
616                $externalVideoSlides.each(function () {
617                    var $slide = $(this);
618                    var $videoDiv = $slide.find('div.external-video');
619
620                    if ($videoDiv.length > 0) {
621                        // Get video sources from data-sources attribute
622                        var dataSources = $videoDiv.attr('data-sources');
623                        var videoSources = [];
624                        var videoUrl = null;
625
626                        if (dataSources) {
627                            try {
628                                var sources = JSON.parse(dataSources);
629                                if (sources && sources.length > 0) {
630                                    // Use the first source as the primary video URL
631                                    videoUrl = sources[0].src;
632
633                                    // Prepare all sources for LightGallery
634                                    videoSources = sources.map(function (source) {
635                                        return {
636                                            'src': source.src,
637                                            'type': source.type || getVideoType(source.src)
638                                        };
639                                    });
640                                }
641                            } catch (e) {
642                                console.error('MetaSlider Lightbox: Error parsing video sources', e);
643                            }
644                        }
645
646                        if (!videoUrl || videoSources.length === 0) {
647                            return;
648                        }
649
650                        // Get MetaSlider lightbox settings
651                        var showArrows = true;
652                        var showThumbnails = false;
653
654                        if (typeof mlLightboxSettings !== 'undefined' && mlLightboxSettings.metaslider_options) {
655                            showArrows = mlLightboxSettings.metaslider_options.show_arrows !== false;
656                            showThumbnails = mlLightboxSettings.metaslider_options.show_thumbnails === true;
657                        }
658
659                        // Get poster image if available
660                        var posterUrl = $videoDiv.attr('data-poster');
661
662                        // Create data-video JSON attribute with Video.js configuration
663                        var videoData = {
664                            'source': videoSources,
665                            'attributes': {
666                                'preload': false,
667                                'controls': true
668                            },
669                            'videojs': true,
670                            'videojsOptions': {
671                                'fluid': true,
672                                'responsive': true,
673                                'playsinline': true,
674                                'preload': 'none'
675                            }
676                        };
677
678                        // Don't add poster to Video.js to avoid overlay issues
679
680                        // Create lightbox button using helper function
681                        // For videos with data-video attribute, don't set href/data-src to avoid conflicts
682                        var $lightboxBtn = createLightboxButton('', '', 'Open in Lightbox', {
683                            showArrows: showArrows,
684                            showThumbnails: showThumbnails,
685                            slideType: 'external-video',
686                            lgSize: '1280-720',
687                            dataVideo: JSON.stringify(videoData),
688                            dataPoster: posterUrl,
689                            dataThumb: posterUrl || getPlaceholderThumb()
690                        });
691
692                        // Insert button into slide
693                        $slide.addClass('ml-lightbox-slide').append($lightboxBtn);
694
695                        // Add to lightbox links
696                        $lightboxLinks = $lightboxLinks.add($lightboxBtn);
697                    }
698                });
699            }
700
701            // Handle Custom HTML slides using ms-custom-html class (exclude clones)
702            var $customHtmlSlides = $slider.find('.ms-custom-html').not('.clone');
703
704            if ($customHtmlSlides.length > 0) {
705                $customHtmlSlides.each(function () {
706                    var $slide = $(this);
707
708                    // Get MetaSlider lightbox settings
709                    var showArrows = true;
710                    var showThumbnails = false;
711
712                    if (typeof mlLightboxSettings !== 'undefined' && mlLightboxSettings.metaslider_options) {
713                        showArrows = mlLightboxSettings.metaslider_options.show_arrows !== false;
714                        showThumbnails = mlLightboxSettings.metaslider_options.show_thumbnails === true;
715                    }
716
717                    // Get the current slide content for the lightbox
718                    var slideContent = $slide.html();
719
720                    // Create lightbox button with placeholder image using helper function
721                    var placeholderSrc = getPlaceholderThumb();
722                    var $lightboxBtn = createLightboxButton(placeholderSrc, placeholderSrc, 'Open in Lightbox', {
723                        showArrows: showArrows,
724                        showThumbnails: showThumbnails,
725                        slideType: 'custom-html',
726                        caption: slideContent,
727                        lgSize: '1280-720',
728                        dataThumb: placeholderSrc
729                    });
730
731                    // Insert button into slide
732                    $slide.addClass('ml-lightbox-slide').append($lightboxBtn);
733
734                    // Add to lightbox links
735                    $lightboxLinks = $lightboxLinks.add($lightboxBtn);
736                });
737            }
738
739            // Handle Image Folder slides using ms-folder class (exclude clones)
740            var $folderSlides = $slider.find('.ms-folder').not('.clone');
741
742            if ($folderSlides.length > 0) {
743                $folderSlides.each(function () {
744                    var $slide = $(this);
745
746                    // Get MetaSlider lightbox settings
747                    var showArrows = true;
748                    var showThumbnails = false;
749
750                    if (typeof mlLightboxSettings !== 'undefined' && mlLightboxSettings.metaslider_options) {
751                        showArrows = mlLightboxSettings.metaslider_options.show_arrows !== false;
752                        showThumbnails = mlLightboxSettings.metaslider_options.show_thumbnails === true;
753                    }
754
755                    // Find all images in the folder slide
756                    var $images = $slide.find('img');
757
758                    if ($images.length > 0) {
759                        // Use the first image as representative for the folder
760                        var $firstImg = $images.first();
761                        var imgSrc = $firstImg.attr('src');
762                        var imgAlt = $firstImg.attr('alt') || '';
763
764                        // Get actual image dimensions for smooth loading
765                        var actualWidth = $firstImg.get(0).naturalWidth || $firstImg.width() || $firstImg.attr('width') || $firstImg.data('width') || 1280;
766                        var actualHeight = $firstImg.get(0).naturalHeight || $firstImg.height() || $firstImg.attr('height') || $firstImg.data('height') || 720;
767
768                        // Create lightbox button using helper function
769                        var $lightboxBtn = createLightboxButton(imgSrc, imgSrc, 'Open in Lightbox', {
770                            showArrows: showArrows,
771                            showThumbnails: showThumbnails,
772                            slideType: 'image-folder',
773                            caption: imgAlt ? '<p>' + escapeHtml(imgAlt) + '</p>' : null,
774                            lgSize: actualWidth + '-' + actualHeight,
775                            dataThumb: imgSrc  // Add data-thumb for LightGallery 2.x
776                        });
777
778                        // Insert button into slide
779                        $slide.addClass('ml-lightbox-slide').append($lightboxBtn);
780
781                        // Add to lightbox links
782                        $lightboxLinks = $lightboxLinks.add($lightboxBtn);
783                    }
784                });
785            }
786
787            // Handle Post Feed slides using ms-postfeed class (exclude clones)
788            var $postFeedSlides = $slider.find('.ms-postfeed').not('.clone');
789
790            if ($postFeedSlides.length > 0) {
791                $postFeedSlides.each(function () {
792                    var $slide = $(this);
793
794                    // Get MetaSlider lightbox settings
795                    var showArrows = true;
796                    var showThumbnails = false;
797
798                    if (typeof mlLightboxSettings !== 'undefined' && mlLightboxSettings.metaslider_options) {
799                        showArrows = mlLightboxSettings.metaslider_options.show_arrows !== false;
800                        showThumbnails = mlLightboxSettings.metaslider_options.show_thumbnails === true;
801                    }
802
803                    // Find the main image in the post feed slide
804                    var $img = $slide.find('img').first();
805
806                    if ($img.length > 0) {
807                        var imgSrc = $img.attr('src');
808
809                        // Extract caption information from the post feed slide
810                        var caption = '';
811                        var $captionWrap = $slide.find('.caption-wrap .caption');
812
813                        if ($captionWrap.length > 0) {
814                            // Use the existing caption content
815                            caption = $captionWrap.html();
816                        } else {
817                            // Fallback to image alt text
818                            var imgAlt = $img.attr('alt') || '';
819                            if (imgAlt) {
820                                caption = '<p>' + escapeHtml(imgAlt) + '</p>';
821                            }
822                        }
823
824                        // Get actual image dimensions for smooth loading
825                        var actualWidth = $img.get(0).naturalWidth || $img.width() || $img.attr('width') || $img.data('width') || 1280;
826                        var actualHeight = $img.get(0).naturalHeight || $img.height() || $img.attr('height') || $img.data('height') || 720;
827
828                        // Create lightbox button using helper function
829                        var $lightboxBtn = createLightboxButton(imgSrc, imgSrc, 'Open in Lightbox', {
830                            showArrows: showArrows,
831                            showThumbnails: showThumbnails,
832                            slideType: 'post-feed',
833                            caption: caption,
834                            lgSize: actualWidth + '-' + actualHeight,
835                            dataThumb: imgSrc  // Add data-thumb for LightGallery 2.x
836                        });
837
838                        // Insert button into slide
839                        $slide.addClass('ml-lightbox-slide').append($lightboxBtn);
840
841                        // Add to lightbox links
842                        $lightboxLinks = $lightboxLinks.add($lightboxBtn);
843                    }
844                });
845            }
846
847            // Handle Layer slides using ms-layer class (exclude clones)
848            var $layerSlides = $slider.find('.ms-layer').not('.clone');
849
850            if ($layerSlides.length > 0) {
851                $layerSlides.each(function () {
852                    var $slide = $(this);
853
854                    // Get MetaSlider lightbox settings
855                    var showArrows = true;
856                    var showThumbnails = false;
857
858                    if (typeof mlLightboxSettings !== 'undefined' && mlLightboxSettings.metaslider_options) {
859                        showArrows = mlLightboxSettings.metaslider_options.show_arrows !== false;
860                        showThumbnails = mlLightboxSettings.metaslider_options.show_thumbnails === true;
861                    }
862
863                    // Find the background image in the layer slide
864                    var $backgroundImg = $slide.find('img.msDefaultImage');
865
866                    if ($backgroundImg.length > 0) {
867                        var imgSrc = $backgroundImg.attr('src');
868                        var imgAlt = $backgroundImg.attr('alt') || '';
869
870                        // Get layer content from the overlay
871                        var layerContent = '';
872                        var $layerOverlay = $slide.find('.msHtmlOverlay');
873
874                        if ($layerOverlay.length > 0) {
875                            // Extract the text content from layers, preserving basic formatting
876                            var $layers = $layerOverlay.find('.layer .content');
877                            if ($layers.length > 0) {
878                                var layerTexts = [];
879                                $layers.each(function () {
880                                    var $layer = $(this);
881                                    var layerHtml = $layer.html();
882                                    if (layerHtml && layerHtml.trim() !== '') {
883                                        layerTexts.push('<div class="lightbox-layer-content">' + layerHtml + '</div>');
884                                    }
885                                });
886                                if (layerTexts.length > 0) {
887                                    layerContent = '<div class="lightbox-layer-wrapper">' + layerTexts.join('') + '</div>';
888                                }
889                            }
890                        }
891
892                        // Get actual image dimensions
893                        var actualWidth = $backgroundImg.get(0).naturalWi
893dth || $backgroundImg.width() || $backgroundImg.attr('width') || $backgroundImg.data('width') || 1280;
894                        var actualHeight = $backgroundImg.get(0).naturalHeight || $backgroundImg.height() || $backgroundImg.attr('height') || 720;
895
896                        // Combine image alt and layer content for caption
897                        var captionHtml = '';
898                        if (imgAlt) {
899                            captionHtml += '<p>' + escapeHtml(imgAlt) + '</p>';
900                        }
901                        if (layerContent) {
902                            captionHtml += layerContent;
903                        }
904
905                        // Create lightbox button using helper function
906                        var $lightboxBtn = createLightboxButton(imgSrc, imgSrc, 'Open in Lightbox', {
907                            showArrows: showArrows,
908                            showThumbnails: showThumbnails,
909                            slideType: 'layer',
910                            caption: captionHtml || null,
911                            lgSize: actualWidth + '-' + actualHeight,
912                            dataThumb: imgSrc  // Add data-thumb for LightGallery 2.x
913                        });
914
915                        // Insert button into slide
916                        $slide.addClass('ml-lightbox-slide').append($lightboxBtn);
917
918                        // Add to lightbox links
919                        $lightboxLinks = $lightboxLinks.add($lightboxBtn);
920                    }
921                });
922            }
923
924            // Handle regular MetaSlider image slides (ms-image or regular slides)
925            var $regularImageSlides = $slider.find('li').not('.clone').filter(function () {
926                var $slide = $(this);
927                // Skip if this slide is already handled by other slide types
928                return !$slide.hasClass('ms-external') &&
929                       !$slide.hasClass('ms-vimeo') &&
930                       !$slide.hasClass('ms-youtube') &&
931                       !$slide.hasClass('ms-external-video') &&
932                       !$slide.hasClass('ms-local-video') &&
933                       !$slide.hasClass('ms-custom-html') &&
934                       !$slide.hasClass('ms-folder') &&
935                       !$slide.hasClass('ms-postfeed') &&
936                       !$slide.hasClass('ms-layer');
937            });
938
939            if ($regularImageSlides.length > 0) {
940                $regularImageSlides.each(function () {
941                    var $slide = $(this);
942                    var $img = $slide.find('img').first();
943
944                    if ($img.length > 0) {
945                        var imgSrc = $img.attr('src');
946
947                        // Get MetaSlider lightbox settings
948                        var showArrows = true;
949                        var showThumbnails = false;
950
951                        if (typeof mlLightboxSettings !== 'undefined' && mlLightboxSettings.metaslider_options) {
952                            showArrows = mlLightboxSettings.metaslider_options.show_arrows !== false;
953                            showThumbnails = mlLightboxSettings.metaslider_options.show_thumbnails === true;
954                        }
955
956                        // Add caption from img alt or title
957                        var caption = $img.attr('alt') || $img.attr('title') || '';
958                        var captionHtml = caption ? '<p>' + escapeHtml(caption) + '</p>' : null;
959
960                        // Get actual image dimensions for smooth loading
961                        var actualWidth = $img.get(0).naturalWidth || $img.width() || $img.attr('width') || $img.data('width') || 1280;
962                        var actualHeight = $img.get(0).naturalHeight || $img.height() || $img.attr('height') || $img.data('height') || 720;
963
964                        // Create lightbox button using helper function
965                        var $lightboxBtn = createLightboxButton(imgSrc, imgSrc, 'Open in Lightbox', {
966                            showArrows: showArrows,
967                            showThumbnails: showThumbnails,
968                            slideType: 'image',
969                            caption: captionHtml,
970                            lgSize: actualWidth + '-' + actualHeight,
971                            dataThumb: imgSrc
972                        });
973
974                        // Insert button into slide
975                        $slide.addClass('ml-lightbox-slide').append($lightboxBtn);
976
977                        // Add to lightbox links
978                        $lightboxLinks = $lightboxLinks.add($lightboxBtn);
979                    }
980                });
981            }
982
983
984
985            // Only initialize if we have lightbox links
986            if ($lightboxLinks.length > 0) {
987                // Check if lightGallery is already initialized on this slider
988                if ($slider.data('lightgallery') || $slider.hasClass('lg-initialized')) {
989                    return;
990                }
991
992                // Check if lightGallery is available
993                if (typeof lightGallery === 'undefined') {
994                    console.error('MetaSlider Lightbox: lightGallery is not defined. Make sure the LightGallery library is loaded.');
995                    return;
996                }
997
998                try {
999                    var $firstSlide = $slider.find('a[data-src], a[data-video]').first();
1000                    var showArrows = true;
1001                    var showThumbnails = false;
1002
1003                    if ($firstSlide.length > 0) {
1004                        showArrows = $firstSlide.attr('data-lightbox-arrows') !== 'false';
1005                        showThumbnails = $firstSlide.attr('data-lightbox-thumbnails') === 'true';
1006                    } else {
1007                        if (typeof mlLightboxSettings !== 'undefined' && mlLightboxSettings.metaslider_options) {
1008                            showArrows = mlLightboxSettings.metaslider_options.show_arrows !== false;
1009                            showThumbnails = mlLightboxSettings.metaslider_options.show_thumbnails === true;
1010                        }
1011                    }
1012
1013                    var metaSliderSettings = getCommonLightboxSettings();
1014                    metaSliderSettings.selector = 'a[data-src]:not(.clone):not(.clone *), a[data-video]:not(.clone):not(.clone *)';
1015                    metaSliderSettings.hideBarsDelay = 6000;
1016                    metaSliderSettings.controls = showArrows;
1017                    metaSliderSettings.counter = true;
1018
1019                    // Set enterprise license key from PHP settings
1020                    if (typeof mlLightboxSettings !== 'undefined' && mlLightboxSettings.license_key) {
1021                        metaSliderSettings.licenseKey = mlLightboxSettings.license_key;
1022                    }
1023
1024                    metaSliderSettings.plugins = [];
1025                    if (typeof lgVideo !== 'undefined') {
1026                        metaSliderSettings.plugins.push(lgVideo);
1027                    }
1028                    // Check if Video.js is available and configure LightGallery to use it
1029                    if (typeof videojs !== 'undefined') {
1030                        metaSliderSettings.videojs = true;  // Enable Video.js in LightGallery
1031                        // Video.js library loaded - LightGallery configured to use Video.js
1032                    }
1033                    if (showThumbnails && typeof lgThumbnail !== 'undefined') {
1034                        metaSliderSettings.plugins.push(lgThumbnail);
1035                        metaSliderSettings.thumbnail = true;
1036                        metaSliderSettings.thumbWidth = 100;
1037                        metaSliderSettings.thumbHeight = "80px";
1038                        metaSliderSettings.thumbMargin = 5;
1039                        metaSliderSettings.exThumbImage = 'data-thumb';
1040                        metaSliderSettings.enableThumbDrag = true;
1041                        metaSliderSettings.enableThumbSwipe = true;
1042                        metaSliderSettings.toggleThumb = true;
1043                        metaSliderSettings.alignThumbnails = "middle";
1044                        metaSliderSettings.animateThumb = true;
1045
1046                        // Keep thumbnails on one line
1047                        metaSliderSettings.thumbContHeight = 80;  // Fixed height to prevent wrapping
1048                        metaSliderSettings.thumbHeight = "80px";  // Keep consistent height
1049
1050                        if (typeof lgVimeoThumbnail !== 'undefined') {
1051                            metaSliderSettings.plugins.push(lgVimeoThumbnail);
1052                            metaSliderSettings.loadVimeoThumbnail = true;
1053                        } else {
1054                            metaSliderSettings.loadVimeoThumbnail = false;
1055                        }
1056                        metaSliderSettings.loadYouTubeThumbnail = true;
1057                    } else {
1058                        metaSliderSettings.thumbnail = false;
1059                    }
1060                    metaSliderSettings.thumbImg = function (currentSlide, index) {
1061                        var slideElement;
1062                        var imgSrc;
1063                        if (typeof currentSlide === 'string') {
1064                            slideElement = document.querySelector(currentSlide);
1065                        } else if (currentSlide && currentSlide.slideElement) {
1066                            slideElement = currentSlide.slideElement;
1067                        } else if (currentSlide && currentSlide.el) {
1068                            slideElement = currentSlide.el;
1069                        } else if (currentSlide && currentSlide.tagName) {
1070                            slideElement = currentSlide;
1071                        } else {
1072                            return '';
1073                        }
1074
1075                        var $slide = $(slideElement);
1076
1077                        var poster = $slide.attr('data-poster');
1078                        var isVideo = $slide.attr('data-video') === 'true';
1079                        imgSrc = $slide.attr('data-src') || $slide.attr('href');
1080
1081
1082                        if (isVideo && poster) {
1083                            return poster;
1084                        } else if (imgSrc) {
1085                            return imgSrc;
1086                        } else {
1087                            return getPlaceholderThumb();
1088                        }
1089                    };
1090                    metaSliderSettings.prevHtml = '<span class="lg-icon lg-icon-prev" aria-label="Previous image"></span>';
1091                    metaSliderSettings.nextHtml = '<span class="lg-icon lg-icon-next" aria-label="Next image"></span>';
1092                    metaSliderSettings.aria = {
1093                        slideShow: 'MetaSlider image slideshow',
1094                        slide: 'Image {index} of {totalSlides}',
1095                        closeGallery: 'Close gallery'
1096                    };
1097
1098                    var lgInstance = lightGallery($slider[0], metaSliderSettings);
1099
1100                    $slider.addClass('lg-initialized');
1101
1102                    if (showThumbnails) {
1103                        $slider.on('lgAfterOpen', function () {
1104                            setTimeout(function () {
1105                                $lightboxLinks.each(function (index) {
1106                                    var $link = $(this);
1107                                    var $thumbnail = $('.lg-thumb-item').eq(index);
1108
1109                                    if ($link.attr('data-video') === 'true') {
1110                                        $thumbnail.attr('data-video', 'true');
1111                                        if ($link.attr('data-poster')) {
1112                                            $thumbnail.attr('data-poster', $link.attr('data-poster'));
1113                                        }
1114                                    }
1115                                });
1116                            }, 100);
1117                        });
1118                    }
1119
1120                    $slider.addClass('lg-initialized');
1121                    $slider.addClass('ml-lightgallery-active');
1122                } catch (error) {
1123                    console.error('MetaSlider Lightbox: Error initializing LightGallery', error);
1124                }
1125            }
1126        });
1127    }
1128
1129    /**
1130     * Check if URL is an image
1131     * @param {string} url
1132     * @returns {boolean}
1133     */
1134    function isImageUrl(url)
1135    {
1136        if (!url) {
1137            return false;
1138        }
1139        var imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'bmp', 'tiff'];
1140        var extension = url.split('.').pop().toLowerCase().split('?')[0].split('#')[0];
1141        return imageExtensions.indexOf(extension) !== -1;
1142    }
1143
1144    /**
1145     * Extract YouTube video ID from URL
1146     * @param {string} url
1147     * @returns {string|null}
1148     */
1149    function extractYouTubeId(url)
1150    {
1151        if (!url) {
1152            return null;
1153        }
1154
1155        // Match various YouTube URL formats
1156        var youtubeRegex = /^.*(youtu\.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;
1157        var match = url.match(youtubeRegex);
1158
1159        if (match && match[2] && match[2].length === 11) {
1160            return match[2];
1161        }
1162
1163        return null;
1164    }
1165
1166    /**
1167     * Get video MIME type from file extension
1168     * @param {string} url
1169     * @returns {string}
1170     */
1171    function getVideoType(url)
1172    {
1173        if (!url) {
1174            return 'video/mp4'; // Default fallback
1175        }
1176
1177        var extension = url.split('.').pop().toLowerCase().split('?')[0].split('#')[0];
1178
1179        switch (extension) {
1180            case 'mp4':
1181                return 'video/mp4';
1182            case 'webm':
1183                return 'video/webm';
1184            case 'ogg':
1185            case 'ogv':
1186                return 'video/ogg';
1187            case 'mov':
1188                return 'video/quicktime';
1189            case 'avi':
1190                return 'video/x-msvideo';
1191            case 'm4v':
1192                return 'video/mp4';
1193            default:
1194                return 'video/mp4'; // Default fallback
1195        }
1196    }
1197
1198    /**
1199     * Escape HTML to prevent XSS
1200     * @param {string} text
1201     * @returns {string}
1202     */
1203    function escapeHtml(text)
1204    {
1205        var map = {
1206            '&': '&amp;',
1207            '<': '&lt;',
1208            '>': '&gt;',
1209            '"': '&quot;',
1210            "'": '&#039;'
1211        };
1212        return text.replace(/[&<>"']/g, function (m) {
1213            return map[m]; });
1214    }
1215
1216    /**
1217     * Create a lightbox button with CSS classes
1218     * @param {string} href The image/video URL
1219     * @param {string} dataSrc The data-src attribute value
1220     * @param {string} buttonText The button text
1221     * @param {object} options Additional options like slideType, caption, etc.
1222     * @returns {jQuery} The button element
1223     */
1224    function createLightboxButton(href, dataSrc, buttonText, options)
1225    {
1226        options = options || {};
1227
1228        var $button = $('<a class="ml-lightbox-button" href="' + href + '" data-src="' + dataSrc + '">' + buttonText + '</a>');
1229        $button.attr({
1230            'role': 'button',
1231            'tabindex': '0',
1232            'aria-label': 'Open ' + (options.slideType || 'image') + ' in lightbox'
1233        });
1234
1235        // Add lightbox settings
1236        if (options.showArrows !== undefined) {
1237            $button.attr('data-lightbox-arrows', options.showArrows ? 'true' : 'false');
1238        }
1239        if (options.showThumbnails !== undefined) {
1240            $button.attr('data-lightbox-thumbnails', options.showThumbnails ? 'true' : 'false');
1241        }
1242        if (options.slideType) {
1243            $button.attr('data-slide-type', options.slideType);
1244        }
1245        if (options.caption) {
1246            $button.attr('data-sub-html', options.caption);
1247        }
1248        if (options.lgSize) {
1249            $button.attr('data-lg-size', options.lgSize);
1250        }
1251        if (options.dataVideo) {
1252            $button.attr('data-video', options.dataVideo);
1253        }
1254        if (options.poster) {
1255            $button.attr('data-poster', options.poster);
1256        }
1257        if (options.dataThumb) {
1258            $button.attr('data-thumb', options.dataThumb);
1259        } else if (options.showThumbnails !== false) {
1260            // Use placeholder thumbnail if thumbnails are enabled but no specific thumb provided
1261            $button.attr('data-thumb', getPlaceholderThumb());
1262        }
1263
1264        return $button;
1265    }
1266
1267    /**
1268     * Reinitialize lightbox after MetaSlider updates
1269     */
1270    $(document).on('metaslider:after:resize metaslider:after:change', function (event, slider) {
1271        if (slider && slider.container) {
1272            var $container = $(slider.container);
1273            if ($container.hasClass('ml-builtin-lightbox') || ($container.attr('class') && $container.attr('class').indexOf('metaslider-built-in-lightbox') !== -1)) {
1274                // Properly destroy existing LightGallery instance
1275                if ($container.data('lightgallery')) {
1276                    $container.data('lightgallery').destroy();
1277                }
1278
1279                // Remove existing initialization markers
1280                $container.removeClass('lg-initialized ml-lightgallery-active');
1281
1282                // Reinitialize after a short delay
1283                setTimeout(function () {
1284                    initLightbox();
1285                }, 100);
1286            }
1287        }
1288    });
1289
1290    /**
1291     * Initialize all videos detection
1292     */
1293    function initAllVideos()
1294    {
1295        // Find all video elements on the page (not inside MetaSlider)
1296        var $videos = $('iframe[src*="youtube.com"], iframe[src*="youtu.be"], iframe[src*="vimeo.com"], video')
1297            .not('.metaslider iframe, .metaslider video')
1298            .not('.ml-lightbox-processed');
1299
1300        $videos.each(function () {
1301            var $video = $(this);
1302            var $container = $video.closest('div, p, figure, .wp-block-embed, .wp-block-video');
1303
1304            // Skip if already processed
1305            if ($video.hasClass('ml-lightbox-processed') || $container.find('.ml-lightbox-button').length > 0) {
1306                return;
1307            }
1308
1309            // Mark as processed
1310            $video.addClass('ml-lightbox-processed');
1311
1312            // Get video URL
1313            var videoUrl = '';
1314            var videoType = '';
1315            var posterUrl = '';
1316
1317            if ($video.is('iframe')) {
1318                var src = $video.attr('src');
1319                if (src.includes('youtube.com') || src.includes('youtu.be')) {
1320                    videoType = 'youtube';
1321                    // Extract YouTube ID
1322                    var youtubeId = src.match(/(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/);
1323                    if (youtubeId) {
1324                        videoUrl = 'https://www.youtube.com/watch?v=' + youtubeId[1];
1325                        posterUrl = 'https://img.youtube.com/vi/' + youtubeId[1] + '/maxresdefault.jpg';
1326                    }
1327                } else if (src.includes('vimeo.com')) {
1328                    videoType = 'vimeo';
1329                    // Extract Vimeo ID
1330                    var vimeoId = src.match(/vimeo\.com\/(?:video\/)?(\d+)/);
1331                    if (vimeoId) {
1332                        videoUrl = 'https://vimeo.com/' + vimeoId[1];
1333                    }
1334                }
1335            } else if ($video.is('video')) {
1336                videoType = 'external-video';
1337                videoUrl = $video.attr('src') || $video.find('source').first().attr('src');
1338                posterUrl = $video.attr('poster');
1339            }
1340
1341            if (videoUrl) {
1342                // Create lightbox button
1343                var $button = $('<a class="ml-lightbox-button ml-auto-lightbox" title="Open in Lightbox">Open in Lightbox</a>');
1344
1345                // Add common lightbox attributes
1346                $button.attr('data-lg-size', '1280-720');
1347                $button.attr('data-lightbox-arrows', 'true');
1348                $button.attr('data-lightbox-thumbnails', 'true');
1349                $button.attr('data-slide-type', videoType);
1350
1351                if (videoType === 'external-video') {
1352                    // For external videos (MP4, etc.), use data-video JSON format
1353                    var videoMimeType = 'video/mp4';
1354                    if (videoUrl.includes('.webm')) {
1355                        videoMimeType = 'video/webm';
1356                    } else if (videoUrl.includes('.ogg')) {
1357                        videoMimeType = 'video/ogg';
1358                    } else if (videoUrl.includes('.mov')) {
1359                        videoMimeType = 'video/quicktime';
1360                    }
1361
1362                    var videoData = {
1363                        source: [{
1364                            src: videoUrl,
1365                            type: videoMimeType
1366                        }],
1367                        attributes: {
1368                            preload: false,
1369                            controls: true
1370                        }
1371                    };
1372
1373                    $button.attr('data-video', JSON.stringify(videoData));
1374
1375                    if (posterUrl) {
1376                        $button.attr('data-poster', posterUrl);
1377                    }
1378                } else {
1379                    // For YouTube/Vimeo, use standard format
1380                    $button.attr('href', videoUrl);
1381                    $button.attr('data-src', videoUrl);
1382                    $button.attr('data-video', 'true');
1383
1384                    if (posterUrl) {
1385                        $button.attr('data-poster', posterUrl);
1386                    }
1387                }
1388
1389                // Position container relatively (CSS class will handle button styling)
1390                $container.css('position', 'relative');
1391
1392                // Add button to container
1393                $container.append($button);
1394
1395                // Initialize lightbox on the button
1396                if (typeof lightGallery !== 'undefined') {
1397                    var settings = getCommonLightboxSettings();
1398                    settings.selector = 'a.ml-auto-lightbox';
1399                    settings.plugins = [
1400                        ...(typeof lgVideo !== 'undefined' ? [lgVideo] : [])
1401                    ];
1402
1403                    lightGallery($container[0], settings);
1404                }
1405            }
1406        });
1407    }
1408
1409})(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.