1/** 2 * TCS CTA Banner front-end behavior. 3 */ 4(function () { 5 'use strict'; 6 7 var cfg = window.tcsCtaBanner || {}; 8 var banner = document.getElementById('tcs-cta-banner'); 9 if (!banner) { 10 return; 11 } 12 13 var threshold = Number(cfg.scrollThreshold); 14 if (!Number.isFinite(threshold) || threshold < 0) { 15 threshold = 700; 16 } 17 18 var viewportMode = cfg.viewportMode === 'all' ? 'all' : 'max_width'; 19 var maxWidth = Number(cfg.maxWidth); 20 if (!Number.isFinite(maxWidth) || maxWidth < 320) { 21 maxWidth = 768; 22 } 23 24 var reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; 25 var mq = window.matchMedia('(max-width: ' + (maxWidth - 1) + 'px)'); 26 var ticking = false; 27 28 function viewportOk() { 29 return viewportMode === 'all' || mq.matches; 30 } 31 32 function showBanner(show) { 33 if (!viewportOk()) { 34 banner.hidden = true; 35 banner.classList.remove('is-visible'); 36 return; 37 } 38 39 if (show) { 40 banner.hidden = false; 41 if (!reducedMotion) { 42 void banner.offsetWidth; 43 } 44 banner.classList.add('is-visible'); 45 } else { 46 banner.classList.remove('is-visible'); 47 if (reducedMotion) { 48 banner.hidden = true; 49 } else { 50 window.setTimeout(function () { 51 if (!banner.classList.contains('is-visible')) { 52 banner.hidden = true; 53 } 54 }, 300); 55 } 56 } 57 } 58 59 function onScroll() { 60 if (ticking) { 61 return; 62 } 63 ticking = true; 64 window.requestAnimationFrame(function () { 65 ticking = false; 66 var y = window.scrollY || window.pageYOffset || 0; 67 showBanner(y >= threshold); 68 }); 69 } 70 71 function onViewportChange() { 72 onScroll(); 73 } 74 75 function originalHref(link) { 76 if (!link.hasAttribute('data-tcs-orig-href')) { 77 link.setAttribute('data-tcs-orig-href', link.getAttribute('href') || ''); 78 } 79 return link.getAttribute('data-tcs-orig-href') || ''; 80 } 81 82 function mergeSearchParams(pageSearch, extraSearch) { 83 var out = new URLSearchParams(pageSearch || ''); 84 var extra = new URLSearchParams(extraSearch || ''); 85 extra.forEach(function (value, key) { 86 if (!out.has(key)) { 87 out.append(key, value); 88 } 89 }); 90 return out; 91 } 92 93 function searchString(params) { 94 var s = params.toString(); 95 return s ? '?' + s : ''; 96 } 97 98 function mergedHashUrl(href) { 99 var rest = href.slice(1); 100 var qpos = rest.indexOf('?'); 101 var id = qpos === -1 ? rest : rest.slice(0, qpos); 102 var extra = qpos === -1 ? '' : rest.slice(qpos + 1); 103 return window.location.pathname + searchString(mergeSearchParams(window.location.search, extra)) + '#' + id; 104 } 105 106 function applyOutboundMerge(link) { 107 var href = originalHref(link); 108 if (!href || href.charAt(0) === '#') { 109 return; 110 } 111 112 var url; 113 try { 114 url = new URL(href, window.location.href); 115 } catch (err) { 116 return; 117 } 118 119 if (url.protocol !== 'http:' && url.protocol !== 'https:') { 120 return; 121 } 122 123 url.search = mergeSearchParams(window.location.search, url.search).toString(); 124 var next = 125 url.origin === window.location.origin 126 ? url.pathname + url.search + url.hash 127 : url.href; 128 129 if (next !== (link.getAttribute('href') || '')) { 130 link.setAttribute('href', next); 131 } 132 } 133 134 function onBannerLink(event) { 135 var target = event.target; 136 if (!(target instanceof Element)) { 137 return; 138 } 139 140 var link = target.closest('a.tcs-cta-banner__btn'); 141 if (!link) { 142 return; 143 } 144 145 var href = originalHref(link); 146 if (link.hasAttribute('data-tcs-smooth-scroll') && href.charAt(0) === '#') { 147 var id = href.slice(1).split('?')[0]; 148 if (!id || !/^[A-Za-z][\w\-:.]*$/.test(id)) { 149 return; 150 } 151 var el = document.getElementById(id) || document.getElementsByName(id)[0]; 152 if (!el) { 153 return; 154 } 155 event.preventDefault(); 156 el.scrollIntoView({ 157 behavior: reducedMotion ? 'auto' : 'smooth', 158 block: 'start', 159 }); 160 var next = mergedHashUrl(href); 161 if (window.history && typeof window.history.replaceState === 'function') { 162 window.history.replaceState(null, '', next); 163 } else { 164 window.location.hash = id; 165 } 166 if (typeof el.focus === 'function') { 167 try { 168 el.focus({ preventScroll: true });
169 } catch (err) { 170 el.setAttribute('tabindex', '-1'); 171 el.focus(); 172 } 173 } 174 return; 175 } 176 177 applyOutboundMerge(link); 178 } 179 180 banner.addEventListener('click', onBannerLink); 181 banner.addEventListener('auxclick', onBannerLink); 182 183 if (typeof mq.addEventListener === 'function') { 184 mq.addEventListener('change', onViewportChange); 185 } else if (typeof mq.addListener === 'function') { 186 mq.addListener(onViewportChange); 187 } 188 189 window.addEventListener('scroll', onScroll, { passive: true }); 190 window.addEventListener('resize', onViewportChange, { passive: true }); 191 onScroll(); 192})();
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.