1(function () { 2 if (window.__genericOfferingAdTrackingInitialized) { 3 return; 4 } 5 window.__genericOfferingAdTrackingInitialized = true; 6 7 var TRACKING_URL = '/api/offerings/track'; 8 var offeringsAdTrackingStore = window.__offeringsAdTracking = window.__offeringsAdTracking || {}; 9 var genericAdImpressionObserver = null; 10 var genericAdTrackedElements = typeof WeakSet !== 'undefined' ? new WeakSet() : null; 11 var genericAdTrackedFallbackIds = {}; 12 13 if (!offeringsAdTrackingStore.onPageUrl) { 14 offeringsAdTrackingStore.onPageUrl = window.location.href; 15 } 16 17 function shouldInterceptTrackedNavigation(event) { 18 return !( 19 event.defaultPrevented || 20 event.button !== 0 || 21 event.metaKey || 22 event.ctrlKey || 23 event.shiftKey || 24 event.altKey 25 ); 26 } 27 28 function getTrackingOnPageUrl() { 29 return offeringsAdTrackingStore.onPageUrl || null; 30 } 31 32 function appendIfPresent(formData, key, value) { 33 if (value) { 34 formData.append(key, value); 35 } 36 } 37 38 function getLeadToUrl(adElement) { 39 var linkElement = adElement && adElement.matches && adElement.matches('a[href]') ? adElement : null; 40 41 if (!linkElement && adElement && adElement.querySelector) { 42 linkElement = adElement.querySelector('a[href]'); 43 } 44 45 if (!linkElement && adElement && adElement.closest) { 46 linkElement = adElement.closest('a[href]'); 47 } 48 49 return linkElement ? (linkElement.getAttribute('href') || null) : null; 50 } 51 52 function trackOfferingsAd(category, offeringAdTrackingData, trackingType, onPageUrl, leadToUrl) { 53 if (typeof isCrawler !== 'undefined' && isCrawler === 1) { 54 return Promise.resolve(); 55 } 56 var formData = new FormData(); 57 formData.append('category', category || ''); 58 formData.append('offering_ad_tracking_data', offeringAdTrackingData || ''); 59 formData.append('tracking_type', trackingType); 60 appendIfPresent(formData, 'on_page', onPageUrl); 61 appendIfPresent(formData, 'lead_to', leadToUrl); 62 appendIfPresent(formData, 'device', typeof window.getDeviceDetailsJson === 'function' ? window.getDeviceDetailsJson() : null); 63 64 return fetch(TRACKING_URL, { 65 method: 'POST', 66 body: formData, 67 credentials: 'same-origin' 68 }); 69 } 70 71 function isGenericOfferingAdElement(element) { 72 return !!( 73 element && 74 element.classList && 75 element.classList.contains('generic-offering-ad') && 76 !element.classList.contains('mobile-bottom-nav') && 77 element.getAttribute('data-is-ad') === '1' && 78 element.hasAttribute('data-offering-ad-tracking-data') 79 ); 80 } 81 82 function hasTrackedGenericAdImpression(adElement) { 83 if (genericAdTrackedElements) { 84 return genericAdTrackedElements.has(adElement); 85 } 86 87 var fallbackId = adElement.id || adElement.getAttribute('data-ad-id'); 88 return !!(fallbackId && genericAdTrackedFallbackIds[fallbackId]); 89 } 90 91 function markGenericAdImpressionTracked(adElement) { 92 if (genericAdTrackedElements) { 93 genericAdTrackedElements.add(adElement); 94 return; 95 } 96 97 var fallbackId = adElement.id || adElement.getAttribute('data-ad-id'); 98 if (fallbackId) { 99 genericAdTrackedFallbackIds[fallbackId] = true; 100 } 101 } 102 103 function unmarkGenericAdImpressionTracked(adElement) { 104 if (genericAdTrackedElements) { 105 genericAdTrackedElements.delete(adElement); 106 return; 107 } 108 109 var fallbackId = adElement.id || adElement.getAttribute('data-ad-id'); 110 if (fallbackId) { 111 delete genericAdTrackedFallbackIds[fallbackId]; 112 } 113 } 114 115 function trackGenericAdImpression(adElement) { 116 var category; 117 var offeringAdTrackingData; 118 119 if (!isGenericOfferingAdElement(adElement) || hasTrackedGenericAdImpression(adElement)) { 120 return; 121 } 122 123 markGenericAdImpressionTracked(adElement); 124 category = adElement.getAttribute('data-offering-category') || ''; 125 offeringAdTrackingData = adElement.getAttribute('data-offering-ad-tracking-data') || ''; 126 127 trackOfferingsAd(category, offeringAdTrackingData, 'impression', getTrackingOnPageUrl(), getLeadToUrl(adElement)).catch(function () { 128 unmarkGenericAdImpressionTracked(adElement); 129 }); 130 } 131 132 function observeGenericOfferingAdElement(adElement) { 133 if (!isGenericOfferingAdElement(adElement) || hasTrackedGenericAdImpression(adElement)) { 134 return; 135 } 136 137 if (genericAdImpressionObserver) { 138 genericAdImpressionObserver.observe(adElement); 139 return; 140 } 141 142 trackGenericAdImpression(adElement); 143 } 144 145 function observeGenericOfferingAds(root) { 146 var ads; 147 var container = root && root.querySelectorAll ? root : document; 148 149 if (!container.querySelectorAll) { 150 return; 151 } 152 153 ads = container.querySelectorAll('.generic-offering-ad[data-offering-ad-tracking-data][data-is-ad="1"]'); 154 Array.prototype.forEach.call(ads, function (adElement) { 155 observeGenericOfferingAdElement(adElement); 156 }); 157 } 158 159 function initGenericOfferingAdTracking() { 160 if ('IntersectionObserver' in window) { 161 genericAdImpressionObserver = new IntersectionObserver(function (entries) { 162 Array.prototype.forEach.call(entries, function (entry) { 163 if (!entry.isIntersecting || entry.intersectionRatio <= 0) { 164 return; 165 } 166 167 trackGenericAdImpression(entry.target); 168 genericAdImpressionObserver.unobserve(entry.target); 169 }); 170 }, { threshold: 0.25 }); 171 } 172 173 observeGenericOfferingAds(document); 174 175 if ('MutationObserver' in window && document.body) { 176 new MutationObserver(function (mutations) { 177 Array.prototype.forEach.call(mutations, function (mutation) { 178 Array.prototype.forEach.call(mutation.addedNodes, function (node) { 179 if (node.nodeType !== 1) { 180 return; 181 } 182 183 if (isGenericOfferingAdElement(node)) { 184 observeGenericOfferingAdElement(node); 185 return; 186 } 187 188 observeGenericOfferingAds(node); 189 }); 190 }); 191 }).observe(document.body, { childList: true, subtree: true }); 192 } 193 } 194 195 document.addEventListener('click', function (event) { 196 var genericAdLink = event.target.closest('a[href]'); 197 var genericAdElement; 198 var category; 199 var offeringAdTrackingData; 200 var url; 201 202 if (!genericAdLink) { 203 return; 204 } 205 206 genericAdElement = genericAdLink.closest('.generic-offering-ad[data-offering-ad-tracking-data][data-is-ad="1"]'); 207 if (!genericAdElement || genericAdElement.classList.contains('mobile-bottom-nav')) { 208 return; 209 } 210 211 category = genericAdElement.getAttribute('data-offering-category') || ''; 212 offeringAdTrackingData = genericAdElement.getAttribute('data-offering-ad-tracking-data') || ''; 213 url = genericAdLink.getAttribute('href'); 214 215 if (!url || !shouldInterceptTrackedNavigation(event)) { 216 return; 217 } 218 219 event.preventDefault(); 220 221 trackOfferingsAd(category, offeringAdTrackingData, 'click', getTrackingOnPageUrl(), url) 222 .catch(function () { 223 return null; 224 }) 225 .then(function () { 226 window.location.assign(url); 227 }); 228 }); 229 230 if (document.body) { 231 initGenericOfferingAdTracking(); 232 } else { 233 document.addEventListener('DOMContentLoaded', initGenericOfferingAdTracking); 234 } 235}());
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.