1jQuery(document).ready(function($){ 2 /* Creatomatic Lightbox */ 3 4 // Append the lightbox container once to the body 5 $('body').append(` 6 <div class="creato-lightbox-overlay"> 7 <div class="creato-lightbox-content"> 8 <div class="creato-lightbox-slider"></div> 9 <span class="creato-lightbox-close"><i class="fas fa-times"></i></span> 10 </div> 11 </div> 12 `); 13 14 const $overlay = $('.creato-lightbox-overlay'); 15 const $slider = $('.creato-lightbox-slider'); 16 17 /* Strip WordPress size suffix from image filenames */ 18 function stripSizeSuffix(src) { 19 return src.replace(/-\d+x\d+(?=\.(jpg|jpeg|png|gif))/i, ''); 20 } 21 22 /* Generate slide markup for image or iframe */ 23 function getSlideMarkup($el) { 24 if ($el.data('featherlight') === 'iframe') { 25 const src = $el.attr('href') || $el.data('src') || $el.data('featherlight-src'); 26 27 28 // Dodgy url 29 if (!isSafeUrl(src)) 30 return; 31 32 const width = $el.data('featherlight-iframe-width') || '100%'; 33 const height = $el.data('featherlight-iframe-height') || '500'; 34 const frameborder = $el.data('featherlight-iframe-frameborder') || '0'; 35 const allow = $el.data('featherlight-iframe-allow') || 'autoplay; encrypted-media'; 36 const allowfullscreen = $el.data('featherlight-iframe-allowfullscreen') ? 'allowfullscreen' : ''; 37 38 return ` 39 <div class="creato-slide"> 40 <div class="iframe-container"> 41 <iframe src="${src}" width="${width}" height="${height}" frameborder="${frameborder}" allow="${allow}" ${allowfullscreen}></iframe> 42 </div> 43 </div> 44 `; 45 } 46 47 let imgSrc = $el.is('img') ? $el.attr('src') 48 : $el.is('a') ? $el.attr('href') 49 : $el.find('img').attr('src'); 50 51 // Dodgy image url 52 if(!isSafeImageUrl(imgSrc)) 53 return false; 54 55 return ` 56 <div class="creato-slide"> 57 <img src="${imgSrc}" /> 58 </div> 59 `; 60 } 61 62 63 64 /* Close lightbox */ 65 function closeLightbox() { 66 $overlay.fadeOut(() => { 67 if ($slider.hasClass('slick-initialized')) { 68 $slider.slick('unslick'); 69 } 70 $slider.empty(); 71 }); 72 } 73 74 /* Links directly to images (with Slick Slider) */ 75 const featherlightSelector = 'a[href$=".jpg"], a[href$=".jpeg"], a[href$=".png"], a[href$=".gif"], a[data-featherlight="iframe"]'; 76 77 78 $(document).on('click', featherlightSelector, function (e) { 79 e.preventDefault(); 80 81 const $clicked = $(this); 82 const imgSrc = $clicked.attr('href'); 83 //const alt = $clicked.find('img').attr('alt') || ''; 84 85 // Create the slide for the clicked image 86 const slide = getSlideMarkup($clicked); 87 88 // Prepare the slider with this single image (or others if part of a gallery) 89 $slider.empty().append(slide); // Start with the clicked image 90 91 // Check if there are any other images within the same gallery to add 92 const $gallery = $clicked.closest('.wp-block-gallery, .sc-agent-property-section, .creato-lightbox-gallery, .woocommerce-product-gallery__wrapper, .gallery, .single-property-page-gallery, .single-property-gallery'); 93 const $images = $gallery.find('a[href$=".jpg"], a[href$=".jpeg"], a[href$=".png"], a[href$=".gif"], a[data-featherlight="iframe"]'); 94 95 const slides = []; 96 let initialIndex = 0; 97 98 $images.each(function (i) { 99 const $el = $(this); 100 const slide = getSlideMarkup($el); 101 if (!slide) return; 102 103 if ($el[0] === $clicked[0]) { 104 initialIndex = i; 105 } 106 107 slides.push(slide); 108 }); 109 110 $slider.empty().append(slides.join('')); 111 112 // Initialize the Slick slider 113 $slider.slick({ 114 dots: true, 115 arrows: true, 116 initialSlide: initialIndex, // Start at the clicked image 117 prevArrow: '<button type="button" class="creato-slick-prev"><i class="fas fa-chevron-left"></i></button>', 118 nextArrow: '<button type="button" class="creato-slick-next"><i class="fas fa-chevron-right"></i></button>', 119 }); 120 121 // Show the overlay with the lightbox 122 $overlay.fadeIn(); 123 }); 124 125 /* Close button */ 126 $('.creato-lightbox-close').on('click', closeLightbox); 127 128 /* Close on outside click */ 129 $overlay.on('click', function (e) { 130 if ( 131 !$(e.target).closest('.creato-lightbox-content img').length && 132 !$(e.target).closest('.creato-slick-prev').length && 133 !$(e.target).closest('.creato-slick-next').length 134 ) { 135 closeLightbox(); 136 } 137 }); 138 139 140 141 142 // The flaw with featherlight, it never sanitized urls for iframes or images etc 143 function isSafeUrl(url) { 144 return /^(https?:)?\/\/[^\s]+$/.test(url); 145 } 146 147 function isSafeImageUrl(url) { 148 return /^https?:\/\/.+\.(jpg|jpeg|png|gif)$/i.test(url); 149 } 150 151});
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.