PageSourceSearch

https://missdream.org/wp-content/plugins/lightpress-pro/lightboxes/lightpress-pro/lightpress-pro.js

js missdream.org collected 2026-09-24 20:41:14 UTC 33,425 bytes, 689 lines download raw bytes

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.