1(function ($) { 2 'use strict'; 3 4 var suppressToggleOutsideClose = false; 5 6 function escapeHtml(value) { 7 return $('<div>').text(value || '').html(); 8 } 9 10 function buildShareLinks(shareUrl, shareTitle) { 11 var encodedUrl = encodeURIComponent(shareUrl); 12 var encodedTitle = encodeURIComponent(shareTitle || ''); 13 var whatsAppText = encodeURIComponent(((shareTitle || '') + ' ' + shareUrl).trim()); 14 15 return [ 16 { className: 'facebook', icon: 'fa-brands fa-facebook-f', label: 'Facebook', href: 'https://www.facebook.com/sharer/sharer.php?u=' + encodedUrl }, 17 { className: 'linkedin', icon: 'fa-brands fa-linkedin-in', label: 'LinkedIn', href: 'https://www.linkedin.com/sharing/share-offsite/?url=' + encodedUrl }, 18 { className: 'twitter', icon: 'fa-brands fa-x-twitter', label: 'X', href: 'https://twitter.com/intent/tweet?url=' + encodedUrl + '&text=' + encodedTitle }, 19 { className: 'whatsapp', icon: 'fa-brands fa-whatsapp', label: 'WhatsApp', href: 'https://wa.me/?text=' + whatsAppText }, 20 { className: 'email', icon: 'fa-solid fa-envelope', label: 'Email', href: 'mailto:?subject=' + encodedTitle + '&body=' + encodedUrl }, 21 { className: 'copy', icon: 'fa-solid fa-link', label: 'Copy link', isButton: true } 22 ]; 23 } 24
25 function renderShareMarkup(shareUrl, shareTitle, variant) { 26 var links = buildShareLinks(shareUrl, shareTitle); 27 var variantClass = variant === 'compact' ? ' social-share--compact' : ''; 28 var html = '<div class="social-share' + variantClass + ' itma-generated-share">'; 29 html += '<span class="social-share__label">Share</span><ul class="social-share__list" aria-label="Share on social media">'; 30 31 links.forEach(function (link) { 32 if (link.isButton) { 33 html += '<li><button type="button" class="social-share__btn social-share__btn--copy" data-share-url="' + escapeHtml(shareUrl) + '" title="Copy link" aria-label="Copy link">'; 34 html += '<em class="' + link.icon + '" aria-hidden="true"></em></button></li>'; 35 return; 36 } 37 38 html += '<li><a class="social-share__btn social-share__btn--' + link.className + '" href="' + escapeHtml(link.href) + '"'; 39 if (link.className !== 'email') { 40 html += ' target="_blank" rel="noopener noreferrer"'; 41 } 42 html += ' title="Share on ' + link.label + '" aria-label="Share on ' + link.label + '">'; 43 html += '<em class="' + link.icon + '" aria-hidden="true"></em></a></li>'; 44 }); 45 46 html += '</ul></div>'; 47 return html; 48 } 49 50 function copyShareUrl(url, $button) { 51 if (!url) { 52 return; 53 } 54 55 var onCopied = function () { 56 var $icon = $button.find('em'); 57 var originalClass = $icon.attr('class'); 58 $button.addClass('is-copied'); 59 $icon.attr('class', 'fa-solid fa-check'); 60 61 setTimeout(function () { 62 $button.removeClass('is-copied'); 63 $icon.attr('class', originalClass); 64 }, 2000); 65 }; 66 67 if (navigator.clipboard && navigator.clipboard.writeText) { 68 navigator.clipboard.writeText(url).then(onCopied).catch(function () { 69 fallbackCopy(url, onCopied, $button); 70 }); 71 return; 72 } 73 74 fallbackCopy(url, onCopied, $button); 75 } 76 77 function fallbackCopy(url, onCopied, $button) { 78 var $container = $button.closest('.itma-media-share-bar, .social-share'); 79 var $temp = $('<textarea readonly aria-hidden="true"></textarea>') 80 .val(url) 81 .css({ position: 'fixed', left: '-9999px', top: '0', opacity: '0' }) 82 .appendTo($container.length ? $container : 'body'); 83 84 $temp[0].focus(); 85 $temp[0].select(); 86 87 try { 88 var copied = document.execCommand('copy'); 89 if (copied) { 90 onCopied(); 91 } else { 92 window.prompt('Copy this link:', url); 93 } 94 } catch (err) { 95 window.prompt('Copy this link:', url); 96 } 97 98 $temp.remove(); 99 } 100 101 function closeAllToggleShares() { 102 $('.social-share--toggle.is-open').each(function () { 103 $(this).removeClass('is-open'); 104 $(this).find('.social-share__trigger').attr('aria-expanded', 'false'); 105 $(this).closest('.ginner').removeClass('ginner--share-open'); 106 }); 107 } 108 109 function openToggleShare($share) { 110 closeAllToggleShares(); 111 $share.addClass('is-open'); 112 $share.find('.social-share__trigger').attr('aria-expanded', 'true'); 113 $share.closest('.ginner').addClass('ginner--share-open'); 114 } 115 116 function removeMediaShareBar() { 117 $('.itma-media-share-bar').remove(); 118 $('.fancybox__container').removeClass('itma-share-injected'); 119 } 120 121 function getShareDataFromTrigger($trigger) { 122 if (!$trigger || !$trigger.length) { 123 return null; 124 } 125 126 var el = $trigger[0]; 127 // Prefer native getAttribute so hash/query values are not altered by jQuery. 128 var shareUrl = el.getAttribute('data-share-url') || ''; 129 var shareTitle = el.getAttribute('data-share-title') || ''; 130 131 // Rebuild from the media card if the attribute is missing. Never fall back to 132 // href/data-src â for photos those are CDN image URLs, not the Resources page URL. 133 if (!shareUrl) { 134 var $card = $trigger.closest('[data-media-id]'); 135 var mediaId = $card.attr('data-media-id'); 136 var mediaKind = $card.attr('data-media-kind') || 'photo'; 137 var categoryId = $card.attr('data-category-id') || ''; 138 139 if (mediaId) { 140 // Dedicated share page â avoids hash stripping and /resources canonical collapse. 141 shareUrl = window.location.origin + '/share/media/' + mediaKind + '-' + mediaId; 142 } 143 } 144 145 if (!shareTitle) { 146 shareTitle = $.trim($trigger.closest('.ginner').find('.gtxt h3').first().text()) || ''; 147 } 148 149 return { 150 shareUrl: shareUrl, 151 shareTitle: shareTitle 152 }; 153 } 154 155 function bindMediaShareBarEvents($bar) { 156 $bar.on('mousedown', function (e) { 157 e.stopPropagation(); 158 }); 159 160 $bar.on('click', function (e) { 161 e.stopPropagation(); 162 }); 163 164 $bar.find('.social-share__btn--copy').on('click', function (e) { 165 e.preventDefault(); 166 e.stopPropagation(); 167 var copyUrl = this.getAttribute('data-share-url') || ''; 168 copyShareUrl(copyUrl, $(this)); 169 }); 170 } 171 172 function injectMediaShareBar(shareUrl, shareTitle) { 173 removeMediaShareBar(); 174 175 var $container = $('.fancybox__container:visible').first(); 176 if (!$container.length || !shareUrl) { 177 return; 178 } 179 180 $container.addClass('itma-share-injected'); 181 var shareHtml = renderShareMarkup(shareUrl, shareTitle, 'compact'); 182 var $bar = $('<div class="itma-media-share-bar"></div>').html(shareHtml); 183 bindMediaShareBarEvents($bar); 184 $container.append($bar); 185 } 186 187 function stopEventPropagation(e) { 188 e.stopPropagation(); 189 if (typeof e.stopImmediatePropagation === 'function') { 190 e.stopImmediatePropagation(); 191 } 192 } 193
194 window.ITMASocialShare = { 195 injectMediaShareBar: injectMediaShareBar, 196 removeMediaShareBar: removeMediaShareBar 197 }; 198 199 function handleMediaShareOpen($trigger) { 200 var shareData = getShareDataFromTrigger($trigger); 201 if (!shareData || !shareData.shareUrl) { 202 return; 203 } 204 205 setTimeout(function () { 206 if ($('.fancybox__container:visible').length) { 207 injectMediaShareBar(shareData.shareUrl, shareData.shareTitle); 208 } 209 }, 400); 210 } 211 212 $(document).on('click', '.social-share__btn--copy', function (e) { 213 if ($(this).closest('.itma-media-share-bar').length) { 214 return; 215 } 216 217 stopEventPropagation(e); 218 e.preventDefault(); 219 copyShareUrl($(this).attr('data-share-url'), $(this)); 220 }); 221 222 $(document).on('mousedown', '.social-share__btn--copy', function (e) { 223 if ($(this).closest('.itma-media-share-bar').length) { 224 return; 225 } 226 227 e.stopPropagation(); 228 }); 229 230 $(document).on('click', '.social-share--toggle .social-share__trigger', function (e) { 231 stopEventPropagation(e); 232 e.preventDefault(); 233 234 var $share = $(this).closest('.social-share--toggle'); 235 var isOpen = $share.hasClass('is-open'); 236 237 suppressToggleOutsideClose = true; 238 setTimeout(function () { 239 suppressToggleOutsideClose = false; 240 }, 0); 241 242 if (isOpen) { 243 closeAllToggleShares(); 244 return; 245 } 246 247 openToggleShare($share); 248 }); 249 250 $(document).on('mousedown', '.social-share--toggle .social-share__trigger', stopEventPropagation); 251 252 $(document).on('click', '.social-share--toggle .social-share__list--vertical a, .social-share--toggle .social-share__list--vertical button', function (e) { 253 stopEventPropagation(e); 254 }); 255 256 $(document).on('mousedown', '.social-share--toggle .social-share__list--vertical a, .social-share--toggle .social-share__list--vertical button', stopEventPropagation); 257 258 $(document).on('click', function (e) { 259 if (suppressToggleOutsideClose) { 260 return; 261 } 262 263 if ($(e.target).closest('.social-share--toggle').length) { 264 return; 265 } 266 267 closeAllToggleShares(); 268 }); 269 270 document.addEventListener('mousedown', function (e) { 271 if (e.target.closest && e.target.closest('.itma-media-share-bar')) { 272 e.stopPropagation(); 273 } 274 }, true); 275 276 $(document).on('click', '[data-fancybox="video"][data-share-url], [data-fancybox="photo"][data-share-url]', function () { 277 handleMediaShareOpen($(this)); 278 }); 279 280 document.addEventListener('fancybox:reveal', function (event) { 281 var slide = event.detail && event.detail.slide; 282 var trigger = slide && slide.triggerEl ? $(slide.triggerEl) : null; 283 284 if (trigger && trigger.is('[data-share-url]')) { 285 handleMediaShareOpen(trigger); 286 } 287 }); 288 289 $(document).on('click', '.fancybox__button--close, .fancybox__backdrop', function (e) { 290 if ($(e.target).closest('.itma-media-share-bar').length) { 291 stopEventPropagation(e); 292 return; 293 } 294 295 removeMediaShareBar(); 296 }); 297 298 $(document).on('keyup', function (e) { 299 if (e.key === 'Escape') { 300 closeAllToggleShares(); 301 removeMediaShareBar(); 302 } 303 }); 304})(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.