1/** 2 * 3 * Changes within this file can potentially affect functionality of other components if errors arise. 4 * Ensure mobile navigation and social share click events are working as expected if any new code is added. 5 * 6 */ 7 8/** 9 * Pilot GA4 Implementation. Register a navbar see event 10 */ 11class ga4Handler { 12 constructor() { 13 } 14 15 gtagIsAvailable() { 16 return window.gtag !== undefined && typeof window.gtag === "function"; 17 } 18 19 dataLayerPush(data) { 20 window.dataLayer = window.dataLayer || []; 21 window.dataLayer.push(data); 22 } 23 24 recordUserElementInteraction(name) { 25 this.dataLayerPush({ 26 event: "element_interaction", 27 element_name: name, 28 }); 29 } 30 31 recordCalendarClick(calendarName) { 32 this.dataLayerPush({ 33 event: "sessionboard_add_to_calendar", 34 action: "click", 35 calendar_selected: calendarName, 36 }); 37 } 38} 39 40const ga4 = new ga4Handler(); 41 42 43/** 44 * Floats the main menu. 45 * 46 * Used in scroll event as well as in vuejs components to detach that event 47 * from the window object. 48 */ 49var lastScroll = 0; 50 51function floatMainMenuOnScroll() { 52 let scrollingUp = false; 53 let currentScrollPos = window.pageYOffset || document.documentElement.scrollTop; 54 55 if (currentScrollPos < lastScroll) { 56 scrollingUp = true; 57 } 58 59 let headerBlock = document.getElementsByClassName('block-quartz-blocks-header')[0]; 60 if (!headerBlock) { 61 return; 62 } 63 let rect = headerBlock.getBoundingClientRect(); 64 let belowHeaderBottom = rect.y + rect.height; 65 let mainMenuSubContainer = document.getElementsByClassName('js-main-menu-sub-container')[0]; 66 let mobileMenuSubContainer = document.getElementsByClassName('js-mobile-menu-sub-container')[0]; 67 let mainWrapper = document.getElementsByClassName('layout-main-wrapper')[0]; 68 // pass the lower header box, float the menu and hide it 69 let belowMenu = belowHeaderBottom < 20; 70 if (!belowMenu) { 71 // Main Nav 72 mainMenuSubContainer.classList.remove('show-menu'); 73 mainMenuSubContainer.classList.remove('hide-menu'); 74 mainMenuSubContainer.classList.remove('float-menu'); 75 76 // Mobile Nav 77 mobileMenuSubContainer.classList.remove('show-menu'); 78 mobileMenuSubContainer.classList.remove('hide-menu'); 79 mobileMenuSubContainer.classList.remove('float-menu'); 80 mainWrapper.classList.remove('show-mobile-menu'); 81 } 82 else if (belowMenu && scrollingUp) { 83 // Main Nav 84 mainMenuSubContainer.classList.add('show-menu'); 85 mainMenuSubContainer.classList.remove('hide-menu'); 86 87 // Mobile Nav 88 mobileMenuSubContainer.classList.add('show-menu'); 89 mobileMenuSubContainer.classList.remove('hide-menu'); 90 mainWrapper.classList.add('show-mobile-menu'); 91 92 93 } 94 else if (belowMenu && !scrollingUp) { 95 // Main Nav 96 mainMenuSubContainer.classList.add('float-menu'); 97 mainMenuSubContainer.classList.add('hide-menu'); 98 mainMenuSubContainer.classList.remove('show-menu'); 99 100 // Mobile Nav 101 mobileMenuSubContainer.classList.add('float-menu'); 102 mobileMenuSubContainer.classList.add('hide-menu'); 103 mobileMenuSubContainer.classList.remove('show-menu'); 104 mainWrapper.classList.remove('show-mobile-menu'); 105 } 106 lastScroll = currentScrollPos; 107} 108 109// Float the Main Menu on scroll 110window.addEventListener('scroll', floatMainMenuOnScroll); 111 112function closeMobileSubNavs() { 113 [].forEach.call(document.querySelectorAll('.header-dropdown .menu-item--expanded'), function (e) { 114 e.classList.remove('active'); 115 }); 116 [].forEach.call(document.querySelectorAll('.sub-nav-toggle'), function (e) { 117 e.classList.remove('active'); 118 }); 119 document.querySelector('.header__wrapper').classList.remove('active'); 120} 121 122/** 123 * Get the closest matching element up the DOM tree. 124 * @private 125 * @param {Element} elem Starting element 126 * @param {String} selector Selector to match against 127 * @return {Boolean|Element} Returns null if not match found 128 */ 129var getClosest = function (elem, selector) { 130 // Element.matches() polyfill 131 if (!Element.prototype.matches) { 132 Element.prototype.matches = 133 Element.prototype.matchesSelector || 134 Element.prototype.mozMatchesSelector || 135 Element.prototype.msMatchesSelector || 136 Element.prototype.oMatchesSelector || 137 Element.prototype.webkitMatchesSelector || 138 function (s) { 139 var matches = (this.document || this.ownerDocument).querySelectorAll(s), 140 i = matches.length; 141 while (--i >= 0 && matches.item(i) !== this) { 142 } 143 return i > -1; 144 }; 145 } 146 // Get closest match 147 for (; elem && elem !== document; elem = elem.parentNode) { 148 if (elem.matches(selector)) { 149 return elem; 150 } 151 } 152 return null; 153}; 154 155document.querySelectorAll('.sb-calendar-click').forEach(el => { 156 el.addEventListener('click', () => { 157 ga4.recordCalendarClick(el.dataset.calendarType) 158 }); 159}); 160 161 162document.addEventListener('click', function (event) { 163 let target = event.target; 164 let body = document.querySelector('body'); 165 let headerToggle = document.querySelector('.header-toggle'); 166 let closedToggleIcon = document.querySelector('.toggle-icon.closed'); 167 let openToggleIcon = document.querySelector('.toggle-icon.open'); 168 let headerDropdown = document.querySelector('.header-dropdown'); 169 let headerWrapper = document.querySelector('.header__wrapper'); 170 let mobileNav = document.querySelector('.mobile-nav'); 171 let bottomNavPopup = document.querySelector('.bottom-nav-popup'); 172 let calButton = document.querySelector('.cal-button'); 173 let calDropdownToggle = document.getElementById('calendarBtns'); 174 175 if (target.tagName === 'IMG' && target.parentElement && target.parentElement.classList.contains('mobile-menu-open')) { 176 target.parentElement.classList.remove('active'); 177 body.classList.add('hide-scrollbar'); 178 openToggleIcon.classList.add('active'); 179 headerWrapper.classList.add('active'); 180 mobileNav.classList.add('active'); 181 headerToggle.classList.add('active'); 182 headerDropdown.classList.add('active'); 183 } 184 185 if (target.tagName === 'IMG' && target.parentElement && target.parentElement.classList.contains('mobile-menu-close')) { 186 target.parentElement.classList.remove('active'); 187 body.classList.remove('hide-scrollbar'); 188 closedToggleIcon.classList.add('active'); 189 headerWrapper.classList.remove('active'); 190 mobileNav.classList.remove('active'); 191 headerToggle.classList.remove('active'); 192 headerDropdown.classList.remove('active'); 193 closeMobileSubNavs(); 194 } 195 196 // Open Bottom Tab Nav 197 if (target.classList.contains('bottom-nav-toggle-open') || getClosest(target, '.bottom-nav-toggle-open')) { 198 bottomNavPopup.classList.add('active'); 199 body.classList.add('hide-scrollbar'); 200 } 201 202 // Close Bottom Tab Nav 203 if ((target.tagName === 'IMG' && target.parentElement && target.parentElement.classList.contains('bottom-nav-toggle-close')) || target.classList.contains('bottom-nav-toggle-close')) { 204 bottomNavPopup.classList.remove('active'); 205 body.classList.remove('hide-scrollbar'); 206 } 207 208 // Open/close functionality of sub-nav-toggle element. Note: Upd
208ated to not apply to events-mega-menu 209 if (target && target.classList.contains('sub-nav-toggle') && !getClosest(target, '.menu-item--expanded').classList.contains('events-mega-menu')) { 210 var list = getClosest(target, '.menu-item--expanded'); 211 212 // If the clicked sub-nav-toggle is not active, add the active class to it, as well as the parent list item 213 if (!target.classList.contains('active')) { 214 target.classList.add('active'); 215 list.classList.add('active'); 216 } 217 218 // If the clicked sub-nav-toggle is active, remove the active class from it, as well as the parent list item 219 else { 220 target.classList.remove('active'); 221 list.classList.remove('active'); 222 } 223 } 224 225 if (target && target.classList && target.classList.contains('social-share-toggle')) { 226 getClosest(target, '.social-share').classList.add('open'); 227 getClosest(target, '.social-share').classList.remove('closed'); 228 body.classList.add('hide-scrollbar'); 229 230 } 231 232 if (target && target.classList && target.classList.contains('small-social')) { 233 getClosest(target, '.social-share').classList.add('closed'); 234 getClosest(target, '.social-share').classList.remove('open'); 235 body.classList.remove('hide-scrollbar'); 236 } 237 238 //Open/close functionality of the add to calendar CTA on mobile devices 239 if (target.tagName === 'BUTTON' && target.classList.contains('cal-button')) { 240 241 calButton.classList.add('cal-button-open'); 242 calDropdownToggle.classList.toggle('show'); 243 } else { 244 if (calButton && calDropdownToggle) { 245 let isClickInsideButton = calButton.contains(target); 246 let isClickInsideDropdown = calDropdownToggle.contains(target); 247 248 if (!isClickInsideButton && !isClickInsideDropdown) { 249 calButton.classList.remove('cal-button-open'); 250 calDropdownToggle.classList.remove('show'); 251 } 252 } 253 } 254}); 255 256 257 258window.addEventListener('load', function () { 259 //ga4.recordUserElementInteraction("see", "main nav bar"); 260 261 let mobileSubNav = document.querySelectorAll('.header-dropdown .menu-item--expanded'); 262 263 [].forEach.call(document.querySelectorAll('.footer-menu .nav li.menu-item--expanded > a'), function (el) { 264 el.removeAttribute('href'); 265 }); 266 267}, false); 268 269/** 270 * Record newsletter form signups through the Omeda iframe forms. 271 */ 272window.addEventListener("message", function (event) { 273 if (event.data && event.data.event === 'newsletter_signup') { 274 if (window.hasOwnProperty('ga') && window.ga.length > 0) { 275 let gaName = ga.getAll()[0].get('name'); 276 ga(gaName + ".send", "event", "Newsletter Signup", "Omeda Iframe Form Submit", window.location.pathname, 1); 277 } 278 } 279}); 280 281/** 282 * Open/Close functionality for the premium landing page social share 283 */ 284 285/** * Set image width and height attributes for SEO */ 286/* todo: temp disable 287setTimeout(function () { 288 [].forEach.call(document.querySelectorAll('.image-w-h img'), function (e) { 289 let imgWidth = e.naturalWidth; 290 let imgHeight = e.naturalHeight; 291 e.setAttribute("width", imgWidth); 292 e.setAttribute("height", imgHeight); 293 }); 294}, 200); 295*/
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.