1wp.domReady( function () { 2 3 /************* 4 * GET OPTIONS 5 *************/ 6 7 // Enable Settings 8 const autodetectImage = Boolean( settings.autodetectImage ); 9 const autodetectInline = Boolean( settings.autodetectInline ) ?? false; 10 const autodetectPDF = Boolean( settings.autodetectPDF ) ?? false; 11 const autodetectSWF = Boolean( settings.autodetectSWF ) ?? false; 12 const autodetectSVG = Boolean( settings.autodetectSVG ) ?? false; 13 const autodetectVideo = Boolean( settings.autodetectVideo ) ?? false; 14 const autodetectVideopress = Boolean( settings.autodetectVideopress ) ?? false; 15 const autodetectYoutube = Boolean( settings.autodetectYoutube ) ?? false; 16 const autodetectVimeo = Boolean( settings.autodetectVimeo ) ?? false; 17 const autodetectDailymotion = Boolean( settings.autodetectDailymotion ) ?? false; 18 const autodetectGoogleMaps = Boolean( settings.autodetectGoogleMaps ) ?? false; 19 const autodetectElementorImages = Boolean( settings.autodetectElementorImages ) ?? false; 20 const autodetectElementorGalleries = Boolean( settings.autodetectElementorGalleries ) ?? false; 21 const autodetectElementorCarousel = Boolean( settings.autodetectElementorCarousel ) ?? false; 22 const autodetectNextgen = Boolean( settings.autodetectNextgen ) ?? false; 23 24 // General Settings 25 const colorTheme = settings.colorTheme; 26 const transitionStyle = settings.transitionStyle; 27 const thumbnails = Boolean( settings.thumbnails ); 28 const thumbnailStyle = settings.thumbnailStyle; 29 const thumbnailsOnStart = Boolean( settings.thumbnailsOnStart ); 30 const showTitle = Boolean( settings.showTitle ); 31 const showAlt = Boolean( settings.showAlt ); 32 const showCamera = Boolean( settings.showCamera ); 33 const showLens = Boolean( settings.showLens ); 34 const showFocal = Boolean( settings.showFocal ); 35 const showAperture = Boolean( settings.showAperture ); 36 const showExposure = Boolean( settings.showExposure ); 37 const showIso = Boolean( settings.showIso ) 38 const showExif = Boolean( settings.showExif ) 39 && ( showCamera || showLens || showFocal || showAperture || showExposure || showIso ); 40 const showExifIcons = Boolean( settings.showExifIcons ) 41 const showCaption = Boolean( settings.showCaption ); 42 const applyWithoutLinks = Boolean( settings.applyWithoutLinks ); 43 const groupImages = settings.groupImages; 44 const customGroupSelectors = settings.customGroupSelectors; 45 const useCompactStyle = Boolean( settings.useCompactStyle ); 46 const useFilenameInUrl = Boolean( settings.useFilenameInUrl ); 47 const hasValidProLicense = Boolean( settings.hasValidProLicense ); 48 const restUrl = settings.restUrl; 49 50 // Toolbar Settings 51 const toolbarPosition = settings.toolbarPosition; 52 const thumbnailButton = Boolean( settings.thumbnailButton ); 53 const zoomButton = Boolean( settings.zoomButton ); 54 const slideshowButton = Boolean( settings.slideshowButton ); 55 const fullScreenButton = Boolean( settings.fullscreenButton ); 56 const downloadButton = Boolean( settings.downloadButton ); 57 const imageNumbers = Boolean( settings.imageNumbers ); 58 const socialButton = Boolean( settings.socialButton ); 59 const toolbar = [ 60 ... socialButton ? ['social']: [], 61 ... downloadButton ? ['download']: [], 62 ... zoomButton ? ['iterateZoom'] : [], 63 ... slideshowButton ? ['slideshow'] : [], 64 ... fullScreenButton ? ['fullscreen'] : [], 65 ... thumbnailButton ? ['thumbs'] : [], 66 'close' 67 ] 68 const infobar = [ ... imageNumbers ? ['infobar'] : [] ]; 69 const leftToolbar = [ 70 ... ( toolbarPosition === 'left' ? toolbar.filter( item => item !== 'close' ) : [] ), 71 ... ( toolbarPosition === 'right' ) ? infobar : [] 72 ]; 73 const middleToolbar = [ 74 ...( toolbarPosition === 'center' ? infobar : [] ), 75 ...( toolbarPosition === 'center' ? toolbar : [] ) 76 ]; 77 const rightToolbar = [ 78 ... ( toolbarPosition === 'right' ? toolbar : [] ), 79 ... ( toolbarPosition === 'left' ? infobar : [] ), 80 ... ( toolbarPosition === 'left' ? ['close'] : [] ) 81 ]; 82 83 // Social Icons 84 const shareSvg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" id="share"><path fill="currentColor" d="M6.54 55.08a1.91 1.91 0 0 1-.62-.1 2 2 0 0 1-1.38-2c0-.3 2.06-29.34 31.18-31.62V10.92a2 2 0 0 1 3.43-1.4l19.74 20.16a2 2 0 0 1 0 2.8L39.15 52.64a2 2 0 0 1-3.43-1.4V41c-19.44.74-27.41 13-27.49 13.15a2 2 0 0 1-1.69.93Zm33.18-39.26v7.41a2 2 0 0 1-1.93 2c-18.84.69-25.58 13.24-28 21.31 5-4.32 13.91-9.6 27.81-9.6h.09a2 2 0 0 1 2 2v7.41l15-15.26Z"></path></svg>'; 85 const linkSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" id="link">
85<path fill="currentColor" d="M18.51 3.868a4 4 0 0 0-5.657 0L8.611 8.111a4 4 0 0 0 5.657 5.657l.502-.503s-.226-.635-.502-.911c-.276-.277-.912-.503-.912-.503l-.502.503a2 2 0 0 1-2.829-2.829l4.243-4.243a2 2 0 0 1 2.828 2.829l-.707.707s.49.318.798.627c.31.309.616.787.616.787l.707-.707a4 4 0 0 0 0-5.657Z"></path><path fill="currentColor" d="M16.39 10.232a4 4 0 0 0-5.658 0l-.541.542s.268.6.544.875c.276.276.87.539.87.539l.541-.542a2 2 0 1 1 2.829 2.829l-4.243 4.243a2 2 0 1 1-2.828-2.829l.779-.779s-.503-.359-.78-.635c-.275-.276-.635-.779-.635-.779l-.778.779a4 4 0 1 0 5.656 5.657l4.243-4.243a4 4 0 0 0 0-5.657Z"></path></svg>'; 86 const facebookSvg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" id="facebook"><path fill="currentColor" fill-rule="evenodd" d="M12 5.5H9v-2a1 1 0 0 1 1-1h1V0H9a3 3 0 0 0-3 3v2.5H4V8h2v8h3V8h2l1-2.5z" clip-rule="evenodd"></path></svg>'; 87 const twitterSvg = '<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 1668.56 1221.19" viewBox="0 0 1668.56 1221.19" id="twitter-x"><path d="M283.94,167.31l386.39,516.64L281.5,1104h87.51l340.42-367.76L984.48,1104h297.8L874.15,558.3l361.92-390.99h-87.51l-313.51,338.7l-253.31-338.7H283.94z M412.63,231.77h136.81l604.13,807.76h-136.81L412.63,231.77z" transform="translate(52.39 -25.059)"></path></svg>'; 88 const pinterestSvg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" id="pinterest"><path fill="currentColor" d="M8.717 0C4.332 0 2 2.81 2 5.874c0 1.421.794 3.193 2.065 3.755.193.087.298.05.341-.129.038-.136.205-.791.286-1.1a.283.283 0 0 0-.068-.278c-.422-.488-.757-1.377-.757-2.211 0-2.137 1.699-4.212 4.59-4.212 2.5 0 4.249 1.624 4.249 3.947 0 2.625-1.389 4.441-3.194 4.441-.999 0-1.743-.784-1.507-1.754.285-1.155.844-2.397.844-3.23 0-.747-.422-1.365-1.284-1.365-1.017 0-1.842 1.007-1.842 2.359 0 .859.304 1.439.304 1.439l-1.193 4.823c-.316 1.285.043 3.366.074 3.545.019.099.13.13.192.049.099-.13 1.315-1.865 1.656-3.119.124-.457.633-2.31.633-2.31.335.605 1.302 1.112 2.332 1.112 3.064 0 5.278-2.693 5.278-6.035C14.988 2.397 12.246 0 8.717 0"></path></svg>'; 89 const linkedinSvg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" id="linkedin"><path d="M0 5h3.578v11H0zM13.324 5.129c-.038-.012-.074-.025-.114-.036a2.32 2.32 0 0 0-.145-.028A3.207 3.207 0 0 0 12.423 5c-2.086 0-3.409 1.517-3.845 2.103V5H5v11h3.578v-6s2.704-3.766 3.845-1v7H16V8.577a3.568 3.568 0 0 0-2.676-3.448z"></path><circle cx="1.75" cy="1.75" r="1.75"></circle></svg>'; 90 const cameraSvg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="camera"><g><circle path fill="currentColor" cx="16" cy="17" r="5"></circle><path fill="currentColor" d="M25,8h-.76a1,1,0,0,1-.9-.55L23,6.76A5,5,0,0,0,18.53,4H13.47A5,5,0,0,0,9,6.76l-.34.69a1,1,0,0,1-.9.55H7a5,5,0,0,0-5,5V23a5,5,0,0,0,5,5H25a5,5,0,0,0,5-5V13A5,5,0,0,0,25,8ZM16,24a7,7,0,1,1,7-7A7,7,0,0,1,16,24Zm9-10a1,1,0,1,1,1-1A1,1,0,0,1,25,14Z"></path></g></svg>'; 91 const lensSvg = '<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 72 72" viewBox="0 0 80 80" id="camera-lens"><path fill="currentColor" d="M52.9 1.7H14.1c-.6 0-1 .4-1 1v6.7c0 .6.4 1 1 1h38.8c.6 0 1-.4 1-1V2.7C53.9 2.1 53.5 1.7 52.9 1.7zM49.9 59.2v5.1c0 .6-.5 1-1 1H18.1c-.6 0-1-.4-1-1v-5.1H49.9zM53.9 42.3v6.6c0 2.2-1.8 4-4 4h0v4.3H17.1v-4.3h0c-2.2 0-4-1.8-4-4v-6.6H53.9zM51.9 17.4h-2v-5H17.1v5h-2c-1.1 0-2 .9-2 2v20.9h40.8V19.4C53.9 18.3 53 17.4 51.9 17.4zM20.1 35c0 .6-.4 1-1 1s-1-.4-1-1V22.7c0-.6.4-1 1-1s1 .4 1 1V35zM25.9 35c0 .6-.4 1-1 1s-1-.4-1-1V22.7c0-.6.4-1 1-1s1 .4 1 1V35zM31.6 35c0 .6-.4 1-1 1s-1-.4-1-1V22.7c0-.6.4-1 1-1s1 .4 1 1V35zM37.4 35c0 .6-.4 1-1 1s-1-.4-1-1V22.7c0-.6.4-1 1-1s1 .4 1 1V35zM43.1 35c0 .6-.4 1-1 1s-1-.4-1-1V22.7c0-.6.4-1 1-1s1 .4 1 1V35zM48.9 35c0 .6-.4 1-1 1s-1-.4-1-1V22.7c0-.6.4-1 1-1s1 .4 1 1V35z"></path></svg>'; 92 const apertureSvg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" id="aperture"><path fill="currentColor" d="M57.28 19.96L42.31 45.88H56.3A28.17939 28.17939 0 0057.28 19.96zM32.14 60A28.00011 28.00011 0 0055.05 47.88H25.14zM7.83 46.12A28.03368 28.03368 0 0029.78 59.9L14.83 34z"></path>
92<polygon fill="currentColor" points="15.98 32 23.99 45.88 40.01 45.88 48.02 32 40.01 18.12 23.99 18.12 15.98 32"></polygon><path fill="currentColor" d="M56.17 17.88A28.03375 28.03375 0 0034.22 4.1L49.17 30zM31.86 4A28 28 0 008.95 16.12H38.86zM7.7 18.12a27.94085 27.94085 0 00-.98 25.92L21.69 18.12z"></path></svg>'; 93 const exposureSvg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23 23" id="shutter-speed"><path fill="none" d="M0 0h24v24H0V0z"></path><path fill="currentColor" d="M10 3h4c.55 0 1-.45 1-1s-.45-1-1-1h-4c-.55 0-1 .45-1 1s.45 1 1 1zm9.03 4.39l.75-.75c.38-.38.39-1.01 0-1.4l-.01-.01c-.39-.39-1.01-.38-1.4 0l-.75.75C16.07 4.74 14.12 4 12 4c-4.8 0-8.88 3.96-9 8.76C2.87 17.84 6.94 22 12 22c4.98 0 9-4.03 9-9 0-2.12-.74-4.07-1.97-5.61zM12 20c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7zm-1.19-5h-3.7c-.38 0-.62.4-.45.74.56 1.12 1.44 2.01 2.57 2.57.23.11.52.02.65-.21l1.37-2.35c.19-.33-.05-.75-.44-.75zm3.92-7.35c-.23-.12-.52-.02-.65.2l-1.38 2.39c-.2.34.04.76.43.76h3.76c.38 0 .62-.4.45-.73-.58-1.13-1.49-2.04-2.61-2.62zm-.85 7.05c-.19-.34-.68-.35-.87-.01l-2.04 3.52c-.18.32.02.72.39.75 1.34.14 2.69-.18 3.83-.89.22-.14.28-.43.16-.66l-1.47-2.71zm-3.57-1.47L7.93 9.57c-.2-.3-.64-.3-.84 0-.81 1.16-1.17 2.57-1.05 3.98.02.26.24.45.5.45h3.35c.39 0 .63-.44.42-.77zm3.66-.49l2.02 3.74c.18.33.64.35.86.05.86-1.18 1.24-2.62 1.12-4.08-.02-.26-.25-.45-.5-.45h-3.05c-.39 0-.63.4-.45.74zm-3.8-1.57c.2.31.66.3.85-.02l1.94-3.35c.19-.32-.03-.72-.4-.76-1.36-.12-2.73.21-3.88.97-.22.15-.27.46-.13.68l1.62 2.48z"></path></svg>'; 94 const isoSvg = '<svg xmlns="http://www.w3.org/2000/svg" id="iso" viewBox="0 0 46 46"><path fill="none" d="M0 0h48v48H0zm0 0h48v48H0z"></path><path fill="currentColor" d="M38 6H10c-2.21 0-4 1.79-4 4v28c0 2.21 1.79 4 4 4h28c2.21 0 4-1.79 4-4V10c0-2.21-1.79-4-4-4zm-27 9h4v-4h3v4h4v3h-4v4h-3v-4h-4v-3zm27 23H10l28-28v28zm-4-4v-3H24v3h10z"></path></svg>'; 95 96 /************* 97 * ADD FANCYBOX ATTRIBUTES TO ELEMENTS 98 *************/ 99 100 // Next apply fancybox attributes to images 101 if ( autodetectImage ) { 102 let imageSelectors = 'a[href*=".jpg" i]:not(.nolightpress,li.nolightpress>a),area[href*=".jpg" i]:not(.nolightpress),a[href*=".jpeg" i]:not(.nolightpress,li.nolightpress>a),area[href*=".jpeg" i]:not(.nolightpress),a[href*=".png" i]:not(.nolightpress,li.nolightpress>a),area[href*=".png" i]:not(.nolightpress),a[href*=".webp" i]:not(.nolightpress,li.nolightpress>a),area[href*=".webp" i]:not(.nolightpress)'; 103 if ( applyWithoutLinks ) { 104 imageSelectors += ',.wp-block-image:not(.nolightpress) > img'; 105 } 106 if ( autodetectSVG && hasValidProLicense ) { 107 imageSelectors += ',a[href*=".svg" i],area[href*=".svg" i]'; 108 } 109 110 // Apply to images 111 const images = document.querySelectorAll( imageSelectors ); 112 images.forEach( image => { 113 applyFancyboxAttributes( image, { 'data-fancybox': '' }, useFilenameInUrl ); 114 } ); 115 116 // Group images 117 applyImageGroups( images, imageSelectors ); 118 } 119 120 // Elementor compatibility 121 // Apply fancybox attributes to Elementor images/galleries/carousels 122 if ( autodetectElementorImages && hasValidProLicense ) { 123 const elementorImages = document.querySelectorAll( '.elementor-widget-image img:not(.nolightpress)' ); 124 elementorImages.forEach( image => { 125 applyFancyboxAttributes( image, { 'data-fancybox': '' } ); 126 } ); 127 } 128 if ( autodetectElementorGalleries && hasValidProLicense ) { 129 const elementorGalleries = document.querySelectorAll( '.elementor-widget-image-gallery:not(.nolightpress)' ); 130 elementorGalleries.forEach( ( section, sectionIndex ) => { 131 const images = section.querySelectorAll( '.gallery-item a:not(.nolightpress)' ); 132 images.forEach( image => { 133 applyFancyboxAttributes( image, { 'data-fancybox': 'elementor-gallery-' + sectionIndex } ); 134 } ); 135 } ); 136 } 137 if ( autodetectElementorCarousel && hasValidProLicense ) { 138 const elementorCarousels = document.querySelectorAll( '.elementor-widget-image-carousel:not(.nolightpress)' ); 139 elementorCarousels.forEach( ( section, sectionIndex ) => { 140 const images = section.querySelectorAll( '.swiper-slide a:not(.nolightpress)' );
141 images.forEach( image => { 142 applyFancyboxAttributes( image, { 'data-fancybox': 'elementor-carousel-' + sectionIndex } ); 143 } ); 144 } ); 145 } 146 147 // Apply fancybox attributes to videos (including SWFs here) 148 const videoSelectors = [ 149 ... ( autodetectSWF ? [ 'a[href*=".swf" i]:not(.nolightpress),area[href*=".swf" i]:not(.nolightpress)' ] : [] ), 150 ... ( autodetectVideo ? [ 'a[href*=".mp4" i]:not(.nolightpress),area[href*=".mp4" i]:not(.nolightpress),a[href*=".mov" i]:not(.nolightpress),area[href*=".mov" i]:not(.nolightpress),a[href*=".avi" i]:not(.nolightpress),area[href*=".avi" i]:not(.nolightpress),a[href*=".flv" i]:not(.nolightpress),area[href*=".flv" i]:not(.nolightpress),a[href*=".mkv" i]:not(.nolightpress),area[href*=".mkv" i]:not(.nolightpress),a[href*=".wmv" i]:not(.nolightpress),area[href*=".wmv" i]:not(.nolightpress),a[href*=".avchd" i]:not(.nolightpress),area[href*=".avchd" i]:not(.nolightpress),a[href*=".webm" i]:not(.nolightpress),area[href*=".webm" i]:not(.nolightpress)' ] : [] ), 151 ... ( autodetectVideopress ? [ 'a[href*="video.wordpress.com/v/"]:not(.nolightpress),area[href*="video.wordpress.com/v/"]:not(.nolightpress),a[href*="videopress.com/v/"]:not(.nolightpress),area[href*="videopress.com/v/"]:not(.nolightpress)' ] : [] ), 152 ... ( autodetectYoutube ? [ 'a[href*="youtu.be/" i]:not(.nolightpress),area[href*="youtu.be/" i]:not(.nolightpress),a[href*="youtube.com/" i]:not(.nolightpress),area[href*="youtube.com/" i]:not(.nolightpress)' ] : [] ), 153 ... ( autodetectVimeo ? [ 'a[href*="vimeo.com/" i]:not(.nolightpress),area[href*="vimeo.com/" i]:not(.nolightpress)' ] : [] ), 154 ... ( autodetectDailymotion ? [ 'a[href*="dailymotion.com/" i]:not(.nolightpress),area[href*="dailymotion.com/" i]:not(.nolightpress)' ] : [] ), 155 ]; 156 if ( videoSelectors.length > 0 && hasValidProLicense ) { 157 const videoMatches = document.querySelectorAll( videoSelectors.toString() ); 158 videoMatches.forEach( item => { 159 applyFancyboxAttributes( item, { 'data-fancybox-video': '' } ); 160 }); 161 } 162 163 // Apply fancybox attributes to Inline elements 164 if ( autodetectInline && hasValidProLicense ) { 165 const inlineMatches = document.querySelectorAll( 'a.lightpress-inline:not(.nolightpress),area.lightpress-inline:not(.nolightpress),.lightpress-inline>a:not(.nolightpress)' ); 166 inlineMatches.forEach( item => { 167 applyFancyboxAttributes( item, { 'data-fancybox-inline': '' } ); 168 }); 169 } 170 171 // Apply fancybox attributes to PDFs 172 if ( autodetectPDF && hasValidProLicense ) { 173 const pdfMatches = document.querySelectorAll( 'a[href*=".pdf" i]:not(.nolightpress),area[href*=".pdf" i]:not(.nolightpress)' ); 174 pdfMatches.forEach( item => { 175 applyFancyboxAttributes( item, { 'data-fancybox-pdf': '' } ); 176 }); 177 } 178 179 // Apply fancybox attributes to Maps 180 if ( autodetectGoogleMaps && hasValidProLicense ) { 181 const mapMatches = document.querySelectorAll( 'a[href*="google.com/maps" i]:not(.nolightpress),area[href*="google.com/maps" i]:not(.nolightpress)' ); 182 mapMatches.forEach( item => { 183 applyFancyboxAttributes( item, { 'data-fancybox-map': '' } ); 184 }); 185 } 186 187 // Apply fancybox attributes to Iframe elements 188 const autodetectIframe = true; 189 if ( autodetectIframe && hasValidProLicense ) { 190 const iframeMatches = document.querySelectorAll( 'a.lightpress-iframe:not(.nolightpress),.lightpress-iframe>a:not(.nolightpress)' ); 191 iframeMatches.forEach( item => { 192 applyFancyboxAttributes( 193 item, 194 { 'data-fancybox-iframe': '', 'data-type': 'iframe' } 195 ); 196 }); 197 } 198 199 /******************** 200 * APPLY THE LIGHTBOX TO IMAGES 201 * 202 * Documentation included for what each setting does. 203 ********************/ 204 Fancybox.bind("[data-fancybox]", { 205 Carousel: { 206 transition: transitionStyle, 207 }, 208 Toolbar: { 209 items: { 210 social: { 211 tpl: `<a class="f-button social share" href="#">${ shareSvg }</a>`, 212 click: ( event ) => { 213 const fancybox = event?.instance; 214 const shareButton = document.querySelector( '.f-button.social.share' ); 215 const socialIcons = document.querySelector( '.fancybox-social-icons' ); 216 if ( ! socialIcons ) { 217 const newSocialIcons = ` 218 <div class="fancybox-social-icons"> 219 <a class="f-button social link" href="#">${ linkSvg }</a> 220 <a class="f-button social facebook" href="#">${ facebookSvg }</a> 221 <a class="f-button social twitter" href="#">${ twitterSvg }</a> 222 <a class="f-button social pinterest" href="#">${ pinterestSvg }</a> 223 <a class="f-button social linkedin" href="#">${ linkedinSvg }</a> 224 </div> 225 `; 226 shareButton.insertAdjacentHTML('beforebegin', newSocialIcons ); 227 addShareEventListeners( fancybox ); 228 } else { 229 socialIcons.remove(); 230 } 231 }, 232 }, 233 }, 234 display: { 235 left: leftToolbar, 236 middle: middleToolbar, 237 right: rightToolbar, 238 }, 239 }, 240 Thumbs: thumbnails 241 ? { 242 type: thumbnailStyle, 243 showOnStart: thumbnailsOnStart 244 } : false, 245 caption: function ( fancybox, slide ) { 246 return getCaption( fancybox, slide ); 247 }, 248 compact: isTouchDevice(), // Mobile mode - if enabled cannot click image. 249 on: { 250 'Carousel.ready Carousel.change': ( fancybox, slide ) => { 251 // Check for exif class. 252 const imageClasses = fancybox.getSlide()?.triggerEl?.classList; 253 const imageClass = imageClasses 254 ? '.' + [ ...imageClasses ] 255 : null; 256 const gallery = imageClass 257 ? document.querySelector( imageClass ).closest( '.wp-block-gallery' ) 258 : null; 259 const hasExifClass = gallery 260 ? gallery.classList.contains( 'firelight-exif' ) || gallery.classList.contains( 'fancybox-exif' ) 261 : false;
262 263 // Add exif depending on options. 264 if ( showExif || hasExifClass ) { 265 addExifToCaption( fancybox, slide ); 266 } 267 }, 268 }, 269 }); 270 271 /******************** 272 * APPLY THE LIGHTBOX TO NON IMAGES 273 * 274 * Documentation included for what each setting does. 275 ********************/ 276 if ( hasValidProLicense ) { 277 Fancybox.bind("[data-fancybox-video]", { 278 mainClass: 'non-image video', 279 keyboard: { 280 Escape: "close", 281 Delete: "close", 282 Backspace: "close", 283 PageUp: "next", 284 PageDown: "prev", 285 ArrowUp: "prev", 286 ArrowDown: "next", 287 ArrowRight: "next", 288 ArrowLeft: "prev", 289 }, 290 autoFocus: false, 291 compact: useCompactStyle ? true : isTouchDevice() 292 }); 293 294 Fancybox.bind("[data-fancybox-inline]", { 295 mainClass: 'non-image inline', 296 compact: useCompactStyle ? true : isTouchDevice() 297 }); 298 299 Fancybox.bind("[data-fancybox-pdf]", { 300 mainClass: 'non-image pdf', 301 autoFocus: false, 302 compact: useCompactStyle ? true : isTouchDevice() 303 }); 304 305 Fancybox.bind("[data-fancybox-map]", { 306 mainClass: 'non-image map', 307 autoFocus: false, 308 compact: useCompactStyle ? true : isTouchDevice() 309 }); 310 311 Fancybox.bind("[data-fancybox-iframe]", { 312 mainClass: 'non-image iframe', 313 autoFocus: false, 314 compact: useCompactStyle ? true : isTouchDevice() 315 }); 316 } 317 318 /**************** 319 * HELPER METHODS 320 ****************/ 321 322 /** 323 * Applies fancybox attributes. 324 * 325 * @param string element Type of element (image, pdf, video, iframe, etc). 326 * @param array attributes Array of attributes to apply. 327 * @param bool useFilename Whether filanem should be used in url. 328 * @returns void 329 */ 330 function applyFancyboxAttributes( element, attributes = {}, isImage = true ) { 331 // All get fancybox attribute 332 element.classList.add( 'fancybox' ); 333 334 // Then apply provided attributes. 335 const attributeNames = Object.keys( attributes ); 336 if ( attributeNames.length > 0 ) { 337 attributeNames.forEach( name => element.setAttribute( name, attributes[name] ) ); 338 } 339 340 // In right conditions, apply data-slug for lightbox url. 341 const isImg = element.nodeName.toLowerCase() === 'img'; 342 const containsImg = element.getElementsByTagName('img').length > 0; 343 if ( ( isImg || containsImg ) && useFilenameInUrl ) { 344 const url = isImg ? element.getAttribute( 'src' ) : element.getAttribute( 'href' ); 345 if ( url ) { 346 const filename = url.substring( url.lastIndexOf("/") + 1, url.lastIndexOf('.') ); 347 const fileNoDash = filename.split( '-' ).join( '' );
348 element.setAttribute( 'data-slug', fileNoDash ); 349 } 350 } 351 } 352 353 /** 354 * Determine if user is on a touch device. 355 * 356 * @returns bool 357 */ 358 function isTouchDevice() { 359 return ( ('ontouchstart' in window) || 360 (navigator.maxTouchPoints > 0) || 361 (navigator.msMaxTouchPoints > 0)); 362 } 363 364 /** 365 * Groups images into galleries. 366 * 367 * @returns bool 368 */ 369 function applyImageGroups( images, imageSelectorList ) { 370 if ( 'all' === groupImages ) { 371 images.forEach( image => { 372 image.setAttribute( 'data-fancybox', 'gallery-all' ); 373 image.classList.add( 'fancybox' ); 374 } ); 375 } 376 if ( 'default' === groupImages || 'single' === groupImages ) { 377 let defaultGroupSelectors = 'article, div.hentry, .gallery,.wp-block-gallery,.tiled-gallery,.wp-block-jetpack-tiled-gallery'; 378 const sections = document.querySelectorAll( defaultGroupSelectors ); 379 sections.forEach( ( section, sectionIndex ) => { 380 section.querySelectorAll( imageSelectorList ).forEach( image => { 381 image.setAttribute( 'data-fancybox', 'gallery-' + sectionIndex ); 382 } ); 383 } ); 384 } 385 if ( 'single' === groupImages ) { 386 const allImages = Array.from( document.querySelectorAll( imageSelectorList ) ); 387 const imagesWithoutGallery = allImages.filter( image => { 388 const isFancybox = image.classList.contains('fancybox'); 389 const hasGalleryAttribute = image.getAttribute('data-fancybox') && image.getAttribute('data-fancybox').includes('gallery'); 390 return isFancybox && ! hasGalleryAttribute; 391 }); 392 imagesWithoutGallery.forEach( image => { 393 image.setAttribute( 'data-fancybox', 'gallery-single-images' ); 394 } ); 395 } 396 if ( 'custom' === groupImages ) { 397 if ( customGroupSelectors ) { 398 const sections = document.querySelectorAll( customGroupSelectors ); 399 sections.forEach( ( section, sectionIndex ) => { 400 section.querySelectorAll( imageSelectorList ).forEach( image => { 401 image.setAttribute( 'data-fancybox', 'gallery-' + sectionIndex ); 402 } ); 403 } ); 404 } 405 } 406 if ( autodetectNextgen ) { 407 const nextgenSectionSelectors = '.ngg-galleryoverview, .ngg-imagebrowser, .nextgen_pro_blog_gallery, .nextgen_pro_film, .nextgen_pro_horizontal_filmstrip, .ngg-pro-masonry-wrapper, .ngg-pro-mosaic-container, .nextgen_pro_sidescroll, .nextgen_pro_slideshow, .nextgen_pro_thumbnail_grid, .tiled-gallery'; 408 const nextgenGalleries = document.querySelectorAll( nextgenSectionSelectors ); 409 nextgenGalleries.forEach( ( section, sectionIndex ) => { 410 section.querySelectorAll( imageSelectorList ).forEach( image => { 411 image.setAttribute( 'data-fancybox', 'gallery-' + sectionIndex ); 412 } ); 413 } ); 414 // Handle Ajax Pagination. 415 document.addEventListener( 'nextgen_page_refreshed', function ( e ) { 416 const refreshedNextgenGalleries = document.querySelectorAll( nextgenSectionSelectors ); 417 nextgenGalleries.forEach( ( section, sectionIndex ) => { 418 section.querySelectorAll( imageSelectorList ).forEach( image => { 419 applyFancyboxAttributes( image, { 'data-fancybox': '' } ); 420 image.setAttribute( 'data-fancybox', 'gallery-' + sectionIndex ); 421 } ); 422 } ); 423 } ); 424 } 425 } 426 427 428 /** 429 * Gets caption to display. 430 * Could include title, alt text, or caption based on options. 431 * 432 * @param {*} fancybox 433 * @param {*} slide 434 * @returns string 435 */ 436 function getCaption( fancybox, slide ) { 437 const triggerElement = slide.triggerEl; 438 const isImage = 'IMG' === triggerElement?.tagName; 439 let title = ''; 440 let alt = ''; 441 let caption = ''; 442 443 // Item clicked could be <img> or <a> with image inside 444 if ( showTitle ) { 445 title = isImage && triggerElement.getAttribute("title") 446 ? triggerElement.getAttribute("title") // If is image 447 : triggerElement.querySelector( 'img' ) && triggerElement.querySelector( 'img' ).getAttribute("title") 448 ? triggerElement.querySelector( 'img' ).getAttribute("title") // If image is child 449 : triggerElement.getAttribute("title") // Fallback if no img tag in markup 450 ? triggerElement.getAttribute("title") 451 : ''; 452 } 453 454 // Item clicked could be <img> or <a> with image inside 455 if ( showAlt ) { 456 alt = isImage && triggerElement.getAttribute("alt") 457 ? triggerElement.getAttribute("alt") 458 : triggerElement.querySelector( 'img' ) && triggerElement.querySelector( 'img' ).getAttribute("alt") 459 ? triggerElement.querySelector( 'img' ).getAttribute("alt") 460 : triggerElement.getAttribute("alt") 461 ? triggerElement.getAttribute("alt") // Fallback if no img tag in markup 462 : ''; 463 } 464 465 // For caption, must find figcaption element. 466 if ( showCaption ) { 467 const figcaption = isImage 468 ? triggerElement.parentElement.querySelector( 'figcaption' ) 469 : triggerElement.closest('figure') 470 ? triggerElement.closest('figure').querySelector( 'figcaption' ) 471 : triggerElement.querySelector( '.caption' ) 472 ? triggerElement.querySelector( '.caption' ) 473 : null; 474 caption = figcaption ? DOMPurify.sanitize( figcaption.innerHTML ) : ''; 475 } 476 477 const titleSeparator = title && ( alt || caption ) ? ' | ' : ''; 478 const altSeparator = alt && caption ? ' | ' : ''; 479 480 // Needed to ensure caption element is available later for EXIF. 481 const captionIsEmpty = '' === title + titleSeparator + alt + altSeparator + caption; 482 if ( showExif && captionIsEmpty ) { 483 return ' '; 484 } 485 486 return title + titleSeparator + alt + altSeparator + caption; 487 } 488 489 /** 490 * Adds event listeners to social share buttons. 491 * 492 * @param {*} fancybox 493 * @returns void 494 */ 495 function addShareEventListeners( fancybox ) { 496 const linkButton = document.querySelector( '.f-button.social.link' ); 497 const facebookButton = document.querySelector( '.f-button.social.facebook' ); 498 const twitterButton = document.querySelector( '.f-button.social.twitter' ); 499 const pinterestButton = document.querySelector( '.f-button.social.pinterest' ); 500 const linkedinButton = document.querySelector( '.f-button.social.linkedin' ); 501 const { imageId, imageTitle, imageAlt, imageUrl, imageFilename } = getImageAttributes( fancybox );
502 const shareUrl = restUrl 503 + '?p=' + window.location.pathname 504 + '&h=' + window.location.hash.replace('#', '') 505 + '&i=' + ( imageId ? imageId : imageFilename ) 506 + '&t=' + encodeURIComponent( imageTitle ); 507 508 const encodedShareUrl = encodeURIComponent( shareUrl ); 509 510 linkButton.addEventListener( 'click', function( event ) { 511 event.preventDefault(); 512 copyToClipboard( window.location.href ); 513 514 // Show copied confirmation 515 const span = document.createElement( 'span' ); 516 const text = document.createTextNode( 'Copied!' ); 517 span.appendChild( text ); 518 span.classList.add( 'fancybox-copied' ); 519 span.classList.add( 'f-button' ); 520 const linkButton = document.querySelector( '.f-button.social.link' ); 521 linkButton.appendChild( span ); 522 setTimeout( function() { 523 document.querySelector( '.fancybox-copied' ).remove(); 524 }, 2000 ); 525 }); 526 527 facebookButton.addEventListener( 'click', function() { 528 window.open( "https://www.facebook.com/sharer/sharer.php?u=" + encodedShareUrl ); 529 }); 530 531 twitterButton.addEventListener( 'click', function() { 532 window.open( "http://twitter.com/share?url=" + encodedShareUrl ); 533 }); 534 535 pinterestButton.addEventListener( 'click', function() { 536 window.open( "http://pinterest.com/pin/create/button/?url=" + encodedShareUrl ); 537 }); 538 539 linkedinButton.addEventListener( 'click', function() { 540 window.open( "https://www.linkedin.com/sharing/share-offsite/?url=" + encodedShareUrl ); 541 }); 542 } 543 544 /** 545 * Get image title, url from fancbox current slide 546 * 547 * @param {*} fancybox 548 * @return {Object} Object containing image attributes (id, title, alt, url, filename). 549 */ 550 function getImageAttributes( fancybox ) { 551 const image = fancybox?.getSlide()?.thumbEl 552 ? fancybox?.getSlide()?.thumbEl 553 : fancybox?.getSlide()?.triggerEl; 554 const imageUrl = fancybox?.getSlide()?.thumbSrc 555 ? fancybox?.getSlide()?.thumbSrc 556 : fancybox?.getSlide()?.src; 557 558 if ( ! image ) { 559 return; 560 } 561 562 // Get image id from data-id or else from classlist. 563 let imageId = image.attributes['data-id']?.nodeValue || null; 564 if ( ! imageId ) { 565 const imageClasses = image.attributes?.class?.nodeValue 566 ? image.attributes?.class?.nodeValue.split(' ') 567 : null; 568 if ( imageClasses && imageClasses.length > 0 ) { 569 const imageIdClass = imageClasses.filter( className => className.includes( 'wp-image-' ) ); 570 if ( imageIdClass.length > 0 ) { 571 imageId = imageIdClass[0].substring( imageIdClass[0].lastIndexOf('-') + 1 ); 572 } 573 } 574 } 575 576 // Get image title or use alt or use filename. 577 const titleAttr = image.attributes?.title?.nodeValue || null; 578 const imageAlt = image.attributes?.alt?.nodeValue || null; 579 const imageFilename = imageUrl.substring( imageUrl.lastIndexOf("/") + 1, imageUrl.lastIndexOf('.') ); 580 const imageFilenameNoDash = imageFilename.split( '-' ).join( '' ); 581 const imageTitle = titleAttr 582 ? titleAttr 583 : imageAlt 584 ? imageAlt 585 : imageFilenameNoDash; 586 587 return { imageId, imageTitle, imageAlt, imageUrl, imageFilename }; 588 } 589 590 /** 591 * Copies text to clipboard. 592 * Allows users to copy lightbox url deep link to clipboard. 593 * 594 * @returns void 595 */ 596 async function copyToClipboard( textToCopy ) { 597 // Navigator clipboard api needs a secure context (https) 598 if ( navigator.clipboard && window.isSecureContext ) { 599 await navigator.clipboard.writeText(textToCopy); 600 } else { 601 // Use the 'out of viewport hidden text area' trick 602 const textArea = document.createElement("textarea"); 603 textArea.value = textToCopy; 604 605 // Move textarea out of the viewport so it's not visible 606 textArea.style.position = "absolute"; 607 textArea.style.left = "-999999px"; 608 609 // Add to page and select 610 document.body.prepend(textArea); 611 textArea.select(); 612 613 // Copy to cliboard, then remove 614 try { 615 document.execCommand('copy'); 616 } catch (error) { 617 console.error(error); 618 } finally { 619 textArea.remove(); 620 } 621 } 622 } 623 624 /** 625 * Adds exif data to caption area. 626 * 627 * @param {*} fancybox 628 * @returns void 629 */ 630 function addExifToCaption( fancybox, slide ) { 631 let exifData = ''; 632 const { imageUrl } = getImageAttributes( fancybox );
633 const hostName = location.hostname; 634 635 // Only fetch exif for images on the current domain. 636 if ( ! imageUrl.includes( hostName ) ) { 637 return; 638 } 639 640 const exifItems = [ 641 { id: 'camera', show: showCamera, svg: cameraSvg, exifName: 'Model' }, 642 { id: 'lens', show: showLens, svg: lensSvg, exifName: 'LensModel' }, 643 { id: 'focal', show: showFocal, svg: lensSvg, exifName: 'FocalLength' }, 644 { id: 'aperture', show: showAperture, svg: apertureSvg, exifName: 'FNumber' }, 645 { id: 'exposure', show: showExposure, svg: exposureSvg, exifName: 'ExposureTime' }, 646 { id: 'iso', show: showIso, svg: isoSvg, exifName: 'ISOSpeedRatings' }, 647 ]; 648 const exifToShow = exifItems.filter( item => item.show === true ); 649 650 fetch( imageUrl ) 651 .then( response => response.arrayBuffer() ) 652 .then( buffer => { 653 const exif = ExifReader.load( buffer ); 654 exifToShow.forEach( ( item, i ) => { 655 if ( exif.hasOwnProperty( item.exifName ) ) { 656 const spanStart = `<span class="exif-data ${ showExifIcons && 'with-icons' }"></span>`; 657 const label = showExifIcons ? `<span class="exif-icons ${ item.id }">${ item.svg }</span>` : ''; 658 const value = DOMPurify.sanitize( exif[item.exifName].description ); 659 const isLastItem = i === exifToShow.length - 1; 660 const seperator = showExifIcons || isLastItem ? '' : '|'; 661 const spanEnd = '</span>'; 662 exifData += `${spanStart}${label} ${value} ${seperator}${spanEnd}`; 663 664 665 } 666 }) 667 668 // Caption markup differs for compact vs non-compact mode. 669 isCompact = !! fancybox?.caption?.innerHTML; 670 const initialCaption = isCompact ? fancybox.caption.innerHTML : fancybox.getSlide().captionEl.innerHTML; 671 if ( ' ' === initialCaption && exifData === '' ) { 672 // No caption or exif. Remove caption placeholder. 673 const caption = fancybox.getSlide()?.captionEl; 674 if ( caption ) caption.remove(); 675 } else if ( ' ' === initialCaption ) { 676 // Exif but no caption. Replace caption placeholder with exif. 677 if ( isCompact ) initifancybox.caption.innerHTML = exifData; 678 if ( ! isCompact ) fancybox.getSlide().captionEl.innerHTML = exifData; 679 } else { 680 // Caption and exif. Add exif to end of caption. 681 if ( isCompact ) fancybox.caption.innerHTML = initialCaption + '<br>' + exifData; 682 if ( ! isCompact ) fancybox.getSlide().captionEl.innerHTML = initialCaption + '<br>' + exifData; 683 } 684 }) 685 .catch(error => { 686 console.error('Error loading EXIF data:', error); 687 }); 688 } 689} );
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.