1/* JS for preset "Menu V2" */ 2(function() { 3 $(function() { 4 $('.menu-wrapper').each(function() { 5 initMenu($(this)) 6 }); 7 }); 8 9 // Make :active pseudo classes work on iOS 10 document.addEventListener("touchstart", function() {}, false); 11 12 const initMenu = function($menuWrapper) { 13 const $body = $('body'); 14 const $menu = $('.ed-menu', $menuWrapper); 15 const $menuLinks = $('a', $menu); 16 const $menuTrigger = $('.menu-trigger', $menuWrapper); 17 const $banner = $('.banner').first(); 18 19 const smoothScrollOffset = 20; 20 21 // Set aria attributes 22 $menuTrigger.attr({ 23 'aria-expanded': 'false', 24 'aria-controls': $menu.attr('id'), 25 }); 26 27 toggleClassOnClick($body.add($menu), $menuTrigger, null, 'open open-menu'); // Keep open on $menu for backward compatibility 28 activateSmoothScroll($menuLinks.add($('.scroll a')), smoothScrollOffset); 29 addClassOnVisibleLinkTargets($menuLinks, 'active', 2 / 3); 30 handleSticky($menuWrapper, 'sticky', $banner); 31 }; 32 33 /** 34 * Observe element's height changes and reload the initMenu() function 35 * 36 * @param {HTMLElement} elm Element to observe 37 * @param {function} callback to call when elmement's height changed 38 */ 39 const observeHeightChange = function(elm, callback) { 40 if (!('ResizeObserver' in window) || elm == null) return; 41 42 const ro = new ResizeObserver(callback); 43 ro.observe(elm); 44 } 45 46 /** 47 * Toggles class on a target when a trigger is clicked 48 * 49 * @param {jQuery} $target The target to apply the CSS class to 50 * @param {jQuery} $trigger The Trigger 51 * @param {jQuery} $closeTrigger Optional close trigger 52 * @param {string} cssClass CSS Class to toggle on the target 53 */ 54 const toggleClassOnClick = function($target, $trigger, $closeTrigger, cssClass) { 55 56 // Reset in case class "open" was saved accidentally 57 $target.removeClass(cssClass); 58 $trigger.removeClass(cssClass).attr('aria-expanded', 'false'); 59 60 // Click on trigger toggles class "open" 61 $trigger.off('.toggle').on('click.toggle', function() { 62 const isExpanded = $(this).attr('aria-expanded') === 'true'; 63 const $menu = $target.filter('.ed-menu'); 64 $(this).toggleClass(cssClass).attr('aria-expanded', !isExpanded); 65 $target.toggleClass(cssClass); 66 67 // Set focus to menu on open 68 if (!isExpanded) { 69 $menu.attr('tabindex', '0'); 70 const focusMenu = () => { 71 $menu.focus(); 72 $menu.off('transitionend', focusMenu); 73 }; 74 $menu.on('transitionend', focusMenu); 75 } 76 77 $menu[0].addEventListener( 78 'blur', 79 function() { 80 $menu[0].removeAttribute('tabindex'); 81 }, { 82 once: true 83 } 84 ); 85 }); 86 87 // Close target when link inside is clicked 88 $target.find('a').click(function() { 89 $target.removeClass(cssClass); 90 $trigger.removeClass(cssClass).attr('aria-expanded', 'false'); 91 }); 92 93 if (!$closeTrigger || !$closeTrigger.length) { 94 return; 95 } 96 97 $closeTrigger.click(function() { 98 $target.removeClass(cssClass); 99 $trigger.removeClass(cssClass).attr('aria-expanded', 'false'); 100 }); 101 }; 102 103 /** 104 * Smooth scroll to link targets 105 * 106 * @param {jQuery} $scrollLinks The links 107 * @param {jQuery} scrollOffset Offset to subtract from the scroll target position (e.g. for fixed positioned elements like a menu) 108 */ 109 const activateSmoothScroll = function($scrollLinks, scrollOffset) { 110 if (typeof scrollOffset === 'undefined') { 111 scrollOffset = 0; 112 } 113 114 const determineTarget = function($trigger, hash) { 115 if (hash == '#!next') { 116 return $trigger.closest('.ed-element').next(); 117 } 118 // Prevent invalid selectors 119 try { 120 return $(hash); 121 } catch (e) { 122 return $(); 123 } 124 } 125 126 $scrollLinks.click(function(e) { 127 const $target = determineTarget($(this), this.hash); 128 if (!$target.length) return; 129 e.preventDefault(); 130 131 viewport.scrollTo($target, 'top', 500, 0); 132 133 }); 134 }; 135 136 /** 137 * We are using the fill property on an element to pass user's choices from CSS to JavaScript 138 * 139 * @param {jQuery} $element 140 */ 141 const getStickyMode = function($element) { 142 const fillValue = getComputedStyle($element[0]).fill; 143 144 return fillValue === 'rgb(255, 0, 0)' ? 145 'sticky_banner' : 146 fillValue === 'rgb(0, 255, 0)' ? 147 'sticky_menu' : 148 fillValue === 'rgb(0, 0, 255)' ? 149 'sticky_instant' : 150 fillValue === 'rgb(255, 255, 255)' ? 151 'sticky_reverse' : 152 'sticky_none'; 153 }; 154 155 /** 156 * Adds a class to an element when not currently visible 157 * 158 * @param {jQuery} $element The element to handle stickyness for 159 * @param {string} cssClass The actual CSS class to be applied to the element when it's above a certain scroll position 160 * @param {jQuery} $banner A banner to reference the scroll position to 161 */ 162 const handleSticky = function($element, cssClass, $banner) { 163 let triggerPos = 0, 164 offset = 0; 165 let menuWrapperHeight = $element.outerHeight(); 166 let mode; 167 let prevScroll = 0; 168 $element.removeClass(cssClass); 169 170 const toggleSpacer = function(toggle) { 171 document.body.style.setProperty('--spacer-height', toggle ? menuWrapperHeight + 'px' : ''); 172 }; 173 174 const handleScroll = function() { 175 if (!$element.length || mode === 'sticky_none') return; 176 //if (!$element.length || mode === 'sticky_none' || mode === 'sticky_instant') return; 177 178 const isReverse = mode === 'sticky_reverse', 179 curScroll = viewport.getScrollTop(); 180 181 if (triggerPos <= curScroll && (!isReverse || prevScroll > curScroll)) { 182 $element.addClass(cssClass); 183 toggleSpacer(true); 184 } else { 185 $element.removeClass(cssClass); 186 toggleSpacer(false); 187 } 188 189 prevScroll = curScroll; 190 }; 191
192 const updateOffset = function() { 193 mode = getStickyMode($element); 194 menuWrapperHeight = $element.outerHeight(); 195 if (!$element.hasClass(cssClass)) { 196 offset = $element.offset().top; 197 } 198 if (mode === 'sticky_banner' && !$banner.length) { 199 mode = 'sticky_menu'; 200 } 201 if (mode === 'sticky_banner') { 202 triggerPos = $banner.offset().top + ($banner.length ? $banner.outerHeight() : $element.outerHeight()); 203 } 204 if (mode === 'sticky_menu' || mode === 'sticky_reverse') { 205 triggerPos = offset + $element.outerHeight(); 206 } 207 if (mode === 'sticky_instant') { 208 triggerPos = offset; 209 } 210 211 handleScroll(); 212 } 213 214 viewport.observe('resize', updateOffset); 215 viewport.observe('animation.end', updateOffset); 216 observeHeightChange($element[0], updateOffset); 217 updateOffset(); 218 219 viewport.observe('scroll', handleScroll); 220 handleScroll(); 221 }; 222 223 /** 224 * Adds a class to links whose target is currently inside the viewport 225 * 226 * @param {jQuery} $links Link(s) to be observed 227 * @param {string} cssClass CSS Class to be applied 228 * @param {float} sectionViewportRatio Ratio by which the target should be within the viewport 229 */ 230 const addClassOnVisibleLinkTargets = function($links, cssClass, sectionViewportRatio) { 231 if (typeof sectionViewportRatio === 'undefined') { 232 sectionViewportRatio = 1 / 2; 233 } 234 235 const menuTargets = []; 236 const activeLink = $links.filter('.active'); 237 238 const links = $links.filter(function() { 239 // Prevent invalid selectors 240 let $target; 241 try { 242 $target = $(this.hash); 243 } catch (e) { 244 return false; 245 } 246 if (!this.hash || !$target.length) { 247 return false; 248 } 249 250 // Cache offset position to improve performance (update on resize) 251 const updateOffset = function() { 252 $target.data('offset', $target.offset().top); 253 }; 254 255 viewport.observe('resize', updateOffset); 256 viewport.observe('animation.end', updateOffset); 257 updateOffset(); 258 259 menuTargets.push($target); 260 return true; 261 }); 262 263 // No hash links found, so don't handle it at all 264 if (!links.length) { 265 return; 266 } 267 268 const checkVisibility = function() { 269 $links.removeClass('active'); 270 271 // Check section position reversely 272 for (let i = menuTargets.length - 1; i >= 0; i--) { 273 const desiredScrollPosition = menuTargets[i].data('offset') - viewport.getHeight() * (1 - sectionViewportRatio); 274 if (viewport.getScrollTop() >= desiredScrollPosition && menuTargets[i][0].offsetParent !== null) { 275 links.eq(i).addClass(cssClass); 276 return; 277 } 278 } 279 280 // Fallback to originally active item 281 activeLink.addClass(cssClass); 282 }; 283 284 viewport.observe('scroll', checkVisibility); 285 checkVisibility(); 286 }; 287})(); 288/* End JS for preset "Menu V2" */ 289 290/* JS for preset "Cookie Bar V2" */ 291$(function() { 292 if (!$('body').is('.edit')) { 293 $('.cookie-close').click(function(e) { 294 e.preventDefault(); 295 $('.cookie-bar').hide(); 296 createCookie('cookieBar', true, 0.5); 297 }); 298 } 299 300 var preview = false; 301 302 var listener = function() { 303 if (!preview && document.body.classList.contains('preview')) { 304 console.log("entering preview"); 305 preview = true; 306 } else if (preview && !document.body.classList.contains('preview')) { 307 console.log("leaving preview"); 308 $('.cookie-bar').show(); 309 preview = false; 310 } 311 requestAnimationFrame(listener); 312 }; 313 314 requestAnimationFrame(listener); 315 316 if (document.body.classList.contains('edit') || document.body.classList.contains('preview')) { 317 return; 318 } 319 320 // Cookie bar 321 if (readCookie('cookieBar') !== null) { 322 $('.cookie-bar').hide(); 323 } else { 324 $('.cookie-bar').show(); 325 } 326 327 function readCookie(name) { 328 var nameEQ = name + "="; 329 var ca = document.cookie.split(';'); 330 for (var i = 0; i < ca.length; i++) { 331 var c = ca[i]; 332 while (c.charAt(0) == ' ') c = c.substring(1, c.length); 333 if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length); 334 } 335 return null; 336 } 337 338 function createCookie(name, value, days) { 339 if (days) { 340 var date = new Date(); 341 date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); 342 var expires = "; expires=" + date.toGMTString(); 343 } else var expires = ""; 344 document.cookie = name + "=" + value + expires + "; path=/"; 345 } 346}); 347 348/* End JS for preset "Cookie Bar V2" */ 349 350/* JS for preset "Cookie Consent Bar V3" */ 351$(function() { 352 $('#cookieClose').click(function(e) { 353 e.preventDefault(); 354 createCookie('cookieConsentBar', "rejected", 0.5); 355 $('.cookie-consent-bar').hide(); 356 357 // If inside of an overlay, close it too 358 if ($('.cookie-consent-bar').closest('.mfp-content').length) { 359 $.magnificPopup.close(); 360 return; 361 } 362 }); 363 364 $('#acceptCookie').click(function(e) { 365 e.preventDefault(); 366 createCookie('cookieConsentBar', "accepted", 0.5); 367 $('.cookie-consent-bar').hide(); 368 369 if (typeof ThirdPartyScripts !== "undefined") { 370 ThirdPartyScripts.unblock(); 371 } 372 373 // If inside of an overlay, close it too 374 if ($('.cookie-consent-bar').closest('.mfp-content').length) { 375 $.magnificPopup.close(); 376 return; 377 } 378 }); 379 380 var preview = false;
381 382 var listener = function() { 383 if (!preview && document.body.classList.contains('preview')) { 384 console.log("entering preview"); 385 preview = true; 386 } else if (preview && !document.body.classList.contains('preview')) { 387 console.log("leaving preview"); 388 $('.cookie-consent-bar').show(); 389 preview = false; 390 } 391 requestAnimationFrame(listener); 392 }; 393 394 requestAnimationFrame(listener); 395 396 if (document.body.classList.contains('edit') || document.body.classList.contains('preview')) { 397 return; 398 } 399 400 401 // Cookie bar 402 if (readCookie('cookieConsentBar') == "accepted") { 403 $('.cookie-consent-bar').hide(); 404 window.setTimeout(function() { 405 if (typeof ThirdPartyScripts !== "undefined") { 406 ThirdPartyScripts.unblock(); 407 } 408 }, 100); 409 } else if (readCookie('cookieConsentBar') == "rejected") { 410 $('.cookie-consent-bar').hide(); 411 } else { 412 $('.cookie-consent-bar').show(); 413 } 414 415 function readCookie(name) { 416 var nameEQ = name + "="; 417 var ca = document.cookie.split(';'); 418 for (var i = 0; i < ca.length; i++) { 419 var c = ca[i]; 420 while (c.charAt(0) == ' ') c = c.substring(1, c.length); 421 if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length); 422 } 423 return null; 424 } 425 426 function createCookie(name, value, days) { 427 if (days) { 428 var date = new Date(); 429 date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); 430 var expires = "; expires=" + date.toGMTString(); 431 } else expires = ""; 432 document.cookie = name + "=" + value + expires + "; path=/"; 433 } 434 435 // Fix for hiding Content till page is loaded 436 $(document).ready(function() { 437 $('.hide-cookie-content').removeClass("hide-cookie-content"); 438 }); 439}); 440/* End JS for preset "Cookie Consent Bar V3" */
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.